aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-12 17:27:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:08:53 -0400
commitdcfadfa4ec5a12404a99ad6426871a6b03a62b37 (patch)
treea8c2898366470e795dac369040b905985c0bb9fc
parenttake rlimit check to callers of expand_files() (diff)
downloadlinux-dev-dcfadfa4ec5a12404a99ad6426871a6b03a62b37.tar.xz
linux-dev-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.c59
-rw-r--r--fs/file.c12
-rw-r--r--include/linux/fdtable.h3
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 */