aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-06-21 20:17:12 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-21 22:07:43 -0400
commit06d91a5fe0b50c9060e70bdf7786f8a3c66249db (patch)
tree95a8b9228534cebb12eb31c1cc9cc0c45f685410 /drivers/md/md.c
parentfca4d848f0e6fafdc2b25f8a0cf1e76935f13ac2 (diff)
[PATCH] md: improve locking on 'safemode' and move superblock writes
When md marks the superblock dirty before a write, it calls generic_make_request (to write the superblock) from within generic_make_request (to write the first dirty block), which could cause problems later. With this patch, the superblock write is always done by the helper thread, and write request are delayed until that write completes. Also, the locking around marking the array dirty and writing the superblock is improved to avoid possible races. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c73
1 files changed, 59 insertions, 14 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c842e34d850e..177d2a7d7cea 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -218,6 +218,8 @@ static mddev_t * mddev_find(dev_t unit)
218 INIT_LIST_HEAD(&new->all_mddevs); 218 INIT_LIST_HEAD(&new->all_mddevs);
219 init_timer(&new->safemode_timer); 219 init_timer(&new->safemode_timer);
220 atomic_set(&new->active, 1); 220 atomic_set(&new->active, 1);
221 bio_list_init(&new->write_list);
222 spin_lock_init(&new->write_lock);
221 223
222 new->queue = blk_alloc_queue(GFP_KERNEL); 224 new->queue = blk_alloc_queue(GFP_KERNEL);
223 if (!new->queue) { 225 if (!new->queue) {
@@ -1251,9 +1253,11 @@ static void md_update_sb(mddev_t * mddev)
1251 int err, count = 100; 1253 int err, count = 100;
1252 struct list_head *tmp; 1254 struct list_head *tmp;
1253 mdk_rdev_t *rdev; 1255 mdk_rdev_t *rdev;
1256 int sync_req;
1254 1257
1255 mddev->sb_dirty = 0;
1256repeat: 1258repeat:
1259 spin_lock(&mddev->write_lock);
1260 sync_req = mddev->in_sync;
1257 mddev->utime = get_seconds(); 1261 mddev->utime = get_seconds();
1258 mddev->events ++; 1262 mddev->events ++;
1259 1263
@@ -1272,8 +1276,12 @@ repeat:
1272 * do not write anything to disk if using 1276 * do not write anything to disk if using
1273 * nonpersistent superblocks 1277 * nonpersistent superblocks
1274 */ 1278 */
1275 if (!mddev->persistent) 1279 if (!mddev->persistent) {
1280 mddev->sb_dirty = 0;
1281 spin_unlock(&mddev->write_lock);
1276 return; 1282 return;
1283 }
1284 spin_unlock(&mddev->write_lock);
1277 1285
1278 dprintk(KERN_INFO 1286 dprintk(KERN_INFO
1279 "md: updating %s RAID superblock on device (in sync %d)\n", 1287 "md: updating %s RAID superblock on device (in sync %d)\n",
@@ -1304,6 +1312,15 @@ repeat:
1304 printk(KERN_ERR \ 1312 printk(KERN_ERR \
1305 "md: excessive errors occurred during superblock update, exiting\n"); 1313 "md: excessive errors occurred during superblock update, exiting\n");
1306 } 1314 }
1315 spin_lock(&mddev->write_lock);
1316 if (mddev->in_sync != sync_req) {
1317 /* have to write it out again */
1318 spin_unlock(&mddev->write_lock);
1319 goto repeat;
1320 }
1321 mddev->sb_dirty = 0;
1322 spin_unlock(&mddev->write_lock);
1323
1307} 1324}
1308 1325
1309/* 1326/*
@@ -3178,19 +3195,31 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok)
3178} 3195}
3179 3196
3180 3197
3181void md_write_start(mddev_t *mddev) 3198/* md_write_start(mddev, bi)
3199 * If we need to update some array metadata (e.g. 'active' flag
3200 * in superblock) before writing, queue bi for later writing
3201 * and return 0, else return 1 and it will be written now
3202 */
3203int md_write_start(mddev_t *mddev, struct bio *bi)
3182{ 3204{
3183 if (!atomic_read(&mddev->writes_pending)) { 3205 if (bio_data_dir(bi) != WRITE)
3184 mddev_lock_uninterruptible(mddev); 3206 return 1;
3185 if (mddev->in_sync) { 3207
3186 mddev->in_sync = 0; 3208 atomic_inc(&mddev->writes_pending);
3187 del_timer(&mddev->safemode_timer); 3209 spin_lock(&mddev->write_lock);
3188 md_update_sb(mddev); 3210 if (mddev->in_sync == 0 && mddev->sb_dirty == 0) {
3189 } 3211 spin_unlock(&mddev->write_lock);
3190 atomic_inc(&mddev->writes_pending); 3212 return 1;
3191 mddev_unlock(mddev); 3213 }
3192 } else 3214 bio_list_add(&mddev->write_list, bi);
3193 atomic_inc(&mddev->writes_pending); 3215
3216 if (mddev->in_sync) {
3217 mddev->in_sync = 0;
3218 mddev->sb_dirty = 1;
3219 }
3220 spin_unlock(&mddev->write_lock);
3221 md_wakeup_thread(mddev->thread);
3222 return 0;
3194} 3223}
3195 3224
3196void md_write_end(mddev_t *mddev) 3225void md_write_end(mddev_t *mddev)
@@ -3472,6 +3501,7 @@ void md_check_recovery(mddev_t *mddev)
3472 mddev->sb_dirty || 3501 mddev->sb_dirty ||
3473 test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || 3502 test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
3474 test_bit(MD_RECOVERY_DONE, &mddev->recovery) || 3503 test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
3504 mddev->write_list.head ||
3475 (mddev->safemode == 1) || 3505 (mddev->safemode == 1) ||
3476 (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) 3506 (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
3477 && !mddev->in_sync && mddev->recovery_cp == MaxSector) 3507 && !mddev->in_sync && mddev->recovery_cp == MaxSector)
@@ -3480,7 +3510,9 @@ void md_check_recovery(mddev_t *mddev)
3480 3510
3481 if (mddev_trylock(mddev)==0) { 3511 if (mddev_trylock(mddev)==0) {
3482 int spares =0; 3512 int spares =0;
3513 struct bio *blist;
3483 3514
3515 spin_lock(&mddev->write_lock);
3484 if (mddev->safemode && !atomic_read(&mddev->writes_pending) && 3516 if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
3485 !mddev->in_sync && mddev->recovery_cp == MaxSector) { 3517 !mddev->in_sync && mddev->recovery_cp == MaxSector) {
3486 mddev->in_sync = 1; 3518 mddev->in_sync = 1;
@@ -3488,9 +3520,22 @@ void md_check_recovery(mddev_t *mddev)
3488 } 3520 }
3489 if (mddev->safemode == 1) 3521 if (mddev->safemode == 1)
3490 mddev->safemode = 0; 3522 mddev->safemode = 0;
3523 blist = bio_list_get(&mddev->write_list);
3524 spin_unlock(&mddev->write_lock);
3491 3525
3492 if (mddev->sb_dirty) 3526 if (mddev->sb_dirty)
3493 md_update_sb(mddev); 3527 md_update_sb(mddev);
3528
3529 while (blist) {
3530 struct bio *b = blist;
3531 blist = blist->bi_next;
3532 b->bi_next = NULL;
3533 generic_make_request(b);
3534 /* we already counted this, so need to un-count */
3535 md_write_end(mddev);
3536 }
3537
3538
3494 if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && 3539 if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
3495 !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) { 3540 !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
3496 /* resync/recovery still happening */ 3541 /* resync/recovery still happening */