[PATCH] dup_fd() fixes, part 1
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 8 May 2008 23:42:56 +0000 (19:42 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 16 May 2008 21:22:26 +0000 (17:22 -0400)
Move the sucker to fs/file.c in preparation to the rest

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/file.c
include/linux/fdtable.h
kernel/fork.c

index 754cd05b06af7ff3b58ddc0c7dde3dc67f54f420..7dbadaaf00f016d7c388fa9133a739a5cce349e8 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -261,6 +261,136 @@ int expand_files(struct files_struct *files, int nr)
        return expand_fdtable(files, nr);
 }
 
+static int count_open_files(struct fdtable *fdt)
+{
+       int size = fdt->max_fds;
+       int i;
+
+       /* Find the last open fd */
+       for (i = size/(8*sizeof(long)); i > 0; ) {
+               if (fdt->open_fds->fds_bits[--i])
+                       break;
+       }
+       i = (i+1) * 8 * sizeof(long);
+       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.
+ * errorp will be valid only when the returned files_struct is NULL.
+ */
+struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
+{
+       struct files_struct *newf;
+       struct file **old_fds, **new_fds;
+       int open_files, size, i;
+       struct fdtable *old_fdt, *new_fdt;
+
+       *errorp = -ENOMEM;
+       newf = alloc_files();
+       if (!newf)
+               goto out;
+
+       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) {
+               new_fdt->max_fds = 0;
+               spin_unlock(&oldf->file_lock);
+               spin_lock(&newf->file_lock);
+               *errorp = expand_files(newf, open_files-1);
+               spin_unlock(&newf->file_lock);
+               if (*errorp < 0)
+                       goto out_release;
+               new_fdt = files_fdtable(newf);
+               /*
+                * Reacquire the oldf lock and a pointer to its fd table
+                * who knows it may have a new bigger fd table. We need
+                * the latest pointer.
+                */
+               spin_lock(&oldf->file_lock);
+               old_fdt = files_fdtable(oldf);
+       }
+
+       old_fds = old_fdt->fd;
+       new_fds = new_fdt->fd;
+
+       memcpy(new_fdt->open_fds->fds_bits,
+               old_fdt->open_fds->fds_bits, open_files/8);
+       memcpy(new_fdt->close_on_exec->fds_bits,
+               old_fdt->close_on_exec->fds_bits, open_files/8);
+
+       for (i = open_files; i != 0; i--) {
+               struct file *f = *old_fds++;
+               if (f) {
+                       get_file(f);
+               } else {
+                       /*
+                        * The fd may be claimed in the fd bitmap but not yet
+                        * instantiated in the files array if a sibling thread
+                        * is partway through open().  So make sure that this
+                        * fd is available to the new process.
+                        */
+                       FD_CLR(open_files - i, new_fdt->open_fds);
+               }
+               rcu_assign_pointer(*new_fds++, f);
+       }
+       spin_unlock(&oldf->file_lock);
+
+       /* compute the remainder to be cleared */
+       size = (new_fdt->max_fds - open_files) * sizeof(struct file *);
+
+       /* This is long word aligned thus could use a optimized version */
+       memset(new_fds, 0, size);
+
+       if (new_fdt->max_fds > open_files) {
+               int left = (new_fdt->max_fds-open_files)/8;
+               int start = open_files / (8 * sizeof(unsigned long));
+
+               memset(&new_fdt->open_fds->fds_bits[start], 0, left);
+               memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
+       }
+
+       return newf;
+
+out_release:
+       kmem_cache_free(files_cachep, newf);
+out:
+       return NULL;
+}
+
 static void __devinit fdtable_defer_list_init(int cpu)
 {
        struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu);
index a118f3c0b240feb6b18c93c6c968557bdab117ae..4aab6f12cfab1cb32a13c220916a9710cb42cb7d 100644 (file)
@@ -93,6 +93,7 @@ struct files_struct *get_files_struct(struct task_struct *);
 void put_files_struct(struct files_struct *fs);
 void reset_files_struct(struct files_struct *);
 int unshare_files(struct files_struct **);
+struct files_struct *dup_fd(struct files_struct *, int *);
 
 extern struct kmem_cache *files_cachep;
 
index 933e60ebccae9f35001753a4426993c6aaf54fb6..19908b26cf80494a0db8f3410384521081293a32 100644 (file)
@@ -660,136 +660,6 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
        return 0;
 }
 
-static int count_open_files(struct fdtable *fdt)
-{
-       int size = fdt->max_fds;
-       int i;
-
-       /* Find the last open fd */
-       for (i = size/(8*sizeof(long)); i > 0; ) {
-               if (fdt->open_fds->fds_bits[--i])
-                       break;
-       }
-       i = (i+1) * 8 * sizeof(long);
-       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.
- * errorp will be valid only when the returned files_struct is NULL.
- */
-static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
-{
-       struct files_struct *newf;
-       struct file **old_fds, **new_fds;
-       int open_files, size, i;
-       struct fdtable *old_fdt, *new_fdt;
-
-       *errorp = -ENOMEM;
-       newf = alloc_files();
-       if (!newf)
-               goto out;
-
-       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) {
-               new_fdt->max_fds = 0;
-               spin_unlock(&oldf->file_lock);
-               spin_lock(&newf->file_lock);
-               *errorp = expand_files(newf, open_files-1);
-               spin_unlock(&newf->file_lock);
-               if (*errorp < 0)
-                       goto out_release;
-               new_fdt = files_fdtable(newf);
-               /*
-                * Reacquire the oldf lock and a pointer to its fd table
-                * who knows it may have a new bigger fd table. We need
-                * the latest pointer.
-                */
-               spin_lock(&oldf->file_lock);
-               old_fdt = files_fdtable(oldf);
-       }
-
-       old_fds = old_fdt->fd;
-       new_fds = new_fdt->fd;
-
-       memcpy(new_fdt->open_fds->fds_bits,
-               old_fdt->open_fds->fds_bits, open_files/8);
-       memcpy(new_fdt->close_on_exec->fds_bits,
-               old_fdt->close_on_exec->fds_bits, open_files/8);
-
-       for (i = open_files; i != 0; i--) {
-               struct file *f = *old_fds++;
-               if (f) {
-                       get_file(f);
-               } else {
-                       /*
-                        * The fd may be claimed in the fd bitmap but not yet
-                        * instantiated in the files array if a sibling thread
-                        * is partway through open().  So make sure that this
-                        * fd is available to the new process.
-                        */
-                       FD_CLR(open_files - i, new_fdt->open_fds);
-               }
-               rcu_assign_pointer(*new_fds++, f);
-       }
-       spin_unlock(&oldf->file_lock);
-
-       /* compute the remainder to be cleared */
-       size = (new_fdt->max_fds - open_files) * sizeof(struct file *);
-
-       /* This is long word aligned thus could use a optimized version */
-       memset(new_fds, 0, size);
-
-       if (new_fdt->max_fds > open_files) {
-               int left = (new_fdt->max_fds-open_files)/8;
-               int start = open_files / (8 * sizeof(unsigned long));
-
-               memset(&new_fdt->open_fds->fds_bits[start], 0, left);
-               memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
-       }
-
-       return newf;
-
-out_release:
-       kmem_cache_free(files_cachep, newf);
-out:
-       return NULL;
-}
-
 static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 {
        struct files_struct *oldf, *newf;