Skip to content

Commit 4ad350a

Browse files
author
Darrick J. Wong
committed
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: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent b27ce0d commit 4ad350a

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

fs/xfs/scrub/scrub.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,37 @@ xfs_scrubv_check_barrier(
792792
return 0;
793793
}
794794

795+
/*
796+
* If the caller provided us with a nonzero inode number that isn't the ioctl
797+
* file, try to grab a reference to it to eliminate all further untrusted inode
798+
* lookups. If we can't get the inode, let each scrub function try again.
799+
*/
800+
STATIC struct xfs_inode *
801+
xchk_scrubv_open_by_handle(
802+
struct xfs_mount *mp,
803+
const struct xfs_scrub_vec_head *head)
804+
{
805+
struct xfs_trans *tp;
806+
struct xfs_inode *ip;
807+
int error;
808+
809+
error = xfs_trans_alloc_empty(mp, &tp);
810+
if (error)
811+
return NULL;
812+
813+
error = xfs_iget(mp, tp, head->svh_ino, XCHK_IGET_FLAGS, 0, &ip);
814+
xfs_trans_cancel(tp);
815+
if (error)
816+
return NULL;
817+
818+
if (VFS_I(ip)->i_generation != head->svh_gen) {
819+
xfs_irele(ip);
820+
return NULL;
821+
}
822+
823+
return ip;
824+
}
825+
795826
/* Vectored scrub implementation to reduce ioctl calls. */
796827
int
797828
xfs_ioc_scrubv_metadata(
@@ -804,6 +835,7 @@ xfs_ioc_scrubv_metadata(
804835
struct xfs_scrub_vec __user *uvectors;
805836
struct xfs_inode *ip_in = XFS_I(file_inode(file));
806837
struct xfs_mount *mp = ip_in->i_mount;
838+
struct xfs_inode *handle_ip = NULL;
807839
struct xfs_scrub_vec *v;
808840
size_t vec_bytes;
809841
unsigned int i;
@@ -848,6 +880,17 @@ xfs_ioc_scrubv_metadata(
848880
trace_xchk_scrubv_item(mp, &head, i, v);
849881
}
850882

883+
/*
884+
* If the caller wants us to do a scrub-by-handle and the file used to
885+
* call the ioctl is not the same file, load the incore inode and pin
886+
* it across all the scrubv actions to avoid repeated UNTRUSTED
887+
* lookups. The reference is not passed to deeper layers of scrub
888+
* because each scrubber gets to decide its own strategy and return
889+
* values for getting an inode.
890+
*/
891+
if (head.svh_ino && head.svh_ino != ip_in->i_ino)
892+
handle_ip = xchk_scrubv_open_by_handle(mp, &head);
893+
851894
/* Run all the scrubbers. */
852895
for (i = 0, v = vectors; i < head.svh_nr; i++, v++) {
853896
struct xfs_scrub_metadata sm = {
@@ -895,6 +938,8 @@ xfs_ioc_scrubv_metadata(
895938
}
896939

897940
out_free:
941+
if (handle_ip)
942+
xfs_irele(handle_ip);
898943
kfree(vectors);
899944
return error;
900945
}

0 commit comments

Comments
 (0)