diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 99e0ae1a4c78..b3c1efff5e1d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -285,6 +285,8 @@ static void init_once(void *foo) | |||
285 | INIT_LIST_HEAD(&bdev->bd_holder_list); | 285 | INIT_LIST_HEAD(&bdev->bd_holder_list); |
286 | #endif | 286 | #endif |
287 | inode_init_once(&ei->vfs_inode); | 287 | inode_init_once(&ei->vfs_inode); |
288 | /* Initialize mutex for freeze. */ | ||
289 | mutex_init(&bdev->bd_fsfreeze_mutex); | ||
288 | } | 290 | } |
289 | 291 | ||
290 | static inline void __bd_forget(struct inode *inode) | 292 | static inline void __bd_forget(struct inode *inode) |
@@ -326,12 +328,13 @@ static struct file_system_type bd_type = { | |||
326 | .kill_sb = kill_anon_super, | 328 | .kill_sb = kill_anon_super, |
327 | }; | 329 | }; |
328 | 330 | ||
329 | static struct vfsmount *bd_mnt __read_mostly; | 331 | struct super_block *blockdev_superblock __read_mostly; |
330 | struct super_block *blockdev_superblock; | ||
331 | 332 | ||
332 | void __init bdev_cache_init(void) | 333 | void __init bdev_cache_init(void) |
333 | { | 334 | { |
334 | int err; | 335 | int err; |
336 | struct vfsmount *bd_mnt; | ||
337 | |||
335 | bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), | 338 | bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), |
336 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | 339 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| |
337 | SLAB_MEM_SPREAD|SLAB_PANIC), | 340 | SLAB_MEM_SPREAD|SLAB_PANIC), |
@@ -373,7 +376,7 @@ struct block_device *bdget(dev_t dev) | |||
373 | struct block_device *bdev; | 376 | struct block_device *bdev; |
374 | struct inode *inode; | 377 | struct inode *inode; |
375 | 378 | ||
376 | inode = iget5_locked(bd_mnt->mnt_sb, hash(dev), | 379 | inode = iget5_locked(blockdev_superblock, hash(dev), |
377 | bdev_test, bdev_set, &dev); | 380 | bdev_test, bdev_set, &dev); |
378 | 381 | ||
379 | if (!inode) | 382 | if (!inode) |
@@ -463,7 +466,7 @@ void bd_forget(struct inode *inode) | |||
463 | 466 | ||
464 | spin_lock(&bdev_lock); | 467 | spin_lock(&bdev_lock); |
465 | if (inode->i_bdev) { | 468 | if (inode->i_bdev) { |
466 | if (inode->i_sb != blockdev_superblock) | 469 | if (!sb_is_blkdev_sb(inode->i_sb)) |
467 | bdev = inode->i_bdev; | 470 | bdev = inode->i_bdev; |
468 | __bd_forget(inode); | 471 | __bd_forget(inode); |
469 | } | 472 | } |
@@ -1004,6 +1007,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1004 | } | 1007 | } |
1005 | 1008 | ||
1006 | lock_kernel(); | 1009 | lock_kernel(); |
1010 | restart: | ||
1007 | 1011 | ||
1008 | ret = -ENXIO; | 1012 | ret = -ENXIO; |
1009 | disk = get_gendisk(bdev->bd_dev, &partno); | 1013 | disk = get_gendisk(bdev->bd_dev, &partno); |
@@ -1024,6 +1028,19 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1024 | 1028 | ||
1025 | if (disk->fops->open) { | 1029 | if (disk->fops->open) { |
1026 | ret = disk->fops->open(bdev, mode); | 1030 | ret = disk->fops->open(bdev, mode); |
1031 | if (ret == -ERESTARTSYS) { | ||
1032 | /* Lost a race with 'disk' being | ||
1033 | * deleted, try again. | ||
1034 | * See md.c | ||
1035 | */ | ||
1036 | disk_put_part(bdev->bd_part); | ||
1037 | bdev->bd_part = NULL; | ||
1038 | module_put(disk->fops->owner); | ||
1039 | put_disk(disk); | ||
1040 | bdev->bd_disk = NULL; | ||
1041 | mutex_unlock(&bdev->bd_mutex); | ||
1042 | goto restart; | ||
1043 | } | ||
1027 | if (ret) | 1044 | if (ret) |
1028 | goto out_clear; | 1045 | goto out_clear; |
1029 | } | 1046 | } |
@@ -1219,6 +1236,20 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
1219 | return blkdev_ioctl(bdev, mode, cmd, arg); | 1236 | return blkdev_ioctl(bdev, mode, cmd, arg); |
1220 | } | 1237 | } |
1221 | 1238 | ||
1239 | /* | ||
1240 | * Try to release a page associated with block device when the system | ||
1241 | * is under memory pressure. | ||
1242 | */ | ||
1243 | static int blkdev_releasepage(struct page *page, gfp_t wait) | ||
1244 | { | ||
1245 | struct super_block *super = BDEV_I(page->mapping->host)->bdev.bd_super; | ||
1246 | |||
1247 | if (super && super->s_op->bdev_try_to_free_page) | ||
1248 | return super->s_op->bdev_try_to_free_page(super, page, wait); | ||
1249 | |||
1250 | return try_to_free_buffers(page); | ||
1251 | } | ||
1252 | |||
1222 | static const struct address_space_operations def_blk_aops = { | 1253 | static const struct address_space_operations def_blk_aops = { |
1223 | .readpage = blkdev_readpage, | 1254 | .readpage = blkdev_readpage, |
1224 | .writepage = blkdev_writepage, | 1255 | .writepage = blkdev_writepage, |
@@ -1226,6 +1257,7 @@ static const struct address_space_operations def_blk_aops = { | |||
1226 | .write_begin = blkdev_write_begin, | 1257 | .write_begin = blkdev_write_begin, |
1227 | .write_end = blkdev_write_end, | 1258 | .write_end = blkdev_write_end, |
1228 | .writepages = generic_writepages, | 1259 | .writepages = generic_writepages, |
1260 | .releasepage = blkdev_releasepage, | ||
1229 | .direct_IO = blkdev_direct_IO, | 1261 | .direct_IO = blkdev_direct_IO, |
1230 | }; | 1262 | }; |
1231 | 1263 | ||
@@ -1261,7 +1293,7 @@ EXPORT_SYMBOL(ioctl_by_bdev); | |||
1261 | 1293 | ||
1262 | /** | 1294 | /** |
1263 | * lookup_bdev - lookup a struct block_device by name | 1295 | * lookup_bdev - lookup a struct block_device by name |
1264 | * @path: special file representing the block device | 1296 | * @pathname: special file representing the block device |
1265 | * | 1297 | * |
1266 | * Get a reference to the blockdevice at @pathname in the current | 1298 | * Get a reference to the blockdevice at @pathname in the current |
1267 | * namespace if possible and return it. Return ERR_PTR(error) | 1299 | * namespace if possible and return it. Return ERR_PTR(error) |