[PATCH] knfsd: Allow lockd to drop replies as appropriate
[pandora-kernel.git] / fs / file.c
index b3c6b82..8e81775 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -281,80 +281,70 @@ static struct fdtable *alloc_fdtable(int nr)
 out2:
        nfds = fdt->max_fdset;
 out:
-       if (new_openset)
-               free_fdset(new_openset, nfds);
-       if (new_execset)
-               free_fdset(new_execset, nfds);
+       free_fdset(new_openset, nfds);
+       free_fdset(new_execset, nfds);
        kfree(fdt);
        return NULL;
 }
 
 /*
- * Expands the file descriptor table - it will allocate a new fdtable and
- * both fd array and fdset. It is expected to be called with the
- * files_lock held.
+ * Expand the file descriptor table.
+ * This function will allocate a new fdtable and both fd array and fdset, of
+ * the given size.
+ * Return <0 error code on error; 1 on successful completion.
+ * The files->file_lock should be held on entry, and will be held on exit.
  */
 static int expand_fdtable(struct files_struct *files, int nr)
        __releases(files->file_lock)
        __acquires(files->file_lock)
 {
-       int error = 0;
-       struct fdtable *fdt;
-       struct fdtable *nfdt = NULL;
+       struct fdtable *new_fdt, *cur_fdt;
 
        spin_unlock(&files->file_lock);
-       nfdt = alloc_fdtable(nr);
-       if (!nfdt) {
-               error = -ENOMEM;
-               spin_lock(&files->file_lock);
-               goto out;
-       }
-
+       new_fdt = alloc_fdtable(nr);
        spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
+       if (!new_fdt)
+               return -ENOMEM;
        /*
-        * Check again since another task may have expanded the
-        * fd table while we dropped the lock
+        * Check again since another task may have expanded the fd table while
+        * we dropped the lock
         */
-       if (nr >= fdt->max_fds || nr >= fdt->max_fdset) {
-               copy_fdtable(nfdt, fdt);
+       cur_fdt = files_fdtable(files);
+       if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
+               /* Continue as planned */
+               copy_fdtable(new_fdt, cur_fdt);
+               rcu_assign_pointer(files->fdt, new_fdt);
+               free_fdtable(cur_fdt);
        } else {
-               /* Somebody expanded while we dropped file_lock */
-               spin_unlock(&files->file_lock);
-               __free_fdtable(nfdt);
-               spin_lock(&files->file_lock);
-               goto out;
+               /* Somebody else expanded, so undo our attempt */
+               __free_fdtable(new_fdt);
        }
-       rcu_assign_pointer(files->fdt, nfdt);
-       free_fdtable(fdt);
-out:
-       return error;
+       return 1;
 }
 
 /*
  * Expand files.
- * Return <0 on error; 0 nothing done; 1 files expanded, we may have blocked.
- * Should be called with the files->file_lock spinlock held for write.
+ * This function will expand the file structures, if the requested size exceeds
+ * the current capacity and there is room for expansion.
+ * Return <0 error code on error; 0 when nothing done; 1 when files were
+ * expanded and execution may have blocked.
+ * The files->file_lock should be held on entry, and will be held on exit.
  */
 int expand_files(struct files_struct *files, int nr)
 {
-       int err, expand = 0;
        struct fdtable *fdt;
 
        fdt = files_fdtable(files);
-       if (nr >= fdt->max_fdset || nr >= fdt->max_fds) {
-               if (fdt->max_fdset >= NR_OPEN ||
-                       fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) {
-                       err = -EMFILE;
-                       goto out;
-               }
-               expand = 1;
-               if ((err = expand_fdtable(files, nr)))
-                       goto out;
-       }
-       err = expand;
-out:
-       return err;
+       /* Do we need to expand? */
+       if (nr < fdt->max_fdset && nr < fdt->max_fds)
+               return 0;
+       /* Can we expand? */
+       if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
+           nr >= NR_OPEN)
+               return -EMFILE;
+
+       /* All good, so we try */
+       return expand_fdtable(files, nr);
 }
 
 static void __devinit fdtable_defer_list_init(int cpu)