Commit 7444c718 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] md 21 of 22 - Improve handling of MD super blocks

1/ don't free the rdev->sb on an error -- it might be
   accessed again later.  Just wait for the device to be
   exported.
2/ Change md_update_sb to __md_update_sb and have it
   clear the sb_dirty flag.
   New md_update_sb locks the device and calls __md_update_sb
   if sb_dirty.  This avoids any possbile races around
   updating the superblock
parent f7bbc7e1
...@@ -921,12 +921,13 @@ static int sync_sbs(mddev_t * mddev) ...@@ -921,12 +921,13 @@ static int sync_sbs(mddev_t * mddev)
return 0; return 0;
} }
int md_update_sb(mddev_t * mddev) void __md_update_sb(mddev_t * mddev)
{ {
int err, count = 100; int err, count = 100;
struct list_head *tmp; struct list_head *tmp;
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
mddev->sb_dirty = 0;
repeat: repeat:
mddev->sb->utime = CURRENT_TIME; mddev->sb->utime = CURRENT_TIME;
if (!(++mddev->sb->events_lo)) if (!(++mddev->sb->events_lo))
...@@ -948,7 +949,7 @@ int md_update_sb(mddev_t * mddev) ...@@ -948,7 +949,7 @@ int md_update_sb(mddev_t * mddev)
* nonpersistent superblocks * nonpersistent superblocks
*/ */
if (mddev->sb->not_persistent) if (mddev->sb->not_persistent)
return 0; return;
printk(KERN_INFO "md: updating md%d RAID superblock on device\n", printk(KERN_INFO "md: updating md%d RAID superblock on device\n",
mdidx(mddev)); mdidx(mddev));
...@@ -976,9 +977,18 @@ int md_update_sb(mddev_t * mddev) ...@@ -976,9 +977,18 @@ int md_update_sb(mddev_t * mddev)
} }
printk(KERN_ERR "md: excessive errors occurred during superblock update, exiting\n"); printk(KERN_ERR "md: excessive errors occurred during superblock update, exiting\n");
} }
return 0;
} }
void md_update_sb(mddev_t *mddev)
{
if (mddev_lock(mddev))
return;
if (mddev->sb_dirty)
__md_update_sb(mddev);
mddev_unlock(mddev);
}
/* /*
* Import a device. If 'on_disk', then sanity check the superblock * Import a device. If 'on_disk', then sanity check the superblock
* *
...@@ -1648,7 +1658,7 @@ static int do_md_run(mddev_t * mddev) ...@@ -1648,7 +1658,7 @@ static int do_md_run(mddev_t * mddev)
} }
mddev->sb->state &= ~(1 << MD_SB_CLEAN); mddev->sb->state &= ~(1 << MD_SB_CLEAN);
md_update_sb(mddev); __md_update_sb(mddev);
/* /*
* md_size has units of 1K blocks, which are * md_size has units of 1K blocks, which are
...@@ -1770,7 +1780,7 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -1770,7 +1780,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
printk(KERN_INFO "md: marking sb clean...\n"); printk(KERN_INFO "md: marking sb clean...\n");
mddev->sb->state |= 1 << MD_SB_CLEAN; mddev->sb->state |= 1 << MD_SB_CLEAN;
} }
md_update_sb(mddev); __md_update_sb(mddev);
} }
if (ro) if (ro)
set_device_ro(dev, 1); set_device_ro(dev, 1);
...@@ -2281,8 +2291,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) ...@@ -2281,8 +2291,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev)
remove_descriptor(disk, mddev->sb); remove_descriptor(disk, mddev->sb);
kick_rdev_from_array(rdev); kick_rdev_from_array(rdev);
mddev->sb_dirty = 1; __md_update_sb(mddev);
md_update_sb(mddev);
return 0; return 0;
busy: busy:
...@@ -2393,9 +2402,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) ...@@ -2393,9 +2402,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev)
mddev->sb->spare_disks++; mddev->sb->spare_disks++;
mddev->sb->working_disks++; mddev->sb->working_disks++;
mddev->sb_dirty = 1; __md_update_sb(mddev);
md_update_sb(mddev);
/* /*
* Kick recovery, maybe this spare has to be added to the * Kick recovery, maybe this spare has to be added to the
...@@ -2918,7 +2925,6 @@ int md_error(mddev_t *mddev, struct block_device *bdev) ...@@ -2918,7 +2925,6 @@ int md_error(mddev_t *mddev, struct block_device *bdev)
return 0; return 0;
if (!mddev->pers->error_handler if (!mddev->pers->error_handler
|| mddev->pers->error_handler(mddev,rdev) <= 0) { || mddev->pers->error_handler(mddev,rdev) <= 0) {
free_disk_sb(rrdev);
rrdev->faulty = 1; rrdev->faulty = 1;
} else } else
return 1; return 1;
...@@ -3423,8 +3429,7 @@ void md_do_recovery(void *data) ...@@ -3423,8 +3429,7 @@ void md_do_recovery(void *data)
sb->active_disks++; sb->active_disks++;
sb->spare_disks--; sb->spare_disks--;
} }
mddev->sb_dirty = 1; __md_update_sb(mddev);
md_update_sb(mddev);
mddev->recovery_running = 0; mddev->recovery_running = 0;
unlock: unlock:
mddev_unlock(mddev); mddev_unlock(mddev);
......
...@@ -699,7 +699,6 @@ static void multipathd (void *data) ...@@ -699,7 +699,6 @@ static void multipathd (void *data)
mddev = mp_bh->mddev; mddev = mp_bh->mddev;
if (mddev->sb_dirty) { if (mddev->sb_dirty) {
printk(KERN_INFO "dirty sb detected, updating.\n"); printk(KERN_INFO "dirty sb detected, updating.\n");
mddev->sb_dirty = 0;
md_update_sb(mddev); md_update_sb(mddev);
} }
bio = mp_bh->bio; bio = mp_bh->bio;
......
...@@ -1084,7 +1084,6 @@ static void raid1d(void *data) ...@@ -1084,7 +1084,6 @@ static void raid1d(void *data)
conf = mddev_to_conf(mddev); conf = mddev_to_conf(mddev);
if (mddev->sb_dirty) { if (mddev->sb_dirty) {
printk(KERN_INFO "raid1: dirty sb detected, updating.\n"); printk(KERN_INFO "raid1: dirty sb detected, updating.\n");
mddev->sb_dirty = 0;
md_update_sb(mddev); md_update_sb(mddev);
} }
bio = r1_bio->master_bio; bio = r1_bio->master_bio;
......
...@@ -1335,10 +1335,8 @@ static void raid5d (void *data) ...@@ -1335,10 +1335,8 @@ static void raid5d (void *data)
handled = 0; handled = 0;
if (mddev->sb_dirty) { if (mddev->sb_dirty)
mddev->sb_dirty = 0;
md_update_sb(mddev); md_update_sb(mddev);
}
spin_lock_irq(&conf->device_lock); spin_lock_irq(&conf->device_lock);
while (1) { while (1) {
struct list_head *first; struct list_head *first;
......
...@@ -75,7 +75,7 @@ extern mdk_thread_t * md_register_thread (void (*run) (void *data), ...@@ -75,7 +75,7 @@ extern mdk_thread_t * md_register_thread (void (*run) (void *data),
extern void md_unregister_thread (mdk_thread_t *thread); extern void md_unregister_thread (mdk_thread_t *thread);
extern void md_wakeup_thread(mdk_thread_t *thread); extern void md_wakeup_thread(mdk_thread_t *thread);
extern void md_interrupt_thread (mdk_thread_t *thread); extern void md_interrupt_thread (mdk_thread_t *thread);
extern int md_update_sb (mddev_t *mddev); extern void md_update_sb (mddev_t *mddev);
extern int md_do_sync(mddev_t *mddev, mdp_disk_t *spare); extern int md_do_sync(mddev_t *mddev, mdp_disk_t *spare);
extern void md_done_sync(mddev_t *mddev, int blocks, int ok); extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
extern void md_sync_acct(kdev_t dev, unsigned long nr_sectors); extern void md_sync_acct(kdev_t dev, unsigned long nr_sectors);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment