diff options
Diffstat (limited to 'fs/block_dev.c')
| -rw-r--r-- | fs/block_dev.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index f5958f413bd1..44aaba202f78 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -414,21 +414,31 @@ EXPORT_SYMBOL(bdput); | |||
| 414 | static struct block_device *bd_acquire(struct inode *inode) | 414 | static struct block_device *bd_acquire(struct inode *inode) |
| 415 | { | 415 | { |
| 416 | struct block_device *bdev; | 416 | struct block_device *bdev; |
| 417 | |||
| 417 | spin_lock(&bdev_lock); | 418 | spin_lock(&bdev_lock); |
| 418 | bdev = inode->i_bdev; | 419 | bdev = inode->i_bdev; |
| 419 | if (bdev && igrab(bdev->bd_inode)) { | 420 | if (bdev) { |
| 421 | atomic_inc(&bdev->bd_inode->i_count); | ||
| 420 | spin_unlock(&bdev_lock); | 422 | spin_unlock(&bdev_lock); |
| 421 | return bdev; | 423 | return bdev; |
| 422 | } | 424 | } |
| 423 | spin_unlock(&bdev_lock); | 425 | spin_unlock(&bdev_lock); |
| 426 | |||
| 424 | bdev = bdget(inode->i_rdev); | 427 | bdev = bdget(inode->i_rdev); |
| 425 | if (bdev) { | 428 | if (bdev) { |
| 426 | spin_lock(&bdev_lock); | 429 | spin_lock(&bdev_lock); |
| 427 | if (inode->i_bdev) | 430 | if (!inode->i_bdev) { |
| 428 | __bd_forget(inode); | 431 | /* |
| 429 | inode->i_bdev = bdev; | 432 | * We take an additional bd_inode->i_count for inode, |
| 430 | inode->i_mapping = bdev->bd_inode->i_mapping; | 433 | * and it's released in clear_inode() of inode. |
| 431 | list_add(&inode->i_devices, &bdev->bd_inodes); | 434 | * So, we can access it via ->i_mapping always |
| 435 | * without igrab(). | ||
| 436 | */ | ||
| 437 | atomic_inc(&bdev->bd_inode->i_count); | ||
| 438 | inode->i_bdev = bdev; | ||
| 439 | inode->i_mapping = bdev->bd_inode->i_mapping; | ||
| 440 | list_add(&inode->i_devices, &bdev->bd_inodes); | ||
| 441 | } | ||
| 432 | spin_unlock(&bdev_lock); | 442 | spin_unlock(&bdev_lock); |
| 433 | } | 443 | } |
| 434 | return bdev; | 444 | return bdev; |
| @@ -438,10 +448,18 @@ static struct block_device *bd_acquire(struct inode *inode) | |||
| 438 | 448 | ||
| 439 | void bd_forget(struct inode *inode) | 449 | void bd_forget(struct inode *inode) |
| 440 | { | 450 | { |
| 451 | struct block_device *bdev = NULL; | ||
| 452 | |||
| 441 | spin_lock(&bdev_lock); | 453 | spin_lock(&bdev_lock); |
| 442 | if (inode->i_bdev) | 454 | if (inode->i_bdev) { |
| 455 | if (inode->i_sb != blockdev_superblock) | ||
| 456 | bdev = inode->i_bdev; | ||
| 443 | __bd_forget(inode); | 457 | __bd_forget(inode); |
| 458 | } | ||
| 444 | spin_unlock(&bdev_lock); | 459 | spin_unlock(&bdev_lock); |
| 460 | |||
| 461 | if (bdev) | ||
| 462 | iput(bdev->bd_inode); | ||
| 445 | } | 463 | } |
| 446 | 464 | ||
| 447 | int bd_claim(struct block_device *bdev, void *holder) | 465 | int bd_claim(struct block_device *bdev, void *holder) |
