]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/file.c
Introduce rculist.h
[linux-2.6-omap-h63xx.git] / fs / file.c
index 6491b2b5bc3828fd012a094d93216b67b31b9f0e..7b3887e054d0bcb5e0e187c8e1e42691c4fadcd0 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -26,6 +26,8 @@ struct fdtable_defer {
 };
 
 int sysctl_nr_open __read_mostly = 1024*1024;
+int sysctl_nr_open_min = BITS_PER_LONG;
+int sysctl_nr_open_max = 1024 * 1024; /* raised later */
 
 /*
  * We use this list to defer free fdtables that have vmalloced
@@ -273,31 +275,6 @@ static int count_open_files(struct fdtable *fdt)
        return i;
 }
 
-static struct files_struct *alloc_files(void)
-{
-       struct files_struct *newf;
-       struct fdtable *fdt;
-
-       newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
-       if (!newf)
-               goto out;
-
-       atomic_set(&newf->count, 1);
-
-       spin_lock_init(&newf->file_lock);
-       newf->next_fd = 0;
-       fdt = &newf->fdtab;
-       fdt->max_fds = NR_OPEN_DEFAULT;
-       fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
-       fdt->open_fds = (fd_set *)&newf->open_fds_init;
-       fdt->fd = &newf->fd_array[0];
-       INIT_RCU_HEAD(&fdt->rcu);
-       fdt->next = NULL;
-       rcu_assign_pointer(newf->fdt, fdt);
-out:
-       return newf;
-}
-
 /*
  * Allocate a new files structure and copy contents from the
  * passed in files structure.
@@ -311,22 +288,38 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
        struct fdtable *old_fdt, *new_fdt;
 
        *errorp = -ENOMEM;
-       newf = alloc_files();
+       newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
        if (!newf)
                goto out;
 
+       atomic_set(&newf->count, 1);
+
+       spin_lock_init(&newf->file_lock);
+       newf->next_fd = 0;
+       new_fdt = &newf->fdtab;
+       new_fdt->max_fds = NR_OPEN_DEFAULT;
+       new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
+       new_fdt->open_fds = (fd_set *)&newf->open_fds_init;
+       new_fdt->fd = &newf->fd_array[0];
+       INIT_RCU_HEAD(&new_fdt->rcu);
+       new_fdt->next = NULL;
+
        spin_lock(&oldf->file_lock);
        old_fdt = files_fdtable(oldf);
-       new_fdt = files_fdtable(newf);
        open_files = count_open_files(old_fdt);
 
        /*
         * Check whether we need to allocate a larger fd array and fd set.
-        * Note: we're not a clone task, so the open count won't change.
         */
-       if (open_files > new_fdt->max_fds) {
+       while (unlikely(open_files > new_fdt->max_fds)) {
                spin_unlock(&oldf->file_lock);
 
+               if (new_fdt != &newf->fdtab) {
+                       free_fdarr(new_fdt);
+                       free_fdset(new_fdt);
+                       kfree(new_fdt);
+               }
+
                new_fdt = alloc_fdtable(open_files - 1);
                if (!new_fdt) {
                        *errorp = -ENOMEM;
@@ -341,7 +334,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
                        *errorp = -EMFILE;
                        goto out_release;
                }
-               rcu_assign_pointer(files->fdt, new_fdt);
 
                /*
                 * Reacquire the oldf lock and a pointer to its fd table
@@ -350,6 +342,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
                 */
                spin_lock(&oldf->file_lock);
                old_fdt = files_fdtable(oldf);
+               open_files = count_open_files(old_fdt);
        }
 
        old_fds = old_fdt->fd;
@@ -391,6 +384,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
                memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
        }
 
+       rcu_assign_pointer(newf->fdt, new_fdt);
+
        return newf;
 
 out_release:
@@ -412,6 +407,8 @@ void __init files_defer_init(void)
        int i;
        for_each_possible_cpu(i)
                fdtable_defer_list_init(i);
+       sysctl_nr_open_max = min((size_t)INT_MAX, ~(size_t)0/sizeof(void *)) &
+                            -BITS_PER_LONG;
 }
 
 struct files_struct init_files = {