forked from mirrors/linux
		
	[readdir] convert procfs
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									68c6147113
								
							
						
					
					
						commit
						f0c3b5093a
					
				
					 9 changed files with 283 additions and 488 deletions
				
			
		| 
						 | 
					@ -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,
 | 
				
			||||||
	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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										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
 | 
					 * 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,
 | 
				
			||||||
		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 = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
		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,91 +1956,73 @@ 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:
 | 
							goto out_put_task;
 | 
				
			||||||
		ino = inode->i_ino;
 | 
					 | 
				
			||||||
		if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0)
 | 
					 | 
				
			||||||
			goto out_put_task;
 | 
					 | 
				
			||||||
		filp->f_pos++;
 | 
					 | 
				
			||||||
	case 1:
 | 
					 | 
				
			||||||
		ino = parent_ino(dentry);
 | 
					 | 
				
			||||||
		if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
 | 
					 | 
				
			||||||
			goto out_put_task;
 | 
					 | 
				
			||||||
		filp->f_pos++;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		unsigned long nr_files, pos, i;
 | 
					 | 
				
			||||||
		struct flex_array *fa = NULL;
 | 
					 | 
				
			||||||
		struct map_files_info info;
 | 
					 | 
				
			||||||
		struct map_files_info *p;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mm = get_task_mm(task);
 | 
						mm = get_task_mm(task);
 | 
				
			||||||
		if (!mm)
 | 
						if (!mm)
 | 
				
			||||||
			goto out_put_task;
 | 
							goto out_put_task;
 | 
				
			||||||
		down_read(&mm->mmap_sem);
 | 
						down_read(&mm->mmap_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		nr_files = 0;
 | 
						nr_files = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
						/*
 | 
				
			||||||
		 * We need two passes here:
 | 
						 * We need two passes here:
 | 
				
			||||||
		 *
 | 
						 *
 | 
				
			||||||
		 *  1) Collect vmas of mapped files with mmap_sem taken
 | 
						 *  1) Collect vmas of mapped files with mmap_sem taken
 | 
				
			||||||
		 *  2) Release mmap_sem and instantiate entries
 | 
						 *  2) Release mmap_sem and instantiate entries
 | 
				
			||||||
		 *
 | 
						 *
 | 
				
			||||||
		 * otherwise we get lockdep complained, since filldir()
 | 
						 * otherwise we get lockdep complained, since filldir()
 | 
				
			||||||
		 * routine might require mmap_sem taken in might_fault().
 | 
						 * routine might require mmap_sem taken in might_fault().
 | 
				
			||||||
		 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		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++;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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:
 | 
					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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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,
 | 
				
			||||||
	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;
 | 
							goto out;
 | 
				
			||||||
	switch (i) {
 | 
					
 | 
				
			||||||
	case 0:
 | 
						if (ctx->pos >= nents + 2)
 | 
				
			||||||
		ino = inode->i_ino;
 | 
							goto out;
 | 
				
			||||||
		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
 | 
					
 | 
				
			||||||
			goto out;
 | 
						for (p = ents + (ctx->pos - 2); p <= ents + nents - 1; p++) {
 | 
				
			||||||
		i++;
 | 
							if (!proc_fill_cache(file, ctx, p->name, p->len,
 | 
				
			||||||
		filp->f_pos++;
 | 
									proc_pident_instantiate, task, p))
 | 
				
			||||||
		/* fall through */
 | 
								break;
 | 
				
			||||||
	case 1:
 | 
							ctx->pos++;
 | 
				
			||||||
		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++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = 1;
 | 
					 | 
				
			||||||
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[] = {
 | 
				
			||||||
	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[] = {
 | 
				
			||||||
#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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[] = {
 | 
				
			||||||
#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
	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
 | 
				
			||||||
	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:
 | 
							goto out;
 | 
				
			||||||
		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 */
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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 = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										92
									
								
								fs/proc/fd.c
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								fs/proc/fd.c
									
									
									
									
									
								
							| 
						 | 
					@ -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) {
 | 
							goto out;
 | 
				
			||||||
		case 0:
 | 
						if (!dir_emit_dots(file, ctx))
 | 
				
			||||||
			if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
 | 
							goto out;
 | 
				
			||||||
				goto out;
 | 
						files = get_files_struct(p);
 | 
				
			||||||
			filp->f_pos++;
 | 
						if (!files)
 | 
				
			||||||
		case 1:
 | 
							goto out;
 | 
				
			||||||
			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))
 | 
						rcu_read_lock();
 | 
				
			||||||
					continue;
 | 
						for (fd = ctx->pos - 2;
 | 
				
			||||||
				rcu_read_unlock();
 | 
						     fd < files_fdtable(files)->max_fds;
 | 
				
			||||||
 | 
						     fd++, ctx->pos++) {
 | 
				
			||||||
 | 
							char name[PROC_NUMBUF];
 | 
				
			||||||
 | 
							int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				len = snprintf(name, sizeof(name), "%d", fd);
 | 
							if (!fcheck_files(files, fd))
 | 
				
			||||||
				rv = proc_fill_cache(filp, dirent, filldir,
 | 
								continue;
 | 
				
			||||||
						     name, len, instantiate, p,
 | 
							rcu_read_unlock();
 | 
				
			||||||
						     (void *)(unsigned long)fd);
 | 
					
 | 
				
			||||||
				if (rv < 0)
 | 
							len = snprintf(name, sizeof(name), "%d", fd);
 | 
				
			||||||
					goto out_fd_loop;
 | 
							if (!proc_fill_cache(file, ctx,
 | 
				
			||||||
				rcu_read_lock();
 | 
									     name, len, instantiate, p,
 | 
				
			||||||
			}
 | 
									     (void *)(unsigned long)fd))
 | 
				
			||||||
			rcu_read_unlock();
 | 
								goto out_fd_loop;
 | 
				
			||||||
out_fd_loop:
 | 
							rcu_read_lock();
 | 
				
			||||||
			put_files_struct(files);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					out_fd_loop:
 | 
				
			||||||
 | 
						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)
 | 
				
			||||||
	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 = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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,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
 | 
					 * 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;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ino = inode->i_ino;
 | 
						if (!dir_emit_dots(file, ctx))
 | 
				
			||||||
	i = filp->f_pos;
 | 
							return 0;
 | 
				
			||||||
	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 {
 | 
						spin_lock(&proc_subdir_lock);
 | 
				
			||||||
				struct proc_dir_entry *next;
 | 
						de = de->subdir;
 | 
				
			||||||
 | 
						i = ctx->pos - 2;
 | 
				
			||||||
				/* filldir passes info to user space */
 | 
						for (;;) {
 | 
				
			||||||
				pde_get(de);
 | 
							if (!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_unlock(&proc_subdir_lock);
 | 
								spin_unlock(&proc_subdir_lock);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!i)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							de = de->next;
 | 
				
			||||||
 | 
							i--;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret = 1;
 | 
					
 | 
				
			||||||
out:
 | 
						do {
 | 
				
			||||||
	return ret;	
 | 
							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 = {
 | 
					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 *);
 | 
				
			||||||
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;
 | 
				
			||||||
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,
 | 
				
			||||||
	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;
 | 
							goto out;
 | 
				
			||||||
	switch (i) {
 | 
						if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))
 | 
				
			||||||
	case 0:
 | 
							goto out;
 | 
				
			||||||
		ino = inode->i_ino;
 | 
						entry = ns_entries + (ctx->pos - 2);
 | 
				
			||||||
		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
 | 
						last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
 | 
				
			||||||
			goto out;
 | 
						while (entry <= last) {
 | 
				
			||||||
		i++;
 | 
							const struct proc_ns_operations *ops = *entry;
 | 
				
			||||||
		filp->f_pos++;
 | 
							if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),
 | 
				
			||||||
		/* fall through */
 | 
									     proc_ns_instantiate, task, ops))
 | 
				
			||||||
	case 1:
 | 
								break;
 | 
				
			||||||
		ino = parent_ino(dentry);
 | 
							ctx->pos++;
 | 
				
			||||||
		if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
 | 
							entry++;
 | 
				
			||||||
			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++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	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 = {
 | 
				
			||||||
	.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,
 | 
				
			||||||
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)
 | 
				
			||||||
	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,
 | 
				
			||||||
			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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
	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,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue