Commit 02afc6267f6d55d47aba9fcafdbd1b7230d2294a

Authored by Al Viro
1 parent f52111b154

[PATCH] dup_fd() fixes, part 1

Move the sucker to fs/file.c in preparation to the rest

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 3 changed files with 131 additions and 130 deletions Side-by-side Diff

... ... @@ -261,6 +261,136 @@
261 261 return expand_fdtable(files, nr);
262 262 }
263 263  
  264 +static int count_open_files(struct fdtable *fdt)
  265 +{
  266 + int size = fdt->max_fds;
  267 + int i;
  268 +
  269 + /* Find the last open fd */
  270 + for (i = size/(8*sizeof(long)); i > 0; ) {
  271 + if (fdt->open_fds->fds_bits[--i])
  272 + break;
  273 + }
  274 + i = (i+1) * 8 * sizeof(long);
  275 + return i;
  276 +}
  277 +
  278 +static struct files_struct *alloc_files(void)
  279 +{
  280 + struct files_struct *newf;
  281 + struct fdtable *fdt;
  282 +
  283 + newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
  284 + if (!newf)
  285 + goto out;
  286 +
  287 + atomic_set(&newf->count, 1);
  288 +
  289 + spin_lock_init(&newf->file_lock);
  290 + newf->next_fd = 0;
  291 + fdt = &newf->fdtab;
  292 + fdt->max_fds = NR_OPEN_DEFAULT;
  293 + fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
  294 + fdt->open_fds = (fd_set *)&newf->open_fds_init;
  295 + fdt->fd = &newf->fd_array[0];
  296 + INIT_RCU_HEAD(&fdt->rcu);
  297 + fdt->next = NULL;
  298 + rcu_assign_pointer(newf->fdt, fdt);
  299 +out:
  300 + return newf;
  301 +}
  302 +
  303 +/*
  304 + * Allocate a new files structure and copy contents from the
  305 + * passed in files structure.
  306 + * errorp will be valid only when the returned files_struct is NULL.
  307 + */
  308 +struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
  309 +{
  310 + struct files_struct *newf;
  311 + struct file **old_fds, **new_fds;
  312 + int open_files, size, i;
  313 + struct fdtable *old_fdt, *new_fdt;
  314 +
  315 + *errorp = -ENOMEM;
  316 + newf = alloc_files();
  317 + if (!newf)
  318 + goto out;
  319 +
  320 + spin_lock(&oldf->file_lock);
  321 + old_fdt = files_fdtable(oldf);
  322 + new_fdt = files_fdtable(newf);
  323 + open_files = count_open_files(old_fdt);
  324 +
  325 + /*
  326 + * Check whether we need to allocate a larger fd array and fd set.
  327 + * Note: we're not a clone task, so the open count won't change.
  328 + */
  329 + if (open_files > new_fdt->max_fds) {
  330 + new_fdt->max_fds = 0;
  331 + spin_unlock(&oldf->file_lock);
  332 + spin_lock(&newf->file_lock);
  333 + *errorp = expand_files(newf, open_files-1);
  334 + spin_unlock(&newf->file_lock);
  335 + if (*errorp < 0)
  336 + goto out_release;
  337 + new_fdt = files_fdtable(newf);
  338 + /*
  339 + * Reacquire the oldf lock and a pointer to its fd table
  340 + * who knows it may have a new bigger fd table. We need
  341 + * the latest pointer.
  342 + */
  343 + spin_lock(&oldf->file_lock);
  344 + old_fdt = files_fdtable(oldf);
  345 + }
  346 +
  347 + old_fds = old_fdt->fd;
  348 + new_fds = new_fdt->fd;
  349 +
  350 + memcpy(new_fdt->open_fds->fds_bits,
  351 + old_fdt->open_fds->fds_bits, open_files/8);
  352 + memcpy(new_fdt->close_on_exec->fds_bits,
  353 + old_fdt->close_on_exec->fds_bits, open_files/8);
  354 +
  355 + for (i = open_files; i != 0; i--) {
  356 + struct file *f = *old_fds++;
  357 + if (f) {
  358 + get_file(f);
  359 + } else {
  360 + /*
  361 + * The fd may be claimed in the fd bitmap but not yet
  362 + * instantiated in the files array if a sibling thread
  363 + * is partway through open(). So make sure that this
  364 + * fd is available to the new process.
  365 + */
  366 + FD_CLR(open_files - i, new_fdt->open_fds);
  367 + }
  368 + rcu_assign_pointer(*new_fds++, f);
  369 + }
  370 + spin_unlock(&oldf->file_lock);
  371 +
  372 + /* compute the remainder to be cleared */
  373 + size = (new_fdt->max_fds - open_files) * sizeof(struct file *);
  374 +
  375 + /* This is long word aligned thus could use a optimized version */
  376 + memset(new_fds, 0, size);
  377 +
  378 + if (new_fdt->max_fds > open_files) {
  379 + int left = (new_fdt->max_fds-open_files)/8;
  380 + int start = open_files / (8 * sizeof(unsigned long));
  381 +
  382 + memset(&new_fdt->open_fds->fds_bits[start], 0, left);
  383 + memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
  384 + }
  385 +
  386 + return newf;
  387 +
  388 +out_release:
  389 + kmem_cache_free(files_cachep, newf);
  390 +out:
  391 + return NULL;
  392 +}
  393 +
264 394 static void __devinit fdtable_defer_list_init(int cpu)
265 395 {
266 396 struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu);
include/linux/fdtable.h
... ... @@ -93,6 +93,7 @@
93 93 void put_files_struct(struct files_struct *fs);
94 94 void reset_files_struct(struct files_struct *);
95 95 int unshare_files(struct files_struct **);
  96 +struct files_struct *dup_fd(struct files_struct *, int *);
96 97  
97 98 extern struct kmem_cache *files_cachep;
98 99  
... ... @@ -660,136 +660,6 @@
660 660 return 0;
661 661 }
662 662  
663   -static int count_open_files(struct fdtable *fdt)
664   -{
665   - int size = fdt->max_fds;
666   - int i;
667   -
668   - /* Find the last open fd */
669   - for (i = size/(8*sizeof(long)); i > 0; ) {
670   - if (fdt->open_fds->fds_bits[--i])
671   - break;
672   - }
673   - i = (i+1) * 8 * sizeof(long);
674   - return i;
675   -}
676   -
677   -static struct files_struct *alloc_files(void)
678   -{
679   - struct files_struct *newf;
680   - struct fdtable *fdt;
681   -
682   - newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
683   - if (!newf)
684   - goto out;
685   -
686   - atomic_set(&newf->count, 1);
687   -
688   - spin_lock_init(&newf->file_lock);
689   - newf->next_fd = 0;
690   - fdt = &newf->fdtab;
691   - fdt->max_fds = NR_OPEN_DEFAULT;
692   - fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
693   - fdt->open_fds = (fd_set *)&newf->open_fds_init;
694   - fdt->fd = &newf->fd_array[0];
695   - INIT_RCU_HEAD(&fdt->rcu);
696   - fdt->next = NULL;
697   - rcu_assign_pointer(newf->fdt, fdt);
698   -out:
699   - return newf;
700   -}
701   -
702   -/*
703   - * Allocate a new files structure and copy contents from the
704   - * passed in files structure.
705   - * errorp will be valid only when the returned files_struct is NULL.
706   - */
707   -static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
708   -{
709   - struct files_struct *newf;
710   - struct file **old_fds, **new_fds;
711   - int open_files, size, i;
712   - struct fdtable *old_fdt, *new_fdt;
713   -
714   - *errorp = -ENOMEM;
715   - newf = alloc_files();
716   - if (!newf)
717   - goto out;
718   -
719   - spin_lock(&oldf->file_lock);
720   - old_fdt = files_fdtable(oldf);
721   - new_fdt = files_fdtable(newf);
722   - open_files = count_open_files(old_fdt);
723   -
724   - /*
725   - * Check whether we need to allocate a larger fd array and fd set.
726   - * Note: we're not a clone task, so the open count won't change.
727   - */
728   - if (open_files > new_fdt->max_fds) {
729   - new_fdt->max_fds = 0;
730   - spin_unlock(&oldf->file_lock);
731   - spin_lock(&newf->file_lock);
732   - *errorp = expand_files(newf, open_files-1);
733   - spin_unlock(&newf->file_lock);
734   - if (*errorp < 0)
735   - goto out_release;
736   - new_fdt = files_fdtable(newf);
737   - /*
738   - * Reacquire the oldf lock and a pointer to its fd table
739   - * who knows it may have a new bigger fd table. We need
740   - * the latest pointer.
741   - */
742   - spin_lock(&oldf->file_lock);
743   - old_fdt = files_fdtable(oldf);
744   - }
745   -
746   - old_fds = old_fdt->fd;
747   - new_fds = new_fdt->fd;
748   -
749   - memcpy(new_fdt->open_fds->fds_bits,
750   - old_fdt->open_fds->fds_bits, open_files/8);
751   - memcpy(new_fdt->close_on_exec->fds_bits,
752   - old_fdt->close_on_exec->fds_bits, open_files/8);
753   -
754   - for (i = open_files; i != 0; i--) {
755   - struct file *f = *old_fds++;
756   - if (f) {
757   - get_file(f);
758   - } else {
759   - /*
760   - * The fd may be claimed in the fd bitmap but not yet
761   - * instantiated in the files array if a sibling thread
762   - * is partway through open(). So make sure that this
763   - * fd is available to the new process.
764   - */
765   - FD_CLR(open_files - i, new_fdt->open_fds);
766   - }
767   - rcu_assign_pointer(*new_fds++, f);
768   - }
769   - spin_unlock(&oldf->file_lock);
770   -
771   - /* compute the remainder to be cleared */
772   - size = (new_fdt->max_fds - open_files) * sizeof(struct file *);
773   -
774   - /* This is long word aligned thus could use a optimized version */
775   - memset(new_fds, 0, size);
776   -
777   - if (new_fdt->max_fds > open_files) {
778   - int left = (new_fdt->max_fds-open_files)/8;
779   - int start = open_files / (8 * sizeof(unsigned long));
780   -
781   - memset(&new_fdt->open_fds->fds_bits[start], 0, left);
782   - memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
783   - }
784   -
785   - return newf;
786   -
787   -out_release:
788   - kmem_cache_free(files_cachep, newf);
789   -out:
790   - return NULL;
791   -}
792   -
793 663 static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
794 664 {
795 665 struct files_struct *oldf, *newf;