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>
This commit is contained in:
parent
bfe8804d90
commit
30ee052e12
|
@ -239,19 +239,33 @@ xfs_init_local_fork(
|
|||
int size)
|
||||
{
|
||||
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
|
||||
int real_size = 0;
|
||||
int mem_size = size, real_size = 0;
|
||||
bool zero_terminate;
|
||||
|
||||
/*
|
||||
* If we are using the local fork to store a symlink body we need to
|
||||
* zero-terminate it so that we can pass it back to the VFS directly.
|
||||
* Overallocate the in-memory fork by one for that and add a zero
|
||||
* to terminate it below.
|
||||
*/
|
||||
zero_terminate = S_ISLNK(VFS_I(ip)->i_mode);
|
||||
if (zero_terminate)
|
||||
mem_size++;
|
||||
|
||||
if (size == 0)
|
||||
ifp->if_u1.if_data = NULL;
|
||||
else if (size <= sizeof(ifp->if_u2.if_inline_data))
|
||||
else if (mem_size <= sizeof(ifp->if_u2.if_inline_data))
|
||||
ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
|
||||
else {
|
||||
real_size = roundup(size, 4);
|
||||
real_size = roundup(mem_size, 4);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
|
||||
}
|
||||
|
||||
if (size)
|
||||
if (size) {
|
||||
memcpy(ifp->if_u1.if_data, data, size);
|
||||
if (zero_terminate)
|
||||
ifp->if_u1.if_data[size] = '\0';
|
||||
}
|
||||
|
||||
ifp->if_bytes = size;
|
||||
ifp->if_real_bytes = real_size;
|
||||
|
|
|
@ -210,7 +210,7 @@ xfs_inode_item_format_data_fork(
|
|||
*/
|
||||
data_bytes = roundup(ip->i_df.if_bytes, 4);
|
||||
ASSERT(ip->i_df.if_real_bytes == 0 ||
|
||||
ip->i_df.if_real_bytes == data_bytes);
|
||||
ip->i_df.if_real_bytes >= data_bytes);
|
||||
ASSERT(ip->i_df.if_u1.if_data != NULL);
|
||||
ASSERT(ip->i_d.di_size > 0);
|
||||
xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL,
|
||||
|
@ -305,7 +305,7 @@ xfs_inode_item_format_attr_fork(
|
|||
*/
|
||||
data_bytes = roundup(ip->i_afp->if_bytes, 4);
|
||||
ASSERT(ip->i_afp->if_real_bytes == 0 ||
|
||||
ip->i_afp->if_real_bytes == data_bytes);
|
||||
ip->i_afp->if_real_bytes >= data_bytes);
|
||||
ASSERT(ip->i_afp->if_u1.if_data != NULL);
|
||||
xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL,
|
||||
ip->i_afp->if_u1.if_data,
|
||||
|
|
|
@ -446,6 +446,16 @@ xfs_vn_get_link(
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
STATIC const char *
|
||||
xfs_vn_get_link_inline(
|
||||
struct dentry *dentry,
|
||||
struct inode *inode,
|
||||
struct delayed_call *done)
|
||||
{
|
||||
ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE);
|
||||
return XFS_I(inode)->i_df.if_u1.if_data;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_vn_getattr(
|
||||
struct vfsmount *mnt,
|
||||
|
@ -1171,6 +1181,18 @@ static const struct inode_operations xfs_symlink_inode_operations = {
|
|||
.update_time = xfs_vn_update_time,
|
||||
};
|
||||
|
||||
static const struct inode_operations xfs_inline_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.get_link = xfs_vn_get_link_inline,
|
||||
.getattr = xfs_vn_getattr,
|
||||
.setattr = xfs_vn_setattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.listxattr = xfs_vn_listxattr,
|
||||
.update_time = xfs_vn_update_time,
|
||||
};
|
||||
|
||||
STATIC void
|
||||
xfs_diflags_to_iflags(
|
||||
struct inode *inode,
|
||||
|
@ -1282,9 +1304,10 @@ xfs_setup_iops(
|
|||
inode->i_fop = &xfs_dir_file_operations;
|
||||
break;
|
||||
case S_IFLNK:
|
||||
inode->i_op = &xfs_symlink_inode_operations;
|
||||
if (!(ip->i_df.if_flags & XFS_IFINLINE))
|
||||
inode->i_mapping->a_ops = &xfs_address_space_operations;
|
||||
if (ip->i_df.if_flags & XFS_IFINLINE)
|
||||
inode->i_op = &xfs_inline_symlink_inode_operations;
|
||||
else
|
||||
inode->i_op = &xfs_symlink_inode_operations;
|
||||
break;
|
||||
default:
|
||||
inode->i_op = &xfs_inode_operations;
|
||||
|
|
|
@ -131,6 +131,8 @@ xfs_readlink(
|
|||
|
||||
trace_xfs_readlink(ip);
|
||||
|
||||
ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
|
||||
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return -EIO;
|
||||
|
||||
|
@ -150,12 +152,7 @@ xfs_readlink(
|
|||
}
|
||||
|
||||
|
||||
if (ip->i_df.if_flags & XFS_IFINLINE) {
|
||||
memcpy(link, ip->i_df.if_u1.if_data, pathlen);
|
||||
link[pathlen] = '\0';
|
||||
} else {
|
||||
error = xfs_readlink_bmap(ip, link);
|
||||
}
|
||||
error = xfs_readlink_bmap(ip, link);
|
||||
|
||||
out:
|
||||
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
||||
|
|
Loading…
Reference in New Issue