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; |
