diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 163 |
1 files changed, 94 insertions, 69 deletions
| @@ -10,7 +10,7 @@ | |||
| 10 | #include <linux/file.h> | 10 | #include <linux/file.h> |
| 11 | #include <linux/smp_lock.h> | 11 | #include <linux/smp_lock.h> |
| 12 | #include <linux/quotaops.h> | 12 | #include <linux/quotaops.h> |
| 13 | #include <linux/dnotify.h> | 13 | #include <linux/fsnotify.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/tty.h> | 16 | #include <linux/tty.h> |
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
| 25 | #include <linux/pagemap.h> | 25 | #include <linux/pagemap.h> |
| 26 | #include <linux/syscalls.h> | 26 | #include <linux/syscalls.h> |
| 27 | #include <linux/rcupdate.h> | ||
| 27 | 28 | ||
| 28 | #include <asm/unistd.h> | 29 | #include <asm/unistd.h> |
| 29 | 30 | ||
| @@ -737,52 +738,15 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) | |||
| 737 | return error; | 738 | return error; |
| 738 | } | 739 | } |
| 739 | 740 | ||
| 740 | /* | 741 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
| 741 | * Note that while the flag value (low two bits) for sys_open means: | 742 | int flags, struct file *f) |
| 742 | * 00 - read-only | ||
| 743 | * 01 - write-only | ||
| 744 | * 10 - read-write | ||
| 745 | * 11 - special | ||
| 746 | * it is changed into | ||
| 747 | * 00 - no permissions needed | ||
| 748 | * 01 - read-permission | ||
| 749 | * 10 - write-permission | ||
| 750 | * 11 - read-write | ||
| 751 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
| 752 | * used by symlinks. | ||
| 753 | */ | ||
| 754 | struct file *filp_open(const char * filename, int flags, int mode) | ||
| 755 | { | 743 | { |
| 756 | int namei_flags, error; | ||
| 757 | struct nameidata nd; | ||
| 758 | |||
| 759 | namei_flags = flags; | ||
| 760 | if ((namei_flags+1) & O_ACCMODE) | ||
| 761 | namei_flags++; | ||
| 762 | if (namei_flags & O_TRUNC) | ||
| 763 | namei_flags |= 2; | ||
| 764 | |||
| 765 | error = open_namei(filename, namei_flags, mode, &nd); | ||
| 766 | if (!error) | ||
| 767 | return dentry_open(nd.dentry, nd.mnt, flags); | ||
| 768 | |||
| 769 | return ERR_PTR(error); | ||
| 770 | } | ||
| 771 | |||
| 772 | EXPORT_SYMBOL(filp_open); | ||
| 773 | |||
| 774 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | ||
| 775 | { | ||
| 776 | struct file * f; | ||
| 777 | struct inode *inode; | 744 | struct inode *inode; |
| 778 | int error; | 745 | int error; |
| 779 | 746 | ||
| 780 | error = -ENFILE; | ||
| 781 | f = get_empty_filp(); | ||
| 782 | if (!f) | ||
| 783 | goto cleanup_dentry; | ||
| 784 | f->f_flags = flags; | 747 | f->f_flags = flags; |
| 785 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; | 748 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | |
| 749 | FMODE_PREAD | FMODE_PWRITE; | ||
| 786 | inode = dentry->d_inode; | 750 | inode = dentry->d_inode; |
| 787 | if (f->f_mode & FMODE_WRITE) { | 751 | if (f->f_mode & FMODE_WRITE) { |
| 788 | error = get_write_access(inode); | 752 | error = get_write_access(inode); |
| @@ -827,12 +791,63 @@ cleanup_all: | |||
| 827 | f->f_vfsmnt = NULL; | 791 | f->f_vfsmnt = NULL; |
| 828 | cleanup_file: | 792 | cleanup_file: |
| 829 | put_filp(f); | 793 | put_filp(f); |
| 830 | cleanup_dentry: | ||
| 831 | dput(dentry); | 794 | dput(dentry); |
| 832 | mntput(mnt); | 795 | mntput(mnt); |
| 833 | return ERR_PTR(error); | 796 | return ERR_PTR(error); |
| 834 | } | 797 | } |
| 835 | 798 | ||
| 799 | /* | ||
| 800 | * Note that while the flag value (low two bits) for sys_open means: | ||
| 801 | * 00 - read-only | ||
| 802 | * 01 - write-only | ||
| 803 | * 10 - read-write | ||
| 804 | * 11 - special | ||
| 805 | * it is changed into | ||
| 806 | * 00 - no permissions needed | ||
| 807 | * 01 - read-permission | ||
| 808 | * 10 - write-permission | ||
| 809 | * 11 - read-write | ||
| 810 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
| 811 | * used by symlinks. | ||
| 812 | */ | ||
| 813 | struct file *filp_open(const char * filename, int flags, int mode) | ||
| 814 | { | ||
| 815 | int namei_flags, error; | ||
| 816 | struct nameidata nd; | ||
| 817 | struct file *f; | ||
| 818 | |||
| 819 | namei_flags = flags; | ||
| 820 | if ((namei_flags+1) & O_ACCMODE) | ||
| 821 | namei_flags++; | ||
| 822 | if (namei_flags & O_TRUNC) | ||
| 823 | namei_flags |= 2; | ||
| 824 | |||
| 825 | error = -ENFILE; | ||
| 826 | f = get_empty_filp(); | ||
| 827 | if (f == NULL) | ||
| 828 | return ERR_PTR(error); | ||
| 829 | |||
| 830 | error = open_namei(filename, namei_flags, mode, &nd); | ||
| 831 | if (!error) | ||
| 832 | return __dentry_open(nd.dentry, nd.mnt, flags, f); | ||
| 833 | |||
| 834 | put_filp(f); | ||
| 835 | return ERR_PTR(error); | ||
| 836 | } | ||
| 837 | EXPORT_SYMBOL(filp_open); | ||
| 838 | |||
| 839 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | ||
| 840 | { | ||
| 841 | int error; | ||
| 842 | struct file *f; | ||
| 843 | |||
| 844 | error = -ENFILE; | ||
| 845 | f = get_empty_filp(); | ||
| 846 | if (f == NULL) | ||
| 847 | return ERR_PTR(error); | ||
| 848 | |||
| 849 | return __dentry_open(dentry, mnt, flags, f); | ||
| 850 | } | ||
| 836 | EXPORT_SYMBOL(dentry_open); | 851 | EXPORT_SYMBOL(dentry_open); |
| 837 | 852 | ||
| 838 | /* | 853 | /* |
| @@ -842,14 +857,16 @@ int get_unused_fd(void) | |||
| 842 | { | 857 | { |
| 843 | struct files_struct * files = current->files; | 858 | struct files_struct * files = current->files; |
| 844 | int fd, error; | 859 | int fd, error; |
| 860 | struct fdtable *fdt; | ||
| 845 | 861 | ||
| 846 | error = -EMFILE; | 862 | error = -EMFILE; |
| 847 | spin_lock(&files->file_lock); | 863 | spin_lock(&files->file_lock); |
| 848 | 864 | ||
| 849 | repeat: | 865 | repeat: |
| 850 | fd = find_next_zero_bit(files->open_fds->fds_bits, | 866 | fdt = files_fdtable(files); |
| 851 | files->max_fdset, | 867 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, |
| 852 | files->next_fd); | 868 | fdt->max_fdset, |
| 869 | fdt->next_fd); | ||
| 853 | 870 | ||
| 854 | /* | 871 | /* |
| 855 | * N.B. For clone tasks sharing a files structure, this test | 872 | * N.B. For clone tasks sharing a files structure, this test |
| @@ -872,14 +889,14 @@ repeat: | |||
| 872 | goto repeat; | 889 | goto repeat; |
| 873 | } | 890 | } |
| 874 | 891 | ||
| 875 | FD_SET(fd, files->open_fds); | 892 | FD_SET(fd, fdt->open_fds); |
| 876 | FD_CLR(fd, files->close_on_exec); | 893 | FD_CLR(fd, fdt->close_on_exec); |
| 877 | files->next_fd = fd + 1; | 894 | fdt->next_fd = fd + 1; |
| 878 | #if 1 | 895 | #if 1 |
| 879 | /* Sanity check */ | 896 | /* Sanity check */ |
| 880 | if (files->fd[fd] != NULL) { | 897 | if (fdt->fd[fd] != NULL) { |
| 881 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | 898 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); |
| 882 | files->fd[fd] = NULL; | 899 | fdt->fd[fd] = NULL; |
| 883 | } | 900 | } |
| 884 | #endif | 901 | #endif |
| 885 | error = fd; | 902 | error = fd; |
| @@ -893,9 +910,10 @@ EXPORT_SYMBOL(get_unused_fd); | |||
| 893 | 910 | ||
| 894 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) | 911 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) |
| 895 | { | 912 | { |
| 896 | __FD_CLR(fd, files->open_fds); | 913 | struct fdtable *fdt = files_fdtable(files); |
| 897 | if (fd < files->next_fd) | 914 | __FD_CLR(fd, fdt->open_fds); |
| 898 | files->next_fd = fd; | 915 | if (fd < fdt->next_fd) |
| 916 | fdt->next_fd = fd; | ||
| 899 | } | 917 | } |
| 900 | 918 | ||
| 901 | void fastcall put_unused_fd(unsigned int fd) | 919 | void fastcall put_unused_fd(unsigned int fd) |
| @@ -924,25 +942,21 @@ EXPORT_SYMBOL(put_unused_fd); | |||
| 924 | void fastcall fd_install(unsigned int fd, struct file * file) | 942 | void fastcall fd_install(unsigned int fd, struct file * file) |
| 925 | { | 943 | { |
| 926 | struct files_struct *files = current->files; | 944 | struct files_struct *files = current->files; |
| 945 | struct fdtable *fdt; | ||
| 927 | spin_lock(&files->file_lock); | 946 | spin_lock(&files->file_lock); |
| 928 | if (unlikely(files->fd[fd] != NULL)) | 947 | fdt = files_fdtable(files); |
| 929 | BUG(); | 948 | BUG_ON(fdt->fd[fd] != NULL); |
| 930 | files->fd[fd] = file; | 949 | rcu_assign_pointer(fdt->fd[fd], file); |
| 931 | spin_unlock(&files->file_lock); | 950 | spin_unlock(&files->file_lock); |
| 932 | } | 951 | } |
| 933 | 952 | ||
| 934 | EXPORT_SYMBOL(fd_install); | 953 | EXPORT_SYMBOL(fd_install); |
| 935 | 954 | ||
| 936 | asmlinkage long sys_open(const char __user * filename, int flags, int mode) | 955 | long do_sys_open(const char __user *filename, int flags, int mode) |
| 937 | { | 956 | { |
| 938 | char * tmp; | 957 | char *tmp = getname(filename); |
| 939 | int fd; | 958 | int fd = PTR_ERR(tmp); |
| 940 | |||
| 941 | if (force_o_largefile()) | ||
| 942 | flags |= O_LARGEFILE; | ||
| 943 | 959 | ||
| 944 | tmp = getname(filename); | ||
| 945 | fd = PTR_ERR(tmp); | ||
| 946 | if (!IS_ERR(tmp)) { | 960 | if (!IS_ERR(tmp)) { |
| 947 | fd = get_unused_fd(); | 961 | fd = get_unused_fd(); |
| 948 | if (fd >= 0) { | 962 | if (fd >= 0) { |
| @@ -951,6 +965,7 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode) | |||
| 951 | put_unused_fd(fd); | 965 | put_unused_fd(fd); |
| 952 | fd = PTR_ERR(f); | 966 | fd = PTR_ERR(f); |
| 953 | } else { | 967 | } else { |
| 968 | fsnotify_open(f->f_dentry); | ||
| 954 | fd_install(fd, f); | 969 | fd_install(fd, f); |
| 955 | } | 970 | } |
| 956 | } | 971 | } |
| @@ -958,6 +973,14 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode) | |||
| 958 | } | 973 | } |
| 959 | return fd; | 974 | return fd; |
| 960 | } | 975 | } |
| 976 | |||
| 977 | asmlinkage long sys_open(const char __user *filename, int flags, int mode) | ||
| 978 | { | ||
| 979 | if (force_o_largefile()) | ||
| 980 | flags |= O_LARGEFILE; | ||
| 981 | |||
| 982 | return do_sys_open(filename, flags, mode); | ||
| 983 | } | ||
| 961 | EXPORT_SYMBOL_GPL(sys_open); | 984 | EXPORT_SYMBOL_GPL(sys_open); |
| 962 | 985 | ||
| 963 | #ifndef __alpha__ | 986 | #ifndef __alpha__ |
| @@ -1006,15 +1029,17 @@ asmlinkage long sys_close(unsigned int fd) | |||
| 1006 | { | 1029 | { |
| 1007 | struct file * filp; | 1030 | struct file * filp; |
| 1008 | struct files_struct *files = current->files; | 1031 | struct files_struct *files = current->files; |
| 1032 | struct fdtable *fdt; | ||
| 1009 | 1033 | ||
| 1010 | spin_lock(&files->file_lock); | 1034 | spin_lock(&files->file_lock); |
| 1011 | if (fd >= files->max_fds) | 1035 | fdt = files_fdtable(files); |
| 1036 | if (fd >= fdt->max_fds) | ||
| 1012 | goto out_unlock; | 1037 | goto out_unlock; |
| 1013 | filp = files->fd[fd]; | 1038 | filp = fdt->fd[fd]; |
| 1014 | if (!filp) | 1039 | if (!filp) |
| 1015 | goto out_unlock; | 1040 | goto out_unlock; |
| 1016 | files->fd[fd] = NULL; | 1041 | rcu_assign_pointer(fdt->fd[fd], NULL); |
| 1017 | FD_CLR(fd, files->close_on_exec); | 1042 | FD_CLR(fd, fdt->close_on_exec); |
| 1018 | __put_unused_fd(files, fd); | 1043 | __put_unused_fd(files, fd); |
| 1019 | spin_unlock(&files->file_lock); | 1044 | spin_unlock(&files->file_lock); |
| 1020 | return filp_close(filp, files); | 1045 | return filp_close(filp, files); |
