Message ID | 20220410160904.3758789-7-ruansy.fnst@fujitsu.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | fsdax: introduce fs query to support reflink | expand |
Hi Shiyang, Thank you for the patch! Yet something to improve: [auto build test ERROR on hnaz-mm/master] [also build test ERROR on next-20220408] [cannot apply to xfs-linux/for-next linus/master linux/master v5.18-rc1] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/intel-lab-lkp/linux/commits/Shiyang-Ruan/fsdax-introduce-fs-query-to-support-reflink/20220411-001048 base: https://github.com/hnaz/linux-mm master config: s390-defconfig (https://download.01.org/0day-ci/archive/20220411/202204110240.oa3G7lsW-lkp@intel.com/config) compiler: s390-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/bf68be0c39b8ecc4223b948a9ee126af167d74f0 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Shiyang-Ruan/fsdax-introduce-fs-query-to-support-reflink/20220411-001048 git checkout bf68be0c39b8ecc4223b948a9ee126af167d74f0 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=s390 SHELL=/bin/bash If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): s390-linux-ld: fs/xfs/xfs_buf.o: in function `xfs_alloc_buftarg': >> fs/xfs/xfs_buf.c:1968: undefined reference to `xfs_dax_holder_operations' pahole: .tmp_vmlinux.btf: No such file or directory .btf.vmlinux.bin.o: file not recognized: file format not recognized vim +1968 fs/xfs/xfs_buf.c 1955 1956 struct xfs_buftarg * 1957 xfs_alloc_buftarg( 1958 struct xfs_mount *mp, 1959 struct block_device *bdev) 1960 { 1961 xfs_buftarg_t *btp; 1962 1963 btp = kmem_zalloc(sizeof(*btp), KM_NOFS); 1964 1965 btp->bt_mount = mp; 1966 btp->bt_dev = bdev->bd_dev; 1967 btp->bt_bdev = bdev; > 1968 btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, 1969 &xfs_dax_holder_operations); 1970 1971 /* 1972 * Buffer IO error rate limiting. Limit it to no more than 10 messages 1973 * per 30 seconds so as to not spam logs too much on repeated errors. 1974 */ 1975 ratelimit_state_init(&btp->bt_ioerror_rl, 30 * HZ, 1976 DEFAULT_RATELIMIT_BURST); 1977 1978 if (xfs_setsize_buftarg_early(btp, bdev)) 1979 goto error_free; 1980 1981 if (list_lru_init(&btp->bt_lru)) 1982 goto error_free; 1983 1984 if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL)) 1985 goto error_lru; 1986 1987 btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count; 1988 btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan; 1989 btp->bt_shrinker.seeks = DEFAULT_SEEKS; 1990 btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE; 1991 if (register_shrinker(&btp->bt_shrinker)) 1992 goto error_pcpu; 1993 return btp; 1994 1995 error_pcpu: 1996 percpu_counter_destroy(&btp->bt_io_count); 1997 error_lru: 1998 list_lru_destroy(&btp->bt_lru); 1999 error_free: 2000 kmem_free(btp); 2001 return NULL; 2002 } 2003
Hi Shiyang,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on hnaz-mm/master]
[also build test ERROR on next-20220408]
[cannot apply to xfs-linux/for-next linus/master linux/master v5.18-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Shiyang-Ruan/fsdax-introduce-fs-query-to-support-reflink/20220411-001048
base: https://github.com/hnaz/linux-mm master
config: s390-allyesconfig (https://download.01.org/0day-ci/archive/20220411/202204110700.66Eh1XZg-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/bf68be0c39b8ecc4223b948a9ee126af167d74f0
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Shiyang-Ruan/fsdax-introduce-fs-query-to-support-reflink/20220411-001048
git checkout bf68be0c39b8ecc4223b948a9ee126af167d74f0
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=s390 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
s390-linux-ld: fs/xfs/xfs_buf.o: in function `xfs_alloc_buftarg':
>> xfs_buf.c:(.text+0x9920): undefined reference to `xfs_dax_holder_operations'
> --- a/fs/xfs/xfs_super.h > +++ b/fs/xfs/xfs_super.h > @@ -93,6 +93,7 @@ extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *, > extern const struct export_operations xfs_export_operations; > extern const struct xattr_handler *xfs_xattr_handlers[]; > extern const struct quotactl_ops xfs_quotactl_operations; > +extern const struct dax_holder_operations xfs_dax_holder_operations; This needs to be defined to NULL if at least one of CONFIG_FS_DAX or CONFIG_MEMORY_FAILURE is not set. Otherwise looks good: Reviewed-by: Christoph Hellwig <hch@lst.de>
On Mon, Apr 11, 2022 at 12:09:03AM +0800, Shiyang Ruan wrote: > Introduce xfs_notify_failure.c to handle failure related works, such as > implement ->notify_failure(), register/unregister dax holder in xfs, and > so on. > > If the rmap feature of XFS enabled, we can query it to find files and > metadata which are associated with the corrupt data. For now all we do > is kill processes with that file mapped into their address spaces, but > future patches could actually do something about corrupt metadata. > > After that, the memory failure needs to notify the processes who are > using those files. > > Signed-off-by: Shiyang Ruan <ruansy.fnst@fujitsu.com> > --- > fs/xfs/Makefile | 5 + > fs/xfs/xfs_buf.c | 7 +- > fs/xfs/xfs_fsops.c | 3 + > fs/xfs/xfs_mount.h | 1 + > fs/xfs/xfs_notify_failure.c | 219 ++++++++++++++++++++++++++++++++++++ > fs/xfs/xfs_super.h | 1 + > 6 files changed, 233 insertions(+), 3 deletions(-) > create mode 100644 fs/xfs/xfs_notify_failure.c > > diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile > index 04611a1068b4..09f5560e29f2 100644 > --- a/fs/xfs/Makefile > +++ b/fs/xfs/Makefile > @@ -128,6 +128,11 @@ xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o > xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o > xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o > > +# notify failure > +ifeq ($(CONFIG_MEMORY_FAILURE),y) > +xfs-$(CONFIG_FS_DAX) += xfs_notify_failure.o > +endif > + > # online scrub/repair > ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) > > diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c > index f9ca08398d32..9064b8dfbc66 100644 > --- a/fs/xfs/xfs_buf.c > +++ b/fs/xfs/xfs_buf.c > @@ -5,6 +5,7 @@ > */ > #include "xfs.h" > #include <linux/backing-dev.h> > +#include <linux/dax.h> > > #include "xfs_shared.h" > #include "xfs_format.h" > @@ -1911,7 +1912,7 @@ xfs_free_buftarg( > list_lru_destroy(&btp->bt_lru); > > blkdev_issue_flush(btp->bt_bdev); > - fs_put_dax(btp->bt_daxdev, NULL); > + fs_put_dax(btp->bt_daxdev, btp->bt_mount); > > kmem_free(btp); > } > @@ -1964,8 +1965,8 @@ xfs_alloc_buftarg( > btp->bt_mount = mp; > btp->bt_dev = bdev->bd_dev; > btp->bt_bdev = bdev; > - btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, NULL, > - NULL); > + btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, > + &xfs_dax_holder_operations); I see a problem with this: we are setting up notify callbacks before we've even read in the superblock during mount. i.e. we don't even kow yet if we've got an XFS filesystem on this block device. Hence if we get a notification immediately after registering this notification callback.... [...] > + > +static int > +xfs_dax_notify_ddev_failure( > + struct xfs_mount *mp, > + xfs_daddr_t daddr, > + xfs_daddr_t bblen, > + int mf_flags) > +{ > + struct xfs_trans *tp = NULL; > + struct xfs_btree_cur *cur = NULL; > + struct xfs_buf *agf_bp = NULL; > + int error = 0; > + xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr); > + xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); > + xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen); > + xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno); .... none of this code is going to function correctly because it is dependent on the superblock having been read, validated and copied to the in-memory superblock. > + error = xfs_trans_alloc_empty(mp, &tp); > + if (error) > + return error; ... and it's not valid to use transactions (even empty ones) before log recovery has completed and set the log up correctly. > + > + for (; agno <= end_agno; agno++) { > + struct xfs_rmap_irec ri_low = { }; > + struct xfs_rmap_irec ri_high; > + struct failure_info notify; > + struct xfs_agf *agf; > + xfs_agblock_t agend; > + > + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp); > + if (error) > + break; > + > + cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, agf_bp->b_pag); ... and none of the structures this rmapbt walk is dependent on (e.g. perag structures) have been initialised yet so there's null pointer dereferences going to happen here. Perhaps even worse is that the rmapbt is not guaranteed to be in consistent state until after log recovery has completed, so this walk could get stuck forever in a stale on-disk cycle that recovery would have corrected.... Hence these notifications need to be delayed until after the filesystem is mounted, all the internal structures have been set up and log recovery has completed. Cheers, Dave.
On Tue, Apr 12, 2022 at 5:04 PM Dave Chinner <david@fromorbit.com> wrote: > > On Mon, Apr 11, 2022 at 12:09:03AM +0800, Shiyang Ruan wrote: > > Introduce xfs_notify_failure.c to handle failure related works, such as > > implement ->notify_failure(), register/unregister dax holder in xfs, and > > so on. > > > > If the rmap feature of XFS enabled, we can query it to find files and > > metadata which are associated with the corrupt data. For now all we do > > is kill processes with that file mapped into their address spaces, but > > future patches could actually do something about corrupt metadata. > > > > After that, the memory failure needs to notify the processes who are > > using those files. > > > > Signed-off-by: Shiyang Ruan <ruansy.fnst@fujitsu.com> > > --- > > fs/xfs/Makefile | 5 + > > fs/xfs/xfs_buf.c | 7 +- > > fs/xfs/xfs_fsops.c | 3 + > > fs/xfs/xfs_mount.h | 1 + > > fs/xfs/xfs_notify_failure.c | 219 ++++++++++++++++++++++++++++++++++++ > > fs/xfs/xfs_super.h | 1 + > > 6 files changed, 233 insertions(+), 3 deletions(-) > > create mode 100644 fs/xfs/xfs_notify_failure.c > > > > diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile > > index 04611a1068b4..09f5560e29f2 100644 > > --- a/fs/xfs/Makefile > > +++ b/fs/xfs/Makefile > > @@ -128,6 +128,11 @@ xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o > > xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o > > xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o > > > > +# notify failure > > +ifeq ($(CONFIG_MEMORY_FAILURE),y) > > +xfs-$(CONFIG_FS_DAX) += xfs_notify_failure.o > > +endif > > + > > # online scrub/repair > > ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) > > > > diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c > > index f9ca08398d32..9064b8dfbc66 100644 > > --- a/fs/xfs/xfs_buf.c > > +++ b/fs/xfs/xfs_buf.c > > @@ -5,6 +5,7 @@ > > */ > > #include "xfs.h" > > #include <linux/backing-dev.h> > > +#include <linux/dax.h> > > > > #include "xfs_shared.h" > > #include "xfs_format.h" > > @@ -1911,7 +1912,7 @@ xfs_free_buftarg( > > list_lru_destroy(&btp->bt_lru); > > > > blkdev_issue_flush(btp->bt_bdev); > > - fs_put_dax(btp->bt_daxdev, NULL); > > + fs_put_dax(btp->bt_daxdev, btp->bt_mount); > > > > kmem_free(btp); > > } > > @@ -1964,8 +1965,8 @@ xfs_alloc_buftarg( > > btp->bt_mount = mp; > > btp->bt_dev = bdev->bd_dev; > > btp->bt_bdev = bdev; > > - btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, NULL, > > - NULL); > > + btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, > > + &xfs_dax_holder_operations); > > I see a problem with this: we are setting up notify callbacks before > we've even read in the superblock during mount. i.e. we don't even > kow yet if we've got an XFS filesystem on this block device. > > Hence if we get a notification immediately after registering this > notification callback.... > > [...] > > > + > > +static int > > +xfs_dax_notify_ddev_failure( > > + struct xfs_mount *mp, > > + xfs_daddr_t daddr, > > + xfs_daddr_t bblen, > > + int mf_flags) > > +{ > > + struct xfs_trans *tp = NULL; > > + struct xfs_btree_cur *cur = NULL; > > + struct xfs_buf *agf_bp = NULL; > > + int error = 0; > > + xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr); > > + xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); > > + xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen); > > + xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno); > > .... none of this code is going to function correctly because it > is dependent on the superblock having been read, validated and > copied to the in-memory superblock. > > > + error = xfs_trans_alloc_empty(mp, &tp); > > + if (error) > > + return error; > > ... and it's not valid to use transactions (even empty ones) before > log recovery has completed and set the log up correctly. > > > + > > + for (; agno <= end_agno; agno++) { > > + struct xfs_rmap_irec ri_low = { }; > > + struct xfs_rmap_irec ri_high; > > + struct failure_info notify; > > + struct xfs_agf *agf; > > + xfs_agblock_t agend; > > + > > + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp); > > + if (error) > > + break; > > + > > + cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, agf_bp->b_pag); > > ... and none of the structures this rmapbt walk is dependent on > (e.g. perag structures) have been initialised yet so there's null > pointer dereferences going to happen here. > > Perhaps even worse is that the rmapbt is not guaranteed to be in > consistent state until after log recovery has completed, so this > walk could get stuck forever in a stale on-disk cycle that > recovery would have corrected.... > > Hence these notifications need to be delayed until after the > filesystem is mounted, all the internal structures have been set up > and log recovery has completed. So I think this gets back to the fact that there will eventually be 2 paths into this notifier. One will be the currently proposed synchronous / CPU-consumes-poison while accessing the filesystem (potentially even while recovery is running), and another will be in response to some asynchronous background scanning. I am thinking that the latter would be driven from a userspace daemon reconciling background scan events and notifying the filesystem and any other interested party. All that to say, I think it is ok / expected for the filesystem to drop notifications on the floor when it is not ready to handle them. For example there are no processes to send SIGBUS to if the filesystem has not even finished mount. It is then up to userspace to replay any relevant error notifications that may be pending after mount completes to sync the filesystem with the current state of the hardware.
On Tue, Apr 12, 2022 at 07:06:40PM -0700, Dan Williams wrote: > On Tue, Apr 12, 2022 at 5:04 PM Dave Chinner <david@fromorbit.com> wrote: > > On Mon, Apr 11, 2022 at 12:09:03AM +0800, Shiyang Ruan wrote: > > > Introduce xfs_notify_failure.c to handle failure related works, such as > > > implement ->notify_failure(), register/unregister dax holder in xfs, and > > > so on. > > > > > > If the rmap feature of XFS enabled, we can query it to find files and > > > metadata which are associated with the corrupt data. For now all we do > > > is kill processes with that file mapped into their address spaces, but > > > future patches could actually do something about corrupt metadata. > > > > > > After that, the memory failure needs to notify the processes who are > > > using those files. ... > > > @@ -1964,8 +1965,8 @@ xfs_alloc_buftarg( > > > btp->bt_mount = mp; > > > btp->bt_dev = bdev->bd_dev; > > > btp->bt_bdev = bdev; > > > - btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, NULL, > > > - NULL); > > > + btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, > > > + &xfs_dax_holder_operations); > > > > I see a problem with this: we are setting up notify callbacks before > > we've even read in the superblock during mount. i.e. we don't even > > kow yet if we've got an XFS filesystem on this block device. > > Hence these notifications need to be delayed until after the > > filesystem is mounted, all the internal structures have been set up > > and log recovery has completed. > > So I think this gets back to the fact that there will eventually be 2 > paths into this notifier. I'm not really concerned by how the notifications are generated; my concern is purely that notifications can be handled safely. > All that to say, I think it is ok / expected for the filesystem to > drop notifications on the floor when it is not ready to handle them. Well, yes. The whole point of notifications is the consumer makes the decision on what to do with the notification it receives - the producer of the notification does not (and can not) dictate what policy the consumer(s) implement... > For example there are no processes to send SIGBUS to if the filesystem > has not even finished mount. There may be not processes to send SIGBUS to even if the filesystem has finished mount. But we still want the notifications to be delivered and we still need to handle them safely. IOWs, while we might start by avoiding notifications during mount, this doesn't mean we will never have reason to process events during mount. What we do with this notification is going to evolve over time as we add new and adapt existing functionality.... Cheers, Dave.
On Tue, Apr 12, 2022 at 11:10 PM Dave Chinner <david@fromorbit.com> wrote: > > On Tue, Apr 12, 2022 at 07:06:40PM -0700, Dan Williams wrote: > > On Tue, Apr 12, 2022 at 5:04 PM Dave Chinner <david@fromorbit.com> wrote: > > > On Mon, Apr 11, 2022 at 12:09:03AM +0800, Shiyang Ruan wrote: > > > > Introduce xfs_notify_failure.c to handle failure related works, such as > > > > implement ->notify_failure(), register/unregister dax holder in xfs, and > > > > so on. > > > > > > > > If the rmap feature of XFS enabled, we can query it to find files and > > > > metadata which are associated with the corrupt data. For now all we do > > > > is kill processes with that file mapped into their address spaces, but > > > > future patches could actually do something about corrupt metadata. > > > > > > > > After that, the memory failure needs to notify the processes who are > > > > using those files. > ... > > > > @@ -1964,8 +1965,8 @@ xfs_alloc_buftarg( > > > > btp->bt_mount = mp; > > > > btp->bt_dev = bdev->bd_dev; > > > > btp->bt_bdev = bdev; > > > > - btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, NULL, > > > > - NULL); > > > > + btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, > > > > + &xfs_dax_holder_operations); > > > > > > I see a problem with this: we are setting up notify callbacks before > > > we've even read in the superblock during mount. i.e. we don't even > > > kow yet if we've got an XFS filesystem on this block device. > > > Hence these notifications need to be delayed until after the > > > filesystem is mounted, all the internal structures have been set up > > > and log recovery has completed. > > > > So I think this gets back to the fact that there will eventually be 2 > > paths into this notifier. > > I'm not really concerned by how the notifications are generated; > my concern is purely that notifications can be handled safely. > > > All that to say, I think it is ok / expected for the filesystem to > > drop notifications on the floor when it is not ready to handle them. > > Well, yes. The whole point of notifications is the consumer makes > the decision on what to do with the notification it receives - the > producer of the notification does not (and can not) dictate what > policy the consumer(s) implement... > > > For example there are no processes to send SIGBUS to if the filesystem > > has not even finished mount. > > There may be not processes to send SIGBUS to even if the filesystem > has finished mount. But we still want the notifications to be > delivered and we still need to handle them safely. > > IOWs, while we might start by avoiding notifications during mount, > this doesn't mean we will never have reason to process events during > mount. What we do with this notification is going to evolve over > time as we add new and adapt existing functionality.... Yes, sounds like we're on the same page. I had mistakenly interpreted "Hence these notifications need to be delayed until after the filesystem is mounted" as something the producer would need to handle, but yes, consumer is free to drop if the notification arrives at an inopportune time.
On Wed, Apr 13, 2022 at 10:09:40AM -0700, Dan Williams wrote: > Yes, sounds like we're on the same page. I had mistakenly interpreted > "Hence these notifications need to be delayed until after the > filesystem is mounted" as something the producer would need to handle, > but yes, consumer is free to drop if the notification arrives at an > inopportune time. A SB_BORN check might be all that we need.
Greeting, FYI, we noticed the following commit (built with gcc-11): commit: bf68be0c39b8ecc4223b948a9ee126af167d74f0 ("[PATCH v12 6/7] xfs: Implement ->notify_failure() for XFS") url: https://github.com/intel-lab-lkp/linux/commits/Shiyang-Ruan/fsdax-introduce-fs-query-to-support-reflink/20220411-001048 base: https://github.com/hnaz/linux-mm master patch link: https://lore.kernel.org/lkml/20220410160904.3758789-7-ruansy.fnst@fujitsu.com in testcase: xfstests version: xfstests-x86_64-1de1db8-1_20220217 with following parameters: disk: 4HDD fs: xfs test: xfs-group-05 ucode: 0x21 test-description: xfstests is a regression test suite for xfs and other files ystems. test-url: git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git on test machine: 4 threads 1 sockets Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz with 8G memory caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace): If you fix the issue, kindly add following tag Reported-by: kernel test robot <oliver.sang@intel.com> [ 62.111233][ T1606] BUG: KASAN: null-ptr-deref in fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.117884][ T1606] Write of size 8 at addr 00000000000002f0 by task umount/1606 [ 62.125379][ T1606] [ 62.127616][ T1606] CPU: 2 PID: 1606 Comm: umount Not tainted 5.18.0-rc1-mm1-00194-gbf68be0c39b8 #1 [ 62.136760][ T1606] Hardware name: Hewlett-Packard HP Pro 3340 MT/17A1, BIOS 8.07 01/24/2013 [ 62.145339][ T1606] Call Trace: [ 62.148554][ T1606] <TASK> [ 62.151404][ T1606] ? fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.155651][ T1606] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) [ 62.160110][ T1606] kasan_report (mm/kasan/report.c:162 mm/kasan/report.c:493) [ 62.164447][ T1606] ? fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.168677][ T1606] kasan_check_range (mm/kasan/generic.c:190) [ 62.173427][ T1606] fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.177519][ T1606] xfs_free_buftarg (fs/xfs/kmem.h:62 fs/xfs/xfs_buf.c:1917) xfs [ 62.182900][ T1606] xfs_fs_put_super (fs/xfs/xfs_super.c:1101) xfs [ 62.188326][ T1606] generic_shutdown_super (fs/super.c:464) [ 62.193636][ T1606] kill_block_super (fs/super.c:1395) [ 62.198325][ T1606] deactivate_locked_super (fs/super.c:339) [ 62.203656][ T1606] cleanup_mnt (fs/namespace.c:138 fs/namespace.c:1187) [ 62.208023][ T1606] ? path_umount (fs/namespace.c:1808) [ 62.212530][ T1606] task_work_run (kernel/task_work.c:166 (discriminator 1)) [ 62.216932][ T1606] exit_to_user_mode_loop (include/linux/resume_user_mode.h:49 kernel/entry/common.c:169) [ 62.222253][ T1606] exit_to_user_mode_prepare (kernel/entry/common.c:201) [ 62.227749][ T1606] syscall_exit_to_user_mode (arch/x86/include/asm/jump_label.h:27 include/linux/context_tracking_state.h:31 include/linux/context_tracking.h:40 kernel/entry/common.c:132 kernel/entry/common.c:296) [ 62.233149][ T1606] do_syscall_64 (arch/x86/entry/common.c:87) [ 62.237447][ T1606] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:115) [ 62.243288][ T1606] RIP: 0033:0x7fa858fee507 [ 62.247649][ T1606] Code: 19 0c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 59 19 0c 00 f7 d8 64 89 01 48 All code ======== 0: 19 0c 00 sbb %ecx,(%rax,%rax,1) 3: f7 d8 neg %eax 5: 64 89 01 mov %eax,%fs:(%rcx) 8: 48 83 c8 ff or $0xffffffffffffffff,%rax c: c3 retq d: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 13: 31 f6 xor %esi,%esi 15: e9 09 00 00 00 jmpq 0x23 1a: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 21: 00 00 23: b8 a6 00 00 00 mov $0xa6,%eax 28: 0f 05 syscall 2a:* 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax <-- trapping instruction 30: 73 01 jae 0x33 32: c3 retq 33: 48 8b 0d 59 19 0c 00 mov 0xc1959(%rip),%rcx # 0xc1993 3a: f7 d8 neg %eax 3c: 64 89 01 mov %eax,%fs:(%rcx) 3f: 48 rex.W Code starting with the faulting instruction =========================================== 0: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax 6: 73 01 jae 0x9 8: c3 retq 9: 48 8b 0d 59 19 0c 00 mov 0xc1959(%rip),%rcx # 0xc1969 10: f7 d8 neg %eax 12: 64 89 01 mov %eax,%fs:(%rcx) 15: 48 rex.W [ 62.267385][ T1606] RSP: 002b:00007ffe344b8b68 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 [ 62.275814][ T1606] RAX: 0000000000000000 RBX: 00005639c92b5970 RCX: 00007fa858fee507 [ 62.283744][ T1606] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 00005639c92b5b80 [ 62.291682][ T1606] RBP: 0000000000000000 R08: 00005639c92b5ba0 R09: 00007fa85906fe80 [ 62.299622][ T1606] R10: 0000000000000000 R11: 0000000000000246 R12: 00005639c92b5b80 [ 62.307568][ T1606] R13: 00007fa8591141c4 R14: 00005639c92b5a68 R15: 0000000000000000 [ 62.315510][ T1606] </TASK> [ 62.318445][ T1606] ================================================================== [ 62.326514][ T1606] Disabling lock debugging due to kernel taint [ 62.332634][ T1606] BUG: kernel NULL pointer dereference, address: 00000000000002f0 [ 62.340410][ T1606] #PF: supervisor write access in kernel mode [ 62.346422][ T1606] #PF: error_code(0x0002) - not-present page [ 62.352357][ T1606] PGD 0 P4D 0 [ 62.355658][ T1606] Oops: 0002 [#1] SMP KASAN PTI [ 62.360475][ T1606] CPU: 2 PID: 1606 Comm: umount Tainted: G B 5.18.0-rc1-mm1-00194-gbf68be0c39b8 #1 [ 62.371045][ T1606] Hardware name: Hewlett-Packard HP Pro 3340 MT/17A1, BIOS 8.07 01/24/2013 [ 62.379598][ T1606] RIP: 0010:fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.384466][ T1606] Code: 40 00 0f 1f 44 00 00 55 48 89 fd 53 48 85 f6 74 27 48 89 f3 48 8d bf f0 02 00 00 be 08 00 00 00 e8 9d a8 29 ff 48 89 d8 31 d2 <f0> 48 0f b1 95 f0 02 00 00 48 39 c3 74 12 48 85 ed 74 0a 48 89 ef All code ======== 0: 40 00 0f add %cl,(%rdi) 3: 1f (bad) 4: 44 00 00 add %r8b,(%rax) 7: 55 push %rbp 8: 48 89 fd mov %rdi,%rbp b: 53 push %rbx c: 48 85 f6 test %rsi,%rsi f: 74 27 je 0x38 11: 48 89 f3 mov %rsi,%rbx 14: 48 8d bf f0 02 00 00 lea 0x2f0(%rdi),%rdi 1b: be 08 00 00 00 mov $0x8,%esi 20: e8 9d a8 29 ff callq 0xffffffffff29a8c2 25: 48 89 d8 mov %rbx,%rax 28: 31 d2 xor %edx,%edx 2a:* f0 48 0f b1 95 f0 02 lock cmpxchg %rdx,0x2f0(%rbp) <-- trapping instruction 31: 00 00 33: 48 39 c3 cmp %rax,%rbx 36: 74 12 je 0x4a 38: 48 85 ed test %rbp,%rbp 3b: 74 0a je 0x47 3d: 48 89 ef mov %rbp,%rdi Code starting with the faulting instruction =========================================== 0: f0 48 0f b1 95 f0 02 lock cmpxchg %rdx,0x2f0(%rbp) 7: 00 00 9: 48 39 c3 cmp %rax,%rbx c: 74 12 je 0x20 e: 48 85 ed test %rbp,%rbp 11: 74 0a je 0x1d 13: 48 89 ef mov %rbp,%rdi [ 62.404142][ T1606] RSP: 0018:ffffc90000f5fd90 EFLAGS: 00010246 [ 62.410137][ T1606] RAX: ffff888140f34000 RBX: ffff888140f34000 RCX: ffffffff811992e6 [ 62.418085][ T1606] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffffffff85c0b600 [ 62.426032][ T1606] RBP: 0000000000000000 R08: 0000000000000001 R09: ffffffff85c0b607 [ 62.433997][ T1606] R10: fffffbfff0b816c0 R11: 0000000000000000 R12: ffff8882189e80b8 [ 62.441943][ T1606] R13: ffff888140f34180 R14: ffff888140f34188 R15: ffff8881312f4180 [ 62.449876][ T1606] FS: 00007fa858bc8080(0000) GS:ffff8881aad00000(0000) knlGS:0000000000000000 [ 62.458774][ T1606] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 62.465317][ T1606] CR2: 00000000000002f0 CR3: 0000000134b6a002 CR4: 00000000001706e0 [ 62.473283][ T1606] Call Trace: [ 62.476463][ T1606] <TASK> [ 62.479331][ T1606] xfs_free_buftarg (fs/xfs/kmem.h:62 fs/xfs/xfs_buf.c:1917) xfs [ 62.484688][ T1606] xfs_fs_put_super (fs/xfs/xfs_super.c:1101) xfs [ 62.490091][ T1606] generic_shutdown_super (fs/super.c:464) [ 62.495390][ T1606] kill_block_super (fs/super.c:1395) [ 62.500072][ T1606] deactivate_locked_super (fs/super.c:339) [ 62.505394][ T1606] cleanup_mnt (fs/namespace.c:138 fs/namespace.c:1187) [ 62.509717][ T1606] ? path_umount (fs/namespace.c:1808) [ 62.514233][ T1606] task_work_run (kernel/task_work.c:166 (discriminator 1)) [ 62.518679][ T1606] exit_to_user_mode_loop (include/linux/resume_user_mode.h:49 kernel/entry/common.c:169) [ 62.524009][ T1606] exit_to_user_mode_prepare (kernel/entry/common.c:201) [ 62.529493][ T1606] syscall_exit_to_user_mode (arch/x86/include/asm/jump_label.h:27 include/linux/context_tracking_state.h:31 include/linux/context_tracking.h:40 kernel/entry/common.c:132 kernel/entry/common.c:296) [ 62.534902][ T1606] do_syscall_64 (arch/x86/entry/common.c:87) [ 62.539220][ T1606] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:115) [ 62.545042][ T1606] RIP: 0033:0x7fa858fee507 [ 62.549388][ T1606] Code: 19 0c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 59 19 0c 00 f7 d8 64 89 01 48 All code ======== 0: 19 0c 00 sbb %ecx,(%rax,%rax,1) 3: f7 d8 neg %eax 5: 64 89 01 mov %eax,%fs:(%rcx) 8: 48 83 c8 ff or $0xffffffffffffffff,%rax c: c3 retq d: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 13: 31 f6 xor %esi,%esi 15: e9 09 00 00 00 jmpq 0x23 1a: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 21: 00 00 23: b8 a6 00 00 00 mov $0xa6,%eax 28: 0f 05 syscall 2a:* 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax <-- trapping instruction 30: 73 01 jae 0x33 32: c3 retq 33: 48 8b 0d 59 19 0c 00 mov 0xc1959(%rip),%rcx # 0xc1993 3a: f7 d8 neg %eax 3c: 64 89 01 mov %eax,%fs:(%rcx) 3f: 48 rex.W Code starting with the faulting instruction =========================================== 0: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax 6: 73 01 jae 0x9 8: c3 retq 9: 48 8b 0d 59 19 0c 00 mov 0xc1959(%rip),%rcx # 0xc1969 10: f7 d8 neg %eax 12: 64 89 01 mov %eax,%fs:(%rcx) 15: 48 rex.W [ 62.569097][ T1606] RSP: 002b:00007ffe344b8b68 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 [ 62.577467][ T1606] RAX: 0000000000000000 RBX: 00005639c92b5970 RCX: 00007fa858fee507 [ 62.585386][ T1606] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 00005639c92b5b80 [ 62.593265][ T1606] RBP: 0000000000000000 R08: 00005639c92b5ba0 R09: 00007fa85906fe80 [ 62.601248][ T1606] R10: 0000000000000000 R11: 0000000000000246 R12: 00005639c92b5b80 [ 62.609151][ T1606] R13: 00007fa8591141c4 R14: 00005639c92b5a68 R15: 0000000000000000 [ 62.617075][ T1606] </TASK> [ 62.619995][ T1606] Modules linked in: xfs dm_mod netconsole btrfs blake2b_generic xor raid6_pq zstd_compress libcrc32c sd_mod t10_pi crc64_rocksoft_generic intel_rapl_msr crc64_rocksoft intel_rapl_common crc64 sg x86_pkg_temp_thermal intel_powerclamp coretemp ipmi_devintf i915 ipmi_msghandler kvm_intel kvm intel_gtt drm_buddy drm_dp_helper ttm irqbypass crct10dif_pclmul crc32_pclmul drm_kms_helper wmi_bmof crc32c_intel syscopyarea ghash_clmulni_intel rapl intel_cstate sysfillrect sysimgblt ahci fb_sys_fops libahci intel_uncore mei_me drm libata mei video wmi ip_tables [ 62.670932][ T1606] CR2: 00000000000002f0 [ 62.675025][ T1606] ---[ end trace 0000000000000000 ]--- [ 62.680557][ T1606] RIP: 0010:fs_put_dax (drivers/dax/super.c:116 (discriminator 1)) [ 62.685457][ T1606] Code: 40 00 0f 1f 44 00 00 55 48 89 fd 53 48 85 f6 74 27 48 89 f3 48 8d bf f0 02 00 00 be 08 00 00 00 e8 9d a8 29 ff 48 89 d8 31 d2 <f0> 48 0f b1 95 f0 02 00 00 48 39 c3 74 12 48 85 ed 74 0a 48 89 ef All code ======== 0: 40 00 0f add %cl,(%rdi) 3: 1f (bad) 4: 44 00 00 add %r8b,(%rax) 7: 55 push %rbp 8: 48 89 fd mov %rdi,%rbp b: 53 push %rbx c: 48 85 f6 test %rsi,%rsi f: 74 27 je 0x38 11: 48 89 f3 mov %rsi,%rbx 14: 48 8d bf f0 02 00 00 lea 0x2f0(%rdi),%rdi 1b: be 08 00 00 00 mov $0x8,%esi 20: e8 9d a8 29 ff callq 0xffffffffff29a8c2 25: 48 89 d8 mov %rbx,%rax 28: 31 d2 xor %edx,%edx 2a:* f0 48 0f b1 95 f0 02 lock cmpxchg %rdx,0x2f0(%rbp) <-- trapping instruction 31: 00 00 33: 48 39 c3 cmp %rax,%rbx 36: 74 12 je 0x4a 38: 48 85 ed test %rbp,%rbp 3b: 74 0a je 0x47 3d: 48 89 ef mov %rbp,%rdi Code starting with the faulting instruction =========================================== 0: f0 48 0f b1 95 f0 02 lock cmpxchg %rdx,0x2f0(%rbp) 7: 00 00 9: 48 39 c3 cmp %rax,%rbx c: 74 12 je 0x20 e: 48 85 ed test %rbp,%rbp 11: 74 0a je 0x1d 13: 48 89 ef mov %rbp,%rdi To reproduce: git clone https://github.com/intel/lkp-tests.git cd lkp-tests sudo bin/lkp install job.yaml # job file is attached in this email bin/lkp split-job --compatible job.yaml # generate the yaml file for lkp run sudo bin/lkp run generated-yaml-file # if come across any failure that blocks the test, # please remove ~/.lkp and /lkp dir to run from a clean state.
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 04611a1068b4..09f5560e29f2 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -128,6 +128,11 @@ xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o +# notify failure +ifeq ($(CONFIG_MEMORY_FAILURE),y) +xfs-$(CONFIG_FS_DAX) += xfs_notify_failure.o +endif + # online scrub/repair ifeq ($(CONFIG_XFS_ONLINE_SCRUB),y) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index f9ca08398d32..9064b8dfbc66 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -5,6 +5,7 @@ */ #include "xfs.h" #include <linux/backing-dev.h> +#include <linux/dax.h> #include "xfs_shared.h" #include "xfs_format.h" @@ -1911,7 +1912,7 @@ xfs_free_buftarg( list_lru_destroy(&btp->bt_lru); blkdev_issue_flush(btp->bt_bdev); - fs_put_dax(btp->bt_daxdev, NULL); + fs_put_dax(btp->bt_daxdev, btp->bt_mount); kmem_free(btp); } @@ -1964,8 +1965,8 @@ xfs_alloc_buftarg( btp->bt_mount = mp; btp->bt_dev = bdev->bd_dev; btp->bt_bdev = bdev; - btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, NULL, - NULL); + btp->bt_daxdev = fs_dax_get_by_bdev(bdev, &btp->bt_dax_part_off, mp, + &xfs_dax_holder_operations); /* * Buffer IO error rate limiting. Limit it to no more than 10 messages diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 68f74549fa22..56530900bb86 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -536,6 +536,9 @@ xfs_do_force_shutdown( } else if (flags & SHUTDOWN_CORRUPT_INCORE) { tag = XFS_PTAG_SHUTDOWN_CORRUPT; why = "Corruption of in-memory data"; + } else if (flags & SHUTDOWN_CORRUPT_ONDISK) { + tag = XFS_PTAG_SHUTDOWN_CORRUPT; + why = "Corruption of on-disk metadata"; } else { tag = XFS_PTAG_SHUTDOWN_IOERROR; why = "Metadata I/O Error"; diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f6dc19de8322..9237cc159542 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -435,6 +435,7 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ #define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ #define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */ +#define SHUTDOWN_CORRUPT_ONDISK 0x0010 /* corrupt metadata on device */ #define XFS_SHUTDOWN_STRINGS \ { SHUTDOWN_META_IO_ERROR, "metadata_io" }, \ diff --git a/fs/xfs/xfs_notify_failure.c b/fs/xfs/xfs_notify_failure.c new file mode 100644 index 000000000000..aac44f54feb4 --- /dev/null +++ b/fs/xfs/xfs_notify_failure.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Fujitsu. All Rights Reserved. + */ + +#include "xfs.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_alloc.h" +#include "xfs_bit.h" +#include "xfs_btree.h" +#include "xfs_inode.h" +#include "xfs_icache.h" +#include "xfs_rmap.h" +#include "xfs_rmap_btree.h" +#include "xfs_rtalloc.h" +#include "xfs_trans.h" + +#include <linux/mm.h> +#include <linux/dax.h> + +struct failure_info { + xfs_agblock_t startblock; + xfs_extlen_t blockcount; + int mf_flags; +}; + +static pgoff_t +xfs_failure_pgoff( + struct xfs_mount *mp, + const struct xfs_rmap_irec *rec, + const struct failure_info *notify) +{ + uint64_t pos = rec->rm_offset; + + if (notify->startblock > rec->rm_startblock) + pos += XFS_FSB_TO_B(mp, + notify->startblock - rec->rm_startblock); + return pos >> PAGE_SHIFT; +} + +static unsigned long +xfs_failure_pgcnt( + struct xfs_mount *mp, + const struct xfs_rmap_irec *rec, + const struct failure_info *notify) +{ + xfs_agblock_t end_rec; + xfs_agblock_t end_notify; + xfs_agblock_t start_cross; + xfs_agblock_t end_cross; + + start_cross = max(rec->rm_startblock, notify->startblock); + + end_rec = rec->rm_startblock + rec->rm_blockcount; + end_notify = notify->startblock + notify->blockcount; + end_cross = min(end_rec, end_notify); + + return XFS_FSB_TO_B(mp, end_cross - start_cross) >> PAGE_SHIFT; +} + +static int +xfs_dax_failure_fn( + struct xfs_btree_cur *cur, + const struct xfs_rmap_irec *rec, + void *data) +{ + struct xfs_mount *mp = cur->bc_mp; + struct xfs_inode *ip; + struct failure_info *notify = data; + int error = 0; + + if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || + (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) { + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); + return -EFSCORRUPTED; + } + + /* Get files that incore, filter out others that are not in use. */ + error = xfs_iget(mp, cur->bc_tp, rec->rm_owner, XFS_IGET_INCORE, + 0, &ip); + /* Continue the rmap query if the inode isn't incore */ + if (error == -ENODATA) + return 0; + if (error) + return error; + + error = mf_dax_kill_procs(VFS_I(ip)->i_mapping, + xfs_failure_pgoff(mp, rec, notify), + xfs_failure_pgcnt(mp, rec, notify), + notify->mf_flags); + xfs_irele(ip); + return error; +} + +static int +xfs_dax_notify_ddev_failure( + struct xfs_mount *mp, + xfs_daddr_t daddr, + xfs_daddr_t bblen, + int mf_flags) +{ + struct xfs_trans *tp = NULL; + struct xfs_btree_cur *cur = NULL; + struct xfs_buf *agf_bp = NULL; + int error = 0; + xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr); + xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); + xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen); + xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno); + + error = xfs_trans_alloc_empty(mp, &tp); + if (error) + return error; + + for (; agno <= end_agno; agno++) { + struct xfs_rmap_irec ri_low = { }; + struct xfs_rmap_irec ri_high; + struct failure_info notify; + struct xfs_agf *agf; + xfs_agblock_t agend; + + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp); + if (error) + break; + + cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, agf_bp->b_pag); + + /* + * Set the rmap range from ri_low to ri_high, which represents + * a [start, end] where we looking for the files or metadata. + * The part of range out of a AG will be ignored. So, it's fine + * to set ri_low to "startblock" in all loops. When it reaches + * the last AG, set the ri_high to "endblock" to make sure we + * actually end at the end. + */ + memset(&ri_high, 0xFF, sizeof(ri_high)); + ri_low.rm_startblock = XFS_FSB_TO_AGBNO(mp, fsbno); + if (agno == end_agno) + ri_high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsbno); + + agf = agf_bp->b_addr; + agend = min(be32_to_cpu(agf->agf_length), + ri_high.rm_startblock); + notify.startblock = ri_low.rm_startblock; + notify.blockcount = agend - ri_low.rm_startblock; + + error = xfs_rmap_query_range(cur, &ri_low, &ri_high, + xfs_dax_failure_fn, ¬ify); + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, agf_bp); + if (error) + break; + + fsbno = XFS_AGB_TO_FSB(mp, agno + 1, 0); + } + + xfs_trans_cancel(tp); + return error; +} + +static int +xfs_dax_notify_failure( + struct dax_device *dax_dev, + u64 offset, + u64 len, + int mf_flags) +{ + struct xfs_mount *mp = dax_holder(dax_dev); + u64 ddev_start; + u64 ddev_end; + + if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_daxdev == dax_dev) { + xfs_warn(mp, + "notify_failure() not supported on realtime device!"); + return -EOPNOTSUPP; + } + + if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev && + mp->m_logdev_targp != mp->m_ddev_targp) { + xfs_err(mp, "ondisk log corrupt, shutting down fs!"); + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); + return -EFSCORRUPTED; + } + + if (!xfs_has_rmapbt(mp)) { + xfs_warn(mp, "notify_failure() needs rmapbt enabled!"); + return -EOPNOTSUPP; + } + + ddev_start = mp->m_ddev_targp->bt_dax_part_off; + ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1; + + /* Ignore the range out of filesystem area */ + if (offset + len < ddev_start) + return -ENXIO; + if (offset > ddev_end) + return -ENXIO; + + /* Calculate the real range when it touches the boundary */ + if (offset > ddev_start) + offset -= ddev_start; + else { + len -= ddev_start - offset; + offset = 0; + } + if (offset + len > ddev_end) + len -= ddev_end - offset; + + return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len), + mf_flags); +} + +const struct dax_holder_operations xfs_dax_holder_operations = { + .notify_failure = xfs_dax_notify_failure, +}; diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h index 167d23f92ffe..27ab5087d0b3 100644 --- a/fs/xfs/xfs_super.h +++ b/fs/xfs/xfs_super.h @@ -93,6 +93,7 @@ extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *, extern const struct export_operations xfs_export_operations; extern const struct xattr_handler *xfs_xattr_handlers[]; extern const struct quotactl_ops xfs_quotactl_operations; +extern const struct dax_holder_operations xfs_dax_holder_operations; extern void xfs_reinit_percpu_counters(struct xfs_mount *mp);
Introduce xfs_notify_failure.c to handle failure related works, such as implement ->notify_failure(), register/unregister dax holder in xfs, and so on. If the rmap feature of XFS enabled, we can query it to find files and metadata which are associated with the corrupt data. For now all we do is kill processes with that file mapped into their address spaces, but future patches could actually do something about corrupt metadata. After that, the memory failure needs to notify the processes who are using those files. Signed-off-by: Shiyang Ruan <ruansy.fnst@fujitsu.com> --- fs/xfs/Makefile | 5 + fs/xfs/xfs_buf.c | 7 +- fs/xfs/xfs_fsops.c | 3 + fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_notify_failure.c | 219 ++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_super.h | 1 + 6 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 fs/xfs/xfs_notify_failure.c