Re: [md PATCH 01/36] md: beginnings of bad block management.
From: Namhyung Kim <hidden>
Date: 2011-07-22 16:52:22
NeilBrown [off-list ref] writes:
quoted hunk
This the first step in allowing md to track bad-blocks per-device so that we can fail individual blocks rather than the whole device. This patch just adds a data structure for recording bad blocks, with routines to add, remove, search the list. Signed-off-by: NeilBrown <redacted> --- drivers/md/md.c | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/md.h | 49 ++++++ 2 files changed, 502 insertions(+), 4 deletions(-)diff --git a/drivers/md/md.c b/drivers/md/md.c index 2a32050..220fadb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c@@ -1952,6 +1952,10 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) sysfs_remove_link(&rdev->kobj, "block"); sysfs_put(rdev->sysfs_state); rdev->sysfs_state = NULL; + kfree(rdev->badblocks.page); + rdev->badblocks.count = 0; + rdev->badblocks.page = NULL; + rdev->badblocks.active_page = NULL; /* We need to delay this, otherwise we can deadlock when * writing to 'remove' to "dev/state". We also need * to delay it due to rcu usage.@@ -2778,7 +2782,7 @@ static struct kobj_type rdev_ktype = { .default_attrs = rdev_default_attrs, }; -void md_rdev_init(mdk_rdev_t *rdev) +int md_rdev_init(mdk_rdev_t *rdev) { rdev->desc_nr = -1; rdev->saved_raid_disk = -1;@@ -2794,6 +2798,20 @@ void md_rdev_init(mdk_rdev_t *rdev) INIT_LIST_HEAD(&rdev->same_set); init_waitqueue_head(&rdev->blocked_wait); + + /* Add space to store bad block list. + * This reserves the space even on arrays where it cannot + * be used - I wonder if that matters + */ + rdev->badblocks.count = 0; + rdev->badblocks.shift = 0; + rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL); + rdev->badblocks.active_page = rdev->badblocks.page; + spin_lock_init(&rdev->badblocks.lock); + if (rdev->badblocks.page == NULL) + return -ENOMEM; + + return 0; } EXPORT_SYMBOL_GPL(md_rdev_init); /*@@ -2819,8 +2837,11 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi return ERR_PTR(-ENOMEM); } - md_rdev_init(rdev); - if ((err = alloc_disk_sb(rdev))) + err = md_rdev_init(rdev); + if (err) + goto abort_free; + err = alloc_disk_sb(rdev); + if (err) goto abort_free; err = lock_rdev(rdev, newdev, super_format == -2);
Now error path at abort_free needs to free rdev->badblocks.page otherwise there will be memory leaks.