* [PATCH 3/4] btrfs-convert: permit support for non-ext2 FSs
@ 2010-03-20 4:27 Sean Bartell
0 siblings, 0 replies; only message in thread
From: Sean Bartell @ 2010-03-20 4:27 UTC (permalink / raw)
To: linux-btrfs
Filesystems need to provide a function open_blah that fills a struct
convert_fs with some information and three function pointers.
The function pointers are:
- cache_free_extents, which takes a struct extent_io_tree and marks all
extents not being used by the filesystem as DIRTY
- copy_inodes, which copies the contents of the filesystem into a
btrfs_root using CoW.
- close
There's a void* in struct convert_fs for private use by the filesystem.
libblkid is used to determine the filesystem.
---
Makefile | 2 +-
convert.c | 184 +++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 126 insertions(+), 60 deletions(-)
diff --git a/Makefile b/Makefile
index 525676e..755cc24 100644
--- a/Makefile
+++ b/Makefile
@@ -75,7 +75,7 @@ quick-test: $(objects) quick-test.o
gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS)
convert: $(objects) convert.o
- gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs $(LDFLAGS) $(LIBS)
+ gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lblkid $(LDFLAGS) $(LIBS)
ioctl-test: $(objects) ioctl-test.o
gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
diff --git a/convert.c b/convert.c
index bd91990..6dfcb97 100644
--- a/convert.c
+++ b/convert.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <uuid/uuid.h>
#include <linux/fs.h>
+#include <blkid/blkid.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
@@ -42,9 +43,26 @@
#include <ext2fs/ext2fs.h>
#include <ext2fs/ext2_ext_attr.h>
+struct convert_fs {
+ u64 total_bytes;
+ u64 blocksize;
+ const char *label;
+
+ /* Close the FS */
+ int (*close)(struct convert_fs *fs);
+ /* Mark free extents as dirty */
+ int (*cache_free_extents)(struct convert_fs *fs,
+ struct extent_io_tree *tree);
+ /* Copy everything over */
+ int (*copy_inodes)(struct convert_fs *fs, struct btrfs_root *root,
+ int datacsum, int packing, int noxattr);
+
+ void *privdata;
+};
+
#define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO)
#define STRIPE_LEN (64 * 1024)
-#define EXT2_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
+#define ORIG_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
/*
* Open Ext2fs in readonly mode, read block allocation bitmap and
@@ -89,15 +107,16 @@ fail:
return -1;
}
-static int close_ext2fs(ext2_filsys fs)
+static int ext2_close(struct convert_fs *fs)
{
- ext2fs_close(fs);
+ ext2fs_close((ext2_filsys)fs->privdata);
return 0;
}
-static int ext2_cache_free_extents(ext2_filsys ext2_fs,
+static int ext2_cache_free_extents(struct convert_fs *fs,
struct extent_io_tree *free_tree)
{
+ ext2_filsys ext2_fs = fs->privdata;
int ret = 0;
blk_t block;
u64 bytenr;
@@ -117,19 +136,18 @@ static int ext2_cache_free_extents(ext2_filsys ext2_fs,
}
/* mark btrfs-reserved blocks as used */
-static void adjust_free_extents(ext2_filsys ext2_fs,
+static void adjust_free_extents(struct convert_fs *fs,
struct extent_io_tree *free_tree)
{
int i;
u64 bytenr;
- u64 blocksize = ext2_fs->blocksize;
clear_extent_dirty(free_tree, 0, BTRFS_SUPER_INFO_OFFSET - 1, 0);
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i);
bytenr &= ~((u64)STRIPE_LEN - 1);
- if (bytenr >= blocksize * ext2_fs->super->s_blocks_count)
+ if (bytenr >= fs->total_bytes)
break;
clear_extent_dirty(free_tree, bytenr, bytenr + STRIPE_LEN - 1,
0);
@@ -1373,9 +1391,10 @@ fail:
/*
* scan ext2's inode bitmap and copy all used inode.
*/
-static int copy_inodes(struct btrfs_root *root, ext2_filsys ext2_fs,
- int datacsum, int packing, int noxattr)
+static int ext2_copy_inodes(struct convert_fs *fs, struct btrfs_root *root,
+ int datacsum, int packing, int noxattr)
{
+ ext2_filsys ext2_fs = fs->privdata;
int ret;
errcode_t err;
ext2_inode_scan ext2_scan;
@@ -1426,8 +1445,8 @@ static int copy_inodes(struct btrfs_root *root, ext2_filsys ext2_fs,
}
/*
- * Construct a range of ext2fs image file.
- * scan block allocation bitmap, find all blocks used by the ext2fs
+ * Construct a range of the image file.
+ * scan block allocation bitmap, find all blocks used by the filesystem
* in this range and create file extents that point to these blocks.
*
* Note: Before calling the function, no file extent points to blocks
@@ -1465,10 +1484,10 @@ static int create_image_file_range(struct btrfs_trans_handle *trans,
return ret;
}
/*
- * Create the ext2fs image file.
+ * Create the image file.
*/
-static int create_ext2_image(struct btrfs_root *root, const char *name,
- struct extent_io_tree *orig_free_tree)
+static int create_image(struct btrfs_root *root, const char *name,
+ struct extent_io_tree *orig_free_tree)
{
int ret;
struct btrfs_key key;
@@ -1620,7 +1639,7 @@ next:
btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY);
ret = btrfs_insert_dir_item(trans, root, name, strlen(name),
btrfs_root_dirid(&root->root_item),
- &location, EXT2_FT_REG_FILE, objectid);
+ &location, BTRFS_FT_REG_FILE, objectid);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(trans, root, name, strlen(name),
@@ -1996,8 +2015,8 @@ static int init_btrfs(struct btrfs_root *root)
btrfs_set_root_dirid(&fs_info->fs_root->root_item,
BTRFS_FIRST_FREE_OBJECTID);
- /* subvol for ext2 image file */
- ret = create_subvol(trans, root, EXT2_IMAGE_SUBVOL_OBJECTID);
+ /* subvol for image file */
+ ret = create_subvol(trans, root, ORIG_IMAGE_SUBVOL_OBJECTID);
BUG_ON(ret);
/* subvol for data relocation */
ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
@@ -2273,7 +2292,7 @@ fail:
}
static int relocate_extents_range(struct btrfs_root *fs_root,
- struct btrfs_root *ext2_root,
+ struct btrfs_root *image_root,
u64 start_byte, u64 end_byte)
{
struct btrfs_fs_info *info = fs_root->fs_info;
@@ -2320,7 +2339,7 @@ static int relocate_extents_range(struct btrfs_root *fs_root,
}
btrfs_release_path(extent_root, &path);
again:
- cur_root = (pass % 2 == 0) ? ext2_root : fs_root;
+ cur_root = (pass % 2 == 0) ? image_root : fs_root;
num_extents = 0;
trans = btrfs_start_transaction(cur_root, 1);
@@ -2428,7 +2447,7 @@ fail:
* relocate data in system chunk
*/
static int cleanup_sys_chunk(struct btrfs_root *fs_root,
- struct btrfs_root *ext2_root)
+ struct btrfs_root *image_root)
{
struct btrfs_block_group_cache *cache;
int i, ret = 0;
@@ -2442,7 +2461,7 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
end_byte = cache->key.objectid + cache->key.offset;
if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {
- ret = relocate_extents_range(fs_root, ext2_root,
+ ret = relocate_extents_range(fs_root, image_root,
cache->key.objectid,
end_byte);
if (ret)
@@ -2454,7 +2473,7 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
offset = btrfs_sb_offset(i);
offset &= ~((u64)STRIPE_LEN - 1);
- ret = relocate_extents_range(fs_root, ext2_root,
+ ret = relocate_extents_range(fs_root, image_root,
offset, offset + STRIPE_LEN);
if (ret)
goto fail;
@@ -2567,6 +2586,55 @@ static int copy_dirtiness(struct extent_io_tree *out,
return 0;
}
+int ext2_open(struct convert_fs *fs, const char *name)
+{
+ int ret;
+ ext2_filsys ext2_fs;
+ ret = open_ext2fs(name, &ext2_fs);
+ if (ret)
+ return ret;
+
+ fs->privdata = ext2_fs;
+ fs->blocksize = ext2_fs->blocksize;
+ fs->label = ext2_fs->super->s_volume_name;
+ fs->total_bytes = ext2_fs->super->s_blocks_count * fs->blocksize;
+
+ fs->cache_free_extents = ext2_cache_free_extents;
+ fs->close = ext2_close;
+ fs->copy_inodes = ext2_copy_inodes;
+
+ return 0;
+}
+
+static int open_fs(struct convert_fs *fs, const char *devname)
+{
+ static struct {
+ const char *name; /* must match libblkid */
+ int (*open)(struct convert_fs *fs, const char *name);
+ } convert_fs_types[] = {
+ {"ext2", ext2_open},
+ {"ext3", ext2_open},
+ {"ext4", ext2_open},
+ {"ext4dev", ext2_open},
+ };
+
+ int i;
+ char *type = blkid_get_tag_value(NULL, "TYPE", devname);
+ if (!type) {
+ fprintf(stderr, "unrecognized filesystem type\n");
+ return -1;
+ }
+ for (i = 0; i < ARRAY_SIZE(convert_fs_types); i++) {
+ if (!strcmp(type, convert_fs_types[i].name)) {
+ free(type);
+ return convert_fs_types[i].open(fs, devname);
+ }
+ }
+ fprintf(stderr, "%s filesystems are not supported\n", type);
+ free(type);
+ return -1;
+}
+
int do_convert(const char *devname, int datacsum, int packing, int noxattr)
{
int fd, ret;
@@ -2574,31 +2642,27 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
u64 blocks[7];
u64 total_bytes;
u64 super_bytenr;
- ext2_filsys ext2_fs;
+ struct convert_fs fs;
struct btrfs_root *root;
- struct btrfs_root *ext2_root;
+ struct btrfs_root *image_root;
struct extent_io_tree free_tree;
struct extent_io_tree orig_free_tree;
extent_io_tree_init(&free_tree);
extent_io_tree_init(&orig_free_tree);
- ret = open_ext2fs(devname, &ext2_fs);
+ fs.privdata = NULL;
+ ret = open_fs(&fs, devname);
if (ret) {
- fprintf(stderr, "unable to open the Ext2fs\n");
+ fprintf(stderr, "unable to open the filesystem\n");
goto fail;
}
- blocksize = ext2_fs->blocksize;
- total_bytes = (u64)ext2_fs->super->s_blocks_count * blocksize;
+ blocksize = fs.blocksize;
+ total_bytes = fs.total_bytes;
if (blocksize < 4096) {
fprintf(stderr, "block size is too small\n");
goto fail;
}
- if (!(ext2_fs->super->s_feature_incompat &
- EXT2_FEATURE_INCOMPAT_FILETYPE)) {
- fprintf(stderr, "filetype feature is missing\n");
- goto fail;
- }
- ret = ext2_cache_free_extents(ext2_fs, &orig_free_tree);
+ ret = fs.cache_free_extents(&fs, &orig_free_tree);
if (ret) {
fprintf(stderr, "error during cache_free_extents %d\n", ret);
goto fail;
@@ -2611,7 +2675,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "error during copy_dirtiness %d\n", ret);
goto fail;
}
- adjust_free_extents(ext2_fs, &free_tree);
+ adjust_free_extents(&fs, &free_tree);
ret = alloc_blocks(&free_tree, blocks, 7, blocksize);
if (ret) {
goto fail;
@@ -2622,9 +2686,8 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "unable to open %s\n", devname);
goto fail;
}
- ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name,
- blocks, total_bytes, blocksize, blocksize,
- blocksize, blocksize);
+ ret = make_btrfs(fd, devname, fs.label, blocks, total_bytes, blocksize,
+ blocksize, blocksize, blocksize);
if (ret) {
fprintf(stderr, "unable to create initial ctree\n");
goto fail;
@@ -2649,25 +2712,25 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
goto fail;
}
printf("creating btrfs metadata.\n");
- ret = copy_inodes(root, ext2_fs, datacsum, packing, noxattr);
+ ret = fs.copy_inodes(&fs, root, datacsum, packing, noxattr);
if (ret) {
fprintf(stderr, "error during copy_inodes %d\n", ret);
goto fail;
}
- printf("creating ext2fs image file.\n");
- ext2_root = link_subvol(root, "ext2_saved", EXT2_IMAGE_SUBVOL_OBJECTID);
- if (!ext2_root) {
+ printf("creating image file.\n");
+ image_root = link_subvol(root, "image_saved", ORIG_IMAGE_SUBVOL_OBJECTID);
+ if (!image_root) {
fprintf(stderr, "unable to create subvol\n");
goto fail;
}
- ret = create_ext2_image(ext2_root, "image", &orig_free_tree);
+ ret = create_image(image_root, "image", &orig_free_tree);
if (ret) {
- fprintf(stderr, "error during create_ext2_image %d\n", ret);
+ fprintf(stderr, "error during create_image %d\n", ret);
goto fail;
}
extent_io_tree_cleanup(&orig_free_tree);
printf("cleaning up system chunk.\n");
- ret = cleanup_sys_chunk(root, ext2_root);
+ ret = cleanup_sys_chunk(root, image_root);
if (ret) {
fprintf(stderr, "error during cleanup_sys_chunk %d\n", ret);
goto fail;
@@ -2677,11 +2740,12 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "error during close_ctree %d\n", ret);
goto fail;
}
- close_ext2fs(ext2_fs);
+ fs.close(&fs);
+ fs.privdata = NULL;
/*
* If this step succeed, we get a mountable btrfs. Otherwise
- * the ext2fs is left unchanged.
+ * the original filesystem is left unchanged.
*/
ret = migrate_super_block(fd, super_bytenr, blocksize);
if (ret) {
@@ -2706,6 +2770,8 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
printf("conversion complete.\n");
return 0;
fail:
+ if (fs.privdata)
+ fs.close(&fs);
fprintf(stderr, "conversion aborted.\n");
return -1;
}
@@ -2755,7 +2821,7 @@ int do_rollback(const char *devname, int force)
int ret;
int i;
struct btrfs_root *root;
- struct btrfs_root *ext2_root;
+ struct btrfs_root *image_root;
struct btrfs_root *chunk_root;
struct btrfs_dir_item *dir;
struct btrfs_inode_item *inode;
@@ -2808,11 +2874,11 @@ int do_rollback(const char *devname, int force)
btrfs_init_path(&path);
- key.objectid = EXT2_IMAGE_SUBVOL_OBJECTID;
+ key.objectid = ORIG_IMAGE_SUBVOL_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
- ext2_root = btrfs_read_fs_root(root->fs_info, &key);
- if (!ext2_root || IS_ERR(ext2_root)) {
+ image_root = btrfs_read_fs_root(root->fs_info, &key);
+ if (!image_root || IS_ERR(image_root)) {
fprintf(stderr, "unable to open subvol %llu\n",
key.objectid);
goto fail;
@@ -2820,7 +2886,7 @@ int do_rollback(const char *devname, int force)
name = "image";
root_dir = btrfs_root_dirid(&root->root_item);
- dir = btrfs_lookup_dir_item(NULL, ext2_root, &path,
+ dir = btrfs_lookup_dir_item(NULL, image_root, &path,
root_dir, name, strlen(name), 0);
if (!dir || IS_ERR(dir)) {
fprintf(stderr, "unable to find file %s\n", name);
@@ -2828,11 +2894,11 @@ int do_rollback(const char *devname, int force)
}
leaf = path.nodes[0];
btrfs_dir_item_key_to_cpu(leaf, dir, &key);
- btrfs_release_path(ext2_root, &path);
+ btrfs_release_path(image_root, &path);
objectid = key.objectid;
- ret = btrfs_lookup_inode(NULL, ext2_root, &path, &key, 0);
+ ret = btrfs_lookup_inode(NULL, image_root, &path, &key, 0);
if (ret) {
fprintf(stderr, "unable to find inode item\n");
goto fail;
@@ -2840,15 +2906,15 @@ int do_rollback(const char *devname, int force)
leaf = path.nodes[0];
inode = btrfs_item_ptr(leaf, path.slots[0], struct btrfs_inode_item);
total_bytes = btrfs_inode_size(leaf, inode);
- btrfs_release_path(ext2_root, &path);
+ btrfs_release_path(image_root, &path);
key.objectid = objectid;
key.offset = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
- ret = btrfs_search_slot(NULL, ext2_root, &key, &path, 0, 0);
+ ret = btrfs_search_slot(NULL, image_root, &key, &path, 0, 0);
if (ret != 0) {
fprintf(stderr, "unable to find first file extent\n");
- btrfs_release_path(ext2_root, &path);
+ btrfs_release_path(image_root, &path);
goto fail;
}
@@ -2899,7 +2965,7 @@ next_extent:
offset += btrfs_file_extent_num_bytes(leaf, fi);
path.slots[0]++;
}
- btrfs_release_path(ext2_root, &path);
+ btrfs_release_path(image_root, &path);
if (offset < total_bytes) {
fprintf(stderr, "unable to build extent mapping\n");
@@ -3058,7 +3124,7 @@ static void print_usage(void)
printf("\t-d disable data checksum\n");
printf("\t-i ignore xattrs and ACLs\n");
printf("\t-n disable packing of small files\n");
- printf("\t-r roll back to ext2fs\n");
+ printf("\t-r roll back to original filesystem\n");
}
int main(int argc, char *argv[])
--
1.6.4.4
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2010-03-20 4:27 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-20 4:27 [PATCH 3/4] btrfs-convert: permit support for non-ext2 FSs Sean Bartell
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.