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 = {
};
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,
......
This diff is collapsed.
......@@ -219,74 +219,58 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
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,
};
......@@ -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,
};
/*
......
......@@ -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)
{
......
......@@ -213,74 +213,36 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
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,
......
......@@ -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)
......
......@@ -573,12 +573,12 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
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 @@ static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
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,
};
......
......@@ -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;