aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-04-05 17:53:29 -0400
committerDave Chinner <david@fromorbit.com>2016-04-05 17:53:29 -0400
commit30ee052e12b97c190b27fe6f20e3ac3047df7b5c (patch)
tree92b34446e88e72e6ddce730b1f1b4192614a45be
parentbfe8804d908a791b16e3686c101f0d7eca9fb5b9 (diff)
xfs: optimize inline symlinks
By overallocating the in-core inode fork data buffer and zero terminating the link target in xfs_init_local_fork we can avoid the memory allocation in ->follow_link. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c22
-rw-r--r--fs/xfs/xfs_inode_item.c4
-rw-r--r--fs/xfs/xfs_iops.c29
-rw-r--r--fs/xfs/xfs_symlink.c9
4 files changed, 49 insertions, 15 deletions
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 86a97f8a9de3..4fbe2263c1fc 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -239,19 +239,33 @@ xfs_init_local_fork(
239 int size) 239 int size)
240{ 240{
241 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); 241 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
242 int real_size = 0; 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++;
243 254
244 if (size == 0) 255 if (size == 0)
245 ifp->if_u1.if_data = NULL; 256 ifp->if_u1.if_data = NULL;
246 else if (size <= sizeof(ifp->if_u2.if_inline_data)) 257 else if (mem_size <= sizeof(ifp->if_u2.if_inline_data))
247 ifp->if_u1.if_data = ifp->if_u2.if_inline_data; 258 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
248 else { 259 else {
249 real_size = roundup(size, 4); 260 real_size = roundup(mem_size, 4);
250 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); 261 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
251 } 262 }
252 263
253 if (size) 264 if (size) {
254 memcpy(ifp->if_u1.if_data, data, size); 265 memcpy(ifp->if_u1.if_data, data, size);
266 if (zero_terminate)
267 ifp->if_u1.if_data[size] = '\0';
268 }
255 269
256 ifp->if_bytes = size; 270 ifp->if_bytes = size;
257 ifp->if_real_bytes = real_size; 271 ifp->if_real_bytes = real_size;
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_iops.c b/fs/xfs/xfs_iops.c
index f08d91c51b7f..aee06d9a7b6c 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -446,6 +446,16 @@ xfs_vn_get_link(
446 return ERR_PTR(error); 446 return ERR_PTR(error);
447} 447}
448 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
449STATIC int 459STATIC int
450xfs_vn_getattr( 460xfs_vn_getattr(
451 struct vfsmount *mnt, 461 struct vfsmount *mnt,
@@ -1171,6 +1181,18 @@ static const struct inode_operations xfs_symlink_inode_operations = {
1171 .update_time = xfs_vn_update_time, 1181 .update_time = xfs_vn_update_time,
1172}; 1182};
1173 1183
1184static const struct inode_operations xfs_inline_symlink_inode_operations = {
1185 .readlink = generic_readlink,
1186 .get_link = xfs_vn_get_link_inline,
1187 .getattr = xfs_vn_getattr,
1188 .setattr = xfs_vn_setattr,
1189 .setxattr = generic_setxattr,
1190 .getxattr = generic_getxattr,
1191 .removexattr = generic_removexattr,
1192 .listxattr = xfs_vn_listxattr,
1193 .update_time = xfs_vn_update_time,
1194};
1195
1174STATIC void 1196STATIC void
1175xfs_diflags_to_iflags( 1197xfs_diflags_to_iflags(
1176 struct inode *inode, 1198 struct inode *inode,
@@ -1282,9 +1304,10 @@ xfs_setup_iops(
1282 inode->i_fop = &xfs_dir_file_operations; 1304 inode->i_fop = &xfs_dir_file_operations;
1283 break; 1305 break;
1284 case S_IFLNK: 1306 case S_IFLNK:
1285 inode->i_op = &xfs_symlink_inode_operations; 1307 if (ip->i_df.if_flags & XFS_IFINLINE)
1286 if (!(ip->i_df.if_flags & XFS_IFINLINE)) 1308 inode->i_op = &xfs_inline_symlink_inode_operations;
1287 inode->i_mapping->a_ops = &xfs_address_space_operations; 1309 else
1310 inode->i_op = &xfs_symlink_inode_operations;
1288 break; 1311 break;
1289 default: 1312 default:
1290 inode->i_op = &xfs_inode_operations; 1313 inode->i_op = &xfs_inode_operations;
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index b69f4a770fc9..5961c1e880c2 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);