};
struct hppfs_dirent {
- void *vfs_dirent;
- filldir_t filldir;
+ struct dir_context ctx;
+ struct dir_context *caller;
struct dentry *dentry;
};
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,
* 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;
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
};
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;
goto out;
ret = -ENOENT;
- task = get_proc_task(inode);
+ task = get_proc_task(file_inode(file));
if (!task)
goto out;
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);
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,
};
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
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,
};
#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,
};
#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;
}
#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)
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,
};
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;
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)
static const struct file_operations proc_task_operations = {
.read = generic_read_dir,
- .readdir = proc_task_readdir,
+ .iterate = proc_task_readdir,
.llseek = default_llseek,
};
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,
};
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);
}
const struct file_operations proc_fdinfo_operations = {
.read = generic_read_dir,
- .readdir = proc_readfdinfo,
+ .iterate = proc_readfdinfo,
.llseek = default_llseek,
};
* 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);
}
/*
static const struct file_operations proc_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
- .readdir = proc_readdir,
+ .iterate = proc_readdir,
};
/*
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 *);
/*
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)
{
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,
.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;
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)
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;
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;
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)
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,
};
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);
}
/*
*/
static const struct file_operations proc_root_operations = {
.read = generic_read_dir,
- .readdir = proc_root_readdir,
+ .iterate = proc_root_readdir,
.llseek = default_llseek,
};