mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	new helper: __alloc_fd()
Essentially, alloc_fd() in a files_struct we own a reference to. Most of the time wanting to use it is a sign of lousy API design (such as android/binder). It's *not* a general-purpose interface; better that than open-coding its guts, but again, playing with other process' descriptor table is a sign of bad design. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									f33ff9927f
								
							
						
					
					
						commit
						dcfadfa4ec
					
				
					 3 changed files with 16 additions and 58 deletions
				
			
		| 
						 | 
					@ -362,71 +362,22 @@ struct binder_transaction {
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
 | 
					binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * copied from get_unused_fd_flags
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
 | 
					int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct files_struct *files = proc->files;
 | 
						struct files_struct *files = proc->files;
 | 
				
			||||||
	int fd, error;
 | 
					 | 
				
			||||||
	struct fdtable *fdt;
 | 
					 | 
				
			||||||
	unsigned long rlim_cur;
 | 
						unsigned long rlim_cur;
 | 
				
			||||||
	unsigned long irqs;
 | 
						unsigned long irqs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (files == NULL)
 | 
						if (files == NULL)
 | 
				
			||||||
		return -ESRCH;
 | 
							return -ESRCH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = -EMFILE;
 | 
						if (!lock_task_sighand(proc->tsk, &irqs))
 | 
				
			||||||
	spin_lock(&files->file_lock);
 | 
							return -EMFILE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repeat:
 | 
						rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
 | 
				
			||||||
	fdt = files_fdtable(files);
 | 
					 | 
				
			||||||
	fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * N.B. For clone tasks sharing a files structure, this test
 | 
					 | 
				
			||||||
	 * will limit the total number of files that can be opened.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	rlim_cur = 0;
 | 
					 | 
				
			||||||
	if (lock_task_sighand(proc->tsk, &irqs)) {
 | 
					 | 
				
			||||||
		rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur;
 | 
					 | 
				
			||||||
	unlock_task_sighand(proc->tsk, &irqs);
 | 
						unlock_task_sighand(proc->tsk, &irqs);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (fd >= rlim_cur)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do we need to expand the fd array or fd set?  */
 | 
						return __alloc_fd(files, 0, rlim_cur, flags);
 | 
				
			||||||
	error = expand_files(files, fd);
 | 
					 | 
				
			||||||
	if (error < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (error) {
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * If we needed to expand the fs array we
 | 
					 | 
				
			||||||
		 * might have blocked - try again.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		error = -EMFILE;
 | 
					 | 
				
			||||||
		goto repeat;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__set_open_fd(fd, fdt);
 | 
					 | 
				
			||||||
	if (flags & O_CLOEXEC)
 | 
					 | 
				
			||||||
		__set_close_on_exec(fd, fdt);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		__clear_close_on_exec(fd, fdt);
 | 
					 | 
				
			||||||
	files->next_fd = fd + 1;
 | 
					 | 
				
			||||||
#if 1
 | 
					 | 
				
			||||||
	/* Sanity check */
 | 
					 | 
				
			||||||
	if (fdt->fd[fd] != NULL) {
 | 
					 | 
				
			||||||
		pr_warn("get_unused_fd: slot %d not NULL!\n", fd);
 | 
					 | 
				
			||||||
		fdt->fd[fd] = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	error = fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	spin_unlock(&files->file_lock);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								fs/file.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								fs/file.c
									
									
									
									
									
								
							| 
						 | 
					@ -420,11 +420,10 @@ struct files_struct init_files = {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * allocate a file descriptor, mark it busy.
 | 
					 * allocate a file descriptor, mark it busy.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int alloc_fd(unsigned start, unsigned flags)
 | 
					int __alloc_fd(struct files_struct *files,
 | 
				
			||||||
 | 
						       unsigned start, unsigned end, unsigned flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct files_struct *files = current->files;
 | 
					 | 
				
			||||||
	unsigned int fd;
 | 
						unsigned int fd;
 | 
				
			||||||
	unsigned end = rlimit(RLIMIT_NOFILE);
 | 
					 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
	struct fdtable *fdt;
 | 
						struct fdtable *fdt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -479,8 +478,13 @@ int alloc_fd(unsigned start, unsigned flags)
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int alloc_fd(unsigned start, unsigned flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int get_unused_fd_flags(unsigned flags)
 | 
					int get_unused_fd_flags(unsigned flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return alloc_fd(0, flags);
 | 
						return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(get_unused_fd_flags);
 | 
					EXPORT_SYMBOL(get_unused_fd_flags);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,6 +125,9 @@ void reset_files_struct(struct files_struct *);
 | 
				
			||||||
int unshare_files(struct files_struct **);
 | 
					int unshare_files(struct files_struct **);
 | 
				
			||||||
struct files_struct *dup_fd(struct files_struct *, int *);
 | 
					struct files_struct *dup_fd(struct files_struct *, int *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int __alloc_fd(struct files_struct *files,
 | 
				
			||||||
 | 
							      unsigned start, unsigned end, unsigned flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct kmem_cache *files_cachep;
 | 
					extern struct kmem_cache *files_cachep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __LINUX_FDTABLE_H */
 | 
					#endif /* __LINUX_FDTABLE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue