[RFC PATCH 2/2] xfs: initial/partial support for badblocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Cc: Dave Chinner <david@xxxxxxxxxxxxx>
Signed-off-by: Vishal Verma <vishal.l.verma@xxxxxxxxx>
---
 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

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs



[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux