[readdir] convert procfs
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 16 May 2013 16:07:31 +0000 (12:07 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 29 Jun 2013 08:56:32 +0000 (12:56 +0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/hppfs/hppfs.c
fs/proc/base.c
fs/proc/fd.c
fs/proc/generic.c
fs/proc/internal.h
fs/proc/namespaces.c
fs/proc/proc_net.c
fs/proc/proc_sysctl.c
fs/proc/root.c

index cd3e38972c86a8ae27ed8abfcb90e8466eac3490..fc90ab11c34049e6431e0b9dcf220040cfbbb146 100644 (file)
@@ -542,8 +542,8 @@ static const struct file_operations hppfs_file_fops = {
 };
 
 struct hppfs_dirent {
-       void *vfs_dirent;
-       filldir_t filldir;
+       struct dir_context ctx;
+       struct dir_context *caller;
        struct dentry *dentry;
 };
 
@@ -555,34 +555,29 @@ static int hppfs_filldir(void *d, const char *name, int size,
        if (file_removed(dirent->dentry, name))
                return 0;
 
-       return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset,
-                                 inode, type);
+       dirent->caller->pos = dirent->ctx.pos;
+       return !dir_emit(dirent->caller, name, size, inode, type);
 }
 
-static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
+static int hppfs_readdir(struct file *file, struct dir_context *ctx)
 {
        struct hppfs_private *data = file->private_data;
        struct file *proc_file = data->proc_file;
-       int (*readdir)(struct file *, void *, filldir_t);
-       struct hppfs_dirent dirent = ((struct hppfs_dirent)
-                                     { .vfs_dirent     = ent,
-                                       .filldir        = filldir,
-                                       .dentry         = file->f_path.dentry
-                                     });
+       struct hppfs_dirent d = {
+               .ctx.actor      = hppfs_filldir,
+               .caller         = ctx,
+               .dentry         = file->f_path.dentry
+       };
        int err;
-
-       readdir = file_inode(proc_file)->i_fop->readdir;
-
-       proc_file->f_pos = file->f_pos;
-       err = (*readdir)(proc_file, &dirent, hppfs_filldir);
-       file->f_pos = proc_file->f_pos;
-
+       proc_file->f_pos = ctx->pos;
+       err = iterate_dir(proc_file, &d.ctx);
+       ctx->pos = d.ctx.pos;
        return err;
 }
 
 static const struct file_operations hppfs_dir_fops = {
        .owner          = NULL,
-       .readdir        = hppfs_readdir,
+       .iterate        = hppfs_readdir,
        .open           = hppfs_dir_open,
        .llseek         = default_llseek,
        .release        = hppfs_release,
index c3834dad09b3bce4dccec2180478d852ffddb70d..0016350ad95e13a646978f8d3f19fb1afa145424 100644 (file)
@@ -1681,11 +1681,11 @@ const struct dentry_operations pid_dentry_operations =
  * reported by readdir in sync with the inode numbers reported
  * by stat.
  */
-int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+bool proc_fill_cache(struct file *file, struct dir_context *ctx,
        const char *name, int len,
        instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
-       struct dentry *child, *dir = filp->f_path.dentry;
+       struct dentry *child, *dir = file->f_path.dentry;
        struct inode *inode;
        struct qstr qname;
        ino_t ino = 0;
@@ -1720,7 +1720,7 @@ end_instantiate:
                ino = find_inode_number(dir, &qname);
        if (!ino)
                ino = 1;
-       return filldir(dirent, name, len, filp->f_pos, ino, type);
+       return dir_emit(ctx, name, len, ino, type);
 }
 
 #ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1931,14 +1931,15 @@ static const struct inode_operations proc_map_files_inode_operations = {
 };
 
 static int
-proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
+proc_map_files_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
        struct vm_area_struct *vma;
        struct task_struct *task;
        struct mm_struct *mm;
-       ino_t ino;
+       unsigned long nr_files, pos, i;
+       struct flex_array *fa = NULL;
+       struct map_files_info info;
+       struct map_files_info *p;
        int ret;
 
        ret = -EPERM;
@@ -1946,7 +1947,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
                goto out;
 
        ret = -ENOENT;
-       task = get_proc_task(inode);
+       task = get_proc_task(file_inode(file));
        if (!task)
                goto out;
 
@@ -1955,91 +1956,73 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
                goto out_put_task;
 
        ret = 0;
-       switch (filp->f_pos) {
-       case 0:
-               ino = inode->i_ino;
-               if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0)
-                       goto out_put_task;
-               filp->f_pos++;
-       case 1:
-               ino = parent_ino(dentry);
-               if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
-                       goto out_put_task;
-               filp->f_pos++;
-       default:
-       {
-               unsigned long nr_files, pos, i;
-               struct flex_array *fa = NULL;
-               struct map_files_info info;
-               struct map_files_info *p;
-
-               mm = get_task_mm(task);
-               if (!mm)
-                       goto out_put_task;
-               down_read(&mm->mmap_sem);
+       if (!dir_emit_dots(file, ctx))
+               goto out_put_task;
 
-               nr_files = 0;
+       mm = get_task_mm(task);
+       if (!mm)
+               goto out_put_task;
+       down_read(&mm->mmap_sem);
 
-               /*
-                * We need two passes here:
-                *
-                *  1) Collect vmas of mapped files with mmap_sem taken
-                *  2) Release mmap_sem and instantiate entries
-                *
-                * otherwise we get lockdep complained, since filldir()
-                * routine might require mmap_sem taken in might_fault().
-                */
+       nr_files = 0;
 
-               for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
-                       if (vma->vm_file && ++pos > filp->f_pos)
-                               nr_files++;
-               }
+       /*
+        * We need two passes here:
+        *
+        *  1) Collect vmas of mapped files with mmap_sem taken
+        *  2) Release mmap_sem and instantiate entries
+        *
+        * otherwise we get lockdep complained, since filldir()
+        * routine might require mmap_sem taken in might_fault().
+        */
 
-               if (nr_files) {
-                       fa = flex_array_alloc(sizeof(info), nr_files,
-                                               GFP_KERNEL);
-                       if (!fa || flex_array_prealloc(fa, 0, nr_files,
-                                                       GFP_KERNEL)) {
-                               ret = -ENOMEM;
-                               if (fa)
-                                       flex_array_free(fa);
-                               up_read(&mm->mmap_sem);
-                               mmput(mm);
-                               goto out_put_task;
-                       }
-                       for (i = 0, vma = mm->mmap, pos = 2; vma;
-                                       vma = vma->vm_next) {
-                               if (!vma->vm_file)
-                                       continue;
-                               if (++pos <= filp->f_pos)
-                                       continue;
-
-                               info.mode = vma->vm_file->f_mode;
-                               info.len = snprintf(info.name,
-                                               sizeof(info.name), "%lx-%lx",
-                                               vma->vm_start, vma->vm_end);
-                               if (flex_array_put(fa, i++, &info, GFP_KERNEL))
-                                       BUG();
-                       }
+       for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
+               if (vma->vm_file && ++pos > ctx->pos)
+                       nr_files++;
+       }
+
+       if (nr_files) {
+               fa = flex_array_alloc(sizeof(info), nr_files,
+                                       GFP_KERNEL);
+               if (!fa || flex_array_prealloc(fa, 0, nr_files,
+                                               GFP_KERNEL)) {
+                       ret = -ENOMEM;
+                       if (fa)
+                               flex_array_free(fa);
+                       up_read(&mm->mmap_sem);
+                       mmput(mm);
+                       goto out_put_task;
                }
-               up_read(&mm->mmap_sem);
-
-               for (i = 0; i < nr_files; i++) {
-                       p = flex_array_get(fa, i);
-                       ret = proc_fill_cache(filp, dirent, filldir,
-                                             p->name, p->len,
-                                             proc_map_files_instantiate,
-                                             task,
-                                             (void *)(unsigned long)p->mode);
-                       if (ret)
-                               break;
-                       filp->f_pos++;
+               for (i = 0, vma = mm->mmap, pos = 2; vma;
+                               vma = vma->vm_next) {
+                       if (!vma->vm_file)
+                               continue;
+                       if (++pos <= ctx->pos)
+                               continue;
+
+                       info.mode = vma->vm_file->f_mode;
+                       info.len = snprintf(info.name,
+                                       sizeof(info.name), "%lx-%lx",
+                                       vma->vm_start, vma->vm_end);
+                       if (flex_array_put(fa, i++, &info, GFP_KERNEL))
+                               BUG();
                }
-               if (fa)
-                       flex_array_free(fa);
-               mmput(mm);
        }
+       up_read(&mm->mmap_sem);
+
+       for (i = 0; i < nr_files; i++) {
+               p = flex_array_get(fa, i);
+               if (!proc_fill_cache(file, ctx,
+                                     p->name, p->len,
+                                     proc_map_files_instantiate,
+                                     task,
+                                     (void *)(unsigned long)p->mode))
+                       break;
+               ctx->pos++;
        }
+       if (fa)
+               flex_array_free(fa);
+       mmput(mm);
 
 out_put_task:
        put_task_struct(task);
@@ -2049,7 +2032,7 @@ out:
 
 static const struct file_operations proc_map_files_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_map_files_readdir,
+       .iterate        = proc_map_files_readdir,
        .llseek         = default_llseek,
 };
 
@@ -2217,67 +2200,30 @@ out_no_task:
        return error;
 }
 
-static int proc_pident_fill_cache(struct file *filp, void *dirent,
-       filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
-{
-       return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
-                               proc_pident_instantiate, task, p);
-}
-
-static int proc_pident_readdir(struct file *filp,
-               void *dirent, filldir_t filldir,
+static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
                const struct pid_entry *ents, unsigned int nents)
 {
-       int i;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task = get_proc_task(inode);
-       const struct pid_entry *p, *last;
-       ino_t ino;
-       int ret;
+       struct task_struct *task = get_proc_task(file_inode(file));
+       const struct pid_entry *p;
 
-       ret = -ENOENT;
        if (!task)
-               goto out_no_task;
+               return -ENOENT;
 
-       ret = 0;
-       i = filp->f_pos;
-       switch (i) {
-       case 0:
-               ino = inode->i_ino;
-               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       case 1:
-               ino = parent_ino(dentry);
-               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       default:
-               i -= 2;
-               if (i >= nents) {
-                       ret = 1;
-                       goto out;
-               }
-               p = ents + i;
-               last = &ents[nents - 1];
-               while (p <= last) {
-                       if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
-                               goto out;
-                       filp->f_pos++;
-                       p++;
-               }
-       }
+       if (!dir_emit_dots(file, ctx))
+               goto out;
+
+       if (ctx->pos >= nents + 2)
+               goto out;
 
-       ret = 1;
+       for (p = ents + (ctx->pos - 2); p <= ents + nents - 1; p++) {
+               if (!proc_fill_cache(file, ctx, p->name, p->len,
+                               proc_pident_instantiate, task, p))
+                       break;
+               ctx->pos++;
+       }
 out:
        put_task_struct(task);
-out_no_task:
-       return ret;
+       return 0;
 }
 
 #ifdef CONFIG_SECURITY
@@ -2362,16 +2308,15 @@ static const struct pid_entry attr_dir_stuff[] = {
        REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
 };
 
-static int proc_attr_dir_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
+static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
 {
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
+       return proc_pident_readdir(file, ctx, 
+                                  attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
 }
 
 static const struct file_operations proc_attr_dir_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_attr_dir_readdir,
+       .iterate        = proc_attr_dir_readdir,
        .llseek         = default_llseek,
 };
 
@@ -2725,16 +2670,15 @@ static const struct pid_entry tgid_base_stuff[] = {
 #endif
 };
 
-static int proc_tgid_base_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
+static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
 {
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
+       return proc_pident_readdir(file, ctx,
+                                  tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
 }
 
 static const struct file_operations proc_tgid_base_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_tgid_base_readdir,
+       .iterate        = proc_tgid_base_readdir,
        .llseek         = default_llseek,
 };
 
@@ -2936,58 +2880,42 @@ retry:
 
 #define TGID_OFFSET (FIRST_PROCESS_ENTRY + 1)
 
-static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
-       struct tgid_iter iter)
-{
-       char name[PROC_NUMBUF];
-       int len = snprintf(name, sizeof(name), "%d", iter.tgid);
-       return proc_fill_cache(filp, dirent, filldir, name, len,
-                               proc_pid_instantiate, iter.task, NULL);
-}
-
-static int fake_filldir(void *buf, const char *name, int namelen,
-                       loff_t offset, u64 ino, unsigned d_type)
-{
-       return 0;
-}
-
 /* for the /proc/ directory itself, after non-process stuff has been done */
-int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
+int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 {
        struct tgid_iter iter;
        struct pid_namespace *ns;
-       filldir_t __filldir;
-       loff_t pos = filp->f_pos;
+       loff_t pos = ctx->pos;
 
        if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
-               goto out;
+               return 0;
 
        if (pos == TGID_OFFSET - 1) {
-               if (proc_fill_cache(filp, dirent, filldir, "self", 4,
-                                       NULL, NULL, NULL) < 0)
-                       goto out;
+               if (!proc_fill_cache(file, ctx, "self", 4, NULL, NULL, NULL))
+                       return 0;
                iter.tgid = 0;
        } else {
                iter.tgid = pos - TGID_OFFSET;
        }
        iter.task = NULL;
-       ns = filp->f_dentry->d_sb->s_fs_info;
+       ns = file->f_dentry->d_sb->s_fs_info;
        for (iter = next_tgid(ns, iter);
             iter.task;
             iter.tgid += 1, iter = next_tgid(ns, iter)) {
-               if (has_pid_permissions(ns, iter.task, 2))
-                       __filldir = filldir;
-               else
-                       __filldir = fake_filldir;
+               char name[PROC_NUMBUF];
+               int len;
+               if (!has_pid_permissions(ns, iter.task, 2))
+                       continue;
 
-               filp->f_pos = iter.tgid + TGID_OFFSET;
-               if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) {
+               len = snprintf(name, sizeof(name), "%d", iter.tgid);
+               ctx->pos = iter.tgid + TGID_OFFSET;
+               if (!proc_fill_cache(file, ctx, name, len,
+                                    proc_pid_instantiate, iter.task, NULL)) {
                        put_task_struct(iter.task);
-                       goto out;
+                       return 0;
                }
        }
-       filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
-out:
+       ctx->pos = PID_MAX_LIMIT + TGID_OFFSET;
        return 0;
 }
 
@@ -3075,11 +3003,10 @@ static const struct pid_entry tid_base_stuff[] = {
 #endif
 };
 
-static int proc_tid_base_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
+static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
 {
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
+       return proc_pident_readdir(file, ctx,
+                                  tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
 }
 
 static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
@@ -3090,7 +3017,7 @@ static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *den
 
 static const struct file_operations proc_tid_base_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_tid_base_readdir,
+       .iterate        = proc_tid_base_readdir,
        .llseek         = default_llseek,
 };
 
@@ -3231,30 +3158,16 @@ static struct task_struct *next_tid(struct task_struct *start)
        return pos;
 }
 
-static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
-       struct task_struct *task, int tid)
-{
-       char name[PROC_NUMBUF];
-       int len = snprintf(name, sizeof(name), "%d", tid);
-       return proc_fill_cache(filp, dirent, filldir, name, len,
-                               proc_task_instantiate, task, NULL);
-}
-
 /* for the /proc/TGID/task/ directories */
-static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
+static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
        struct task_struct *leader = NULL;
-       struct task_struct *task;
-       int retval = -ENOENT;
-       ino_t ino;
-       int tid;
+       struct task_struct *task = get_proc_task(file_inode(file));
        struct pid_namespace *ns;
+       int tid;
 
-       task = get_proc_task(inode);
        if (!task)
-               goto out_no_task;
+               return -ENOENT;
        rcu_read_lock();
        if (pid_alive(task)) {
                leader = task->group_leader;
@@ -3263,46 +3176,36 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
        rcu_read_unlock();
        put_task_struct(task);
        if (!leader)
-               goto out_no_task;
-       retval = 0;
+               return -ENOENT;
 
-       switch ((unsigned long)filp->f_pos) {
-       case 0:
-               ino = inode->i_ino;
-               if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
-                       goto out;
-               filp->f_pos++;
-               /* fall through */
-       case 1:
-               ino = parent_ino(dentry);
-               if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) < 0)
-                       goto out;
-               filp->f_pos++;
-               /* fall through */
-       }
+       if (!dir_emit_dots(file, ctx))
+               goto out;
 
        /* f_version caches the tgid value that the last readdir call couldn't
         * return. lseek aka telldir automagically resets f_version to 0.
         */
-       ns = filp->f_dentry->d_sb->s_fs_info;
-       tid = (int)filp->f_version;
-       filp->f_version = 0;
-       for (task = first_tid(leader, tid, filp->f_pos - 2, ns);
+       ns = file->f_dentry->d_sb->s_fs_info;
+       tid = (int)file->f_version;
+       file->f_version = 0;
+       for (task = first_tid(leader, tid, ctx->pos - 2, ns);
             task;
-            task = next_tid(task), filp->f_pos++) {
+            task = next_tid(task), ctx->pos++) {
+               char name[PROC_NUMBUF];
+               int len;
                tid = task_pid_nr_ns(task, ns);
-               if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
+               len = snprintf(name, sizeof(name), "%d", tid);
+               if (!proc_fill_cache(file, ctx, name, len,
+                               proc_task_instantiate, task, NULL)) {
                        /* returning this tgid failed, save it as the first
                         * pid for the next readir call */
-                       filp->f_version = (u64)tid;
+                       file->f_version = (u64)tid;
                        put_task_struct(task);
                        break;
                }
        }
 out:
        put_task_struct(leader);
-out_no_task:
-       return retval;
+       return 0;
 }
 
 static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
@@ -3328,6 +3231,6 @@ static const struct inode_operations proc_task_inode_operations = {
 
 static const struct file_operations proc_task_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_task_readdir,
+       .iterate        = proc_task_readdir,
        .llseek         = default_llseek,
 };
index d7a4a28ef63024c66ef862594701d1e389e77a47..1441f143c43b6d187f5d6f2b181118148d2501e5 100644 (file)
@@ -219,74 +219,58 @@ out_no_task:
        return result;
 }
 
-static int proc_readfd_common(struct file * filp, void * dirent,
-                             filldir_t filldir, instantiate_t instantiate)
+static int proc_readfd_common(struct file *file, struct dir_context *ctx,
+                             instantiate_t instantiate)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *p = get_proc_task(inode);
+       struct task_struct *p = get_proc_task(file_inode(file));
        struct files_struct *files;
-       unsigned int fd, ino;
-       int retval;
+       unsigned int fd;
 
-       retval = -ENOENT;
        if (!p)
-               goto out_no_task;
-       retval = 0;
-
-       fd = filp->f_pos;
-       switch (fd) {
-               case 0:
-                       if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
-                               goto out;
-                       filp->f_pos++;
-               case 1:
-                       ino = parent_ino(dentry);
-                       if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
-                               goto out;
-                       filp->f_pos++;
-               default:
-                       files = get_files_struct(p);
-                       if (!files)
-                               goto out;
-                       rcu_read_lock();
-                       for (fd = filp->f_pos - 2;
-                            fd < files_fdtable(files)->max_fds;
-                            fd++, filp->f_pos++) {
-                               char name[PROC_NUMBUF];
-                               int len;
-                               int rv;
-
-                               if (!fcheck_files(files, fd))
-                                       continue;
-                               rcu_read_unlock();
+               return -ENOENT;
 
-                               len = snprintf(name, sizeof(name), "%d", fd);
-                               rv = proc_fill_cache(filp, dirent, filldir,
-                                                    name, len, instantiate, p,
-                                                    (void *)(unsigned long)fd);
-                               if (rv < 0)
-                                       goto out_fd_loop;
-                               rcu_read_lock();
-                       }
-                       rcu_read_unlock();
-out_fd_loop:
-                       put_files_struct(files);
+       if (!dir_emit_dots(file, ctx))
+               goto out;
+       if (!dir_emit_dots(file, ctx))
+               goto out;
+       files = get_files_struct(p);
+       if (!files)
+               goto out;
+
+       rcu_read_lock();
+       for (fd = ctx->pos - 2;
+            fd < files_fdtable(files)->max_fds;
+            fd++, ctx->pos++) {
+               char name[PROC_NUMBUF];
+               int len;
+
+               if (!fcheck_files(files, fd))
+                       continue;
+               rcu_read_unlock();
+
+               len = snprintf(name, sizeof(name), "%d", fd);
+               if (!proc_fill_cache(file, ctx,
+                                    name, len, instantiate, p,
+                                    (void *)(unsigned long)fd))
+                       goto out_fd_loop;
+               rcu_read_lock();
        }
+       rcu_read_unlock();
+out_fd_loop:
+       put_files_struct(files);
 out:
        put_task_struct(p);
-out_no_task:
-       return retval;
+       return 0;
 }
 
-static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
+static int proc_readfd(struct file *file, struct dir_context *ctx)
 {
-       return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
+       return proc_readfd_common(file, ctx, proc_fd_instantiate);
 }
 
 const struct file_operations proc_fd_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_readfd,
+       .iterate        = proc_readfd,
        .llseek         = default_llseek,
 };
 
@@ -351,9 +335,9 @@ proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)
        return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
 }
 
-static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+static int proc_readfdinfo(struct file *file, struct dir_context *ctx)
 {
-       return proc_readfd_common(filp, dirent, filldir,
+       return proc_readfd_common(file, ctx,
                                  proc_fdinfo_instantiate);
 }
 
@@ -364,6 +348,6 @@ const struct inode_operations proc_fdinfo_inode_operations = {
 
 const struct file_operations proc_fdinfo_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_readfdinfo,
+       .iterate        = proc_readfdinfo,
        .llseek         = default_llseek,
 };
index a2596afffae6dad430f8cb2727628e162c567876..94441a407337bb02fb77e89fe93dfbbed169f827 100644 (file)
@@ -233,76 +233,52 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
  * value of the readdir() call, as long as it's non-negative
  * for success..
  */
-int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
-               filldir_t filldir)
+int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
+                   struct dir_context *ctx)
 {
-       unsigned int ino;
        int i;
-       struct inode *inode = file_inode(filp);
-       int ret = 0;
-
-       ino = inode->i_ino;
-       i = filp->f_pos;
-       switch (i) {
-               case 0:
-                       if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-                               goto out;
-                       i++;
-                       filp->f_pos++;
-                       /* fall through */
-               case 1:
-                       if (filldir(dirent, "..", 2, i,
-                                   parent_ino(filp->f_path.dentry),
-                                   DT_DIR) < 0)
-                               goto out;
-                       i++;
-                       filp->f_pos++;
-                       /* fall through */
-               default:
-                       spin_lock(&proc_subdir_lock);
-                       de = de->subdir;
-                       i -= 2;
-                       for (;;) {
-                               if (!de) {
-                                       ret = 1;
-                                       spin_unlock(&proc_subdir_lock);
-                                       goto out;
-                               }
-                               if (!i)
-                                       break;
-                               de = de->next;
-                               i--;
-                       }
 
-                       do {
-                               struct proc_dir_entry *next;
-
-                               /* filldir passes info to user space */
-                               pde_get(de);
-                               spin_unlock(&proc_subdir_lock);
-                               if (filldir(dirent, de->name, de->namelen, filp->f_pos,
-                                           de->low_ino, de->mode >> 12) < 0) {
-                                       pde_put(de);
-                                       goto out;
-                               }
-                               spin_lock(&proc_subdir_lock);
-                               filp->f_pos++;
-                               next = de->next;
-                               pde_put(de);
-                               de = next;
-                       } while (de);
+       if (!dir_emit_dots(file, ctx))
+               return 0;
+
+       spin_lock(&proc_subdir_lock);
+       de = de->subdir;
+       i = ctx->pos - 2;
+       for (;;) {
+               if (!de) {
                        spin_unlock(&proc_subdir_lock);
+                       return 0;
+               }
+               if (!i)
+                       break;
+               de = de->next;
+               i--;
        }
-       ret = 1;
-out:
-       return ret;     
+
+       do {
+               struct proc_dir_entry *next;
+               pde_get(de);
+               spin_unlock(&proc_subdir_lock);
+               if (!dir_emit(ctx, de->name, de->namelen,
+                           de->low_ino, de->mode >> 12)) {
+                       pde_put(de);
+                       return 0;
+               }
+               spin_lock(&proc_subdir_lock);
+               ctx->pos++;
+               next = de->next;
+               pde_put(de);
+               de = next;
+       } while (de);
+       spin_unlock(&proc_subdir_lock);
+       return 0;
 }
 
-int proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
+int proc_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = file_inode(file);
 
-       return proc_readdir_de(PDE(inode), filp, dirent, filldir);
+       return proc_readdir_de(PDE(inode), file, ctx);
 }
 
 /*
@@ -313,7 +289,7 @@ int proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
 static const struct file_operations proc_dir_operations = {
        .llseek                 = generic_file_llseek,
        .read                   = generic_read_dir,
-       .readdir                = proc_readdir,
+       .iterate                = proc_readdir,
 };
 
 /*
index d600fb098b6ad3ad51d227709d43161d8a9d0abc..4eae2e149f31c05bb2d802c05f64bf91afdd4d29 100644 (file)
@@ -165,14 +165,14 @@ extern int proc_setattr(struct dentry *, struct iattr *);
 extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *);
 extern int pid_revalidate(struct dentry *, unsigned int);
 extern int pid_delete_dentry(const struct dentry *);
-extern int proc_pid_readdir(struct file *, void *, filldir_t);
+extern int proc_pid_readdir(struct file *, struct dir_context *);
 extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int);
 extern loff_t mem_lseek(struct file *, loff_t, int);
 
 /* Lookups */
 typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
                                     struct task_struct *, const void *);
-extern int proc_fill_cache(struct file *, void *, filldir_t, const char *, int,
+extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int,
                           instantiate_t, struct task_struct *, const void *);
 
 /*
@@ -183,8 +183,8 @@ extern spinlock_t proc_subdir_lock;
 extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int);
 extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *,
                                     struct dentry *);
-extern int proc_readdir(struct file *, void *, filldir_t);
-extern int proc_readdir_de(struct proc_dir_entry *, struct file *, void *, filldir_t);
+extern int proc_readdir(struct file *, struct dir_context *);
+extern int proc_readdir_de(struct proc_dir_entry *, struct file *, struct dir_context *);
 
 static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
 {
index 54bdc6701e9fd785ddc14c277a48ff455683d773..f6abbbbfad8a765d115013ae65b07632b7e15258 100644 (file)
@@ -213,74 +213,36 @@ out:
        return error;
 }
 
-static int proc_ns_fill_cache(struct file *filp, void *dirent,
-       filldir_t filldir, struct task_struct *task,
-       const struct proc_ns_operations *ops)
+static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
 {
-       return proc_fill_cache(filp, dirent, filldir,
-                               ops->name, strlen(ops->name),
-                               proc_ns_instantiate, task, ops);
-}
-
-static int proc_ns_dir_readdir(struct file *filp, void *dirent,
-                               filldir_t filldir)
-{
-       int i;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task = get_proc_task(inode);
+       struct task_struct *task = get_proc_task(file_inode(file));
        const struct proc_ns_operations **entry, **last;
-       ino_t ino;
-       int ret;
 
-       ret = -ENOENT;
        if (!task)
-               goto out_no_task;
+               return -ENOENT;
 
-       ret = 0;
-       i = filp->f_pos;
-       switch (i) {
-       case 0:
-               ino = inode->i_ino;
-               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       case 1:
-               ino = parent_ino(dentry);
-               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       default:
-               i -= 2;
-               if (i >= ARRAY_SIZE(ns_entries)) {
-                       ret = 1;
-                       goto out;
-               }
-               entry = ns_entries + i;
-               last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
-               while (entry <= last) {
-                       if (proc_ns_fill_cache(filp, dirent, filldir,
-                                               task, *entry) < 0)
-                               goto out;
-                       filp->f_pos++;
-                       entry++;
-               }
+       if (!dir_emit_dots(file, ctx))
+               goto out;
+       if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))
+               goto out;
+       entry = ns_entries + (ctx->pos - 2);
+       last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
+       while (entry <= last) {
+               const struct proc_ns_operations *ops = *entry;
+               if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),
+                                    proc_ns_instantiate, task, ops))
+                       break;
+               ctx->pos++;
+               entry++;
        }
-
-       ret = 1;
 out:
        put_task_struct(task);
-out_no_task:
-       return ret;
+       return 0;
 }
 
 const struct file_operations proc_ns_dir_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_ns_dir_readdir,
+       .iterate        = proc_ns_dir_readdir,
 };
 
 static struct dentry *proc_ns_dir_lookup(struct inode *dir,
index 986e83220d56e57524b533acb8e6a52a6cffe612..4677bb7dc7c29cda9d7eb5825b86044851dbca6c 100644 (file)
@@ -160,16 +160,15 @@ const struct inode_operations proc_net_inode_operations = {
        .getattr        = proc_tgid_net_getattr,
 };
 
-static int proc_tgid_net_readdir(struct file *filp, void *dirent,
-               filldir_t filldir)
+static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)
 {
        int ret;
        struct net *net;
 
        ret = -EINVAL;
-       net = get_proc_task_net(file_inode(filp));
+       net = get_proc_task_net(file_inode(file));
        if (net != NULL) {
-               ret = proc_readdir_de(net->proc_net, filp, dirent, filldir);
+               ret = proc_readdir_de(net->proc_net, file, ctx);
                put_net(net);
        }
        return ret;
@@ -178,7 +177,7 @@ static int proc_tgid_net_readdir(struct file *filp, void *dirent,
 const struct file_operations proc_net_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
-       .readdir        = proc_tgid_net_readdir,
+       .iterate        = proc_tgid_net_readdir,
 };
 
 static __net_init int proc_net_ns_init(struct net *net)
index ac05f33a0dde360aebbcacd9d02df8a8b927797a..f3a570e7c2575a723b5ac4061c1dd7aca1cb80c8 100644 (file)
@@ -573,12 +573,12 @@ out:
        return ret;
 }
 
-static int proc_sys_fill_cache(struct file *filp, void *dirent,
-                               filldir_t filldir,
+static bool proc_sys_fill_cache(struct file *file,
+                               struct dir_context *ctx,
                                struct ctl_table_header *head,
                                struct ctl_table *table)
 {
-       struct dentry *child, *dir = filp->f_path.dentry;
+       struct dentry *child, *dir = file->f_path.dentry;
        struct inode *inode;
        struct qstr qname;
        ino_t ino = 0;
@@ -595,38 +595,38 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent,
                        inode = proc_sys_make_inode(dir->d_sb, head, table);
                        if (!inode) {
                                dput(child);
-                               return -ENOMEM;
+                               return false;
                        } else {
                                d_set_d_op(child, &proc_sys_dentry_operations);
                                d_add(child, inode);
                        }
                } else {
-                       return -ENOMEM;
+                       return false;
                }
        }
        inode = child->d_inode;
        ino  = inode->i_ino;
        type = inode->i_mode >> 12;
        dput(child);
-       return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
+       return dir_emit(ctx, qname.name, qname.len, ino, type);
 }
 
-static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
-                                   filldir_t filldir,
+static bool proc_sys_link_fill_cache(struct file *file,
+                                   struct dir_context *ctx,
                                    struct ctl_table_header *head,
                                    struct ctl_table *table)
 {
-       int err, ret = 0;
+       bool ret = true;
        head = sysctl_head_grab(head);
 
        if (S_ISLNK(table->mode)) {
                /* It is not an error if we can not follow the link ignore it */
-               err = sysctl_follow_link(&head, &table, current->nsproxy);
+               int err = sysctl_follow_link(&head, &table, current->nsproxy);
                if (err)
                        goto out;
        }
 
-       ret = proc_sys_fill_cache(filp, dirent, filldir, head, table);
+       ret = proc_sys_fill_cache(file, ctx, head, table);
 out:
        sysctl_head_finish(head);
        return ret;
@@ -634,67 +634,50 @@ out:
 
 static int scan(struct ctl_table_header *head, ctl_table *table,
                unsigned long *pos, struct file *file,
-               void *dirent, filldir_t filldir)
+               struct dir_context *ctx)
 {
-       int res;
+       bool res;
 
-       if ((*pos)++ < file->f_pos)
-               return 0;
+       if ((*pos)++ < ctx->pos)
+               return true;
 
        if (unlikely(S_ISLNK(table->mode)))
-               res = proc_sys_link_fill_cache(file, dirent, filldir, head, table);
+               res = proc_sys_link_fill_cache(file, ctx, head, table);
        else
-               res = proc_sys_fill_cache(file, dirent, filldir, head, table);
+               res = proc_sys_fill_cache(file, ctx, head, table);
 
-       if (res == 0)
-               file->f_pos = *pos;
+       if (res)
+               ctx->pos = *pos;
 
        return res;
 }
 
-static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct ctl_table_header *head = grab_header(inode);
+       struct ctl_table_header *head = grab_header(file_inode(file));
        struct ctl_table_header *h = NULL;
        struct ctl_table *entry;
        struct ctl_dir *ctl_dir;
        unsigned long pos;
-       int ret = -EINVAL;
 
        if (IS_ERR(head))
                return PTR_ERR(head);
 
        ctl_dir = container_of(head, struct ctl_dir, header);
 
-       ret = 0;
-       /* Avoid a switch here: arm builds fail with missing __cmpdi2 */
-       if (filp->f_pos == 0) {
-               if (filldir(dirent, ".", 1, filp->f_pos,
-                               inode->i_ino, DT_DIR) < 0)
-                       goto out;
-               filp->f_pos++;
-       }
-       if (filp->f_pos == 1) {
-               if (filldir(dirent, "..", 2, filp->f_pos,
-                               parent_ino(dentry), DT_DIR) < 0)
-                       goto out;
-               filp->f_pos++;
-       }
+       if (!dir_emit_dots(file, ctx))
+               return 0;
+
        pos = 2;
 
        for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
-               ret = scan(h, entry, &pos, filp, dirent, filldir);
-               if (ret) {
+               if (!scan(h, entry, &pos, file, ctx)) {
                        sysctl_head_finish(h);
                        break;
                }
        }
-       ret = 1;
-out:
        sysctl_head_finish(head);
-       return ret;
+       return 0;
 }
 
 static int proc_sys_permission(struct inode *inode, int mask)
@@ -769,7 +752,7 @@ static const struct file_operations proc_sys_file_operations = {
 
 static const struct file_operations proc_sys_dir_file_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_sys_readdir,
+       .iterate        = proc_sys_readdir,
        .llseek         = generic_file_llseek,
 };
 
index 41a6ea93f486ff81b6b112821339a66f0b020324..229e366598daecd4e905e8f51f13efaf0a44e773 100644 (file)
@@ -202,21 +202,14 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
        return proc_pid_lookup(dir, dentry, flags);
 }
 
-static int proc_root_readdir(struct file * filp,
-       void * dirent, filldir_t filldir)
+static int proc_root_readdir(struct file *file, struct dir_context *ctx)
 {
-       unsigned int nr = filp->f_pos;
-       int ret;
-
-       if (nr < FIRST_PROCESS_ENTRY) {
-               int error = proc_readdir(filp, dirent, filldir);
-               if (error <= 0)
-                       return error;
-               filp->f_pos = FIRST_PROCESS_ENTRY;
+       if (ctx->pos < FIRST_PROCESS_ENTRY) {
+               proc_readdir(file, ctx);
+               ctx->pos = FIRST_PROCESS_ENTRY;
        }
 
-       ret = proc_pid_readdir(filp, dirent, filldir);
-       return ret;
+       return proc_pid_readdir(file, ctx);
 }
 
 /*
@@ -226,7 +219,7 @@ static int proc_root_readdir(struct file * filp,
  */
 static const struct file_operations proc_root_operations = {
        .read            = generic_read_dir,
-       .readdir         = proc_root_readdir,
+       .iterate         = proc_root_readdir,
        .llseek         = default_llseek,
 };