Skip to content

Commit

Permalink
backing-dev: ensure that a removed bdi no longer has super_block refe…
Browse files Browse the repository at this point in the history
…rencing 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: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
  • Loading branch information
Jens Axboe committed Oct 29, 2009
1 parent 960cc0f commit 592b09a
Showing 1 changed file with 16 additions and 0 deletions.
16 changes: 16 additions & 0 deletions mm/backing-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,21 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
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)
{
if (bdi->dev) {
Expand Down Expand Up @@ -682,6 +697,7 @@ void bdi_destroy(struct backing_dev_info *bdi)
spin_unlock(&inode_lock);
}

bdi_prune_sb(bdi);
bdi_unregister(bdi);

for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
Expand Down

0 comments on commit 592b09a

Please sign in to comment.