- 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

Reply via email to