diff options
author | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-11-06 09:36:37 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-11-06 09:36:37 -0500 |
commit | 2fc2991175bf77395e6b15fe6b2304d3bf72da40 (patch) | |
tree | b0ff38c09240e7c00e1577d447ebe89143d752dc /fs/open.c | |
parent | 8b491d750885ebe8e7d385ce4186c85957d67123 (diff) | |
parent | 7015faa7df829876a0f931cd18aa6d7c24a1b581 (diff) |
Merge branch 'master' of /home/tglx/work/mtd/git/linux-2.6.git/
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 215 |
1 files changed, 145 insertions, 70 deletions
@@ -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,16 @@ 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 | int (*open)(struct inode *, struct file *)) |
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 | { | ||
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 | { | 744 | { |
776 | struct file * f; | ||
777 | struct inode *inode; | 745 | struct inode *inode; |
778 | int error; | 746 | int error; |
779 | 747 | ||
780 | error = -ENFILE; | ||
781 | f = get_empty_filp(); | ||
782 | if (!f) | ||
783 | goto cleanup_dentry; | ||
784 | f->f_flags = flags; | 748 | f->f_flags = flags; |
785 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; | 749 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | |
750 | FMODE_PREAD | FMODE_PWRITE; | ||
786 | inode = dentry->d_inode; | 751 | inode = dentry->d_inode; |
787 | if (f->f_mode & FMODE_WRITE) { | 752 | if (f->f_mode & FMODE_WRITE) { |
788 | error = get_write_access(inode); | 753 | error = get_write_access(inode); |
@@ -797,11 +762,14 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
797 | f->f_op = fops_get(inode->i_fop); | 762 | f->f_op = fops_get(inode->i_fop); |
798 | file_move(f, &inode->i_sb->s_files); | 763 | file_move(f, &inode->i_sb->s_files); |
799 | 764 | ||
800 | if (f->f_op && f->f_op->open) { | 765 | if (!open && f->f_op) |
801 | error = f->f_op->open(inode,f); | 766 | open = f->f_op->open; |
767 | if (open) { | ||
768 | error = open(inode, f); | ||
802 | if (error) | 769 | if (error) |
803 | goto cleanup_all; | 770 | goto cleanup_all; |
804 | } | 771 | } |
772 | |||
805 | f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | 773 | f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); |
806 | 774 | ||
807 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); | 775 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); |
@@ -827,12 +795,110 @@ cleanup_all: | |||
827 | f->f_vfsmnt = NULL; | 795 | f->f_vfsmnt = NULL; |
828 | cleanup_file: | 796 | cleanup_file: |
829 | put_filp(f); | 797 | put_filp(f); |
830 | cleanup_dentry: | ||
831 | dput(dentry); | 798 | dput(dentry); |
832 | mntput(mnt); | 799 | mntput(mnt); |
833 | return ERR_PTR(error); | 800 | return ERR_PTR(error); |
834 | } | 801 | } |
835 | 802 | ||
803 | /* | ||
804 | * Note that while the flag value (low two bits) for sys_open means: | ||
805 | * 00 - read-only | ||
806 | * 01 - write-only | ||
807 | * 10 - read-write | ||
808 | * 11 - special | ||
809 | * it is changed into | ||
810 | * 00 - no permissions needed | ||
811 | * 01 - read-permission | ||
812 | * 10 - write-permission | ||
813 | * 11 - read-write | ||
814 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
815 | * used by symlinks. | ||
816 | */ | ||
817 | struct file *filp_open(const char * filename, int flags, int mode) | ||
818 | { | ||
819 | int namei_flags, error; | ||
820 | struct nameidata nd; | ||
821 | |||
822 | namei_flags = flags; | ||
823 | if ((namei_flags+1) & O_ACCMODE) | ||
824 | namei_flags++; | ||
825 | |||
826 | error = open_namei(filename, namei_flags, mode, &nd); | ||
827 | if (!error) | ||
828 | return nameidata_to_filp(&nd, flags); | ||
829 | |||
830 | return ERR_PTR(error); | ||
831 | } | ||
832 | EXPORT_SYMBOL(filp_open); | ||
833 | |||
834 | /** | ||
835 | * lookup_instantiate_filp - instantiates the open intent filp | ||
836 | * @nd: pointer to nameidata | ||
837 | * @dentry: pointer to dentry | ||
838 | * @open: open callback | ||
839 | * | ||
840 | * Helper for filesystems that want to use lookup open intents and pass back | ||
841 | * a fully instantiated struct file to the caller. | ||
842 | * This function is meant to be called from within a filesystem's | ||
843 | * lookup method. | ||
844 | * Note that in case of error, nd->intent.open.file is destroyed, but the | ||
845 | * path information remains valid. | ||
846 | * If the open callback is set to NULL, then the standard f_op->open() | ||
847 | * filesystem callback is substituted. | ||
848 | */ | ||
849 | struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, | ||
850 | int (*open)(struct inode *, struct file *)) | ||
851 | { | ||
852 | if (IS_ERR(nd->intent.open.file)) | ||
853 | goto out; | ||
854 | if (IS_ERR(dentry)) | ||
855 | goto out_err; | ||
856 | nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->mnt), | ||
857 | nd->intent.open.flags - 1, | ||
858 | nd->intent.open.file, | ||
859 | open); | ||
860 | out: | ||
861 | return nd->intent.open.file; | ||
862 | out_err: | ||
863 | release_open_intent(nd); | ||
864 | nd->intent.open.file = (struct file *)dentry; | ||
865 | goto out; | ||
866 | } | ||
867 | EXPORT_SYMBOL_GPL(lookup_instantiate_filp); | ||
868 | |||
869 | /** | ||
870 | * nameidata_to_filp - convert a nameidata to an open filp. | ||
871 | * @nd: pointer to nameidata | ||
872 | * @flags: open flags | ||
873 | * | ||
874 | * Note that this function destroys the original nameidata | ||
875 | */ | ||
876 | struct file *nameidata_to_filp(struct nameidata *nd, int flags) | ||
877 | { | ||
878 | struct file *filp; | ||
879 | |||
880 | /* Pick up the filp from the open intent */ | ||
881 | filp = nd->intent.open.file; | ||
882 | /* Has the filesystem initialised the file for us? */ | ||
883 | if (filp->f_dentry == NULL) | ||
884 | filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL); | ||
885 | else | ||
886 | path_release(nd); | ||
887 | return filp; | ||
888 | } | ||
889 | |||
890 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | ||
891 | { | ||
892 | int error; | ||
893 | struct file *f; | ||
894 | |||
895 | error = -ENFILE; | ||
896 | f = get_empty_filp(); | ||
897 | if (f == NULL) | ||
898 | return ERR_PTR(error); | ||
899 | |||
900 | return __dentry_open(dentry, mnt, flags, f, NULL); | ||
901 | } | ||
836 | EXPORT_SYMBOL(dentry_open); | 902 | EXPORT_SYMBOL(dentry_open); |
837 | 903 | ||
838 | /* | 904 | /* |
@@ -842,14 +908,16 @@ int get_unused_fd(void) | |||
842 | { | 908 | { |
843 | struct files_struct * files = current->files; | 909 | struct files_struct * files = current->files; |
844 | int fd, error; | 910 | int fd, error; |
911 | struct fdtable *fdt; | ||
845 | 912 | ||
846 | error = -EMFILE; | 913 | error = -EMFILE; |
847 | spin_lock(&files->file_lock); | 914 | spin_lock(&files->file_lock); |
848 | 915 | ||
849 | repeat: | 916 | repeat: |
850 | fd = find_next_zero_bit(files->open_fds->fds_bits, | 917 | fdt = files_fdtable(files); |
851 | files->max_fdset, | 918 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, |
852 | files->next_fd); | 919 | fdt->max_fdset, |
920 | fdt->next_fd); | ||
853 | 921 | ||
854 | /* | 922 | /* |
855 | * N.B. For clone tasks sharing a files structure, this test | 923 | * N.B. For clone tasks sharing a files structure, this test |
@@ -872,14 +940,14 @@ repeat: | |||
872 | goto repeat; | 940 | goto repeat; |
873 | } | 941 | } |
874 | 942 | ||
875 | FD_SET(fd, files->open_fds); | 943 | FD_SET(fd, fdt->open_fds); |
876 | FD_CLR(fd, files->close_on_exec); | 944 | FD_CLR(fd, fdt->close_on_exec); |
877 | files->next_fd = fd + 1; | 945 | fdt->next_fd = fd + 1; |
878 | #if 1 | 946 | #if 1 |
879 | /* Sanity check */ | 947 | /* Sanity check */ |
880 | if (files->fd[fd] != NULL) { | 948 | if (fdt->fd[fd] != NULL) { |
881 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | 949 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); |
882 | files->fd[fd] = NULL; | 950 | fdt->fd[fd] = NULL; |
883 | } | 951 | } |
884 | #endif | 952 | #endif |
885 | error = fd; | 953 | error = fd; |
@@ -893,9 +961,10 @@ EXPORT_SYMBOL(get_unused_fd); | |||
893 | 961 | ||
894 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) | 962 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) |
895 | { | 963 | { |
896 | __FD_CLR(fd, files->open_fds); | 964 | struct fdtable *fdt = files_fdtable(files); |
897 | if (fd < files->next_fd) | 965 | __FD_CLR(fd, fdt->open_fds); |
898 | files->next_fd = fd; | 966 | if (fd < fdt->next_fd) |
967 | fdt->next_fd = fd; | ||
899 | } | 968 | } |
900 | 969 | ||
901 | void fastcall put_unused_fd(unsigned int fd) | 970 | void fastcall put_unused_fd(unsigned int fd) |
@@ -924,25 +993,21 @@ EXPORT_SYMBOL(put_unused_fd); | |||
924 | void fastcall fd_install(unsigned int fd, struct file * file) | 993 | void fastcall fd_install(unsigned int fd, struct file * file) |
925 | { | 994 | { |
926 | struct files_struct *files = current->files; | 995 | struct files_struct *files = current->files; |
996 | struct fdtable *fdt; | ||
927 | spin_lock(&files->file_lock); | 997 | spin_lock(&files->file_lock); |
928 | if (unlikely(files->fd[fd] != NULL)) | 998 | fdt = files_fdtable(files); |
929 | BUG(); | 999 | BUG_ON(fdt->fd[fd] != NULL); |
930 | files->fd[fd] = file; | 1000 | rcu_assign_pointer(fdt->fd[fd], file); |
931 | spin_unlock(&files->file_lock); | 1001 | spin_unlock(&files->file_lock); |
932 | } | 1002 | } |
933 | 1003 | ||
934 | EXPORT_SYMBOL(fd_install); | 1004 | EXPORT_SYMBOL(fd_install); |
935 | 1005 | ||
936 | asmlinkage long sys_open(const char __user * filename, int flags, int mode) | 1006 | long do_sys_open(const char __user *filename, int flags, int mode) |
937 | { | 1007 | { |
938 | char * tmp; | 1008 | char *tmp = getname(filename); |
939 | int fd; | 1009 | int fd = PTR_ERR(tmp); |
940 | |||
941 | if (force_o_largefile()) | ||
942 | flags |= O_LARGEFILE; | ||
943 | 1010 | ||
944 | tmp = getname(filename); | ||
945 | fd = PTR_ERR(tmp); | ||
946 | if (!IS_ERR(tmp)) { | 1011 | if (!IS_ERR(tmp)) { |
947 | fd = get_unused_fd(); | 1012 | fd = get_unused_fd(); |
948 | if (fd >= 0) { | 1013 | if (fd >= 0) { |
@@ -959,6 +1024,14 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode) | |||
959 | } | 1024 | } |
960 | return fd; | 1025 | return fd; |
961 | } | 1026 | } |
1027 | |||
1028 | asmlinkage long sys_open(const char __user *filename, int flags, int mode) | ||
1029 | { | ||
1030 | if (force_o_largefile()) | ||
1031 | flags |= O_LARGEFILE; | ||
1032 | |||
1033 | return do_sys_open(filename, flags, mode); | ||
1034 | } | ||
962 | EXPORT_SYMBOL_GPL(sys_open); | 1035 | EXPORT_SYMBOL_GPL(sys_open); |
963 | 1036 | ||
964 | #ifndef __alpha__ | 1037 | #ifndef __alpha__ |
@@ -1007,15 +1080,17 @@ asmlinkage long sys_close(unsigned int fd) | |||
1007 | { | 1080 | { |
1008 | struct file * filp; | 1081 | struct file * filp; |
1009 | struct files_struct *files = current->files; | 1082 | struct files_struct *files = current->files; |
1083 | struct fdtable *fdt; | ||
1010 | 1084 | ||
1011 | spin_lock(&files->file_lock); | 1085 | spin_lock(&files->file_lock); |
1012 | if (fd >= files->max_fds) | 1086 | fdt = files_fdtable(files); |
1087 | if (fd >= fdt->max_fds) | ||
1013 | goto out_unlock; | 1088 | goto out_unlock; |
1014 | filp = files->fd[fd]; | 1089 | filp = fdt->fd[fd]; |
1015 | if (!filp) | 1090 | if (!filp) |
1016 | goto out_unlock; | 1091 | goto out_unlock; |
1017 | files->fd[fd] = NULL; | 1092 | rcu_assign_pointer(fdt->fd[fd], NULL); |
1018 | FD_CLR(fd, files->close_on_exec); | 1093 | FD_CLR(fd, fdt->close_on_exec); |
1019 | __put_unused_fd(files, fd); | 1094 | __put_unused_fd(files, fd); |
1020 | spin_unlock(&files->file_lock); | 1095 | spin_unlock(&files->file_lock); |
1021 | return filp_close(filp, files); | 1096 | return filp_close(filp, files); |