aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-12-13 20:49:46 -0500
committerNeilBrown <neilb@suse.de>2009-12-13 20:49:46 -0500
commitaa5cbd103887011b4830355f88fb055f9ad2d556 (patch)
tree92ef7c80999c6d0bfc6fef9a9cd3e4a75ee16c06 /drivers
parentf40542532e96dda5506eb76badea322f2ae4731c (diff)
md/bitmap: protect against bitmap removal while being updated.
A write intent bitmap can be removed from an array while the array is active. When this happens, all IO is suspended and flushed before the bitmap is removed. However it is possible that bitmap_daemon_work is still running to clear old bits from the bitmap. If it is, it can dereference the bitmap after it has been freed. So introduce a new mutex to protect bitmap_daemon_work and get it before destroying a bitmap. This is suitable for any current -stable kernel. Signed-off-by: NeilBrown <neilb@suse.de> Cc: stable@kernel.org
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/bitmap.c24
-rw-r--r--drivers/md/bitmap.h2
-rw-r--r--drivers/md/md.c3
-rw-r--r--drivers/md/md.h1
4 files changed, 22 insertions, 8 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 60e2b322db11..a5e5f2fbf963 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1078,23 +1078,31 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
1078 * out to disk 1078 * out to disk
1079 */ 1079 */
1080 1080
1081void bitmap_daemon_work(struct bitmap *bitmap) 1081void bitmap_daemon_work(mddev_t *mddev)
1082{ 1082{
1083 struct bitmap *bitmap;
1083 unsigned long j; 1084 unsigned long j;
1084 unsigned long flags; 1085 unsigned long flags;
1085 struct page *page = NULL, *lastpage = NULL; 1086 struct page *page = NULL, *lastpage = NULL;
1086 int blocks; 1087 int blocks;
1087 void *paddr; 1088 void *paddr;
1088 1089
1089 if (bitmap == NULL) 1090 /* Use a mutex to guard daemon_work against
1091 * bitmap_destroy.
1092 */
1093 mutex_lock(&mddev->bitmap_mutex);
1094 bitmap = mddev->bitmap;
1095 if (bitmap == NULL) {
1096 mutex_unlock(&mddev->bitmap_mutex);
1090 return; 1097 return;
1098 }
1091 if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) 1099 if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ))
1092 goto done; 1100 goto done;
1093 1101
1094 bitmap->daemon_lastrun = jiffies; 1102 bitmap->daemon_lastrun = jiffies;
1095 if (bitmap->allclean) { 1103 if (bitmap->allclean) {
1096 bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; 1104 bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
1097 return; 1105 goto done;
1098 } 1106 }
1099 bitmap->allclean = 1; 1107 bitmap->allclean = 1;
1100 1108
@@ -1203,6 +1211,7 @@ void bitmap_daemon_work(struct bitmap *bitmap)
1203 done: 1211 done:
1204 if (bitmap->allclean == 0) 1212 if (bitmap->allclean == 0)
1205 bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; 1213 bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ;
1214 mutex_unlock(&mddev->bitmap_mutex);
1206} 1215}
1207 1216
1208static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, 1217static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
@@ -1541,9 +1550,9 @@ void bitmap_flush(mddev_t *mddev)
1541 */ 1550 */
1542 sleep = bitmap->daemon_sleep; 1551 sleep = bitmap->daemon_sleep;
1543 bitmap->daemon_sleep = 0; 1552 bitmap->daemon_sleep = 0;
1544 bitmap_daemon_work(bitmap); 1553 bitmap_daemon_work(mddev);
1545 bitmap_daemon_work(bitmap); 1554 bitmap_daemon_work(mddev);
1546 bitmap_daemon_work(bitmap); 1555 bitmap_daemon_work(mddev);
1547 bitmap->daemon_sleep = sleep; 1556 bitmap->daemon_sleep = sleep;
1548 bitmap_update_sb(bitmap); 1557 bitmap_update_sb(bitmap);
1549} 1558}
@@ -1574,6 +1583,7 @@ static void bitmap_free(struct bitmap *bitmap)
1574 kfree(bp); 1583 kfree(bp);
1575 kfree(bitmap); 1584 kfree(bitmap);
1576} 1585}
1586
1577void bitmap_destroy(mddev_t *mddev) 1587void bitmap_destroy(mddev_t *mddev)
1578{ 1588{
1579 struct bitmap *bitmap = mddev->bitmap; 1589 struct bitmap *bitmap = mddev->bitmap;
@@ -1581,7 +1591,9 @@ void bitmap_destroy(mddev_t *mddev)
1581 if (!bitmap) /* there was no bitmap */ 1591 if (!bitmap) /* there was no bitmap */
1582 return; 1592 return;
1583 1593
1594 mutex_lock(&mddev->bitmap_mutex);
1584 mddev->bitmap = NULL; /* disconnect from the md device */ 1595 mddev->bitmap = NULL; /* disconnect from the md device */
1596 mutex_unlock(&mddev->bitmap_mutex);
1585 if (mddev->thread) 1597 if (mddev->thread)
1586 mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; 1598 mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
1587 1599
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index e98900671ca9..7e38d13ddcac 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -282,7 +282,7 @@ void bitmap_close_sync(struct bitmap *bitmap);
282void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); 282void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
283 283
284void bitmap_unplug(struct bitmap *bitmap); 284void bitmap_unplug(struct bitmap *bitmap);
285void bitmap_daemon_work(struct bitmap *bitmap); 285void bitmap_daemon_work(mddev_t *mddev);
286#endif 286#endif
287 287
288#endif 288#endif
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5f154ef1e4be..1be7a16a7a53 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -363,6 +363,7 @@ static mddev_t * mddev_find(dev_t unit)
363 363
364 mutex_init(&new->open_mutex); 364 mutex_init(&new->open_mutex);
365 mutex_init(&new->reconfig_mutex); 365 mutex_init(&new->reconfig_mutex);
366 mutex_init(&new->bitmap_mutex);
366 INIT_LIST_HEAD(&new->disks); 367 INIT_LIST_HEAD(&new->disks);
367 INIT_LIST_HEAD(&new->all_mddevs); 368 INIT_LIST_HEAD(&new->all_mddevs);
368 init_timer(&new->safemode_timer); 369 init_timer(&new->safemode_timer);
@@ -6625,7 +6626,7 @@ void md_check_recovery(mddev_t *mddev)
6625 6626
6626 6627
6627 if (mddev->bitmap) 6628 if (mddev->bitmap)
6628 bitmap_daemon_work(mddev->bitmap); 6629 bitmap_daemon_work(mddev);
6629 6630
6630 if (mddev->ro) 6631 if (mddev->ro)
6631 return; 6632 return;
diff --git a/drivers/md/md.h b/drivers/md/md.h
index f184b69ef337..87430fea2875 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -289,6 +289,7 @@ struct mddev_s
289 * hot-adding a bitmap. It should 289 * hot-adding a bitmap. It should
290 * eventually be settable by sysfs. 290 * eventually be settable by sysfs.
291 */ 291 */
292 struct mutex bitmap_mutex;
292 293
293 struct list_head all_mddevs; 294 struct list_head all_mddevs;
294}; 295};