new helper: __alloc_fd()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 12 Aug 2012 21:27:30 +0000 (17:27 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 27 Sep 2012 01:08:53 +0000 (21:08 -0400)
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>
drivers/staging/android/binder.c
fs/file.c
include/linux/fdtable.h

index b9a534c..4946d28 100644 (file)
@@ -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);
 }
 
 /*
index 08922af..a3a0705 100644 (file)
--- 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);
index 158a41e..b84ca06 100644 (file)
@@ -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 */