diff options
| author | Jens Axboe <jens.axboe@oracle.com> | 2009-10-29 06:46:12 -0400 |
|---|---|---|
| committer | Jens Axboe <jens.axboe@oracle.com> | 2009-10-29 06:46:12 -0400 |
| commit | 592b09a42fc3ae6737a0f3ecf4fee42ecd0296f8 (patch) | |
| tree | d06ca7165c5dfc5224910993b36a50e54a896831 | |
| parent | 960cc0f4fef607baabc2232fbd7cce5368a9dcfd (diff) | |
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: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
| -rw-r--r-- | mm/backing-dev.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 5a37e2055717..1065b715ef64 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
| @@ -610,6 +610,21 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) | |||
| 610 | kthread_stop(wb->task); | 610 | kthread_stop(wb->task); |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | /* | ||
| 614 | * This bdi is going away now, make sure that no super_blocks point to it | ||
| 615 | */ | ||
| 616 | static void bdi_prune_sb(struct backing_dev_info *bdi) | ||
| 617 | { | ||
| 618 | struct super_block *sb; | ||
| 619 | |||
| 620 | spin_lock(&sb_lock); | ||
| 621 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 622 | if (sb->s_bdi == bdi) | ||
| 623 | sb->s_bdi = NULL; | ||
| 624 | } | ||
| 625 | spin_unlock(&sb_lock); | ||
| 626 | } | ||
| 627 | |||
| 613 | void bdi_unregister(struct backing_dev_info *bdi) | 628 | void bdi_unregister(struct backing_dev_info *bdi) |
| 614 | { | 629 | { |
| 615 | if (bdi->dev) { | 630 | if (bdi->dev) { |
| @@ -682,6 +697,7 @@ void bdi_destroy(struct backing_dev_info *bdi) | |||
| 682 | spin_unlock(&inode_lock); | 697 | spin_unlock(&inode_lock); |
| 683 | } | 698 | } |
| 684 | 699 | ||
| 700 | bdi_prune_sb(bdi); | ||
| 685 | bdi_unregister(bdi); | 701 | bdi_unregister(bdi); |
| 686 | 702 | ||
| 687 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) | 703 | for (i = 0; i < NR_BDI_STAT_ITEMS; i++) |
