Commit 0d7d5cf2 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: ioctl, brinfo



Provide info about the branches, which will be used from user-space.
This is essentially equivalent to the entries under sysfs
(/sys/fs/aufs/si_*/).
But the ioctl behaviour is atomic and never confuse the matching of the
branch id.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent de0ee5c9
...@@ -115,6 +115,10 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -115,6 +115,10 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
err = au_wbr_fd(&file->f_path, (void __user *)arg); err = au_wbr_fd(&file->f_path, (void __user *)arg);
break; break;
case AUFS_CTL_BRINFO:
err = au_brinfo_ioctl(file, arg);
break;
default: default:
/* do not call the lower */ /* do not call the lower */
AuDbg("0x%x\n", cmd); AuDbg("0x%x\n", cmd);
...@@ -150,7 +154,14 @@ long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ...@@ -150,7 +154,14 @@ long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
{ {
long err; long err;
err = aufs_ioctl_dir(file, cmd, arg); switch (cmd) {
case AUFS_CTL_BRINFO:
err = au_brinfo_compat_ioctl(file, arg);
break;
default:
err = aufs_ioctl_dir(file, cmd, arg);
}
AuTraceErr(err); AuTraceErr(err);
return err; return err;
......
...@@ -57,6 +57,10 @@ extern struct attribute_group *sysaufs_attr_group; ...@@ -57,6 +57,10 @@ extern struct attribute_group *sysaufs_attr_group;
int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
char *buf); char *buf);
long au_brinfo_ioctl(struct file *file, unsigned long arg);
#ifdef CONFIG_COMPAT
long au_brinfo_compat_ioctl(struct file *file, unsigned long arg);
#endif
void sysaufs_br_init(struct au_branch *br); void sysaufs_br_init(struct au_branch *br);
void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* sysfs interface * sysfs interface
*/ */
#include <linux/compat.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include "aufs.h" #include "aufs.h"
...@@ -182,6 +183,91 @@ out: ...@@ -182,6 +183,91 @@ out:
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg)
{
int err;
int16_t brid;
aufs_bindex_t bindex, bbot;
size_t sz;
char *buf;
struct seq_file *seq;
struct au_branch *br;
si_read_lock(sb, AuLock_FLUSH);
bbot = au_sbbot(sb);
err = bbot + 1;
if (!arg)
goto out;
err = -ENOMEM;
buf = (void *)__get_free_page(GFP_NOFS);
if (unlikely(!buf))
goto out;
seq = au_seq(buf, PAGE_SIZE);
err = PTR_ERR(seq);
if (IS_ERR(seq))
goto out_buf;
sz = sizeof(*arg) - offsetof(union aufs_brinfo, path);
for (bindex = 0; bindex <= bbot; bindex++, arg++) {
/* VERIFY_WRITE */
err = !access_ok(arg, sizeof(*arg));
if (unlikely(err))
break;
br = au_sbr(sb, bindex);
brid = br->br_id;
BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id));
err = __put_user(brid, &arg->id);
if (unlikely(err))
break;
BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm));
err = __put_user(br->br_perm, &arg->perm);
if (unlikely(err))
break;
err = au_seq_path(seq, &br->br_path);
if (unlikely(err))
break;
seq_putc(seq, '\0');
if (!seq_has_overflowed(seq)) {
err = copy_to_user(arg->path, seq->buf, seq->count);
seq->count = 0;
if (unlikely(err))
break;
} else {
err = -E2BIG;
goto out_seq;
}
}
if (unlikely(err))
err = -EFAULT;
out_seq:
au_kfree_rcu(seq);
out_buf:
free_page((unsigned long)buf);
out:
si_read_unlock(sb);
return err;
}
long au_brinfo_ioctl(struct file *file, unsigned long arg)
{
return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg);
}
#ifdef CONFIG_COMPAT
long au_brinfo_compat_ioctl(struct file *file, unsigned long arg)
{
return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg));
}
#endif
/* ---------------------------------------------------------------------- */
void sysaufs_br_init(struct au_branch *br) void sysaufs_br_init(struct au_branch *br)
{ {
int i; int i;
......
...@@ -193,7 +193,8 @@ static inline int au_br_wh_linkable(int brperm) ...@@ -193,7 +193,8 @@ static inline int au_br_wh_linkable(int brperm)
/* ioctl */ /* ioctl */
enum { enum {
AuCtl_WBR_FD /* pathconf wrapper */ AuCtl_WBR_FD, /* pathconf wrapper */
AuCtl_BR /* info about branches */
}; };
/* borrowed from linux/include/linux/kernel.h */ /* borrowed from linux/include/linux/kernel.h */
...@@ -243,8 +244,21 @@ struct aufs_wbr_fd { ...@@ -243,8 +244,21 @@ struct aufs_wbr_fd {
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
union aufs_brinfo {
/* PATH_MAX may differ between kernel-space and user-space */
char _spacer[4096];
struct {
int16_t id;
int perm;
char path[0];
};
} __aligned(8);
/* ---------------------------------------------------------------------- */
#define AuCtlType 'A' #define AuCtlType 'A'
#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ #define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \
struct aufs_wbr_fd) struct aufs_wbr_fd)
#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo)
#endif /* __AUFS_TYPE_H__ */ #endif /* __AUFS_TYPE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment