fs,block: get holder during claim
Now that we open block devices as files we need to deal with the
realities that closing is a deferred operation. An operation on the
block device such as e.g., freeze, thaw, or removal that runs
concurrently with umount, tries to acquire a stable reference on the
holder. The holder might already be gone though. Make that reliable by
grabbing a passive reference to the holder during bdev_open() and
releasing it during bdev_release().
Fixes: f3a608827d
("bdev: open block device as files") # mainline only
Reported-by: Christoph Hellwig <hch@infradead.org>
Link: https://lore.kernel.org/r/ZfEQQ9jZZVes0WCZ@infradead.org
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@infradead.org>
Tested-by: Yi Zhang <yi.zhang@redhat.com>
Reported-by: https://lore.kernel.org/r/CAHj4cs8tbDwKRwfS1=DmooP73ysM__xAb2PQc6XsAmWR+VuYmg@mail.gmail.com
Link: https://lore.kernel.org/r/20240315-freibad-annehmbar-ca68c375af91@brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
b74c02a379
commit
59a55a63c2
|
@ -583,6 +583,9 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder,
|
||||||
mutex_unlock(&bdev->bd_holder_lock);
|
mutex_unlock(&bdev->bd_holder_lock);
|
||||||
bd_clear_claiming(whole, holder);
|
bd_clear_claiming(whole, holder);
|
||||||
mutex_unlock(&bdev_lock);
|
mutex_unlock(&bdev_lock);
|
||||||
|
|
||||||
|
if (hops && hops->get_holder)
|
||||||
|
hops->get_holder(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -605,6 +608,7 @@ EXPORT_SYMBOL(bd_abort_claiming);
|
||||||
static void bd_end_claim(struct block_device *bdev, void *holder)
|
static void bd_end_claim(struct block_device *bdev, void *holder)
|
||||||
{
|
{
|
||||||
struct block_device *whole = bdev_whole(bdev);
|
struct block_device *whole = bdev_whole(bdev);
|
||||||
|
const struct blk_holder_ops *hops = bdev->bd_holder_ops;
|
||||||
bool unblock = false;
|
bool unblock = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -627,6 +631,9 @@ static void bd_end_claim(struct block_device *bdev, void *holder)
|
||||||
whole->bd_holder = NULL;
|
whole->bd_holder = NULL;
|
||||||
mutex_unlock(&bdev_lock);
|
mutex_unlock(&bdev_lock);
|
||||||
|
|
||||||
|
if (hops && hops->put_holder)
|
||||||
|
hops->put_holder(holder);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this was the last claim, remove holder link and unblock evpoll if
|
* If this was the last claim, remove holder link and unblock evpoll if
|
||||||
* it was a write holder.
|
* it was a write holder.
|
||||||
|
|
18
fs/super.c
18
fs/super.c
|
@ -1515,11 +1515,29 @@ static int fs_bdev_thaw(struct block_device *bdev)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fs_bdev_super_get(void *data)
|
||||||
|
{
|
||||||
|
struct super_block *sb = data;
|
||||||
|
|
||||||
|
spin_lock(&sb_lock);
|
||||||
|
sb->s_count++;
|
||||||
|
spin_unlock(&sb_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fs_bdev_super_put(void *data)
|
||||||
|
{
|
||||||
|
struct super_block *sb = data;
|
||||||
|
|
||||||
|
put_super(sb);
|
||||||
|
}
|
||||||
|
|
||||||
const struct blk_holder_ops fs_holder_ops = {
|
const struct blk_holder_ops fs_holder_ops = {
|
||||||
.mark_dead = fs_bdev_mark_dead,
|
.mark_dead = fs_bdev_mark_dead,
|
||||||
.sync = fs_bdev_sync,
|
.sync = fs_bdev_sync,
|
||||||
.freeze = fs_bdev_freeze,
|
.freeze = fs_bdev_freeze,
|
||||||
.thaw = fs_bdev_thaw,
|
.thaw = fs_bdev_thaw,
|
||||||
|
.get_holder = fs_bdev_super_get,
|
||||||
|
.put_holder = fs_bdev_super_put,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(fs_holder_ops);
|
EXPORT_SYMBOL_GPL(fs_holder_ops);
|
||||||
|
|
||||||
|
|
|
@ -1505,6 +1505,16 @@ struct blk_holder_ops {
|
||||||
* Thaw the file system mounted on the block device.
|
* Thaw the file system mounted on the block device.
|
||||||
*/
|
*/
|
||||||
int (*thaw)(struct block_device *bdev);
|
int (*thaw)(struct block_device *bdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If needed, get a reference to the holder.
|
||||||
|
*/
|
||||||
|
void (*get_holder)(void *holder);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the holder.
|
||||||
|
*/
|
||||||
|
void (*put_holder)(void *holder);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue