xfs: online scrub support
v10 cover xfs: online scrub support
Hi all,
This is the ninth revision of a patchset that adds to XFS kernel support for online metadata scrubbing and repair. There aren't any on-disk format changes. Changes since v9 include minor bug fixes and rebasing to 4.14. I have been performing daily online scrubs of my XFS filesystems for several months now, with surprisingly few problems.
Online scrub/repair support consists of four major pieces -- first, an ioctl that maps physical extents to their owners (GETFSMAP; already in 4.12); second, various in-kernel metadata scrubbing ioctls to examine metadata records and cross-reference them with other filesystem metadata; third, an in-kernel mechanism for rebuilding damaged metadata objects and btrees; and fourth, a userspace component to coordinate scrubbing and repair operations.
This new utility, xfs_scrub, is separate from the existing offline xfs_repair tool. The program uses various XFS ioctls to iterate all XFS metadata and asks the kernel to check the metadata and repair it if necessary.
While I understand that reviewer bandwidth is limited, I would like to get this series prepped for 4.15, if possible. I have isolated the scrub code such that it can be compiled out entirely, in the hopes that we can stabilize the code while not exposing regular users to riskier code.
If you're going to start using this mess, you probably ought to just pull from my git trees. The kernel patches[1] should apply against 4.14-rc1. xfsprogs[2] and xfstests[3] can be found in their usual places. The git trees contain all four series' worth of changes.
This is an extraordinary way to eat your data. Enjoy! Comments and questions are, as always, welcome.
--D
[1] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=djwong-devel
[2] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=djwong-devel
[3] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=djwong-devel
PATCH v10 1/27 xfs: return a distinct error code value for IGET_INCORE cache misses
From: Darrick J. Wong <[email protected]>
For an XFS_IGET_INCORE iget operation, if the inode isn't in the cache, return ENODATA so that we don't confuse it with the pre-existing ENOENT cases (inode is in cache, but freed).
--- fs/xfs/xfs_icache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_icache.c +1 -1
@@ -610,7 +610,7 @@ xfs_iget( }else {rcu_read_unlock ();if (flags &XFS_IGET_INCORE ) { - error = -ENOENT ; + error = -ENODATA ; goto out_error_or_again; }XFS_STATS_INC (mp, xs_ig_missed);
Re: [PATCH 01/27] xfs: return a distinct error code value for IGET_INCORE cache misses
Quoted 8 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
For an
XFS_IGET_INCOREiget operation, if the inode isn't in the cache, return ENODATA so that we don't confuse it with the pre-existing ENOENT cases (inode is in cache, but freed).Signed-off-by Darrick J. Wong <[email protected]>---
Quoted 22 lines
fs/xfs/xfs_icache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)fs/xfs/xfs_icache.c +1
-2@@ -610,7 +610,7 @@ xfs_iget( }else {rcu_read_unlock ();if (flags &XFS_IGET_INCORE ) { - error = -ENOENT ; + error = -ENODATA ; goto out_error_or_again; }XFS_STATS_INC (mp, xs_ig_missed); --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 2/27 xfs: query the per-AG reservation counters
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Establish an ioctl for userspace to query the original and current per-AG reservation counts. This will be used by xfs_scrub to check that the vfs counters are at least somewhat sane.
--- fs/xfs/libxfs/xfs_fs.h | 12 ++++++++++++ fs/xfs/xfs_fsops.c | 26 ++++++++++++++++++++++++++ fs/xfs/xfs_fsops.h | 2 ++ fs/xfs/xfs_ioctl.c | 24 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 5 files changed, 65 insertions(+)
fs/xfs/libxfs/xfs_fs.h +12 -0
@@ -469,6 +469,17 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ /* +* AG reserved block counters +*/ +struct xfs_fsop_ag_resblks { +__u32 ar_flags;/* output flags, none defined now */ +__u32 ar_reserved;/* zero */ +__u64 ar_current_resv;/* blocks reserved now */ +__u64 ar_mount_resv;/* blocks reserved at mount time */ +__u64 ar_reserved2[5 ];/* zero */ +}; + +/* * ioctl limits */ #ifdef XATTR_LIST_MAX
@@ -543,6 +554,7 @@ typedef struct xfs_swapext#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)#define XFS_IOC_GOINGDOWN _IOR ('X', 125, uint32_t) +#define XFS_IOC_GET_AG_RESBLKS _IOR ('X', 126, struct xfs_fsop_ag_resblks)/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
fs/xfs/xfs_fsops.c +26 -0
@@ -44,6 +44,7 @@#include "xfs_filestream.h" #include "xfs_rmap.h" #include "xfs_ag_resv.h" +#include "xfs_fs.h" /* * File system operations
@@ -1046,3 +1047,28 @@ xfs_fs_unreserve_ag_blocks(return error; } + +/* Query the per-AG reservations to see how many blocks we have reserved. */ +int +xfs_fs_get_ag_reserve_blocks ( +struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out) +{ +struct xfs_ag_resv *r; +struct xfs_perag *pag; +xfs_agnumber_t agno; + +memset (out,0 ,sizeof (struct xfs_fsop_ag_resblks )); +for (agno =0 ; agno < mp->m_sb.sb_agcount; agno++) { + pag =xfs_perag_get (mp, agno); + r =xfs_perag_resv (pag,XFS_AG_RESV_METADATA ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; + r =xfs_perag_resv (pag,XFS_AG_RESV_AGFL ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; +xfs_perag_put (pag); + } + +return 0 ; +}
fs/xfs/xfs_fsops.h +2 -0
@@ -25,6 +25,8 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt);extern int xfs_reserve_blocks (xfs_mount_t *mp,uint64_t *inval,xfs_fsop_resblks_t *outval);extern int xfs_fs_goingdown (xfs_mount_t *mp,uint32_t inflags); +extern int xfs_fs_get_ag_reserve_blocks (struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out);extern int xfs_fs_reserve_ag_blocks (struct xfs_mount *mp);extern int xfs_fs_unreserve_ag_blocks (struct xfs_mount *mp);
fs/xfs/xfs_ioctl.c +24 -0
@@ -1782,6 +1782,27 @@ xfs_ioc_swapext(return error; } +static int +xfs_ioc_get_ag_reserve_blocks ( +struct xfs_mount *mp, +void __user *arg) +{ +struct xfs_fsop_ag_resblks out; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + error =xfs_fs_get_ag_reserve_blocks (mp, &out); +if (error) +return error; + +if (copy_to_user (arg, &out,sizeof (out))) +return -EFAULT ; + +return 0 ; +} +/* * Note: some of the ioctl's return positive numbers as a * byte count indicating success, such as readlink_by_handle.
@@ -1987,6 +2008,9 @@ xfs_file_ioctl(return 0 ; } +case XFS_IOC_GET_AG_RESBLKS : +return xfs_ioc_get_ag_reserve_blocks (mp, arg); +case XFS_IOC_FSGROWFSDATA : {xfs_growfs_data_t in;
fs/xfs/xfs_ioctl32.c +1 -0
@@ -556,6 +556,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_INJECTION :case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP : +case XFS_IOC_GET_AG_RESBLKS :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */
Re: [PATCH 02/27] xfs: query the per-AG reservation counters
Quoted 8 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Establish an ioctl for userspace to query the original and current per-AG reservation counts. This will be used by
xfs_scrubto check that the vfs counters are at least somewhat sane.Signed-off-by Darrick J. Wong <[email protected]>---
The code seems fine, but I'm wondering how much of this would remain as is based on Dave's potential switch of the perag res stuff to be a hidden reservation. That itself still needs to be posted/reviewed/etc., so might it be smarter to defer defining an interface to export this stuff until the core mechanism is worked out?
That aside, I'm also wondering how/what userspace scrub does with the overall total values as opposed to individual AG reservation values. Are the current "ask" values expected to be uniform across each AG..? For example, what happens if one AG has a bogus "current" value for whatever reason (perhaps this is more relevant for both values if we do actually end up with on-disk reservations)?
Brian
Quoted 151 lines
fs/xfs/libxfs/xfs_fs.h | 12 ++++++++++++ fs/xfs/xfs_fsops.c | 26 ++++++++++++++++++++++++++ fs/xfs/xfs_fsops.h | 2 ++ fs/xfs/xfs_ioctl.c | 24 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 5 files changed, 65 insertions(+)fs/xfs/libxfs/xfs_fs.h +12
-0@@ -469,6 +469,17 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ /* +* AG reserved block counters +*/ +struct xfs_fsop_ag_resblks { +__u32 ar_flags;/* output flags, none defined now */ +__u32 ar_reserved;/* zero */ +__u64 ar_current_resv;/* blocks reserved now */ +__u64 ar_mount_resv;/* blocks reserved at mount time */ +__u64 ar_reserved2[5 ];/* zero */ +}; + +/* * ioctl limits */ #ifdef XATTR_LIST_MAX @@ -543,6 +554,7 @@ typedef struct xfs_swapext#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)#define XFS_IOC_GOINGDOWN _IOR ('X', 125, uint32_t) +#define XFS_IOC_GET_AG_RESBLKS _IOR ('X', 126, struct xfs_fsop_ag_resblks)/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ fs/xfs/xfs_fsops.c +26
-0@@ -44,6 +44,7 @@#include "xfs_filestream.h" #include "xfs_rmap.h" #include "xfs_ag_resv.h" +#include "xfs_fs.h" /* * File system operations @@ -1046,3 +1047,28 @@ xfs_fs_unreserve_ag_blocks(return error; } + +/* Query the per-AG reservations to see how many blocks we have reserved. */ +int +xfs_fs_get_ag_reserve_blocks ( +struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out) +{ +struct xfs_ag_resv *r; +struct xfs_perag *pag; +xfs_agnumber_t agno; + +memset (out,0 ,sizeof (struct xfs_fsop_ag_resblks )); +for (agno =0 ; agno < mp->m_sb.sb_agcount; agno++) { + pag =xfs_perag_get (mp, agno); + r =xfs_perag_resv (pag,XFS_AG_RESV_METADATA ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; + r =xfs_perag_resv (pag,XFS_AG_RESV_AGFL ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; +xfs_perag_put (pag); + } + +return 0 ; +}fs/xfs/xfs_fsops.h +2
-0@@ -25,6 +25,8 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt);extern int xfs_reserve_blocks (xfs_mount_t *mp,uint64_t *inval,xfs_fsop_resblks_t *outval);extern int xfs_fs_goingdown (xfs_mount_t *mp,uint32_t inflags); +extern int xfs_fs_get_ag_reserve_blocks (struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out);extern int xfs_fs_reserve_ag_blocks (struct xfs_mount *mp);extern int xfs_fs_unreserve_ag_blocks (struct xfs_mount *mp);fs/xfs/xfs_ioctl.c +24
-0@@ -1782,6 +1782,27 @@ xfs_ioc_swapext(return error; } +static int +xfs_ioc_get_ag_reserve_blocks ( +struct xfs_mount *mp, +void __user *arg) +{ +struct xfs_fsop_ag_resblks out; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + error =xfs_fs_get_ag_reserve_blocks (mp, &out); +if (error) +return error; + +if (copy_to_user (arg, &out,sizeof (out))) +return -EFAULT ; + +return 0 ; +} +/* * Note: some of the ioctl's return positive numbers as a * byte count indicating success, such as readlink_by_handle. @@ -1987,6 +2008,9 @@ xfs_file_ioctl(return 0 ; } +case XFS_IOC_GET_AG_RESBLKS : +return xfs_ioc_get_ag_reserve_blocks (mp, arg); +case XFS_IOC_FSGROWFSDATA : {xfs_growfs_data_t in;fs/xfs/xfs_ioctl32.c +1
-1@@ -556,6 +556,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_INJECTION :case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP : +case XFS_IOC_GET_AG_RESBLKS :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/27] xfs: query the per-AG reservation counters
Quoted 7 lines · Brian Foster
Quoted 6 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Establish an ioctl for userspace to query the original and current per-AG reservation counts. This will be used by
xfs_scrubto check that the vfs counters are at least somewhat sane.
Quoted 8 lines
Quoted 2 lines
Signed-off-by Darrick J. Wong <[email protected]>---
The code seems fine, but I'm wondering how much of this would remain as is based on Dave's potential switch of the perag res stuff to be a hidden reservation. That itself still needs to be posted/reviewed/etc., so might it be smarter to defer defining an interface to export this stuff until the core mechanism is worked out?
I think Dave's vision is that we should permanently steal the AG reservations from the max fs size:
(device size - static metadata - static per-ag reservations)
In which case the ioctl isn't needed at all, since the statfs counters would simply never report the per-ag reservations at all.
Quoted 2 lines
That aside, I'm also wondering how/what userspace scrub does with the overall total values as opposed to individual AG reservation values.
To a rough approximation, xfs_scrub (phase 7) compares the fs geometry data (used blocks, used inodes) against what it found via getfsmap and bulkstat and warns about a potentially insufficient scrub if the counts are off by more than 10% from what the fs reports. The per-AG summary counter ar_current_resv is added to the statvfs.f_bfree counter since reserved blocks don't show up in getfsmap.
Since per-AG reservations never use more than 9% of the fs space worst case (1k blocks) and usually 2% (4k blocks) the current 10% tolerance built into xfs_scrub is probably good enough for now.
Anyway, I plan to withdraw this patch.
Quoted 1 line
Are the current "ask" values expected to be uniform across each AG..?
scrub doesn't care.
Quoted 3 lines
For example, what happens if one AG has a bogus "current" value for whatever reason (perhaps this is more relevant for both values if we do actually end up with on-disk reservations)?
If it exceeds scrub's tolerances it'll warn about the discrepancy. There's probably no way to fix the summary counters without an xfs_repair run, unless it's acceptable to freeze the whole fs.
Not going to try to do that. :)
--D
Quoted 158 lines
Brian
Quoted 148 lines
fs/xfs/libxfs/xfs_fs.h | 12 ++++++++++++ fs/xfs/xfs_fsops.c | 26 ++++++++++++++++++++++++++ fs/xfs/xfs_fsops.h | 2 ++ fs/xfs/xfs_ioctl.c | 24 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 5 files changed, 65 insertions(+)fs/xfs/libxfs/xfs_fs.h +12
-0@@ -469,6 +469,17 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ /* +* AG reserved block counters +*/ +struct xfs_fsop_ag_resblks { +__u32 ar_flags;/* output flags, none defined now */ +__u32 ar_reserved;/* zero */ +__u64 ar_current_resv;/* blocks reserved now */ +__u64 ar_mount_resv;/* blocks reserved at mount time */ +__u64 ar_reserved2[5 ];/* zero */ +}; + +/* * ioctl limits */ #ifdef XATTR_LIST_MAX @@ -543,6 +554,7 @@ typedef struct xfs_swapext#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)#define XFS_IOC_GOINGDOWN _IOR ('X', 125, uint32_t) +#define XFS_IOC_GET_AG_RESBLKS _IOR ('X', 126, struct xfs_fsop_ag_resblks)/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ fs/xfs/xfs_fsops.c +26
-0@@ -44,6 +44,7 @@#include "xfs_filestream.h" #include "xfs_rmap.h" #include "xfs_ag_resv.h" +#include "xfs_fs.h" /* * File system operations @@ -1046,3 +1047,28 @@ xfs_fs_unreserve_ag_blocks(return error; } + +/* Query the per-AG reservations to see how many blocks we have reserved. */ +int +xfs_fs_get_ag_reserve_blocks ( +struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out) +{ +struct xfs_ag_resv *r; +struct xfs_perag *pag; +xfs_agnumber_t agno; + +memset (out,0 ,sizeof (struct xfs_fsop_ag_resblks )); +for (agno =0 ; agno < mp->m_sb.sb_agcount; agno++) { + pag =xfs_perag_get (mp, agno); + r =xfs_perag_resv (pag,XFS_AG_RESV_METADATA ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; + r =xfs_perag_resv (pag,XFS_AG_RESV_AGFL ); + out->ar_current_resv += r->ar_reserved; + out->ar_mount_resv += r->ar_asked; +xfs_perag_put (pag); + } + +return 0 ; +}fs/xfs/xfs_fsops.h +2
-0@@ -25,6 +25,8 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt);extern int xfs_reserve_blocks (xfs_mount_t *mp,uint64_t *inval,xfs_fsop_resblks_t *outval);extern int xfs_fs_goingdown (xfs_mount_t *mp,uint32_t inflags); +extern int xfs_fs_get_ag_reserve_blocks (struct xfs_mount *mp, +struct xfs_fsop_ag_resblks *out);extern int xfs_fs_reserve_ag_blocks (struct xfs_mount *mp);extern int xfs_fs_unreserve_ag_blocks (struct xfs_mount *mp);fs/xfs/xfs_ioctl.c +24
-0@@ -1782,6 +1782,27 @@ xfs_ioc_swapext(return error; } +static int +xfs_ioc_get_ag_reserve_blocks ( +struct xfs_mount *mp, +void __user *arg) +{ +struct xfs_fsop_ag_resblks out; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + error =xfs_fs_get_ag_reserve_blocks (mp, &out); +if (error) +return error; + +if (copy_to_user (arg, &out,sizeof (out))) +return -EFAULT ; + +return 0 ; +} +/* * Note: some of the ioctl's return positive numbers as a * byte count indicating success, such as readlink_by_handle. @@ -1987,6 +2008,9 @@ xfs_file_ioctl(return 0 ; } +case XFS_IOC_GET_AG_RESBLKS : +return xfs_ioc_get_ag_reserve_blocks (mp, arg); +case XFS_IOC_FSGROWFSDATA : {xfs_growfs_data_t in;fs/xfs/xfs_ioctl32.c +1
-1@@ -556,6 +556,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_INJECTION :case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP : +case XFS_IOC_GET_AG_RESBLKS :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ --Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 3/27 xfs: create an ioctl to scrub AG metadata
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create an ioctl that can be used to scrub internal filesystem metadata. The new ioctl takes the metadata type, an (optional) AG number, an (optional) inode number and generation, and a flags argument. This will be used by the upcoming XFS online scrub tool.
--- fs/xfs/Kconfig | 17 ++++++++++++++ fs/xfs/Makefile | 11 +++++++++ fs/xfs/libxfs/xfs_fs.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 25 +++++++++++++++++++++ fs/xfs/scrub/trace.c | 41 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 33 ++++++++++++++++++++++++++++ fs/xfs/scrub/xfs_scrub.h | 29 +++++++++++++++++++++++++ fs/xfs/xfs_ioctl.c | 28 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 10 files changed, 292 insertions(+) create mode 100644 fs/xfs/scrub/scrub.c create mode 100644 fs/xfs/scrub/scrub.h create mode 100644 fs/xfs/scrub/trace.c create mode 100644 fs/xfs/scrub/trace.h create mode 100644 fs/xfs/scrub/xfs_scrub.h
fs/xfs/Kconfig +17 -0
@@ -71,6 +71,23 @@ config XFS_RT If unsure, say N. +config XFS_ONLINE_SCRUB + bool "XFS online metadata check support" + default n + depends on XFS_FS + help + If you say Y here you will be able to check metadata on a + mounted XFS filesystem. This feature is intended to reduce + filesystem downtime by supplementing xfs_repair. The key + advantage here is to look for problems proactively so that + they can be dealt with in a controlled manner. + + This feature is considered EXPERIMENTAL. Use with caution! + + See the xfs_scrub man page in section 8 for additional information. + + If unsure, say N. + config XFS_WARN bool "XFS Verbose Warnings" depends on XFS_FS && !XFS_DEBUG
fs/xfs/Makefile +11 -0
@@ -138,3 +138,14 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o + +# online scrub/repair +ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) + +# Tracepoints like to blow up, so build that before everything else + +xfs-y += $(addprefix scrub/, \ + trace.o \ + scrub.o \ + ) +endif
fs/xfs/libxfs/xfs_fs.h +53 -0
65 lines not on this page · raw message
fs/xfs/scrub/scrub.c new file +54 -0
54 lines not on this page · raw message
fs/xfs/scrub/scrub.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_SCRUB_H__ +#define __XFS_SCRUB_SCRUB_H__ + +/* Metadata scrubbers */ + +#endif /* __XFS_SCRUB_SCRUB_H__ */
fs/xfs/scrub/trace.c new file +41 -0
41 lines not on this page · raw message
fs/xfs/scrub/trace.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xfs_scrub + +#if !defined(_TRACE_XFS_SCRUB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_XFS_SCRUB_TRACE_H + +#include <linux/tracepoint.h> + +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE scrub/trace +#include <trace/define_trace.h>
fs/xfs/scrub/xfs_scrub.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_H__ +#define __XFS_SCRUB_H__ + +#ifndef CONFIG_XFS_ONLINE_SCRUB +# define xfs_scrub_metadata (ip, sm) (-ENOTTY) +#else +int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm); +#endif /* CONFIG_XFS_ONLINE_SCRUB */ + +#endif /* __XFS_SCRUB_H__ */
fs/xfs/xfs_ioctl.c +28 -0
@@ -44,6 +44,7 @@#include "xfs_btree.h" #include <linux/fsmap.h> #include "xfs_fsmap.h" +#include "scrub/xfs_scrub.h" #include <linux/capability.h> #include <linux/cred.h>
@@ -1702,6 +1703,30 @@ xfs_ioc_getfsmap(return 0 ; } +STATIC int +xfs_ioc_scrub_metadata ( +struct xfs_inode *ip, +void __user *arg) +{ +struct xfs_scrub_metadata scrub; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +if (copy_from_user (&scrub, arg,sizeof (scrub))) +return -EFAULT ; + + error =xfs_scrub_metadata (ip, &scrub); +if (error) +return error; + +if (copy_to_user (arg, &scrub,sizeof (scrub))) +return -EFAULT ; + +return 0 ; +} +int xfs_ioc_swapext (xfs_swapext_t *sxp)
@@ -1906,6 +1931,9 @@ xfs_file_ioctl(case FS_IOC_GETFSMAP :return xfs_ioc_getfsmap (ip, arg); +case XFS_IOC_SCRUB_METADATA : +return xfs_ioc_scrub_metadata (ip, arg); +case XFS_IOC_FD_TO_HANDLE :case XFS_IOC_PATH_TO_HANDLE :case XFS_IOC_PATH_TO_FSHANDLE : {
fs/xfs/xfs_ioctl32.c +1 -0
@@ -557,6 +557,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP :case XFS_IOC_GET_AG_RESBLKS : +case XFS_IOC_SCRUB_METADATA :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */
Re: [PATCH 03/27] xfs: create an ioctl to scrub AG metadata
Quoted 17 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create an ioctl that can be used to scrub internal filesystem metadata. The new ioctl takes the metadata type, an (optional) AG number, an (optional) inode number and generation, and a flags argument. This will be used by the upcoming XFS online scrub tool.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Kconfig | 17 ++++++++++++++ fs/xfs/Makefile | 11 +++++++++ fs/xfs/libxfs/xfs_fs.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 25 +++++++++++++++++++++ fs/xfs/scrub/trace.c | 41 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 33 ++++++++++++++++++++++++++++ fs/xfs/scrub/xfs_scrub.h | 29 +++++++++++++++++++++++++
Quoted 10 lines
fs/xfs/xfs_ioctl.c | 28 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 10 files changed, 292 insertions(+) create mode 100644 fs/xfs/scrub/scrub.c create mode 100644 fs/xfs/scrub/scrub.h create mode 100644 fs/xfs/scrub/trace.c create mode 100644 fs/xfs/scrub/trace.h create mode 100644 fs/xfs/scrub/xfs_scrub.h
The code looks sane, though I think I need to understand the error codes a bit better. Perhaps once I get further into the series..
Brian
Quoted 400 lines
fs/xfs/Kconfig +17
-0@@ -71,6 +71,23 @@ config XFS_RT If unsure, say N. +config XFS_ONLINE_SCRUB + bool "XFS online metadata check support" + default n + depends on XFS_FS + help + If you say Y here you will be able to check metadata on a + mounted XFS filesystem. This feature is intended to reduce + filesystem downtime by supplementing xfs_repair. The key + advantage here is to look for problems proactively so that + they can be dealt with in a controlled manner. + + This feature is considered EXPERIMENTAL. Use with caution! + + See the xfs_scrub man page in section 8 for additional information. + + If unsure, say N. + config XFS_WARN bool "XFS Verbose Warnings" depends on XFS_FS && !XFS_DEBUGfs/xfs/Makefile +11
-0@@ -138,3 +138,14 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o + +# online scrub/repair +ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) + +# Tracepoints like to blow up, so build that before everything else + +xfs-y += $(addprefix scrub/, \ + trace.o \ + scrub.o \ + ) +endiffs/xfs/libxfs/xfs_fs.h +53
-0@@ -468,6 +468,58 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1/* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ +/* metadata scrubbing */ +struct xfs_scrub_metadata { +__u32 sm_type;/* What to check? */ +__u32 sm_flags;/* flags; see below. */ +__u64 sm_ino;/* inode number. */ +__u32 sm_gen;/* inode generation. */ +__u32 sm_agno;/* ag number. */ +__u64 sm_reserved[5 ];/* pad to 64 bytes */ +}; + +/* +* Metadata types and flags for scrub operation. +*/ + +/* Scrub subcommands. */ + +/* Number of scrub subcommands. */ +#define XFS_SCRUB_TYPE_NR 0 + +/* i: Repair this metadata. */ +#define XFS_SCRUB_IFLAG_REPAIR (1 << 0) + +/* o: Metadata object needs repair. */ +#define XFS_SCRUB_OFLAG_CORRUPT (1 << 1) + +/* +* o: Metadata object could be optimized. It's not corrupt, but +* we could improve on it somehow. +*/ +#define XFS_SCRUB_OFLAG_PREEN (1 << 2) + +/* o: Cross-referencing failed. */ +#define XFS_SCRUB_OFLAG_XFAIL (1 << 3) + +/* o: Metadata object disagrees with cross-referenced metadata. */ +#define XFS_SCRUB_OFLAG_XCORRUPT (1 << 4) + +/* o: Scan was not complete. */ +#define XFS_SCRUB_OFLAG_INCOMPLETE (1 << 5) + +/* o: Metadata object looked funny but isn't corrupt. */ +#define XFS_SCRUB_OFLAG_WARNING (1 << 6) + +#define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR) +#define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_PREEN | \ + XFS_SCRUB_OFLAG_XFAIL | \ + XFS_SCRUB_OFLAG_XCORRUPT | \ + XFS_SCRUB_OFLAG_INCOMPLETE | \ + XFS_SCRUB_OFLAG_WARNING) +#define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +/* * AG reserved block counters */ @@ -522,6 +574,7 @@ struct xfs_fsop_ag_resblks {#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)/* XFS_IOC_GETFSMAP ------ hoisted 59 */ +#define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)/* * ioctl commands that replace IRIX syssgi()'s fs/xfs/scrub/scrub.c new file +54
-0@@ -0,0 +1,54 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/trace.h" + +/* Dispatch metadata scrubbing. */ +int +xfs_scrub_metadata ( +struct xfs_inode *ip, +struct xfs_scrub_metadata *sm) +{ +return -EOPNOTSUPP ; +}fs/xfs/scrub/scrub.h new file +25
-0@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_SCRUB_H__ +#define __XFS_SCRUB_SCRUB_H__ + +/* Metadata scrubbers */ + +#endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.c new file +41
-0@@ -0,0 +1,41 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_da_format.h" +#include "xfs_defer.h" +#include "xfs_inode.h" +#include "xfs_btree.h" +#include "xfs_trans.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" + +/* +* We include this last to have the helpers above available for the trace +* event implementations. +*/ +#define CREATE_TRACE_POINTS +#include "scrub/trace.h" fs/xfs/scrub/trace.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xfs_scrub + +#if !defined(_TRACE_XFS_SCRUB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_XFS_SCRUB_TRACE_H + +#include <linux/tracepoint.h> + +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE scrub/trace +#include <trace/define_trace.h> fs/xfs/scrub/xfs_scrub.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_H__ +#define __XFS_SCRUB_H__ + +#ifndef CONFIG_XFS_ONLINE_SCRUB +# define xfs_scrub_metadata (ip, sm) (-ENOTTY) +#else +int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm); +#endif /* CONFIG_XFS_ONLINE_SCRUB */ + +#endif /* __XFS_SCRUB_H__ */ fs/xfs/xfs_ioctl.c +28
-0@@ -44,6 +44,7 @@#include "xfs_btree.h" #include <linux/fsmap.h> #include "xfs_fsmap.h" +#include "scrub/xfs_scrub.h" #include <linux/capability.h> #include <linux/cred.h> @@ -1702,6 +1703,30 @@ xfs_ioc_getfsmap(return 0 ; } +STATIC int +xfs_ioc_scrub_metadata ( +struct xfs_inode *ip, +void __user *arg) +{ +struct xfs_scrub_metadata scrub; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +if (copy_from_user (&scrub, arg,sizeof (scrub))) +return -EFAULT ; + + error =xfs_scrub_metadata (ip, &scrub); +if (error) +return error; + +if (copy_to_user (arg, &scrub,sizeof (scrub))) +return -EFAULT ; + +return 0 ; +} +int xfs_ioc_swapext (xfs_swapext_t *sxp)@@ -1906,6 +1931,9 @@ xfs_file_ioctl(case FS_IOC_GETFSMAP :return xfs_ioc_getfsmap (ip, arg); +case XFS_IOC_SCRUB_METADATA : +return xfs_ioc_scrub_metadata (ip, arg); +case XFS_IOC_FD_TO_HANDLE :case XFS_IOC_PATH_TO_HANDLE :case XFS_IOC_PATH_TO_FSHANDLE : {fs/xfs/xfs_ioctl32.c +1
-1@@ -557,6 +557,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP :case XFS_IOC_GET_AG_RESBLKS : +case XFS_IOC_SCRUB_METADATA :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 03/27] xfs: create an ioctl to scrub AG metadata
Quoted 29 lines · Brian Foster
Quoted 17 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create an ioctl that can be used to scrub internal filesystem metadata. The new ioctl takes the metadata type, an (optional) AG number, an (optional) inode number and generation, and a flags argument. This will be used by the upcoming XFS online scrub tool.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Kconfig | 17 ++++++++++++++ fs/xfs/Makefile | 11 +++++++++ fs/xfs/libxfs/xfs_fs.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 25 +++++++++++++++++++++ fs/xfs/scrub/trace.c | 41 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 33 ++++++++++++++++++++++++++++ fs/xfs/scrub/xfs_scrub.h | 29 +++++++++++++++++++++++++Quoted 10 lines
fs/xfs/xfs_ioctl.c | 28 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 10 files changed, 292 insertions(+) create mode 100644 fs/xfs/scrub/scrub.c create mode 100644 fs/xfs/scrub/scrub.h create mode 100644 fs/xfs/scrub/trace.c create mode 100644 fs/xfs/scrub/trace.h create mode 100644 fs/xfs/scrub/xfs_scrub.h
Quoted 2 lines
The code looks sane, though I think I need to understand the error codes a bit better. Perhaps once I get further into the series..
Yes, the ioctl needs documentation, though I'm unclear on where's an appropriate place to put them. The ioctl is not intended for general consumption, so man-pages.git seems inappropriate. I was thinking either in xfs_fs.h directly, or perhaps xfsprogs' man pages?
(We don't seem to document the xfs ioctls afaict?)
--D
Quoted 407 lines
Brian
Quoted 397 lines
fs/xfs/Kconfig +17
-0@@ -71,6 +71,23 @@ config XFS_RT If unsure, say N. +config XFS_ONLINE_SCRUB + bool "XFS online metadata check support" + default n + depends on XFS_FS + help + If you say Y here you will be able to check metadata on a + mounted XFS filesystem. This feature is intended to reduce + filesystem downtime by supplementing xfs_repair. The key + advantage here is to look for problems proactively so that + they can be dealt with in a controlled manner. + + This feature is considered EXPERIMENTAL. Use with caution! + + See the xfs_scrub man page in section 8 for additional information. + + If unsure, say N. + config XFS_WARN bool "XFS Verbose Warnings" depends on XFS_FS && !XFS_DEBUGfs/xfs/Makefile +11
-0@@ -138,3 +138,14 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o + +# online scrub/repair +ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) + +# Tracepoints like to blow up, so build that before everything else + +xfs-y += $(addprefix scrub/, \ + trace.o \ + scrub.o \ + ) +endiffs/xfs/libxfs/xfs_fs.h +53
-0@@ -468,6 +468,58 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1/* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ +/* metadata scrubbing */ +struct xfs_scrub_metadata { +__u32 sm_type;/* What to check? */ +__u32 sm_flags;/* flags; see below. */ +__u64 sm_ino;/* inode number. */ +__u32 sm_gen;/* inode generation. */ +__u32 sm_agno;/* ag number. */ +__u64 sm_reserved[5 ];/* pad to 64 bytes */ +}; + +/* +* Metadata types and flags for scrub operation. +*/ + +/* Scrub subcommands. */ + +/* Number of scrub subcommands. */ +#define XFS_SCRUB_TYPE_NR 0 + +/* i: Repair this metadata. */ +#define XFS_SCRUB_IFLAG_REPAIR (1 << 0) + +/* o: Metadata object needs repair. */ +#define XFS_SCRUB_OFLAG_CORRUPT (1 << 1) + +/* +* o: Metadata object could be optimized. It's not corrupt, but +* we could improve on it somehow. +*/ +#define XFS_SCRUB_OFLAG_PREEN (1 << 2) + +/* o: Cross-referencing failed. */ +#define XFS_SCRUB_OFLAG_XFAIL (1 << 3) + +/* o: Metadata object disagrees with cross-referenced metadata. */ +#define XFS_SCRUB_OFLAG_XCORRUPT (1 << 4) + +/* o: Scan was not complete. */ +#define XFS_SCRUB_OFLAG_INCOMPLETE (1 << 5) + +/* o: Metadata object looked funny but isn't corrupt. */ +#define XFS_SCRUB_OFLAG_WARNING (1 << 6) + +#define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR) +#define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_PREEN | \ + XFS_SCRUB_OFLAG_XFAIL | \ + XFS_SCRUB_OFLAG_XCORRUPT | \ + XFS_SCRUB_OFLAG_INCOMPLETE | \ + XFS_SCRUB_OFLAG_WARNING) +#define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +/* * AG reserved block counters */ @@ -522,6 +574,7 @@ struct xfs_fsop_ag_resblks {#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)/* XFS_IOC_GETFSMAP ------ hoisted 59 */ +#define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)/* * ioctl commands that replace IRIX syssgi()'s fs/xfs/scrub/scrub.c new file +54
-0@@ -0,0 +1,54 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/trace.h" + +/* Dispatch metadata scrubbing. */ +int +xfs_scrub_metadata ( +struct xfs_inode *ip, +struct xfs_scrub_metadata *sm) +{ +return -EOPNOTSUPP ; +}fs/xfs/scrub/scrub.h new file +25
-0@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_SCRUB_H__ +#define __XFS_SCRUB_SCRUB_H__ + +/* Metadata scrubbers */ + +#endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.c new file +41
-0@@ -0,0 +1,41 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_da_format.h" +#include "xfs_defer.h" +#include "xfs_inode.h" +#include "xfs_btree.h" +#include "xfs_trans.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" + +/* +* We include this last to have the helpers above available for the trace +* event implementations. +*/ +#define CREATE_TRACE_POINTS +#include "scrub/trace.h" fs/xfs/scrub/trace.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xfs_scrub + +#if !defined(_TRACE_XFS_SCRUB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_XFS_SCRUB_TRACE_H + +#include <linux/tracepoint.h> + +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE scrub/trace +#include <trace/define_trace.h> fs/xfs/scrub/xfs_scrub.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_H__ +#define __XFS_SCRUB_H__ + +#ifndef CONFIG_XFS_ONLINE_SCRUB +# define xfs_scrub_metadata (ip, sm) (-ENOTTY) +#else +int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm); +#endif /* CONFIG_XFS_ONLINE_SCRUB */ + +#endif /* __XFS_SCRUB_H__ */ fs/xfs/xfs_ioctl.c +28
-0@@ -44,6 +44,7 @@#include "xfs_btree.h" #include <linux/fsmap.h> #include "xfs_fsmap.h" +#include "scrub/xfs_scrub.h" #include <linux/capability.h> #include <linux/cred.h> @@ -1702,6 +1703,30 @@ xfs_ioc_getfsmap(return 0 ; } +STATIC int +xfs_ioc_scrub_metadata ( +struct xfs_inode *ip, +void __user *arg) +{ +struct xfs_scrub_metadata scrub; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +if (copy_from_user (&scrub, arg,sizeof (scrub))) +return -EFAULT ; + + error =xfs_scrub_metadata (ip, &scrub); +if (error) +return error; + +if (copy_to_user (arg, &scrub,sizeof (scrub))) +return -EFAULT ; + +return 0 ; +} +int xfs_ioc_swapext (xfs_swapext_t *sxp)@@ -1906,6 +1931,9 @@ xfs_file_ioctl(case FS_IOC_GETFSMAP :return xfs_ioc_getfsmap (ip, arg); +case XFS_IOC_SCRUB_METADATA : +return xfs_ioc_scrub_metadata (ip, arg); +case XFS_IOC_FD_TO_HANDLE :case XFS_IOC_PATH_TO_HANDLE :case XFS_IOC_PATH_TO_FSHANDLE : {fs/xfs/xfs_ioctl32.c +1
-1@@ -557,6 +557,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP :case XFS_IOC_GET_AG_RESBLKS : +case XFS_IOC_SCRUB_METADATA :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ --Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 03/27] xfs: create an ioctl to scrub AG metadata
Quoted 30 lines · Darrick J. Wong
Quoted 29 lines · Brian Foster
Quoted 27 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create an ioctl that can be used to scrub internal filesystem metadata. The new ioctl takes the metadata type, an (optional) AG number, an (optional) inode number and generation, and a flags argument. This will be used by the upcoming XFS online scrub tool.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Kconfig | 17 ++++++++++++++ fs/xfs/Makefile | 11 +++++++++ fs/xfs/libxfs/xfs_fs.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 25 +++++++++++++++++++++ fs/xfs/scrub/trace.c | 41 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 33 ++++++++++++++++++++++++++++ fs/xfs/scrub/xfs_scrub.h | 29 +++++++++++++++++++++++++ fs/xfs/xfs_ioctl.c | 28 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 10 files changed, 292 insertions(+) create mode 100644 fs/xfs/scrub/scrub.c create mode 100644 fs/xfs/scrub/scrub.h create mode 100644 fs/xfs/scrub/trace.c create mode 100644 fs/xfs/scrub/trace.h create mode 100644 fs/xfs/scrub/xfs_scrub.h
Quoted 8 lines
Quoted 2 lines
The code looks sane, though I think I need to understand the error codes a bit better. Perhaps once I get further into the series..
Yes, the ioctl needs documentation, though I'm unclear on where's an appropriate place to put them. The ioctl is not intended for general consumption, so man-pages.git seems inappropriate. I was thinking either in
xfs_fs.hdirectly, or perhaps xfsprogs' man pages?
For now (while all of this is still experimental and until you get a better answer :P), it seems reasonable enough to me to add basic interface documentation to the kernel source. Then we at least have the content and can move it out into a manpage or something later, if needed.
Brian
Quoted 415 lines
(We don't seem to document the xfs ioctls afaict?)
--D
Quoted 399 lines
Brian
Quoted 396 lines
fs/xfs/Kconfig +17
-0@@ -71,6 +71,23 @@ config XFS_RT If unsure, say N. +config XFS_ONLINE_SCRUB + bool "XFS online metadata check support" + default n + depends on XFS_FS + help + If you say Y here you will be able to check metadata on a + mounted XFS filesystem. This feature is intended to reduce + filesystem downtime by supplementing xfs_repair. The key + advantage here is to look for problems proactively so that + they can be dealt with in a controlled manner. + + This feature is considered EXPERIMENTAL. Use with caution! + + See the xfs_scrub man page in section 8 for additional information. + + If unsure, say N. + config XFS_WARN bool "XFS Verbose Warnings" depends on XFS_FS && !XFS_DEBUGfs/xfs/Makefile +11
-0@@ -138,3 +138,14 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o + +# online scrub/repair +ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) + +# Tracepoints like to blow up, so build that before everything else + +xfs-y += $(addprefix scrub/, \ + trace.o \ + scrub.o \ + ) +endiffs/xfs/libxfs/xfs_fs.h +53
-0@@ -468,6 +468,58 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1/* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ +/* metadata scrubbing */ +struct xfs_scrub_metadata { +__u32 sm_type;/* What to check? */ +__u32 sm_flags;/* flags; see below. */ +__u64 sm_ino;/* inode number. */ +__u32 sm_gen;/* inode generation. */ +__u32 sm_agno;/* ag number. */ +__u64 sm_reserved[5 ];/* pad to 64 bytes */ +}; + +/* +* Metadata types and flags for scrub operation. +*/ + +/* Scrub subcommands. */ + +/* Number of scrub subcommands. */ +#define XFS_SCRUB_TYPE_NR 0 + +/* i: Repair this metadata. */ +#define XFS_SCRUB_IFLAG_REPAIR (1 << 0) + +/* o: Metadata object needs repair. */ +#define XFS_SCRUB_OFLAG_CORRUPT (1 << 1) + +/* +* o: Metadata object could be optimized. It's not corrupt, but +* we could improve on it somehow. +*/ +#define XFS_SCRUB_OFLAG_PREEN (1 << 2) + +/* o: Cross-referencing failed. */ +#define XFS_SCRUB_OFLAG_XFAIL (1 << 3) + +/* o: Metadata object disagrees with cross-referenced metadata. */ +#define XFS_SCRUB_OFLAG_XCORRUPT (1 << 4) + +/* o: Scan was not complete. */ +#define XFS_SCRUB_OFLAG_INCOMPLETE (1 << 5) + +/* o: Metadata object looked funny but isn't corrupt. */ +#define XFS_SCRUB_OFLAG_WARNING (1 << 6) + +#define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR) +#define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_PREEN | \ + XFS_SCRUB_OFLAG_XFAIL | \ + XFS_SCRUB_OFLAG_XCORRUPT | \ + XFS_SCRUB_OFLAG_INCOMPLETE | \ + XFS_SCRUB_OFLAG_WARNING) +#define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +/* * AG reserved block counters */ @@ -522,6 +574,7 @@ struct xfs_fsop_ag_resblks {#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)/* XFS_IOC_GETFSMAP ------ hoisted 59 */ +#define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)/* * ioctl commands that replace IRIX syssgi()'s fs/xfs/scrub/scrub.c new file +54
-0@@ -0,0 +1,54 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/trace.h" + +/* Dispatch metadata scrubbing. */ +int +xfs_scrub_metadata ( +struct xfs_inode *ip, +struct xfs_scrub_metadata *sm) +{ +return -EOPNOTSUPP ; +}fs/xfs/scrub/scrub.h new file +25
-0@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_SCRUB_H__ +#define __XFS_SCRUB_SCRUB_H__ + +/* Metadata scrubbers */ + +#endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.c new file +41
-0@@ -0,0 +1,41 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_da_format.h" +#include "xfs_defer.h" +#include "xfs_inode.h" +#include "xfs_btree.h" +#include "xfs_trans.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" + +/* +* We include this last to have the helpers above available for the trace +* event implementations. +*/ +#define CREATE_TRACE_POINTS +#include "scrub/trace.h" fs/xfs/scrub/trace.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xfs_scrub + +#if !defined(_TRACE_XFS_SCRUB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_XFS_SCRUB_TRACE_H + +#include <linux/tracepoint.h> + +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE scrub/trace +#include <trace/define_trace.h> fs/xfs/scrub/xfs_scrub.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_H__ +#define __XFS_SCRUB_H__ + +#ifndef CONFIG_XFS_ONLINE_SCRUB +# define xfs_scrub_metadata (ip, sm) (-ENOTTY) +#else +int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm); +#endif /* CONFIG_XFS_ONLINE_SCRUB */ + +#endif /* __XFS_SCRUB_H__ */ fs/xfs/xfs_ioctl.c +28
-0@@ -44,6 +44,7 @@#include "xfs_btree.h" #include <linux/fsmap.h> #include "xfs_fsmap.h" +#include "scrub/xfs_scrub.h" #include <linux/capability.h> #include <linux/cred.h> @@ -1702,6 +1703,30 @@ xfs_ioc_getfsmap(return 0 ; } +STATIC int +xfs_ioc_scrub_metadata ( +struct xfs_inode *ip, +void __user *arg) +{ +struct xfs_scrub_metadata scrub; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +if (copy_from_user (&scrub, arg,sizeof (scrub))) +return -EFAULT ; + + error =xfs_scrub_metadata (ip, &scrub); +if (error) +return error; + +if (copy_to_user (arg, &scrub,sizeof (scrub))) +return -EFAULT ; + +return 0 ; +} +int xfs_ioc_swapext (xfs_swapext_t *sxp)@@ -1906,6 +1931,9 @@ xfs_file_ioctl(case FS_IOC_GETFSMAP :return xfs_ioc_getfsmap (ip, arg); +case XFS_IOC_SCRUB_METADATA : +return xfs_ioc_scrub_metadata (ip, arg); +case XFS_IOC_FD_TO_HANDLE :case XFS_IOC_PATH_TO_HANDLE :case XFS_IOC_PATH_TO_FSHANDLE : {fs/xfs/xfs_ioctl32.c +1
-0@@ -557,6 +557,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP :case XFS_IOC_GET_AG_RESBLKS : +case XFS_IOC_SCRUB_METADATA :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ Quoted 8 lines
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 03/27] xfs: create an ioctl to scrub AG metadata
Quoted 40 lines · Brian Foster
Quoted 30 lines · Darrick J. Wong
Quoted 29 lines · Brian Foster
Quoted 27 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create an ioctl that can be used to scrub internal filesystem metadata. The new ioctl takes the metadata type, an (optional) AG number, an (optional) inode number and generation, and a flags argument. This will be used by the upcoming XFS online scrub tool.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Kconfig | 17 ++++++++++++++ fs/xfs/Makefile | 11 +++++++++ fs/xfs/libxfs/xfs_fs.h | 53 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 25 +++++++++++++++++++++ fs/xfs/scrub/trace.c | 41 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 33 ++++++++++++++++++++++++++++ fs/xfs/scrub/xfs_scrub.h | 29 +++++++++++++++++++++++++ fs/xfs/xfs_ioctl.c | 28 ++++++++++++++++++++++++ fs/xfs/xfs_ioctl32.c | 1 + 10 files changed, 292 insertions(+) create mode 100644 fs/xfs/scrub/scrub.c create mode 100644 fs/xfs/scrub/scrub.h create mode 100644 fs/xfs/scrub/trace.c create mode 100644 fs/xfs/scrub/trace.h create mode 100644 fs/xfs/scrub/xfs_scrub.hQuoted 8 lines
Quoted 2 lines
The code looks sane, though I think I need to understand the error codes a bit better. Perhaps once I get further into the series..
Yes, the ioctl needs documentation, though I'm unclear on where's an appropriate place to put them. The ioctl is not intended for general consumption, so man-pages.git seems inappropriate. I was thinking either in
xfs_fs.hdirectly, or perhaps xfsprogs' man pages?
Quoted 5 lines
For now (while all of this is still experimental and until you get a better answer :P), it seems reasonable enough to me to add basic interface documentation to the kernel source. Then we at least have the content and can move it out into a manpage or something later, if needed.
It's more or less documented in the source... but in a somewhat piecemeal fashion as we add functionality. I've drafted a manpage to describe all of what the ioctl wants to do, so I'll tack that on the end of this series (and cc you and Dave).
--D
Quoted 422 lines
Brian
Quoted 411 lines
(We don't seem to document the xfs ioctls afaict?)
--D
Quoted 399 lines
Brian
Quoted 396 lines
fs/xfs/Kconfig +17
-0@@ -71,6 +71,23 @@ config XFS_RT If unsure, say N. +config XFS_ONLINE_SCRUB + bool "XFS online metadata check support" + default n + depends on XFS_FS + help + If you say Y here you will be able to check metadata on a + mounted XFS filesystem. This feature is intended to reduce + filesystem downtime by supplementing xfs_repair. The key + advantage here is to look for problems proactively so that + they can be dealt with in a controlled manner. + + This feature is considered EXPERIMENTAL. Use with caution! + + See the xfs_scrub man page in section 8 for additional information. + + If unsure, say N. + config XFS_WARN bool "XFS Verbose Warnings" depends on XFS_FS && !XFS_DEBUGfs/xfs/Makefile +11
-0@@ -138,3 +138,14 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o + +# online scrub/repair +ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) + +# Tracepoints like to blow up, so build that before everything else + +xfs-y += $(addprefix scrub/, \ + trace.o \ + scrub.o \ + ) +endiffs/xfs/libxfs/xfs_fs.h +53
-0@@ -468,6 +468,58 @@ typedef struct xfs_swapext#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1/* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2/* don't flush log nor data */ +/* metadata scrubbing */ +struct xfs_scrub_metadata { +__u32 sm_type;/* What to check? */ +__u32 sm_flags;/* flags; see below. */ +__u64 sm_ino;/* inode number. */ +__u32 sm_gen;/* inode generation. */ +__u32 sm_agno;/* ag number. */ +__u64 sm_reserved[5 ];/* pad to 64 bytes */ +}; + +/* +* Metadata types and flags for scrub operation. +*/ + +/* Scrub subcommands. */ + +/* Number of scrub subcommands. */ +#define XFS_SCRUB_TYPE_NR 0 + +/* i: Repair this metadata. */ +#define XFS_SCRUB_IFLAG_REPAIR (1 << 0) + +/* o: Metadata object needs repair. */ +#define XFS_SCRUB_OFLAG_CORRUPT (1 << 1) + +/* +* o: Metadata object could be optimized. It's not corrupt, but +* we could improve on it somehow. +*/ +#define XFS_SCRUB_OFLAG_PREEN (1 << 2) + +/* o: Cross-referencing failed. */ +#define XFS_SCRUB_OFLAG_XFAIL (1 << 3) + +/* o: Metadata object disagrees with cross-referenced metadata. */ +#define XFS_SCRUB_OFLAG_XCORRUPT (1 << 4) + +/* o: Scan was not complete. */ +#define XFS_SCRUB_OFLAG_INCOMPLETE (1 << 5) + +/* o: Metadata object looked funny but isn't corrupt. */ +#define XFS_SCRUB_OFLAG_WARNING (1 << 6) + +#define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR) +#define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_PREEN | \ + XFS_SCRUB_OFLAG_XFAIL | \ + XFS_SCRUB_OFLAG_XCORRUPT | \ + XFS_SCRUB_OFLAG_INCOMPLETE | \ + XFS_SCRUB_OFLAG_WARNING) +#define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +/* * AG reserved block counters */ @@ -522,6 +574,7 @@ struct xfs_fsop_ag_resblks {#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)/* XFS_IOC_GETFSMAP ------ hoisted 59 */ +#define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)/* * ioctl commands that replace IRIX syssgi()'s fs/xfs/scrub/scrub.c new file +54
-0@@ -0,0 +1,54 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/trace.h" + +/* Dispatch metadata scrubbing. */ +int +xfs_scrub_metadata ( +struct xfs_inode *ip, +struct xfs_scrub_metadata *sm) +{ +return -EOPNOTSUPP ; +}fs/xfs/scrub/scrub.h new file +25
-0@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_SCRUB_H__ +#define __XFS_SCRUB_SCRUB_H__ + +/* Metadata scrubbers */ + +#endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.c new file +41
-0@@ -0,0 +1,41 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_da_format.h" +#include "xfs_defer.h" +#include "xfs_inode.h" +#include "xfs_btree.h" +#include "xfs_trans.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" + +/* +* We include this last to have the helpers above available for the trace +* event implementations. +*/ +#define CREATE_TRACE_POINTS +#include "scrub/trace.h" fs/xfs/scrub/trace.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xfs_scrub + +#if !defined(_TRACE_XFS_SCRUB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_XFS_SCRUB_TRACE_H + +#include <linux/tracepoint.h> + +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE scrub/trace +#include <trace/define_trace.h> fs/xfs/scrub/xfs_scrub.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __XFS_SCRUB_H__ +#define __XFS_SCRUB_H__ + +#ifndef CONFIG_XFS_ONLINE_SCRUB +# define xfs_scrub_metadata (ip, sm) (-ENOTTY) +#else +int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm); +#endif /* CONFIG_XFS_ONLINE_SCRUB */ + +#endif /* __XFS_SCRUB_H__ */ fs/xfs/xfs_ioctl.c +28
-0@@ -44,6 +44,7 @@#include "xfs_btree.h" #include <linux/fsmap.h> #include "xfs_fsmap.h" +#include "scrub/xfs_scrub.h" #include <linux/capability.h> #include <linux/cred.h> @@ -1702,6 +1703,30 @@ xfs_ioc_getfsmap(return 0 ; } +STATIC int +xfs_ioc_scrub_metadata ( +struct xfs_inode *ip, +void __user *arg) +{ +struct xfs_scrub_metadata scrub; +int error; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +if (copy_from_user (&scrub, arg,sizeof (scrub))) +return -EFAULT ; + + error =xfs_scrub_metadata (ip, &scrub); +if (error) +return error; + +if (copy_to_user (arg, &scrub,sizeof (scrub))) +return -EFAULT ; + +return 0 ; +} +int xfs_ioc_swapext (xfs_swapext_t *sxp)@@ -1906,6 +1931,9 @@ xfs_file_ioctl(case FS_IOC_GETFSMAP :return xfs_ioc_getfsmap (ip, arg); +case XFS_IOC_SCRUB_METADATA : +return xfs_ioc_scrub_metadata (ip, arg); +case XFS_IOC_FD_TO_HANDLE :case XFS_IOC_PATH_TO_HANDLE :case XFS_IOC_PATH_TO_FSHANDLE : {fs/xfs/xfs_ioctl32.c +1
-0@@ -557,6 +557,7 @@ xfs_file_compat_ioctl(case XFS_IOC_ERROR_CLEARALL :case FS_IOC_GETFSMAP :case XFS_IOC_GET_AG_RESBLKS : +case XFS_IOC_SCRUB_METADATA :return xfs_file_ioctl (filp, cmd, p);#ifndef BROKEN_X86_ALIGNMENT /* These are handled fine if no alignment issues */ Quoted 8 lines
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.htmlQuoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 4/27 xfs: dispatch metadata scrub subcommands
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create structures needed to hold scrubbing context and dispatch incoming commands to the individual scrubbers.
--- fs/xfs/scrub/scrub.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 19 ++++++ fs/xfs/scrub/trace.h | 43 +++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-)
fs/xfs/scrub/scrub.c +171 -1
@@ -44,11 +44,181 @@#include "scrub/scrub.h" #include "scrub/trace.h" +/* +* Online Scrub and Repair +* +* Traditionally, XFS (the kernel driver) did not know how to check or +* repair on-disk data structures. That task was left to the xfs_check +* and xfs_repair tools, both of which require taking the filesystem +* offline for a thorough but time consuming examination. Online +* scrub & repair, on the other hand, enables us to check the metadata +* for obvious errors while carefully stepping around the filesystem's +* ongoing operations, locking rules, etc. +* +* Given that most XFS metadata consist of records stored in a btree, +* most of the checking functions iterate the btree blocks themselves +* looking for irregularities. When a record block is encountered, each +* record can be checked for obviously bad values. Record values can +* also be cross-referenced against other btrees to look for potential +* misunderstandings between pieces of metadata. +* +* It is expected that the checkers responsible for per-AG metadata +* structures will lock the AG headers (AGI, AGF, AGFL), iterate the +* metadata structure, and perform any relevant cross-referencing before +* unlocking the AG and returning the results to userspace. These +* scrubbers must not keep an AG locked for too long to avoid tying up +* the block and inode allocators. +* +* Block maps and b-trees rooted in an inode present a special challenge +* because they can involve extents from any AG. The general scrubber +* structure of lock -> check -> xref -> unlock still holds, but AG +* locking order rules /must/ be obeyed to avoid deadlocks. The +* ordering rule, of course, is that we must lock in increasing AG +* order. Helper functions are provided to track which AG headers we've +* already locked. If we detect an imminent locking order violation, we +* can signal a potential deadlock, in which case the scrubber can jump +* out to the top level, lock all the AGs in order, and retry the scrub. +* +* For file data (directories, extended attributes, symlinks) scrub, we +* can simply lock the inode and walk the data. For btree data +* (directories and attributes) we follow the same btree-scrubbing +* strategy outlined previously to check the records. +* +* We use a bit of trickery with transactions to avoid buffer deadlocks +* if there is a cycle in the metadata. The basic problem is that +* travelling down a btree involves locking the current buffer at each +* tree level. If a pointer should somehow point back to a buffer that +* we've already examined, we will deadlock due to the second buffer +* locking attempt. Note however that grabbing a buffer in transaction +* context links the locked buffer to the transaction. If we try to +* re-grab the buffer in the context of the same transaction, we avoid +* the second lock attempt and continue. Between the verifier and the +* scrubber, something will notice that something is amiss and report +* the corruption. Therefore, each scrubber will allocate an empty +* transaction, attach buffers to it, and cancel the transaction at the +* end of the scrub run. Cancelling a non-dirty transaction simply +* unlocks the buffers. +* +* There are four pieces of data that scrub can communicate to +* userspace. The first is the error code (errno), which can be used to +* communicate operational errors in performing the scrub. There are +* also three flags that can be set in the scrub context. If the data +* structure itself is corrupt, the CORRUPT flag will be set. If +* the metadata is correct but otherwise suboptimal, the PREEN flag +* will be set. +*/ + +/* Scrub setup and teardown */ + +/* Free all the resources and finish the transactions. */ +STATIC int +xfs_scrub_teardown ( +struct xfs_scrub_context *sc, +int error) +{ +if (sc->tp) { +xfs_trans_cancel (sc->tp); + sc->tp =NULL ; + } +return error; +} + +/* Scrubbing dispatch. */ + +static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { +}; +/* Dispatch metadata scrubbing. */ int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm) { -return -EOPNOTSUPP ; +struct xfs_scrub_context sc; +struct xfs_mount *mp = ip->i_mount; +const struct xfs_scrub_meta_ops *ops; +bool try_harder = false; +int error =0 ; + +trace_xfs_scrub_start (ip, sm, error); + +/* Forbidden if we are shut down or mounted norecovery. */ + error = -ESHUTDOWN ; +if (XFS_FORCED_SHUTDOWN (mp)) + goto out; + error = -ENOTRECOVERABLE ; +if (mp->m_flags &XFS_MOUNT_NORECOVERY ) + goto out; + +/* Check our inputs. */ + error = -EINVAL ; + sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT ; +if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN ) + goto out; +if (memchr_inv (sm->sm_reserved,0 ,sizeof (sm->sm_reserved))) + goto out; + +/* Do we know about this type of metadata? */ + error = -ENOENT ; +if (sm->sm_type >=XFS_SCRUB_TYPE_NR ) + goto out; + ops = &meta_scrub_ops[sm->sm_type]; +if (ops->scrub ==NULL ) + goto out; + +/* Does this fs even support this type of metadata? */ +if (ops->has && !ops->has (&mp->m_sb)) + goto out; + +/* We don't know how to repair anything yet. */ + error = -EOPNOTSUPP ; +if (sm->sm_flags &XFS_SCRUB_IFLAG_REPAIR ) + goto out; + +/* This isn't a stable feature. Use with care. */ + { +static bool warned; + +if (!warned) +xfs_alert (mp, +"EXPERIMENTAL online scrub feature in use. Use at your own risk!" ); + warned = true; + } + +retry_op: +/* Set up for the operation. */ +memset (&sc,0 ,sizeof (sc)); + sc.mp = ip->i_mount; + sc.sm = sm; + sc.ops = ops; + sc.try_harder = try_harder; + error = sc.ops->setup (&sc, ip); +if (error) + goto out_teardown; + +/* Scrub for errors. */ + error = sc.ops->scrub (&sc); +if (!try_harder && error == -EDEADLOCK ) { +/* +* Scrubbers return -EDEADLOCK to mean 'try harder'. +* Tear down everything we hold, then set up again with +* preparation for worst-case scenarios. +*/ + error =xfs_scrub_teardown (&sc,0 ); +if (error) + goto out; + try_harder = true; + goto retry_op; + }else if (error) + goto out_teardown; + +if (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT | +XFS_SCRUB_OFLAG_XCORRUPT )) +xfs_alert_ratelimited (mp,"Corruption detected during scrub." ); + +out_teardown: + error =xfs_scrub_teardown (&sc, error); +out: +trace_xfs_scrub_done (ip, sm, error); +return error; }
fs/xfs/scrub/scrub.h +19 -0
@@ -20,6 +20,25 @@#ifndef __XFS_SCRUB_SCRUB_H__#define __XFS_SCRUB_SCRUB_H__ +struct xfs_scrub_context ; + +struct xfs_scrub_meta_ops { +int (*setup)(struct xfs_scrub_context *, +struct xfs_inode *); +int (*scrub)(struct xfs_scrub_context *); +bool (*has)(struct xfs_sb *); +}; + +struct xfs_scrub_context { +/* General scrub state. */ +struct xfs_mount *mp; +struct xfs_scrub_metadata *sm; +const struct xfs_scrub_meta_ops *ops; +struct xfs_trans *tp; +struct xfs_inode *ip; +bool try_harder; +}; +/* Metadata scrubbers */ #endif /* __XFS_SCRUB_SCRUB_H__ */
fs/xfs/scrub/trace.h +43 -0
49 lines not on this page · raw message
Re: [PATCH 04/27] xfs: dispatch metadata scrub subcommands
Quoted 73 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create structures needed to hold scrubbing context and dispatch incoming commands to the individual scrubbers.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/scrub.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 19 ++++++ fs/xfs/scrub/trace.h | 43 +++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-)fs/xfs/scrub/scrub.c +52
-0@@ -44,11 +44,181 @@#include "scrub/scrub.h" #include "scrub/trace.h" +/* +* Online Scrub and Repair +* +* Traditionally, XFS (the kernel driver) did not know how to check or +* repair on-disk data structures. That task was left to the xfs_check +* and xfs_repair tools, both of which require taking the filesystem +* offline for a thorough but time consuming examination. Online +* scrub & repair, on the other hand, enables us to check the metadata +* for obvious errors while carefully stepping around the filesystem's +* ongoing operations, locking rules, etc. +* +* Given that most XFS metadata consist of records stored in a btree, +* most of the checking functions iterate the btree blocks themselves +* looking for irregularities. When a record block is encountered, each +* record can be checked for obviously bad values. Record values can +* also be cross-referenced against other btrees to look for potential +* misunderstandings between pieces of metadata. +* +* It is expected that the checkers responsible for per-AG metadata +* structures will lock the AG headers (AGI, AGF, AGFL), iterate the +* metadata structure, and perform any relevant cross-referencing before +* unlocking the AG and returning the results to userspace. These +* scrubbers must not keep an AG locked for too long to avoid tying up +* the block and inode allocators. +* +* Block maps and b-trees rooted in an inode present a special challenge +* because they can involve extents from any AG. The general scrubber +* structure of lock -> check -> xref -> unlock still holds, but AG +* locking order rules /must/ be obeyed to avoid deadlocks. The +* ordering rule, of course, is that we must lock in increasing AG +* order. Helper functions are provided to track which AG headers we've +* already locked. If we detect an imminent locking order violation, we +* can signal a potential deadlock, in which case the scrubber can jump +* out to the top level, lock all the AGs in order, and retry the scrub. +* +* For file data (directories, extended attributes, symlinks) scrub, we +* can simply lock the inode and walk the data. For btree data +* (directories and attributes) we follow the same btree-scrubbing +* strategy outlined previously to check the records. +* +* We use a bit of trickery with transactions to avoid buffer deadlocks +* if there is a cycle in the metadata. The basic problem is that +* travelling down a btree involves locking the current buffer at each +* tree level. If a pointer should somehow point back to a buffer that +* we've already examined, we will deadlock due to the second buffer +* locking attempt. Note however that grabbing a buffer in transaction +* context links the locked buffer to the transaction. If we try to +* re-grab the buffer in the context of the same transaction, we avoid +* the second lock attempt and continue. Between the verifier and the +* scrubber, something will notice that something is amiss and report +* the corruption. Therefore, each scrubber will allocate an empty +* transaction, attach buffers to it, and cancel the transaction at the
fs/xfs/scrub/scrub.c line 108
Quoted 10 lines
fs/xfs/scrub/scrub.c +10
-0+* end of the scrub run. Cancelling a non-dirty transaction simply +* unlocks the buffers. +* +* There are four pieces of data that scrub can communicate to +* userspace. The first is the error code (errno), which can be used to +* communicate operational errors in performing the scrub. There are +* also three flags that can be set in the scrub context. If the data +* structure itself is corrupt, the CORRUPT flag will be set. If +* the metadata is correct but otherwise suboptimal, the PREEN flag +* will be set.
Did you mean to describe other flags here?
fs/xfs/scrub/scrub.c line 117
Quoted 9 lines
fs/xfs/scrub/scrub.c +9
-0+*/ + +/* Scrub setup and teardown */ + +/* Free all the resources and finish the transactions. */ +STATIC int +xfs_scrub_teardown ( +struct xfs_scrub_context *sc, +int error)
What's the purpose of passing error just to return it?
Quoted 113 lines
fs/xfs/scrub/scrub.c +100
-1+{ +if (sc->tp) { +xfs_trans_cancel (sc->tp); + sc->tp =NULL ; + } +return error; +} + +/* Scrubbing dispatch. */ + +static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { +}; +/* Dispatch metadata scrubbing. */ int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm) { -return -EOPNOTSUPP ; +struct xfs_scrub_context sc; +struct xfs_mount *mp = ip->i_mount; +const struct xfs_scrub_meta_ops *ops; +bool try_harder = false; +int error =0 ; + +trace_xfs_scrub_start (ip, sm, error); + +/* Forbidden if we are shut down or mounted norecovery. */ + error = -ESHUTDOWN ; +if (XFS_FORCED_SHUTDOWN (mp)) + goto out; + error = -ENOTRECOVERABLE ; +if (mp->m_flags &XFS_MOUNT_NORECOVERY ) + goto out; + +/* Check our inputs. */ + error = -EINVAL ; + sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT ; +if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN ) + goto out; +if (memchr_inv (sm->sm_reserved,0 ,sizeof (sm->sm_reserved))) + goto out; + +/* Do we know about this type of metadata? */ + error = -ENOENT ; +if (sm->sm_type >=XFS_SCRUB_TYPE_NR ) + goto out; + ops = &meta_scrub_ops[sm->sm_type]; +if (ops->scrub ==NULL ) + goto out; + +/* Does this fs even support this type of metadata? */ +if (ops->has && !ops->has (&mp->m_sb)) + goto out; + +/* We don't know how to repair anything yet. */ + error = -EOPNOTSUPP ; +if (sm->sm_flags &XFS_SCRUB_IFLAG_REPAIR ) + goto out; + +/* This isn't a stable feature. Use with care. */ + { +static bool warned; + +if (!warned) +xfs_alert (mp, +"EXPERIMENTAL online scrub feature in use. Use at your own risk!" ); + warned = true; + } + +retry_op: +/* Set up for the operation. */ +memset (&sc,0 ,sizeof (sc)); + sc.mp = ip->i_mount; + sc.sm = sm; + sc.ops = ops; + sc.try_harder = try_harder; + error = sc.ops->setup (&sc, ip); +if (error) + goto out_teardown; + +/* Scrub for errors. */ + error = sc.ops->scrub (&sc); +if (!try_harder && error == -EDEADLOCK ) { +/* +* Scrubbers return -EDEADLOCK to mean 'try harder'. +* Tear down everything we hold, then set up again with +* preparation for worst-case scenarios. +*/ + error =xfs_scrub_teardown (&sc,0 ); +if (error) + goto out; + try_harder = true; + goto retry_op; + }else if (error) + goto out_teardown; + +if (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT | +XFS_SCRUB_OFLAG_XCORRUPT )) +xfs_alert_ratelimited (mp,"Corruption detected during scrub." ); + +out_teardown: + error =xfs_scrub_teardown (&sc, error); +out: +trace_xfs_scrub_done (ip, sm, error); +return error; }fs/xfs/scrub/scrub.h +0
-0
fs/xfs/scrub/scrub.h line 29
Quoted 10 lines
fs/xfs/scrub/scrub.h +7
-0@@ -20,6 +20,25 @@ #ifndef __XFS_SCRUB_SCRUB_H__ #define __XFS_SCRUB_SCRUB_H__ +struct xfs_scrub_context; + +struct xfs_scrub_meta_ops { + int (*setup)(struct xfs_scrub_context *, + struct xfs_inode *); + int (*scrub)(struct xfs_scrub_context *); + bool (*has)(struct xfs_sb *);
I assume 'has' is to identify whether a particular mount supports a particular feature. I suppose a better name would be nice here, or perhaps just a comment to outline the purpose of each callout.
Brian
Quoted 74 lines
fs/xfs/scrub/scrub.h +12
-0+}; + +struct xfs_scrub_context { +/* General scrub state. */ +struct xfs_mount *mp; +struct xfs_scrub_metadata *sm; +const struct xfs_scrub_meta_ops *ops; +struct xfs_trans *tp; +struct xfs_inode *ip; +bool try_harder; +}; +/* Metadata scrubbers */ #endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.h +43
-1@@ -25,6 +25,49 @@#include <linux/tracepoint.h> +DECLARE_EVENT_CLASS (xfs_scrub_class, + TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm, + int error), +TP_ARGS (ip, sm, error), +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned int, type) + __field(xfs_agnumber_t, agno) + __field(xfs_ino_t, inum) + __field(unsigned int, gen) + __field(unsigned int, flags) +__field (int, error) + ), +TP_fast_assign ( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->type = sm->sm_type; + __entry->agno = sm->sm_agno; + __entry->inum = sm->sm_ino; + __entry->gen = sm->sm_gen; + __entry->flags = sm->sm_flags; + __entry->error = error; + ), +TP_printk ("dev %d:%d ino %llu type %u agno %u inum %llu gen %u flags 0x%x error %d" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->ino, + __entry->type, + __entry->agno, + __entry->inum, + __entry->gen, + __entry->flags, + __entry->error) +) +#define DEFINE_SCRUB_EVENT (name) \ +DEFINE_EVENT(xfs_scrub_class, name, \ + TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm, \ + int error), \ + TP_ARGS(ip, sm, error)) + +DEFINE_SCRUB_EVENT (xfs_scrub_start); +DEFINE_SCRUB_EVENT (xfs_scrub_done); +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ #undef TRACE_INCLUDE_PATH --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/27] xfs: dispatch metadata scrub subcommands
Quoted 78 lines · Brian Foster
Quoted 77 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create structures needed to hold scrubbing context and dispatch incoming commands to the individual scrubbers.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/scrub.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 19 ++++++ fs/xfs/scrub/trace.h | 43 +++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-)fs/xfs/scrub/scrub.c +56
-0@@ -44,11 +44,181 @@#include "scrub/scrub.h" #include "scrub/trace.h" +/* +* Online Scrub and Repair +* +* Traditionally, XFS (the kernel driver) did not know how to check or +* repair on-disk data structures. That task was left to the xfs_check +* and xfs_repair tools, both of which require taking the filesystem +* offline for a thorough but time consuming examination. Online +* scrub & repair, on the other hand, enables us to check the metadata +* for obvious errors while carefully stepping around the filesystem's +* ongoing operations, locking rules, etc. +* +* Given that most XFS metadata consist of records stored in a btree, +* most of the checking functions iterate the btree blocks themselves +* looking for irregularities. When a record block is encountered, each +* record can be checked for obviously bad values. Record values can +* also be cross-referenced against other btrees to look for potential +* misunderstandings between pieces of metadata. +* +* It is expected that the checkers responsible for per-AG metadata +* structures will lock the AG headers (AGI, AGF, AGFL), iterate the +* metadata structure, and perform any relevant cross-referencing before +* unlocking the AG and returning the results to userspace. These +* scrubbers must not keep an AG locked for too long to avoid tying up +* the block and inode allocators. +* +* Block maps and b-trees rooted in an inode present a special challenge +* because they can involve extents from any AG. The general scrubber +* structure of lock -> check -> xref -> unlock still holds, but AG +* locking order rules /must/ be obeyed to avoid deadlocks. The +* ordering rule, of course, is that we must lock in increasing AG +* order. Helper functions are provided to track which AG headers we've +* already locked. If we detect an imminent locking order violation, we +* can signal a potential deadlock, in which case the scrubber can jump +* out to the top level, lock all the AGs in order, and retry the scrub. +* +* For file data (directories, extended attributes, symlinks) scrub, we +* can simply lock the inode and walk the data. For btree data +* (directories and attributes) we follow the same btree-scrubbing +* strategy outlined previously to check the records. +* +* We use a bit of trickery with transactions to avoid buffer deadlocks +* if there is a cycle in the metadata. The basic problem is that +* travelling down a btree involves locking the current buffer at each +* tree level. If a pointer should somehow point back to a buffer that +* we've already examined, we will deadlock due to the second buffer +* locking attempt. Note however that grabbing a buffer in transaction +* context links the locked buffer to the transaction. If we try to +* re-grab the buffer in the context of the same transaction, we avoid +* the second lock attempt and continue. Between the verifier and the +* scrubber, something will notice that something is amiss and report +* the corruption. Therefore, each scrubber will allocate an empty +* transaction, attach buffers to it, and cancel the transaction at the +* end of the scrub run. Cancelling a non-dirty transaction simply +* unlocks the buffers. +* +* There are four pieces of data that scrub can communicate to
Quoted 8 lines
fs/xfs/scrub/scrub.c line 108
Quoted 6 lines
fs/xfs/scrub/scrub.c +6
-0+* userspace. The first is the error code (errno), which can be used to +* communicate operational errors in performing the scrub. There are +* also three flags that can be set in the scrub context. If the data +* structure itself is corrupt, the CORRUPT flag will be set. If +* the metadata is correct but otherwise suboptimal, the PREEN flag +* will be set. Did you mean to describe other flags here?
Somewhere; the other flags get added in whichever patch(es) start using them.
Quoted 11 lines
fs/xfs/scrub/scrub.c line 117
Quoted 9 lines
fs/xfs/scrub/scrub.c +9
-0+*/ + +/* Scrub setup and teardown */ + +/* Free all the resources and finish the transactions. */ +STATIC int +xfs_scrub_teardown ( +struct xfs_scrub_context *sc, +int error)What's the purpose of passing error just to return it?
Eventually repair needs it to decide if it's cancelling the transaction or commiting a repair. I suppose I could remove it here and add it back later.
Quoted 116 lines
Quoted 116 lines
fs/xfs/scrub/scrub.c +100
-1+{ +if (sc->tp) { +xfs_trans_cancel (sc->tp); + sc->tp =NULL ; + } +return error; +} + +/* Scrubbing dispatch. */ + +static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { +}; +/* Dispatch metadata scrubbing. */ int xfs_scrub_metadata (struct xfs_inode *ip,struct xfs_scrub_metadata *sm) { -return -EOPNOTSUPP ; +struct xfs_scrub_context sc; +struct xfs_mount *mp = ip->i_mount; +const struct xfs_scrub_meta_ops *ops; +bool try_harder = false; +int error =0 ; + +trace_xfs_scrub_start (ip, sm, error); + +/* Forbidden if we are shut down or mounted norecovery. */ + error = -ESHUTDOWN ; +if (XFS_FORCED_SHUTDOWN (mp)) + goto out; + error = -ENOTRECOVERABLE ; +if (mp->m_flags &XFS_MOUNT_NORECOVERY ) + goto out; + +/* Check our inputs. */ + error = -EINVAL ; + sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT ; +if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN ) + goto out; +if (memchr_inv (sm->sm_reserved,0 ,sizeof (sm->sm_reserved))) + goto out; + +/* Do we know about this type of metadata? */ + error = -ENOENT ; +if (sm->sm_type >=XFS_SCRUB_TYPE_NR ) + goto out; + ops = &meta_scrub_ops[sm->sm_type]; +if (ops->scrub ==NULL ) + goto out; + +/* Does this fs even support this type of metadata? */ +if (ops->has && !ops->has (&mp->m_sb)) + goto out; + +/* We don't know how to repair anything yet. */ + error = -EOPNOTSUPP ; +if (sm->sm_flags &XFS_SCRUB_IFLAG_REPAIR ) + goto out; + +/* This isn't a stable feature. Use with care. */ + { +static bool warned; + +if (!warned) +xfs_alert (mp, +"EXPERIMENTAL online scrub feature in use. Use at your own risk!" ); + warned = true; + } + +retry_op: +/* Set up for the operation. */ +memset (&sc,0 ,sizeof (sc)); + sc.mp = ip->i_mount; + sc.sm = sm; + sc.ops = ops; + sc.try_harder = try_harder; + error = sc.ops->setup (&sc, ip); +if (error) + goto out_teardown; + +/* Scrub for errors. */ + error = sc.ops->scrub (&sc); +if (!try_harder && error == -EDEADLOCK ) { +/* +* Scrubbers return -EDEADLOCK to mean 'try harder'. +* Tear down everything we hold, then set up again with +* preparation for worst-case scenarios. +*/ + error =xfs_scrub_teardown (&sc,0 ); +if (error) + goto out; + try_harder = true; + goto retry_op; + }else if (error) + goto out_teardown; + +if (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT | +XFS_SCRUB_OFLAG_XCORRUPT )) +xfs_alert_ratelimited (mp,"Corruption detected during scrub." ); + +out_teardown: + error =xfs_scrub_teardown (&sc, error); +out: +trace_xfs_scrub_done (ip, sm, error); +return error; }fs/xfs/scrub/scrub.h +0
-0@@ -20,6 +20,25 @@#ifndef __XFS_SCRUB_SCRUB_H__#define __XFS_SCRUB_SCRUB_H__
Quoted 11 lines
fs/xfs/scrub/scrub.h line 29
Quoted 7 lines
fs/xfs/scrub/scrub.h +7
-0+struct xfs_scrub_context ; + +struct xfs_scrub_meta_ops { +int (*setup)(struct xfs_scrub_context *, +struct xfs_inode *); +int (*scrub)(struct xfs_scrub_context *); +bool (*has)(struct xfs_sb *);I assume 'has' is to identify whether a particular mount supports a particular feature. I suppose a better name would be nice here, or perhaps just a comment to outline the purpose of each callout.
I'll add some comments.
--D
Quoted 81 lines
Brian
Quoted 71 lines
fs/xfs/scrub/scrub.h +12
-0+}; + +struct xfs_scrub_context { +/* General scrub state. */ +struct xfs_mount *mp; +struct xfs_scrub_metadata *sm; +const struct xfs_scrub_meta_ops *ops; +struct xfs_trans *tp; +struct xfs_inode *ip; +bool try_harder; +}; +/* Metadata scrubbers */ #endif /* __XFS_SCRUB_SCRUB_H__ */ fs/xfs/scrub/trace.h +43
-1@@ -25,6 +25,49 @@#include <linux/tracepoint.h> +DECLARE_EVENT_CLASS (xfs_scrub_class, + TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm, + int error), +TP_ARGS (ip, sm, error), +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned int, type) + __field(xfs_agnumber_t, agno) + __field(xfs_ino_t, inum) + __field(unsigned int, gen) + __field(unsigned int, flags) +__field (int, error) + ), +TP_fast_assign ( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->type = sm->sm_type; + __entry->agno = sm->sm_agno; + __entry->inum = sm->sm_ino; + __entry->gen = sm->sm_gen; + __entry->flags = sm->sm_flags; + __entry->error = error; + ), +TP_printk ("dev %d:%d ino %llu type %u agno %u inum %llu gen %u flags 0x%x error %d" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->ino, + __entry->type, + __entry->agno, + __entry->inum, + __entry->gen, + __entry->flags, + __entry->error) +) +#define DEFINE_SCRUB_EVENT (name) \ +DEFINE_EVENT(xfs_scrub_class, name, \ + TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm, \ + int error), \ + TP_ARGS(ip, sm, error)) + +DEFINE_SCRUB_EVENT (xfs_scrub_start); +DEFINE_SCRUB_EVENT (xfs_scrub_done); +#endif /* _TRACE_XFS_SCRUB_TRACE_H */ #undef TRACE_INCLUDE_PATH --Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 5/27 xfs: test the scrub ioctl
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a test scrubber with id 0. This will be used by xfs_scrub to probe the kernel's abilities to scrub (and repair) the metadata.
--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_fs.h | 3 ++ fs/xfs/scrub/common.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 44 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 33 ++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 1 + fs/xfs/scrub/trace.c | 1 + 7 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/common.c create mode 100644 fs/xfs/scrub/common.h
fs/xfs/Makefile +1 -0
@@ -146,6 +146,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ + common.o \ scrub.o \ ) endif
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -483,9 +483,10 @@ struct xfs_scrub_metadata {*/ /* Scrub subcommands. */ +#define XFS_SCRUB_TYPE_TEST 0/* presence test ioctl */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 0 +#define XFS_SCRUB_TYPE_NR 1/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.c new file +60 -0
60 lines not on this page · raw message
fs/xfs/scrub/common.h new file +44 -0
44 lines not on this page · raw message
fs/xfs/scrub/scrub.c +33 -0
@@ -42,6 +42,7 @@#include "xfs_rmap_btree.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" +#include "scrub/common.h" #include "scrub/trace.h" /*
@@ -108,6 +109,34 @@* will be set. */ +/* +* Test scrubber -- userspace uses this to probe if we're willing to +* scrub or repair a given mountpoint. +*/ +int +xfs_scrub_tester ( +struct xfs_scrub_context *sc) +{ +if (sc->sm->sm_ino || sc->sm->sm_agno) +return -EINVAL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_CORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_PREEN ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XFAIL ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XFAIL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XCORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XCORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_INCOMPLETE ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_INCOMPLETE ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_WARNING ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_WARNING ; +if (sc->sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT ) +return -ENOENT ; + +return 0 ; +} +/* Scrub setup and teardown */ /* Free all the resources and finish the transactions. */
@@ -126,6 +155,10 @@ xfs_scrub_teardown(/* Scrubbing dispatch. */ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { + {/* ioctl presence test */ + .setup = xfs_scrub_setup_fs, + .scrub = xfs_scrub_tester, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -40,5 +40,6 @@ struct xfs_scrub_context { };/* Metadata scrubbers */ +int xfs_scrub_tester (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
fs/xfs/scrub/trace.c +1 -0
@@ -32,6 +32,7 @@#include "xfs_trans.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" +#include "scrub/common.h" /* * We include this last to have the helpers above available for the trace
Re: [PATCH 05/27] xfs: test the scrub ioctl
Quoted 36 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a test scrubber with id 0. This will be used by
xfs_scrubto probe the kernel's abilities to scrub (and repair) the metadata.Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_fs.h | 3 ++ fs/xfs/scrub/common.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 44 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 33 ++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 1 + fs/xfs/scrub/trace.c | 1 + 7 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/common.c create mode 100644 fs/xfs/scrub/common.hfs/xfs/Makefile +1
-0@@ -146,6 +146,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ + common.o \ scrub.o \ ) endiffs/xfs/libxfs/xfs_fs.h +0
-0
fs/xfs/libxfs/xfs_fs.h struct xfs_scrub_metadata { · line 486
Quoted 4 lines
fs/xfs/libxfs/xfs_fs.h +1
-0@@ -483,9 +483,10 @@ struct xfs_scrub_metadata {*/ /* Scrub subcommands. */ +#define XFS_SCRUB_TYPE_TEST 0/* presence test ioctl */
Shouldn't we call this a "probe" - as in "probe for support" so it doesn't get confused with "use this to test whether scrub works"
Quoted 62 lines
fs/xfs/libxfs/xfs_fs.h +1
-1/* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 0 +#define XFS_SCRUB_TYPE_NR 1/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)fs/xfs/scrub/common.c new file +50
-0@@ -0,0 +1,60 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/common.h" +#include "scrub/trace.h" + +/* Common code for the metadata scrubbers. */ + +/* Per-scrubber setup functions */
fs/xfs/scrub/common.c line 60
Quoted 10 lines
fs/xfs/scrub/common.c new file +10
-0+ +/* Set us up with a transaction and an empty context. */ +int +xfs_scrub_setup_fs ( +struct xfs_scrub_context *sc, +struct xfs_inode *ip) +{ +return xfs_scrub_trans_alloc (sc->sm, sc->mp, + &M_RES (sc->mp)->tr_itruncate,0 ,0 ,0 , &sc->tp); +}
Using the truncate transaction reservation really needs explaining here....
.....
Quoted 5 lines
+/*
+ * Test scrubber -- userspace uses this to probe if we're willing to
+ * scrub or repair a given mountpoint.
+ */
Yup, definitely should be called xfs_scrub_probe()....
Quoted 10 lines
fs/xfs/scrub/common.c new file +10
-0+int +xfs_scrub_tester ( +struct xfs_scrub_context *sc) +{ +if (sc->sm->sm_ino || sc->sm->sm_agno) +return -EINVAL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_CORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_PREEN ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ;
fs/xfs/scrub/common.c
Quoted 10 lines
fs/xfs/scrub/common.c new file +10
-0+if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XFAIL ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XFAIL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XCORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XCORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_INCOMPLETE ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_INCOMPLETE ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_WARNING ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_WARNING ; +if (sc->sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT ) +return -ENOENT ;
Shouldn't this check should be first? If not, comment to explain?
Also, I find that really hard to parse because it's so dense and so much is repeated over and over again (makes my pattern matching brain cells scream). It's copying the exact same flags from sc->sm->sm_gen to sc->sm->sm_flags, so why not somethign like:
struct xfs_scrub_m... *sm = sc->sm; if (sm->sm_ino || sm->sm_agno) return -EINVAL; sm->flags = sm->sm_gen & XFS_SCRUB_FLAGS_OUT; if (sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT) return -ENOENT;
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 05/27] xfs: test the scrub ioctl
Quoted 39 lines · Dave Chinner
Quoted 38 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a test scrubber with id 0. This will be used by
xfs_scrubto probe the kernel's abilities to scrub (and repair) the metadata.Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_fs.h | 3 ++ fs/xfs/scrub/common.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 44 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 33 ++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 1 + fs/xfs/scrub/trace.c | 1 + 7 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/common.c create mode 100644 fs/xfs/scrub/common.hfs/xfs/Makefile +1
-0@@ -146,6 +146,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ + common.o \ scrub.o \ ) endiffs/xfs/libxfs/xfs_fs.h +0
-0@@ -483,9 +483,10 @@ struct xfs_scrub_metadata {*/
Quoted 5 lines
fs/xfs/libxfs/xfs_fs.h struct xfs_scrub_metadata { · line 486
Quoted 2 lines
fs/xfs/libxfs/xfs_fs.h +1
-0/* Scrub subcommands. */ +#define XFS_SCRUB_TYPE_TEST 0/* presence test ioctl */ Shouldn't we call this a "probe" - as in "probe for support" so it doesn't get confused with "use this to test whether scrub works"
I'd thought "test" as in "test if it's even there", but "probe" works just as well and (hopefully) confuses everyone less.
Quoted 68 lines
Quoted 68 lines
fs/xfs/libxfs/xfs_fs.h +1
-1/* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 0 +#define XFS_SCRUB_TYPE_NR 1/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)fs/xfs/scrub/common.c new file +55
-0@@ -0,0 +1,60 @@ +/* +* Copyright (C) 2017 Oracle. All Rights Reserved. +* +* Author: Darrick J. Wong <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_alloc_btree.h" +#include "xfs_bmap.h" +#include "xfs_bmap_btree.h" +#include "xfs_ialloc.h" +#include "xfs_ialloc_btree.h" +#include "xfs_refcount.h" +#include "xfs_refcount_btree.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/common.h" +#include "scrub/trace.h" + +/* Common code for the metadata scrubbers. */ + +/* Per-scrubber setup functions */ + +/* Set us up with a transaction and an empty context. */ +int +xfs_scrub_setup_fs( + struct xfs_scrub_context *sc,
Quoted 8 lines
fs/xfs/scrub/common.c line 60
Quoted 5 lines
fs/xfs/scrub/common.c new file +5
-0+ struct xfs_inode *ip) +{ +return xfs_scrub_trans_alloc (sc->sm, sc->mp, + &M_RES (sc->mp)->tr_itruncate,0 ,0 ,0 , &sc->tp); +}Using the truncate transaction reservation really needs explaining here....
/*
* Reserve a transaction with the largest reservation so that we can
* handle the worst case log item space requirement if we have to repair
* something big.
*/
Hm, come to think of it all callres of xfs_scrub_trans_alloc differ only in the resblks passed in, so I can factor out the rtblks/flags/type parameters.
Quoted 9 lines
.....
Quoted 5 lines
+/*
+ * Test scrubber -- userspace uses this to probe if we're willing to
+ * scrub or repair a given mountpoint.
+ */Yup, definitely should be called
xfs_scrub_probe()....
Ok.
Quoted 29 lines
Quoted 10 lines
fs/xfs/scrub/common.c new file +10
-0+int +xfs_scrub_tester ( +struct xfs_scrub_context *sc) +{ +if (sc->sm->sm_ino || sc->sm->sm_agno) +return -EINVAL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_CORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_PREEN ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ;fs/xfs/scrub/common.c
Quoted 10 lines
fs/xfs/scrub/common.c new file +10
-0+if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XFAIL ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XFAIL ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_XCORRUPT ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_XCORRUPT ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_INCOMPLETE ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_INCOMPLETE ; +if (sc->sm->sm_gen &XFS_SCRUB_OFLAG_WARNING ) + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_WARNING ; +if (sc->sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT ) +return -ENOENT ;Shouldn't this check should be first? If not, comment to explain?
Also, I find that really hard to parse because it's so dense and so much is repeated over and over again (makes my pattern matching brain cells scream). It's copying the exact same flags from
sc->sm->sm_gentosc->sm->sm_flags, so why not somethign like:
Quoted 8 lines
struct xfs_scrub_m... *sm = sc->sm; if (sm->sm_ino || sm->sm_agno) return -EINVAL; sm->flags = sm->sm_gen & XFS_SCRUB_FLAGS_OUT; if (sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT) return -ENOENT;
Yes, that could be:
if (sm->sm_ino || sm->sm_agno) return -EINVAL; if (sm->sm_gen & ~XFS_SCRUB_FLAGS_OUT) return -ENOENT; /* Echo parameters back to userspace to prove that we exist. */ sm->flags = sm->sm_gen & XFS_SCRUB_FLAGS_OUT;
--D
Quoted 11 lines
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 6/27 xfs: create helpers to record and deal with scrub problems
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise.
--- fs/xfs/scrub/common.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 39 ++++++++ fs/xfs/scrub/trace.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+)
fs/xfs/scrub/common.c +243 -0
@@ -47,6 +47,249 @@/* Common code for the metadata scrubbers. */ +/* Check for operational errors. */ +bool +xfs_scrub_op_ok ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +xfs_agblock_t bno, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_op_error (sc, agno, bno, *error, + __return_address); +break ; + } +return false; +} + +/* Check for operational errors for a file offset. */ +bool +xfs_scrub_fblock_op_ok ( +struct xfs_scrub_context *sc, +int whichfork, +xfs_fileoff_t offset, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_file_op_error (sc, whichfork, offset, *error, + __return_address); +break ; + } +return false; +} + +/* Check for metadata block optimization possibilities. */ +bool +xfs_scrub_block_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_block_preen (sc, agno, bno, __return_address); +return fs_ok; +} + +/* Check for inode metadata optimization possibilities. */ +bool +xfs_scrub_ino_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_inode *ip = sc->ip; +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + +if (bp) { + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + }else { + agno =XFS_INO_TO_AGNO (mp, ip->i_ino); + bno =XFS_INO_TO_AGINO (mp, ip->i_ino); + } + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_ino_preen (sc, ip->i_ino, agno, bno, __return_address); +return fs_ok; +} + +/* Check for metadata block corruption. */ +bool +xfs_scrub_block_check_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +trace_xfs_scrub_block_error (sc, agno, bno, __return_address); +return fs_ok; +} + +/* Check for inode metadata corruption. */ +bool +xfs_scrub_ino_check_ok ( +struct xfs_scrub_context *sc, +xfs_ino_t ino, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_inode *ip = sc->ip; +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + +if (bp) { + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + }else { + agno =XFS_INO_TO_AGNO (mp, ip->i_ino); + bno =XFS_INO_TO_AGINO (mp, ip->i_ino); + } + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +trace_xfs_scrub_ino_error (sc, ino, agno, bno, __return_address); +return fs_ok; +} + +/* Check for file fork block corruption. */ +bool +xfs_scrub_fblock_check_ok ( +struct xfs_scrub_context *sc, +int whichfork, +xfs_fileoff_t offset, +bool fs_ok) +{ +if (fs_ok) +return fs_ok; + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; +trace_xfs_scrub_fblock_error (sc, whichfork, offset, __return_address); +return fs_ok; +} + +/* Check for inode metadata non-corruption problems. */ +bool +xfs_scrub_ino_warn_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_inode *ip = sc->ip; +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + +if (bp) { + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + }else { + agno =XFS_INO_TO_AGNO (mp, ip->i_ino); + bno =XFS_INO_TO_AGINO (mp, ip->i_ino); + } + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_WARNING ; +trace_xfs_scrub_ino_warning (sc, ip->i_ino, agno, bno, __return_address); +return fs_ok; +} + +/* Check for file fork block non-corruption problems. */ +bool +xfs_scrub_fblock_warn_ok ( +struct xfs_scrub_context *sc, +int whichfork, +xfs_fileoff_t offset, +bool fs_ok) +{ +if (fs_ok) +return fs_ok; + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_WARNING ; +trace_xfs_scrub_fblock_warning (sc, whichfork, offset, __return_address); +return fs_ok; +} + +/* Signal an incomplete scrub. */ +bool +xfs_scrub_check_thoroughness ( +struct xfs_scrub_context *sc, +bool fs_ok) +{ +if (fs_ok) +return fs_ok; + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_INCOMPLETE ; +trace_xfs_scrub_incomplete (sc, __return_address); +return fs_ok; +} +/* Per-scrubber setup functions */ /* Set us up with a transaction and an empty context. */
fs/xfs/scrub/common.h +39 -0
@@ -38,6 +38,45 @@ xfs_scrub_trans_alloc(return xfs_trans_alloc_empty (mp, tpp); } +/* Check for operational errors for a block check. */ +bool xfs_scrub_op_ok (struct xfs_scrub_context *sc,xfs_agnumber_t agno, +xfs_agblock_t bno,int *error); + +/* Check for operational errors for a file offset check. */ +bool xfs_scrub_fblock_op_ok (struct xfs_scrub_context *sc,int whichfork, +xfs_fileoff_t offset,int *error); + +/* Check for metadata block optimization possibilities. */ +bool xfs_scrub_block_preen_ok (struct xfs_scrub_context *sc,struct xfs_buf *bp, +bool fs_ok); + +/* Check for inode metadata optimization possibilities. */ +bool xfs_scrub_ino_preen_ok (struct xfs_scrub_context *sc,struct xfs_buf *bp, +bool fs_ok); + +/* Check for metadata block corruption. */ +bool xfs_scrub_block_check_ok (struct xfs_scrub_context *sc,struct xfs_buf *bp, +bool fs_ok); + +/* Check for inode metadata corruption. */ +bool xfs_scrub_ino_check_ok (struct xfs_scrub_context *sc,xfs_ino_t ino, +struct xfs_buf *bp,bool fs_ok); + +/* Check for file fork block corruption. */ +bool xfs_scrub_fblock_check_ok (struct xfs_scrub_context *sc,int whichfork, +xfs_fileoff_t offset,bool fs_ok); + +/* Check for inode metadata non-corruption weirdness problems. */ +bool xfs_scrub_ino_warn_ok (struct xfs_scrub_context *sc,struct xfs_buf *bp, +bool fs_ok); + +/* Check for file data block non-corruption weirdness problems. */ +bool xfs_scrub_fblock_warn_ok (struct xfs_scrub_context *sc,int whichfork, +xfs_fileoff_t offset,bool fs_ok); + +/* Signal an incomplete scrub. */ +bool xfs_scrub_check_thoroughness (struct xfs_scrub_context *sc,bool fs_ok); +/* Setup functions */ int xfs_scrub_setup_fs (struct xfs_scrub_context *sc,struct xfs_inode *ip);
fs/xfs/scrub/trace.h +193 -0
199 lines not on this page · raw message
Re: [PATCH 06/27] xfs: create helpers to record and deal with scrub problems
Quoted 39 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/common.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 39 ++++++++ fs/xfs/scrub/trace.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+)fs/xfs/scrub/common.c +18
-0@@ -47,6 +47,249 @@/* Common code for the metadata scrubbers. */ +/* Check for operational errors. */ +bool +xfs_scrub_op_ok ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +xfs_agblock_t bno, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */
fs/xfs/scrub/common.c line 77
Quoted 10 lines
fs/xfs/scrub/common.c +10
-0+ sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_op_error (sc, agno, bno, *error, + __return_address); +break ; + } +return false; +}
What are the semantics here w.r.t. *error? on some errors it's cleared before we return, on others it's ignored. It's as clear as mud what we should expect from these functions...
Quoted 13 lines
fs/xfs/scrub/common.c +13
-0+/* Check for metadata block optimization possibilities. */ +bool +xfs_scrub_block_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok)
fs/xfs/scrub/common.c line 130
Quoted 10 lines
fs/xfs/scrub/common.c +10
-0+return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno); + + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_block_preen (sc, agno, bno, __return_address); +return fs_ok; +}
Again, I'm not sure what the return value semantics of the functioon are? Why does the fs_ok return shortcut exist?
Same for all the other functions...
fs/xfs/scrub/common.c line 238
Quoted 7 lines
fs/xfs/scrub/common.c +7
-0+ +/* Check for inode metadata non-corruption problems. */ +bool +xfs_scrub_ino_warn_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok)
Confusing. What's the difference between a corruption problem and a "non-corruption problem" that requires a warning?
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 06/27] xfs: create helpers to record and deal with scrub problems
Quoted 46 lines · Dave Chinner
Quoted 45 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/common.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 39 ++++++++ fs/xfs/scrub/trace.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+)fs/xfs/scrub/common.c +24
-0@@ -47,6 +47,249 @@/* Common code for the metadata scrubbers. */ +/* Check for operational errors. */ +bool +xfs_scrub_op_ok ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +xfs_agblock_t bno, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_op_error (sc, agno, bno, *error, + __return_address);
Quoted 8 lines
fs/xfs/scrub/common.c line 77
Quoted 4 lines
fs/xfs/scrub/common.c +4
-0+break ; + } +return false; +}What are the semantics here w.r.t. *error? on some errors it's cleared before we return, on others it's ignored. It's as clear as mud what we should expect from these functions...
If there's no error, we return true to tell the caller that it's ok to move on to the next check in its list.
For non-verifier errors (e.g. ENOMEM) we return false to tell the caller that there's no point in it continuing, and we preserve *error so that the caller can return the *error up the stack. Checking stops immediately and the error is handed to userspace.
Verifier errors (EFSBADCRC/EFSCORRUPTED) are recorded in sm_flags and the *error is cleared. We return false to tell the caller that there's point in it continuing with this record. The caller returns zero to its caller, which means that checking continues, having skipped whatever block failed the verifier.
Quoted 18 lines
Quoted 18 lines
fs/xfs/scrub/common.c +18
-0+/* Check for metadata block optimization possibilities. */ +bool +xfs_scrub_block_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno);
Quoted 8 lines
fs/xfs/scrub/common.c line 130
Quoted 5 lines
fs/xfs/scrub/common.c +5
-0+ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_block_preen (sc, agno, bno, __return_address); +return fs_ok; +}Again, I'm not sure what the return value semantics of the functioon are? Why does the
fs_okreturn shortcut exist?
The fs_ok functions are wrappers around an if test; the results of the if test are passed in as fs_ok.
Therefore, if fs_ok then things are fine and we just skip out.
Otherwise, we found something and we should set sm_flags and jump out.
Quoted 12 lines
Same for all the other functions...
fs/xfs/scrub/common.c line 238
Quoted 7 lines
fs/xfs/scrub/common.c +7
-0+ +/* Check for inode metadata non-corruption problems. */ +bool +xfs_scrub_ino_warn_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok)Confusing. What's the difference between a corruption problem and a "non-corruption problem" that requires a warning?
Anything that's less severe than "your fs is corrupt" but otherwise requires administrator review. The inode scrubber sets this for inodes with a -1 uid/gid. XFS seems fine with it, but the VFS treats -1ULL as a magic "doesn't exist" value, and then userspace can't change it. The quota code sets warnings if it detects quota usage exceeding the hard limit, or if the limits are larger than the fs, etc.
In these cases I'd want the administrator to have a look and/or take corrective action, but XFS doesn't flag those situations as fs corruption nor does xfs_repair complain about them as corruption.
--D
Quoted 11 lines
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/27] xfs: create helpers to record and deal with scrub problems
Darrick,
Excuse the nasty top post, but can you wrap all this up in comments in the code? It all makes sense now you explain it, but I'm not going to remember all that in a couple of months time...
-Dave.
Quoted 142 lines · Darrick J. Wong
Quoted 46 lines · Dave Chinner
Quoted 45 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/common.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 39 ++++++++ fs/xfs/scrub/trace.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+)fs/xfs/scrub/common.c +24
-0@@ -47,6 +47,249 @@/* Common code for the metadata scrubbers. */ +/* Check for operational errors. */ +bool +xfs_scrub_op_ok ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +xfs_agblock_t bno, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_op_error (sc, agno, bno, *error, + __return_address);Quoted 8 lines
fs/xfs/scrub/common.c line 77
Quoted 4 lines
fs/xfs/scrub/common.c +4
-0+break ; + } +return false; +}What are the semantics here w.r.t. *error? on some errors it's cleared before we return, on others it's ignored. It's as clear as mud what we should expect from these functions...
If there's no error, we return true to tell the caller that it's ok to move on to the next check in its list.
For non-verifier errors (e.g. ENOMEM) we return false to tell the caller that there's no point in it continuing, and we preserve *error so that the caller can return the *error up the stack. Checking stops immediately and the error is handed to userspace.
Verifier errors (EFSBADCRC/EFSCORRUPTED) are recorded in
sm_flagsand the *error is cleared. We return false to tell the caller that there's point in it continuing with this record. The caller returns zero to its caller, which means that checking continues, having skipped whatever block failed the verifier.Quoted 18 lines
Quoted 18 lines
fs/xfs/scrub/common.c +18
-0+/* Check for metadata block optimization possibilities. */ +bool +xfs_scrub_block_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno);Quoted 8 lines
fs/xfs/scrub/common.c line 130
Quoted 5 lines
fs/xfs/scrub/common.c +5
-0+ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_block_preen (sc, agno, bno, __return_address); +return fs_ok; +}Again, I'm not sure what the return value semantics of the functioon are? Why does the
fs_okreturn shortcut exist?The
fs_okfunctions are wrappers around an if test; the results of the if test are passed in asfs_ok.Therefore, if
fs_okthen things are fine and we just skip out.Otherwise, we found something and we should set
sm_flagsand jump out.Quoted 12 lines
Same for all the other functions...
fs/xfs/scrub/common.c line 238
Quoted 7 lines
fs/xfs/scrub/common.c +7
-0+ +/* Check for inode metadata non-corruption problems. */ +bool +xfs_scrub_ino_warn_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok)Confusing. What's the difference between a corruption problem and a "non-corruption problem" that requires a warning?
Anything that's less severe than "your fs is corrupt" but otherwise requires administrator review. The inode scrubber sets this for inodes with a -1 uid/gid. XFS seems fine with it, but the VFS treats -1ULL as a magic "doesn't exist" value, and then userspace can't change it. The quota code sets warnings if it detects quota usage exceeding the hard limit, or if the limits are larger than the fs, etc.
In these cases I'd want the administrator to have a look and/or take corrective action, but XFS doesn't flag those situations as fs corruption nor does
xfs_repaircomplain about them as corruption.--D
Quoted 11 lines
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 06/27] xfs: create helpers to record and deal with scrub problems
Quoted 5 lines · Dave Chinner
Darrick,
Excuse the nasty top post, but can you wrap all this up in comments in the code? It all makes sense now you explain it, but I'm not going to remember all that in a couple of months time...
Already done.
(FWIW top-posting doesn't bother me...)
--D
Quoted 154 lines
-Dave.
Quoted 142 lines · Darrick J. Wong
Quoted 46 lines · Dave Chinner
Quoted 45 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create helper functions to record crc and corruption problems, and deal with any other runtime errors that arise.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/scrub/common.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 39 ++++++++ fs/xfs/scrub/trace.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+)fs/xfs/scrub/common.c +24
-0@@ -47,6 +47,249 @@/* Common code for the metadata scrubbers. */ +/* Check for operational errors. */ +bool +xfs_scrub_op_ok ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +xfs_agblock_t bno, +int *error) +{ +switch (*error) { +case 0 : +return true; +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +trace_xfs_scrub_op_error (sc, agno, bno, *error, + __return_address);Quoted 8 lines
fs/xfs/scrub/common.c line 77
Quoted 4 lines
fs/xfs/scrub/common.c +4
-0+break ; + } +return false; +}What are the semantics here w.r.t. *error? on some errors it's cleared before we return, on others it's ignored. It's as clear as mud what we should expect from these functions...
If there's no error, we return true to tell the caller that it's ok to move on to the next check in its list.
For non-verifier errors (e.g. ENOMEM) we return false to tell the caller that there's no point in it continuing, and we preserve *error so that the caller can return the *error up the stack. Checking stops immediately and the error is handed to userspace.
Verifier errors (EFSBADCRC/EFSCORRUPTED) are recorded in
sm_flagsand the *error is cleared. We return false to tell the caller that there's point in it continuing with this record. The caller returns zero to its caller, which means that checking continues, having skipped whatever block failed the verifier.Quoted 18 lines
Quoted 18 lines
fs/xfs/scrub/common.c +18
-0+/* Check for metadata block optimization possibilities. */ +bool +xfs_scrub_block_preen_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok) +{ +struct xfs_mount *mp = sc->mp; +xfs_fsblock_t fsbno; +xfs_agnumber_t agno; +xfs_agblock_t bno; + +if (fs_ok) +return fs_ok; + + fsbno =XFS_DADDR_TO_FSB (mp, bp->b_bn); + agno =XFS_FSB_TO_AGNO (mp, fsbno); + bno =XFS_FSB_TO_AGBNO (mp, fsbno);Quoted 8 lines
fs/xfs/scrub/common.c line 130
Quoted 5 lines
fs/xfs/scrub/common.c +5
-0+ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_PREEN ; +trace_xfs_scrub_block_preen (sc, agno, bno, __return_address); +return fs_ok; +}Again, I'm not sure what the return value semantics of the functioon are? Why does the
fs_okreturn shortcut exist?The
fs_okfunctions are wrappers around an if test; the results of the if test are passed in asfs_ok.Therefore, if
fs_okthen things are fine and we just skip out.Otherwise, we found something and we should set
sm_flagsand jump out.Quoted 12 lines
Same for all the other functions...
fs/xfs/scrub/common.c line 238
Quoted 7 lines
fs/xfs/scrub/common.c +7
-0+ +/* Check for inode metadata non-corruption problems. */ +bool +xfs_scrub_ino_warn_ok ( +struct xfs_scrub_context *sc, +struct xfs_buf *bp, +bool fs_ok)Confusing. What's the difference between a corruption problem and a "non-corruption problem" that requires a warning?
Anything that's less severe than "your fs is corrupt" but otherwise requires administrator review. The inode scrubber sets this for inodes with a -1 uid/gid. XFS seems fine with it, but the VFS treats -1ULL as a magic "doesn't exist" value, and then userspace can't change it. The quota code sets warnings if it detects quota usage exceeding the hard limit, or if the limits are larger than the fs, etc.
In these cases I'd want the administrator to have a look and/or take corrective action, but XFS doesn't flag those situations as fs corruption nor does
xfs_repaircomplain about them as corruption.--D
Quoted 11 lines
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.htmlSignature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 7/27 xfs: create helpers to scrub a metadata btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create helper functions and tracepoints to deal with errors while scrubbing a metadata btree.
--- fs/xfs/Makefile | 1 fs/xfs/scrub/btree.c | 114 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/btree.h | 57 ++++++++++++++++++ fs/xfs/scrub/trace.c | 14 ++++ fs/xfs/scrub/trace.h | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 348 insertions(+) create mode 100644 fs/xfs/scrub/btree.c create mode 100644 fs/xfs/scrub/btree.h
fs/xfs/Makefile +1 -0
@@ -146,6 +146,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ + btree.o \ common.o \ scrub.o \ )
fs/xfs/scrub/btree.c new file +114 -0
114 lines not on this page · raw message
fs/xfs/scrub/btree.h new file +57 -0
57 lines not on this page · raw message
fs/xfs/scrub/trace.c +14 -0
@@ -30,10 +30,24 @@#include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_trans.h" +#include "xfs_bit.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h" +/* Figure out which block the btree cursor was pointing to. */ +static inline xfs_fsblock_t +xfs_scrub_btree_cur_fsbno ( +struct xfs_btree_cur *cur, +int level) +{ +if (level < cur->bc_nlevels && cur->bc_bufs[level]) +return XFS_DADDR_TO_FSB (cur->bc_mp, cur->bc_bufs[level]->b_bn); +else if (cur->bc_flags &XFS_BTREE_LONG_PTRS ) +return XFS_INO_TO_FSB (cur->bc_mp, cur->bc_private.b.ip->i_ino); +return XFS_AGB_TO_FSB (cur->bc_mp, cur->bc_private.a.agno,0 ); +} +/* * We include this last to have the helpers above available for the trace * event implementations.
fs/xfs/scrub/trace.h +162 -0
168 lines not on this page · raw message
Re: [PATCH 07/27] xfs: create helpers to scrub a metadata btree
Quoted 19 lines · Darrick J. Wong
fs/xfs/scrub/btree.c new file +19
-0+/* Check for btree operation errors . */ +bool +xfs_scrub_btree_op_ok ( +struct xfs_scrub_context *sc, +struct xfs_btree_cur *cur, +int level, +int *error) +{ +if (*error ==0 ) +return true; + +switch (*error) { +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */
fs/xfs/scrub/btree.c line 69
Quoted 10 lines
fs/xfs/scrub/btree.c new file +10
-0+ sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +if (cur->bc_flags &XFS_BTREE_ROOT_IN_INODE ) +trace_xfs_scrub_ifork_btree_op_error (sc, cur, level, + *error, __return_address); +else +trace_xfs_scrub_btree_op_error (sc, cur, level, + *error, __return_address);
Why different tracepoints when you could just output the cur->bc_flags in the trace output and use the same tracepoint? Doing that looks like it would simplify the tracepoint code in this patch....
fs/xfs/scrub/trace.c line 46
Quoted 9 lines
fs/xfs/scrub/trace.c +9
-0+/* Figure out which block the btree cursor was pointing to. */ +static inline xfs_fsblock_t +xfs_scrub_btree_cur_fsbno ( +struct xfs_btree_cur *cur, +int level) +{ +if (level < cur->bc_nlevels && cur->bc_bufs[level]) +return XFS_DADDR_TO_FSB (cur->bc_mp, cur->bc_bufs[level]->b_bn); +else if (cur->bc_flags &XFS_BTREE_LONG_PTRS )
no need for "else if", just "if" will do.
fs/xfs/scrub/trace.c line 47
Quoted 1 line
fs/xfs/scrub/trace.c +1
-0+return XFS_INO_TO_FSB (cur->bc_mp, cur->bc_private.b.ip->i_ino);
This makes no sense to me. Why are we returning the block address of the inode here? It's not part of the btree....
fs/xfs/scrub/trace.c line 48
Quoted 1 line
fs/xfs/scrub/trace.c +1
-0+return XFS_AGB_TO_FSB (cur->bc_mp, cur->bc_private.a.agno,0 );
Nor is the first block of the AG....
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 07/27] xfs: create helpers to scrub a metadata btree
Quoted 27 lines · Dave Chinner
Quoted 26 lines · Darrick J. Wong
fs/xfs/scrub/btree.c new file +26
-0+/* Check for btree operation errors . */ +bool +xfs_scrub_btree_op_ok ( +struct xfs_scrub_context *sc, +struct xfs_btree_cur *cur, +int level, +int *error) +{ +if (*error ==0 ) +return true; + +switch (*error) { +case -EDEADLOCK : +/* Used to restart an op with deadlock avoidance. */ +trace_xfs_scrub_deadlock_retry (sc->ip, sc->sm, *error); +break ; +case -EFSBADCRC : +case -EFSCORRUPTED : +/* Note the badness but don't abort. */ + sc->sm->sm_flags |=XFS_SCRUB_OFLAG_CORRUPT ; + *error =0 ; +/* fall through */ +default : +if (cur->bc_flags &XFS_BTREE_ROOT_IN_INODE ) +trace_xfs_scrub_ifork_btree_op_error (sc, cur, level, + *error, __return_address);
Quoted 8 lines
fs/xfs/scrub/btree.c line 69
Quoted 3 lines
fs/xfs/scrub/btree.c new file +3
-0+else +trace_xfs_scrub_btree_op_error (sc, cur, level, + *error, __return_address);Why different tracepoints when you could just output the
cur->bc_flagsin the trace output and use the same tracepoint? Doing that looks like it would simplify the tracepoint code in this patch....
The ifork_btree_op_error tracepoint records the inode number and whichfork, whereas the btree_op_error of course does not. I don't know how to write a tracepoint that changes the TP_printk format string & arguments based on the inputs. If the bmap scrubber sees a problem with an inode's fork, I want to know which inode and which fork without having to go find the previous xfs_scrub_start trace.
Quoted 19 lines
fs/xfs/scrub/trace.c line 46
Quoted 10 lines
fs/xfs/scrub/trace.c +9
-0+/* Figure out which block the btree cursor was pointing to. */ +static inline xfs_fsblock_t +xfs_scrub_btree_cur_fsbno ( +struct xfs_btree_cur *cur, +int level) +{ +if (level < cur->bc_nlevels && cur->bc_bufs[level]) +return XFS_DADDR_TO_FSB (cur->bc_mp, cur->bc_bufs[level]->b_bn); +else if (cur->bc_flags &XFS_BTREE_LONG_PTRS )no need for "else if", just "if" will do.
fs/xfs/scrub/trace.c line 47
Quoted 1 line
fs/xfs/scrub/trace.c +1
-0+return XFS_INO_TO_FSB (cur->bc_mp, cur->bc_private.b.ip->i_ino);This makes no sense to me. Why are we returning the block address of the inode here? It's not part of the btree....
Quoted 3 lines
fs/xfs/scrub/trace.c line 48
Quoted 1 line
fs/xfs/scrub/trace.c +1
-0+return XFS_AGB_TO_FSB (cur->bc_mp, cur->bc_private.a.agno,0 );Nor is the first block of the AG....
I should've written into the comment that the fsb returned by this function is used only for tracepoint output.
These two clauses are fallbacks to handle the case that this level of the btree cursor doesn't point to a buffer. If there is no xfs_buf and this is a long-pointer btree then either we're looking at the btree root in the inode or staring into space, for either of these we might as well report the block that contains the inode. If there is no xfs_buf and it's a short-pointer btree then it must be an AG tree and so report the AG.
I could be persuaded that if we don't have a buffer and it's not the inode root then just report NULLFSBLOCK in the tracepoint, since I revised all the tracepoints to contain the inum/agno anyway.
--D
Quoted 11 lines
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 8/27 xfs: scrub the shape of a metadata btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_btree.c +14 -2
@@ -1027,7 +1027,7 @@ xfs_btree_setbuf( } } -STATIC int +bool xfs_btree_ptr_is_null (struct xfs_btree_cur *cur,union xfs_btree_ptr *ptr)
@@ -1052,7 +1052,7 @@ xfs_btree_set_ptr_null(/* * Get/set/init sibling pointers */ -STATIC void +void xfs_btree_get_sibling( struct xfs_btree_cur *cur, struct xfs_btree_block *block,
@@ -4914,3 +4914,15 @@ xfs_btree_count_blocks(return xfs_btree_visit_blocks (cur, xfs_btree_count_blocks_helper, blocks); } + +/* Compare two btree pointers. */ +int64_t +xfs_btree_diff_two_ptrs ( +struct xfs_btree_cur *cur, +const union xfs_btree_ptr *a, +const union xfs_btree_ptr *b) +{ +if (cur->bc_flags &XFS_BTREE_LONG_PTRS ) +return (int64_t )be64_to_cpu (a->l) -be64_to_cpu (b->l); +return (int64_t )be32_to_cpu (a->s) -be32_to_cpu (b->s); +}
fs/xfs/libxfs/xfs_btree.h +7 -0
@@ -517,5 +517,12 @@ int xfs_btree_lookup_get_block(struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *pp, struct xfs_btree_block **blkp);struct xfs_btree_block *xfs_btree_get_block (struct xfs_btree_cur *cur,int level,struct xfs_buf **bpp); +bool xfs_btree_ptr_is_null (struct xfs_btree_cur *cur,union xfs_btree_ptr *ptr); +int64_t xfs_btree_diff_two_ptrs (struct xfs_btree_cur *cur, +const union xfs_btree_ptr *a, +const union xfs_btree_ptr *b); +void xfs_btree_get_sibling (struct xfs_btree_cur *cur, +struct xfs_btree_block *block, +union xfs_btree_ptr *ptr,int lr);#endif /* __XFS_BTREE_H__ */
fs/xfs/scrub/btree.c +234 -2
246 lines not on this page · raw message
fs/xfs/scrub/common.h +13 -0
@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not,
Re: [PATCH 08/27] xfs: scrub the shape of a metadata btree
Quoted 18 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)
...
Quoted 4 lines
fs/xfs/scrub/btree.c +0
-0
...
Quoted 29 lines
fs/xfs/scrub/btree.c +23
-2@@ -109,6 +255,92 @@ xfs_scrub_btree(struct xfs_owner_info *oinfo, void *private) { - xfs_scrub_btree_op_ok(sc, cur, 0, false); -return -EOPNOTSUPP ; + struct xfs_scrub_btree bs = {0}; +union xfs_btree_ptr ptr; +union xfs_btree_ptr *pp; +struct xfs_btree_block *block; +int level; +struct xfs_buf *bp; +int i; +int error =0 ; + +/* Initialize scrub state */ + bs.cur = cur; + bs.scrub_rec = scrub_fn; + bs.oinfo = oinfo; + bs.firstrec = true; + bs.private = private; + bs.sc = sc; +for (i =0 ; i <XFS_BTREE_MAXLEVELS ; i++) + bs.firstkey[i] = true; +INIT_LIST_HEAD (&bs.to_check); + +/* Don't try to check a tree with a height we can't handle. */ +if (!xfs_scrub_btree_check_ok (sc, cur,0 , cur->bc_nlevels >0 && + cur->bc_nlevels <=XFS_BTREE_MAXLEVELS ))
fs/xfs/scrub/btree.c xfs_scrub_btree( · line 290
Quoted 10 lines
fs/xfs/scrub/btree.c +10
-0+ goto out; + +/* Make sure the root isn't in the superblock. */ +if (!(cur->bc_flags &XFS_BTREE_ROOT_IN_INODE )) { + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_ptr (&bs, cur->bc_nlevels, &ptr); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + } +
This is kind of in line with Dave's comments on the previous patch that introduce some of these helpers. I just glanced over them for now because I didn't have enough context to grok the error processing.
FWIW, the btree_op_ok()/btree_check_ok() stuff kind of makes my eyes cross a bit because I can't easily see the logic checks or distinguish between those and error code checks. This is also a bit confusing because it looks like we overload return codes for various things. E.g., we generate -EFSCORRUPTED in some cases just so the caller can set the state on the context and clear it, but then we still use the fact that an error _was_ set to control the flow of the task via the op_ok() return value. This makes some of the code flow/decision making logic hard to follow, particularly since some of that state looks like it can be lost.
Case in point.. what happens if say xfs_btree_increment() returns -EFSCORRUPTED back to xfs_scrub_btree_block_check_sibling()? It looks to me that the latter calls btree_op_ok() to set the corrupt state, clears the error code and skips out appropriately. xfs_scrub_btree_block_check_sibling() now returns zero, which potentially bubbles up to xfs_scrub_btree() where we check the error code again. Is it expected that error == 0 here? What is supposed to happen here?
I'm wondering if this could all be made more clear by trying to explicitly separate out operational errors, scrub failures and whatever we want to call the logic that clears an -EFSCORRUPTED/-EFSBADCRC error code but still indicates something happened. :P
For starters, rather than wrap every logic check with btree_op_check(), could we use explicit logic and let each function update the context based on problems it found? For example, something like the following is much more easy to read for me than the associated logic above:
/* Don't try to check a tree with a height we can't handle. */
if (!(cur->bc_nlevels > 0 &&
cur->bc_nlevels <= XFS_BTREE_MAXLEVELS)) {
xfs_scrub_sc_corrupt(...);
goto out;
}And of course the context update calls could be factored into an out_corrupt label or something where appropriate.
Beyond that, where we need to identify a bit of metadata is busted to perhaps do something like skip it but not abort (as we may have filtered out an -EFSCORRUPTED) return code, could we pass a flag down a particular callchain (i.e., think 'bool *bad' or 'int *stat' a la the core btree code)? Then we can still transfer that state back up the chain and the caller(s) can distinguish operational errors from "this thing is corrupted, act accordingly," regardless of how the corruption was detected.
Brian
Quoted 85 lines
fs/xfs/scrub/btree.c +55
-0+/* Load the root of the btree. */ + level = cur->bc_nlevels -1 ; + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_block (&bs, level, &ptr, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + +while (level < cur->bc_nlevels) { + block =xfs_btree_get_block (cur, level, &bp); + +if (level ==0 ) { +/* End of leaf, pop back towards the root. */ +if (cur->bc_ptrs[level] > +be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +if (xfs_scrub_should_terminate (&error)) +break ; + + cur->bc_ptrs[level]++; +continue ; + } + +/* End of node, pop back towards the root. */ +if (cur->bc_ptrs[level] >be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +/* Drill another level deeper. */ + pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); + error =xfs_scrub_btree_ptr (&bs, level, pp); +if (error) { + error =0 ; + cur->bc_ptrs[level]++; +continue ; + } + level--; + error =xfs_scrub_btree_block (&bs, level, pp, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, level, &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + } + +out: +return error; }fs/xfs/scrub/common.h +13
-1@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not, -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/27] xfs: scrub the shape of a metadata btree
Quoted 60 lines · Brian Foster
Quoted 18 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)...
Quoted 4 lines
fs/xfs/scrub/btree.c +0
-0...
Quoted 35 lines
fs/xfs/scrub/btree.c +29
-2@@ -109,6 +255,92 @@ xfs_scrub_btree(struct xfs_owner_info *oinfo, void *private) { - xfs_scrub_btree_op_ok(sc, cur, 0, false); -return -EOPNOTSUPP ; + struct xfs_scrub_btree bs = {0}; +union xfs_btree_ptr ptr; +union xfs_btree_ptr *pp; +struct xfs_btree_block *block; +int level; +struct xfs_buf *bp; +int i; +int error =0 ; + +/* Initialize scrub state */ + bs.cur = cur; + bs.scrub_rec = scrub_fn; + bs.oinfo = oinfo; + bs.firstrec = true; + bs.private = private; + bs.sc = sc; +for (i =0 ; i <XFS_BTREE_MAXLEVELS ; i++) + bs.firstkey[i] = true; +INIT_LIST_HEAD (&bs.to_check); + +/* Don't try to check a tree with a height we can't handle. */ +if (!xfs_scrub_btree_check_ok (sc, cur,0 , cur->bc_nlevels >0 && + cur->bc_nlevels <=XFS_BTREE_MAXLEVELS )) + goto out; + +/* Make sure the root isn't in the superblock. */ +if (!(cur->bc_flags &XFS_BTREE_ROOT_IN_INODE )) { + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_ptr (&bs, cur->bc_nlevels, &ptr);
Quoted 8 lines
fs/xfs/scrub/btree.c xfs_scrub_btree( · line 290
Quoted 4 lines
fs/xfs/scrub/btree.c +4
-0+if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + } +This is kind of in line with Dave's comments on the previous patch that introduce some of these helpers. I just glanced over them for now because I didn't have enough context to grok the error processing.
(That's been a struggle with this patchset -- some of these helpers don't get used until much further in the patchset. I could have sprinkled them into whichever patch uses them first, but now the hunks are all over the series, I'd have to do more dependency tracking to make sure bisect continues to work, and the frequency of auto-merge failures as I push and pop the stack increase dramatically.)
Quoted 11 lines
FWIW, the btree_op_ok()/btree_check_ok() stuff kind of makes my eyes cross a bit because I can't easily see the logic checks or distinguish between those and error code checks. This is also a bit confusing because it looks like we overload return codes for various things. E.g., we generate
-EFSCORRUPTEDin some cases just so the caller can set the state on the context and clear it, but then we still use the fact that an error _was_ set to control the flow of the task via theop_ok()return value. This makes some of the code flow/decision making logic hard to follow, particularly since some of that state looks like it can be lost.
Quoted 8 lines
Case in point.. what happens if say
xfs_btree_increment()returns-EFSCORRUPTEDback toxfs_scrub_btree_block_check_sibling()? It looks to me that the latter callsbtree_op_ok()to set the corrupt state, clears the error code and skips out appropriately.xfs_scrub_btree_block_check_sibling()now returns zero, which potentially bubbles up toxfs_scrub_btree()where we check the error code again. Is it expected that error == 0 here? What is supposed to happen here?
Yes, error == 0 is intended here. Given a block B, we want to check that B->rightsib->leftsib (if the sibling exists at all) point back to B. If the btree_increment operation returns EFSCORRUPTED we don't know if that's because the B->rightsib points at something it's not supposed to, or if B->rightsib points at a btree block, but that sibling block is corrupt. Therefore we set the corrupt flag and bubble error == 0 up the
call stack so that we can check the other records in the btree. This
enables those following with ftrace to see everything that scrub thinks is wrong with that piece of metadata.
IOWs, we only use error code returns for "runtime error, abort the whole operation immediately".
Quoted 17 lines
I'm wondering if this could all be made more clear by trying to explicitly separate out operational errors, scrub failures and whatever we want to call the logic that clears an -EFSCORRUPTED/-EFSBADCRC error code but still indicates something happened. :P
For starters, rather than wrap every logic check with
btree_op_check(), could we use explicit logic and let each function update the context based on problems it found? For example, something like the following is much more easy to read for me than the associated logic above:/* Don't try to check a tree with a height we can't handle. */ if (!(cur->bc_nlevels > 0 && cur->bc_nlevels <= XFS_BTREE_MAXLEVELS)) { xfs_scrub_sc_corrupt(...); goto out; }
Quoted 2 lines
And of course the context update calls could be factored into an
out_corruptlabel or something where appropriate.
Yes, that could be done.
Quoted 8 lines
Beyond that, where we need to identify a bit of metadata is busted to perhaps do something like skip it but not abort (as we may have filtered out an
-EFSCORRUPTED) return code, could we pass a flag down a particular callchain (i.e., think 'bool *bad' or 'int *stat' a la the core btree code)? Then we can still transfer that state back up the chain and the caller(s) can distinguish operational errors from "this thing is corrupted, act accordingly," regardless of how the corruption was detected.
So far I haven't needed to distinguish between "no problems encountered" and "this callchain hit a verifier error so we just set _CORRUPT" -- scrub always keeps going until it runs out of things to check.
(Maybe I'm missing something?)
--D
Quoted 92 lines
Brian
Quoted 82 lines
fs/xfs/scrub/btree.c +55
-0+/* Load the root of the btree. */ + level = cur->bc_nlevels -1 ; + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_block (&bs, level, &ptr, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + +while (level < cur->bc_nlevels) { + block =xfs_btree_get_block (cur, level, &bp); + +if (level ==0 ) { +/* End of leaf, pop back towards the root. */ +if (cur->bc_ptrs[level] > +be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +if (xfs_scrub_should_terminate (&error)) +break ; + + cur->bc_ptrs[level]++; +continue ; + } + +/* End of node, pop back towards the root. */ +if (cur->bc_ptrs[level] >be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +/* Drill another level deeper. */ + pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); + error =xfs_scrub_btree_ptr (&bs, level, pp); +if (error) { + error =0 ; + cur->bc_ptrs[level]++; +continue ; + } + level--; + error =xfs_scrub_btree_block (&bs, level, pp, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, level, &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + } + +out: +return error; }fs/xfs/scrub/common.h +13
-1@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not, -- Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/27] xfs: scrub the shape of a metadata btree
Quoted 107 lines · Darrick J. Wong
Quoted 60 lines · Brian Foster
Quoted 18 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)...
Quoted 4 lines
fs/xfs/scrub/btree.c +0
-0...
Quoted 35 lines
fs/xfs/scrub/btree.c +29
-2@@ -109,6 +255,92 @@ xfs_scrub_btree(struct xfs_owner_info *oinfo, void *private) { - xfs_scrub_btree_op_ok(sc, cur, 0, false); -return -EOPNOTSUPP ; + struct xfs_scrub_btree bs = {0}; +union xfs_btree_ptr ptr; +union xfs_btree_ptr *pp; +struct xfs_btree_block *block; +int level; +struct xfs_buf *bp; +int i; +int error =0 ; + +/* Initialize scrub state */ + bs.cur = cur; + bs.scrub_rec = scrub_fn; + bs.oinfo = oinfo; + bs.firstrec = true; + bs.private = private; + bs.sc = sc; +for (i =0 ; i <XFS_BTREE_MAXLEVELS ; i++) + bs.firstkey[i] = true; +INIT_LIST_HEAD (&bs.to_check); + +/* Don't try to check a tree with a height we can't handle. */ +if (!xfs_scrub_btree_check_ok (sc, cur,0 , cur->bc_nlevels >0 && + cur->bc_nlevels <=XFS_BTREE_MAXLEVELS )) + goto out; + +/* Make sure the root isn't in the superblock. */ +if (!(cur->bc_flags &XFS_BTREE_ROOT_IN_INODE )) { + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_ptr (&bs, cur->bc_nlevels, &ptr);Quoted 8 lines
fs/xfs/scrub/btree.c xfs_scrub_btree( · line 290
Quoted 4 lines
fs/xfs/scrub/btree.c +4
-0+if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + } +This is kind of in line with Dave's comments on the previous patch that introduce some of these helpers. I just glanced over them for now because I didn't have enough context to grok the error processing.
(That's been a struggle with this patchset -- some of these helpers don't get used until much further in the patchset. I could have sprinkled them into whichever patch uses them first, but now the hunks are all over the series, I'd have to do more dependency tracking to make sure bisect continues to work, and the frequency of auto-merge failures as I push and pop the stack increase dramatically.)
Quoted 11 lines
FWIW, the btree_op_ok()/btree_check_ok() stuff kind of makes my eyes cross a bit because I can't easily see the logic checks or distinguish between those and error code checks. This is also a bit confusing because it looks like we overload return codes for various things. E.g., we generate
-EFSCORRUPTEDin some cases just so the caller can set the state on the context and clear it, but then we still use the fact that an error _was_ set to control the flow of the task via theop_ok()return value. This makes some of the code flow/decision making logic hard to follow, particularly since some of that state looks like it can be lost.Quoted 8 lines
Case in point.. what happens if say
xfs_btree_increment()returns-EFSCORRUPTEDback toxfs_scrub_btree_block_check_sibling()? It looks to me that the latter callsbtree_op_ok()to set the corrupt state, clears the error code and skips out appropriately.xfs_scrub_btree_block_check_sibling()now returns zero, which potentially bubbles up toxfs_scrub_btree()where we check the error code again. Is it expected that error == 0 here? What is supposed to happen here?Yes, error == 0 is intended here. Given a block B, we want to check that
B->rightsib->leftsib(if the sibling exists at all) point back to B. If thebtree_incrementoperation returns EFSCORRUPTED we don't know if that's because theB->rightsibpoints at something it's not supposed to, or ifB->rightsibpoints at a btree block, but that sibling block is corrupt. Therefore we set the corrupt flag and bubble error == 0 up the
call stack so that we can check the other records in the btree. This
enables those following with ftrace to see everything that scrub thinks is wrong with that piece of metadata.
Quoted 3 lines
IOWs, we only use error code returns for "runtime error, abort the whole operation immediately".
Ok, so we intentionally have to consume the error here because it doesn't necessarily reflect the corrupted state of the scrubbed block. So IIUC, overloading return codes as such means error handling must either return -EFSCORRUPTED for the current object being corrupted, return some other error for an error in the infrastructure, or clear any -EFSCORRUPTED error generated by checks that don't necessarily mean the current object is corrupted (or too much so to interrupt processing).
Quoted 31 lines
Quoted 17 lines
I'm wondering if this could all be made more clear by trying to explicitly separate out operational errors, scrub failures and whatever we want to call the logic that clears an -EFSCORRUPTED/-EFSBADCRC error code but still indicates something happened. :P
For starters, rather than wrap every logic check with
btree_op_check(), could we use explicit logic and let each function update the context based on problems it found? For example, something like the following is much more easy to read for me than the associated logic above:/* Don't try to check a tree with a height we can't handle. */ if (!(cur->bc_nlevels > 0 && cur->bc_nlevels <= XFS_BTREE_MAXLEVELS)) { xfs_scrub_sc_corrupt(...); goto out; }Quoted 2 lines
And of course the context update calls could be factored into an
out_corruptlabel or something where appropriate.Yes, that could be done.
Quoted 8 lines
Beyond that, where we need to identify a bit of metadata is busted to perhaps do something like skip it but not abort (as we may have filtered out an
-EFSCORRUPTED) return code, could we pass a flag down a particular callchain (i.e., think 'bool *bad' or 'int *stat' a la the core btree code)? Then we can still transfer that state back up the chain and the caller(s) can distinguish operational errors from "this thing is corrupted, act accordingly," regardless of how the corruption was detected.
Quoted 4 lines
So far I haven't needed to distinguish between "no problems encountered" and "this callchain hit a verifier error so we just set
_CORRUPT" -- scrub always keeps going until it runs out of things to check.
Ok. This is partly speculation on the above (trying to wrap my head around the error consumption bits as is) and partly to try and see if we can make the flow more readable.
In my mind, this is more clear if return codes are reserved for operational/infrastructure errors and the corrupted state of a piece of metadata is its own state. Using the example above, any -EFSCORRUPTED errors from external calls (xfs_btree_check_block(), xfs_btree_increment(), etc.) would always be cleared and replaced with a return 0. The difference between those is the former (check_block()) error sets a 'bad = true' state on the currently scrubbed bit of metadata and the latter (check_sibling()) does not. The latter can of course still set the global corrupted state on the context to track that there is an inconsistency in the fs. Thoughts?
Brian
Quoted 96 lines
(Maybe I'm missing something?)
--D
Quoted 92 lines
Brian
Quoted 82 lines
fs/xfs/scrub/btree.c +55
-0+/* Load the root of the btree. */ + level = cur->bc_nlevels -1 ; + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_block (&bs, level, &ptr, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + +while (level < cur->bc_nlevels) { + block =xfs_btree_get_block (cur, level, &bp); + +if (level ==0 ) { +/* End of leaf, pop back towards the root. */ +if (cur->bc_ptrs[level] > +be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +if (xfs_scrub_should_terminate (&error)) +break ; + + cur->bc_ptrs[level]++; +continue ; + } + +/* End of node, pop back towards the root. */ +if (cur->bc_ptrs[level] >be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +/* Drill another level deeper. */ + pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); + error =xfs_scrub_btree_ptr (&bs, level, pp); +if (error) { + error =0 ; + cur->bc_ptrs[level]++; +continue ; + } + level--; + error =xfs_scrub_btree_block (&bs, level, pp, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, level, &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + } + +out: +return error; }fs/xfs/scrub/common.h +13
-1@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not, -- Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/27] xfs: scrub the shape of a metadata btree
Quoted 108 lines · Brian Foster
Quoted 107 lines · Darrick J. Wong
Quoted 60 lines · Brian Foster
Quoted 18 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)...
Quoted 4 lines
fs/xfs/scrub/btree.c +0
-0...
Quoted 35 lines
fs/xfs/scrub/btree.c +29
-2@@ -109,6 +255,92 @@ xfs_scrub_btree(struct xfs_owner_info *oinfo, void *private) { - xfs_scrub_btree_op_ok(sc, cur, 0, false); -return -EOPNOTSUPP ; + struct xfs_scrub_btree bs = {0}; +union xfs_btree_ptr ptr; +union xfs_btree_ptr *pp; +struct xfs_btree_block *block; +int level; +struct xfs_buf *bp; +int i; +int error =0 ; + +/* Initialize scrub state */ + bs.cur = cur; + bs.scrub_rec = scrub_fn; + bs.oinfo = oinfo; + bs.firstrec = true; + bs.private = private; + bs.sc = sc; +for (i =0 ; i <XFS_BTREE_MAXLEVELS ; i++) + bs.firstkey[i] = true; +INIT_LIST_HEAD (&bs.to_check); + +/* Don't try to check a tree with a height we can't handle. */ +if (!xfs_scrub_btree_check_ok (sc, cur,0 , cur->bc_nlevels >0 && + cur->bc_nlevels <=XFS_BTREE_MAXLEVELS )) + goto out; + +/* Make sure the root isn't in the superblock. */ +if (!(cur->bc_flags &XFS_BTREE_ROOT_IN_INODE )) { + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_ptr (&bs, cur->bc_nlevels, &ptr);Quoted 8 lines
fs/xfs/scrub/btree.c xfs_scrub_btree( · line 290
Quoted 4 lines
fs/xfs/scrub/btree.c +4
-0+if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + } +This is kind of in line with Dave's comments on the previous patch that introduce some of these helpers. I just glanced over them for now because I didn't have enough context to grok the error processing.
(That's been a struggle with this patchset -- some of these helpers don't get used until much further in the patchset. I could have sprinkled them into whichever patch uses them first, but now the hunks are all over the series, I'd have to do more dependency tracking to make sure bisect continues to work, and the frequency of auto-merge failures as I push and pop the stack increase dramatically.)
Quoted 11 lines
FWIW, the btree_op_ok()/btree_check_ok() stuff kind of makes my eyes cross a bit because I can't easily see the logic checks or distinguish between those and error code checks. This is also a bit confusing because it looks like we overload return codes for various things. E.g., we generate
-EFSCORRUPTEDin some cases just so the caller can set the state on the context and clear it, but then we still use the fact that an error _was_ set to control the flow of the task via theop_ok()return value. This makes some of the code flow/decision making logic hard to follow, particularly since some of that state looks like it can be lost.Quoted 8 lines
Case in point.. what happens if say
xfs_btree_increment()returns-EFSCORRUPTEDback toxfs_scrub_btree_block_check_sibling()? It looks to me that the latter callsbtree_op_ok()to set the corrupt state, clears the error code and skips out appropriately.xfs_scrub_btree_block_check_sibling()now returns zero, which potentially bubbles up toxfs_scrub_btree()where we check the error code again. Is it expected that error == 0 here? What is supposed to happen here?Yes, error == 0 is intended here. Given a block B, we want to check that
B->rightsib->leftsib(if the sibling exists at all) point back to B. If thebtree_incrementoperation returns EFSCORRUPTED we don't know if that's because theB->rightsibpoints at something it's not supposed to, or ifB->rightsibpoints at a btree block, but that sibling block is corrupt. Therefore we set the corrupt flag and bubble error == 0 up the
call stack so that we can check the other records in the btree. This
enables those following with ftrace to see everything that scrub thinks is wrong with that piece of metadata.
Quoted 6 lines
Quoted 3 lines
IOWs, we only use error code returns for "runtime error, abort the whole operation immediately".
Ok, so we intentionally have to consume the error here because it doesn't necessarily reflect the corrupted state of the scrubbed block.
Not quite -- while we're examining blocks or otherwise operating on the btree we've been told to scrub, we always want to consume an EFSCORRUPTED error (and set the CORRUPT flag) because we always want to try to check everything, even if we find problems midway through a scan.
This is similar to how gcc will keep processing past the first error to try to report everything that's wrong in the source file instead of bailing out at the first error like it used to do.
Quoted 2 lines
So IIUC, overloading return codes as such means error handling must either return
-EFSCORRUPTEDfor the current object being corrupted,
We /never/ return EFSCORRUPTED to userspace, because we have the OFLAG_CORRUPT flag to indicate any kind of corruption anywhere in this data structure we're checking.
Let's say that a 2-level btree looks like this:
B0
|
+-----+-----+--------+-----+----------------+-------------------+
| | | | | | |
| | | V | | |
| | | someblock | | |
| | | | | |
V V V V V VB1 -> B2 -> B3 ----> B4 -> B5 (badmagic) -> B6 (bad records) -> B7
Here we have a bad pointer in B0 that should point to B4 but now points to something that was never part of B. In B6 we have some incorrect records, and in B5 we have a bad checksum.
First we visit B0. Nothing obviously wrong there, so we proceed with the depth-first search of B. We examine B1 and B2 via pointer[1] and pointer[2], respectively, and find nothing wrong. Now we try pointer[3], which we follow to B3.
Then we get to B3's sibling pointer check. Leftsib is ok, but when we move on to checking rightsib, the xfs_btree_increment returns EFSBADCRC because the pointer[4] in B0 points to a block that isn't in the btree. Here we want to consume the EFSBADCRC, so we set OFLAG_CORRUPT and continue walking the tree.
Next we try to walk pointer[4] in B0 and again hit a EFSBADCRC error. Again we set OFLAG_CORRUPT and continue walking the tree.
Then we try to walk pointer[5] in B0 and encounter B5. The CRC matches, but the magic number is wrong, so we hit EFSCORRUPTED. The block is toast, but we still need to keep walking.
Now we walk pointer[6] and encounter B6. We encounter no operational errors but then we see some incorrect records so we set OFLAG_CORRUPT (it's still set) and continue.
Finally we get to pointer[7], where everything is fine again. If we haven't encountered any operational problems like ENOMEM then we'll return to userspace with OFLAG_CORRUPT set, a return value of zero.
The ftrace buffer will have a report about the operational error trying to walk down pointer[4], another one about B5, record check failures from B6.
(If instead we run out of memory checking B7 then we'll return the ENOMEM to userspace.)
Quoted 40 lines
return some other error for an error in the infrastructure, or clear any
-EFSCORRUPTEDerror generated by checks that don't necessarily mean the current object is corrupted (or too much so to interrupt processing).Quoted 31 lines
Quoted 17 lines
I'm wondering if this could all be made more clear by trying to explicitly separate out operational errors, scrub failures and whatever we want to call the logic that clears an -EFSCORRUPTED/-EFSBADCRC error code but still indicates something happened. :P
For starters, rather than wrap every logic check with
btree_op_check(), could we use explicit logic and let each function update the context based on problems it found? For example, something like the following is much more easy to read for me than the associated logic above:/* Don't try to check a tree with a height we can't handle. */ if (!(cur->bc_nlevels > 0 && cur->bc_nlevels <= XFS_BTREE_MAXLEVELS)) { xfs_scrub_sc_corrupt(...); goto out; }Quoted 2 lines
And of course the context update calls could be factored into an
out_corruptlabel or something where appropriate.Yes, that could be done.
Quoted 8 lines
Beyond that, where we need to identify a bit of metadata is busted to perhaps do something like skip it but not abort (as we may have filtered out an
-EFSCORRUPTED) return code, could we pass a flag down a particular callchain (i.e., think 'bool *bad' or 'int *stat' a la the core btree code)? Then we can still transfer that state back up the chain and the caller(s) can distinguish operational errors from "this thing is corrupted, act accordingly," regardless of how the corruption was detected.Quoted 4 lines
So far I haven't needed to distinguish between "no problems encountered" and "this callchain hit a verifier error so we just set
_CORRUPT" -- scrub always keeps going until it runs out of things to check.
Quoted 6 lines
Ok. This is partly speculation on the above (trying to wrap my head around the error consumption bits as is) and partly to try and see if we can make the flow more readable.
In my mind, this is more clear if return codes are reserved for operational/infrastructure errors
Yes, this is true.
Quoted 1 line
and the corrupted state of a piece of metadata is its own state.
Also true -- this is OFLAG_CORRUPT.
Quoted 3 lines
Using the example above, any
-EFSCORRUPTEDerrors from external calls (xfs_btree_check_block(),xfs_btree_increment(), etc.) would always be cleared and replaced with a return 0.
<nod>
Quoted 3 lines
The difference between those is the former (
check_block()) error sets a 'bad = true' state on the currently scrubbed bit of metadata and the latter (check_sibling()) does not.
Nothing in the scrub code needs to track badness at that fine-grained of a level. When we get to the repair patches you'll see that any kind of error triggers a complete rebuild of the btree index, with absolutely no attempt to touch the existing (inconsistent) btree.
We /could/ return to userspace as soon as we hit the first EFSCORRUPTED or failed check, TBH.
Quoted 2 lines
The latter can of course still set the global corrupted state on the context to track that there is an inconsistency in the fs. Thoughts?
I've wondered if it might be clearer if we did something like:
int error;
bool bailout;
error = xfs_btree_increment(...);
bailout = xfs_scrub_op_error(..., &error);
if (bailout)
return error;
if (ptr->field == BADVAL) {
xfs_scrub_corrupt(...);
return error;
}<shrug>
--D
Quoted 103 lines
Brian
Quoted 96 lines
(Maybe I'm missing something?)
--D
Quoted 92 lines
Brian
Quoted 82 lines
fs/xfs/scrub/btree.c +55
-0+/* Load the root of the btree. */ + level = cur->bc_nlevels -1 ; + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_block (&bs, level, &ptr, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + +while (level < cur->bc_nlevels) { + block =xfs_btree_get_block (cur, level, &bp); + +if (level ==0 ) { +/* End of leaf, pop back towards the root. */ +if (cur->bc_ptrs[level] > +be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +if (xfs_scrub_should_terminate (&error)) +break ; + + cur->bc_ptrs[level]++; +continue ; + } + +/* End of node, pop back towards the root. */ +if (cur->bc_ptrs[level] >be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +/* Drill another level deeper. */ + pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); + error =xfs_scrub_btree_ptr (&bs, level, pp); +if (error) { + error =0 ; + cur->bc_ptrs[level]++; +continue ; + } + level--; + error =xfs_scrub_btree_block (&bs, level, pp, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, level, &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + } + +out: +return error; }fs/xfs/scrub/common.h +13
-1@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not, -- Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/27] xfs: scrub the shape of a metadata btree
Quoted 113 lines · Darrick J. Wong
Quoted 112 lines · Brian Foster
Quoted 110 lines · Darrick J. Wong
Quoted 60 lines · Brian Foster
Quoted 18 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
Create a function that can check the shape of a btree -- each block passes basic inspection and all the pointers look ok. In the next patch we'll add the ability to check the actual keys and records stored within the btree. Add some helper functions so that we report detailed scrub errors in a uniform manner in dmesg. These are helper functions for subsequent patches.
Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_btree.c | 16 +++ fs/xfs/libxfs/xfs_btree.h | 7 + fs/xfs/scrub/btree.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 13 ++ 4 files changed, 268 insertions(+), 4 deletions(-)...
Quoted 4 lines
fs/xfs/scrub/btree.c +0
-0...
Quoted 35 lines
fs/xfs/scrub/btree.c +29
-2@@ -109,6 +255,92 @@ xfs_scrub_btree(struct xfs_owner_info *oinfo, void *private) { - xfs_scrub_btree_op_ok(sc, cur, 0, false); -return -EOPNOTSUPP ; + struct xfs_scrub_btree bs = {0}; +union xfs_btree_ptr ptr; +union xfs_btree_ptr *pp; +struct xfs_btree_block *block; +int level; +struct xfs_buf *bp; +int i; +int error =0 ; + +/* Initialize scrub state */ + bs.cur = cur; + bs.scrub_rec = scrub_fn; + bs.oinfo = oinfo; + bs.firstrec = true; + bs.private = private; + bs.sc = sc; +for (i =0 ; i <XFS_BTREE_MAXLEVELS ; i++) + bs.firstkey[i] = true; +INIT_LIST_HEAD (&bs.to_check); + +/* Don't try to check a tree with a height we can't handle. */ +if (!xfs_scrub_btree_check_ok (sc, cur,0 , cur->bc_nlevels >0 && + cur->bc_nlevels <=XFS_BTREE_MAXLEVELS )) + goto out; + +/* Make sure the root isn't in the superblock. */ +if (!(cur->bc_flags &XFS_BTREE_ROOT_IN_INODE )) { + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_ptr (&bs, cur->bc_nlevels, &ptr);Quoted 8 lines
fs/xfs/scrub/btree.c xfs_scrub_btree( · line 290
Quoted 4 lines
fs/xfs/scrub/btree.c +4
-0+if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + } +This is kind of in line with Dave's comments on the previous patch that introduce some of these helpers. I just glanced over them for now because I didn't have enough context to grok the error processing.
(That's been a struggle with this patchset -- some of these helpers don't get used until much further in the patchset. I could have sprinkled them into whichever patch uses them first, but now the hunks are all over the series, I'd have to do more dependency tracking to make sure bisect continues to work, and the frequency of auto-merge failures as I push and pop the stack increase dramatically.)
Quoted 11 lines
FWIW, the btree_op_ok()/btree_check_ok() stuff kind of makes my eyes cross a bit because I can't easily see the logic checks or distinguish between those and error code checks. This is also a bit confusing because it looks like we overload return codes for various things. E.g., we generate
-EFSCORRUPTEDin some cases just so the caller can set the state on the context and clear it, but then we still use the fact that an error _was_ set to control the flow of the task via theop_ok()return value. This makes some of the code flow/decision making logic hard to follow, particularly since some of that state looks like it can be lost.Quoted 8 lines
Case in point.. what happens if say
xfs_btree_increment()returns-EFSCORRUPTEDback toxfs_scrub_btree_block_check_sibling()? It looks to me that the latter callsbtree_op_ok()to set the corrupt state, clears the error code and skips out appropriately.xfs_scrub_btree_block_check_sibling()now returns zero, which potentially bubbles up toxfs_scrub_btree()where we check the error code again. Is it expected that error == 0 here? What is supposed to happen here?Yes, error == 0 is intended here. Given a block B, we want to check that
B->rightsib->leftsib(if the sibling exists at all) point back to B. If thebtree_incrementoperation returns EFSCORRUPTED we don't know if that's because theB->rightsibpoints at something it's not supposed to, or ifB->rightsibpoints at a btree block, but that sibling block is corrupt. Therefore we set the corrupt flag and bubble error == 0 up the
call stack so that we can check the other records in the btree. This
enables those following with ftrace to see everything that scrub thinks is wrong with that piece of metadata.IOWs, we only use error code returns for "runtime error, abort the whole operation immediately".
Quoted 8 lines
Quoted 2 lines
Ok, so we intentionally have to consume the error here because it doesn't necessarily reflect the corrupted state of the scrubbed block.
Not quite -- while we're examining blocks or otherwise operating on the btree we've been told to scrub, we always want to consume an EFSCORRUPTED error (and set the CORRUPT flag) because we always want to try to check everything, even if we find problems midway through a scan.
Then why don't we consume -EFSCORRUPTED errors from the call to xfs_btree_check_block() in xfs_scrub_btree_block(), but leave it for the caller? Note that the point I'm trying to get at is not to say that we sometimes don't consume -EFSCORRUPTED errors at all, but rather we consume them in different places to implicitly affect the code flow.
In the xfs_btree_check_block() case, my understanding is that we have to leave that one for the caller to consume rather than consume it immediately like we do in the check_sibling() code. If my understand is not correct, what's the difference between those two sites with regard to consuming -EFSCORRUPTED immediately in one and not the other?
Quoted 11 lines
This is similar to how gcc will keep processing past the first error to try to report everything that's wrong in the source file instead of bailing out at the first error like it used to do.
Quoted 2 lines
So IIUC, overloading return codes as such means error handling must either return
-EFSCORRUPTEDfor the current object being corrupted,We /never/ return EFSCORRUPTED to userspace, because we have the
OFLAG_CORRUPTflag to indicate any kind of corruption anywhere in this data structure we're checking.
Understood, I'm not suggesting we'd return -EFSCORRUPTED to userspace.
Quoted 42 lines
Let's say that a 2-level btree looks like this:
B0 | +-----+-----+--------+-----+----------------+-------------------+ | | | | | | | | | | V | | | | | | someblock | | | | | | | | | V V V V V VB1 -> B2 -> B3 ----> B4 -> B5 (badmagic) -> B6 (bad records) -> B7
Here we have a bad pointer in B0 that should point to B4 but now points to something that was never part of B. In B6 we have some incorrect records, and in B5 we have a bad checksum.
First we visit B0. Nothing obviously wrong there, so we proceed with the depth-first search of B. We examine B1 and B2 via pointer[1] and pointer[2], respectively, and find nothing wrong. Now we try pointer[3], which we follow to B3.
Then we get to B3's sibling pointer check. Leftsib is ok, but when we move on to checking rightsib, the
xfs_btree_incrementreturns EFSBADCRC because the pointer[4] in B0 points to a block that isn't in the btree. Here we want to consume the EFSBADCRC, so we setOFLAG_CORRUPTand continue walking the tree.Next we try to walk pointer[4] in B0 and again hit a EFSBADCRC error. Again we set
OFLAG_CORRUPTand continue walking the tree.Then we try to walk pointer[5] in B0 and encounter B5. The CRC matches, but the magic number is wrong, so we hit EFSCORRUPTED. The block is toast, but we still need to keep walking.
Now we walk pointer[6] and encounter B6. We encounter no operational errors but then we see some incorrect records so we set
OFLAG_CORRUPT(it's still set) and continue.Finally we get to pointer[7], where everything is fine again. If we haven't encountered any operational problems like ENOMEM then we'll return to userspace with
OFLAG_CORRUPTset, a return value of zero.
Quoted 7 lines
The ftrace buffer will have a report about the operational error trying to walk down pointer[4], another one about B5, record check failures from B6.
(If instead we run out of memory checking B7 then we'll return the ENOMEM to userspace.)
Got it, thanks. Note that I'm not trying to suggest to deviate from this behavior. It's just a refactoring such that -EFSCORRUPTED is always consumed immediately from any external function that could generate it and is translated into the local scrub state (i.e., corrupted = true and/or OFLAG_CORRUPT, where the latter is a subset of the former). Basically, think of it as instead of never returning -EFSCORRUPTED to userspace, it should not be returned by any scrub function, ever.
Quoted 59 lines
Quoted 40 lines
return some other error for an error in the infrastructure, or clear any
-EFSCORRUPTEDerror generated by checks that don't necessarily mean the current object is corrupted (or too much so to interrupt processing).Quoted 31 lines
Quoted 17 lines
I'm wondering if this could all be made more clear by trying to explicitly separate out operational errors, scrub failures and whatever we want to call the logic that clears an -EFSCORRUPTED/-EFSBADCRC error code but still indicates something happened. :P
For starters, rather than wrap every logic check with
btree_op_check(), could we use explicit logic and let each function update the context based on problems it found? For example, something like the following is much more easy to read for me than the associated logic above:/* Don't try to check a tree with a height we can't handle. */ if (!(cur->bc_nlevels > 0 && cur->bc_nlevels <= XFS_BTREE_MAXLEVELS)) { xfs_scrub_sc_corrupt(...); goto out; }Quoted 2 lines
And of course the context update calls could be factored into an
out_corruptlabel or something where appropriate.Yes, that could be done.
Quoted 8 lines
Beyond that, where we need to identify a bit of metadata is busted to perhaps do something like skip it but not abort (as we may have filtered out an
-EFSCORRUPTED) return code, could we pass a flag down a particular callchain (i.e., think 'bool *bad' or 'int *stat' a la the core btree code)? Then we can still transfer that state back up the chain and the caller(s) can distinguish operational errors from "this thing is corrupted, act accordingly," regardless of how the corruption was detected.Quoted 4 lines
So far I haven't needed to distinguish between "no problems encountered" and "this callchain hit a verifier error so we just set
_CORRUPT" -- scrub always keeps going until it runs out of things to check.Quoted 6 lines
Ok. This is partly speculation on the above (trying to wrap my head around the error consumption bits as is) and partly to try and see if we can make the flow more readable.
In my mind, this is more clear if return codes are reserved for operational/infrastructure errors
Yes, this is true.
Quoted 1 line
and the corrupted state of a piece of metadata is its own state.
Also true -- this is
OFLAG_CORRUPT.Quoted 3 lines
Using the example above, any
-EFSCORRUPTEDerrors from external calls (xfs_btree_check_block(),xfs_btree_increment(), etc.) would always be cleared and replaced with a return 0.<nod>
Quoted 9 lines
Quoted 3 lines
The difference between those is the former (
check_block()) error sets a 'bad = true' state on the currently scrubbed bit of metadata and the latter (check_sibling()) does not.Nothing in the scrub code needs to track badness at that fine-grained of a level. When we get to the repair patches you'll see that any kind of error triggers a complete rebuild of the btree index, with absolutely no attempt to touch the existing (inconsistent) btree.
Perhaps, but that's not really the point. My argument is that it simplifies the logic and thus makes the code more clear. :)
Quoted 3 lines
We /could/ return to userspace as soon as we hit the first EFSCORRUPTED or failed check, TBH.
That's a separate question that I haven't really thought much about yet tbh. I suppose I could see use for a oneshot option or something for users who may want to exit quickly in favor of offline repair rather than wait for a thorough scan.
Quoted 11 lines
Quoted 2 lines
The latter can of course still set the global corrupted state on the context to track that there is an inconsistency in the fs. Thoughts?
I've wondered if it might be clearer if we did something like:
int error;
bool bailout;error =
xfs_btree_increment(...);
bailout =xfs_scrub_op_error(..., &error);
if (bailout)
Quoted 7 lines
return error;if (ptr->field == BADVAL) { xfs_scrub_corrupt(...); return error; }
It still appears confusing to me because isn't whatever we were going to do that depends on the xfs_btree_increment() call now bogus if the increment itself fails, for whatever reason? When would you not bail out of here on increment failure?
Using a more simple example of xfs_scrub_btree_block(), I'd expect it to look something like this:
xfs_scrub_btree_block(..., bool *bad, ...)
{
...
error = xfs_btree_lookup_get_block(bs->cur, ...);
if (error)
goto out_err;
xfs_btree_get_block(bs->cur, ...);
error = xfs_btree_check_block(bs->cur, ...);
if (error)
goto out_err;
error = xfs_scrub_btree_block_check_siblings(bs, ...);
ASSERT(error != -EFSCORRUPTED);
return error;out_err:
if (error == -EFSCORRUPTED) {
*bad = true;
error = 0;
}
return error;
}check_siblings() doesn't need bad because it's checking the siblings. It just sets OFLAG_CORRUPT if it finds corruption or returns a non corruption error if one occurs. The caller sets OFLAG_CORRUPT if bad == true or bails if error != 0.
Brian
Quoted 107 lines
<shrug>
--D
Quoted 103 lines
Brian
Quoted 96 lines
(Maybe I'm missing something?)
--D
Quoted 92 lines
Brian
Quoted 82 lines
fs/xfs/scrub/btree.c +55
-0+/* Load the root of the btree. */ + level = cur->bc_nlevels -1 ; + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + error =xfs_scrub_btree_block (&bs, level, &ptr, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, cur->bc_nlevels -1 , &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + +while (level < cur->bc_nlevels) { + block =xfs_btree_get_block (cur, level, &bp); + +if (level ==0 ) { +/* End of leaf, pop back towards the root. */ +if (cur->bc_ptrs[level] > +be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +if (xfs_scrub_should_terminate (&error)) +break ; + + cur->bc_ptrs[level]++; +continue ; + } + +/* End of node, pop back towards the root. */ +if (cur->bc_ptrs[level] >be16_to_cpu (block->bb_numrecs)) { +if (level < cur->bc_nlevels -1 ) + cur->bc_ptrs[level +1 ]++; + level++; +continue ; + } + +/* Drill another level deeper. */ + pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); + error =xfs_scrub_btree_ptr (&bs, level, pp); +if (error) { + error =0 ; + cur->bc_ptrs[level]++; +continue ; + } + level--; + error =xfs_scrub_btree_block (&bs, level, pp, &block, &bp); +if (!xfs_scrub_btree_op_ok (sc, cur, level, &error)) + goto out; + + cur->bc_ptrs[level] =1 ; + } + +out: +return error; }fs/xfs/scrub/common.h +13
-1@@ -20,6 +20,19 @@#ifndef __XFS_SCRUB_COMMON_H__#define __XFS_SCRUB_COMMON_H__ +/* Should we end the scrub early? */ +static inline bool +xfs_scrub_should_terminate ( +int *error) +{ +if (fatal_signal_pending (current)) { +if (*error ==0 ) + *error = -EAGAIN ; +return true; + } +return false; +} +/* * Grab a transaction. If we're going to repair something, we need to * ensure there's enough reservation to make all the changes. If not, -- Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v10 9/27 xfs: scrub btree keys and records
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add to the btree scrubber the ability to check that the keys and records are in the right order and actually call out to our record iterator to do actual checking of the records.
--- fs/xfs/scrub/btree.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/trace.h | 44 +++++++++++++++++++ 2 files changed, 159 insertions(+)
fs/xfs/scrub/btree.c +115 -0
@@ -94,6 +94,104 @@ xfs_scrub_btree_check_ok(return fs_ok; } +/* +* Make sure this record is in order and doesn't stray outside of the parent +* keys. +*/ +STATIC int +xfs_scrub_btree_rec ( +struct xfs_scrub_btree *bs) +{ +struct xfs_btree_cur *cur = bs->cur; +union xfs_btree_rec *rec; +union xfs_btree_key key; +union xfs_btree_key hkey; +union xfs_btree_key *keyp; +struct xfs_btree_block *block; +struct xfs_btree_block *keyblock; +struct xfs_buf *bp; + + block =xfs_btree_get_block (cur,0 , &bp); + rec =xfs_btree_rec_addr (cur, cur->bc_ptrs[0 ], block); + +trace_xfs_scrub_btree_rec (bs->sc, cur,0 ); + +/* If this isn't the first record, are they in order? */ +xfs_scrub_btree_check_ok (bs->sc, cur,0 , bs->firstrec || + cur->bc_ops->recs_inorder (cur, &bs->lastrec, rec)); + bs->firstrec = false; +memcpy (&bs->lastrec, rec, cur->bc_ops->rec_len); + +if (cur->bc_nlevels ==1 ) +return 0 ; + +/* Is this at least as large as the parent low key? */ + cur->bc_ops->init_key_from_rec (&key, rec); + keyblock =xfs_btree_get_block (cur,1 , &bp); + keyp =xfs_btree_key_addr (cur, cur->bc_ptrs[1 ], keyblock); +xfs_scrub_btree_check_ok (bs->sc, cur,1 , + cur->bc_ops->diff_two_keys (cur, &key, keyp) >=0 ); + +if (!(cur->bc_flags &XFS_BTREE_OVERLAPPING )) +return 0 ; + +/* Is this no larger than the parent high key? */ + cur->bc_ops->init_high_key_from_rec (&hkey, rec); + keyp =xfs_btree_high_key_addr (cur, cur->bc_ptrs[1 ], keyblock); +xfs_scrub_btree_check_ok (bs->sc, cur,1 , + cur->bc_ops->diff_two_keys (cur, keyp, &hkey) >=0 ); + +return 0 ; +} + +/* +* Make sure this key is in order and doesn't stray outside of the parent +* keys. +*/ +STATIC int +xfs_scrub_btree_key ( +struct xfs_scrub_btree *bs, +int level) +{ +struct xfs_btree_cur *cur = bs->cur; +union xfs_btree_key *key; +union xfs_btree_key *keyp; +struct xfs_btree_block *block; +struct xfs_btree_block *keyblock; +struct xfs_buf *bp; + + block =xfs_btree_get_block (cur, level, &bp); + key =xfs_btree_key_addr (cur, cur->bc_ptrs[level], block); + +trace_xfs_scrub_btree_key (bs->sc, cur, level); + +/* If this isn't the first key, are they in order? */ +xfs_scrub_btree_check_ok (bs->sc, cur, level, bs->firstkey[level] || + cur->bc_ops->keys_inorder (cur, &bs->lastkey[level], key)); + bs->firstkey[level] = false; +memcpy (&bs->lastkey[level], key, cur->bc_ops->key_len); + +if (level +1 >= cur->bc_nlevels) +return 0 ; + +/* Is this at least as large as the parent low key? */ + keyblock =xfs_btree_get_block (cur, level +1 , &bp); + keyp =xfs_btree_key_addr (cur, cur->bc_ptrs[level +1 ], keyblock); +xfs_scrub_btree_check_ok (bs->sc, cur, level, + cur->bc_ops->diff_two_keys (cur, key, keyp) >=0 ); + +if (!(cur->bc_flags &XFS_BTREE_OVERLAPPING )) +return 0 ; + +/* Is this no larger than the parent high key? */ + key =xfs_btree_high_key_addr (cur, cur->bc_ptrs[level], block); + keyp =xfs_btree_high_key_addr (cur, cur->bc_ptrs[level +1 ], keyblock); +xfs_scrub_btree_check_ok (bs->sc, cur, level, + cur->bc_ops->diff_two_keys (cur, keyp, key) >=0 ); + +return 0 ; +} +/* Check a btree pointer. */ static int xfs_scrub_btree_ptr(
@@ -258,6 +356,7 @@ xfs_scrub_btree(struct xfs_scrub_btree bs = {0 };union xfs_btree_ptr ptr;union xfs_btree_ptr *pp; +union xfs_btree_rec *recp;struct xfs_btree_block *block;int level;struct xfs_buf *bp;
@@ -310,6 +409,17 @@ xfs_scrub_btree(continue ; } +/* Records in order for scrub? */ + error =xfs_scrub_btree_rec (&bs); +if (error) + goto out; + +/* Call out to the record checker. */ + recp =xfs_btree_rec_addr (cur, cur->bc_ptrs[0 ], block); + error = bs.scrub_rec (&bs, recp); +if (error <0 || + error ==XFS_BTREE_QUERY_RANGE_ABORT ) +break ;if (xfs_scrub_should_terminate (&error))break ;
@@ -325,6 +435,11 @@ xfs_scrub_btree(continue ; } +/* Keys in order for scrub? */ + error =xfs_scrub_btree_key (&bs, level); +if (error) + goto out; +/* Drill another level deeper. */ pp =xfs_btree_ptr_addr (cur, cur->bc_ptrs[level], block); error =xfs_scrub_btree_ptr (&bs, level, pp);
fs/xfs/scrub/trace.h +44 -0
50 lines not on this page · raw message
PATCH v10 10/27 xfs: create helpers to scan an allocation group
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add some helpers to enable us to lock an AG's headers, create btree cursors for all btrees in that allocation group, and clean up afterwards.
--- fs/xfs/scrub/common.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 10 +++ fs/xfs/scrub/scrub.c | 4 + fs/xfs/scrub/scrub.h | 21 ++++++ 4 files changed, 208 insertions(+)
fs/xfs/scrub/common.c +173 -0
@@ -44,6 +44,7 @@#include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" +#include "scrub/btree.h" /* Common code for the metadata scrubbers. */
@@ -290,6 +291,178 @@ xfs_scrub_check_thoroughness(return fs_ok; } +/* +* AG scrubbing +* +* These helpers facilitate locking an allocation group's header +* buffers, setting up cursors for all btrees that are present, and +* cleaning everything up once we're through. +*/ + +/* Grab all the headers for an AG. */ +int +xfs_scrub_ag_read_headers ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +struct xfs_buf **agi, +struct xfs_buf **agf, +struct xfs_buf **agfl) +{ +struct xfs_mount *mp = sc->mp; +int error; + + error =xfs_ialloc_read_agi (mp, sc->tp, agno, agi); +if (error) + goto out; + + error =xfs_alloc_read_agf (mp, sc->tp, agno,0 , agf); +if (error) + goto out; +if (!*agf) { + error = -ENOMEM ; + goto out; + } + + error =xfs_alloc_read_agfl (mp, sc->tp, agno, agfl); +if (error) + goto out; + +out: +return error; +} + +/* Release all the AG btree cursors. */ +void +xfs_scrub_ag_btcur_free ( +struct xfs_scrub_ag *sa) +{ +if (sa->refc_cur) +xfs_btree_del_cursor (sa->refc_cur,XFS_BTREE_ERROR ); +if (sa->rmap_cur) +xfs_btree_del_cursor (sa->rmap_cur,XFS_BTREE_ERROR ); +if (sa->fino_cur) +xfs_btree_del_cursor (sa->fino_cur,XFS_BTREE_ERROR ); +if (sa->ino_cur) +xfs_btree_del_cursor (sa->ino_cur,XFS_BTREE_ERROR ); +if (sa->cnt_cur) +xfs_btree_del_cursor (sa->cnt_cur,XFS_BTREE_ERROR ); +if (sa->bno_cur) +xfs_btree_del_cursor (sa->bno_cur,XFS_BTREE_ERROR ); + + sa->refc_cur =NULL ; + sa->rmap_cur =NULL ; + sa->fino_cur =NULL ; + sa->ino_cur =NULL ; + sa->bno_cur =NULL ; + sa->cnt_cur =NULL ; +} + +/* Initialize all the btree cursors for an AG. */ +int +xfs_scrub_ag_btcur_init ( +struct xfs_scrub_context *sc, +struct xfs_scrub_ag *sa) +{ +struct xfs_mount *mp = sc->mp; +xfs_agnumber_t agno = sa->agno; + +if (sa->agf_bp) { +/* Set up a bnobt cursor for cross-referencing. */ + sa->bno_cur =xfs_allocbt_init_cursor (mp, sc->tp, sa->agf_bp, + agno,XFS_BTNUM_BNO ); +if (!sa->bno_cur) + goto err; + +/* Set up a cntbt cursor for cross-referencing. */ + sa->cnt_cur =xfs_allocbt_init_cursor (mp, sc->tp, sa->agf_bp, + agno,XFS_BTNUM_CNT ); +if (!sa->cnt_cur) + goto err; + } + +/* Set up a inobt cursor for cross-referencing. */ +if (sa->agi_bp) { + sa->ino_cur =xfs_inobt_init_cursor (mp, sc->tp, sa->agi_bp, + agno,XFS_BTNUM_INO ); +if (!sa->ino_cur) + goto err; + } + +/* Set up a finobt cursor for cross-referencing. */ +if (sa->agi_bp &&xfs_sb_version_hasfinobt (&mp->m_sb)) { + sa->fino_cur =xfs_inobt_init_cursor (mp, sc->tp, sa->agi_bp, + agno,XFS_BTNUM_FINO ); +if (!sa->fino_cur) + goto err; + } + +/* Set up a rmapbt cursor for cross-referencing. */ +if (sa->agf_bp &&xfs_sb_version_hasrmapbt (&mp->m_sb)) { + sa->rmap_cur =xfs_rmapbt_init_cursor (mp, sc->tp, sa->agf_bp, + agno); +if (!sa->rmap_cur) + goto err; + } + +/* Set up a refcountbt cursor for cross-referencing. */ +if (sa->agf_bp &&xfs_sb_version_hasreflink (&mp->m_sb)) { + sa->refc_cur =xfs_refcountbt_init_cursor (mp, sc->tp, + sa->agf_bp, agno,NULL ); +if (!sa->refc_cur) + goto err; + } + +return 0 ; +err: +return -ENOMEM ; +} + +/* Release the AG header context and btree cursors. */ +void +xfs_scrub_ag_free ( +struct xfs_scrub_context *sc, +struct xfs_scrub_ag *sa) +{ +xfs_scrub_ag_btcur_free (sa); +if (sa->agfl_bp) { +xfs_trans_brelse (sc->tp, sa->agfl_bp); + sa->agfl_bp =NULL ; + } +if (sa->agf_bp) { +xfs_trans_brelse (sc->tp, sa->agf_bp); + sa->agf_bp =NULL ; + } +if (sa->agi_bp) { +xfs_trans_brelse (sc->tp, sa->agi_bp); + sa->agi_bp =NULL ; + } + sa->agno =NULLAGNUMBER ; +} + +/* +* For scrub, grab the AGI and the AGF headers, in that order. Locking +* order requires us to get the AGI before the AGF. We use the +* transaction to avoid deadlocking on crosslinked metadata buffers; +* either the caller passes one in (bmap scrub) or we have to create a +* transaction ourselves. +*/ +int +xfs_scrub_ag_init ( +struct xfs_scrub_context *sc, +xfs_agnumber_t agno, +struct xfs_scrub_ag *sa) +{ +int error; + + sa->agno = agno; + error =xfs_scrub_ag_read_headers (sc, agno, &sa->agi_bp, + &sa->agf_bp, &sa->agfl_bp); +if (error) +return error; + +return xfs_scrub_ag_btcur_init (sc, sa); +} +/* Per-scrubber setup functions */ /* Set us up with a transaction and an empty context. */
fs/xfs/scrub/common.h +10 -0
@@ -93,4 +93,14 @@ bool xfs_scrub_check_thoroughness(struct xfs_scrub_context *sc, bool fs_ok);/* Setup functions */ int xfs_scrub_setup_fs (struct xfs_scrub_context *sc,struct xfs_inode *ip); +void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); +int xfs_scrub_ag_init (struct xfs_scrub_context *sc,xfs_agnumber_t agno, +struct xfs_scrub_ag *sa); +int xfs_scrub_ag_read_headers (struct xfs_scrub_context *sc,xfs_agnumber_t agno, +struct xfs_buf **agi,struct xfs_buf **agf, +struct xfs_buf **agfl); +void xfs_scrub_ag_btcur_free (struct xfs_scrub_ag *sa); +int xfs_scrub_ag_btcur_init (struct xfs_scrub_context *sc, +struct xfs_scrub_ag *sa); +#endif /* __XFS_SCRUB_COMMON_H__ */
fs/xfs/scrub/scrub.c +4 -0
@@ -44,6 +44,8 @@#include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" +#include "scrub/scrub.h" +#include "scrub/btree.h" /* * Online Scrub and Repair
@@ -145,6 +147,7 @@ xfs_scrub_teardown(struct xfs_scrub_context *sc, int error) { + xfs_scrub_ag_free(sc, &sc->sa);if (sc->tp) {xfs_trans_cancel (sc->tp); sc->tp =NULL ;
@@ -225,6 +228,7 @@ xfs_scrub_metadata( sc.sm = sm; sc.ops = ops; sc.try_harder = try_harder; + sc.sa.agno =NULLAGNUMBER ; error = sc.ops->setup (&sc, ip);if (error) goto out_teardown;
fs/xfs/scrub/scrub.h +21 -0
@@ -29,6 +29,24 @@ struct xfs_scrub_meta_ops {bool (*has)(struct xfs_sb *); }; +/* Buffer pointers and btree cursors for an entire AG. */ +struct xfs_scrub_ag { +xfs_agnumber_t agno; + +/* AG btree roots */ +struct xfs_buf *agf_bp; +struct xfs_buf *agfl_bp; +struct xfs_buf *agi_bp; + +/* AG btrees */ +struct xfs_btree_cur *bno_cur; +struct xfs_btree_cur *cnt_cur; +struct xfs_btree_cur *ino_cur; +struct xfs_btree_cur *fino_cur; +struct xfs_btree_cur *rmap_cur; +struct xfs_btree_cur *refc_cur; +}; +struct xfs_scrub_context {/* General scrub state. */ struct xfs_mount *mp;
@@ -37,6 +55,9 @@ struct xfs_scrub_context {struct xfs_trans *tp;struct xfs_inode *ip;bool try_harder; + +/* State tracking for single-AG operations. */ +struct xfs_scrub_ag sa; };/* Metadata scrubbers */
PATCH v10 11/27 xfs: scrub the backup superblocks
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Ensure that the geometry presented in the backup superblocks matches the primary superblock so that repair can recover the filesystem if that primary gets corrupted.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 fs/xfs/scrub/agheader.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 2 fs/xfs/scrub/scrub.c | 4 + fs/xfs/scrub/scrub.h | 1 6 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/agheader.c
fs/xfs/Makefile +1 -0
@@ -146,6 +146,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ + agheader.o \ btree.o \ common.o \ scrub.o \
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -484,9 +484,10 @@ struct xfs_scrub_metadata {/* Scrub subcommands. */ #define XFS_SCRUB_TYPE_TEST 0/* presence test ioctl */ +#define XFS_SCRUB_TYPE_SB 1/* superblock */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 1 +#define XFS_SCRUB_TYPE_NR 2/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/agheader.c new file +326 -0
326 lines not on this page · raw message
fs/xfs/scrub/common.h +2 -0
@@ -92,6 +92,8 @@ bool xfs_scrub_check_thoroughness(struct xfs_scrub_context *sc, bool fs_ok);/* Setup functions */ int xfs_scrub_setup_fs (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_ag_header (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/scrub.c +4 -0
@@ -162,6 +162,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_fs, .scrub = xfs_scrub_tester, }, + {/* superblock */ + .setup = xfs_scrub_setup_ag_header, + .scrub = xfs_scrub_superblock, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -62,5 +62,6 @@ struct xfs_scrub_context {/* Metadata scrubbers */ int xfs_scrub_tester (struct xfs_scrub_context *sc); +int xfs_scrub_superblock (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 12/27 xfs: scrub AGF and AGFL
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the block references in the AGF and AGFL headers to make sure they make sense.
--- fs/xfs/libxfs/xfs_fs.h | 4 + fs/xfs/scrub/agheader.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.c | 60 +++++++++++++ fs/xfs/scrub/common.h | 6 + fs/xfs/scrub/scrub.c | 8 ++ fs/xfs/scrub/scrub.h | 2 6 files changed, 299 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_fs.h +3 -1
@@ -485,9 +485,11 @@ struct xfs_scrub_metadata {/* Scrub subcommands. */ #define XFS_SCRUB_TYPE_TEST 0/* presence test ioctl */ #define XFS_SCRUB_TYPE_SB 1/* superblock */ +#define XFS_SCRUB_TYPE_AGF 2/* AG free header */ +#define XFS_SCRUB_TYPE_AGFL 3/* AG free list */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 2 +#define XFS_SCRUB_TYPE_NR 4/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/agheader.c +220 -0
229 lines not on this page · raw message
fs/xfs/scrub/common.c +60 -0
66 lines not on this page · raw message
fs/xfs/scrub/common.h +6 -0
@@ -104,5 +104,11 @@ int xfs_scrub_ag_read_headers(struct xfs_scrub_context *sc, xfs_agnumber_t agno,void xfs_scrub_ag_btcur_free (struct xfs_scrub_ag *sa);int xfs_scrub_ag_btcur_init (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); +int xfs_scrub_load_ag_headers (struct xfs_scrub_context *sc,xfs_agnumber_t agno, +unsigned int type); +int xfs_scrub_walk_agfl (struct xfs_scrub_context *sc, +int (*fn)(struct xfs_scrub_context *,xfs_agblock_t bno, +void *), +void *priv);#endif /* __XFS_SCRUB_COMMON_H__ */
fs/xfs/scrub/scrub.c +8 -0
@@ -166,6 +166,14 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_ag_header, .scrub = xfs_scrub_superblock, }, + {/* agf */ + .setup = xfs_scrub_setup_ag_header, + .scrub = xfs_scrub_agf, + }, + {/* agfl */ + .setup = xfs_scrub_setup_ag_header, + .scrub = xfs_scrub_agfl, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +2 -0
@@ -63,5 +63,7 @@ struct xfs_scrub_context {/* Metadata scrubbers */ int xfs_scrub_tester (struct xfs_scrub_context *sc);int xfs_scrub_superblock (struct xfs_scrub_context *sc); +int xfs_scrub_agf (struct xfs_scrub_context *sc); +int xfs_scrub_agfl (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 13/27 xfs: scrub the AGI
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add a forgotten check to the AGI verifier, then wire up the scrub infrastructure to check the AGI contents.
--- fs/xfs/libxfs/xfs_fs.h | 3 +- fs/xfs/scrub/agheader.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.c | 6 ++- fs/xfs/scrub/scrub.c | 4 ++ fs/xfs/scrub/scrub.h | 1 + 5 files changed, 99 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -487,9 +487,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_SB 1/* superblock */ #define XFS_SCRUB_TYPE_AGF 2/* AG free header */ #define XFS_SCRUB_TYPE_AGFL 3/* AG free list */ +#define XFS_SCRUB_TYPE_AGI 4/* AG inode header */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 4 +#define XFS_SCRUB_TYPE_NR 5/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/agheader.c +88 -0
91 lines not on this page · raw message
fs/xfs/scrub/common.c +4 -2
@@ -499,12 +499,14 @@ xfs_scrub_load_ag_headers(struct xfs_mount *mp = sc->mp;int error; -ASSERT (type ==XFS_SCRUB_TYPE_AGF || type ==XFS_SCRUB_TYPE_AGFL ); +ASSERT (type ==XFS_SCRUB_TYPE_AGF || type ==XFS_SCRUB_TYPE_AGFL || + type ==XFS_SCRUB_TYPE_AGI );memset (&sc->sa,0 ,sizeof (sc->sa)); sc->sa.agno = agno; error =xfs_scrub_load_ag_header (sc,XFS_AGI_DADDR (mp), - &sc->sa.agi_bp, &xfs_agi_buf_ops, false); + &sc->sa.agi_bp, &xfs_agi_buf_ops, + type ==XFS_SCRUB_TYPE_AGI );if (error)return error;
fs/xfs/scrub/scrub.c +4 -0
@@ -174,6 +174,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_ag_header, .scrub = xfs_scrub_agfl, }, + {/* agi */ + .setup = xfs_scrub_setup_ag_header, + .scrub = xfs_scrub_agi, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -65,5 +65,6 @@ int xfs_scrub_tester(struct xfs_scrub_context *sc);int xfs_scrub_superblock (struct xfs_scrub_context *sc);int xfs_scrub_agf (struct xfs_scrub_context *sc);int xfs_scrub_agfl (struct xfs_scrub_context *sc); +int xfs_scrub_agi (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 14/27 xfs: scrub free space btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the extent records free space btrees to ensure that the values look sane.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 4 +- fs/xfs/scrub/alloc.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.c | 16 +++++++ fs/xfs/scrub/common.h | 6 +++ fs/xfs/scrub/scrub.c | 8 ++++ fs/xfs/scrub/scrub.h | 2 + 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/alloc.c
fs/xfs/Makefile +1 -0
@@ -147,6 +147,7 @@ ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) xfs-y += $(addprefix scrub/, \ trace.o \ agheader.o \ + alloc.o \ btree.o \ common.o \ scrub.o \
fs/xfs/libxfs/xfs_fs.h +3 -1
@@ -488,9 +488,11 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_AGF 2/* AG free header */ #define XFS_SCRUB_TYPE_AGFL 3/* AG free list */ #define XFS_SCRUB_TYPE_AGI 4/* AG inode header */ +#define XFS_SCRUB_TYPE_BNOBT 5/* freesp by block btree */ +#define XFS_SCRUB_TYPE_CNTBT 6/* freesp by length btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 5 +#define XFS_SCRUB_TYPE_NR 7/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/alloc.c new file +108 -0
108 lines not on this page · raw message
fs/xfs/scrub/common.c +16 -0
@@ -536,3 +536,19 @@ xfs_scrub_setup_fs(return xfs_scrub_trans_alloc (sc->sm, sc->mp, &M_RES (sc->mp)->tr_itruncate,0 ,0 ,0 , &sc->tp); } + +/* Set us up with AG headers and btree cursors. */ +int +xfs_scrub_setup_ag_btree ( +struct xfs_scrub_context *sc, +struct xfs_inode *ip, +bool force_log) +{ +int error; + + error =xfs_scrub_setup_ag_header (sc, ip); +if (error) +return error; + +return xfs_scrub_ag_init (sc, sc->sm->sm_agno, &sc->sa); +}
fs/xfs/scrub/common.h +6 -0
@@ -94,6 +94,9 @@ bool xfs_scrub_check_thoroughness(struct xfs_scrub_context *sc, bool fs_ok);int xfs_scrub_setup_fs (struct xfs_scrub_context *sc,struct xfs_inode *ip);int xfs_scrub_setup_ag_header (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_ag_allocbt (struct xfs_scrub_context *sc, +struct xfs_inode *ip); +void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
@@ -111,4 +114,7 @@ int xfs_scrub_walk_agfl(struct xfs_scrub_context *sc, void *), void *priv); +int xfs_scrub_setup_ag_btree (struct xfs_scrub_context *sc, +struct xfs_inode *ip,bool force_log); +#endif /* __XFS_SCRUB_COMMON_H__ */
fs/xfs/scrub/scrub.c +8 -0
@@ -178,6 +178,14 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_ag_header, .scrub = xfs_scrub_agi, }, + {/* bnobt */ + .setup = xfs_scrub_setup_ag_allocbt, + .scrub = xfs_scrub_bnobt, + }, + {/* cntbt */ + .setup = xfs_scrub_setup_ag_allocbt, + .scrub = xfs_scrub_cntbt, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +2 -0
@@ -66,5 +66,7 @@ int xfs_scrub_superblock(struct xfs_scrub_context *sc);int xfs_scrub_agf (struct xfs_scrub_context *sc);int xfs_scrub_agfl (struct xfs_scrub_context *sc);int xfs_scrub_agi (struct xfs_scrub_context *sc); +int xfs_scrub_bnobt (struct xfs_scrub_context *sc); +int xfs_scrub_cntbt (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 15/27 xfs: scrub inode btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the records of the inode btrees to make sure that the values make sense given the inode records themselves.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_format.h | 2 fs/xfs/libxfs/xfs_fs.h | 4 - fs/xfs/scrub/common.h | 2 fs/xfs/scrub/ialloc.c | 332 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 9 + fs/xfs/scrub/scrub.h | 2 7 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 fs/xfs/scrub/ialloc.c
fs/xfs/Makefile +1 -0
@@ -150,6 +150,7 @@ xfs-y += $(addprefix scrub/, \ alloc.o \ btree.o \ common.o \ + ialloc.o \ scrub.o \ ) endif
fs/xfs/libxfs/xfs_format.h +1 -1
@@ -518,7 +518,7 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); } -static inline int xfs_sb_version_hasfinobt (xfs_sb_t *sbp) +static inline bool xfs_sb_version_hasfinobt (xfs_sb_t *sbp) {return (XFS_SB_VERSION_NUM (sbp) ==XFS_SB_VERSION_5 ) && (sbp->sb_features_ro_compat &XFS_SB_FEAT_RO_COMPAT_FINOBT );
fs/xfs/libxfs/xfs_fs.h +3 -1
@@ -490,9 +490,11 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_AGI 4/* AG inode header */ #define XFS_SCRUB_TYPE_BNOBT 5/* freesp by block btree */ #define XFS_SCRUB_TYPE_CNTBT 6/* freesp by length btree */ +#define XFS_SCRUB_TYPE_INOBT 7/* inode btree */ +#define XFS_SCRUB_TYPE_FINOBT 8/* free inode btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 7 +#define XFS_SCRUB_TYPE_NR 9/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +2 -0
@@ -96,6 +96,8 @@ int xfs_scrub_setup_ag_header(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_ag_allocbt (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_ag_iallocbt (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa);
fs/xfs/scrub/ialloc.c new file +332 -0
332 lines not on this page · raw message
fs/xfs/scrub/scrub.c +9 -0
@@ -186,6 +186,15 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_ag_allocbt, .scrub = xfs_scrub_cntbt, }, + {/* inobt */ + .setup = xfs_scrub_setup_ag_iallocbt, + .scrub = xfs_scrub_inobt, + }, + {/* finobt */ + .setup = xfs_scrub_setup_ag_iallocbt, + .scrub = xfs_scrub_finobt, + .has = xfs_sb_version_hasfinobt, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +2 -0
@@ -68,5 +68,7 @@ int xfs_scrub_agfl(struct xfs_scrub_context *sc);int xfs_scrub_agi (struct xfs_scrub_context *sc);int xfs_scrub_bnobt (struct xfs_scrub_context *sc);int xfs_scrub_cntbt (struct xfs_scrub_context *sc); +int xfs_scrub_inobt (struct xfs_scrub_context *sc); +int xfs_scrub_finobt (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 16/27 xfs: scrub rmap btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the reverse mapping records to make sure that the contents make sense.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 + fs/xfs/scrub/common.h | 2 + fs/xfs/scrub/rmap.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 5 ++ fs/xfs/scrub/scrub.h | 1 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/rmap.c
fs/xfs/Makefile +1 -0
@@ -151,6 +151,7 @@ xfs-y += $(addprefix scrub/, \ btree.o \ common.o \ ialloc.o \ + rmap.o \ scrub.o \ ) endif
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -492,9 +492,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_CNTBT 6/* freesp by length btree */ #define XFS_SCRUB_TYPE_INOBT 7/* inode btree */ #define XFS_SCRUB_TYPE_FINOBT 8/* free inode btree */ +#define XFS_SCRUB_TYPE_RMAPBT 9/* reverse mapping btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 9 +#define XFS_SCRUB_TYPE_NR 10/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +2 -0
@@ -98,6 +98,8 @@ int xfs_scrub_setup_ag_allocbt(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_ag_iallocbt (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_ag_rmapbt (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa);
fs/xfs/scrub/rmap.c new file +130 -0
130 lines not on this page · raw message
fs/xfs/scrub/scrub.c +5 -0
@@ -195,6 +195,11 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .scrub = xfs_scrub_finobt, .has = xfs_sb_version_hasfinobt, }, + {/* rmapbt */ + .setup = xfs_scrub_setup_ag_rmapbt, + .scrub = xfs_scrub_rmapbt, + .has = xfs_sb_version_hasrmapbt, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -70,5 +70,6 @@ int xfs_scrub_bnobt(struct xfs_scrub_context *sc);int xfs_scrub_cntbt (struct xfs_scrub_context *sc);int xfs_scrub_inobt (struct xfs_scrub_context *sc);int xfs_scrub_finobt (struct xfs_scrub_context *sc); +int xfs_scrub_rmapbt (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 17/27 xfs: scrub refcount btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Plumb in the pieces necessary to check the refcount btree. If rmap is available, check the reference count by performing an interval query against the rmapbt.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 + fs/xfs/scrub/common.h | 2 + fs/xfs/scrub/refcount.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 5 ++ fs/xfs/scrub/scrub.h | 1 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/refcount.c
fs/xfs/Makefile +1 -0
@@ -151,6 +151,7 @@ xfs-y += $(addprefix scrub/, \ btree.o \ common.o \ ialloc.o \ + refcount.o \ rmap.o \ scrub.o \ )
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -493,9 +493,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_INOBT 7/* inode btree */ #define XFS_SCRUB_TYPE_FINOBT 8/* free inode btree */ #define XFS_SCRUB_TYPE_RMAPBT 9/* reverse mapping btree */ +#define XFS_SCRUB_TYPE_REFCNTBT 10/* reference count btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 10 +#define XFS_SCRUB_TYPE_NR 11/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +2 -0
@@ -100,6 +100,8 @@ int xfs_scrub_setup_ag_iallocbt(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_ag_rmapbt (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_ag_refcountbt (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa);
fs/xfs/scrub/refcount.c new file +99 -0
99 lines not on this page · raw message
fs/xfs/scrub/scrub.c +5 -0
@@ -200,6 +200,11 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .scrub = xfs_scrub_rmapbt, .has = xfs_sb_version_hasrmapbt, }, + {/* refcountbt */ + .setup = xfs_scrub_setup_ag_refcountbt, + .scrub = xfs_scrub_refcountbt, + .has = xfs_sb_version_hasreflink, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -71,5 +71,6 @@ int xfs_scrub_cntbt(struct xfs_scrub_context *sc);int xfs_scrub_inobt (struct xfs_scrub_context *sc);int xfs_scrub_finobt (struct xfs_scrub_context *sc);int xfs_scrub_rmapbt (struct xfs_scrub_context *sc); +int xfs_scrub_refcountbt (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 18/27 xfs: scrub inodes
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scrub the fields within an inode.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 fs/xfs/scrub/common.c | 49 +++++++ fs/xfs/scrub/common.h | 3 fs/xfs/scrub/inode.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 17 ++ fs/xfs/scrub/scrub.h | 2 7 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 fs/xfs/scrub/inode.c
fs/xfs/Makefile +1 -0
@@ -151,6 +151,7 @@ xfs-y += $(addprefix scrub/, \ btree.o \ common.o \ ialloc.o \ + inode.o \ refcount.o \ rmap.o \ scrub.o \
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -494,9 +494,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_FINOBT 8/* free inode btree */ #define XFS_SCRUB_TYPE_RMAPBT 9/* reverse mapping btree */ #define XFS_SCRUB_TYPE_REFCNTBT 10/* reference count btree */ +#define XFS_SCRUB_TYPE_INODE 11/* inode record */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 11 +#define XFS_SCRUB_TYPE_NR 12/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.c +49 -0
58 lines not on this page · raw message
fs/xfs/scrub/common.h +3 -0
@@ -102,6 +102,8 @@ int xfs_scrub_setup_ag_rmapbt(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_ag_refcountbt (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_inode (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa);
@@ -122,5 +124,6 @@ int xfs_scrub_walk_agfl(struct xfs_scrub_context *sc,int xfs_scrub_setup_ag_btree (struct xfs_scrub_context *sc,struct xfs_inode *ip,bool force_log); +int xfs_scrub_get_inode (struct xfs_scrub_context *sc,struct xfs_inode *ip_in);#endif /* __XFS_SCRUB_COMMON_H__ */
fs/xfs/scrub/inode.c new file +342 -0
342 lines not on this page · raw message
fs/xfs/scrub/scrub.c +15 -2
@@ -30,6 +30,8 @@#include "xfs_trans.h" #include "xfs_sb.h" #include "xfs_inode.h" +#include "xfs_icache.h" +#include "xfs_itable.h" #include "xfs_alloc.h" #include "xfs_alloc_btree.h" #include "xfs_bmap.h"
@@ -145,6 +147,7 @@ xfs_scrub_tester( STATIC intxfs_scrub_teardown (struct xfs_scrub_context *sc, +struct xfs_inode *ip_in,int error) {xfs_scrub_ag_free (sc, &sc->sa);
@@ -152,6 +155,12 @@ xfs_scrub_teardown(xfs_trans_cancel (sc->tp); sc->tp =NULL ; } +if (sc->ip) { +xfs_iunlock (sc->ip, sc->ilock_flags); +if (sc->ip != ip_in) +iput (VFS_I (sc->ip)); + sc->ip =NULL ; + }return error; }
@@ -205,6 +214,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .scrub = xfs_scrub_refcountbt, .has = xfs_sb_version_hasreflink, }, + {/* inode record */ + .setup = xfs_scrub_setup_inode, + .scrub = xfs_scrub_inode, + }, };/* Dispatch metadata scrubbing. */
@@ -284,7 +297,7 @@ xfs_scrub_metadata(* Tear down everything we hold, then set up again with * preparation for worst-case scenarios. */ - error =xfs_scrub_teardown (&sc,0 ); + error =xfs_scrub_teardown (&sc, ip,0 );if (error) goto out; try_harder = true;
@@ -297,7 +310,7 @@ xfs_scrub_metadata(xfs_alert_ratelimited (mp,"Corruption detected during scrub." ); out_teardown: - error =xfs_scrub_teardown (&sc, error); + error =xfs_scrub_teardown (&sc, ip, error); out:trace_xfs_scrub_done (ip, sm, error);return error;
fs/xfs/scrub/scrub.h +2 -0
@@ -54,6 +54,7 @@ struct xfs_scrub_context {const struct xfs_scrub_meta_ops *ops;struct xfs_trans *tp;struct xfs_inode *ip; +uint ilock_flags;bool try_harder;/* State tracking for single-AG operations. */
@@ -72,5 +73,6 @@ int xfs_scrub_inobt(struct xfs_scrub_context *sc);int xfs_scrub_finobt (struct xfs_scrub_context *sc);int xfs_scrub_rmapbt (struct xfs_scrub_context *sc);int xfs_scrub_refcountbt (struct xfs_scrub_context *sc); +int xfs_scrub_inode (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 19/27 xfs: scrub inode block mappings
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scrub an individual inode's block mappings to make sure they make sense.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 5 + fs/xfs/scrub/bmap.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 5 + fs/xfs/scrub/scrub.c | 12 ++ fs/xfs/scrub/scrub.h | 3 6 files changed, 382 insertions(+), 2 deletions(-) create mode 100644 fs/xfs/scrub/bmap.c
fs/xfs/Makefile +1 -0
@@ -148,6 +148,7 @@ xfs-y += $(addprefix scrub/, \ trace.o \ agheader.o \ alloc.o \ + bmap.o \ btree.o \ common.o \ ialloc.o \
fs/xfs/libxfs/xfs_fs.h +4 -1
@@ -495,9 +495,12 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_RMAPBT 9/* reverse mapping btree */ #define XFS_SCRUB_TYPE_REFCNTBT 10/* reference count btree */ #define XFS_SCRUB_TYPE_INODE 11/* inode record */ +#define XFS_SCRUB_TYPE_BMBTD 12/* data fork block mapping */ +#define XFS_SCRUB_TYPE_BMBTA 13/* attr fork block mapping */ +#define XFS_SCRUB_TYPE_BMBTC 14/* CoW fork block mapping */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 12 +#define XFS_SCRUB_TYPE_NR 15/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/bmap.c new file +358 -0
358 lines not on this page · raw message
fs/xfs/scrub/common.h +4 -1
@@ -104,7 +104,10 @@ int xfs_scrub_setup_ag_refcountbt(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_inode (struct xfs_scrub_context *sc,struct xfs_inode *ip); - +int xfs_scrub_setup_inode_bmap (struct xfs_scrub_context *sc, +struct xfs_inode *ip); +int xfs_scrub_setup_inode_bmap_data (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/scrub.c +12 -0
@@ -218,6 +218,18 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_inode, .scrub = xfs_scrub_inode, }, + { /* inode data fork */ + .setup = xfs_scrub_setup_inode_bmap_data, + .scrub = xfs_scrub_bmap_data, + }, + { /* inode attr fork */ + .setup = xfs_scrub_setup_inode_bmap, + .scrub = xfs_scrub_bmap_attr, + }, + { /* inode CoW fork */ + .setup = xfs_scrub_setup_inode_bmap, + .scrub = xfs_scrub_bmap_cow, + }, }; /* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +3 -0
@@ -74,5 +74,8 @@ int xfs_scrub_finobt(struct xfs_scrub_context *sc);int xfs_scrub_rmapbt (struct xfs_scrub_context *sc);int xfs_scrub_refcountbt (struct xfs_scrub_context *sc);int xfs_scrub_inode (struct xfs_scrub_context *sc); +int xfs_scrub_bmap_data (struct xfs_scrub_context *sc); +int xfs_scrub_bmap_attr (struct xfs_scrub_context *sc); +int xfs_scrub_bmap_cow (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 20/27 xfs: scrub directory/attribute btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Provide a way to check the shape and scrub the hashes and records in a directory or extended attribute btree. These are helper functions for the directory & attribute scrubbers in subsequent patches.
--- fs/xfs/Makefile | 1 fs/xfs/scrub/dabtree.c | 539 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/dabtree.h | 52 +++++ 3 files changed, 592 insertions(+) create mode 100644 fs/xfs/scrub/dabtree.c create mode 100644 fs/xfs/scrub/dabtree.h
fs/xfs/Makefile +1 -0
@@ -151,6 +151,7 @@ xfs-y += $(addprefix scrub/, \ bmap.o \ btree.o \ common.o \ + dabtree.o \ ialloc.o \ inode.o \ refcount.o \
fs/xfs/scrub/dabtree.c new file +539 -0
539 lines not on this page · raw message
fs/xfs/scrub/dabtree.h new file +52 -0
52 lines not on this page · raw message
PATCH v10 21/27 xfs: scrub directory metadata
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scrub the hash tree and all the entries in a directory.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 fs/xfs/scrub/common.c | 33 +++++ fs/xfs/scrub/common.h | 4 + fs/xfs/scrub/dir.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 4 + fs/xfs/scrub/scrub.h | 1 7 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/dir.c
fs/xfs/Makefile +1 -0
@@ -152,6 +152,7 @@ xfs-y += $(addprefix scrub/, \ btree.o \ common.o \ dabtree.o \ + dir.o \ ialloc.o \ inode.o \ refcount.o \
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -498,9 +498,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_BMBTD 12/* data fork block mapping */ #define XFS_SCRUB_TYPE_BMBTA 13/* attr fork block mapping */ #define XFS_SCRUB_TYPE_BMBTC 14/* CoW fork block mapping */ +#define XFS_SCRUB_TYPE_DIR 15/* directory */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 15 +#define XFS_SCRUB_TYPE_NR 16/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.c +33 -0
@@ -601,3 +601,36 @@ xfs_scrub_get_inode( sc->ip = ips;return 0 ; } + +/* Set us up to scrub a file's contents. */ +int +xfs_scrub_setup_inode_contents ( +struct xfs_scrub_context *sc, +struct xfs_inode *ip, +unsigned int resblks) +{ +struct xfs_mount *mp = sc->mp; +int error; + + error =xfs_scrub_get_inode (sc, ip); +if (error) +return error; + +/* Got the inode, lock it and we're ready to go. */ + sc->ilock_flags =XFS_IOLOCK_EXCL |XFS_MMAPLOCK_EXCL ; +xfs_ilock (sc->ip, sc->ilock_flags); + error =xfs_scrub_trans_alloc (sc->sm, mp, &M_RES (mp)->tr_itruncate, + resblks,0 ,0 , &sc->tp); +if (error) + goto out_unlock; + sc->ilock_flags |=XFS_ILOCK_EXCL ; +xfs_ilock (sc->ip,XFS_ILOCK_EXCL ); + +return 0 ; +out_unlock: +xfs_iunlock (sc->ip, sc->ilock_flags); +if (sc->ip != ip) +iput (VFS_I (sc->ip)); + sc->ip =NULL ; +return error; +}
fs/xfs/scrub/common.h +4 -0
@@ -108,6 +108,8 @@ int xfs_scrub_setup_inode_bmap(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_inode_bmap_data (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_directory (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
@@ -128,5 +130,7 @@ int xfs_scrub_walk_agfl(struct xfs_scrub_context *sc,int xfs_scrub_setup_ag_btree (struct xfs_scrub_context *sc,struct xfs_inode *ip,bool force_log);int xfs_scrub_get_inode (struct xfs_scrub_context *sc,struct xfs_inode *ip_in); +int xfs_scrub_setup_inode_contents (struct xfs_scrub_context *sc, +struct xfs_inode *ip,unsigned int resblks);#endif /* __XFS_SCRUB_COMMON_H__ */
fs/xfs/scrub/dir.c new file +289 -0
289 lines not on this page · raw message
fs/xfs/scrub/scrub.c +4 -0
@@ -230,6 +230,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_inode_bmap, .scrub = xfs_scrub_bmap_cow, }, + {/* directory */ + .setup = xfs_scrub_setup_directory, + .scrub = xfs_scrub_directory, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -77,5 +77,6 @@ int xfs_scrub_inode(struct xfs_scrub_context *sc);int xfs_scrub_bmap_data (struct xfs_scrub_context *sc);int xfs_scrub_bmap_attr (struct xfs_scrub_context *sc);int xfs_scrub_bmap_cow (struct xfs_scrub_context *sc); +int xfs_scrub_directory (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 22/27 xfs: scrub directory freespace
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the free space information in a directory.
--- fs/xfs/scrub/dir.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+)
fs/xfs/scrub/dir.c +339 -0
@@ -229,6 +229,340 @@ xfs_scrub_dir_rec(return error; } +/* Is this free entry either in the bestfree or smaller than all of them? */ +static inline bool +xfs_scrub_directory_check_free_entry ( +struct xfs_dir2_data_free *bf, +struct xfs_dir2_data_unused *dup) +{ +struct xfs_dir2_data_free *dfp; +unsigned int smallest; + + smallest =-1U ; +for (dfp = &bf[0 ]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT ]; dfp++) { +if (dfp->offset && +be16_to_cpu (dfp->length) ==be16_to_cpu (dup->length)) +return true; +if (smallest <be16_to_cpu (dfp->length)) + smallest =be16_to_cpu (dfp->length); + } + +return be16_to_cpu (dup->length) <= smallest; +} + +/* Check free space info in a directory data block. */ +STATIC int +xfs_scrub_directory_data_bestfree ( +struct xfs_scrub_context *sc, +xfs_dablk_t lblk, +bool is_block) +{ +struct xfs_dir2_data_unused *dup; +struct xfs_dir2_data_free *dfp; +struct xfs_buf *bp; +struct xfs_dir2_data_free *bf; +struct xfs_mount *mp = sc->mp; +char *ptr; +char *endptr; +u16 tag; +int newlen; +int offset; +int error; + +if (is_block) { +/* dir block format */ +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, lblk == +XFS_B_TO_FSBT (mp,XFS_DIR2_DATA_OFFSET )); + error =xfs_dir3_block_read (sc->tp, sc->ip, &bp); + }else { +/* dir data format */ + error =xfs_dir3_data_read (sc->tp, sc->ip, lblk,-1 , &bp); + } +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) + goto out; + +/* Do the bestfrees correspond to actual free space? */ + bf = sc->ip->d_ops->data_bestfree_p (bp->b_addr); +for (dfp = &bf[0 ]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT ]; dfp++) { + offset =be16_to_cpu (dfp->offset); +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + offset <BBTOB (bp->b_length)) || !offset) +continue ; + dup = (struct xfs_dir2_data_unused *)(bp->b_addr + offset); + tag =be16_to_cpu (*xfs_dir2_data_unused_tag_p (dup)); + +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + dup->freetag == +cpu_to_be16 (XFS_DIR2_DATA_FREE_TAG ) && +be16_to_cpu (dup->length) == +be16_to_cpu (dfp->length) && + tag == ((char *)dup - (char *)bp->b_addr)); + } + +/* Make sure the bestfrees are actually the best free spaces. */ + ptr = (char *)sc->ip->d_ops->data_entry_p (bp->b_addr); +if (is_block) { +struct xfs_dir2_block_tail *btp; + + btp =xfs_dir2_block_tail_p (sc->mp->m_dir_geo, bp->b_addr); + endptr = (char *)xfs_dir2_block_leaf_p (btp); + }else + endptr = (char *)bp->b_addr +BBTOB (bp->b_length); +while (ptr < endptr) { + dup = (struct xfs_dir2_data_unused *)ptr; +/* Skip real entries */ +if (dup->freetag !=cpu_to_be16 (XFS_DIR2_DATA_FREE_TAG )) { +struct xfs_dir2_data_entry *dep; + + dep = (struct xfs_dir2_data_entry *)ptr; + newlen = sc->ip->d_ops->data_entsize (dep->namelen); +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + newlen >0 )) + goto out_buf; + ptr += newlen; +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + ptr <= endptr); +continue ; + } + +/* Spot check this free entry */ + tag =be16_to_cpu (*xfs_dir2_data_unused_tag_p (dup)); +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + tag == ((char *)dup - (char *)bp->b_addr)); + +/* +* Either this entry is a bestfree or it's smaller than +* any of the bestfrees. +*/ +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, +xfs_scrub_directory_check_free_entry (bf, dup)); + +/* Move on. */ + newlen =be16_to_cpu (dup->length); +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + newlen >0 )) + goto out_buf; + ptr += newlen; +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + ptr <= endptr); + } +out_buf: +xfs_trans_brelse (sc->tp, bp); +out: +return error; +} + +/* Is this the longest free entry in the block? */ +static inline bool +xfs_scrub_directory_check_freesp ( +struct xfs_inode *dp, +struct xfs_buf *dbp, +unsigned int len) +{ +struct xfs_dir2_data_free *bf; +struct xfs_dir2_data_free *dfp; +unsigned int longest =0 ; +int offset; + + bf = dp->d_ops->data_bestfree_p (dbp->b_addr); +for (dfp = &bf[0 ]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT ]; dfp++) { + offset =be16_to_cpu (dfp->offset); +if (!offset) +continue ; +if (longest <be16_to_cpu (dfp->length)) + longest =be16_to_cpu (dfp->length); + } + +return longest == len; +} + +/* Check free space info in a directory leaf1 block. */ +STATIC int +xfs_scrub_directory_leaf1_bestfree ( +struct xfs_scrub_context *sc, +struct xfs_da_args *args, +xfs_dablk_t lblk) +{ +struct xfs_dir2_leaf_tail *ltp; +struct xfs_buf *dbp; +struct xfs_buf *bp; +struct xfs_mount *mp = sc->mp; +__be16 *bestp; +__u16 best; +int i; +int error; + +/* Read the free space block */ + error =xfs_dir3_leaf_read (sc->tp, sc->ip, lblk,-1 , &bp); +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) + goto out; + +/* Check all the entries. */ + ltp =xfs_dir2_leaf_tail_p (mp->m_dir_geo, bp->b_addr); + bestp =xfs_dir2_leaf_bests_p (ltp); +for (i =0 ; i <be32_to_cpu (ltp->bestcount); i++, bestp++) { + best =be16_to_cpu (*bestp); +if (best ==NULLDATAOFF ) +continue ; + error =xfs_dir3_data_read (sc->tp, sc->ip, + i * args->geo->fsbcount,-1 , &dbp); +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) +continue ; +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, +xfs_scrub_directory_check_freesp (sc->ip, dbp, + best)); +xfs_trans_brelse (sc->tp, dbp); + } +out: +return error; +} + +/* Check free space info in a directory freespace block. */ +STATIC int +xfs_scrub_directory_free_bestfree ( +struct xfs_scrub_context *sc, +struct xfs_da_args *args, +xfs_dablk_t lblk) +{ +struct xfs_dir3_icfree_hdr freehdr; +struct xfs_buf *dbp; +struct xfs_buf *bp; +__be16 *bestp; +__be16 best; +int i; +int error; + +/* Read the free space block */ + error =xfs_dir2_free_read (sc->tp, sc->ip, lblk, &bp); +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) + goto out; + +/* Check all the entries. */ + sc->ip->d_ops->free_hdr_from_disk (&freehdr, bp->b_addr); + bestp = sc->ip->d_ops->free_bests_p (bp->b_addr); +for (i =0 ; i < freehdr.nvalid; i++, bestp++) { + best =be16_to_cpu (*bestp); +if (best ==NULLDATAOFF ) +continue ; + error =xfs_dir3_data_read (sc->tp, sc->ip, + (freehdr.firstdb + i) * args->geo->fsbcount, +-1 , &dbp); +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) +continue ; +xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, +xfs_scrub_directory_check_freesp (sc->ip, dbp, + best)); +xfs_trans_brelse (sc->tp, dbp); + } +out: +return error; +} + +/* Check free space information in directories. */ +STATIC int +xfs_scrub_directory_blocks ( +struct xfs_scrub_context *sc) +{ +struct xfs_bmbt_irec got; +struct xfs_da_args args; +struct xfs_ifork *ifp; +struct xfs_mount *mp = sc->mp; +xfs_fileoff_t leaf_lblk; +xfs_fileoff_t free_lblk; +xfs_fileoff_t lblk; +xfs_extnum_t idx; +bool found; +int is_block =0 ; +int error; + +/* Ignore local format directories. */ +if (sc->ip->i_d.di_format !=XFS_DINODE_FMT_EXTENTS && + sc->ip->i_d.di_format !=XFS_DINODE_FMT_BTREE ) +return 0 ; + + ifp =XFS_IFORK_PTR (sc->ip,XFS_DATA_FORK ); + lblk =XFS_B_TO_FSB (mp,XFS_DIR2_DATA_OFFSET ); + leaf_lblk =XFS_B_TO_FSB (mp,XFS_DIR2_LEAF_OFFSET ); + free_lblk =XFS_B_TO_FSB (mp,XFS_DIR2_FREE_OFFSET ); + +/* Is this a block dir? */ + args.dp = sc->ip; + args.geo = mp->m_dir_geo; + args.trans = sc->tp; + error =xfs_dir2_isblock (&args, &is_block); +if (!xfs_scrub_fblock_op_ok (sc,XFS_DATA_FORK , lblk, &error)) + goto out; + +/* Iterate all the data extents in the directory... */ + found =xfs_iext_lookup_extent (sc->ip, ifp, lblk, &idx, &got); +while (found) { +/* No more data blocks... */ +if (got.br_startoff >= leaf_lblk) +break ; + +/* Check each data block's bestfree data */ +for (lblk =roundup ((xfs_dablk_t )got.br_startoff, + args.geo->fsbcount); + lblk < got.br_startoff + got.br_blockcount; + lblk += args.geo->fsbcount) { + error =xfs_scrub_directory_data_bestfree (sc, lblk, + is_block); +if (error) + goto out; + } + + found =xfs_iext_get_extent (ifp, ++idx, &got); + } + +/* Look for a leaf1 block, which has free info. */ +if (xfs_iext_lookup_extent (sc->ip, ifp, leaf_lblk, &idx, &got) && + got.br_startoff == leaf_lblk && + got.br_blockcount == args.geo->fsbcount && + !xfs_iext_get_extent (ifp, ++idx, &got)) { +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + !is_block)) + goto not_leaf1; + error =xfs_scrub_directory_leaf1_bestfree (sc, &args, + leaf_lblk); +if (error) + goto out; + } +not_leaf1: + +/* Scan for free blocks */ + lblk = free_lblk; + found =xfs_iext_lookup_extent (sc->ip, ifp, lblk, &idx, &got); +while (found) { +/* +* Dirs can't have blocks mapped above 2^32. +* Single-block dirs shouldn't even be here. +*/ + lblk = got.br_startoff; +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + !(lblk & ~((1ULL <<32 ) -1ULL )))) + goto out; +if (!xfs_scrub_fblock_check_ok (sc,XFS_DATA_FORK , lblk, + !is_block)) + goto nextfree; + +/* Check each dir free block's bestfree data */ +for (lblk =roundup ((xfs_dablk_t )got.br_startoff, + args.geo->fsbcount); + lblk < got.br_startoff + got.br_blockcount; + lblk += args.geo->fsbcount) { + error =xfs_scrub_directory_free_bestfree (sc, &args, + lblk); +if (error) + goto out; + } + +nextfree: + found =xfs_iext_get_extent (ifp, ++idx, &got); + } +out: +return error; +} +/* Scrub a whole directory. */ int xfs_scrub_directory(
@@ -255,6 +589,11 @@ xfs_scrub_directory(if (error)return error; +/* Check the freespace. */ + error =xfs_scrub_directory_blocks (sc); +if (error) +return error; +/* * Check that every dirent we see can also be looked up by hash. * Userspace usually asks for a 32k buffer, so we will too.
PATCH v10 23/27 xfs: scrub extended attributes
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scrub the hash tree, keys, and values in an extended attribute structure. Refactor the attribute code to use the transaction if the caller supplied one to avoid buffer deadocks.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 - fs/xfs/scrub/attr.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 2 fs/xfs/scrub/scrub.c | 8 ++ fs/xfs/scrub/scrub.h | 2 6 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/attr.c
fs/xfs/Makefile +1 -0
@@ -148,6 +148,7 @@ xfs-y += $(addprefix scrub/, \ trace.o \ agheader.o \ alloc.o \ + attr.o \ bmap.o \ btree.o \ common.o \
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -499,9 +499,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_BMBTA 13/* attr fork block mapping */ #define XFS_SCRUB_TYPE_BMBTC 14/* CoW fork block mapping */ #define XFS_SCRUB_TYPE_DIR 15/* directory */ +#define XFS_SCRUB_TYPE_XATTR 16/* extended attribute */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 16 +#define XFS_SCRUB_TYPE_NR 17/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/attr.c new file +210 -0
210 lines not on this page · raw message
fs/xfs/scrub/common.h +2 -0
@@ -110,6 +110,8 @@ int xfs_scrub_setup_inode_bmap_data(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_directory (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_xattr (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/scrub.c +8 -0
@@ -161,6 +161,10 @@ xfs_scrub_teardown(iput (VFS_I (sc->ip)); sc->ip =NULL ; } +if (sc->buf) { +kmem_free (sc->buf); + sc->buf =NULL ; + }return error; }
@@ -234,6 +238,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_directory, .scrub = xfs_scrub_directory, }, + {/* extended attributes */ + .setup = xfs_scrub_setup_xattr, + .scrub = xfs_scrub_xattr, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +2 -0
@@ -54,6 +54,7 @@ struct xfs_scrub_context {const struct xfs_scrub_meta_ops *ops;struct xfs_trans *tp;struct xfs_inode *ip; +void *buf;uint ilock_flags;bool try_harder;
@@ -78,5 +79,6 @@ int xfs_scrub_bmap_data(struct xfs_scrub_context *sc);int xfs_scrub_bmap_attr (struct xfs_scrub_context *sc);int xfs_scrub_bmap_cow (struct xfs_scrub_context *sc);int xfs_scrub_directory (struct xfs_scrub_context *sc); +int xfs_scrub_xattr (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 24/27 xfs: scrub symbolic links
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create the infrastructure to scrub symbolic link data.
--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_fs.h | 3 +- fs/xfs/scrub/common.h | 2 + fs/xfs/scrub/scrub.c | 4 ++ fs/xfs/scrub/scrub.h | 1 + fs/xfs/scrub/symlink.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/symlink.c
fs/xfs/Makefile +1 -0
@@ -159,5 +159,6 @@ xfs-y += $(addprefix scrub/, \ refcount.o \ rmap.o \ scrub.o \ + symlink.o \ ) endif
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -500,9 +500,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_BMBTC 14/* CoW fork block mapping */ #define XFS_SCRUB_TYPE_DIR 15/* directory */ #define XFS_SCRUB_TYPE_XATTR 16/* extended attribute */ +#define XFS_SCRUB_TYPE_SYMLINK 17/* symbolic link */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 17 +#define XFS_SCRUB_TYPE_NR 18/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +2 -0
@@ -112,6 +112,8 @@ int xfs_scrub_setup_directory(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_xattr (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_symlink (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/scrub.c +4 -0
@@ -242,6 +242,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_xattr, .scrub = xfs_scrub_xattr, }, + {/* symbolic link */ + .setup = xfs_scrub_setup_symlink, + .scrub = xfs_scrub_symlink, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -80,5 +80,6 @@ int xfs_scrub_bmap_attr(struct xfs_scrub_context *sc);int xfs_scrub_bmap_cow (struct xfs_scrub_context *sc);int xfs_scrub_directory (struct xfs_scrub_context *sc);int xfs_scrub_xattr (struct xfs_scrub_context *sc); +int xfs_scrub_symlink (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
fs/xfs/scrub/symlink.c new file +92 -0
92 lines not on this page · raw message
PATCH v10 25/27 xfs: scrub parent pointers
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scrub parent pointers, sort of. For directories, we can ride the '..' entry up to the parent to confirm that there's at most one dentry that points back to this directory.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 - fs/xfs/scrub/common.h | 2 fs/xfs/scrub/parent.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 4 + fs/xfs/scrub/scrub.h | 1 6 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/parent.c
fs/xfs/Makefile +1 -0
@@ -156,6 +156,7 @@ xfs-y += $(addprefix scrub/, \ dir.o \ ialloc.o \ inode.o \ + parent.o \ refcount.o \ rmap.o \ scrub.o \
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -501,9 +501,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_DIR 15/* directory */ #define XFS_SCRUB_TYPE_XATTR 16/* extended attribute */ #define XFS_SCRUB_TYPE_SYMLINK 17/* symbolic link */ +#define XFS_SCRUB_TYPE_PARENT 18/* parent pointers */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 18 +#define XFS_SCRUB_TYPE_NR 19/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +2 -0
@@ -114,6 +114,8 @@ int xfs_scrub_setup_xattr(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_symlink (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_parent (struct xfs_scrub_context *sc, +struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/parent.c new file +262 -0
262 lines not on this page · raw message
fs/xfs/scrub/scrub.c +4 -0
@@ -246,6 +246,10 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_symlink, .scrub = xfs_scrub_symlink, }, + {/* parent pointers */ + .setup = xfs_scrub_setup_parent, + .scrub = xfs_scrub_parent, + }, };/* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -81,5 +81,6 @@ int xfs_scrub_bmap_cow(struct xfs_scrub_context *sc);int xfs_scrub_directory (struct xfs_scrub_context *sc);int xfs_scrub_xattr (struct xfs_scrub_context *sc);int xfs_scrub_symlink (struct xfs_scrub_context *sc); +int xfs_scrub_parent (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 26/27 xfs: scrub realtime bitmap/summary
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Perform simple tests of the realtime bitmap and summary.
--- fs/xfs/Makefile | 2 + fs/xfs/libxfs/xfs_format.h | 5 ++ fs/xfs/libxfs/xfs_fs.h | 4 +- fs/xfs/scrub/common.h | 1 fs/xfs/scrub/rtbitmap.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 15 +++++++ fs/xfs/scrub/scrub.h | 2 + 7 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/rtbitmap.c
fs/xfs/Makefile +2 -0
@@ -162,4 +162,6 @@ xfs-y += $(addprefix scrub/, \ scrub.o \ symlink.o \ ) + +xfs-$(CONFIG_XFS_RT) += scrub/rtbitmap.o endif
fs/xfs/libxfs/xfs_format.h +5 -0
@@ -315,6 +315,11 @@ static inline bool xfs_sb_good_version(struct xfs_sb *sbp)return false; } +static inline bool xfs_sb_version_hasrealtime (struct xfs_sb *sbp) +{ +return sbp->sb_rblocks >0 ; +} +/* * Detect a mismatched features2 field. Older kernels read/wrote * this into the wrong slot, so to be safe we keep them in sync.
fs/xfs/libxfs/xfs_fs.h +3 -1
@@ -502,9 +502,11 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_XATTR 16/* extended attribute */ #define XFS_SCRUB_TYPE_SYMLINK 17/* symbolic link */ #define XFS_SCRUB_TYPE_PARENT 18/* parent pointers */ +#define XFS_SCRUB_TYPE_RTBITMAP 19/* realtime bitmap */ +#define XFS_SCRUB_TYPE_RTSUM 20/* realtime summary */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 19 +#define XFS_SCRUB_TYPE_NR 21/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +1 -0
@@ -116,6 +116,7 @@ int xfs_scrub_setup_symlink(struct xfs_scrub_context *sc, struct xfs_inode *ip);int xfs_scrub_setup_parent (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_rt (struct xfs_scrub_context *sc,struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/rtbitmap.c new file +98 -0
98 lines not on this page · raw message
fs/xfs/scrub/scrub.c +15 -0
@@ -250,6 +250,21 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { .setup = xfs_scrub_setup_parent, .scrub = xfs_scrub_parent, }, +#ifdef CONFIG_XFS_RT + { /* realtime bitmap */ + .setup = xfs_scrub_setup_rt, + .scrub = xfs_scrub_rtbitmap, + .has = xfs_sb_version_hasrealtime, + }, + { /* realtime summary */ + .setup = xfs_scrub_setup_rt, + .scrub = xfs_scrub_rtsummary, + .has = xfs_sb_version_hasrealtime, + }, +#else + { NULL }, + { NULL }, +#endif }; /* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +2 -0
@@ -82,5 +82,7 @@ int xfs_scrub_directory(struct xfs_scrub_context *sc);int xfs_scrub_xattr (struct xfs_scrub_context *sc);int xfs_scrub_symlink (struct xfs_scrub_context *sc);int xfs_scrub_parent (struct xfs_scrub_context *sc); +int xfs_scrub_rtbitmap (struct xfs_scrub_context *sc); +int xfs_scrub_rtsummary (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH v10 27/27 xfs: scrub quota information
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Perform some quick sanity testing of the disk quota information.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 5 + fs/xfs/scrub/common.h | 1 fs/xfs/scrub/quota.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 18 +++ fs/xfs/scrub/scrub.h | 1 6 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/scrub/quota.c
fs/xfs/Makefile +1 -0
@@ -164,4 +164,5 @@ xfs-y += $(addprefix scrub/, \ ) xfs-$(CONFIG_XFS_RT) += scrub/rtbitmap.o +xfs-$(CONFIG_XFS_QUOTA) += scrub/quota.o endif
fs/xfs/libxfs/xfs_fs.h +4 -1
@@ -504,9 +504,12 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_PARENT 18/* parent pointers */ #define XFS_SCRUB_TYPE_RTBITMAP 19/* realtime bitmap */ #define XFS_SCRUB_TYPE_RTSUM 20/* realtime summary */ +#define XFS_SCRUB_TYPE_UQUOTA 21/* user quotas */ +#define XFS_SCRUB_TYPE_GQUOTA 22/* group quotas */ +#define XFS_SCRUB_TYPE_PQUOTA 23/* project quotas */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 21 +#define XFS_SCRUB_TYPE_NR 24/* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
fs/xfs/scrub/common.h +1 -0
@@ -117,6 +117,7 @@ int xfs_scrub_setup_symlink(struct xfs_scrub_context *sc,int xfs_scrub_setup_parent (struct xfs_scrub_context *sc,struct xfs_inode *ip);int xfs_scrub_setup_rt (struct xfs_scrub_context *sc,struct xfs_inode *ip); +int xfs_scrub_setup_quota (struct xfs_scrub_context *sc,struct xfs_inode *ip);void xfs_scrub_ag_free (struct xfs_scrub_context *sc,struct xfs_scrub_ag *sa); int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
fs/xfs/scrub/quota.c new file +258 -0
258 lines not on this page · raw message
fs/xfs/scrub/scrub.c +18 -0
@@ -265,6 +265,24 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = { { NULL }, { NULL }, #endif +#ifdef CONFIG_XFS_QUOTA + { /* user quota */ + .setup = xfs_scrub_setup_quota, + .scrub = xfs_scrub_quota, + }, + { /* group quota */ + .setup = xfs_scrub_setup_quota, + .scrub = xfs_scrub_quota, + }, + { /* project quota */ + .setup = xfs_scrub_setup_quota, + .scrub = xfs_scrub_quota, + }, +#else + { NULL }, + { NULL }, + { NULL }, +#endif }; /* Dispatch metadata scrubbing. */
fs/xfs/scrub/scrub.h +1 -0
@@ -84,5 +84,6 @@ int xfs_scrub_symlink(struct xfs_scrub_context *sc);int xfs_scrub_parent (struct xfs_scrub_context *sc);int xfs_scrub_rtbitmap (struct xfs_scrub_context *sc);int xfs_scrub_rtsummary (struct xfs_scrub_context *sc); +int xfs_scrub_quota (struct xfs_scrub_context *sc);#endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH 1/1 man: describe the metadata scrubbing ioctl
In reply to Darrick J. WongDocument the XFS-specific metadata scrub/repair ioctl's behavior, arguments, and side effects. Dump this in xfsprogs for lack of a better destination.
--- man/Makefile | 2 man/man2/ioctl_xfs_scrub_metadata.2 | 298 +++++++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 man/man2/ioctl_xfs_scrub_metadata.2
man/Makefile +1 -1
@@ -5,7 +5,7 @@ TOPDIR = .. include $(TOPDIR)/include/builddefs -SUBDIRS = man3 man5 man8 +SUBDIRS = man2 man3 man5 man8 default : $(SUBDIRS)
man/man2/ioctl_xfs_scrub_metadata.2 new file +298 -0
298 lines not on this page · raw message