diff options
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 128 |
1 files changed, 59 insertions, 69 deletions
@@ -34,7 +34,7 @@ static void *alloc_fdmem(size_t size) | |||
34 | * vmalloc() if the allocation size will be considered "large" by the VM. | 34 | * vmalloc() if the allocation size will be considered "large" by the VM. |
35 | */ | 35 | */ |
36 | if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { | 36 | if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { |
37 | void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN); | 37 | void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY); |
38 | if (data != NULL) | 38 | if (data != NULL) |
39 | return data; | 39 | return data; |
40 | } | 40 | } |
@@ -348,21 +348,16 @@ out: | |||
348 | return NULL; | 348 | return NULL; |
349 | } | 349 | } |
350 | 350 | ||
351 | static void close_files(struct files_struct * files) | 351 | static struct fdtable *close_files(struct files_struct * files) |
352 | { | 352 | { |
353 | int i, j; | ||
354 | struct fdtable *fdt; | ||
355 | |||
356 | j = 0; | ||
357 | |||
358 | /* | 353 | /* |
359 | * It is safe to dereference the fd table without RCU or | 354 | * It is safe to dereference the fd table without RCU or |
360 | * ->file_lock because this is the last reference to the | 355 | * ->file_lock because this is the last reference to the |
361 | * files structure. But use RCU to shut RCU-lockdep up. | 356 | * files structure. |
362 | */ | 357 | */ |
363 | rcu_read_lock(); | 358 | struct fdtable *fdt = rcu_dereference_raw(files->fdt); |
364 | fdt = files_fdtable(files); | 359 | int i, j = 0; |
365 | rcu_read_unlock(); | 360 | |
366 | for (;;) { | 361 | for (;;) { |
367 | unsigned long set; | 362 | unsigned long set; |
368 | i = j * BITS_PER_LONG; | 363 | i = j * BITS_PER_LONG; |
@@ -381,6 +376,8 @@ static void close_files(struct files_struct * files) | |||
381 | set >>= 1; | 376 | set >>= 1; |
382 | } | 377 | } |
383 | } | 378 | } |
379 | |||
380 | return fdt; | ||
384 | } | 381 | } |
385 | 382 | ||
386 | struct files_struct *get_files_struct(struct task_struct *task) | 383 | struct files_struct *get_files_struct(struct task_struct *task) |
@@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task) | |||
398 | 395 | ||
399 | void put_files_struct(struct files_struct *files) | 396 | void put_files_struct(struct files_struct *files) |
400 | { | 397 | { |
401 | struct fdtable *fdt; | ||
402 | |||
403 | if (atomic_dec_and_test(&files->count)) { | 398 | if (atomic_dec_and_test(&files->count)) { |
404 | close_files(files); | 399 | struct fdtable *fdt = close_files(files); |
405 | /* not really needed, since nobody can see us */ | 400 | |
406 | rcu_read_lock(); | ||
407 | fdt = files_fdtable(files); | ||
408 | rcu_read_unlock(); | ||
409 | /* free the arrays if they are not embedded */ | 401 | /* free the arrays if they are not embedded */ |
410 | if (fdt != &files->fdtab) | 402 | if (fdt != &files->fdtab) |
411 | __free_fdtable(fdt); | 403 | __free_fdtable(fdt); |
@@ -645,16 +637,16 @@ void do_close_on_exec(struct files_struct *files) | |||
645 | spin_unlock(&files->file_lock); | 637 | spin_unlock(&files->file_lock); |
646 | } | 638 | } |
647 | 639 | ||
648 | struct file *fget(unsigned int fd) | 640 | static struct file *__fget(unsigned int fd, fmode_t mask) |
649 | { | 641 | { |
650 | struct file *file; | ||
651 | struct files_struct *files = current->files; | 642 | struct files_struct *files = current->files; |
643 | struct file *file; | ||
652 | 644 | ||
653 | rcu_read_lock(); | 645 | rcu_read_lock(); |
654 | file = fcheck_files(files, fd); | 646 | file = fcheck_files(files, fd); |
655 | if (file) { | 647 | if (file) { |
656 | /* File object ref couldn't be taken */ | 648 | /* File object ref couldn't be taken */ |
657 | if (file->f_mode & FMODE_PATH || | 649 | if ((file->f_mode & mask) || |
658 | !atomic_long_inc_not_zero(&file->f_count)) | 650 | !atomic_long_inc_not_zero(&file->f_count)) |
659 | file = NULL; | 651 | file = NULL; |
660 | } | 652 | } |
@@ -663,25 +655,16 @@ struct file *fget(unsigned int fd) | |||
663 | return file; | 655 | return file; |
664 | } | 656 | } |
665 | 657 | ||
658 | struct file *fget(unsigned int fd) | ||
659 | { | ||
660 | return __fget(fd, FMODE_PATH); | ||
661 | } | ||
666 | EXPORT_SYMBOL(fget); | 662 | EXPORT_SYMBOL(fget); |
667 | 663 | ||
668 | struct file *fget_raw(unsigned int fd) | 664 | struct file *fget_raw(unsigned int fd) |
669 | { | 665 | { |
670 | struct file *file; | 666 | return __fget(fd, 0); |
671 | struct files_struct *files = current->files; | ||
672 | |||
673 | rcu_read_lock(); | ||
674 | file = fcheck_files(files, fd); | ||
675 | if (file) { | ||
676 | /* File object ref couldn't be taken */ | ||
677 | if (!atomic_long_inc_not_zero(&file->f_count)) | ||
678 | file = NULL; | ||
679 | } | ||
680 | rcu_read_unlock(); | ||
681 | |||
682 | return file; | ||
683 | } | 667 | } |
684 | |||
685 | EXPORT_SYMBOL(fget_raw); | 668 | EXPORT_SYMBOL(fget_raw); |
686 | 669 | ||
687 | /* | 670 | /* |
@@ -700,58 +683,65 @@ EXPORT_SYMBOL(fget_raw); | |||
700 | * The fput_needed flag returned by fget_light should be passed to the | 683 | * The fput_needed flag returned by fget_light should be passed to the |
701 | * corresponding fput_light. | 684 | * corresponding fput_light. |
702 | */ | 685 | */ |
703 | struct file *fget_light(unsigned int fd, int *fput_needed) | 686 | static unsigned long __fget_light(unsigned int fd, fmode_t mask) |
704 | { | 687 | { |
705 | struct file *file; | ||
706 | struct files_struct *files = current->files; | 688 | struct files_struct *files = current->files; |
689 | struct file *file; | ||
707 | 690 | ||
708 | *fput_needed = 0; | ||
709 | if (atomic_read(&files->count) == 1) { | 691 | if (atomic_read(&files->count) == 1) { |
710 | file = fcheck_files(files, fd); | 692 | file = __fcheck_files(files, fd); |
711 | if (file && (file->f_mode & FMODE_PATH)) | 693 | if (!file || unlikely(file->f_mode & mask)) |
712 | file = NULL; | 694 | return 0; |
695 | return (unsigned long)file; | ||
713 | } else { | 696 | } else { |
714 | rcu_read_lock(); | 697 | file = __fget(fd, mask); |
715 | file = fcheck_files(files, fd); | 698 | if (!file) |
716 | if (file) { | 699 | return 0; |
717 | if (!(file->f_mode & FMODE_PATH) && | 700 | return FDPUT_FPUT | (unsigned long)file; |
718 | atomic_long_inc_not_zero(&file->f_count)) | ||
719 | *fput_needed = 1; | ||
720 | else | ||
721 | /* Didn't get the reference, someone's freed */ | ||
722 | file = NULL; | ||
723 | } | ||
724 | rcu_read_unlock(); | ||
725 | } | 701 | } |
702 | } | ||
703 | unsigned long __fdget(unsigned int fd) | ||
704 | { | ||
705 | return __fget_light(fd, FMODE_PATH); | ||
706 | } | ||
707 | EXPORT_SYMBOL(__fdget); | ||
726 | 708 | ||
727 | return file; | 709 | unsigned long __fdget_raw(unsigned int fd) |
710 | { | ||
711 | return __fget_light(fd, 0); | ||
728 | } | 712 | } |
729 | EXPORT_SYMBOL(fget_light); | ||
730 | 713 | ||
731 | struct file *fget_raw_light(unsigned int fd, int *fput_needed) | 714 | unsigned long __fdget_pos(unsigned int fd) |
732 | { | 715 | { |
733 | struct file *file; | ||
734 | struct files_struct *files = current->files; | 716 | struct files_struct *files = current->files; |
717 | struct file *file; | ||
718 | unsigned long v; | ||
735 | 719 | ||
736 | *fput_needed = 0; | ||
737 | if (atomic_read(&files->count) == 1) { | 720 | if (atomic_read(&files->count) == 1) { |
738 | file = fcheck_files(files, fd); | 721 | file = __fcheck_files(files, fd); |
722 | v = 0; | ||
739 | } else { | 723 | } else { |
740 | rcu_read_lock(); | 724 | file = __fget(fd, 0); |
741 | file = fcheck_files(files, fd); | 725 | v = FDPUT_FPUT; |
742 | if (file) { | ||
743 | if (atomic_long_inc_not_zero(&file->f_count)) | ||
744 | *fput_needed = 1; | ||
745 | else | ||
746 | /* Didn't get the reference, someone's freed */ | ||
747 | file = NULL; | ||
748 | } | ||
749 | rcu_read_unlock(); | ||
750 | } | 726 | } |
727 | if (!file) | ||
728 | return 0; | ||
751 | 729 | ||
752 | return file; | 730 | if (file->f_mode & FMODE_ATOMIC_POS) { |
731 | if (file_count(file) > 1) { | ||
732 | v |= FDPUT_POS_UNLOCK; | ||
733 | mutex_lock(&file->f_pos_lock); | ||
734 | } | ||
735 | } | ||
736 | return v | (unsigned long)file; | ||
753 | } | 737 | } |
754 | 738 | ||
739 | /* | ||
740 | * We only lock f_pos if we have threads or if the file might be | ||
741 | * shared with another process. In both cases we'll have an elevated | ||
742 | * file count (done either by fdget() or by fork()). | ||
743 | */ | ||
744 | |||
755 | void set_close_on_exec(unsigned int fd, int flag) | 745 | void set_close_on_exec(unsigned int fd, int flag) |
756 | { | 746 | { |
757 | struct files_struct *files = current->files; | 747 | struct files_struct *files = current->files; |