for-6.10-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmZQjzoACgkQxWXV+ddt WDsFaw/+O6lH+rPLhvUoqtnrydC6QLnEW5Qj5EURDt3HkROOsXHszdNGKdsETZ2i /s4dDiCRwLv7PP/bWlFfQbHzckoBHI9I/1GxHKQM3OM27BpXvILacXSMJ13zw4vq DRQIUdTwfUkegEytZb0ddv6+++R1YyU6nE6LfiF2Pf4XJMQ2WXPRNu6bAa27xUia 4ITHB6m92zynhATJk0/RpfCU64HWwj919WnJDmoVOJ7Nr8Pslz4jKm7HS1qiehNd EbhduQPhj7UvWiL4C9/iFFndgzm1tX1WNlJDu5c0KqwYIHq2+BmDv3Cqhkazkdvu veU0wO62bZzV42vmTvQXzyXeXjNXRyLOvK6uHXv0VCO8VVsl2/WnYTRWmH44ECar z4tByfBKA7nIL2e23ztkyqnhygDf8Y1/Dy+GfprR6JPhyYGHJDqLcB3Gyw9y/AXO b/2MoAEgET9QPM/0HLqdonDJ75D2PF0qmwp1ys79w/BGH0BUoxZs/POL2UT87EJO rO5kW0/nZy99sbWFfZRwDUxTj1IlDqdudaHPOdJs/tUb3wPseLm5abQEyk+Dns6K 3y7OviNVQy0x325JY9RmdfnJv60KHvv5pqws1Nkuhqk1LH8csL6MsYlcybhR+vOk G9qkNxg35aNqjNlBi7RacMT8OgwVbVhik8jVr+MfXk30grIevzU= =XR4r -----END PGP SIGNATURE----- Merge tag 'for-6.10-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull more btrfs updates from David Sterba: "A few more updates, mostly stability fixes or user visible changes: - fix race in zoned mode during device replace that can lead to use-after-free - update return codes and lower message levels for quota rescan where it's causing false alerts - fix unexpected qgroup id reuse under some conditions - fix condition when looking up extent refs - add option norecovery (removed in 6.8), the intended replacements haven't been used and some aplications still rely on the old one - build warning fixes" * tag 'for-6.10-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: re-introduce 'norecovery' mount option btrfs: fix end of tree detection when searching for data extent ref btrfs: scrub: initialize ret in scrub_simple_mirror() to fix compilation warning btrfs: zoned: fix use-after-free due to race with dev replace btrfs: qgroup: fix qgroup id collision across mounts btrfs: qgroup: update rescan message levels and error codes
This commit is contained in:
commit
02c438bbff
@ -477,7 +477,7 @@ again:
|
|||||||
if (path->slots[0] >= nritems) {
|
if (path->slots[0] >= nritems) {
|
||||||
ret = btrfs_next_leaf(root, path);
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret > 1)
|
if (ret > 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -468,6 +468,7 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
|
|||||||
}
|
}
|
||||||
if (!qgroup) {
|
if (!qgroup) {
|
||||||
struct btrfs_qgroup *prealloc;
|
struct btrfs_qgroup *prealloc;
|
||||||
|
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||||
|
|
||||||
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);
|
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);
|
||||||
if (!prealloc) {
|
if (!prealloc) {
|
||||||
@ -475,6 +476,25 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
qgroup = add_qgroup_rb(fs_info, prealloc, found_key.offset);
|
qgroup = add_qgroup_rb(fs_info, prealloc, found_key.offset);
|
||||||
|
/*
|
||||||
|
* If a qgroup exists for a subvolume ID, it is possible
|
||||||
|
* that subvolume has been deleted, in which case
|
||||||
|
* re-using that ID would lead to incorrect accounting.
|
||||||
|
*
|
||||||
|
* Ensure that we skip any such subvol ids.
|
||||||
|
*
|
||||||
|
* We don't need to lock because this is only called
|
||||||
|
* during mount before we start doing things like creating
|
||||||
|
* subvolumes.
|
||||||
|
*/
|
||||||
|
if (is_fstree(qgroup->qgroupid) &&
|
||||||
|
qgroup->qgroupid > tree_root->free_objectid)
|
||||||
|
/*
|
||||||
|
* Don't need to check against BTRFS_LAST_FREE_OBJECTID,
|
||||||
|
* as it will get checked on the next call to
|
||||||
|
* btrfs_get_free_objectid.
|
||||||
|
*/
|
||||||
|
tree_root->free_objectid = qgroup->qgroupid + 1;
|
||||||
}
|
}
|
||||||
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
|
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -3820,14 +3840,14 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
|
|||||||
/* we're resuming qgroup rescan at mount time */
|
/* we're resuming qgroup rescan at mount time */
|
||||||
if (!(fs_info->qgroup_flags &
|
if (!(fs_info->qgroup_flags &
|
||||||
BTRFS_QGROUP_STATUS_FLAG_RESCAN)) {
|
BTRFS_QGROUP_STATUS_FLAG_RESCAN)) {
|
||||||
btrfs_warn(fs_info,
|
btrfs_debug(fs_info,
|
||||||
"qgroup rescan init failed, qgroup rescan is not queued");
|
"qgroup rescan init failed, qgroup rescan is not queued");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
} else if (!(fs_info->qgroup_flags &
|
} else if (!(fs_info->qgroup_flags &
|
||||||
BTRFS_QGROUP_STATUS_FLAG_ON)) {
|
BTRFS_QGROUP_STATUS_FLAG_ON)) {
|
||||||
btrfs_warn(fs_info,
|
btrfs_debug(fs_info,
|
||||||
"qgroup rescan init failed, qgroup is not enabled");
|
"qgroup rescan init failed, qgroup is not enabled");
|
||||||
ret = -EINVAL;
|
ret = -ENOTCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -3838,14 +3858,12 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
|
|||||||
|
|
||||||
if (init_flags) {
|
if (init_flags) {
|
||||||
if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
|
if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
|
||||||
btrfs_warn(fs_info,
|
|
||||||
"qgroup rescan is already in progress");
|
|
||||||
ret = -EINPROGRESS;
|
ret = -EINPROGRESS;
|
||||||
} else if (!(fs_info->qgroup_flags &
|
} else if (!(fs_info->qgroup_flags &
|
||||||
BTRFS_QGROUP_STATUS_FLAG_ON)) {
|
BTRFS_QGROUP_STATUS_FLAG_ON)) {
|
||||||
btrfs_warn(fs_info,
|
btrfs_debug(fs_info,
|
||||||
"qgroup rescan init failed, qgroup is not enabled");
|
"qgroup rescan init failed, qgroup is not enabled");
|
||||||
ret = -EINVAL;
|
ret = -ENOTCONN;
|
||||||
} else if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
|
} else if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
|
||||||
/* Quota disable is in progress */
|
/* Quota disable is in progress */
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
|
@ -2100,7 +2100,7 @@ static int scrub_simple_mirror(struct scrub_ctx *sctx,
|
|||||||
struct btrfs_fs_info *fs_info = sctx->fs_info;
|
struct btrfs_fs_info *fs_info = sctx->fs_info;
|
||||||
const u64 logical_end = logical_start + logical_length;
|
const u64 logical_end = logical_start + logical_length;
|
||||||
u64 cur_logical = logical_start;
|
u64 cur_logical = logical_start;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
/* The range must be inside the bg */
|
/* The range must be inside the bg */
|
||||||
ASSERT(logical_start >= bg->start && logical_end <= bg->start + bg->length);
|
ASSERT(logical_start >= bg->start && logical_end <= bg->start + bg->length);
|
||||||
|
@ -119,6 +119,7 @@ enum {
|
|||||||
Opt_thread_pool,
|
Opt_thread_pool,
|
||||||
Opt_treelog,
|
Opt_treelog,
|
||||||
Opt_user_subvol_rm_allowed,
|
Opt_user_subvol_rm_allowed,
|
||||||
|
Opt_norecovery,
|
||||||
|
|
||||||
/* Rescue options */
|
/* Rescue options */
|
||||||
Opt_rescue,
|
Opt_rescue,
|
||||||
@ -245,6 +246,8 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] = {
|
|||||||
__fsparam(NULL, "nologreplay", Opt_nologreplay, fs_param_deprecated, NULL),
|
__fsparam(NULL, "nologreplay", Opt_nologreplay, fs_param_deprecated, NULL),
|
||||||
/* Deprecated, with alias rescue=usebackuproot */
|
/* Deprecated, with alias rescue=usebackuproot */
|
||||||
__fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated, NULL),
|
__fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated, NULL),
|
||||||
|
/* For compatibility only, alias for "rescue=nologreplay". */
|
||||||
|
fsparam_flag("norecovery", Opt_norecovery),
|
||||||
|
|
||||||
/* Debugging options. */
|
/* Debugging options. */
|
||||||
fsparam_flag_no("enospc_debug", Opt_enospc_debug),
|
fsparam_flag_no("enospc_debug", Opt_enospc_debug),
|
||||||
@ -438,6 +441,11 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||||||
"'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
|
"'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
|
||||||
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
||||||
break;
|
break;
|
||||||
|
case Opt_norecovery:
|
||||||
|
btrfs_info(NULL,
|
||||||
|
"'norecovery' is for compatibility only, recommended to use 'rescue=nologreplay'");
|
||||||
|
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
||||||
|
break;
|
||||||
case Opt_flushoncommit:
|
case Opt_flushoncommit:
|
||||||
if (result.negated)
|
if (result.negated)
|
||||||
btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
|
btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
|
||||||
|
@ -1290,7 +1290,7 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
struct btrfs_chunk_map *map)
|
struct btrfs_chunk_map *map)
|
||||||
{
|
{
|
||||||
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
|
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
|
||||||
struct btrfs_device *device = map->stripes[zone_idx].dev;
|
struct btrfs_device *device;
|
||||||
int dev_replace_is_ongoing = 0;
|
int dev_replace_is_ongoing = 0;
|
||||||
unsigned int nofs_flag;
|
unsigned int nofs_flag;
|
||||||
struct blk_zone zone;
|
struct blk_zone zone;
|
||||||
@ -1298,7 +1298,11 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
|
|
||||||
info->physical = map->stripes[zone_idx].physical;
|
info->physical = map->stripes[zone_idx].physical;
|
||||||
|
|
||||||
|
down_read(&dev_replace->rwsem);
|
||||||
|
device = map->stripes[zone_idx].dev;
|
||||||
|
|
||||||
if (!device->bdev) {
|
if (!device->bdev) {
|
||||||
|
up_read(&dev_replace->rwsem);
|
||||||
info->alloc_offset = WP_MISSING_DEV;
|
info->alloc_offset = WP_MISSING_DEV;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1308,6 +1312,7 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
__set_bit(zone_idx, active);
|
__set_bit(zone_idx, active);
|
||||||
|
|
||||||
if (!btrfs_dev_is_sequential(device, info->physical)) {
|
if (!btrfs_dev_is_sequential(device, info->physical)) {
|
||||||
|
up_read(&dev_replace->rwsem);
|
||||||
info->alloc_offset = WP_CONVENTIONAL;
|
info->alloc_offset = WP_CONVENTIONAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1315,11 +1320,9 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
/* This zone will be used for allocation, so mark this zone non-empty. */
|
/* This zone will be used for allocation, so mark this zone non-empty. */
|
||||||
btrfs_dev_clear_zone_empty(device, info->physical);
|
btrfs_dev_clear_zone_empty(device, info->physical);
|
||||||
|
|
||||||
down_read(&dev_replace->rwsem);
|
|
||||||
dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
|
dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
|
||||||
if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
|
if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
|
||||||
btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);
|
btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);
|
||||||
up_read(&dev_replace->rwsem);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The group is mapped to a sequential zone. Get the zone write pointer
|
* The group is mapped to a sequential zone. Get the zone write pointer
|
||||||
@ -1330,6 +1333,7 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
ret = btrfs_get_dev_zone(device, info->physical, &zone);
|
ret = btrfs_get_dev_zone(device, info->physical, &zone);
|
||||||
memalloc_nofs_restore(nofs_flag);
|
memalloc_nofs_restore(nofs_flag);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
up_read(&dev_replace->rwsem);
|
||||||
if (ret != -EIO && ret != -EOPNOTSUPP)
|
if (ret != -EIO && ret != -EOPNOTSUPP)
|
||||||
return ret;
|
return ret;
|
||||||
info->alloc_offset = WP_MISSING_DEV;
|
info->alloc_offset = WP_MISSING_DEV;
|
||||||
@ -1341,6 +1345,7 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
"zoned: unexpected conventional zone %llu on device %s (devid %llu)",
|
"zoned: unexpected conventional zone %llu on device %s (devid %llu)",
|
||||||
zone.start << SECTOR_SHIFT, rcu_str_deref(device->name),
|
zone.start << SECTOR_SHIFT, rcu_str_deref(device->name),
|
||||||
device->devid);
|
device->devid);
|
||||||
|
up_read(&dev_replace->rwsem);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1368,6 +1373,8 @@ static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up_read(&dev_replace->rwsem);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user