/* Maximum number of zones to report per blkdev_report_zones() call */ #define BTRFS_REPORT_NR_ZONES 4096 /* Invalid allocation pointer value for missing devices */ #define WP_MISSING_DEV ((u64)-1) /* Pseudo write pointer value for conventional zone */ #define WP_CONVENTIONAL ((u64)-2)
/* The emulated zone size is determined from the size of device extent */ staticint calculate_emulated_zone_size(struct btrfs_fs_info *fs_info)
{
BTRFS_PATH_AUTO_FREE(path); struct btrfs_root *root = fs_info->dev_root; struct btrfs_key key; struct extent_buffer *leaf; struct btrfs_dev_extent *dext; int ret = 0;
path = btrfs_alloc_path(); if (!path) return -ENOMEM;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) return ret;
if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
ret = btrfs_next_leaf(root, path); if (ret < 0) return ret; /* No dev extents at all? Not good */ if (ret > 0) return -EUCLEAN;
}
int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
{ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; struct btrfs_device *device; int ret = 0;
/* fs_info->zone_size might not set yet. Use the incomapt flag here. */ if (!btrfs_fs_incompat(fs_info, ZONED)) return0;
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry(device, &fs_devices->devices, dev_list) { /* We can skip reading of zone info for missing devices */ if (!device->bdev) continue;
ret = btrfs_get_dev_zone_info(device, true); if (ret) break;
}
mutex_unlock(&fs_devices->device_list_mutex);
/* We reject devices with a zone size larger than 8GB */ if (zone_info->zone_size > BTRFS_MAX_ZONE_SIZE) {
btrfs_err(fs_info, "zoned: %s: zone size %llu larger than supported maximum %llu",
rcu_dereference(device->name),
zone_info->zone_size, BTRFS_MAX_ZONE_SIZE);
ret = -EINVAL; goto out;
} elseif (zone_info->zone_size < BTRFS_MIN_ZONE_SIZE) {
btrfs_err(fs_info, "zoned: %s: zone size %llu smaller than supported minimum %u",
rcu_dereference(device->name),
zone_info->zone_size, BTRFS_MIN_ZONE_SIZE);
ret = -EINVAL; goto out;
}
max_active_zones = min_not_zero(bdev_max_active_zones(bdev),
bdev_max_open_zones(bdev)); if (!max_active_zones && zone_info->nr_zones > BTRFS_DEFAULT_MAX_ACTIVE_ZONES)
max_active_zones = BTRFS_DEFAULT_MAX_ACTIVE_ZONES; if (max_active_zones && max_active_zones < BTRFS_MIN_ACTIVE_ZONES) {
btrfs_err(fs_info, "zoned: %s: max active zones %u is too small, need at least %u active zones",
rcu_dereference(device->name), max_active_zones,
BTRFS_MIN_ACTIVE_ZONES);
ret = -EINVAL; goto out;
}
zone_info->max_active_zones = max_active_zones;
zone_info->seq_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL); if (!zone_info->seq_zones) {
ret = -ENOMEM; goto out;
}
zone_info->empty_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL); if (!zone_info->empty_zones) {
ret = -ENOMEM; goto out;
}
zone_info->active_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL); if (!zone_info->active_zones) {
ret = -ENOMEM; goto out;
}
zones = kvcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL); if (!zones) {
ret = -ENOMEM; goto out;
}
/* *Enablezonecacheonlyforazoneddevice.Onanon-zoneddevice,we *fillthezoneinfowithemulatedCONVENTIONALzones,sononeedto *usethecache.
*/ if (populate_cache && bdev_is_zoned(device->bdev)) {
zone_info->zone_cache = vcalloc(zone_info->nr_zones, sizeof(struct blk_zone)); if (!zone_info->zone_cache) {
btrfs_err(device->fs_info, "zoned: failed to allocate zone cache for %s",
rcu_dereference(device->name));
ret = -ENOMEM; goto out;
}
}
/* Get zones type */
nactive = 0; while (sector < nr_sectors) {
nr_zones = BTRFS_REPORT_NR_ZONES;
ret = btrfs_get_dev_zones(device, sector << SECTOR_SHIFT, zones,
&nr_zones); if (ret) goto out;
for (i = 0; i < nr_zones; i++) { if (zones[i].type == BLK_ZONE_TYPE_SEQWRITE_REQ)
__set_bit(nreported, zone_info->seq_zones); switch (zones[i].cond) { case BLK_ZONE_COND_EMPTY:
__set_bit(nreported, zone_info->empty_zones); break; case BLK_ZONE_COND_IMP_OPEN: case BLK_ZONE_COND_EXP_OPEN: case BLK_ZONE_COND_CLOSED:
__set_bit(nreported, zone_info->active_zones);
nactive++; break;
}
nreported++;
}
sector = zones[nr_zones - 1].start + zones[nr_zones - 1].len;
}
if (nreported != zone_info->nr_zones) {
btrfs_err(device->fs_info, "inconsistent number of zones on %s (%u/%u)",
rcu_dereference(device->name), nreported,
zone_info->nr_zones);
ret = -EIO; goto out;
}
if (max_active_zones) { if (nactive > max_active_zones) { if (bdev_max_active_zones(bdev) == 0) {
max_active_zones = 0;
zone_info->max_active_zones = 0; goto validate;
}
btrfs_err(device->fs_info, "zoned: %u active zones on %s exceeds max_active_zones %u",
nactive, rcu_dereference(device->name),
max_active_zones);
ret = -EIO; goto out;
}
atomic_set(&zone_info->active_zones_left,
max_active_zones - nactive);
set_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags);
}
validate: /* Validate superblock log */
nr_zones = BTRFS_NR_SB_LOG_ZONES; for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
u32 sb_zone;
u64 sb_wp; int sb_pos = BTRFS_NR_SB_LOG_ZONES * i;
ret = btrfs_get_dev_zones(device,
zone_start_physical(sb_zone, zone_info),
&zone_info->sb_zones[sb_pos],
&nr_zones); if (ret) goto out;
if (nr_zones != BTRFS_NR_SB_LOG_ZONES) {
btrfs_err(device->fs_info, "zoned: failed to read super block log zone info at devid %llu zone %u",
device->devid, sb_zone);
ret = -EUCLEAN; goto out;
}
/* *Checkmountoptionshere,becausewemightchangefs_info->zoned *fromfs_info->zone_size.
*/
ret = btrfs_check_mountopts_zoned(fs_info, &fs_info->mount_opt); if (ret) return ret;
btrfs_info(fs_info, "zoned mode enabled with zone size %llu", zone_size); return0;
}
int btrfs_check_mountopts_zoned(conststruct btrfs_fs_info *info, unsignedlonglong *mount_opt)
{ if (!btrfs_is_zoned(info)) return0;
/* *SpacecachewritingisnotCOWed.Disablethattoavoidwriteerrors *insequentialzones.
*/ if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE)) {
btrfs_err(info, "zoned: space cache v1 is not supported"); return -EINVAL;
}
if (btrfs_raw_test_opt(*mount_opt, NODATACOW)) {
btrfs_err(info, "zoned: NODATACOW not supported"); return -EINVAL;
}
if (btrfs_raw_test_opt(*mount_opt, DISCARD_ASYNC)) {
btrfs_info(info, "zoned: async discard ignored and disabled for zoned mode");
btrfs_clear_opt(*mount_opt, DISCARD_ASYNC);
}
return0;
}
staticint sb_log_location(struct block_device *bdev, struct blk_zone *zones, int rw, u64 *bytenr_ret)
{
u64 wp; int ret;
if (!test_bit(zone_num, zinfo->seq_zones)) returnfalse;
returntrue;
}
int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
{ struct btrfs_zoned_device_info *zinfo = device->zone_info; struct blk_zone *zone; int i;
if (!is_sb_log_zone(zinfo, mirror)) return0;
zone = &zinfo->sb_zones[BTRFS_NR_SB_LOG_ZONES * mirror]; for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) { /* Advance the next zone */ if (zone->cond == BLK_ZONE_COND_FULL) {
zone++; continue;
}
if (zone->cond == BLK_ZONE_COND_EMPTY)
zone->cond = BLK_ZONE_COND_IMP_OPEN;
zone->wp += SUPER_INFO_SECTORS;
if (sb_zone_is_full(zone)) { /* *Noroomlefttowritenewsuperblock.Since *superblockiswrittenwithREQ_SYNC,itissafeto *finishthezonenow. * *Ifthewritepointerisexactlyatthecapacity, *explicitZONE_FINISHisnotnecessary.
*/ if (zone->wp != zone->start + zone->capacity) { unsignedint nofs_flags; int ret;
nofs_flags = memalloc_nofs_save();
ret = blkdev_zone_mgmt(device->bdev,
REQ_OP_ZONE_FINISH, zone->start,
zone->len);
memalloc_nofs_restore(nofs_flags); if (ret) return ret;
}
while (pos < hole_end) {
begin = pos >> shift;
end = begin + nzones;
if (end > zinfo->nr_zones) return hole_end;
/* Check if zones in the region are all empty */ if (btrfs_dev_is_sequential(device, pos) &&
!bitmap_test_range_all_set(zinfo->empty_zones, begin, nzones)) {
pos += zinfo->zone_size; continue;
}
have_sb = false; for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
u32 sb_zone;
u64 sb_pos;
/* We can use any number of zones */ if (zone_info->max_active_zones == 0) returntrue;
if (!test_bit(zno, zone_info->active_zones)) { /* Active zone left? */ if (atomic_dec_if_positive(&zone_info->active_zones_left) < 0) returnfalse; if (test_and_set_bit(zno, zone_info->active_zones)) { /* Someone already set the bit */
atomic_inc(&zone_info->active_zones_left);
}
}
if (begin + nbits > zinfo->nr_zones) return -ERANGE;
/* All the zones are conventional */ if (bitmap_test_range_all_zero(zinfo->seq_zones, begin, nbits)) return0;
/* All the zones are sequential and empty */ if (bitmap_test_range_all_set(zinfo->seq_zones, begin, nbits) &&
bitmap_test_range_all_set(zinfo->empty_zones, begin, nbits)) return0;
if (!btrfs_dev_is_sequential(device, pos) ||
btrfs_dev_is_empty_zone(device, pos)) continue;
/* Free regions should be empty */
btrfs_warn(
device->fs_info, "zoned: resetting device %s (devid %llu) zone %llu for allocation",
rcu_dereference(device->name), device->devid, pos >> shift);
WARN_ON_ONCE(1);
ret = btrfs_reset_device_zone(device, pos, zinfo->zone_size,
&reset_bytes); if (ret) return ret;
}
root = btrfs_extent_root(fs_info, key.objectid);
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); /* We should not find the exact match */ if (!ret)
ret = -EUCLEAN; if (ret < 0) return ret;
ret = btrfs_previous_extent_item(root, path, cache->start); if (ret) { if (ret == 1) {
ret = 0;
*offset_ret = 0;
} return ret;
}
if (zone_info[0].alloc_offset == WP_MISSING_DEV) {
btrfs_err(bg->fs_info, "zoned: cannot recover write pointer for zone %llu",
zone_info[0].physical); return -EIO;
} if (zone_info[1].alloc_offset == WP_MISSING_DEV) {
btrfs_err(bg->fs_info, "zoned: cannot recover write pointer for zone %llu",
zone_info[1].physical); return -EIO;
}
if (zone_info[0].alloc_offset == WP_CONVENTIONAL)
zone_info[0].alloc_offset = last_alloc;
if (zone_info[1].alloc_offset == WP_CONVENTIONAL)
zone_info[1].alloc_offset = last_alloc;
if (zone_info[0].alloc_offset != zone_info[1].alloc_offset) {
btrfs_err(bg->fs_info, "zoned: write pointer offset mismatch of zones in DUP profile"); return -EIO;
}
if (test_bit(0, active) != test_bit(1, active)) { if (!btrfs_zone_activate(bg)) return -EIO;
} elseif (test_bit(0, active)) {
set_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &bg->runtime_flags);
}
out: /* Reject non SINGLE data profiles without RST */ if ((map->type & BTRFS_BLOCK_GROUP_DATA) &&
(map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) &&
!fs_info->stripe_root) {
btrfs_err(fs_info, "zoned: data %s needs raid-stripe-tree",
btrfs_bg_type_to_raid_name(map->type));
ret = -EINVAL;
}
if (cache->alloc_offset > cache->zone_capacity) {
btrfs_err(fs_info, "zoned: invalid write pointer %llu (larger than zone capacity %llu) in block group %llu",
cache->alloc_offset, cache->zone_capacity,
cache->start);
ret = -EIO;
}
/* An extent is allocated after the write pointer */ if (!ret && num_conventional && last_alloc > cache->alloc_offset) {
btrfs_err(fs_info, "zoned: got wrong write pointer in BG %llu: %llu > %llu",
logical, last_alloc, cache->alloc_offset);
ret = -EIO;
}
/* We only need ->free_space in ALLOC_SEQ block groups */
cache->cached = BTRFS_CACHE_FINISHED;
cache->free_space_ctl->free_space = free;
cache->zone_unusable = unusable;
}
write_lock(&em_tree->lock);
em = btrfs_search_extent_mapping(em_tree, ordered->file_offset,
ordered->num_bytes); /* The em should be a new COW extent, thus it should not have an offset. */
ASSERT(em->offset == 0);
em->disk_bytenr = logical;
btrfs_free_extent_map(em);
write_unlock(&em_tree->lock);
}
/* *Writetopre-allocatedregionisforthedatarelocation,andso *itshoulduseWRITEoperation.Nosplit/rewritearenecessary.
*/ if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) return;
ASSERT(!list_empty(&ordered->list)); /* The ordered->list can be empty in the above pre-alloc case. */
sum = list_first_entry(&ordered->list, struct btrfs_ordered_sum, list);
logical = sum->logical;
len = sum->len;
while (len < ordered->disk_num_bytes) {
sum = list_next_entry(sum, list); if (sum->logical == logical + len) {
len += sum->len; continue;
} if (!btrfs_zoned_split_ordered(ordered, logical, len)) {
set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
btrfs_err(fs_info, "failed to split ordered extent"); goto out;
}
logical = sum->logical;
len = sum->len;
}
if (ordered->disk_bytenr != logical)
btrfs_rewrite_logical_zoned(ordered, logical);
if (!block_group) {
block_group = btrfs_lookup_block_group(fs_info, eb->start); if (!block_group) return0;
ctx->zoned_bg = block_group;
}
if (block_group->meta_write_pointer == eb->start) { struct btrfs_block_group **tgt;
if (!test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags)) return0;
if (block_group->flags & BTRFS_BLOCK_GROUP_SYSTEM)
tgt = &fs_info->active_system_bg; else
tgt = &fs_info->active_meta_bg; if (check_bg_is_active(ctx, tgt)) return0;
}
/* *Sincewemayreleasefs_info->zoned_meta_io_lock,someonecanalready *startwritingthiseb.Inthatcase,wecanjustbailout.
*/ if (block_group->meta_write_pointer > eb->start) return -EBUSY;
/* If for_sync, this hole will be filled with transaction commit. */ if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) return -EAGAIN; return -EBUSY;
}
int btrfs_zoned_issue_zeroout(struct btrfs_device *device, u64 physical, u64 length)
{ if (!btrfs_dev_is_sequential(device, physical)) return -EOPNOTSUPP;
if (!btrfs_is_zoned(block_group->fs_info)) returntrue;
map = block_group->physical_map;
spin_lock(&fs_info->zone_active_bgs_lock);
spin_lock(&block_group->lock); if (test_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &block_group->runtime_flags)) {
ret = true; goto out_unlock;
}
if (block_group->flags & BTRFS_BLOCK_GROUP_DATA) { /* The caller should check if the block group is full. */ if (WARN_ON_ONCE(btrfs_zoned_bg_is_full(block_group))) {
ret = false; goto out_unlock;
}
} else { /* Since it is already written, it should have been active. */
WARN_ON_ONCE(block_group->meta_write_pointer != block_group->start);
}
for (i = 0; i < map->num_stripes; i++) { struct btrfs_zoned_device_info *zinfo; int reserved = 0;
if (is_data)
reserved = zinfo->reserved_active_zones; /* *Forthedatablockgroup,leaveactivezonesforone *metadatablockgroupandonesystemblockgroup.
*/ if (atomic_read(&zinfo->active_zones_left) <= reserved) {
ret = false; goto out_unlock;
}
if (!btrfs_dev_set_active_zone(device, physical)) { /* Cannot activate the zone */
ret = false; goto out_unlock;
} if (!is_data)
zinfo->reserved_active_zones--;
}
/* Successfully activated all the zones */
set_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &block_group->runtime_flags);
spin_unlock(&block_group->lock);
/* For the active block group list */
btrfs_get_block_group(block_group);
list_add_tail(&block_group->active_bg_list, &fs_info->zone_active_bgs);
spin_unlock(&fs_info->zone_active_bgs_lock);
spin_lock(&block_group->lock); if (!test_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &block_group->runtime_flags)) {
spin_unlock(&block_group->lock); return0;
}
/* Check if we have unwritten allocated space */ if (is_metadata &&
block_group->start + block_group->alloc_offset > block_group->meta_write_pointer) {
spin_unlock(&block_group->lock); return -EAGAIN;
}
/* *Ifwearesurethattheblockgroupisfull(=nomoreroomleftfor *newallocation)andtheIOforthelastusableblockiscompleted,we *don'tneedtowaitfortheotherIOs.Thisholdsbecauseweensure *thesequentialIOsubmissionsusingtheZONE_APPENDcommandfordata *andblock_group->meta_write_pointerformetadata.
*/ if (!fully_written) { if (test_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags)) {
spin_unlock(&block_group->lock); return -EAGAIN;
}
spin_unlock(&block_group->lock);
ret = btrfs_inc_block_group_ro(block_group, false); if (ret) return ret;
/* Ensure all writes in this block group finish */
btrfs_wait_block_group_reservations(block_group); /* No need to wait for NOCOW writers. Zoned mode does not allow that */
btrfs_wait_ordered_roots(fs_info, U64_MAX, block_group); /* Wait for extent buffers to be written. */ if (is_metadata)
wait_eb_writebacks(block_group);
if (test_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags)) returnfalse;
/* Check if there is a device with active zones left */
mutex_lock(&fs_info->chunk_mutex);
spin_lock(&fs_info->zone_active_bgs_lock);
list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { struct btrfs_zoned_device_info *zinfo = device->zone_info; int reserved = 0;
if (!device->bdev) continue;
if (!zinfo->max_active_zones) {
ret = true; break;
}
if (flags & BTRFS_BLOCK_GROUP_DATA)
reserved = zinfo->reserved_active_zones;
switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) { case0: /* single */
ret = (atomic_read(&zinfo->active_zones_left) >= (1 + reserved)); break; case BTRFS_BLOCK_GROUP_DUP:
ret = (atomic_read(&zinfo->active_zones_left) >= (2 + reserved)); break;
} if (ret) break;
}
spin_unlock(&fs_info->zone_active_bgs_lock);
mutex_unlock(&fs_info->chunk_mutex);
if (!ret)
set_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags);
block_group = btrfs_lookup_block_group(fs_info, logical); if (WARN_ON_ONCE(!block_group)) return -ENOENT;
/* No MIXED_BG on zoned btrfs. */ if (block_group->flags & BTRFS_BLOCK_GROUP_DATA)
min_alloc_bytes = fs_info->sectorsize; else
min_alloc_bytes = fs_info->nodesize;
/* Bail out if we can allocate more data from this block group. */ if (logical + length + min_alloc_bytes <=
block_group->start + block_group->zone_capacity) goto out;
if (WARN_ON(bg->zone_finish_work.func == btrfs_zone_finish_endio_workfn)) {
btrfs_err(bg->fs_info, "double scheduling of bg %llu zone finishing",
bg->start); return;
}
/* For the work */
btrfs_get_block_group(bg);
refcount_inc(&eb->refs);
bg->last_eb = eb;
INIT_WORK(&bg->zone_finish_work, btrfs_zone_finish_endio_workfn);
queue_work(system_unbound_wq, &bg->zone_finish_work);
}
alloc_flags = btrfs_get_alloc_profile(fs_info, space_info->flags);
index = btrfs_bg_flags_to_raid_index(alloc_flags);
/* Scan the data space_info to find empty block groups. Take the second one. */
again:
bg_list = &space_info->block_groups[index];
list_for_each_entry(bg, bg_list, list) { if (bg->alloc_offset != 0) continue;
if (first) {
first = false; continue;
}
if (space_info == data_sinfo) { /* Migrate the block group to the data relocation space_info. */ struct btrfs_space_info *reloc_sinfo = data_sinfo->sub_group[0]; int factor;
down_write(&space_info->groups_sem);
list_del_init(&bg->list); /* We can assume this as we choose the second empty one. */
ASSERT(!list_empty(&space_info->block_groups[index]));
up_write(&space_info->groups_sem);
spin_lock(&space_info->lock);
space_info->total_bytes -= bg->length;
space_info->disk_total -= bg->length * factor;
space_info->disk_total -= bg->zone_unusable; /* There is no allocation ever happened. */
ASSERT(bg->used == 0); /* No super block in a block group on the zoned setup. */
ASSERT(bg->bytes_super == 0);
spin_unlock(&space_info->lock);
bg->space_info = reloc_sinfo; if (reloc_sinfo->block_group_kobjs[index] == NULL)
btrfs_sysfs_add_block_group_type(bg);
block_group = btrfs_lookup_block_group(fs_info, logical); /* It should be called on a previous data relocation block group. */
ASSERT(block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA));
spin_lock(&block_group->lock); if (!test_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags)) goto out;
/* All relocation extents are written. */ if (block_group->start + block_group->alloc_offset == logical + length) { /* *Now,releasethisblockgroupforfurtherallocationsand *zonefinish.
*/
clear_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC,
&block_group->runtime_flags);
}
ret = btrfs_zone_finish_one_bg(fs_info); if (ret == 0) break; if (ret < 0) return ret;
}
return0;
}
/* *Reservezonesforonemetadatablockgroup,onetree-logblockgroup,andone *systemblockgroup.
*/ void btrfs_check_active_zone_reservation(struct btrfs_fs_info *fs_info)
{ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; struct btrfs_block_group *block_group; struct btrfs_device *device; /* Reserve zones for normal SINGLE metadata and tree-log block group. */ unsignedint metadata_reserve = 2; /* Reserve a zone for SINGLE system block group. */ unsignedint system_reserve = 1;
if (!test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags)) return;
/* *Thisfunctioniscalledfromthemountcontext.So,thereisno *parallelprocesstouchingthebits.Noneedforread_seqretry().
*/ if (fs_info->avail_metadata_alloc_bits & BTRFS_BLOCK_GROUP_DUP)
metadata_reserve = 4; if (fs_info->avail_system_alloc_bits & BTRFS_BLOCK_GROUP_DUP)
system_reserve = 2;
/* Apply the reservation on all the devices. */
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry(device, &fs_devices->devices, dev_list) { if (!device->bdev) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.