diff options
author | Alan Jenkins <alan-jenkins@tuffmail.co.uk> | 2009-07-29 15:07:55 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2009-07-29 15:07:55 -0400 |
commit | dddac6a7b445de95515f64fdf82fe5dc36c02f26 (patch) | |
tree | 39651610292d6b0c17f210f253a0dd16b022727d | |
parent | ec79be26875f6c1468784876cb99192b7f41c7a5 (diff) |
PM / Hibernate: Replace bdget call with simple atomic_inc of i_count
Create bdgrab(). This function copies an existing reference to a
block_device. It is safe to call from any context.
Hibernation code wishes to copy a reference to the active swap device.
Right now it calls bdget() under a spinlock, but this is wrong because
bdget() can sleep. It doesn't need a full bdget() because we already
hold a reference to active swap devices (and the spinlock protects
against swapoff).
Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13827
Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | fs/block_dev.c | 10 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | mm/swapfile.c | 4 |
3 files changed, 13 insertions, 2 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 3a6d4fb2a329..94dfda24c06e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -564,6 +564,16 @@ struct block_device *bdget(dev_t dev) | |||
564 | 564 | ||
565 | EXPORT_SYMBOL(bdget); | 565 | EXPORT_SYMBOL(bdget); |
566 | 566 | ||
567 | /** | ||
568 | * bdgrab -- Grab a reference to an already referenced block device | ||
569 | * @bdev: Block device to grab a reference to. | ||
570 | */ | ||
571 | struct block_device *bdgrab(struct block_device *bdev) | ||
572 | { | ||
573 | atomic_inc(&bdev->bd_inode->i_count); | ||
574 | return bdev; | ||
575 | } | ||
576 | |||
567 | long nr_blockdev_pages(void) | 577 | long nr_blockdev_pages(void) |
568 | { | 578 | { |
569 | struct block_device *bdev; | 579 | struct block_device *bdev; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 0872372184fe..a36ffa5a77a4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1946,6 +1946,7 @@ extern void putname(const char *name); | |||
1946 | extern int register_blkdev(unsigned int, const char *); | 1946 | extern int register_blkdev(unsigned int, const char *); |
1947 | extern void unregister_blkdev(unsigned int, const char *); | 1947 | extern void unregister_blkdev(unsigned int, const char *); |
1948 | extern struct block_device *bdget(dev_t); | 1948 | extern struct block_device *bdget(dev_t); |
1949 | extern struct block_device *bdgrab(struct block_device *bdev); | ||
1949 | extern void bd_set_size(struct block_device *, loff_t size); | 1950 | extern void bd_set_size(struct block_device *, loff_t size); |
1950 | extern void bd_forget(struct inode *inode); | 1951 | extern void bd_forget(struct inode *inode); |
1951 | extern void bdput(struct block_device *); | 1952 | extern void bdput(struct block_device *); |
diff --git a/mm/swapfile.c b/mm/swapfile.c index d1ade1a48ee7..8ffdc0d23c53 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -753,7 +753,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p) | |||
753 | 753 | ||
754 | if (!bdev) { | 754 | if (!bdev) { |
755 | if (bdev_p) | 755 | if (bdev_p) |
756 | *bdev_p = bdget(sis->bdev->bd_dev); | 756 | *bdev_p = bdgrab(sis->bdev); |
757 | 757 | ||
758 | spin_unlock(&swap_lock); | 758 | spin_unlock(&swap_lock); |
759 | return i; | 759 | return i; |
@@ -765,7 +765,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p) | |||
765 | struct swap_extent, list); | 765 | struct swap_extent, list); |
766 | if (se->start_block == offset) { | 766 | if (se->start_block == offset) { |
767 | if (bdev_p) | 767 | if (bdev_p) |
768 | *bdev_p = bdget(sis->bdev->bd_dev); | 768 | *bdev_p = bdgrab(sis->bdev); |
769 | 769 | ||
770 | spin_unlock(&swap_lock); | 770 | spin_unlock(&swap_lock); |
771 | bdput(bdev); | 771 | bdput(bdev); |