- new files ioctl.c and rdu.c.
- define the ioctl in aufs_type.h.
Signed-off-by: J. R. Okajima <[email protected]>
---
fs/aufs/Makefile | 2 +-
fs/aufs/dir.c | 1 +
fs/aufs/dir.h | 6 +
fs/aufs/ioctl.c | 42 ++++++
fs/aufs/rdu.c | 327 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/aufs_type.h | 113 +++++++++++-----
6 files changed, 456 insertions(+), 35 deletions(-)
create mode 100644 fs/aufs/ioctl.c
create mode 100644 fs/aufs/rdu.c
diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile
index f529b6f..9cd7146 100644
--- a/fs/aufs/Makefile
+++ b/fs/aufs/Makefile
@@ -47,7 +47,7 @@ aufs-y := module.o super.o sbinfo.o branch.o xino.o opts.o \
cpup.o whout.o plink.o wbr_policy.o \
dentry.o dinfo.o \
file.o f_op.o finfo.o \
- dir.o vdir.o \
+ dir.o vdir.o rdu.o ioctl.o \
inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o iinfo.o \
misc.o
diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c
index c722345..e34e955 100644
--- a/fs/aufs/dir.c
+++ b/fs/aufs/dir.c
@@ -602,6 +602,7 @@ int au_test_empty(struct dentry *dentry, struct au_nhash
*whlist)
struct file_operations aufs_dir_fop = {
.read = generic_read_dir,
.readdir = aufs_readdir,
+ .unlocked_ioctl = aufs_ioctl_dir,
.open = aufs_open_dir,
.release = aufs_release_dir,
.flush = aufs_flush,
diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h
index 161a2fd..f57dbd8 100644
--- a/fs/aufs/dir.h
+++ b/fs/aufs/dir.h
@@ -112,6 +112,12 @@ void au_vdir_free(struct au_vdir *vdir);
int au_vdir_init(struct file *file);
int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir);
+/* ioctl.c */
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
+
+/* rdu.c */
+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
/* ---------------------------------------------------------------------- */
static inline
diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c
new file mode 100644
index 0000000..d2dc7ef
--- /dev/null
+++ b/fs/aufs/ioctl.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * ioctl
+ * readdir in userspace.
+ */
+
+#include "aufs.h"
+
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long err;
+
+ switch (cmd) {
+ case AUFS_CTL_RDU:
+ case AUFS_CTL_RDU_INO:
+ err = au_rdu_ioctl(file, cmd, arg);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ AuTraceErr(err);
+ return err;
+}
diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c
new file mode 100644
index 0000000..907f3ac
--- /dev/null
+++ b/fs/aufs/rdu.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2005-2009 Junjiro R. Okajima
+ *
+ * This program, aufs is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * readdir in userspace.
+ */
+
+#include <linux/security.h>
+#include <linux/uaccess.h>
+#include <linux/aufs_type.h>
+#include "aufs.h"
+
+/* bits for struct aufs_rdu.flags */
+#define AuRdu_CALLED 1
+#define AuRdu_CONT (1 << 1)
+#define AuRdu_FULL (1 << 2)
+#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
+#define au_fset_rdu(flags, name) { (flags) |= AuRdu_##name; }
+#define au_fclr_rdu(flags, name) { (flags) &= ~AuRdu_##name; }
+
+struct au_rdu_arg {
+ struct aufs_rdu *rdu;
+ union au_rdu_ent_ul ent;
+ unsigned long end;
+
+ struct super_block *sb;
+ int err, dlgt;
+};
+
+static int au_rdu_fill(void *__arg, const char *name, int nlen,
+ loff_t offset, u64 h_ino, unsigned int d_type)
+{
+ int err, len;
+ struct au_rdu_arg *arg = __arg;
+ struct aufs_rdu *rdu = arg->rdu;
+ struct au_rdu_ent ent;
+
+ err = 0;
+ arg->err = 0;
+ au_fset_rdu(rdu->cookie.flags, CALLED);
+ len = au_rdu_len(nlen);
+ if (arg->ent.ul + len < arg->end) {
+ ent.ino = h_ino;
+ ent.bindex = rdu->cookie.bindex;
+ ent.type = d_type;
+ ent.nlen = nlen;
+
+ err = -EFAULT;
+ if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
+ goto out;
+ if (copy_to_user(arg->ent.e->name, name, nlen))
+ goto out;
+ /* the terminating NULL */
+ if (__put_user(0, arg->ent.e->name + nlen))
+ goto out;
+ err = 0;
+ /* LKTRTrace("%p, %.*s\n", arg->ent.p, nlen, name); */
+ arg->ent.ul += len;
+ rdu->rent++;
+ } else {
+ err = -EFAULT;
+ au_fset_rdu(rdu->cookie.flags, FULL);
+ rdu->full = 1;
+ rdu->tail = arg->ent;
+ }
+
+ out:
+ /* AuTraceErr(err); */
+ return err;
+}
+
+static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
+{
+ int err;
+ loff_t offset;
+ struct au_rdu_cookie *cookie = &arg->rdu->cookie;
+
+ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
+ err = offset;
+ if (unlikely(offset != cookie->h_pos))
+ goto out;
+
+ err = 0;
+ do {
+ arg->err = 0;
+ au_fclr_rdu(cookie->flags, CALLED);
+ /* smp_mb(); */
+ err = vfsub_readdir(h_file, au_rdu_fill, arg, arg->dlgt);
+ if (err >= 0)
+ err = arg->err;
+ } while (!err
+ && au_ftest_rdu(cookie->flags, CALLED)
+ && !au_ftest_rdu(cookie->flags, FULL));
+ cookie->h_pos = h_file->f_pos;
+
+ out:
+ AuTraceErr(err);
+ return err;
+}
+
+static int au_rdu(struct file *file, struct aufs_rdu *rdu)
+{
+ int err;
+ aufs_bindex_t bend;
+ struct au_rdu_arg arg;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct file *h_file;
+ struct au_rdu_cookie *cookie = &rdu->cookie;
+
+ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ goto out;
+ }
+ rdu->rent = 0;
+ rdu->tail = rdu->ent;
+ rdu->full = 0;
+ arg.rdu = rdu;
+ arg.ent = rdu->ent;
+ arg.end = arg.ent.ul;
+ arg.end += rdu->sz;
+
+ err = -ENOTDIR;
+ if (unlikely(!file->f_op || !file->f_op->readdir))
+ goto out;
+
+ err = security_file_permission(file, MAY_READ);
+ AuTraceErr(err);
+ if (unlikely(err))
+ goto out;
+
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
+#if 1
+ mutex_lock(&inode->i_mutex);
+#else
+ err = mutex_lock_killable(&inode->i_mutex);
+ AuTraceErr(err);
+ if (unlikely(err))
+ goto out;
+#endif
+ err = -ENOENT;
+ if (unlikely(IS_DEADDIR(inode)))
+ goto out_mtx;
+
+ arg.sb = inode->i_sb;
+ si_read_lock(arg.sb, AuLock_FLUSH);
+ fi_read_lock(file);
+ arg.dlgt = !!au_test_dlgt(au_mntflags(arg.sb));
+
+ err = -EAGAIN;
+ if (unlikely(au_ftest_rdu(cookie->flags, CONT)
+ && cookie->generation != au_figen(file)))
+ goto out_unlock;
+
+ err = 0;
+ rdu->blk = au_dir_size(file, /*dentry*/NULL);
+ bend = au_fbstart(file);
+ if (cookie->bindex < bend)
+ cookie->bindex = bend;
+ bend = au_fbend(file);
+ for (; !err && cookie->bindex <= bend;
+ cookie->bindex++, cookie->h_pos = 0) {
+ h_file = au_h_fptr(file, cookie->bindex);
+ if (!h_file)
+ continue;
+
+ au_fclr_rdu(cookie->flags, FULL);
+ err = au_rdu_do(h_file, &arg);
+ AuTraceErr(err);
+ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
+ break;
+ }
+ LKTRTrace("rent %llu\n", rdu->rent);
+
+ if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
+ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
+ au_fset_rdu(cookie->flags, CONT);
+ cookie->generation = au_figen(file);
+ }
+
+ ii_read_lock_child(inode);
+ inode->i_atime = au_h_iptr(inode, au_ibstart(inode))->i_atime;
+ ii_read_unlock(inode);
+
+ out_unlock:
+ fi_read_unlock(file);
+ si_read_unlock(arg.sb);
+ out_mtx:
+ mutex_unlock(&inode->i_mutex);
+ out:
+ AuTraceErr(err);
+ return err;
+}
+
+static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
+{
+ int err;
+ ino_t ino;
+ unsigned long long nent;
+ union au_rdu_ent_ul *u;
+ struct au_rdu_ent ent;
+ struct super_block *sb;
+
+ err = 0;
+ nent = rdu->nent;
+ u = &rdu->ent;
+ sb = file->f_dentry->d_sb;
+ si_read_lock(sb, AuLock_FLUSH);
+ while (nent-- > 0) {
+ err = !access_ok(VERIFY_WRITE, u->e, sizeof(ent));
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ break;
+ }
+
+ err = copy_from_user(&ent, u->e, sizeof(ent));
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ break;
+ }
+
+ /* LKTRTrace("b%d, i%llu\n", ent.bindex, ent.ino); */
+ if (!ent.wh)
+ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
+ else
+ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
+ &ino);
+ if (unlikely(err)) {
+ AuTraceErr(err);
+ break;
+ }
+
+ err = __put_user(ino, &u->e->ino);
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ break;
+ }
+ u->ul += au_rdu_len(ent.nlen);
+ }
+ si_read_unlock(sb);
+
+ return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int au_rdu_verify(struct aufs_rdu *rdu)
+{
+ LKTRTrace("rdu{%llu, %p, (%u, %u) | %u | %llu, %u, %u | "
+ "%llu, b%d, 0x%x, g%u}\n",
+ rdu->sz, rdu->ent.e, rdu->verify[0], rdu->verify[1],
+ rdu->blk,
+ rdu->rent, rdu->shwh, rdu->full,
+ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
+ rdu->cookie.generation);
+
+ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)
+ && rdu->verify[AufsCtlRduV_SZ_PTR] == sizeof(rdu))
+ return 0;
+
+ LKTRTrace("%u:%u, %u:%u\n",
+ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu),
+ rdu->verify[AufsCtlRduV_SZ_PTR], (unsigned int)sizeof(rdu));
+ return -EINVAL;
+}
+
+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long err, e;
+ struct aufs_rdu rdu;
+ void __user *p = (void __user *)arg;
+
+ err = copy_from_user(&rdu, p, sizeof(rdu));
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ goto out;
+ }
+ err = au_rdu_verify(&rdu);
+ if (unlikely(err))
+ goto out;
+
+ switch (cmd) {
+ case AUFS_CTL_RDU:
+ err = au_rdu(file, &rdu);
+ if (unlikely(err))
+ break;
+
+ e = copy_to_user(p, &rdu, sizeof(rdu));
+ if (unlikely(e)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ }
+ break;
+ case AUFS_CTL_RDU_INO:
+ err = au_rdu_ino(file, &rdu);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ out:
+ AuTraceErr(err);
+ return err;
+}
diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h
index b2108be..5783d70 100644
--- a/include/linux/aufs_type.h
+++ b/include/linux/aufs_type.h
@@ -19,6 +19,7 @@
/* $Id: aufs_type.h,v 1.134 2009/01/26 06:24:45 sfjro Exp $ */
#include <linux/ioctl.h>
+#include <linux/types.h>
#ifndef __AUFS_TYPE_H__
#define __AUFS_TYPE_H__
@@ -32,17 +33,21 @@
#ifdef CONFIG_AUFS_BRANCH_MAX_127
/* some environments treat 'char' as 'unsigned char' by default */
-typedef signed char aufs_bindex_t;
+typedef __s8 aufs_bindex_t;
#define AUFS_BRANCH_MAX 127
#else
-typedef short aufs_bindex_t;
+typedef __s16 aufs_bindex_t;
#ifdef CONFIG_AUFS_BRANCH_MAX_511
#define AUFS_BRANCH_MAX 511
#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
#define AUFS_BRANCH_MAX 1023
#elif defined(CONFIG_AUFS_BRANCH_MAX_32767)
#define AUFS_BRANCH_MAX 32767
-#else
+#endif
+#endif
+
+#ifdef __KERNEL__
+#ifndef AUFS_BRANCH_MAX
#error unknown CONFIG_AUFS_BRANCH_MAX value
#endif
#endif
@@ -87,43 +92,83 @@ typedef short aufs_bindex_t;
/* ---------------------------------------------------------------------- */
/* ioctl */
-#if 0 /* reserved for future use */
enum {
- AuCtlErr,
- AuCtlErr_Last
+ /* readdir in userspace */
+ AuCtl_RDU,
+ AuCtl_RDU_INO
};
-enum {
- AuCtl_DIROPQ_GET, AuCtl_DIROPQ_SET,
- AuCtl_MOVE,
- AuCtl_MVDOWN,
-
- /* unimplmented */
- AuCtl_REFRESH, AuCtl_REFRESHV,
- AuCtl_FLUSH_PLINK,
- AuCtl_CPUP,
- AuCtl_CPDOWN
+
+/* borrowed from linux/include/linux/kernel.h */
+#ifndef ALIGN
+#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
+#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
+#endif
+
+/* borrowed from linux/include/linux/compiler-gcc3.h */
+#ifndef __aligned
+#define __aligned(x) __attribute__((aligned(x)))
+#define __packed __attribute__((packed))
+#endif
+
+struct au_rdu_cookie {
+ __u64 h_pos;
+ __s16 bindex;
+ __u8 flags;
+ __u8 pad;
+ __u32 generation;
+} __aligned(8);
+
+struct au_rdu_ent {
+ __u64 ino;
+ __s16 bindex;
+ __u8 type;
+ __u8 nlen;
+ __u8 wh;
+ char name[0];
+} __aligned(8);
+
+static inline int au_rdu_len(int nlen)
+{
+ /* include the terminating NULL */
+ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
+ sizeof(__u64));
+}
+
+union au_rdu_ent_ul {
+ struct au_rdu_ent __user *e;
+ unsigned long ul;
};
-struct aufs_ctl {
- int err;
- aufs_bindex_t bsrc, bdst;
- char *path;
+enum {
+ AufsCtlRduV_SZ,
+ AufsCtlRduV_SZ_PTR,
+ AufsCtlRduV_End
};
+struct aufs_rdu {
+ /* input */
+ union {
+ __u64 sz; /* AuCtl_RDU */
+ __u64 nent; /* AuCtl_RDU_INO */
+ };
+ union au_rdu_ent_ul ent;
+ __u16 verify[AufsCtlRduV_End];
+
+ /* input/output */
+ __u32 blk;
+
+ /* output */
+ union au_rdu_ent_ul tail;
+ /* number of entries which were added in a single call */
+ __u64 rent;
+ __u8 full;
+ __u8 shwh;
+
+ struct au_rdu_cookie cookie;
+} __aligned(8);
+
#define AuCtlType 'A'
-#define AUFS_CTL_DIROPQ_GET _IO(AuCtlType, AuCtl_DIROPQ_GET)
-#define AUFS_CTL_DIROPQ_SET _IOW(AuCtlType, AuCtl_DIROPQ_SET, aufs_bindex_t)
-#define AUFS_CTL_MOVE \
- _IOW(AuCtlType, AuCtl_MVDOWN, aufs_bindex_t)
-#define AUFS_CTL_MVDOWN \
- _IOWR(AuCtlType, AuCtl_MVDOWN, struct aufs_ctl)
-
-#define AUFS_CTL_REFRESH _IO(AuCtlType, AuCtl_REFRESH)
-#define AUFS_CTL_REFRESHV _IO(AuCtlType, AuCtl_REFRESHV)
-#define AUFS_CTL_FLUSH_PLINK _IOR(AuCtlType, AuCtl_FLUSH_PLINK)
-#define AUFS_CTL_CPUP _IOWR(AuCtlType, AuCtl_CPUP, struct aufs_ctl)
-#define AUFS_CTL_CPDOWN \
- _IOWR(AuCtlType, AuCtl_CPDOWN, struct aufs_ctl_cp)
-#endif
+#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
+#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
#endif /* __AUFS_TYPE_H__ */
--
1.6.1.284.g5dc13
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july