diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 35 |
1 files changed, 29 insertions, 6 deletions
@@ -669,11 +669,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
669 | int (*open)(struct inode *, struct file *), | 669 | int (*open)(struct inode *, struct file *), |
670 | const struct cred *cred) | 670 | const struct cred *cred) |
671 | { | 671 | { |
672 | static const struct file_operations empty_fops = {}; | ||
672 | struct inode *inode; | 673 | struct inode *inode; |
673 | int error; | 674 | int error; |
674 | 675 | ||
675 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | | 676 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | |
676 | FMODE_PREAD | FMODE_PWRITE; | 677 | FMODE_PREAD | FMODE_PWRITE; |
678 | |||
679 | if (unlikely(f->f_flags & O_PATH)) | ||
680 | f->f_mode = FMODE_PATH; | ||
681 | |||
677 | inode = dentry->d_inode; | 682 | inode = dentry->d_inode; |
678 | if (f->f_mode & FMODE_WRITE) { | 683 | if (f->f_mode & FMODE_WRITE) { |
679 | error = __get_file_write_access(inode, mnt); | 684 | error = __get_file_write_access(inode, mnt); |
@@ -687,9 +692,15 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
687 | f->f_path.dentry = dentry; | 692 | f->f_path.dentry = dentry; |
688 | f->f_path.mnt = mnt; | 693 | f->f_path.mnt = mnt; |
689 | f->f_pos = 0; | 694 | f->f_pos = 0; |
690 | f->f_op = fops_get(inode->i_fop); | ||
691 | file_sb_list_add(f, inode->i_sb); | 695 | file_sb_list_add(f, inode->i_sb); |
692 | 696 | ||
697 | if (unlikely(f->f_mode & FMODE_PATH)) { | ||
698 | f->f_op = &empty_fops; | ||
699 | return f; | ||
700 | } | ||
701 | |||
702 | f->f_op = fops_get(inode->i_fop); | ||
703 | |||
693 | error = security_dentry_open(f, cred); | 704 | error = security_dentry_open(f, cred); |
694 | if (error) | 705 | if (error) |
695 | goto cleanup_all; | 706 | goto cleanup_all; |
@@ -911,9 +922,18 @@ static inline int build_open_flags(int flags, int mode, struct open_flags *op) | |||
911 | if (flags & __O_SYNC) | 922 | if (flags & __O_SYNC) |
912 | flags |= O_DSYNC; | 923 | flags |= O_DSYNC; |
913 | 924 | ||
914 | op->open_flag = flags; | 925 | /* |
926 | * If we have O_PATH in the open flag. Then we | ||
927 | * cannot have anything other than the below set of flags | ||
928 | */ | ||
929 | if (flags & O_PATH) { | ||
930 | flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; | ||
931 | acc_mode = 0; | ||
932 | } else { | ||
933 | acc_mode = MAY_OPEN | ACC_MODE(flags); | ||
934 | } | ||
915 | 935 | ||
916 | acc_mode = MAY_OPEN | ACC_MODE(flags); | 936 | op->open_flag = flags; |
917 | 937 | ||
918 | /* O_TRUNC implies we need access checks for write permissions */ | 938 | /* O_TRUNC implies we need access checks for write permissions */ |
919 | if (flags & O_TRUNC) | 939 | if (flags & O_TRUNC) |
@@ -926,7 +946,8 @@ static inline int build_open_flags(int flags, int mode, struct open_flags *op) | |||
926 | 946 | ||
927 | op->acc_mode = acc_mode; | 947 | op->acc_mode = acc_mode; |
928 | 948 | ||
929 | op->intent = LOOKUP_OPEN; | 949 | op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN; |
950 | |||
930 | if (flags & O_CREAT) { | 951 | if (flags & O_CREAT) { |
931 | op->intent |= LOOKUP_CREATE; | 952 | op->intent |= LOOKUP_CREATE; |
932 | if (flags & O_EXCL) | 953 | if (flags & O_EXCL) |
@@ -1053,8 +1074,10 @@ int filp_close(struct file *filp, fl_owner_t id) | |||
1053 | if (filp->f_op && filp->f_op->flush) | 1074 | if (filp->f_op && filp->f_op->flush) |
1054 | retval = filp->f_op->flush(filp, id); | 1075 | retval = filp->f_op->flush(filp, id); |
1055 | 1076 | ||
1056 | dnotify_flush(filp, id); | 1077 | if (likely(!(filp->f_mode & FMODE_PATH))) { |
1057 | locks_remove_posix(filp, id); | 1078 | dnotify_flush(filp, id); |
1079 | locks_remove_posix(filp, id); | ||
1080 | } | ||
1058 | fput(filp); | 1081 | fput(filp); |
1059 | return retval; | 1082 | return retval; |
1060 | } | 1083 | } |