diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 3c9a03e51b62..f55aad4d1611 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -359,25 +359,30 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) | |||
359 | mutex_lock(&bd_inode->i_mutex); | 359 | mutex_lock(&bd_inode->i_mutex); |
360 | size = i_size_read(bd_inode); | 360 | size = i_size_read(bd_inode); |
361 | 361 | ||
362 | retval = -EINVAL; | ||
362 | switch (origin) { | 363 | switch (origin) { |
363 | case 2: | 364 | case SEEK_END: |
364 | offset += size; | 365 | offset += size; |
365 | break; | 366 | break; |
366 | case 1: | 367 | case SEEK_CUR: |
367 | offset += file->f_pos; | 368 | offset += file->f_pos; |
369 | case SEEK_SET: | ||
370 | break; | ||
371 | default: | ||
372 | goto out; | ||
368 | } | 373 | } |
369 | retval = -EINVAL; | ||
370 | if (offset >= 0 && offset <= size) { | 374 | if (offset >= 0 && offset <= size) { |
371 | if (offset != file->f_pos) { | 375 | if (offset != file->f_pos) { |
372 | file->f_pos = offset; | 376 | file->f_pos = offset; |
373 | } | 377 | } |
374 | retval = offset; | 378 | retval = offset; |
375 | } | 379 | } |
380 | out: | ||
376 | mutex_unlock(&bd_inode->i_mutex); | 381 | mutex_unlock(&bd_inode->i_mutex); |
377 | return retval; | 382 | return retval; |
378 | } | 383 | } |
379 | 384 | ||
380 | int blkdev_fsync(struct file *filp, int datasync) | 385 | int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
381 | { | 386 | { |
382 | struct inode *bd_inode = filp->f_mapping->host; | 387 | struct inode *bd_inode = filp->f_mapping->host; |
383 | struct block_device *bdev = I_BDEV(bd_inode); | 388 | struct block_device *bdev = I_BDEV(bd_inode); |
@@ -388,14 +393,10 @@ int blkdev_fsync(struct file *filp, int datasync) | |||
388 | * i_mutex and doing so causes performance issues with concurrent | 393 | * i_mutex and doing so causes performance issues with concurrent |
389 | * O_SYNC writers to a block device. | 394 | * O_SYNC writers to a block device. |
390 | */ | 395 | */ |
391 | mutex_unlock(&bd_inode->i_mutex); | ||
392 | |||
393 | error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); | 396 | error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); |
394 | if (error == -EOPNOTSUPP) | 397 | if (error == -EOPNOTSUPP) |
395 | error = 0; | 398 | error = 0; |
396 | 399 | ||
397 | mutex_lock(&bd_inode->i_mutex); | ||
398 | |||
399 | return error; | 400 | return error; |
400 | } | 401 | } |
401 | EXPORT_SYMBOL(blkdev_fsync); | 402 | EXPORT_SYMBOL(blkdev_fsync); |
@@ -766,7 +767,19 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, | |||
766 | if (!disk) | 767 | if (!disk) |
767 | return ERR_PTR(-ENXIO); | 768 | return ERR_PTR(-ENXIO); |
768 | 769 | ||
769 | whole = bdget_disk(disk, 0); | 770 | /* |
771 | * Normally, @bdev should equal what's returned from bdget_disk() | ||
772 | * if partno is 0; however, some drivers (floppy) use multiple | ||
773 | * bdev's for the same physical device and @bdev may be one of the | ||
774 | * aliases. Keep @bdev if partno is 0. This means claimer | ||
775 | * tracking is broken for those devices but it has always been that | ||
776 | * way. | ||
777 | */ | ||
778 | if (partno) | ||
779 | whole = bdget_disk(disk, 0); | ||
780 | else | ||
781 | whole = bdgrab(bdev); | ||
782 | |||
770 | module_put(disk->fops->owner); | 783 | module_put(disk->fops->owner); |
771 | put_disk(disk); | 784 | put_disk(disk); |
772 | if (!whole) | 785 | if (!whole) |
@@ -1439,6 +1452,8 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
1439 | 1452 | ||
1440 | int blkdev_put(struct block_device *bdev, fmode_t mode) | 1453 | int blkdev_put(struct block_device *bdev, fmode_t mode) |
1441 | { | 1454 | { |
1455 | mutex_lock(&bdev->bd_mutex); | ||
1456 | |||
1442 | if (mode & FMODE_EXCL) { | 1457 | if (mode & FMODE_EXCL) { |
1443 | bool bdev_free; | 1458 | bool bdev_free; |
1444 | 1459 | ||
@@ -1447,7 +1462,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode) | |||
1447 | * are protected with bdev_lock. bd_mutex is to | 1462 | * are protected with bdev_lock. bd_mutex is to |
1448 | * synchronize disk_holder unlinking. | 1463 | * synchronize disk_holder unlinking. |
1449 | */ | 1464 | */ |
1450 | mutex_lock(&bdev->bd_mutex); | ||
1451 | spin_lock(&bdev_lock); | 1465 | spin_lock(&bdev_lock); |
1452 | 1466 | ||
1453 | WARN_ON_ONCE(--bdev->bd_holders < 0); | 1467 | WARN_ON_ONCE(--bdev->bd_holders < 0); |
@@ -1465,17 +1479,21 @@ int blkdev_put(struct block_device *bdev, fmode_t mode) | |||
1465 | * If this was the last claim, remove holder link and | 1479 | * If this was the last claim, remove holder link and |
1466 | * unblock evpoll if it was a write holder. | 1480 | * unblock evpoll if it was a write holder. |
1467 | */ | 1481 | */ |
1468 | if (bdev_free) { | 1482 | if (bdev_free && bdev->bd_write_holder) { |
1469 | if (bdev->bd_write_holder) { | 1483 | disk_unblock_events(bdev->bd_disk); |
1470 | disk_unblock_events(bdev->bd_disk); | 1484 | bdev->bd_write_holder = false; |
1471 | disk_check_events(bdev->bd_disk); | ||
1472 | bdev->bd_write_holder = false; | ||
1473 | } | ||
1474 | } | 1485 | } |
1475 | |||
1476 | mutex_unlock(&bdev->bd_mutex); | ||
1477 | } | 1486 | } |
1478 | 1487 | ||
1488 | /* | ||
1489 | * Trigger event checking and tell drivers to flush MEDIA_CHANGE | ||
1490 | * event. This is to ensure detection of media removal commanded | ||
1491 | * from userland - e.g. eject(1). | ||
1492 | */ | ||
1493 | disk_flush_events(bdev->bd_disk, DISK_EVENT_MEDIA_CHANGE); | ||
1494 | |||
1495 | mutex_unlock(&bdev->bd_mutex); | ||
1496 | |||
1479 | return __blkdev_put(bdev, mode, 0); | 1497 | return __blkdev_put(bdev, mode, 0); |
1480 | } | 1498 | } |
1481 | EXPORT_SYMBOL(blkdev_put); | 1499 | EXPORT_SYMBOL(blkdev_put); |