Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30ee052e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent bfe8804d
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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,
+26 −3
Original line number Diff line number Diff line
@@ -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:
		if (ip->i_df.if_flags & XFS_IFINLINE)
			inode->i_op = &xfs_inline_symlink_inode_operations;
		else
			inode->i_op = &xfs_symlink_inode_operations;
		if (!(ip->i_df.if_flags & XFS_IFINLINE))
			inode->i_mapping->a_ops = &xfs_address_space_operations;
		break;
	default:
		inode->i_op = &xfs_inode_operations;
+3 −6
Original line number Diff line number Diff line
@@ -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);
	}

 out:
	xfs_iunlock(ip, XFS_ILOCK_SHARED);