mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
block: integrate bd_start_claiming into __blkdev_get
bd_start_claiming duplicates a lot of the work done in __blkdev_get. Integrate the two functions to avoid the duplicate work, and to do the right thing for the md -ERESTARTSYS corner case. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
committed by
Jens Axboe
parent
ecbe6bc000
commit
5b642d8b9f
177
fs/block_dev.c
177
fs/block_dev.c
@@ -1078,72 +1078,6 @@ static struct gendisk *bdev_get_gendisk(struct block_device *bdev, int *partno)
|
|||||||
return disk;
|
return disk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* bd_start_claiming - start claiming a block device
|
|
||||||
* @bdev: block device of interest
|
|
||||||
* @holder: holder trying to claim @bdev
|
|
||||||
*
|
|
||||||
* @bdev is about to be opened exclusively. Check @bdev can be opened
|
|
||||||
* exclusively and mark that an exclusive open is in progress. Each
|
|
||||||
* successful call to this function must be matched with a call to
|
|
||||||
* either bd_finish_claiming() or bd_abort_claiming() (which do not
|
|
||||||
* fail).
|
|
||||||
*
|
|
||||||
* This function is used to gain exclusive access to the block device
|
|
||||||
* without actually causing other exclusive open attempts to fail. It
|
|
||||||
* should be used when the open sequence itself requires exclusive
|
|
||||||
* access but may subsequently fail.
|
|
||||||
*
|
|
||||||
* CONTEXT:
|
|
||||||
* Might sleep.
|
|
||||||
*
|
|
||||||
* RETURNS:
|
|
||||||
* Pointer to the block device containing @bdev on success, ERR_PTR()
|
|
||||||
* value on failure.
|
|
||||||
*/
|
|
||||||
static struct block_device *bd_start_claiming(struct block_device *bdev,
|
|
||||||
void *holder)
|
|
||||||
{
|
|
||||||
struct gendisk *disk;
|
|
||||||
struct block_device *whole;
|
|
||||||
int partno, err;
|
|
||||||
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @bdev might not have been initialized properly yet, look up
|
|
||||||
* and grab the outer block device the hard way.
|
|
||||||
*/
|
|
||||||
disk = bdev_get_gendisk(bdev, &partno);
|
|
||||||
if (!disk)
|
|
||||||
return ERR_PTR(-ENXIO);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Normally, @bdev should equal what's returned from bdget_disk()
|
|
||||||
* if partno is 0; however, some drivers (floppy) use multiple
|
|
||||||
* bdev's for the same physical device and @bdev may be one of the
|
|
||||||
* aliases. Keep @bdev if partno is 0. This means claimer
|
|
||||||
* tracking is broken for those devices but it has always been that
|
|
||||||
* way.
|
|
||||||
*/
|
|
||||||
if (partno)
|
|
||||||
whole = bdget_disk(disk, 0);
|
|
||||||
else
|
|
||||||
whole = bdgrab(bdev);
|
|
||||||
|
|
||||||
put_disk_and_module(disk);
|
|
||||||
if (!whole)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
err = bd_prepare_to_claim(bdev, whole, holder);
|
|
||||||
if (err) {
|
|
||||||
bdput(whole);
|
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return whole;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bd_clear_claiming(struct block_device *whole, void *holder)
|
static void bd_clear_claiming(struct block_device *whole, void *holder)
|
||||||
{
|
{
|
||||||
lockdep_assert_held(&bdev_lock);
|
lockdep_assert_held(&bdev_lock);
|
||||||
@@ -1156,7 +1090,7 @@ static void bd_clear_claiming(struct block_device *whole, void *holder)
|
|||||||
/**
|
/**
|
||||||
* bd_finish_claiming - finish claiming of a block device
|
* bd_finish_claiming - finish claiming of a block device
|
||||||
* @bdev: block device of interest
|
* @bdev: block device of interest
|
||||||
* @whole: whole block device (returned from bd_start_claiming())
|
* @whole: whole block device
|
||||||
* @holder: holder that has claimed @bdev
|
* @holder: holder that has claimed @bdev
|
||||||
*
|
*
|
||||||
* Finish exclusive open of a block device. Mark the device as exlusively
|
* Finish exclusive open of a block device. Mark the device as exlusively
|
||||||
@@ -1182,7 +1116,7 @@ static void bd_finish_claiming(struct block_device *bdev,
|
|||||||
/**
|
/**
|
||||||
* bd_abort_claiming - abort claiming of a block device
|
* bd_abort_claiming - abort claiming of a block device
|
||||||
* @bdev: block device of interest
|
* @bdev: block device of interest
|
||||||
* @whole: whole block device (returned from bd_start_claiming())
|
* @whole: whole block device
|
||||||
* @holder: holder that has claimed @bdev
|
* @holder: holder that has claimed @bdev
|
||||||
*
|
*
|
||||||
* Abort claiming of a block device when the exclusive open failed. This can be
|
* Abort claiming of a block device when the exclusive open failed. This can be
|
||||||
@@ -1505,13 +1439,15 @@ EXPORT_SYMBOL_GPL(bdev_disk_changed);
|
|||||||
* mutex_lock_nested(whole->bd_mutex, 1)
|
* mutex_lock_nested(whole->bd_mutex, 1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
static int __blkdev_get(struct block_device *bdev, fmode_t mode, void *holder,
|
||||||
|
int for_part)
|
||||||
{
|
{
|
||||||
|
struct block_device *whole = NULL, *claiming = NULL;
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
int ret;
|
int ret;
|
||||||
int partno;
|
int partno;
|
||||||
int perm = 0;
|
int perm = 0;
|
||||||
bool first_open = false, need_restart;
|
bool first_open = false, unblock_events = true, need_restart;
|
||||||
|
|
||||||
if (mode & FMODE_READ)
|
if (mode & FMODE_READ)
|
||||||
perm |= MAY_READ;
|
perm |= MAY_READ;
|
||||||
@@ -1533,6 +1469,25 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
|||||||
if (!disk)
|
if (!disk)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (partno) {
|
||||||
|
whole = bdget_disk(disk, 0);
|
||||||
|
if (!whole) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_put_disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!for_part && (mode & FMODE_EXCL)) {
|
||||||
|
WARN_ON_ONCE(!holder);
|
||||||
|
if (whole)
|
||||||
|
claiming = whole;
|
||||||
|
else
|
||||||
|
claiming = bdev;
|
||||||
|
ret = bd_prepare_to_claim(bdev, claiming, holder);
|
||||||
|
if (ret)
|
||||||
|
goto out_put_whole;
|
||||||
|
}
|
||||||
|
|
||||||
disk_block_events(disk);
|
disk_block_events(disk);
|
||||||
mutex_lock_nested(&bdev->bd_mutex, for_part);
|
mutex_lock_nested(&bdev->bd_mutex, for_part);
|
||||||
if (!bdev->bd_openers) {
|
if (!bdev->bd_openers) {
|
||||||
@@ -1576,18 +1531,11 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_clear;
|
goto out_clear;
|
||||||
} else {
|
} else {
|
||||||
struct block_device *whole;
|
|
||||||
whole = bdget_disk(disk, 0);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
if (!whole)
|
|
||||||
goto out_clear;
|
|
||||||
BUG_ON(for_part);
|
BUG_ON(for_part);
|
||||||
ret = __blkdev_get(whole, mode, 1);
|
ret = __blkdev_get(whole, mode, NULL, 1);
|
||||||
if (ret) {
|
if (ret)
|
||||||
bdput(whole);
|
|
||||||
goto out_clear;
|
goto out_clear;
|
||||||
}
|
bdev->bd_contains = bdgrab(whole);
|
||||||
bdev->bd_contains = whole;
|
|
||||||
bdev->bd_part = disk_get_part(disk, partno);
|
bdev->bd_part = disk_get_part(disk, partno);
|
||||||
if (!(disk->flags & GENHD_FL_UP) ||
|
if (!(disk->flags & GENHD_FL_UP) ||
|
||||||
!bdev->bd_part || !bdev->bd_part->nr_sects) {
|
!bdev->bd_part || !bdev->bd_part->nr_sects) {
|
||||||
@@ -1616,11 +1564,30 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
|||||||
bdev->bd_openers++;
|
bdev->bd_openers++;
|
||||||
if (for_part)
|
if (for_part)
|
||||||
bdev->bd_part_count++;
|
bdev->bd_part_count++;
|
||||||
|
if (claiming)
|
||||||
|
bd_finish_claiming(bdev, claiming, holder);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block event polling for write claims if requested. Any write holder
|
||||||
|
* makes the write_holder state stick until all are released. This is
|
||||||
|
* good enough and tracking individual writeable reference is too
|
||||||
|
* fragile given the way @mode is used in blkdev_get/put().
|
||||||
|
*/
|
||||||
|
if (claiming && (mode & FMODE_WRITE) && !bdev->bd_write_holder &&
|
||||||
|
(disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE)) {
|
||||||
|
bdev->bd_write_holder = true;
|
||||||
|
unblock_events = false;
|
||||||
|
}
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
disk_unblock_events(disk);
|
|
||||||
|
if (unblock_events)
|
||||||
|
disk_unblock_events(disk);
|
||||||
|
|
||||||
/* only one opener holds refs to the module and disk */
|
/* only one opener holds refs to the module and disk */
|
||||||
if (!first_open)
|
if (!first_open)
|
||||||
put_disk_and_module(disk);
|
put_disk_and_module(disk);
|
||||||
|
if (whole)
|
||||||
|
bdput(whole);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_clear:
|
out_clear:
|
||||||
@@ -1631,13 +1598,18 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
|||||||
__blkdev_put(bdev->bd_contains, mode, 1);
|
__blkdev_put(bdev->bd_contains, mode, 1);
|
||||||
bdev->bd_contains = NULL;
|
bdev->bd_contains = NULL;
|
||||||
out_unlock_bdev:
|
out_unlock_bdev:
|
||||||
|
if (claiming)
|
||||||
|
bd_abort_claiming(bdev, claiming, holder);
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
disk_unblock_events(disk);
|
disk_unblock_events(disk);
|
||||||
|
out_put_whole:
|
||||||
|
if (whole)
|
||||||
|
bdput(whole);
|
||||||
|
out_put_disk:
|
||||||
put_disk_and_module(disk);
|
put_disk_and_module(disk);
|
||||||
if (need_restart)
|
if (need_restart)
|
||||||
goto restart;
|
goto restart;
|
||||||
out:
|
out:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1662,50 +1634,11 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
|||||||
*/
|
*/
|
||||||
int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
|
int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
|
||||||
{
|
{
|
||||||
struct block_device *whole = NULL;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
WARN_ON_ONCE((mode & FMODE_EXCL) && !holder);
|
res =__blkdev_get(bdev, mode, holder, 0);
|
||||||
|
|
||||||
if ((mode & FMODE_EXCL) && holder) {
|
|
||||||
whole = bd_start_claiming(bdev, holder);
|
|
||||||
if (IS_ERR(whole)) {
|
|
||||||
bdput(bdev);
|
|
||||||
return PTR_ERR(whole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = __blkdev_get(bdev, mode, 0);
|
|
||||||
|
|
||||||
if (whole) {
|
|
||||||
struct gendisk *disk = whole->bd_disk;
|
|
||||||
|
|
||||||
/* finish claiming */
|
|
||||||
mutex_lock(&bdev->bd_mutex);
|
|
||||||
if (!res)
|
|
||||||
bd_finish_claiming(bdev, whole, holder);
|
|
||||||
else
|
|
||||||
bd_abort_claiming(bdev, whole, holder);
|
|
||||||
/*
|
|
||||||
* Block event polling for write claims if requested. Any
|
|
||||||
* write holder makes the write_holder state stick until
|
|
||||||
* all are released. This is good enough and tracking
|
|
||||||
* individual writeable reference is too fragile given the
|
|
||||||
* way @mode is used in blkdev_get/put().
|
|
||||||
*/
|
|
||||||
if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder &&
|
|
||||||
(disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE)) {
|
|
||||||
bdev->bd_write_holder = true;
|
|
||||||
disk_block_events(disk);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
|
||||||
bdput(whole);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
bdput(bdev);
|
bdput(bdev);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(blkdev_get);
|
EXPORT_SYMBOL(blkdev_get);
|
||||||
|
|||||||
Reference in New Issue
Block a user