Commit dddac6a7b445de95515f64fdf82fe5dc36c02f26
Committed by
Rafael J. Wysocki
1 parent
ec79be2687
Exists in
master
and in
4 other branches
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>
Showing 3 changed files with 13 additions and 2 deletions Side-by-side Diff
fs/block_dev.c
... | ... | @@ -564,6 +564,16 @@ |
564 | 564 | |
565 | 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 | 577 | long nr_blockdev_pages(void) |
568 | 578 | { |
569 | 579 | struct block_device *bdev; |
include/linux/fs.h
... | ... | @@ -1946,6 +1946,7 @@ |
1946 | 1946 | extern int register_blkdev(unsigned int, const char *); |
1947 | 1947 | extern void unregister_blkdev(unsigned int, const char *); |
1948 | 1948 | extern struct block_device *bdget(dev_t); |
1949 | +extern struct block_device *bdgrab(struct block_device *bdev); | |
1949 | 1950 | extern void bd_set_size(struct block_device *, loff_t size); |
1950 | 1951 | extern void bd_forget(struct inode *inode); |
1951 | 1952 | extern void bdput(struct block_device *); |
mm/swapfile.c
... | ... | @@ -753,7 +753,7 @@ |
753 | 753 | |
754 | 754 | if (!bdev) { |
755 | 755 | if (bdev_p) |
756 | - *bdev_p = bdget(sis->bdev->bd_dev); | |
756 | + *bdev_p = bdgrab(sis->bdev); | |
757 | 757 | |
758 | 758 | spin_unlock(&swap_lock); |
759 | 759 | return i; |
... | ... | @@ -765,7 +765,7 @@ |
765 | 765 | struct swap_extent, list); |
766 | 766 | if (se->start_block == offset) { |
767 | 767 | if (bdev_p) |
768 | - *bdev_p = bdget(sis->bdev->bd_dev); | |
768 | + *bdev_p = bdgrab(sis->bdev); | |
769 | 769 | |
770 | 770 | spin_unlock(&swap_lock); |
771 | 771 | bdput(bdev); |