summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2003-03-14 02:09:01 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2003-03-14 02:09:01 -0800
commit9578658e998baaf5bf36d1053b690bd28976b1ca (patch)
treee5fec4439e312003331cd2b6745e90f9f6feff63
parent8eec7ce0744430471c1fce2a503829cd7cd80f11 (diff)
[PATCH] md: Fulltime delayed 'safe_mode' for md
From: Angus Sawyer <angus.sawyer@dsl.pipex.com> If there are no writes for 20 milliseconds, write out superblock to mark array as clean. Write out superblock with dirty flag before allowing any further write to succeed. If an md thread gets signaled with SIGKILL, reduce the delay to 0. Also tidy up some printk's and make sure writing the superblock isn't noisy.
-rw-r--r--drivers/md/md.c64
-rw-r--r--include/linux/raid/md_k.h4
2 files changed, 44 insertions, 24 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 14fd1eadc8d9..5689df88774a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -219,6 +219,7 @@ static mddev_t * mddev_find(int unit)
init_MUTEX(&new->reconfig_sem);
INIT_LIST_HEAD(&new->disks);
INIT_LIST_HEAD(&new->all_mddevs);
+ init_timer(&new->safemode_timer);
atomic_set(&new->active, 1);
blk_queue_make_request(&new->queue, md_fail_request);
@@ -701,10 +702,8 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->recovery_cp = mddev->recovery_cp;
sb->cp_events_hi = (mddev->events>>32);
sb->cp_events_lo = (u32)mddev->events;
- if (mddev->recovery_cp == MaxSector) {
- printk(KERN_INFO "md: marking sb clean...\n");
+ if (mddev->recovery_cp == MaxSector)
sb->state = (1<< MD_SB_CLEAN);
- }
} else
sb->recovery_cp = 0;
@@ -1005,7 +1004,7 @@ static int write_disk_sb(mdk_rdev_t * rdev)
sb_offset = calc_dev_sboffset(rdev->bdev);
if (rdev->sb_offset != sb_offset) {
- printk(KERN_INFO "%s's sb offset has changed from %llu to %llu, skipping\n",
+ printk("%s's sb offset has changed from %llu to %llu, skipping\n",
bdev_partition_name(rdev->bdev),
(unsigned long long)rdev->sb_offset,
(unsigned long long)sb_offset);
@@ -1025,7 +1024,7 @@ static int write_disk_sb(mdk_rdev_t * rdev)
goto skip;
}
- printk(KERN_INFO "(write) %s's sb offset: %llu\n", bdev_partition_name(rdev->bdev), (unsigned long long)sb_offset);
+ dprintk("(write) %s's sb offset: %llu\n", bdev_partition_name(rdev->bdev), (unsigned long long)sb_offset);
if (!sync_page_io(rdev->bdev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE))
goto fail;
@@ -1076,20 +1075,20 @@ repeat:
if (!mddev->persistent)
return;
- printk(KERN_INFO "md: updating md%d RAID superblock on device (in sync %d)\n",
+ dprintk(KERN_INFO "md: updating md%d RAID superblock on device (in sync %d)\n",
mdidx(mddev),mddev->in_sync);
err = 0;
ITERATE_RDEV(mddev,rdev,tmp) {
- printk(KERN_INFO "md: ");
+ dprintk(KERN_INFO "md: ");
if (rdev->faulty)
- printk("(skipping faulty ");
+ dprintk("(skipping faulty ");
- printk("%s ", bdev_partition_name(rdev->bdev));
+ dprintk("%s ", bdev_partition_name(rdev->bdev));
if (!rdev->faulty) {
err += write_disk_sb(rdev);
} else
- printk(")\n");
+ dprintk(")\n");
if (!err && mddev->level == LEVEL_MULTIPATH)
/* only need to write one superblock... */
break;
@@ -1377,6 +1376,16 @@ static struct gendisk *md_probe(dev_t dev, int *part, void *data)
return NULL;
}
+void md_wakeup_thread(mdk_thread_t *thread);
+
+static void md_safemode_timeout(unsigned long data)
+{
+ mddev_t *mddev = (mddev_t *) data;
+
+ mddev->safemode = 1;
+ md_wakeup_thread(mddev->thread);
+}
+
#define TOO_BIG_CHUNKSIZE KERN_ERR \
"too big chunk_size: %d > %d\n"
@@ -1518,10 +1527,10 @@ static int do_md_run(mddev_t * mddev)
}
atomic_set(&mddev->writes_pending,0);
mddev->safemode = 0;
- if (mddev->pers->sync_request)
- mddev->in_sync = 0;
- else
- mddev->in_sync = 1;
+ mddev->safemode_timer.function = md_safemode_timeout;
+ mddev->safemode_timer.data = (unsigned long) mddev;
+ mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
+ mddev->in_sync = 1;
md_update_sb(mddev);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -1551,7 +1560,6 @@ static int restart_array(mddev_t *mddev)
goto out;
mddev->safemode = 0;
- mddev->in_sync = 0;
md_update_sb(mddev);
mddev->ro = 0;
set_disk_ro(disk, 0);
@@ -1597,6 +1605,8 @@ static int do_md_stop(mddev_t * mddev, int ro)
mddev->sync_thread = NULL;
}
+ del_timer_sync(&mddev->safemode_timer);
+
invalidate_device(mk_kdev(disk->major, disk->first_minor), 1);
if (ro) {
@@ -1886,7 +1896,7 @@ static int get_array_info(mddev_t * mddev, void * arg)
info.utime = mddev->utime;
info.state = 0;
- if (mddev->recovery_cp == MaxSector)
+ if (mddev->in_sync)
info.state = (1<<MD_SB_CLEAN);
info.active_disks = active;
info.working_disks = working;
@@ -2896,13 +2906,14 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok)
void md_write_start(mddev_t *mddev)
{
- if (mddev->safemode && !atomic_read(&mddev->writes_pending)) {
+ if (!atomic_read(&mddev->writes_pending)) {
mddev_lock_uninterruptible(mddev);
- atomic_inc(&mddev->writes_pending);
if (mddev->in_sync) {
mddev->in_sync = 0;
+ del_timer(&mddev->safemode_timer);
md_update_sb(mddev);
}
+ atomic_inc(&mddev->writes_pending);
mddev_unlock(mddev);
} else
atomic_inc(&mddev->writes_pending);
@@ -2910,12 +2921,16 @@ void md_write_start(mddev_t *mddev)
void md_write_end(mddev_t *mddev)
{
- if (atomic_dec_and_test(&mddev->writes_pending) && mddev->safemode)
- md_wakeup_thread(mddev->thread);
+ if (atomic_dec_and_test(&mddev->writes_pending)) {
+ if (mddev->safemode == 2)
+ md_wakeup_thread(mddev->thread);
+ else
+ mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay);
+ }
}
+
static inline void md_enter_safemode(mddev_t *mddev)
{
-
mddev_lock_uninterruptible(mddev);
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
@@ -2923,13 +2938,16 @@ static inline void md_enter_safemode(mddev_t *mddev)
md_update_sb(mddev);
}
mddev_unlock(mddev);
+
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
}
void md_handle_safemode(mddev_t *mddev)
{
if (signal_pending(current)) {
- printk(KERN_INFO "md: md%d in safe mode\n",mdidx(mddev));
- mddev->safemode= 1;
+ printk(KERN_INFO "md: md%d in immediate safe mode\n",mdidx(mddev));
+ mddev->safemode = 2;
flush_signals(current);
}
if (mddev->safemode)
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index eb232ae1c768..9f071d407f7b 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -239,9 +239,11 @@ struct mddev_s
atomic_t recovery_active; /* blocks scheduled, but not written */
wait_queue_head_t recovery_wait;
sector_t recovery_cp;
- int safemode; /* if set, update "clean" superblock
+ unsigned int safemode; /* if set, update "clean" superblock
* when no writes pending.
*/
+ unsigned int safemode_delay;
+ struct timer_list safemode_timer;
atomic_t writes_pending;
request_queue_t queue; /* for plugging ... */