Commit 592b09a4 authored by Jens Axboe's avatar Jens Axboe

backing-dev: ensure that a removed bdi no longer has super_block referencing it

When the bdi is being removed, we have to ensure that no super_blocks
currently have that cached in sb->s_bdi. Normally this is ensured by
the sb having a longer life span than the bdi, but if the device is
suddenly yanked, we have to kill this reference. sb->s_bdi is pointed
to freed memory at that point.

This fixes a problem with sync(1) hanging when a USB stick is pulled
without cleanly umounting it first.
Reported-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 960cc0f4
...@@ -610,6 +610,21 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) ...@@ -610,6 +610,21 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
kthread_stop(wb->task); kthread_stop(wb->task);
} }
/*
* This bdi is going away now, make sure that no super_blocks point to it
*/
static void bdi_prune_sb(struct backing_dev_info *bdi)
{
struct super_block *sb;
spin_lock(&sb_lock);
list_for_each_entry(sb, &super_blocks, s_list) {
if (sb->s_bdi == bdi)
sb->s_bdi = NULL;
}
spin_unlock(&sb_lock);
}
void bdi_unregister(struct backing_dev_info *bdi) void bdi_unregister(struct backing_dev_info *bdi)
{ {
if (bdi->dev) { if (bdi->dev) {
...@@ -682,6 +697,7 @@ void bdi_destroy(struct backing_dev_info *bdi) ...@@ -682,6 +697,7 @@ void bdi_destroy(struct backing_dev_info *bdi)
spin_unlock(&inode_lock); spin_unlock(&inode_lock);
} }
bdi_prune_sb(bdi);
bdi_unregister(bdi); bdi_unregister(bdi);
for (i = 0; i < NR_BDI_STAT_ITEMS; i++) for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
......
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