introduce iterate_dir() and dir_context
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 15 May 2013 17:52:59 +0000 (13:52 -0400)
committerStricted <info@stricted.net>
Thu, 3 May 2018 16:33:29 +0000 (18:33 +0200)
iterate_dir(): new helper, replacing vfs_readdir().

struct dir_context: contains the readdir callback (and will get more stuff
in it), embedded into whatever data that callback wants to deal with;
eventually, we'll be passing it to ->readdir() replacement instead of
(data,filldir) pair.

Change-Id: Idb3843e77b97d52490b297b1f9e7d7efab18eaef
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Documentation/filesystems/porting
arch/alpha/kernel/osf_sys.c
arch/parisc/hpux/fs.c
fs/compat.c
fs/ecryptfs/file.c
fs/exportfs/expfs.c
fs/nfsd/nfs4recover.c
fs/nfsd/vfs.c
fs/readdir.c
include/linux/fs.h

index 4db22f6491e026fee3ea01da970404c601a60684..85a4a033bae7815e422545273f6826c6e0e36cd8 100644 (file)
@@ -445,3 +445,6 @@ object doesn't exist.  It's remote/distributed ones that might care...
 [mandatory]
        FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
 in your dentry operations instead.
+--
+[mandatory]
+       vfs_readdir() is gone; switch to iterate_dir() instead
index b9e37ad6fa19ca58b762ab0337d0acd8ea6e30f3..ac19c7299d8e1ed2a32edd9f86bec10ab0d1b313 100644 (file)
@@ -96,6 +96,7 @@ struct osf_dirent {
 };
 
 struct osf_dirent_callback {
+       struct dir_context ctx;
        struct osf_dirent __user *dirent;
        long __user *basep;
        unsigned int count;
@@ -155,8 +156,9 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
        buf.basep = basep;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = osf_filldir;
 
-       error = vfs_readdir(arg.file, osf_filldir, &buf);
+       error = iterate_dir(arg.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        if (count != buf.count)
index 838b479a42c4ebf0ea2a1e186a8f08891de37a2e..fc2cbee86e349e77fa85a46376570d67bacd091c 100644 (file)
@@ -60,6 +60,7 @@ struct hpux_dirent {
 };
 
 struct getdents_callback {
+       struct dir_context ctx;
        struct hpux_dirent __user *current_dir;
        struct hpux_dirent __user *previous;
        int count;
@@ -121,8 +122,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = filldir;
 
-       error = vfs_readdir(arg.file, filldir, &buf);
+       error = iterate_dir(arg.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        lastdirent = buf.previous;
index fc3b55dce184a2637fcbf14d1dc313e61714ad5d..2279b59e81f2172efe48f3034dc5e6dbd4e23f12 100644 (file)
@@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
 };
 
 struct compat_readdir_callback {
+       struct dir_context ctx;
        struct compat_old_linux_dirent __user *dirent;
        int result;
 };
@@ -880,8 +881,9 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
 
        buf.result = 0;
        buf.dirent = dirent;
+       buf.ctx.actor = compat_fillonedir;
 
-       error = vfs_readdir(f.file, compat_fillonedir, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (buf.result)
                error = buf.result;
 
@@ -897,6 +899,7 @@ struct compat_linux_dirent {
 };
 
 struct compat_getdents_callback {
+       struct dir_context ctx;
        struct compat_linux_dirent __user *current_dir;
        struct compat_linux_dirent __user *previous;
        int count;
@@ -965,8 +968,9 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = compat_filldir;
 
-       error = vfs_readdir(f.file, compat_filldir, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        lastdirent = buf.previous;
@@ -983,6 +987,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
 #ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
 
 struct compat_getdents_callback64 {
+       struct dir_context ctx;
        struct linux_dirent64 __user *current_dir;
        struct linux_dirent64 __user *previous;
        int count;
@@ -1050,8 +1055,9 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = compat_filldir64;
 
-       error = vfs_readdir(f.file, compat_filldir64, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        lastdirent = buf.previous;
index d4644cc938ba146bbf7be6bdd3c0f2aa02cf9014..fac9d0125fb6957519cad83b7919b4715222a6e9 100644 (file)
@@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
 }
 
 struct ecryptfs_getdents_callback {
+       struct dir_context ctx;
        void *dirent;
        struct dentry *dentry;
        filldir_t filldir;
@@ -126,7 +127,8 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
        buf.filldir = filldir;
        buf.filldir_called = 0;
        buf.entries_written = 0;
-       rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
+       buf.ctx.actor = ecryptfs_filldir;
+       rc = iterate_dir(lower_file, &buf.ctx);
        file->f_pos = lower_file->f_pos;
        if (rc < 0)
                goto out;
index b4eec4c9a790d6ac1a5832ec013589339569fb45..95b32a6fb3b769314d6b81d2b03ce214161cd75f 100644 (file)
@@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
 }
 
 struct getdents_callback {
+       struct dir_context ctx;
        char *name;             /* name that was found. It already points to a
                                   buffer NAME_MAX+1 is size */
        unsigned long ino;      /* the inum we are looking for */
@@ -278,10 +279,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
        buffer.ino = child->d_inode->i_ino;
        buffer.found = 0;
        buffer.sequence = 0;
+       buffer.ctx.actor = filldir_one;
        while (1) {
                int old_seq = buffer.sequence;
 
-               error = vfs_readdir(file, filldir_one, &buffer);
+               error = iterate_dir(file, &buffer.ctx);
                if (buffer.found) {
                        error = 0;
                        break;
index 4e9a21db867ae60afcc14a6ca362e978495c4a5c..4f8cc6ba7c28ea979678439b9a1b8e7ac62cc03a 100644 (file)
@@ -263,7 +263,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
 {
        const struct cred *original_cred;
        struct dentry *dir = nn->rec_file->f_path.dentry;
-       LIST_HEAD(names);
+       struct {
+               struct dir_context ctx;
+               struct list_head names;
+       } ctx;
        int status;
 
        status = nfs4_save_creds(&original_cred);
@@ -276,11 +279,13 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
                return status;
        }
 
-       status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names);
+       INIT_LIST_HEAD(&ctx.names);     
+       ctx.ctx.actor = nfsd4_build_namelist;
+       status = iterate_dir(nn->rec_file, &ctx.ctx);
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-       while (!list_empty(&names)) {
+       while (!list_empty(&ctx.names)) {
                struct name_list *entry;
-               entry = list_entry(names.next, struct name_list, list);
+               entry = list_entry(ctx.names.next, struct name_list, list);
                if (!status) {
                        struct dentry *dentry;
                        dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
index 81325ba8660aedf61b9ddc39acd066154a1d9961..39098d186af12e9252c60c669c45ca9fb76f11de 100644 (file)
@@ -1950,6 +1950,7 @@ struct buffered_dirent {
 };
 
 struct readdir_data {
+       struct dir_context ctx;
        char            *dirent;
        size_t          used;
        int             full;
@@ -1987,6 +1988,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
        int size;
        loff_t offset;
 
+       buf.ctx.actor = nfsd_buffered_filldir;
        buf.dirent = (void *)__get_free_page(GFP_KERNEL);
        if (!buf.dirent)
                return nfserrno(-ENOMEM);
@@ -2001,7 +2003,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
                buf.used = 0;
                buf.full = 0;
 
-               host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
+               host_err = iterate_dir(file, &buf.ctx);
                if (buf.full)
                        host_err = 0;
 
index fee38e04fae4ab09440c05808e539f72133c6976..5b620a2b45e62e2c533eb897d8c58acb91a569aa 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <asm/uaccess.h>
 
-int vfs_readdir(struct file *file, filldir_t filler, void *buf)
+int iterate_dir(struct file *file, struct dir_context *ctx)
 {
        struct inode *inode = file_inode(file);
        int res = -ENOTDIR;
@@ -37,15 +37,14 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 
        res = -ENOENT;
        if (!IS_DEADDIR(inode)) {
-               res = file->f_op->readdir(file, buf, filler);
+               res = file->f_op->readdir(file, ctx, ctx->actor);
                file_accessed(file);
        }
        mutex_unlock(&inode->i_mutex);
 out:
        return res;
 }
-
-EXPORT_SYMBOL(vfs_readdir);
+EXPORT_SYMBOL(iterate_dir);
 
 /*
  * Traditional linux readdir() handling..
@@ -66,6 +65,7 @@ struct old_linux_dirent {
 };
 
 struct readdir_callback {
+       struct dir_context ctx;
        struct old_linux_dirent __user * dirent;
        int result;
 };
@@ -73,7 +73,7 @@ struct readdir_callback {
 static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
                      u64 ino, unsigned int d_type)
 {
-       struct readdir_callback * buf = (struct readdir_callback *) __buf;
+       struct readdir_callback *buf = (struct readdir_callback *) __buf;
        struct old_linux_dirent __user * dirent;
        unsigned long d_ino;
 
@@ -112,10 +112,11 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
        if (!f.file)
                return -EBADF;
 
+       buf.ctx.actor = fillonedir;
        buf.result = 0;
        buf.dirent = dirent;
 
-       error = vfs_readdir(f.file, fillonedir, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (buf.result)
                error = buf.result;
 
@@ -137,6 +138,7 @@ struct linux_dirent {
 };
 
 struct getdents_callback {
+       struct dir_context ctx;
        struct linux_dirent __user * current_dir;
        struct linux_dirent __user * previous;
        int count;
@@ -205,8 +207,9 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = filldir;
 
-       error = vfs_readdir(f.file, filldir, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        lastdirent = buf.previous;
@@ -221,6 +224,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
 }
 
 struct getdents_callback64 {
+       struct dir_context ctx;
        struct linux_dirent64 __user * current_dir;
        struct linux_dirent64 __user * previous;
        int count;
@@ -285,8 +289,9 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
+       buf.ctx.actor = filldir64;
 
-       error = vfs_readdir(f.file, filldir64, &buf);
+       error = iterate_dir(f.file, &buf.ctx);
        if (error >= 0)
                error = buf.error;
        lastdirent = buf.previous;
index 22e368d32c6caa3888adce876705707a0e950a35..75327e6dc2d8bb92b400f4b79764378d31042cd1 100644 (file)
@@ -1506,6 +1506,9 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
  * to have different dirent layouts depending on the binary type.
  */
 typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
+struct dir_context {
+       filldir_t actor;
+};
 struct block_device_operations;
 
 /* These macros are for out of kernel modules to test that
@@ -2504,6 +2507,7 @@ loff_t inode_get_bytes(struct inode *inode);
 void inode_set_bytes(struct inode *inode, loff_t bytes);
 
 extern int vfs_readdir(struct file *, filldir_t, void *);
+extern int iterate_dir(struct file *, struct dir_context *);
 
 extern int vfs_stat(const char __user *, struct kstat *);
 extern int vfs_lstat(const char __user *, struct kstat *);