aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2016-05-19 20:32:10 -0400
committerDave Chinner <david@fromorbit.com>2016-05-19 20:32:10 -0400
commit5b9113547fedca92bb39b828f7f8cd11a153247b (patch)
treef6b489073b1584d8179bf553e6f90e91f9e79e83 /fs/xfs
parentd6bd9615abdf89b147eb200ea4f63156af8a279e (diff)
parent30ee052e12b97c190b27fe6f20e3ac3047df7b5c (diff)
Merge branch 'xfs-4.7-optimise-inline-symlinks' into for-next
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_dir2_sf.c9
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c62
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.h1
-rw-r--r--fs/xfs/xfs_inode.c1
-rw-r--r--fs/xfs/xfs_inode.h5
-rw-r--r--fs/xfs/xfs_inode_item.c4
-rw-r--r--fs/xfs/xfs_ioctl.c18
-rw-r--r--fs/xfs/xfs_iops.c88
-rw-r--r--fs/xfs/xfs_symlink.c21
9 files changed, 125 insertions, 84 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 974d62e677f4..e5bb9cc3b243 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -257,15 +257,12 @@ xfs_dir2_block_to_sf(
257 * 257 *
258 * Convert the inode to local format and copy the data in. 258 * Convert the inode to local format and copy the data in.
259 */ 259 */
260 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
261 dp->i_df.if_flags |= XFS_IFINLINE;
262 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
263 ASSERT(dp->i_df.if_bytes == 0); 260 ASSERT(dp->i_df.if_bytes == 0);
264 xfs_idata_realloc(dp, size, XFS_DATA_FORK); 261 xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size);
262 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
263 dp->i_d.di_size = size;
265 264
266 logflags |= XFS_ILOG_DDATA; 265 logflags |= XFS_ILOG_DDATA;
267 memcpy(dp->i_df.if_u1.if_data, dst, size);
268 dp->i_d.di_size = size;
269 xfs_dir2_sf_check(args); 266 xfs_dir2_sf_check(args);
270out: 267out:
271 xfs_trans_log_inode(args->trans, dp, logflags); 268 xfs_trans_log_inode(args->trans, dp, logflags);
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 11faf7df14c8..4fbe2263c1fc 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -231,6 +231,48 @@ xfs_iformat_fork(
231 return error; 231 return error;
232} 232}
233 233
234void
235xfs_init_local_fork(
236 struct xfs_inode *ip,
237 int whichfork,
238 const void *data,
239 int size)
240{
241 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
242 int mem_size = size, real_size = 0;
243 bool zero_terminate;
244
245 /*
246 * If we are using the local fork to store a symlink body we need to
247 * zero-terminate it so that we can pass it back to the VFS directly.
248 * Overallocate the in-memory fork by one for that and add a zero
249 * to terminate it below.
250 */
251 zero_terminate = S_ISLNK(VFS_I(ip)->i_mode);
252 if (zero_terminate)
253 mem_size++;
254
255 if (size == 0)
256 ifp->if_u1.if_data = NULL;
257 else if (mem_size <= sizeof(ifp->if_u2.if_inline_data))
258 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
259 else {
260 real_size = roundup(mem_size, 4);
261 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
262 }
263
264 if (size) {
265 memcpy(ifp->if_u1.if_data, data, size);
266 if (zero_terminate)
267 ifp->if_u1.if_data[size] = '\0';
268 }
269
270 ifp->if_bytes = size;
271 ifp->if_real_bytes = real_size;
272 ifp->if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
273 ifp->if_flags |= XFS_IFINLINE;
274}
275
234/* 276/*
235 * The file is in-lined in the on-disk inode. 277 * The file is in-lined in the on-disk inode.
236 * If it fits into if_inline_data, then copy 278 * If it fits into if_inline_data, then copy
@@ -248,8 +290,6 @@ xfs_iformat_local(
248 int whichfork, 290 int whichfork,
249 int size) 291 int size)
250{ 292{
251 xfs_ifork_t *ifp;
252 int real_size;
253 293
254 /* 294 /*
255 * If the size is unreasonable, then something 295 * If the size is unreasonable, then something
@@ -265,22 +305,8 @@ xfs_iformat_local(
265 ip->i_mount, dip); 305 ip->i_mount, dip);
266 return -EFSCORRUPTED; 306 return -EFSCORRUPTED;
267 } 307 }
268 ifp = XFS_IFORK_PTR(ip, whichfork); 308
269 real_size = 0; 309 xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size);
270 if (size == 0)
271 ifp->if_u1.if_data = NULL;
272 else if (size <= sizeof(ifp->if_u2.if_inline_data))
273 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
274 else {
275 real_size = roundup(size, 4);
276 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
277 }
278 ifp->if_bytes = size;
279 ifp->if_real_bytes = real_size;
280 if (size)
281 memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
282 ifp->if_flags &= ~XFS_IFEXTENTS;
283 ifp->if_flags |= XFS_IFINLINE;
284 return 0; 310 return 0;
285} 311}
286 312
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 7d3b1ed6dcbe..f95e072ae646 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -134,6 +134,7 @@ void xfs_iroot_realloc(struct xfs_inode *, int, int);
134int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); 134int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
135int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, 135int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
136 int); 136 int);
137void xfs_init_local_fork(struct xfs_inode *, int, const void *, int);
137 138
138struct xfs_bmbt_rec_host * 139struct xfs_bmbt_rec_host *
139 xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t); 140 xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index b82c729634f6..ca270d9bbb90 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2840,6 +2840,7 @@ xfs_rename_alloc_whiteout(
2840 * and flag it as linkable. 2840 * and flag it as linkable.
2841 */ 2841 */
2842 drop_nlink(VFS_I(tmpfile)); 2842 drop_nlink(VFS_I(tmpfile));
2843 xfs_setup_iops(tmpfile);
2843 xfs_finish_inode_setup(tmpfile); 2844 xfs_finish_inode_setup(tmpfile);
2844 VFS_I(tmpfile)->i_state |= I_LINKABLE; 2845 VFS_I(tmpfile)->i_state |= I_LINKABLE;
2845 2846
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 43e1d51b15eb..e52d7c7aeb5b 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -440,6 +440,9 @@ loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start,
440 440
441 441
442/* from xfs_iops.c */ 442/* from xfs_iops.c */
443extern void xfs_setup_inode(struct xfs_inode *ip);
444extern void xfs_setup_iops(struct xfs_inode *ip);
445
443/* 446/*
444 * When setting up a newly allocated inode, we need to call 447 * When setting up a newly allocated inode, we need to call
445 * xfs_finish_inode_setup() once the inode is fully instantiated at 448 * xfs_finish_inode_setup() once the inode is fully instantiated at
@@ -447,7 +450,6 @@ loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start,
447 * before we've completed instantiation. Otherwise we can do it 450 * before we've completed instantiation. Otherwise we can do it
448 * the moment the inode lookup is complete. 451 * the moment the inode lookup is complete.
449 */ 452 */
450extern void xfs_setup_inode(struct xfs_inode *ip);
451static inline void xfs_finish_inode_setup(struct xfs_inode *ip) 453static inline void xfs_finish_inode_setup(struct xfs_inode *ip)
452{ 454{
453 xfs_iflags_clear(ip, XFS_INEW); 455 xfs_iflags_clear(ip, XFS_INEW);
@@ -458,6 +460,7 @@ static inline void xfs_finish_inode_setup(struct xfs_inode *ip)
458static inline void xfs_setup_existing_inode(struct xfs_inode *ip) 460static inline void xfs_setup_existing_inode(struct xfs_inode *ip)
459{ 461{
460 xfs_setup_inode(ip); 462 xfs_setup_inode(ip);
463 xfs_setup_iops(ip);
461 xfs_finish_inode_setup(ip); 464 xfs_finish_inode_setup(ip);
462} 465}
463 466
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index c48b5b18d771..37e23c7a5684 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -210,7 +210,7 @@ xfs_inode_item_format_data_fork(
210 */ 210 */
211 data_bytes = roundup(ip->i_df.if_bytes, 4); 211 data_bytes = roundup(ip->i_df.if_bytes, 4);
212 ASSERT(ip->i_df.if_real_bytes == 0 || 212 ASSERT(ip->i_df.if_real_bytes == 0 ||
213 ip->i_df.if_real_bytes == data_bytes); 213 ip->i_df.if_real_bytes >= data_bytes);
214 ASSERT(ip->i_df.if_u1.if_data != NULL); 214 ASSERT(ip->i_df.if_u1.if_data != NULL);
215 ASSERT(ip->i_d.di_size > 0); 215 ASSERT(ip->i_d.di_size > 0);
216 xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, 216 xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL,
@@ -305,7 +305,7 @@ xfs_inode_item_format_attr_fork(
305 */ 305 */
306 data_bytes = roundup(ip->i_afp->if_bytes, 4); 306 data_bytes = roundup(ip->i_afp->if_bytes, 4);
307 ASSERT(ip->i_afp->if_real_bytes == 0 || 307 ASSERT(ip->i_afp->if_real_bytes == 0 ||
308 ip->i_afp->if_real_bytes == data_bytes); 308 ip->i_afp->if_real_bytes >= data_bytes);
309 ASSERT(ip->i_afp->if_u1.if_data != NULL); 309 ASSERT(ip->i_afp->if_u1.if_data != NULL);
310 xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, 310 xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL,
311 ip->i_afp->if_u1.if_data, 311 ip->i_afp->if_u1.if_data,
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 6f82187ee297..dbca7375deef 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -277,7 +277,6 @@ xfs_readlink_by_handle(
277{ 277{
278 struct dentry *dentry; 278 struct dentry *dentry;
279 __u32 olen; 279 __u32 olen;
280 void *link;
281 int error; 280 int error;
282 281
283 if (!capable(CAP_SYS_ADMIN)) 282 if (!capable(CAP_SYS_ADMIN))
@@ -288,7 +287,7 @@ xfs_readlink_by_handle(
288 return PTR_ERR(dentry); 287 return PTR_ERR(dentry);
289 288
290 /* Restrict this handle operation to symlinks only. */ 289 /* Restrict this handle operation to symlinks only. */
291 if (!d_is_symlink(dentry)) { 290 if (!d_inode(dentry)->i_op->readlink) {
292 error = -EINVAL; 291 error = -EINVAL;
293 goto out_dput; 292 goto out_dput;
294 } 293 }
@@ -298,21 +297,8 @@ xfs_readlink_by_handle(
298 goto out_dput; 297 goto out_dput;
299 } 298 }
300 299
301 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); 300 error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen);
302 if (!link) {
303 error = -ENOMEM;
304 goto out_dput;
305 }
306
307 error = xfs_readlink(XFS_I(d_inode(dentry)), link);
308 if (error)
309 goto out_kfree;
310 error = readlink_copy(hreq->ohandle, olen, link);
311 if (error)
312 goto out_kfree;
313 301
314 out_kfree:
315 kfree(link);
316 out_dput: 302 out_dput:
317 dput(dentry); 303 dput(dentry);
318 return error; 304 return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index fc7766164dc9..c5d4eba6972e 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -181,6 +181,8 @@ xfs_generic_create(
181 } 181 }
182#endif 182#endif
183 183
184 xfs_setup_iops(ip);
185
184 if (tmpfile) 186 if (tmpfile)
185 d_tmpfile(dentry, inode); 187 d_tmpfile(dentry, inode);
186 else 188 else
@@ -368,6 +370,8 @@ xfs_vn_symlink(
368 if (unlikely(error)) 370 if (unlikely(error))
369 goto out_cleanup_inode; 371 goto out_cleanup_inode;
370 372
373 xfs_setup_iops(cip);
374
371 d_instantiate(dentry, inode); 375 d_instantiate(dentry, inode);
372 xfs_finish_inode_setup(cip); 376 xfs_finish_inode_setup(cip);
373 return 0; 377 return 0;
@@ -442,6 +446,16 @@ xfs_vn_get_link(
442 return ERR_PTR(error); 446 return ERR_PTR(error);
443} 447}
444 448
449STATIC const char *
450xfs_vn_get_link_inline(
451 struct dentry *dentry,
452 struct inode *inode,
453 struct delayed_call *done)
454{
455 ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE);
456 return XFS_I(inode)->i_df.if_u1.if_data;
457}
458
445STATIC int 459STATIC int
446xfs_vn_getattr( 460xfs_vn_getattr(
447 struct vfsmount *mnt, 461 struct vfsmount *mnt,
@@ -1160,6 +1174,18 @@ static const struct inode_operations xfs_symlink_inode_operations = {
1160 .update_time = xfs_vn_update_time, 1174 .update_time = xfs_vn_update_time,
1161}; 1175};
1162 1176
1177static const struct inode_operations xfs_inline_symlink_inode_operations = {
1178 .readlink = generic_readlink,
1179 .get_link = xfs_vn_get_link_inline,
1180 .getattr = xfs_vn_getattr,
1181 .setattr = xfs_vn_setattr,
1182 .setxattr = generic_setxattr,
1183 .getxattr = generic_getxattr,
1184 .removexattr = generic_removexattr,
1185 .listxattr = xfs_vn_listxattr,
1186 .update_time = xfs_vn_update_time,
1187};
1188
1163STATIC void 1189STATIC void
1164xfs_diflags_to_iflags( 1190xfs_diflags_to_iflags(
1165 struct inode *inode, 1191 struct inode *inode,
@@ -1186,7 +1212,7 @@ xfs_diflags_to_iflags(
1186} 1212}
1187 1213
1188/* 1214/*
1189 * Initialize the Linux inode and set up the operation vectors. 1215 * Initialize the Linux inode.
1190 * 1216 *
1191 * When reading existing inodes from disk this is called directly from xfs_iget, 1217 * When reading existing inodes from disk this is called directly from xfs_iget,
1192 * when creating a new inode it is called from xfs_ialloc after setting up the 1218 * when creating a new inode it is called from xfs_ialloc after setting up the
@@ -1225,32 +1251,12 @@ xfs_setup_inode(
1225 i_size_write(inode, ip->i_d.di_size); 1251 i_size_write(inode, ip->i_d.di_size);
1226 xfs_diflags_to_iflags(inode, ip); 1252 xfs_diflags_to_iflags(inode, ip);
1227 1253
1228 ip->d_ops = ip->i_mount->m_nondir_inode_ops; 1254 if (S_ISDIR(inode->i_mode)) {
1229 lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
1230 switch (inode->i_mode & S_IFMT) {
1231 case S_IFREG:
1232 inode->i_op = &xfs_inode_operations;
1233 inode->i_fop = &xfs_file_operations;
1234 inode->i_mapping->a_ops = &xfs_address_space_operations;
1235 break;
1236 case S_IFDIR:
1237 lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); 1255 lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class);
1238 if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb))
1239 inode->i_op = &xfs_dir_ci_inode_operations;
1240 else
1241 inode->i_op = &xfs_dir_inode_operations;
1242 inode->i_fop = &xfs_dir_file_operations;
1243 ip->d_ops = ip->i_mount->m_dir_inode_ops; 1256 ip->d_ops = ip->i_mount->m_dir_inode_ops;
1244 break; 1257 } else {
1245 case S_IFLNK: 1258 ip->d_ops = ip->i_mount->m_nondir_inode_ops;
1246 inode->i_op = &xfs_symlink_inode_operations; 1259 lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
1247 if (!(ip->i_df.if_flags & XFS_IFINLINE))
1248 inode->i_mapping->a_ops = &xfs_address_space_operations;
1249 break;
1250 default:
1251 inode->i_op = &xfs_inode_operations;
1252 init_special_inode(inode, inode->i_mode, inode->i_rdev);
1253 break;
1254 } 1260 }
1255 1261
1256 /* 1262 /*
@@ -1270,3 +1276,35 @@ xfs_setup_inode(
1270 cache_no_acl(inode); 1276 cache_no_acl(inode);
1271 } 1277 }
1272} 1278}
1279
1280void
1281xfs_setup_iops(
1282 struct xfs_inode *ip)
1283{
1284 struct inode *inode = &ip->i_vnode;
1285
1286 switch (inode->i_mode & S_IFMT) {
1287 case S_IFREG:
1288 inode->i_op = &xfs_inode_operations;
1289 inode->i_fop = &xfs_file_operations;
1290 inode->i_mapping->a_ops = &xfs_address_space_operations;
1291 break;
1292 case S_IFDIR:
1293 if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb))
1294 inode->i_op = &xfs_dir_ci_inode_operations;
1295 else
1296 inode->i_op = &xfs_dir_inode_operations;
1297 inode->i_fop = &xfs_dir_file_operations;
1298 break;
1299 case S_IFLNK:
1300 if (ip->i_df.if_flags & XFS_IFINLINE)
1301 inode->i_op = &xfs_inline_symlink_inode_operations;
1302 else
1303 inode->i_op = &xfs_symlink_inode_operations;
1304 break;
1305 default:
1306 inode->i_op = &xfs_inode_operations;
1307 init_special_inode(inode, inode->i_mode, inode->i_rdev);
1308 break;
1309 }
1310}
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index c3aeaa884478..08a46c6181fd 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -131,6 +131,8 @@ xfs_readlink(
131 131
132 trace_xfs_readlink(ip); 132 trace_xfs_readlink(ip);
133 133
134 ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
135
134 if (XFS_FORCED_SHUTDOWN(mp)) 136 if (XFS_FORCED_SHUTDOWN(mp))
135 return -EIO; 137 return -EIO;
136 138
@@ -150,12 +152,7 @@ xfs_readlink(
150 } 152 }
151 153
152 154
153 if (ip->i_df.if_flags & XFS_IFINLINE) { 155 error = xfs_readlink_bmap(ip, link);
154 memcpy(link, ip->i_df.if_u1.if_data, pathlen);
155 link[pathlen] = '\0';
156 } else {
157 error = xfs_readlink_bmap(ip, link);
158 }
159 156
160 out: 157 out:
161 xfs_iunlock(ip, XFS_ILOCK_SHARED); 158 xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -303,19 +300,11 @@ xfs_symlink(
303 * If the symlink will fit into the inode, write it inline. 300 * If the symlink will fit into the inode, write it inline.
304 */ 301 */
305 if (pathlen <= XFS_IFORK_DSIZE(ip)) { 302 if (pathlen <= XFS_IFORK_DSIZE(ip)) {
306 xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); 303 xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
307 memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
308 ip->i_d.di_size = pathlen;
309
310 /*
311 * The inode was initially created in extent format.
312 */
313 ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
314 ip->i_df.if_flags |= XFS_IFINLINE;
315 304
305 ip->i_d.di_size = pathlen;
316 ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; 306 ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
317 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); 307 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
318
319 } else { 308 } else {
320 int offset; 309 int offset;
321 310