diff options
-rw-r--r-- | arch/alpha/include/uapi/asm/fcntl.h | 1 | ||||
-rw-r--r-- | arch/parisc/include/uapi/asm/fcntl.h | 1 | ||||
-rw-r--r-- | arch/sparc/include/uapi/asm/fcntl.h | 1 | ||||
-rw-r--r-- | fs/dcache.c | 16 | ||||
-rw-r--r-- | fs/ext2/namei.c | 24 | ||||
-rw-r--r-- | fs/minix/namei.c | 13 | ||||
-rw-r--r-- | fs/namei.c | 60 | ||||
-rw-r--r-- | fs/open.c | 14 | ||||
-rw-r--r-- | include/linux/dcache.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/uapi/asm-generic/fcntl.h | 4 | ||||
-rw-r--r-- | mm/shmem.c | 32 |
12 files changed, 164 insertions, 5 deletions
diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h index 6d9e805f18a7..dfdadb0b4bef 100644 --- a/arch/alpha/include/uapi/asm/fcntl.h +++ b/arch/alpha/include/uapi/asm/fcntl.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #define O_SYNC (__O_SYNC|O_DSYNC) | 32 | #define O_SYNC (__O_SYNC|O_DSYNC) |
33 | 33 | ||
34 | #define O_PATH 040000000 | 34 | #define O_PATH 040000000 |
35 | #define O_TMPFILE 0100000000 | ||
35 | 36 | ||
36 | #define F_GETLK 7 | 37 | #define F_GETLK 7 |
37 | #define F_SETLK 8 | 38 | #define F_SETLK 8 |
diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h index 0304b92ccfea..cc61c475f277 100644 --- a/arch/parisc/include/uapi/asm/fcntl.h +++ b/arch/parisc/include/uapi/asm/fcntl.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */ | 20 | #define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */ |
21 | 21 | ||
22 | #define O_PATH 020000000 | 22 | #define O_PATH 020000000 |
23 | #define O_TMPFILE 040000000 | ||
23 | 24 | ||
24 | #define F_GETLK64 8 | 25 | #define F_GETLK64 8 |
25 | #define F_SETLK64 9 | 26 | #define F_SETLK64 9 |
diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h index d0b83f66f356..d73e5e008b0d 100644 --- a/arch/sparc/include/uapi/asm/fcntl.h +++ b/arch/sparc/include/uapi/asm/fcntl.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #define O_SYNC (__O_SYNC|O_DSYNC) | 35 | #define O_SYNC (__O_SYNC|O_DSYNC) |
36 | 36 | ||
37 | #define O_PATH 0x1000000 | 37 | #define O_PATH 0x1000000 |
38 | #define O_TMPFILE 0x2000000 | ||
38 | 39 | ||
39 | #define F_GETOWN 5 /* for sockets. */ | 40 | #define F_GETOWN 5 /* for sockets. */ |
40 | #define F_SETOWN 6 /* for sockets. */ | 41 | #define F_SETOWN 6 /* for sockets. */ |
diff --git a/fs/dcache.c b/fs/dcache.c index f09b9085f7d8..b7f049c31526 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2968,6 +2968,22 @@ rename_retry: | |||
2968 | goto again; | 2968 | goto again; |
2969 | } | 2969 | } |
2970 | 2970 | ||
2971 | void d_tmpfile(struct dentry *dentry, struct inode *inode) | ||
2972 | { | ||
2973 | inode_dec_link_count(inode); | ||
2974 | BUG_ON(dentry->d_name.name != dentry->d_iname || | ||
2975 | !hlist_unhashed(&dentry->d_alias) || | ||
2976 | !d_unlinked(dentry)); | ||
2977 | spin_lock(&dentry->d_parent->d_lock); | ||
2978 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
2979 | dentry->d_name.len = sprintf(dentry->d_iname, "#%llu", | ||
2980 | (unsigned long long)inode->i_ino); | ||
2981 | spin_unlock(&dentry->d_lock); | ||
2982 | spin_unlock(&dentry->d_parent->d_lock); | ||
2983 | d_instantiate(dentry, inode); | ||
2984 | } | ||
2985 | EXPORT_SYMBOL(d_tmpfile); | ||
2986 | |||
2971 | /** | 2987 | /** |
2972 | * find_inode_number - check for dentry with name | 2988 | * find_inode_number - check for dentry with name |
2973 | * @dir: directory to check | 2989 | * @dir: directory to check |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 73b0d9519836..256dd5f4c1c4 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -119,6 +119,29 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode | |||
119 | return ext2_add_nondir(dentry, inode); | 119 | return ext2_add_nondir(dentry, inode); |
120 | } | 120 | } |
121 | 121 | ||
122 | static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
123 | { | ||
124 | struct inode *inode = ext2_new_inode(dir, mode, NULL); | ||
125 | if (IS_ERR(inode)) | ||
126 | return PTR_ERR(inode); | ||
127 | |||
128 | inode->i_op = &ext2_file_inode_operations; | ||
129 | if (ext2_use_xip(inode->i_sb)) { | ||
130 | inode->i_mapping->a_ops = &ext2_aops_xip; | ||
131 | inode->i_fop = &ext2_xip_file_operations; | ||
132 | } else if (test_opt(inode->i_sb, NOBH)) { | ||
133 | inode->i_mapping->a_ops = &ext2_nobh_aops; | ||
134 | inode->i_fop = &ext2_file_operations; | ||
135 | } else { | ||
136 | inode->i_mapping->a_ops = &ext2_aops; | ||
137 | inode->i_fop = &ext2_file_operations; | ||
138 | } | ||
139 | mark_inode_dirty(inode); | ||
140 | d_tmpfile(dentry, inode); | ||
141 | unlock_new_inode(inode); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
122 | static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) | 145 | static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) |
123 | { | 146 | { |
124 | struct inode * inode; | 147 | struct inode * inode; |
@@ -398,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = { | |||
398 | #endif | 421 | #endif |
399 | .setattr = ext2_setattr, | 422 | .setattr = ext2_setattr, |
400 | .get_acl = ext2_get_acl, | 423 | .get_acl = ext2_get_acl, |
424 | .tmpfile = ext2_tmpfile, | ||
401 | }; | 425 | }; |
402 | 426 | ||
403 | const struct inode_operations ext2_special_inode_operations = { | 427 | const struct inode_operations ext2_special_inode_operations = { |
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 0db73d9dd668..cd950e2331b6 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c | |||
@@ -54,6 +54,18 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode, | |||
54 | return error; | 54 | return error; |
55 | } | 55 | } |
56 | 56 | ||
57 | static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
58 | { | ||
59 | int error; | ||
60 | struct inode *inode = minix_new_inode(dir, mode, &error); | ||
61 | if (inode) { | ||
62 | minix_set_inode(inode, 0); | ||
63 | mark_inode_dirty(inode); | ||
64 | d_tmpfile(dentry, inode); | ||
65 | } | ||
66 | return error; | ||
67 | } | ||
68 | |||
57 | static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode, | 69 | static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
58 | bool excl) | 70 | bool excl) |
59 | { | 71 | { |
@@ -254,4 +266,5 @@ const struct inode_operations minix_dir_inode_operations = { | |||
254 | .mknod = minix_mknod, | 266 | .mknod = minix_mknod, |
255 | .rename = minix_rename, | 267 | .rename = minix_rename, |
256 | .getattr = minix_getattr, | 268 | .getattr = minix_getattr, |
269 | .tmpfile = minix_tmpfile, | ||
257 | }; | 270 | }; |
diff --git a/fs/namei.c b/fs/namei.c index 402eda351d07..778e253e3d48 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2902,6 +2902,61 @@ stale_open: | |||
2902 | goto retry_lookup; | 2902 | goto retry_lookup; |
2903 | } | 2903 | } |
2904 | 2904 | ||
2905 | static int do_tmpfile(int dfd, struct filename *pathname, | ||
2906 | struct nameidata *nd, int flags, | ||
2907 | const struct open_flags *op, | ||
2908 | struct file *file, int *opened) | ||
2909 | { | ||
2910 | static const struct qstr name = QSTR_INIT("/", 1); | ||
2911 | struct dentry *dentry, *child; | ||
2912 | struct inode *dir; | ||
2913 | int error = path_lookupat(dfd, pathname->name, | ||
2914 | flags | LOOKUP_DIRECTORY, nd); | ||
2915 | if (unlikely(error)) | ||
2916 | return error; | ||
2917 | error = mnt_want_write(nd->path.mnt); | ||
2918 | if (unlikely(error)) | ||
2919 | goto out; | ||
2920 | /* we want directory to be writable */ | ||
2921 | error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC); | ||
2922 | if (error) | ||
2923 | goto out2; | ||
2924 | dentry = nd->path.dentry; | ||
2925 | dir = dentry->d_inode; | ||
2926 | if (!dir->i_op->tmpfile) { | ||
2927 | error = -EOPNOTSUPP; | ||
2928 | goto out2; | ||
2929 | } | ||
2930 | child = d_alloc(dentry, &name); | ||
2931 | if (unlikely(!child)) { | ||
2932 | error = -ENOMEM; | ||
2933 | goto out2; | ||
2934 | } | ||
2935 | nd->flags &= ~LOOKUP_DIRECTORY; | ||
2936 | nd->flags |= op->intent; | ||
2937 | dput(nd->path.dentry); | ||
2938 | nd->path.dentry = child; | ||
2939 | error = dir->i_op->tmpfile(dir, nd->path.dentry, op->mode); | ||
2940 | if (error) | ||
2941 | goto out2; | ||
2942 | audit_inode(pathname, nd->path.dentry, 0); | ||
2943 | error = may_open(&nd->path, op->acc_mode, op->open_flag); | ||
2944 | if (error) | ||
2945 | goto out2; | ||
2946 | file->f_path.mnt = nd->path.mnt; | ||
2947 | error = finish_open(file, nd->path.dentry, NULL, opened); | ||
2948 | if (error) | ||
2949 | goto out2; | ||
2950 | error = open_check_o_direct(file); | ||
2951 | if (error) | ||
2952 | fput(file); | ||
2953 | out2: | ||
2954 | mnt_drop_write(nd->path.mnt); | ||
2955 | out: | ||
2956 | path_put(&nd->path); | ||
2957 | return error; | ||
2958 | } | ||
2959 | |||
2905 | static struct file *path_openat(int dfd, struct filename *pathname, | 2960 | static struct file *path_openat(int dfd, struct filename *pathname, |
2906 | struct nameidata *nd, const struct open_flags *op, int flags) | 2961 | struct nameidata *nd, const struct open_flags *op, int flags) |
2907 | { | 2962 | { |
@@ -2917,6 +2972,11 @@ static struct file *path_openat(int dfd, struct filename *pathname, | |||
2917 | 2972 | ||
2918 | file->f_flags = op->open_flag; | 2973 | file->f_flags = op->open_flag; |
2919 | 2974 | ||
2975 | if (unlikely(file->f_flags & O_TMPFILE)) { | ||
2976 | error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened); | ||
2977 | goto out; | ||
2978 | } | ||
2979 | |||
2920 | error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base); | 2980 | error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base); |
2921 | if (unlikely(error)) | 2981 | if (unlikely(error)) |
2922 | goto out; | 2982 | goto out; |
@@ -840,11 +840,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o | |||
840 | if (flags & __O_SYNC) | 840 | if (flags & __O_SYNC) |
841 | flags |= O_DSYNC; | 841 | flags |= O_DSYNC; |
842 | 842 | ||
843 | /* | 843 | if (flags & O_TMPFILE) { |
844 | * If we have O_PATH in the open flag. Then we | 844 | if (!(flags & O_CREAT)) |
845 | * cannot have anything other than the below set of flags | 845 | return -EINVAL; |
846 | */ | 846 | acc_mode = MAY_OPEN | ACC_MODE(flags); |
847 | if (flags & O_PATH) { | 847 | } else if (flags & O_PATH) { |
848 | /* | ||
849 | * If we have O_PATH in the open flag. Then we | ||
850 | * cannot have anything other than the below set of flags | ||
851 | */ | ||
848 | flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; | 852 | flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; |
849 | acc_mode = 0; | 853 | acc_mode = 0; |
850 | } else { | 854 | } else { |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 1a6bb81f0fe5..86da7595ba31 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -246,6 +246,8 @@ extern struct dentry * d_make_root(struct inode *); | |||
246 | /* <clickety>-<click> the ramfs-type tree */ | 246 | /* <clickety>-<click> the ramfs-type tree */ |
247 | extern void d_genocide(struct dentry *); | 247 | extern void d_genocide(struct dentry *); |
248 | 248 | ||
249 | extern void d_tmpfile(struct dentry *, struct inode *); | ||
250 | |||
249 | extern struct dentry *d_find_alias(struct inode *); | 251 | extern struct dentry *d_find_alias(struct inode *); |
250 | extern void d_prune_aliases(struct inode *); | 252 | extern void d_prune_aliases(struct inode *); |
251 | 253 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 7c30e3a62baf..dd6615f0fd13 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1580,6 +1580,7 @@ struct inode_operations { | |||
1580 | int (*atomic_open)(struct inode *, struct dentry *, | 1580 | int (*atomic_open)(struct inode *, struct dentry *, |
1581 | struct file *, unsigned open_flag, | 1581 | struct file *, unsigned open_flag, |
1582 | umode_t create_mode, int *opened); | 1582 | umode_t create_mode, int *opened); |
1583 | int (*tmpfile) (struct inode *, struct dentry *, umode_t); | ||
1583 | } ____cacheline_aligned; | 1584 | } ____cacheline_aligned; |
1584 | 1585 | ||
1585 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, | 1586 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, |
diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index a48937d4a5ea..06632beaa6d5 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h | |||
@@ -84,6 +84,10 @@ | |||
84 | #define O_PATH 010000000 | 84 | #define O_PATH 010000000 |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | #ifndef O_TMPFILE | ||
88 | #define O_TMPFILE 020000000 | ||
89 | #endif | ||
90 | |||
87 | #ifndef O_NDELAY | 91 | #ifndef O_NDELAY |
88 | #define O_NDELAY O_NONBLOCK | 92 | #define O_NDELAY O_NONBLOCK |
89 | #endif | 93 | #endif |
diff --git a/mm/shmem.c b/mm/shmem.c index 5e6a8422658b..f887358dabc5 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -1965,6 +1965,37 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) | |||
1965 | return error; | 1965 | return error; |
1966 | } | 1966 | } |
1967 | 1967 | ||
1968 | static int | ||
1969 | shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
1970 | { | ||
1971 | struct inode *inode; | ||
1972 | int error = -ENOSPC; | ||
1973 | |||
1974 | inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE); | ||
1975 | if (inode) { | ||
1976 | error = security_inode_init_security(inode, dir, | ||
1977 | NULL, | ||
1978 | shmem_initxattrs, NULL); | ||
1979 | if (error) { | ||
1980 | if (error != -EOPNOTSUPP) { | ||
1981 | iput(inode); | ||
1982 | return error; | ||
1983 | } | ||
1984 | } | ||
1985 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
1986 | error = generic_acl_init(inode, dir); | ||
1987 | if (error) { | ||
1988 | iput(inode); | ||
1989 | return error; | ||
1990 | } | ||
1991 | #else | ||
1992 | error = 0; | ||
1993 | #endif | ||
1994 | d_tmpfile(dentry, inode); | ||
1995 | } | ||
1996 | return error; | ||
1997 | } | ||
1998 | |||
1968 | static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 1999 | static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
1969 | { | 2000 | { |
1970 | int error; | 2001 | int error; |
@@ -2723,6 +2754,7 @@ static const struct inode_operations shmem_dir_inode_operations = { | |||
2723 | .rmdir = shmem_rmdir, | 2754 | .rmdir = shmem_rmdir, |
2724 | .mknod = shmem_mknod, | 2755 | .mknod = shmem_mknod, |
2725 | .rename = shmem_rename, | 2756 | .rename = shmem_rename, |
2757 | .tmpfile = shmem_tmpfile, | ||
2726 | #endif | 2758 | #endif |
2727 | #ifdef CONFIG_TMPFS_XATTR | 2759 | #ifdef CONFIG_TMPFS_XATTR |
2728 | .setxattr = shmem_setxattr, | 2760 | .setxattr = shmem_setxattr, |