Commit 4ad350ac authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: only iget the file once when doing vectored scrub-by-handle

If a program wants us to perform a scrub on a file handle and the fd
passed to ioctl() is not the file referenced in the handle, iget the
file once and pass it into the scrub code.  This amortizes the untrusted
iget lookup over /all/ the scrubbers mentioned in the scrubv call.

When running fstests in "rebuild all metadata after each test" mode, I
observed a 10% reduction in runtime on account of avoiding repeated
inobt lookups.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent b27ce0da
...@@ -792,6 +792,37 @@ xfs_scrubv_check_barrier( ...@@ -792,6 +792,37 @@ xfs_scrubv_check_barrier(
return 0; return 0;
} }
/*
* If the caller provided us with a nonzero inode number that isn't the ioctl
* file, try to grab a reference to it to eliminate all further untrusted inode
* lookups. If we can't get the inode, let each scrub function try again.
*/
STATIC struct xfs_inode *
xchk_scrubv_open_by_handle(
struct xfs_mount *mp,
const struct xfs_scrub_vec_head *head)
{
struct xfs_trans *tp;
struct xfs_inode *ip;
int error;
error = xfs_trans_alloc_empty(mp, &tp);
if (error)
return NULL;
error = xfs_iget(mp, tp, head->svh_ino, XCHK_IGET_FLAGS, 0, &ip);
xfs_trans_cancel(tp);
if (error)
return NULL;
if (VFS_I(ip)->i_generation != head->svh_gen) {
xfs_irele(ip);
return NULL;
}
return ip;
}
/* Vectored scrub implementation to reduce ioctl calls. */ /* Vectored scrub implementation to reduce ioctl calls. */
int int
xfs_ioc_scrubv_metadata( xfs_ioc_scrubv_metadata(
...@@ -804,6 +835,7 @@ xfs_ioc_scrubv_metadata( ...@@ -804,6 +835,7 @@ xfs_ioc_scrubv_metadata(
struct xfs_scrub_vec __user *uvectors; struct xfs_scrub_vec __user *uvectors;
struct xfs_inode *ip_in = XFS_I(file_inode(file)); struct xfs_inode *ip_in = XFS_I(file_inode(file));
struct xfs_mount *mp = ip_in->i_mount; struct xfs_mount *mp = ip_in->i_mount;
struct xfs_inode *handle_ip = NULL;
struct xfs_scrub_vec *v; struct xfs_scrub_vec *v;
size_t vec_bytes; size_t vec_bytes;
unsigned int i; unsigned int i;
...@@ -848,6 +880,17 @@ xfs_ioc_scrubv_metadata( ...@@ -848,6 +880,17 @@ xfs_ioc_scrubv_metadata(
trace_xchk_scrubv_item(mp, &head, i, v); trace_xchk_scrubv_item(mp, &head, i, v);
} }
/*
* If the caller wants us to do a scrub-by-handle and the file used to
* call the ioctl is not the same file, load the incore inode and pin
* it across all the scrubv actions to avoid repeated UNTRUSTED
* lookups. The reference is not passed to deeper layers of scrub
* because each scrubber gets to decide its own strategy and return
* values for getting an inode.
*/
if (head.svh_ino && head.svh_ino != ip_in->i_ino)
handle_ip = xchk_scrubv_open_by_handle(mp, &head);
/* Run all the scrubbers. */ /* Run all the scrubbers. */
for (i = 0, v = vectors; i < head.svh_nr; i++, v++) { for (i = 0, v = vectors; i < head.svh_nr; i++, v++) {
struct xfs_scrub_metadata sm = { struct xfs_scrub_metadata sm = {
...@@ -895,6 +938,8 @@ xfs_ioc_scrubv_metadata( ...@@ -895,6 +938,8 @@ xfs_ioc_scrubv_metadata(
} }
out_free: out_free:
if (handle_ip)
xfs_irele(handle_ip);
kfree(vectors); kfree(vectors);
return error; return error;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment