Commit f0c3b509 authored by Al Viro's avatar Al Viro

[readdir] convert procfs

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 68c61471
...@@ -542,8 +542,8 @@ static const struct file_operations hppfs_file_fops = { ...@@ -542,8 +542,8 @@ static const struct file_operations hppfs_file_fops = {
}; };
struct hppfs_dirent { struct hppfs_dirent {
void *vfs_dirent; struct dir_context ctx;
filldir_t filldir; struct dir_context *caller;
struct dentry *dentry; struct dentry *dentry;
}; };
...@@ -555,34 +555,29 @@ static int hppfs_filldir(void *d, const char *name, int size, ...@@ -555,34 +555,29 @@ static int hppfs_filldir(void *d, const char *name, int size,
if (file_removed(dirent->dentry, name)) if (file_removed(dirent->dentry, name))
return 0; return 0;
return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset, dirent->caller->pos = dirent->ctx.pos;
inode, type); 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 hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file; struct file *proc_file = data->proc_file;
int (*readdir)(struct file *, void *, filldir_t); struct hppfs_dirent d = {
struct hppfs_dirent dirent = ((struct hppfs_dirent) .ctx.actor = hppfs_filldir,
{ .vfs_dirent = ent, .caller = ctx,
.filldir = filldir,
.dentry = file->f_path.dentry .dentry = file->f_path.dentry
}); };
int err; int err;
proc_file->f_pos = ctx->pos;
readdir = file_inode(proc_file)->i_fop->readdir; err = iterate_dir(proc_file, &d.ctx);
ctx->pos = d.ctx.pos;
proc_file->f_pos = file->f_pos;
err = (*readdir)(proc_file, &dirent, hppfs_filldir);
file->f_pos = proc_file->f_pos;
return err; return err;
} }
static const struct file_operations hppfs_dir_fops = { static const struct file_operations hppfs_dir_fops = {
.owner = NULL, .owner = NULL,
.readdir = hppfs_readdir, .iterate = hppfs_readdir,
.open = hppfs_dir_open, .open = hppfs_dir_open,
.llseek = default_llseek, .llseek = default_llseek,
.release = hppfs_release, .release = hppfs_release,
......
...@@ -1681,11 +1681,11 @@ const struct dentry_operations pid_dentry_operations = ...@@ -1681,11 +1681,11 @@ const struct dentry_operations pid_dentry_operations =
* reported by readdir in sync with the inode numbers reported * reported by readdir in sync with the inode numbers reported
* by stat. * 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, const char *name, int len,
instantiate_t instantiate, struct task_struct *task, const void *ptr) 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 inode *inode;
struct qstr qname; struct qstr qname;
ino_t ino = 0; ino_t ino = 0;
...@@ -1720,7 +1720,7 @@ int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, ...@@ -1720,7 +1720,7 @@ int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
ino = find_inode_number(dir, &qname); ino = find_inode_number(dir, &qname);
if (!ino) if (!ino)
ino = 1; ino = 1;
return filldir(dirent, name, len, filp->f_pos, ino, type); return dir_emit(ctx, name, len, ino, type);
} }
#ifdef CONFIG_CHECKPOINT_RESTORE #ifdef CONFIG_CHECKPOINT_RESTORE
...@@ -1931,14 +1931,15 @@ static const struct inode_operations proc_map_files_inode_operations = { ...@@ -1931,14 +1931,15 @@ static const struct inode_operations proc_map_files_inode_operations = {
}; };
static int 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 vm_area_struct *vma;
struct task_struct *task; struct task_struct *task;
struct mm_struct *mm; 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; int ret;
ret = -EPERM; ret = -EPERM;
...@@ -1946,7 +1947,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1946,7 +1947,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto out; goto out;
ret = -ENOENT; ret = -ENOENT;
task = get_proc_task(inode); task = get_proc_task(file_inode(file));
if (!task) if (!task)
goto out; goto out;
...@@ -1955,23 +1956,8 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1955,23 +1956,8 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto out_put_task; goto out_put_task;
ret = 0; ret = 0;
switch (filp->f_pos) { if (!dir_emit_dots(file, ctx))
case 0:
ino = inode->i_ino;
if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0)
goto out_put_task; 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); mm = get_task_mm(task);
if (!mm) if (!mm)
...@@ -1991,7 +1977,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1991,7 +1977,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/ */
for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
if (vma->vm_file && ++pos > filp->f_pos) if (vma->vm_file && ++pos > ctx->pos)
nr_files++; nr_files++;
} }
...@@ -2011,7 +1997,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2011,7 +1997,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
vma = vma->vm_next) { vma = vma->vm_next) {
if (!vma->vm_file) if (!vma->vm_file)
continue; continue;
if (++pos <= filp->f_pos) if (++pos <= ctx->pos)
continue; continue;
info.mode = vma->vm_file->f_mode; info.mode = vma->vm_file->f_mode;
...@@ -2026,20 +2012,17 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2026,20 +2012,17 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
for (i = 0; i < nr_files; i++) { for (i = 0; i < nr_files; i++) {
p = flex_array_get(fa, i); p = flex_array_get(fa, i);
ret = proc_fill_cache(filp, dirent, filldir, if (!proc_fill_cache(file, ctx,
p->name, p->len, p->name, p->len,
proc_map_files_instantiate, proc_map_files_instantiate,
task, task,
(void *)(unsigned long)p->mode); (void *)(unsigned long)p->mode))
if (ret)
break; break;
filp->f_pos++; ctx->pos++;
} }
if (fa) if (fa)
flex_array_free(fa); flex_array_free(fa);
mmput(mm); mmput(mm);
}
}
out_put_task: out_put_task:
put_task_struct(task); put_task_struct(task);
...@@ -2049,7 +2032,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2049,7 +2032,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
static const struct file_operations proc_map_files_operations = { static const struct file_operations proc_map_files_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_map_files_readdir, .iterate = proc_map_files_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -2217,67 +2200,30 @@ static struct dentry *proc_pident_lookup(struct inode *dir, ...@@ -2217,67 +2200,30 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
return error; return error;
} }
static int proc_pident_fill_cache(struct file *filp, void *dirent, static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
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,
const struct pid_entry *ents, unsigned int nents) const struct pid_entry *ents, unsigned int nents)
{ {
int i; struct task_struct *task = get_proc_task(file_inode(file));
struct dentry *dentry = filp->f_path.dentry; const struct pid_entry *p;
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;
ret = -ENOENT;
if (!task) if (!task)
goto out_no_task; return -ENOENT;
ret = 0; if (!dir_emit_dots(file, ctx))
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; goto out;
i++;
filp->f_pos++; if (ctx->pos >= nents + 2)
/* 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; goto out;
filp->f_pos++;
p++;
}
}
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: out:
put_task_struct(task); put_task_struct(task);
out_no_task: return 0;
return ret;
} }
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
...@@ -2362,16 +2308,15 @@ static const struct pid_entry attr_dir_stuff[] = { ...@@ -2362,16 +2308,15 @@ static const struct pid_entry attr_dir_stuff[] = {
REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
}; };
static int proc_attr_dir_readdir(struct file * filp, static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
void * dirent, filldir_t filldir)
{ {
return proc_pident_readdir(filp,dirent,filldir, return proc_pident_readdir(file, ctx,
attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff)); attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
} }
static const struct file_operations proc_attr_dir_operations = { static const struct file_operations proc_attr_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_attr_dir_readdir, .iterate = proc_attr_dir_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -2725,16 +2670,15 @@ static const struct pid_entry tgid_base_stuff[] = { ...@@ -2725,16 +2670,15 @@ static const struct pid_entry tgid_base_stuff[] = {
#endif #endif
}; };
static int proc_tgid_base_readdir(struct file * filp, static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
void * dirent, filldir_t filldir)
{ {
return proc_pident_readdir(filp,dirent,filldir, return proc_pident_readdir(file, ctx,
tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff)); tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
} }
static const struct file_operations proc_tgid_base_operations = { static const struct file_operations proc_tgid_base_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_tgid_base_readdir, .iterate = proc_tgid_base_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -2936,58 +2880,42 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite ...@@ -2936,58 +2880,42 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 1) #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 */ /* 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 tgid_iter iter;
struct pid_namespace *ns; struct pid_namespace *ns;
filldir_t __filldir; loff_t pos = ctx->pos;
loff_t pos = filp->f_pos;
if (pos >= PID_MAX_LIMIT + TGID_OFFSET) if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
goto out; return 0;
if (pos == TGID_OFFSET - 1) { if (pos == TGID_OFFSET - 1) {
if (proc_fill_cache(filp, dirent, filldir, "self", 4, if (!proc_fill_cache(file, ctx, "self", 4, NULL, NULL, NULL))
NULL, NULL, NULL) < 0) return 0;
goto out;
iter.tgid = 0; iter.tgid = 0;
} else { } else {
iter.tgid = pos - TGID_OFFSET; iter.tgid = pos - TGID_OFFSET;
} }
iter.task = NULL; 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); for (iter = next_tgid(ns, iter);
iter.task; iter.task;
iter.tgid += 1, iter = next_tgid(ns, iter)) { iter.tgid += 1, iter = next_tgid(ns, iter)) {
if (has_pid_permissions(ns, iter.task, 2)) char name[PROC_NUMBUF];
__filldir = filldir; int len;
else if (!has_pid_permissions(ns, iter.task, 2))
__filldir = fake_filldir; continue;
filp->f_pos = iter.tgid + TGID_OFFSET; len = snprintf(name, sizeof(name), "%d", iter.tgid);
if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) { 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); put_task_struct(iter.task);
goto out; return 0;
} }
} }
filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; ctx->pos = PID_MAX_LIMIT + TGID_OFFSET;
out:
return 0; return 0;
} }
...@@ -3075,11 +3003,10 @@ static const struct pid_entry tid_base_stuff[] = { ...@@ -3075,11 +3003,10 @@ static const struct pid_entry tid_base_stuff[] = {
#endif #endif
}; };
static int proc_tid_base_readdir(struct file * filp, static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
void * dirent, filldir_t filldir)
{ {
return proc_pident_readdir(filp,dirent,filldir, return proc_pident_readdir(file, ctx,
tid_base_stuff,ARRAY_SIZE(tid_base_stuff)); 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 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 ...@@ -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 = { static const struct file_operations proc_tid_base_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_tid_base_readdir, .iterate = proc_tid_base_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -3231,30 +3158,16 @@ static struct task_struct *next_tid(struct task_struct *start) ...@@ -3231,30 +3158,16 @@ static struct task_struct *next_tid(struct task_struct *start)
return pos; 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 */ /* 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 *leader = NULL;
struct task_struct *task; struct task_struct *task = get_proc_task(file_inode(file));
int retval = -ENOENT;
ino_t ino;
int tid;
struct pid_namespace *ns; struct pid_namespace *ns;
int tid;
task = get_proc_task(inode);
if (!task) if (!task)
goto out_no_task; return -ENOENT;
rcu_read_lock(); rcu_read_lock();
if (pid_alive(task)) { if (pid_alive(task)) {
leader = task->group_leader; leader = task->group_leader;
...@@ -3263,46 +3176,36 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi ...@@ -3263,46 +3176,36 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
rcu_read_unlock(); rcu_read_unlock();
put_task_struct(task); put_task_struct(task);
if (!leader) if (!leader)
goto out_no_task; return -ENOENT;
retval = 0;
switch ((unsigned long)filp->f_pos) { if (!dir_emit_dots(file, ctx))
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; goto out;
filp->f_pos++;
/* fall through */
}
/* f_version caches the tgid value that the last readdir call couldn't /* f_version caches the tgid value that the last readdir call couldn't
* return. lseek aka telldir automagically resets f_version to 0. * return. lseek aka telldir automagically resets f_version to 0.
*/ */
ns = filp->f_dentry->d_sb->s_fs_info; ns = file->f_dentry->d_sb->s_fs_info;
tid = (int)filp->f_version; tid = (int)file->f_version;
filp->f_version = 0; file->f_version = 0;
for (task = first_tid(leader, tid, filp->f_pos - 2, ns); for (task = first_tid(leader, tid, ctx->pos - 2, ns);
task; 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); 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 /* returning this tgid failed, save it as the first
* pid for the next readir call */ * pid for the next readir call */
filp->f_version = (u64)tid; file->f_version = (u64)tid;
put_task_struct(task); put_task_struct(task);
break; break;
} }
} }
out: out:
put_task_struct(leader); put_task_struct(leader);
out_no_task: return 0;
return retval;
} }
static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 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 = { ...@@ -3328,6 +3231,6 @@ static const struct inode_operations proc_task_inode_operations = {
static const struct file_operations proc_task_operations = { static const struct file_operations proc_task_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_task_readdir, .iterate = proc_task_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -219,74 +219,58 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, ...@@ -219,74 +219,58 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
return result; return result;
} }
static int proc_readfd_common(struct file * filp, void * dirent, static int proc_readfd_common(struct file *file, struct dir_context *ctx,
filldir_t filldir, instantiate_t instantiate) instantiate_t instantiate)
{ {
struct dentry *dentry = filp->f_path.dentry; struct task_struct *p = get_proc_task(file_inode(file));
struct inode *inode = dentry->d_inode;
struct task_struct *p = get_proc_task(inode);
struct files_struct *files; struct files_struct *files;
unsigned int fd, ino; unsigned int fd;
int retval;
retval = -ENOENT;
if (!p) if (!p)
goto out_no_task; return -ENOENT;
retval = 0;
fd = filp->f_pos; if (!dir_emit_dots(file, ctx))
switch (fd) {
case 0:
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
goto out; goto out;
filp->f_pos++; if (!dir_emit_dots(file, ctx))
case 1:
ino = parent_ino(dentry);
if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
goto out; goto out;
filp->f_pos++;
default:
files = get_files_struct(p); files = get_files_struct(p);
if (!files) if (!files)
goto out; goto out;
rcu_read_lock(); rcu_read_lock();
for (fd = filp->f_pos - 2; for (fd = ctx->pos - 2;
fd < files_fdtable(files)->max_fds; fd < files_fdtable(files)->max_fds;
fd++, filp->f_pos++) { fd++, ctx->pos++) {
char name[PROC_NUMBUF]; char name[PROC_NUMBUF];
int len; int len;
int rv;
if (!fcheck_files(files, fd)) if (!fcheck_files(files, fd))
continue; continue;
rcu_read_unlock(); rcu_read_unlock();
len = snprintf(name, sizeof(name), "%d", fd); len = snprintf(name, sizeof(name), "%d", fd);
rv = proc_fill_cache(filp, dirent, filldir, if (!proc_fill_cache(file, ctx,
name, len, instantiate, p, name, len, instantiate, p,
(void *)(unsigned long)fd); (void *)(unsigned long)fd))
if (rv < 0)
goto out_fd_loop; goto out_fd_loop;
rcu_read_lock(); rcu_read_lock();
} }
rcu_read_unlock(); rcu_read_unlock();
out_fd_loop: out_fd_loop:
put_files_struct(files); put_files_struct(files);
}
out: out:
put_task_struct(p); put_task_struct(p);
out_no_task: return 0;
return retval;
} }
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 = { const struct file_operations proc_fd_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_readfd, .iterate = proc_readfd,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -351,9 +335,9 @@ proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) ...@@ -351,9 +335,9 @@ proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)
return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 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); proc_fdinfo_instantiate);
} }
...@@ -364,6 +348,6 @@ const struct inode_operations proc_fdinfo_inode_operations = { ...@@ -364,6 +348,6 @@ const struct inode_operations proc_fdinfo_inode_operations = {
const struct file_operations proc_fdinfo_operations = { const struct file_operations proc_fdinfo_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_readfdinfo, .iterate = proc_readfdinfo,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -233,40 +233,21 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, ...@@ -233,40 +233,21 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
* value of the readdir() call, as long as it's non-negative * value of the readdir() call, as long as it's non-negative
* for success.. * for success..
*/ */
int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
filldir_t filldir) struct dir_context *ctx)
{ {
unsigned int ino;
int i; int i;
struct inode *inode = file_inode(filp);
int ret = 0; if (!dir_emit_dots(file, ctx))
return 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); spin_lock(&proc_subdir_lock);
de = de->subdir; de = de->subdir;
i -= 2; i = ctx->pos - 2;
for (;;) { for (;;) {
if (!de) { if (!de) {
ret = 1;
spin_unlock(&proc_subdir_lock); spin_unlock(&proc_subdir_lock);
goto out; return 0;
} }
if (!i) if (!i)
break; break;
...@@ -276,33 +257,28 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, ...@@ -276,33 +257,28 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
do { do {
struct proc_dir_entry *next; struct proc_dir_entry *next;
/* filldir passes info to user space */
pde_get(de); pde_get(de);
spin_unlock(&proc_subdir_lock); spin_unlock(&proc_subdir_lock);
if (filldir(dirent, de->name, de->namelen, filp->f_pos, if (!dir_emit(ctx, de->name, de->namelen,
de->low_ino, de->mode >> 12) < 0) { de->low_ino, de->mode >> 12)) {
pde_put(de); pde_put(de);
goto out; return 0;
} }
spin_lock(&proc_subdir_lock); spin_lock(&proc_subdir_lock);
filp->f_pos++; ctx->pos++;
next = de->next; next = de->next;
pde_put(de); pde_put(de);
de = next; de = next;
} while (de); } while (de);
spin_unlock(&proc_subdir_lock); spin_unlock(&proc_subdir_lock);
} return 0;
ret = 1;
out:
return ret;
} }
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) ...@@ -313,7 +289,7 @@ int proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
static const struct file_operations proc_dir_operations = { static const struct file_operations proc_dir_operations = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_readdir, .iterate = proc_readdir,
}; };
/* /*
......
...@@ -165,14 +165,14 @@ extern int proc_setattr(struct dentry *, struct iattr *); ...@@ -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 struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *);
extern int pid_revalidate(struct dentry *, unsigned int); extern int pid_revalidate(struct dentry *, unsigned int);
extern int pid_delete_dentry(const struct dentry *); 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 struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int);
extern loff_t mem_lseek(struct file *, loff_t, int); extern loff_t mem_lseek(struct file *, loff_t, int);
/* Lookups */ /* Lookups */
typedef struct dentry *instantiate_t(struct inode *, struct dentry *, typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
struct task_struct *, const void *); 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 *); instantiate_t, struct task_struct *, const void *);
/* /*
...@@ -183,8 +183,8 @@ extern spinlock_t proc_subdir_lock; ...@@ -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(struct inode *, struct dentry *, unsigned int);
extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *, extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *,
struct dentry *); struct dentry *);
extern int proc_readdir(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 *, void *, filldir_t); 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) static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
{ {
......
...@@ -213,74 +213,36 @@ static struct dentry *proc_ns_instantiate(struct inode *dir, ...@@ -213,74 +213,36 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
return error; return error;
} }
static int proc_ns_fill_cache(struct file *filp, void *dirent, static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
filldir_t filldir, struct task_struct *task,
const struct proc_ns_operations *ops)
{ {
return proc_fill_cache(filp, dirent, filldir, struct task_struct *task = get_proc_task(file_inode(file));
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);
const struct proc_ns_operations **entry, **last; const struct proc_ns_operations **entry, **last;
ino_t ino;
int ret;
ret = -ENOENT;
if (!task) if (!task)
goto out_no_task; return -ENOENT;
ret = 0; if (!dir_emit_dots(file, ctx))
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; goto out;
i++; if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))
filp->f_pos++;
/* fall through */
default:
i -= 2;
if (i >= ARRAY_SIZE(ns_entries)) {
ret = 1;
goto out; goto out;
} entry = ns_entries + (ctx->pos - 2);
entry = ns_entries + i;
last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
while (entry <= last) { while (entry <= last) {
if (proc_ns_fill_cache(filp, dirent, filldir, const struct proc_ns_operations *ops = *entry;
task, *entry) < 0) if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),
goto out; proc_ns_instantiate, task, ops))
filp->f_pos++; break;
ctx->pos++;
entry++; entry++;
} }
}
ret = 1;
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: return 0;
return ret;
} }
const struct file_operations proc_ns_dir_operations = { const struct file_operations proc_ns_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_ns_dir_readdir, .iterate = proc_ns_dir_readdir,
}; };
static struct dentry *proc_ns_dir_lookup(struct inode *dir, static struct dentry *proc_ns_dir_lookup(struct inode *dir,
......
...@@ -160,16 +160,15 @@ const struct inode_operations proc_net_inode_operations = { ...@@ -160,16 +160,15 @@ const struct inode_operations proc_net_inode_operations = {
.getattr = proc_tgid_net_getattr, .getattr = proc_tgid_net_getattr,
}; };
static int proc_tgid_net_readdir(struct file *filp, void *dirent, static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)
filldir_t filldir)
{ {
int ret; int ret;
struct net *net; struct net *net;
ret = -EINVAL; ret = -EINVAL;
net = get_proc_task_net(file_inode(filp)); net = get_proc_task_net(file_inode(file));
if (net != NULL) { 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); put_net(net);
} }
return ret; return ret;
...@@ -178,7 +177,7 @@ static int proc_tgid_net_readdir(struct file *filp, void *dirent, ...@@ -178,7 +177,7 @@ static int proc_tgid_net_readdir(struct file *filp, void *dirent,
const struct file_operations proc_net_operations = { const struct file_operations proc_net_operations = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read = generic_read_dir, .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) static __net_init int proc_net_ns_init(struct net *net)
......
...@@ -573,12 +573,12 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) ...@@ -573,12 +573,12 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
return ret; return ret;
} }
static int proc_sys_fill_cache(struct file *filp, void *dirent, static bool proc_sys_fill_cache(struct file *file,
filldir_t filldir, struct dir_context *ctx,
struct ctl_table_header *head, struct ctl_table_header *head,
struct ctl_table *table) struct ctl_table *table)
{ {
struct dentry *child, *dir = filp->f_path.dentry; struct dentry *child, *dir = file->f_path.dentry;
struct inode *inode; struct inode *inode;
struct qstr qname; struct qstr qname;
ino_t ino = 0; ino_t ino = 0;
...@@ -595,38 +595,38 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent, ...@@ -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); inode = proc_sys_make_inode(dir->d_sb, head, table);
if (!inode) { if (!inode) {
dput(child); dput(child);
return -ENOMEM; return false;
} else { } else {
d_set_d_op(child, &proc_sys_dentry_operations); d_set_d_op(child, &proc_sys_dentry_operations);
d_add(child, inode); d_add(child, inode);
} }
} else { } else {
return -ENOMEM; return false;
} }
} }
inode = child->d_inode; inode = child->d_inode;
ino = inode->i_ino; ino = inode->i_ino;
type = inode->i_mode >> 12; type = inode->i_mode >> 12;
dput(child); 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, static bool proc_sys_link_fill_cache(struct file *file,
filldir_t filldir, struct dir_context *ctx,
struct ctl_table_header *head, struct ctl_table_header *head,
struct ctl_table *table) struct ctl_table *table)
{ {
int err, ret = 0; bool ret = true;
head = sysctl_head_grab(head); head = sysctl_head_grab(head);
if (S_ISLNK(table->mode)) { if (S_ISLNK(table->mode)) {
/* It is not an error if we can not follow the link ignore it */ /* 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) if (err)
goto out; goto out;
} }
ret = proc_sys_fill_cache(filp, dirent, filldir, head, table); ret = proc_sys_fill_cache(file, ctx, head, table);
out: out:
sysctl_head_finish(head); sysctl_head_finish(head);
return ret; return ret;
...@@ -634,67 +634,50 @@ static int proc_sys_link_fill_cache(struct file *filp, void *dirent, ...@@ -634,67 +634,50 @@ static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
static int scan(struct ctl_table_header *head, ctl_table *table, static int scan(struct ctl_table_header *head, ctl_table *table,
unsigned long *pos, struct file *file, unsigned long *pos, struct file *file,
void *dirent, filldir_t filldir) struct dir_context *ctx)
{ {
int res; bool res;
if ((*pos)++ < file->f_pos) if ((*pos)++ < ctx->pos)
return 0; return true;
if (unlikely(S_ISLNK(table->mode))) 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 else
res = proc_sys_fill_cache(file, dirent, filldir, head, table); res = proc_sys_fill_cache(file, ctx, head, table);
if (res == 0) if (res)
file->f_pos = *pos; ctx->pos = *pos;
return res; 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 ctl_table_header *head = grab_header(file_inode(file));
struct inode *inode = dentry->d_inode;
struct ctl_table_header *head = grab_header(inode);
struct ctl_table_header *h = NULL; struct ctl_table_header *h = NULL;
struct ctl_table *entry; struct ctl_table *entry;
struct ctl_dir *ctl_dir; struct ctl_dir *ctl_dir;
unsigned long pos; unsigned long pos;
int ret = -EINVAL;
if (IS_ERR(head)) if (IS_ERR(head))
return PTR_ERR(head); return PTR_ERR(head);
ctl_dir = container_of(head, struct ctl_dir, header); ctl_dir = container_of(head, struct ctl_dir, header);
ret = 0; if (!dir_emit_dots(file, ctx))
/* Avoid a switch here: arm builds fail with missing __cmpdi2 */ return 0;
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++;
}
pos = 2; pos = 2;
for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) { for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
ret = scan(h, entry, &pos, filp, dirent, filldir); if (!scan(h, entry, &pos, file, ctx)) {
if (ret) {
sysctl_head_finish(h); sysctl_head_finish(h);
break; break;
} }
} }
ret = 1;
out:
sysctl_head_finish(head); sysctl_head_finish(head);
return ret; return 0;
} }
static int proc_sys_permission(struct inode *inode, int mask) static int proc_sys_permission(struct inode *inode, int mask)
...@@ -769,7 +752,7 @@ static const struct file_operations proc_sys_file_operations = { ...@@ -769,7 +752,7 @@ static const struct file_operations proc_sys_file_operations = {
static const struct file_operations proc_sys_dir_file_operations = { static const struct file_operations proc_sys_dir_file_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_sys_readdir, .iterate = proc_sys_readdir,
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
......
...@@ -202,21 +202,14 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr ...@@ -202,21 +202,14 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
return proc_pid_lookup(dir, dentry, flags); return proc_pid_lookup(dir, dentry, flags);
} }
static int proc_root_readdir(struct file * filp, static int proc_root_readdir(struct file *file, struct dir_context *ctx)
void * dirent, filldir_t filldir)
{ {
unsigned int nr = filp->f_pos; if (ctx->pos < FIRST_PROCESS_ENTRY) {
int ret; proc_readdir(file, ctx);
ctx->pos = FIRST_PROCESS_ENTRY;
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(filp, dirent, filldir);
if (error <= 0)
return error;
filp->f_pos = FIRST_PROCESS_ENTRY;
} }
ret = proc_pid_readdir(filp, dirent, filldir); return proc_pid_readdir(file, ctx);
return ret;
} }
/* /*
...@@ -226,7 +219,7 @@ static int proc_root_readdir(struct file * filp, ...@@ -226,7 +219,7 @@ static int proc_root_readdir(struct file * filp,
*/ */
static const struct file_operations proc_root_operations = { static const struct file_operations proc_root_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_root_readdir, .iterate = proc_root_readdir,
.llseek = default_llseek, .llseek = default_llseek,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment