diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2013-06-07 01:20:27 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-06-29 04:57:10 -0400 |
| commit | 60545d0d4610b02e55f65d141c95b18ccf855b6e (patch) | |
| tree | 252111eed41e5f54a7bd13b054420f750cb5e069 | |
| parent | f9652e10c12b43d9bb957269745cf2fa5682fa92 (diff) | |
[O_TMPFILE] it's still short a few helpers, but infrastructure should be OK now...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -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); | ||
