Commit a5491e0c7bb7387e3e6ff9994d6dc2efc78af56c

Authored by Dave Chinner
Committed by Al Viro
1 parent 99a3891924

fs: switch bdev inode bdi's correctly

bdev inodes can remain dirty even after their last close. Hence the
BDI associated with the bdev->inode gets modified duringthe last
close to point to the default BDI. However, the bdev inode still
needs to be moved to the dirty lists of the new BDI, otherwise it
will corrupt the writeback list is was left on.

Add a new function bdev_inode_switch_bdi() to move all the bdi state
from the old bdi to the new one safely. This is only a temporary
measure until the bdev inode<->bdi lifecycle problems are sorted
out.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 1 changed file with 21 additions and 5 deletions Side-by-side Diff

... ... @@ -48,6 +48,21 @@
48 48  
49 49 EXPORT_SYMBOL(I_BDEV);
50 50  
  51 +/*
  52 + * move the inode from it's current bdi to the a new bdi. if the inode is dirty
  53 + * we need to move it onto the dirty list of @dst so that the inode is always
  54 + * on the right list.
  55 + */
  56 +static void bdev_inode_switch_bdi(struct inode *inode,
  57 + struct backing_dev_info *dst)
  58 +{
  59 + spin_lock(&inode_lock);
  60 + inode->i_data.backing_dev_info = dst;
  61 + if (inode->i_state & I_DIRTY)
  62 + list_move(&inode->i_list, &dst->wb.b_dirty);
  63 + spin_unlock(&inode_lock);
  64 +}
  65 +
51 66 static sector_t max_block(struct block_device *bdev)
52 67 {
53 68 sector_t retval = ~((sector_t)0);
... ... @@ -1390,7 +1405,7 @@
1390 1405 bdi = blk_get_backing_dev_info(bdev);
1391 1406 if (bdi == NULL)
1392 1407 bdi = &default_backing_dev_info;
1393   - bdev->bd_inode->i_data.backing_dev_info = bdi;
  1408 + bdev_inode_switch_bdi(bdev->bd_inode, bdi);
1394 1409 }
1395 1410 if (bdev->bd_invalidated)
1396 1411 rescan_partitions(disk, bdev);
... ... @@ -1405,8 +1420,8 @@
1405 1420 if (ret)
1406 1421 goto out_clear;
1407 1422 bdev->bd_contains = whole;
1408   - bdev->bd_inode->i_data.backing_dev_info =
1409   - whole->bd_inode->i_data.backing_dev_info;
  1423 + bdev_inode_switch_bdi(bdev->bd_inode,
  1424 + whole->bd_inode->i_data.backing_dev_info);
1410 1425 bdev->bd_part = disk_get_part(disk, partno);
1411 1426 if (!(disk->flags & GENHD_FL_UP) ||
1412 1427 !bdev->bd_part || !bdev->bd_part->nr_sects) {
... ... @@ -1439,7 +1454,7 @@
1439 1454 disk_put_part(bdev->bd_part);
1440 1455 bdev->bd_disk = NULL;
1441 1456 bdev->bd_part = NULL;
1442   - bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
  1457 + bdev_inode_switch_bdi(bdev->bd_inode, &default_backing_dev_info);
1443 1458 if (bdev != bdev->bd_contains)
1444 1459 __blkdev_put(bdev->bd_contains, mode, 1);
1445 1460 bdev->bd_contains = NULL;
... ... @@ -1533,7 +1548,8 @@
1533 1548 disk_put_part(bdev->bd_part);
1534 1549 bdev->bd_part = NULL;
1535 1550 bdev->bd_disk = NULL;
1536   - bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
  1551 + bdev_inode_switch_bdi(bdev->bd_inode,
  1552 + &default_backing_dev_info);
1537 1553 if (bdev != bdev->bd_contains)
1538 1554 victim = bdev->bd_contains;
1539 1555 bdev->bd_contains = NULL;