[RFC PATCH 2/2] xfs: initial/partial support for badblocks
Vishal Verma
vishal.l.verma at intel.com
Thu Jun 16 20:03:39 CDT 2016
RFC/WIP commit.
This adds the foollowing:
1. In xfs_mountfs(), get an initial badblocks list from gendisk's
badblocks infrastructure.
2. Register with the badblocks notifier to get updates for this disk's
badblocks
TODO:
1. Add badblocks info to the reverse mapping tree (and remove if a
badblock was cleared).
2. Before doing file IO, refer the rmap/badblocks to error out early if
the IO will attempt wo read a bad sector
3. Figure out interactions with mmap/DAX.
Cc: Darrick J. Wong <darrick.wong at oracle.com>
Cc: Dave Chinner <david at fromorbit.com>
Signed-off-by: Vishal Verma <vishal.l.verma at intel.com>
---
fs/xfs/xfs_linux.h | 1 +
fs/xfs/xfs_mount.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_mount.h | 1 +
3 files changed, 106 insertions(+)
diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
index 7e749be..f66d181 100644
--- a/fs/xfs/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -78,6 +78,7 @@ typedef __u32 xfs_nlink_t;
#include <linux/freezer.h>
#include <linux/list_sort.h>
#include <linux/ratelimit.h>
+#include <linux/badblocks.h>
#include <asm/page.h>
#include <asm/div64.h>
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 5e68b2c..1a47737 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -618,6 +618,96 @@ xfs_default_resblks(xfs_mount_t *mp)
return resblks;
}
+STATIC int
+xfs_notifier_call(
+ struct notifier_block *nb,
+ unsigned long action,
+ void *data)
+{
+ struct bb_notifier_data *bb_data = data;
+ struct xfs_mount *mp;
+
+ mp = container_of(nb, struct xfs_mount, m_badblocks_nb);
+ /* TODO xfs_add_bb_to_rmap(mp, bb_data->sector, bb_data->count); */
+ xfs_warn(mp, "xfs badblock %s sector %lu (count %d)\n",
+ (action == BB_ADD)?"added":"cleared",
+ bb_data->sector, bb_data->count);
+ return 0;
+}
+
+STATIC int
+xfs_init_badblocks(struct xfs_mount *mp)
+{
+ struct badblocks *bb = mp->m_super->s_bdev->bd_disk->bb;
+ int done = 0, error = 0;
+ ssize_t len, off = 0;
+ char *p;
+
+ /*
+ * TODO: get a list of known badblocks so far and process it.
+ * Can we just parse the sysfs format that badblocks_show()
+ * returns? That should be the fastest way to get this.
+ * Something like: (Is this too hacky? Should we just do
+ * badblocks_check() in a (rather large) loop?)
+ */
+ p = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ len = badblocks_show(bb, p, 0);
+ while (len) {
+ int count, n;
+ sector_t s;
+
+ /*
+ * The sysfs badblocks format is multiple lines of:
+ * "<sector> <count>"
+ */
+ n = sscanf(p + off, "%lu %d\n%n", &s, &count, &done);
+ if (n < 2 || done < 3) {
+ error = -1;
+ break;
+ }
+ off += done;
+ len -= done;
+ xfs_warn(mp, "got badblocks: sector %ld, count %d", s, count);
+ /* TODO xfs_add_bb_to_rmap(mp, s, count); */
+ }
+ kfree(p);
+ if (error)
+ return error;
+
+ mp->m_badblocks_nb.notifier_call = xfs_notifier_call;
+ error = bb_notifier_register(bb, &mp->m_badblocks_nb);
+ if (error)
+ return error;
+
+ /*
+ * TODO: There is probably a TOCTOU race hiding here - what if the
+ * badblocks list gets updated before we register for notifications..
+ * Can likely be solved by registering for notifications _first_ (the
+ * above xfs_add_bb_to_rmap function has to be ready to accept new
+ * blocks), then querying for the initial list (there could be overlap
+ * here, shich the above function could handle), and then setting the
+ * mount flag below.
+ */
+
+ /*
+ * TODO: set some flag (mount flag?) in xfs so that xfs knows
+ * it will be doing error checking, and can possibly, later,
+ * tell the block layer (possibly using a REQ_ flag in its IO
+ * requests) not to do further badblock checking for those IOs.
+ */
+
+ /* mp->m_flags |= XFS_MOUNT_FS_BADBLOCKS; */
+ return 0;
+}
+
+STATIC void
+xfs_badblocks_unmount(struct xfs_mount *mp)
+{
+ struct badblocks *bb = mp->m_super->s_bdev->bd_disk->bb;
+
+ bb_notifier_unregister(bb, &mp->m_badblocks_nb);
+}
+
/*
* This function does the following on an initial mount of a file system:
* - reads the superblock from disk and init the mount struct
@@ -955,6 +1045,19 @@ xfs_mountfs(
}
/*
+ * Register with the badblocks notifier chain
+ */
+ error = xfs_init_badblocks(mp);
+ if (error) {
+ xfs_warn(mp, "Unable to register to badblocks notifications\n");
+ /*
+ * TODO is this a hard error or can we simply
+ * warn and continue?
+ */
+ goto out_rtunmount;
+ }
+
+ /*
* Now we are mounted, reserve a small amount of unused space for
* privileged transactions. This is needed so that transaction
* space required for critical operations can dip into this pool
@@ -1085,6 +1188,7 @@ xfs_unmountfs(
xfs_log_unmount(mp);
xfs_da_unmount(mp);
xfs_uuid_unmount(mp);
+ xfs_badblocks_unmount(mp);
#if defined(DEBUG)
xfs_errortag_clearall(mp, 0);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 0ca9244..f0d1111 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -139,6 +139,7 @@ typedef struct xfs_mount {
/* low free space thresholds */
struct xfs_kobj m_kobj;
struct xstats m_stats; /* per-fs stats */
+ struct notifier_block m_badblocks_nb; /* disk badblocks notifier */
struct workqueue_struct *m_buf_workqueue;
struct workqueue_struct *m_data_workqueue;
--
2.5.5
More information about the xfs
mailing list