[readdir] convert procfs

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2013-05-16 12:07:31 -04:00
parent 68c6147113
commit f0c3b5093a
9 changed files with 283 additions and 488 deletions

View 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,
};