Commit ba73eadd authored by Jeffle Xu's avatar Jeffle Xu Committed by Gao Xiang
Browse files

erofs: scan devices from device table



When "-o device" mount option is not specified, scan the device table
and instantiate the devices if there's any in the device table. In this
case, the tag field of each device slot uniquely specifies a device.

Signed-off-by: default avatarJeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220512055601.106109-1-jefflexu@linux.alibaba.com


Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
parent d435d532
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -37,10 +37,7 @@
#define EROFS_SB_EXTSLOT_SIZE	16

struct erofs_deviceslot {
	union {
		u8 uuid[16];		/* used for device manager later */
		u8 userdata[64];	/* digest(sha256), etc. */
	} u;
	u8 tag[64];		/* digest(sha256), etc. */
	__le32 blocks;		/* total fs blocks of this device */
	__le32 mapped_blkaddr;	/* map starting at mapped_blkaddr */
	u8 reserved[56];
+69 −33
Original line number Diff line number Diff line
@@ -220,7 +220,52 @@ static int erofs_load_compr_cfgs(struct super_block *sb,
}
#endif

static int erofs_init_devices(struct super_block *sb,
static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
			     struct erofs_device_info *dif, erofs_off_t *pos)
{
	struct erofs_sb_info *sbi = EROFS_SB(sb);
	struct erofs_deviceslot *dis;
	struct block_device *bdev;
	void *ptr;
	int ret;

	ptr = erofs_read_metabuf(buf, sb, erofs_blknr(*pos), EROFS_KMAP);
	if (IS_ERR(ptr))
		return PTR_ERR(ptr);
	dis = ptr + erofs_blkoff(*pos);

	if (!dif->path) {
		if (!dis->tag[0]) {
			erofs_err(sb, "empty device tag @ pos %llu", *pos);
			return -EINVAL;
		}
		dif->path = kmemdup_nul(dis->tag, sizeof(dis->tag), GFP_KERNEL);
		if (!dif->path)
			return -ENOMEM;
	}

	if (erofs_is_fscache_mode(sb)) {
		ret = erofs_fscache_register_cookie(sb, &dif->fscache,
				dif->path, false);
		if (ret)
			return ret;
	} else {
		bdev = blkdev_get_by_path(dif->path, FMODE_READ | FMODE_EXCL,
					  sb->s_type);
		if (IS_ERR(bdev))
			return PTR_ERR(bdev);
		dif->bdev = bdev;
		dif->dax_dev = fs_dax_get_by_bdev(bdev, &dif->dax_part_off);
	}

	dif->blocks = le32_to_cpu(dis->blocks);
	dif->mapped_blkaddr = le32_to_cpu(dis->mapped_blkaddr);
	sbi->total_blocks += dif->blocks;
	*pos += EROFS_DEVT_SLOT_SIZE;
	return 0;
}

static int erofs_scan_devices(struct super_block *sb,
			      struct erofs_super_block *dsb)
{
	struct erofs_sb_info *sbi = EROFS_SB(sb);
@@ -228,8 +273,6 @@ static int erofs_init_devices(struct super_block *sb,
	erofs_off_t pos;
	struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
	struct erofs_device_info *dif;
	struct erofs_deviceslot *dis;
	void *ptr;
	int id, err = 0;

	sbi->total_blocks = sbi->primarydevice_blocks;
@@ -238,7 +281,8 @@ static int erofs_init_devices(struct super_block *sb,
	else
		ondisk_extradevs = le16_to_cpu(dsb->extra_devices);

	if (ondisk_extradevs != sbi->devs->extra_devices) {
	if (sbi->devs->extra_devices &&
	    ondisk_extradevs != sbi->devs->extra_devices) {
		erofs_err(sb, "extra devices don't match (ondisk %u, given %u)",
			  ondisk_extradevs, sbi->devs->extra_devices);
		return -EINVAL;
@@ -249,39 +293,31 @@ static int erofs_init_devices(struct super_block *sb,
	sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1;
	pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
	down_read(&sbi->devs->rwsem);
	if (sbi->devs->extra_devices) {
		idr_for_each_entry(&sbi->devs->tree, dif, id) {
		struct block_device *bdev;

		ptr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos),
					 EROFS_KMAP);
		if (IS_ERR(ptr)) {
			err = PTR_ERR(ptr);
			break;
		}
		dis = ptr + erofs_blkoff(pos);

		if (erofs_is_fscache_mode(sb)) {
			err = erofs_fscache_register_cookie(sb, &dif->fscache,
							    dif->path, false);
			err = erofs_init_device(&buf, sb, dif, &pos);
			if (err)
				break;
		}
	} else {
			bdev = blkdev_get_by_path(dif->path,
						  FMODE_READ | FMODE_EXCL,
						  sb->s_type);
			if (IS_ERR(bdev)) {
				err = PTR_ERR(bdev);
		for (id = 0; id < ondisk_extradevs; id++) {
			dif = kzalloc(sizeof(*dif), GFP_KERNEL);
			if (!dif) {
				err = -ENOMEM;
				break;
			}
			dif->bdev = bdev;
			dif->dax_dev = fs_dax_get_by_bdev(bdev,
							  &dif->dax_part_off);

			err = idr_alloc(&sbi->devs->tree, dif, 0, 0, GFP_KERNEL);
			if (err < 0) {
				kfree(dif);
				break;
			}
			++sbi->devs->extra_devices;

		dif->blocks = le32_to_cpu(dis->blocks);
		dif->mapped_blkaddr = le32_to_cpu(dis->mapped_blkaddr);
		sbi->total_blocks += dif->blocks;
		pos += EROFS_DEVT_SLOT_SIZE;
			err = erofs_init_device(&buf, sb, dif, &pos);
			if (err)
				break;
		}
	}
	up_read(&sbi->devs->rwsem);
	erofs_put_metabuf(&buf);
@@ -368,7 +404,7 @@ static int erofs_read_superblock(struct super_block *sb)
		goto out;

	/* handle multiple devices */
	ret = erofs_init_devices(sb, dsb);
	ret = erofs_scan_devices(sb, dsb);

	if (erofs_sb_has_ztailpacking(sbi))
		erofs_info(sb, "EXPERIMENTAL compressed inline data feature in use. Use at your own risk!");