[readdir] convert procfs
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
68c6147113
commit
f0c3b5093a
@ -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,
|
||||
|
367
fs/proc/base.c
367
fs/proc/base.c
@ -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;
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
goto out_put_task;
|
||||
|
||||
mm = get_task_mm(task);
|
||||
if (!mm)
|
||||
goto out_put_task;
|
||||
down_read(&mm->mmap_sem);
|
||||
mm = get_task_mm(task);
|
||||
if (!mm)
|
||||
goto out_put_task;
|
||||
down_read(&mm->mmap_sem);
|
||||
|
||||
nr_files = 0;
|
||||
nr_files = 0;
|
||||
|
||||
/*
|
||||
* 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().
|
||||
*/
|
||||
/*
|
||||
* 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().
|
||||
*/
|
||||
|
||||
for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
|
||||
if (vma->vm_file && ++pos > filp->f_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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
if (fa)
|
||||
flex_array_free(fa);
|
||||
mmput(mm);
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
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,
|
||||
};
|
||||
|
92
fs/proc/fd.c
92
fs/proc/fd.c
@ -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;
|
||||
return -ENOENT;
|
||||
|
||||
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 (!dir_emit_dots(file, ctx))
|
||||
goto out;
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
goto out;
|
||||
files = get_files_struct(p);
|
||||
if (!files)
|
||||
goto out;
|
||||
|
||||
if (!fcheck_files(files, fd))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
rcu_read_lock();
|
||||
for (fd = ctx->pos - 2;
|
||||
fd < files_fdtable(files)->max_fds;
|
||||
fd++, ctx->pos++) {
|
||||
char name[PROC_NUMBUF];
|
||||
int len;
|
||||
|
||||
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 (!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--;
|
||||
}
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
|
||||
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);
|
||||
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 @@ 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,
|
||||
|
@ -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 @@ 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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user