Skip to content

Commit

Permalink
md/bitmap: protect against bitmap removal while being updated.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
NeilBrown committed Dec 14, 2009
1 parent f405425 commit aa5cbd1
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 8 deletions.
24 changes: 18 additions & 6 deletions drivers/md/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1078,23 +1078,31 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
* out to disk
*/

void bitmap_daemon_work(struct bitmap *bitmap)
void bitmap_daemon_work(mddev_t *mddev)
{
struct bitmap *bitmap;
unsigned long j;
unsigned long flags;
struct page *page = NULL, *lastpage = NULL;
int blocks;
void *paddr;

if (bitmap == NULL)
/* Use a mutex to guard daemon_work against
* bitmap_destroy.
*/
mutex_lock(&mddev->bitmap_mutex);
bitmap = mddev->bitmap;
if (bitmap == NULL) {
mutex_unlock(&mddev->bitmap_mutex);
return;
}
if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ))
goto done;

bitmap->daemon_lastrun = jiffies;
if (bitmap->allclean) {
bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
return;
goto done;
}
bitmap->allclean = 1;

Expand Down Expand Up @@ -1203,6 +1211,7 @@ void bitmap_daemon_work(struct bitmap *bitmap)
done:
if (bitmap->allclean == 0)
bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ;
mutex_unlock(&mddev->bitmap_mutex);
}

static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
Expand Down Expand Up @@ -1541,9 +1550,9 @@ void bitmap_flush(mddev_t *mddev)
*/
sleep = bitmap->daemon_sleep;
bitmap->daemon_sleep = 0;
bitmap_daemon_work(bitmap);
bitmap_daemon_work(bitmap);
bitmap_daemon_work(bitmap);
bitmap_daemon_work(mddev);
bitmap_daemon_work(mddev);
bitmap_daemon_work(mddev);
bitmap->daemon_sleep = sleep;
bitmap_update_sb(bitmap);
}
Expand Down Expand Up @@ -1574,14 +1583,17 @@ static void bitmap_free(struct bitmap *bitmap)
kfree(bp);
kfree(bitmap);
}

void bitmap_destroy(mddev_t *mddev)
{
struct bitmap *bitmap = mddev->bitmap;

if (!bitmap) /* there was no bitmap */
return;

mutex_lock(&mddev->bitmap_mutex);
mddev->bitmap = NULL; /* disconnect from the md device */
mutex_unlock(&mddev->bitmap_mutex);
if (mddev->thread)
mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;

Expand Down
2 changes: 1 addition & 1 deletion drivers/md/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ void bitmap_close_sync(struct bitmap *bitmap);
void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);

void bitmap_unplug(struct bitmap *bitmap);
void bitmap_daemon_work(struct bitmap *bitmap);
void bitmap_daemon_work(mddev_t *mddev);
#endif

#endif
3 changes: 2 additions & 1 deletion drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ static mddev_t * mddev_find(dev_t unit)

mutex_init(&new->open_mutex);
mutex_init(&new->reconfig_mutex);
mutex_init(&new->bitmap_mutex);
INIT_LIST_HEAD(&new->disks);
INIT_LIST_HEAD(&new->all_mddevs);
init_timer(&new->safemode_timer);
Expand Down Expand Up @@ -6625,7 +6626,7 @@ void md_check_recovery(mddev_t *mddev)


if (mddev->bitmap)
bitmap_daemon_work(mddev->bitmap);
bitmap_daemon_work(mddev);

if (mddev->ro)
return;
Expand Down
1 change: 1 addition & 0 deletions drivers/md/md.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ struct mddev_s
* hot-adding a bitmap. It should
* eventually be settable by sysfs.
*/
struct mutex bitmap_mutex;

struct list_head all_mddevs;
};
Expand Down

0 comments on commit aa5cbd1

Please sign in to comment.