[PATCH 3/5] btrfs-progs: mkfs: Shrink the image for rootdir to minimal size

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Follow the original rootdir behavior to shrink the device size to
minimal.

The shrink itself is very simple, since dev extent is allocated on
demand, we just need to shrink the device size to the device extent end
position.

Signed-off-by: Qu Wenruo <quwenruo.btrfs@xxxxxxx>
---
 mkfs/main.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/mkfs/main.c b/mkfs/main.c
index bca836b5..c43ce18d 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -990,6 +990,107 @@ fail_no_dir:
 	goto out;
 }
 
+/*
+ * Shrink the image to its minimal size.
+ *
+ * The work is quite easy, as btrfs only allocates dev extent/chunk on demand.
+ * So we only need to do:
+ * 1) Determine the minimal image size
+ *    By checking the device extent end
+ * 2) Modify in-memory device size
+ * 3) Modify device item
+ * 4) Modify superblock
+ */
+static int shrink_image(struct btrfs_trans_handle *trans,
+			struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_root *dev_root = fs_info->dev_root;
+	struct btrfs_root *chunk_root = fs_info->chunk_root;
+	struct btrfs_path path;
+	struct btrfs_key key;
+	struct btrfs_dev_extent *de;
+	struct btrfs_dev_item *di;
+	struct btrfs_device *dev;
+	u64 min_size;
+	int ret = 0;
+
+	/*
+	 * New rootdir can support multi device easily, but since only one
+	 * device is supported, devid is fixed to 1.
+	 */
+	key.objectid = 1;
+	key.type = BTRFS_DEV_EXTENT_KEY;
+	key.offset = (u64)-1;
+	btrfs_init_path(&path);
+
+	/*
+	 * Determine minimal fs size by find the end position of last dev extent
+	 */
+	ret = btrfs_search_slot(NULL, dev_root, &key, &path, 0, 0);
+	if (ret == 0) {
+		WARN_ON(1);
+		ret = -EIO;
+		goto out_release;
+	}
+	if (ret < 0)
+		goto out_release;
+
+	ret = btrfs_previous_item(dev_root, &path, key.objectid,
+				  BTRFS_DEV_EXTENT_KEY);
+	if (ret < 0)
+		goto out_release;
+	if (ret > 0) {
+		ret = -ENOENT;
+		goto out_release;
+	}
+	btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+	de = btrfs_item_ptr(path.nodes[0], path.slots[0],
+			    struct btrfs_dev_extent);
+	min_size = key.offset + btrfs_dev_extent_length(path.nodes[0], de);
+	btrfs_release_path(&path);
+
+	/*
+	 * Modify btrfs_device size
+	 */
+	dev = list_entry(fs_info->fs_devices->devices.next,
+			 struct btrfs_device, dev_list);
+	if (!dev) {
+		WARN_ON(1);
+		ret = -ENOENT;
+		goto out;
+	}
+	dev->total_bytes = min_size;
+
+	/*
+	 * Modify dev item size
+	 */
+	key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
+	key.type = BTRFS_DEV_ITEM_KEY;
+	key.offset = 1;
+
+	ret = btrfs_search_slot(trans, chunk_root, &key, &path, 0, 1);
+	if (ret > 0) {
+		ret = -ENOENT;
+		goto out_release;
+	}
+	if (ret < 0)
+		goto out_release;
+	di = btrfs_item_ptr(path.nodes[0], path.slots[0],
+			    struct btrfs_dev_item);
+	btrfs_set_device_total_bytes(path.nodes[0], di, min_size);
+	btrfs_release_path(&path);
+
+	/*
+	 * Modify superblock size
+	 */
+	btrfs_set_super_total_bytes(fs_info->super_copy, min_size);
+
+out_release:
+	btrfs_release_path(&path);
+out:
+	return ret;
+}
+
 static int make_image(const char *source_dir, struct btrfs_root *root)
 {
 	int ret;
@@ -1013,6 +1114,12 @@ static int make_image(const char *source_dir, struct btrfs_root *root)
 		error("unable to traverse directory %s: %d", source_dir, ret);
 		goto fail;
 	}
+
+	ret = shrink_image(trans, root->fs_info);
+	if (ret < 0) {
+		error("failed to shrink image: %d", ret);
+		goto out;
+	}
 	ret = btrfs_commit_transaction(trans, root);
 	if (ret) {
 		error("transaction commit failed: %d", ret);
-- 
2.14.1

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux