Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions fs/btrfs/dev-replace.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
return -EINVAL;
}

bdev_file = bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
fs_info->sb, &fs_holder_ops);
bdev_file = fs_bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
fs_info->sb, fs_info->sb);
if (IS_ERR(bdev_file)) {
btrfs_err(fs_info, "target device %s is invalid!", device_path);
return PTR_ERR(bdev_file);
Expand Down Expand Up @@ -325,7 +325,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
return 0;

error:
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, fs_info->sb);
return ret;
}

Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2579,7 +2579,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
err_drop:
mnt_drop_write_file(file);
if (bdev_file)
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, fs_info->sb);
out:
btrfs_put_dev_args_from_path(&args);
kfree(vol_args);
Expand Down Expand Up @@ -2630,7 +2630,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)

mnt_drop_write_file(file);
if (bdev_file)
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, fs_info->sb);
out:
btrfs_put_dev_args_from_path(&args);
out_free:
Expand Down
26 changes: 17 additions & 9 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,12 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
struct block_device *bdev;
int ret;

*bdev_file = bdev_file_open_by_path(device_path, flags, holder, &fs_holder_ops);
if (holder)
*bdev_file = fs_bdev_file_open_by_path(device_path, flags,
holder, holder);
else
*bdev_file = bdev_file_open_by_path(device_path, flags, NULL,
NULL);

if (IS_ERR(*bdev_file)) {
ret = PTR_ERR(*bdev_file);
Expand All @@ -495,15 +500,18 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
if (holder) {
ret = set_blocksize(*bdev_file, BTRFS_BDEV_BLOCKSIZE);
if (ret) {
bdev_fput(*bdev_file);
fs_bdev_file_release(*bdev_file, holder);
goto error;
}
}
invalidate_bdev(bdev);
*disk_super = btrfs_read_disk_super(bdev, 0, false);
if (IS_ERR(*disk_super)) {
ret = PTR_ERR(*disk_super);
bdev_fput(*bdev_file);
if (holder)
fs_bdev_file_release(*bdev_file, holder);
else
bdev_fput(*bdev_file);
goto error;
}

Expand Down Expand Up @@ -727,7 +735,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,

error_free_page:
btrfs_release_disk_super(disk_super);
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, holder);

return -EINVAL;
}
Expand Down Expand Up @@ -1082,7 +1090,7 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
continue;

if (device->bdev_file) {
bdev_fput(device->bdev_file);
fs_bdev_file_release(device->bdev_file, fs_devices->fs_info->sb);
device->bdev = NULL;
device->bdev_file = NULL;
fs_devices->open_devices--;
Expand Down Expand Up @@ -1129,7 +1137,7 @@ static void btrfs_close_bdev(struct btrfs_device *device)
invalidate_bdev(device->bdev);
}

bdev_fput(device->bdev_file);
fs_bdev_file_release(device->bdev_file, device->fs_info->sb);
}

static void btrfs_close_one_device(struct btrfs_device *device)
Expand Down Expand Up @@ -2820,8 +2828,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
if (sb_rdonly(sb) && !fs_devices->seeding)
return -EROFS;

bdev_file = bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
fs_info->sb, &fs_holder_ops);
bdev_file = fs_bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
fs_info->sb, fs_info->sb);
if (IS_ERR(bdev_file))
return PTR_ERR(bdev_file);

Expand Down Expand Up @@ -3045,7 +3053,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
error_free_device:
btrfs_free_device(device);
error:
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, fs_info->sb);
if (locked) {
mutex_unlock(&uuid_mutex);
up_write(&sb->s_umount);
Expand Down
6 changes: 6 additions & 0 deletions fs/erofs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
{
struct erofs_sb_info *sbi = EROFS_SB(sb);

if (erofs_is_shutdown(sb))
return -EIO;

buf->file = NULL;
if (in_metabox) {
if (unlikely(!sbi->metabox_inode))
Expand Down Expand Up @@ -236,6 +239,9 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
}
up_read(&devs->rwsem);
}
if (erofs_is_shutdown(sb) ||
(map->m_dif && READ_ONCE(map->m_dif->dead)))
return -EIO;
return 0;
}

Expand Down
10 changes: 10 additions & 0 deletions fs/erofs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct erofs_device_info {

erofs_blk_t blocks;
erofs_blk_t uniaddr;
bool dead; /* backing device gone; fence I/O */
};

enum {
Expand Down Expand Up @@ -104,6 +105,7 @@ struct erofs_xattr_prefix_item {
struct erofs_sb_info {
struct erofs_device_info dif0;
struct erofs_mount_opts opt; /* options */
unsigned long flags; /* see EROFS_SB_* */
#ifdef CONFIG_EROFS_FS_ZIP
/* list for all registered superblocks, mainly for shrinker */
struct list_head list;
Expand Down Expand Up @@ -195,6 +197,14 @@ static inline bool erofs_is_fscache_mode(struct super_block *sb)
!erofs_is_fileio_mode(EROFS_SB(sb)) && !sb->s_bdev;
}

/* erofs_sb_info->flags */
#define EROFS_SB_SHUTDOWN 0 /* primary device gone; fail all I/O */

static inline bool erofs_is_shutdown(struct super_block *sb)
{
return test_bit(EROFS_SB_SHUTDOWN, &EROFS_SB(sb)->flags);
}

enum {
EROFS_ZIP_CACHE_DISABLED,
EROFS_ZIP_CACHE_READAHEAD,
Expand Down
66 changes: 54 additions & 12 deletions fs/erofs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
} else if (!sbi->devs->flatdev) {
file = erofs_is_fileio_mode(sbi) ?
filp_open(dif->path, O_RDONLY | O_LARGEFILE, 0) :
bdev_file_open_by_path(dif->path,
BLK_OPEN_READ, sb->s_type, NULL);
fs_bdev_file_open_by_path(dif->path,
BLK_OPEN_READ, sb->s_type, sb);
if (IS_ERR(file)) {
if (file == ERR_PTR(-ENOTBLK))
return -EINVAL;
Expand Down Expand Up @@ -843,30 +843,36 @@ static int erofs_fc_reconfigure(struct fs_context *fc)

static int erofs_release_device_info(int id, void *ptr, void *data)
{
struct super_block *sb = data;
struct erofs_device_info *dif = ptr;

fs_put_dax(dif->dax_dev, NULL);
if (dif->file)
fput(dif->file);
if (dif->file) {
if (S_ISBLK(file_inode(dif->file)->i_mode))
fs_bdev_file_release(dif->file, sb);
else
fput(dif->file);
}
erofs_fscache_unregister_cookie(dif->fscache);
dif->fscache = NULL;
kfree(dif->path);
kfree(dif);
return 0;
}

static void erofs_free_dev_context(struct erofs_dev_context *devs)
static void erofs_free_dev_context(struct erofs_dev_context *devs,
struct super_block *sb)
{
if (!devs)
return;
idr_for_each(&devs->tree, &erofs_release_device_info, NULL);
idr_for_each(&devs->tree, &erofs_release_device_info, sb);
idr_destroy(&devs->tree);
kfree(devs);
}

static void erofs_sb_free(struct erofs_sb_info *sbi)
static void erofs_sb_free(struct erofs_sb_info *sbi, struct super_block *sb)
{
erofs_free_dev_context(sbi->devs);
erofs_free_dev_context(sbi->devs, sb);
kfree(sbi->fsid);
kfree_sensitive(sbi->domain_id);
if (sbi->dif0.file)
Expand All @@ -879,8 +885,13 @@ static void erofs_fc_free(struct fs_context *fc)
{
struct erofs_sb_info *sbi = fc->s_fs_info;

if (sbi) /* free here if an error occurs before transferring to sb */
erofs_sb_free(sbi);
/*
* Freed here only if an error occurs before the sb is set up; at that
* point no block-backed device has been claimed (that happens in
* fill_super), so the NULL sb never reaches fs_bdev_file_release().
*/
if (sbi)
erofs_sb_free(sbi, NULL);
}

static const struct fs_context_operations erofs_context_ops = {
Expand Down Expand Up @@ -936,7 +947,7 @@ static void erofs_kill_sb(struct super_block *sb)
erofs_drop_internal_inodes(sbi);
fs_put_dax(sbi->dif0.dax_dev, NULL);
erofs_fscache_unregister_fs(sb);
erofs_sb_free(sbi);
erofs_sb_free(sbi, sb);
sb->s_fs_info = NULL;
}

Expand All @@ -948,7 +959,7 @@ static void erofs_put_super(struct super_block *sb)
erofs_shrinker_unregister(sb);
erofs_xattr_prefixes_cleanup(sb);
erofs_drop_internal_inodes(sbi);
erofs_free_dev_context(sbi->devs);
erofs_free_dev_context(sbi->devs, sb);
sbi->devs = NULL;
erofs_fscache_unregister_fs(sb);
}
Expand Down Expand Up @@ -1121,13 +1132,44 @@ static void erofs_evict_inode(struct inode *inode)
clear_inode(inode);
}

/*
* A blob device may back several erofs superblocks; fence only the affected
* one and keep the rest of the mount alive. The primary device falls back to
* the generic teardown (return non-zero).
*/
static int erofs_remove_bdev(struct super_block *sb, struct block_device *bdev)
{
struct erofs_dev_context *devs = EROFS_SB(sb)->devs;
struct erofs_device_info *dif;
int id;

if (bdev == sb->s_bdev)
return 1;

down_read(&devs->rwsem);
idr_for_each_entry(&devs->tree, dif, id) {
if (dif->file && S_ISBLK(file_inode(dif->file)->i_mode) &&
file_bdev(dif->file)->bd_dev == bdev->bd_dev)
WRITE_ONCE(dif->dead, true);
}
up_read(&devs->rwsem);
return 0;
}

static void erofs_shutdown(struct super_block *sb)
{
set_bit(EROFS_SB_SHUTDOWN, &EROFS_SB(sb)->flags);
}

const struct super_operations erofs_sops = {
.put_super = erofs_put_super,
.alloc_inode = erofs_alloc_inode,
.free_inode = erofs_free_inode,
.evict_inode = erofs_evict_inode,
.statfs = erofs_statfs,
.show_options = erofs_show_options,
.remove_bdev = erofs_remove_bdev,
.shutdown = erofs_shutdown,
};

module_init(erofs_module_init);
Expand Down
10 changes: 7 additions & 3 deletions fs/erofs/zdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -1698,11 +1698,15 @@ static void z_erofs_submit_queue(struct z_erofs_frontend *f,
continue;
}

/* no device id here, thus it will always succeed */
mdev = (struct erofs_map_dev) {
.m_pa = round_down(pcl->pos, sb->s_blocksize),
};
(void)erofs_map_dev(sb, &mdev);
if (erofs_map_dev(sb, &mdev)) {
/* the backing device is gone; fail the batch */
q[JQ_SUBMIT]->eio = true;
qtail[JQ_SUBMIT] = &pcl->next;
continue;
}

cur = mdev.m_pa;
end = round_up(cur + pcl->pageofs_in + pcl->pclustersize,
Expand Down Expand Up @@ -1786,7 +1790,7 @@ static void z_erofs_submit_queue(struct z_erofs_frontend *f,
* although background is preferred, no one is pending for submission.
* don't issue decompression but drop it directly instead.
*/
if (!*force_fg && !nr_bios) {
if (!*force_fg && !nr_bios && !q[JQ_SUBMIT]->eio) {
kvfree(q[JQ_SUBMIT]);
return;
}
Expand Down
12 changes: 6 additions & 6 deletions fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -5793,7 +5793,7 @@ failed_mount8: __maybe_unused
brelse(sbi->s_sbh);
if (sbi->s_journal_bdev_file) {
invalidate_bdev(file_bdev(sbi->s_journal_bdev_file));
bdev_fput(sbi->s_journal_bdev_file);
fs_bdev_file_release(sbi->s_journal_bdev_file, sb);
}
out_fail:
invalidate_bdev(sb->s_bdev);
Expand Down Expand Up @@ -5972,9 +5972,9 @@ static struct file *ext4_get_journal_blkdev(struct super_block *sb,
struct ext4_super_block *es;
int errno;

bdev_file = bdev_file_open_by_dev(j_dev,
bdev_file = fs_bdev_file_open_by_dev(j_dev,
BLK_OPEN_READ | BLK_OPEN_WRITE | BLK_OPEN_RESTRICT_WRITES,
sb, &fs_holder_ops);
sb, sb);
if (IS_ERR(bdev_file)) {
ext4_msg(sb, KERN_ERR,
"failed to open journal device unknown-block(%u,%u) %ld",
Expand Down Expand Up @@ -6034,7 +6034,7 @@ static struct file *ext4_get_journal_blkdev(struct super_block *sb,
out_bh:
brelse(bh);
out_bdev:
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, sb);
return ERR_PTR(errno);
}

Expand Down Expand Up @@ -6073,7 +6073,7 @@ static journal_t *ext4_open_dev_journal(struct super_block *sb,
out_journal:
ext4_journal_destroy(EXT4_SB(sb), journal);
out_bdev:
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, sb);
return ERR_PTR(errno);
}

Expand Down Expand Up @@ -7492,7 +7492,7 @@ static void ext4_kill_sb(struct super_block *sb)
kill_block_super(sb);

if (bdev_file)
bdev_fput(bdev_file);
fs_bdev_file_release(bdev_file, sb);
}

static struct file_system_type ext4_fs_type = {
Expand Down
Loading