diff options
Diffstat (limited to 'fs/xfs/xfs_iops.c')
-rw-r--r-- | fs/xfs/xfs_iops.c | 73 |
1 files changed, 60 insertions, 13 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 9ddfb8190ca1..36d630319a27 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "xfs_da_btree.h" | 39 | #include "xfs_da_btree.h" |
40 | #include "xfs_dir2_priv.h" | 40 | #include "xfs_dir2_priv.h" |
41 | #include "xfs_dinode.h" | 41 | #include "xfs_dinode.h" |
42 | #include "xfs_trans_space.h" | ||
42 | 43 | ||
43 | #include <linux/capability.h> | 44 | #include <linux/capability.h> |
44 | #include <linux/xattr.h> | 45 | #include <linux/xattr.h> |
@@ -48,6 +49,18 @@ | |||
48 | #include <linux/fiemap.h> | 49 | #include <linux/fiemap.h> |
49 | #include <linux/slab.h> | 50 | #include <linux/slab.h> |
50 | 51 | ||
52 | /* | ||
53 | * Directories have different lock order w.r.t. mmap_sem compared to regular | ||
54 | * files. This is due to readdir potentially triggering page faults on a user | ||
55 | * buffer inside filldir(), and this happens with the ilock on the directory | ||
56 | * held. For regular files, the lock order is the other way around - the | ||
57 | * mmap_sem is taken during the page fault, and then we lock the ilock to do | ||
58 | * block mapping. Hence we need a different class for the directory ilock so | ||
59 | * that lockdep can tell them apart. | ||
60 | */ | ||
61 | static struct lock_class_key xfs_nondir_ilock_class; | ||
62 | static struct lock_class_key xfs_dir_ilock_class; | ||
63 | |||
51 | static int | 64 | static int |
52 | xfs_initxattrs( | 65 | xfs_initxattrs( |
53 | struct inode *inode, | 66 | struct inode *inode, |
@@ -59,8 +72,8 @@ xfs_initxattrs( | |||
59 | int error = 0; | 72 | int error = 0; |
60 | 73 | ||
61 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { | 74 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { |
62 | error = xfs_attr_set(ip, xattr->name, xattr->value, | 75 | error = -xfs_attr_set(ip, xattr->name, xattr->value, |
63 | xattr->value_len, ATTR_SECURE); | 76 | xattr->value_len, ATTR_SECURE); |
64 | if (error < 0) | 77 | if (error < 0) |
65 | break; | 78 | break; |
66 | } | 79 | } |
@@ -80,8 +93,8 @@ xfs_init_security( | |||
80 | struct inode *dir, | 93 | struct inode *dir, |
81 | const struct qstr *qstr) | 94 | const struct qstr *qstr) |
82 | { | 95 | { |
83 | return security_inode_init_security(inode, dir, qstr, | 96 | return -security_inode_init_security(inode, dir, qstr, |
84 | &xfs_initxattrs, NULL); | 97 | &xfs_initxattrs, NULL); |
85 | } | 98 | } |
86 | 99 | ||
87 | static void | 100 | static void |
@@ -111,15 +124,15 @@ xfs_cleanup_inode( | |||
111 | xfs_dentry_to_name(&teardown, dentry, 0); | 124 | xfs_dentry_to_name(&teardown, dentry, 0); |
112 | 125 | ||
113 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); | 126 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); |
114 | iput(inode); | ||
115 | } | 127 | } |
116 | 128 | ||
117 | STATIC int | 129 | STATIC int |
118 | xfs_vn_mknod( | 130 | xfs_generic_create( |
119 | struct inode *dir, | 131 | struct inode *dir, |
120 | struct dentry *dentry, | 132 | struct dentry *dentry, |
121 | umode_t mode, | 133 | umode_t mode, |
122 | dev_t rdev) | 134 | dev_t rdev, |
135 | bool tmpfile) /* unnamed file */ | ||
123 | { | 136 | { |
124 | struct inode *inode; | 137 | struct inode *inode; |
125 | struct xfs_inode *ip = NULL; | 138 | struct xfs_inode *ip = NULL; |
@@ -143,8 +156,12 @@ xfs_vn_mknod( | |||
143 | if (error) | 156 | if (error) |
144 | return error; | 157 | return error; |
145 | 158 | ||
146 | xfs_dentry_to_name(&name, dentry, mode); | 159 | if (!tmpfile) { |
147 | error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); | 160 | xfs_dentry_to_name(&name, dentry, mode); |
161 | error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); | ||
162 | } else { | ||
163 | error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip); | ||
164 | } | ||
148 | if (unlikely(error)) | 165 | if (unlikely(error)) |
149 | goto out_free_acl; | 166 | goto out_free_acl; |
150 | 167 | ||
@@ -156,18 +173,22 @@ xfs_vn_mknod( | |||
156 | 173 | ||
157 | #ifdef CONFIG_XFS_POSIX_ACL | 174 | #ifdef CONFIG_XFS_POSIX_ACL |
158 | if (default_acl) { | 175 | if (default_acl) { |
159 | error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); | 176 | error = -xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); |
160 | if (error) | 177 | if (error) |
161 | goto out_cleanup_inode; | 178 | goto out_cleanup_inode; |
162 | } | 179 | } |
163 | if (acl) { | 180 | if (acl) { |
164 | error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); | 181 | error = -xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); |
165 | if (error) | 182 | if (error) |
166 | goto out_cleanup_inode; | 183 | goto out_cleanup_inode; |
167 | } | 184 | } |
168 | #endif | 185 | #endif |
169 | 186 | ||
170 | d_instantiate(dentry, inode); | 187 | if (tmpfile) |
188 | d_tmpfile(dentry, inode); | ||
189 | else | ||
190 | d_instantiate(dentry, inode); | ||
191 | |||
171 | out_free_acl: | 192 | out_free_acl: |
172 | if (default_acl) | 193 | if (default_acl) |
173 | posix_acl_release(default_acl); | 194 | posix_acl_release(default_acl); |
@@ -176,11 +197,23 @@ xfs_vn_mknod( | |||
176 | return -error; | 197 | return -error; |
177 | 198 | ||
178 | out_cleanup_inode: | 199 | out_cleanup_inode: |
179 | xfs_cleanup_inode(dir, inode, dentry); | 200 | if (!tmpfile) |
201 | xfs_cleanup_inode(dir, inode, dentry); | ||
202 | iput(inode); | ||
180 | goto out_free_acl; | 203 | goto out_free_acl; |
181 | } | 204 | } |
182 | 205 | ||
183 | STATIC int | 206 | STATIC int |
207 | xfs_vn_mknod( | ||
208 | struct inode *dir, | ||
209 | struct dentry *dentry, | ||
210 | umode_t mode, | ||
211 | dev_t rdev) | ||
212 | { | ||
213 | return xfs_generic_create(dir, dentry, mode, rdev, false); | ||
214 | } | ||
215 | |||
216 | STATIC int | ||
184 | xfs_vn_create( | 217 | xfs_vn_create( |
185 | struct inode *dir, | 218 | struct inode *dir, |
186 | struct dentry *dentry, | 219 | struct dentry *dentry, |
@@ -340,6 +373,7 @@ xfs_vn_symlink( | |||
340 | 373 | ||
341 | out_cleanup_inode: | 374 | out_cleanup_inode: |
342 | xfs_cleanup_inode(dir, inode, dentry); | 375 | xfs_cleanup_inode(dir, inode, dentry); |
376 | iput(inode); | ||
343 | out: | 377 | out: |
344 | return -error; | 378 | return -error; |
345 | } | 379 | } |
@@ -1034,6 +1068,15 @@ xfs_vn_fiemap( | |||
1034 | return 0; | 1068 | return 0; |
1035 | } | 1069 | } |
1036 | 1070 | ||
1071 | STATIC int | ||
1072 | xfs_vn_tmpfile( | ||
1073 | struct inode *dir, | ||
1074 | struct dentry *dentry, | ||
1075 | umode_t mode) | ||
1076 | { | ||
1077 | return xfs_generic_create(dir, dentry, mode, 0, true); | ||
1078 | } | ||
1079 | |||
1037 | static const struct inode_operations xfs_inode_operations = { | 1080 | static const struct inode_operations xfs_inode_operations = { |
1038 | .get_acl = xfs_get_acl, | 1081 | .get_acl = xfs_get_acl, |
1039 | .set_acl = xfs_set_acl, | 1082 | .set_acl = xfs_set_acl, |
@@ -1072,6 +1115,7 @@ static const struct inode_operations xfs_dir_inode_operations = { | |||
1072 | .removexattr = generic_removexattr, | 1115 | .removexattr = generic_removexattr, |
1073 | .listxattr = xfs_vn_listxattr, | 1116 | .listxattr = xfs_vn_listxattr, |
1074 | .update_time = xfs_vn_update_time, | 1117 | .update_time = xfs_vn_update_time, |
1118 | .tmpfile = xfs_vn_tmpfile, | ||
1075 | }; | 1119 | }; |
1076 | 1120 | ||
1077 | static const struct inode_operations xfs_dir_ci_inode_operations = { | 1121 | static const struct inode_operations xfs_dir_ci_inode_operations = { |
@@ -1099,6 +1143,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { | |||
1099 | .removexattr = generic_removexattr, | 1143 | .removexattr = generic_removexattr, |
1100 | .listxattr = xfs_vn_listxattr, | 1144 | .listxattr = xfs_vn_listxattr, |
1101 | .update_time = xfs_vn_update_time, | 1145 | .update_time = xfs_vn_update_time, |
1146 | .tmpfile = xfs_vn_tmpfile, | ||
1102 | }; | 1147 | }; |
1103 | 1148 | ||
1104 | static const struct inode_operations xfs_symlink_inode_operations = { | 1149 | static const struct inode_operations xfs_symlink_inode_operations = { |
@@ -1191,6 +1236,7 @@ xfs_setup_inode( | |||
1191 | xfs_diflags_to_iflags(inode, ip); | 1236 | xfs_diflags_to_iflags(inode, ip); |
1192 | 1237 | ||
1193 | ip->d_ops = ip->i_mount->m_nondir_inode_ops; | 1238 | ip->d_ops = ip->i_mount->m_nondir_inode_ops; |
1239 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); | ||
1194 | switch (inode->i_mode & S_IFMT) { | 1240 | switch (inode->i_mode & S_IFMT) { |
1195 | case S_IFREG: | 1241 | case S_IFREG: |
1196 | inode->i_op = &xfs_inode_operations; | 1242 | inode->i_op = &xfs_inode_operations; |
@@ -1198,6 +1244,7 @@ xfs_setup_inode( | |||
1198 | inode->i_mapping->a_ops = &xfs_address_space_operations; | 1244 | inode->i_mapping->a_ops = &xfs_address_space_operations; |
1199 | break; | 1245 | break; |
1200 | case S_IFDIR: | 1246 | case S_IFDIR: |
1247 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); | ||
1201 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) | 1248 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) |
1202 | inode->i_op = &xfs_dir_ci_inode_operations; | 1249 | inode->i_op = &xfs_dir_ci_inode_operations; |
1203 | else | 1250 | else |