fs/btrfs/zoned.c

Source file repositories/reference/linux-study-clean/fs/btrfs/zoned.c

File Facts

System
Linux kernel
Corpus path
fs/btrfs/zoned.c
Extension
.c
Size
90300 bytes
Lines
3262
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct zone_info {
	u64 physical;
	u64 capacity;
	u64 alloc_offset;
};

static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
				struct zone_info *info, unsigned long *active,
				struct btrfs_chunk_map *map, bool new)
{
	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
	struct btrfs_device *device;
	bool dev_replace_is_ongoing = false;
	unsigned int nofs_flag;
	struct blk_zone zone;
	int ret;

	info->physical = map->stripes[zone_idx].physical;

	down_read(&dev_replace->rwsem);
	device = map->stripes[zone_idx].dev;

	if (!device->bdev) {
		up_read(&dev_replace->rwsem);
		info->alloc_offset = WP_MISSING_DEV;
		return 0;
	}

	/* Consider a zone as active if we can allow any number of active zones. */
	if (!device->zone_info->max_active_zones)
		__set_bit(zone_idx, active);

	if (!btrfs_dev_is_sequential(device, info->physical)) {
		up_read(&dev_replace->rwsem);
		info->alloc_offset = WP_CONVENTIONAL;
		info->capacity = device->zone_info->zone_size;
		return 0;
	}

	ASSERT(!new || btrfs_dev_is_empty_zone(device, info->physical));

	/* This zone will be used for allocation, so mark this zone non-empty. */
	btrfs_dev_clear_zone_empty(device, info->physical);

	dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
	if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
		btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);

	/*
	 * The group is mapped to a sequential zone. Get the zone write pointer
	 * to determine the allocation offset within the zone.
	 */
	WARN_ON(!IS_ALIGNED(info->physical, fs_info->zone_size));

	if (new) {
		sector_t capacity;

		capacity = bdev_zone_capacity(device->bdev, info->physical >> SECTOR_SHIFT);
		up_read(&dev_replace->rwsem);
		info->alloc_offset = 0;
		info->capacity = capacity << SECTOR_SHIFT;

		return 0;
	}

	nofs_flag = memalloc_nofs_save();
	ret = btrfs_get_dev_zone(device, info->physical, &zone);
	memalloc_nofs_restore(nofs_flag);
	if (ret) {
		up_read(&dev_replace->rwsem);
		if (ret != -EIO && ret != -EOPNOTSUPP)
			return ret;
		info->alloc_offset = WP_MISSING_DEV;
		return 0;
	}

	if (unlikely(zone.type == BLK_ZONE_TYPE_CONVENTIONAL)) {
		btrfs_err(fs_info,
		"zoned: unexpected conventional zone %llu on device %s (devid %llu)",
			zone.start << SECTOR_SHIFT, rcu_dereference(device->name),
			device->devid);
		up_read(&dev_replace->rwsem);
		return -EIO;
	}

	info->capacity = (zone.capacity << SECTOR_SHIFT);

	switch (zone.cond) {
	case BLK_ZONE_COND_OFFLINE:
	case BLK_ZONE_COND_READONLY:

Annotation

Implementation Notes