diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index f5958f413bd1..028d9fb9c2d5 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -300,10 +300,10 @@ static struct super_operations bdev_sops = { | |||
300 | .clear_inode = bdev_clear_inode, | 300 | .clear_inode = bdev_clear_inode, |
301 | }; | 301 | }; |
302 | 302 | ||
303 | static struct super_block *bd_get_sb(struct file_system_type *fs_type, | 303 | static int bd_get_sb(struct file_system_type *fs_type, |
304 | int flags, const char *dev_name, void *data) | 304 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
305 | { | 305 | { |
306 | return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); | 306 | return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576, mnt); |
307 | } | 307 | } |
308 | 308 | ||
309 | static struct file_system_type bd_type = { | 309 | static struct file_system_type bd_type = { |
@@ -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) |