diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-12 17:27:30 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-26 21:08:53 -0400 |
commit | dcfadfa4ec5a12404a99ad6426871a6b03a62b37 (patch) | |
tree | a8c2898366470e795dac369040b905985c0bb9fc | |
parent | f33ff9927f42045116d738ee47ff7bc59f739bd7 (diff) | |
download | lwn-dcfadfa4ec5a12404a99ad6426871a6b03a62b37.tar.gz lwn-dcfadfa4ec5a12404a99ad6426871a6b03a62b37.zip |
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>
-rw-r--r-- | drivers/staging/android/binder.c | 59 | ||||
-rw-r--r-- | fs/file.c | 12 | ||||
-rw-r--r-- | include/linux/fdtable.h | 3 |
3 files changed, 16 insertions, 58 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index b9a534c46aac..4946d282a35c 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -362,71 +362,22 @@ struct binder_transaction { static void 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) { struct files_struct *files = proc->files; - int fd, error; - struct fdtable *fdt; unsigned long rlim_cur; unsigned long irqs; if (files == NULL) return -ESRCH; - error = -EMFILE; - spin_lock(&files->file_lock); + if (!lock_task_sighand(proc->tsk, &irqs)) + return -EMFILE; -repeat: - 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); - } - if (fd >= rlim_cur) - goto out; - - /* Do we need to expand the fd array or fd set? */ - 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; + rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); + unlock_task_sighand(proc->tsk, &irqs); -out: - spin_unlock(&files->file_lock); - return error; + return __alloc_fd(files, 0, rlim_cur, flags); } /* diff --git a/fs/file.c b/fs/file.c index 08922af4a62c..a3a0705f8f51 100644 --- a/fs/file.c +++ b/fs/file.c @@ -420,11 +420,10 @@ struct files_struct init_files = { /* * 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 end = rlimit(RLIMIT_NOFILE); int error; struct fdtable *fdt; @@ -479,8 +478,13 @@ out: 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) { - return alloc_fd(0, flags); + return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); } EXPORT_SYMBOL(get_unused_fd_flags); diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 158a41eed314..b84ca064f727 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -125,6 +125,9 @@ void reset_files_struct(struct files_struct *); int unshare_files(struct files_struct **); 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; #endif /* __LINUX_FDTABLE_H */ |