On 7/25/17 4:54 PM, jeffm@xxxxxxxx wrote:
> From: Jeff Mahoney <jeffm@xxxxxxxx>
>
> This patch adds support to convert reiserfs file systems in-place to btrfs.
>
> It will convert extended attribute files to btrfs extended attributes,
> translate ACLs, coalesce tails that consist of multiple items into one item,
> and convert tails that are too big into indirect files.
>
> This requires that libreiserfscore 3.6.27 be available.
>
> Many of the test cases for convert apply regardless of what the source
> file system is and using ext4 is sufficient. I've included several
> test cases that are reiserfs-specific.
>
> Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx>
> ---
> Makefile | 3 +-
> Makefile.inc.in | 3 +-
> configure.ac | 10 +-
> convert/main.c | 13 +-
> convert/source-reiserfs.c | 1011 ++++++++++++++++++++
> convert/source-reiserfs.h | 105 ++
> tests/common.convert | 14 +-
> tests/convert-tests/010-reiserfs-basic/test.sh | 16 +
> .../011-reiserfs-delete-all-rollback/test.sh | 67 ++
> .../012-reiserfs-large-hole-extent/test.sh | 23 +
> .../013-reiserfs-common-inode-flags/test.sh | 35 +
> 11 files changed, 1290 insertions(+), 10 deletions(-)
> create mode 100644 convert/source-reiserfs.c
> create mode 100644 convert/source-reiserfs.h
> create mode 100755 tests/convert-tests/010-reiserfs-basic/test.sh
> create mode 100755 tests/convert-tests/011-reiserfs-delete-all-rollback/test.sh
> create mode 100755 tests/convert-tests/012-reiserfs-large-hole-extent/test.sh
> create mode 100755 tests/convert-tests/013-reiserfs-common-inode-flags/test.sh
>
> diff --git a/Makefile b/Makefile
> index 81598df..f7f6dab 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -111,7 +111,7 @@ libbtrfs_headers = send-stream.h send-utils.h send.h kernel-lib/rbtree.h btrfs-l
> kernel-lib/radix-tree.h kernel-lib/sizes.h extent-cache.h \
> extent_io.h ioctl.h ctree.h btrfsck.h version.h
> convert_objects = convert/main.o convert/common.o convert/source-fs.o \
> - convert/source-ext2.o
> + convert/source-ext2.o convert/source-reiserfs.o
> mkfs_objects = mkfs/main.o mkfs/common.o
>
> TESTS = fsck-tests.sh convert-tests.sh
> @@ -188,6 +188,7 @@ endif
> # external libs required by various binaries; for btrfs-foo,
> # specify btrfs_foo_libs = <list of libs>; see $($(subst...)) rules below
> btrfs_convert_cflags = -DBTRFSCONVERT_EXT2=$(BTRFSCONVERT_EXT2)
> +btrfs_convert_cflags += -DBTRFSCONVERT_REISERFS=$(BTRFSCONVERT_REISERFS)
> btrfs_fragments_libs = -lgd -lpng -ljpeg -lfreetype
> btrfs_debug_tree_objects = cmds-inspect-dump-tree.o
> btrfs_show_super_objects = cmds-inspect-dump-super.o
> diff --git a/Makefile.inc.in b/Makefile.inc.in
> index 4e1b68c..3c7bc03 100644
> --- a/Makefile.inc.in
> +++ b/Makefile.inc.in
> @@ -12,6 +12,7 @@ INSTALL = @INSTALL@
> DISABLE_DOCUMENTATION = @DISABLE_DOCUMENTATION@
> DISABLE_BTRFSCONVERT = @DISABLE_BTRFSCONVERT@
> BTRFSCONVERT_EXT2 = @BTRFSCONVERT_EXT2@
> +BTRFSCONVERT_REISERFS = @BTRFSCONVERT_REISERFS@
>
> SUBST_CFLAGS = @CFLAGS@
> SUBST_LDFLAGS = @LDFLAGS@
> @@ -31,6 +32,6 @@ udevruledir = ${udevdir}/rules.d
>
> # external libs required by various binaries; for btrfs-foo,
> # specify btrfs_foo_libs = <list of libs>; see $($(subst...)) rules in Makefile
> -btrfs_convert_libs = @EXT2FS_LIBS@ @COM_ERR_LIBS@
> +btrfs_convert_libs = @EXT2FS_LIBS@ @COM_ERR_LIBS@ @REISERFS_LIBS@
>
> MAKEFILE_INC_INCLUDED = yes
> diff --git a/configure.ac b/configure.ac
> index 30055f8..3a8bd3f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -120,6 +120,7 @@ fi
>
> convertfs=
> BTRFSCONVERT_EXT2=0
> +BTRFSCONVERT_REISERFS=0
> if test "x$enable_convert" = xyes; then
> if test "x$with_convert" = "xauto" || echo "$with_convert" | grep -q "ext2"; then
> PKG_CHECK_MODULES(EXT2FS, [ext2fs >= 1.42],,
> @@ -131,11 +132,18 @@ if test "x$enable_convert" = xyes; then
> convertfs="${convertfs:+$convertfs,}ext2"
> BTRFSCONVERT_EXT2=1
> fi
> + if test "x$with_convert" = "xauto" || echo "$with_convert" | grep -q "reiserfs"; then
> + PKG_CHECK_MODULES(REISERFS, [reiserfscore >= 3.6.27],
> + [BTRFSCONVERT_REISERFS=1],[])
> + convertfs="${convertfs:+$convertfs,}reiserfs"
> + BTRFSCONVERT_REISERFS=1
> + fi
> fi
> AC_SUBST([BTRFSCONVERT_EXT2])
> +AC_SUBST([BTRFSCONVERT_REISERFS])
>
> # catch typos
> -tmp=$(echo "$with_convert" | sed -e 's/auto//' | sed -e 's/ext2//' | sed -e 's/,\+/,/')
> +tmp=$(echo "$with_convert" | sed -e 's/auto//' | sed -e 's/ext2//' | sed -e 's/reiserfs//' | sed -e 's/,\+/,/')
> if ! test "x$tmp" = "x"; then
> AC_MSG_ERROR([unknown tokens for --with-convert: $tmp])
> fi
> diff --git a/convert/main.c b/convert/main.c
> index 01657a6..bc459a4 100644
> --- a/convert/main.c
> +++ b/convert/main.c
> @@ -102,12 +102,16 @@
> #include "convert/source-fs.h"
> #include "fsfeatures.h"
>
> -const struct btrfs_convert_operations ext2_convert_ops;
> +extern const struct btrfs_convert_operations ext2_convert_ops;
> +extern const struct btrfs_convert_operations reiserfs_convert_ops;
>
> static const struct btrfs_convert_operations *convert_operations[] = {
> #if BTRFSCONVERT_EXT2
> &ext2_convert_ops,
> #endif
> +#if BTRFSCONVERT_REISERFS
> + &reiserfs_convert_ops,
> +#endif
> };
>
> static void *print_copied_inodes(void *p)
> @@ -411,7 +415,7 @@ static int migrate_one_reserved_range(struct btrfs_trans_handle *trans,
> }
>
> /*
> - * Relocate the used ext2 data in reserved ranges
> + * Relocate the used source fs data in reserved ranges
> */
> static int migrate_reserved_ranges(struct btrfs_trans_handle *trans,
> struct btrfs_root *root,
> @@ -1655,11 +1659,11 @@ static int do_rollback(const char *devname)
> ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0);
> btrfs_release_path(&path);
> if (ret > 0) {
> - error("unable to find ext2 image subvolume, is it deleted?");
> + error("unable to find source fs image subvolume, is it deleted?");
> ret = -ENOENT;
> goto close_fs;
> } else if (ret < 0) {
> - error("failed to find ext2 image subvolume: %s",
> + error("failed to find source fs image subvolume: %s",
> strerror(-ret));
> goto close_fs;
> }
> @@ -1777,6 +1781,7 @@ static void print_usage(void)
> printf("\n");
> printf("Supported filesystems:\n");
> printf("\text2/3/4: %s\n", BTRFSCONVERT_EXT2 ? "yes" : "no");
> + printf("\treiserfs: %s\n", BTRFSCONVERT_REISERFS ? "yes" : "no");
> }
>
> int main(int argc, char *argv[])
> diff --git a/convert/source-reiserfs.c b/convert/source-reiserfs.c
> new file mode 100644
> index 0000000..2d9d4bc
> --- /dev/null
> +++ b/convert/source-reiserfs.c
> @@ -0,0 +1,1011 @@
> +/*
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License v2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with this program; if not, write to the
> + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
> + * Boston, MA 021110-1307, USA.
> + */
> +
> +#if BTRFSCONVERT_REISERFS
> +
> +#include "kerncompat.h"
> +#include <linux/limits.h>
> +#include <linux/fs.h>
> +#include <limits.h>
> +#include <sys/stat.h>
> +#include "disk-io.h"
> +#include "transaction.h"
> +#include "utils.h"
> +#include "bitops.h"
> +#include "convert/common.h"
> +#include "convert/source-reiserfs.h"
> +
> +static inline u8 mode_to_file_type(u32 mode)
> +{
> + switch (mode & S_IFMT) {
> + case S_IFREG: return BTRFS_FT_REG_FILE;
> + case S_IFDIR: return BTRFS_FT_DIR;
> + case S_IFCHR: return BTRFS_FT_CHRDEV;
> + case S_IFBLK: return BTRFS_FT_BLKDEV;
> + case S_IFIFO: return BTRFS_FT_FIFO;
> + case S_IFSOCK: return BTRFS_FT_SOCK;
> + case S_IFLNK: return BTRFS_FT_SYMLINK;
> + };
> +
> + return BTRFS_FT_UNKNOWN;
> +}
> +
> +
> +struct reiserfs_convert_info {
> + int privroot_found;
> + struct reiserfs_key privroot_key;
> + struct reiserfs_key xattr_key;
> + int copy_attrs;
> +
> + struct task_ctx *progress;
> +
> + /* used to track hardlinks */
> + unsigned used_slots;
> + unsigned alloced_slots;
> + u64 *objectids;
> +};
> +
> +static u32 reiserfs_count_objectids(reiserfs_filsys_t fs)
> +{
> + struct reiserfs_super_block *sb = fs->fs_ondisk_sb;
> + u32 count = 0;
> + u32 *map;
> + int i;
> +
> + if (fs->fs_format == REISERFS_FORMAT_3_6)
> + map = (u32 *) (sb + 1);
> + else
> + map = (u32 *)((struct reiserfs_super_block_v1 *)sb + 1);
> +
> + for (i = 0; i < get_sb_oid_cursize(sb); i += 2)
> + count += le32_to_cpu(map[i + 1]) - (le32_to_cpu(map[i]) + 1);
> +
> + return count;
> +}
> +
> +
> +static int reiserfs_open_fs(struct btrfs_convert_context *cxt, const char *name)
> +{
> + struct reiserfs_convert_info *info;
> + reiserfs_filsys_t fs;
> + long error;
> +
> + fs = reiserfs_open(name, O_RDONLY, &error, NULL, 0);
> + if (!fs)
> + return -1;
> +
> + error = reiserfs_open_ondisk_bitmap(fs);
> + if (error) {
> + reiserfs_close(fs);
> + return -1;
> + }
> +
> + cxt->fs_data = fs;
> + cxt->blocksize = fs->fs_blocksize;
> + cxt->block_count = get_sb_block_count(fs->fs_ondisk_sb);
> + cxt->total_bytes = cxt->blocksize * cxt->block_count;
> + cxt->volume_name = strndup(fs->fs_ondisk_sb->s_label, 16);
> + cxt->first_data_block = 0;
> + cxt->inodes_count = reiserfs_count_objectids(fs);
> + cxt->free_inodes_count = 0;
> + info = calloc(1, sizeof(*info));
> + if (!info) {
> + reiserfs_close(fs);
> + return -1;
> + }
> +
> + /*
> + * Inode attributes are somewhat of a hack on reiserfs and it was
> + * once possible to have garbage in the flags field. A superblock
> + * field now indicates that the field has been cleared and can
> + * be considered valid, but only on v3.6 format file systems.
> + */
> + if (fs->fs_format == REISERFS_FORMAT_3_6 &&
> + get_sb_v2_flag(fs->fs_ondisk_sb, reiserfs_attrs_cleared))
> + info->copy_attrs = 1;
> +
> + fs->fs_vp = info;
> + return 0;
> +}
> +
> +#if 0
Whoops. This will be removed as part of the next submission after review.
-Jeff
> +static int reiserfs_alloc_block(struct btrfs_convert_context *cxt, u64 goal,
> + u64 *block_ret)
> +{
> + int ret;
> + reiserfs_filsys_t fs = cxt->fs_data;
> + unsigned long block = goal;
> +
> + ret = reiserfs_bitmap_find_zero_bit(fs->fs_bitmap2, &block);
> +
> + if (ret != 0)
> + return -1;
> +
> + reiserfs_bitmap_set_bit(fs->fs_bitmap2, block);
> +
> + *block_ret = block;
> + return 0;
> +}
> +
> +static void bc_reiserfs_free_block(struct btrfs_convert_context *cxt, u64 block)
> +{
> + reiserfs_filsys_t fs = cxt->fs_data;
> + reiserfs_bitmap_clear_bit(fs->fs_bitmap2, block);
> +}
> +
> +static int reiserfs_test_block(struct btrfs_convert_context *cxt, u64 block64)
> +{
> + reiserfs_filsys_t fs = cxt->fs_data;
> + u32 block = block64;
> +
> + BUG_ON(block != block64);
> + return reiserfs_bitmap_test_bit(fs->fs_bitmap2, block);
> +}
> +#endif
> +
> +static void reiserfs_close_fs(struct btrfs_convert_context *cxt)
> +{
> + reiserfs_filsys_t fs = cxt->fs_data;
> + struct reiserfs_convert_info *info = fs->fs_vp;
> +
> + if (info) {
> + if (info->objectids)
> + free(info->objectids);
> + free(info);
> + fs->fs_vp = NULL;
> + }
> +
> + /* We don't want changes to be persistent */
> + fs->fs_bitmap2->bm_dirty = 0;
> +
> + reiserfs_close(fs);
> +}
> +
> +static int compare_objectids(const void *p1, const void *p2)
> +{
> + u64 v1 = *(u64 *)p1;
> + u64 v2 = *(u64 *)p2;
> +
> + if (v1 > v2)
> + return 1;
> + else if (v1 < v2)
> + return -1;
> + return 0;
> +}
> +
> +static int lookup_cached_objectid(reiserfs_filsys_t fs, u64 objectid)
> +{
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + u64 *result;
> +
> + if (!info->objectids)
> + return 0;
> + result = bsearch(&objectid, info->objectids, info->used_slots,
> + sizeof(u64), compare_objectids);
> + return result != NULL;
> +}
> +
> +static int insert_cached_objectid(reiserfs_filsys_t fs, u64 objectid)
> +{
> + struct reiserfs_convert_info *info = fs->fs_vp;
> +
> + if (info->used_slots + 1 >= info->alloced_slots) {
> + u64 *objectids = realloc(info->objectids,
> + (info->alloced_slots + 1000) * sizeof(u64));
> + if (!objectids)
> + return -ENOMEM;
> + info->objectids = objectids;
> + info->alloced_slots += 1000;
> + }
> + info->objectids[info->used_slots++] = objectid;
> +
> + qsort(info->objectids, info->used_slots, sizeof(u64),
> + compare_objectids);
> + return 0;
> +}
> +
> +static int reiserfs_locate_privroot(reiserfs_filsys_t fs)
> +{
> + int err;
> + unsigned generation;
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + struct reiserfs_key key = root_dir_key;
> +
> + err = reiserfs_find_entry(fs, &key, ".reiserfs_priv",
> + &generation, &info->privroot_key);
> + if (err == 1) {
> + err = reiserfs_find_entry(fs, &info->privroot_key, "xattrs",
> + &generation, &info->xattr_key);
> + if (err != 1)
> + memset(&info->xattr_key, 0, sizeof(info->xattr_key));
> + }
> +
> + return 0;
> +}
> +
> +static void reiserfs_convert_inode_flags(struct btrfs_inode_item *inode,
> + const struct stat_data *sd)
> +{
> + u16 attrs = sd_v2_sd_attrs(sd);
> + u64 new_flags = 0;
> +
> + if (attrs & FS_IMMUTABLE_FL)
> + new_flags |= BTRFS_INODE_IMMUTABLE;
> +
> + if (attrs & FS_APPEND_FL)
> + new_flags |= BTRFS_INODE_APPEND;
> +
> + if (attrs & FS_SYNC_FL)
> + new_flags |= BTRFS_INODE_SYNC;
> +
> + if (attrs & FS_NOATIME_FL)
> + new_flags |= BTRFS_INODE_NOATIME;
> +
> + if (attrs & FS_NODUMP_FL)
> + new_flags |= BTRFS_INODE_NODUMP;
> +
> + if (attrs & FS_NODUMP_FL)
> + new_flags |= BTRFS_INODE_NODUMP;
> +
> + btrfs_set_stack_inode_flags(inode, new_flags);
> +
> +}
> +
> +static void reiserfs_copy_inode_item(struct btrfs_inode_item *inode,
> + struct item_head *ih, void *stat_data,
> + int copy_inode_flags)
> +{
> + u32 mode;
> + u32 rdev = 0;
> +
> + memset(inode, 0, sizeof(*inode));
> + btrfs_set_stack_inode_generation(inode, 1);
> + if (get_ih_key_format(ih) == KEY_FORMAT_1) {
> + struct stat_data_v1 *sd = stat_data;
> +
> + mode = sd_v1_mode(sd);
> + btrfs_set_stack_inode_size(inode, sd_v1_size(sd));
> + btrfs_set_stack_inode_nlink(inode, sd_v1_nlink(sd));
> + btrfs_set_stack_inode_uid(inode, sd_v1_uid(sd));
> + btrfs_set_stack_inode_gid(inode, sd_v1_gid(sd));
> + btrfs_set_stack_timespec_sec(&inode->atime, sd_v1_atime(sd));
> + btrfs_set_stack_timespec_sec(&inode->ctime, sd_v1_ctime(sd));
> + btrfs_set_stack_timespec_sec(&inode->mtime, sd_v1_mtime(sd));
> +
> + if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
> + rdev = new_decode_dev(sd_v1_rdev(sd));
> + } else {
> + struct stat_data *sd = stat_data;
> +
> + mode = sd_v2_mode(sd);
> + btrfs_set_stack_inode_size(inode, sd_v2_size(sd));
> + btrfs_set_stack_inode_nlink(inode, sd_v2_nlink(sd));
> + btrfs_set_stack_inode_uid(inode, sd_v2_uid(sd));
> + btrfs_set_stack_inode_gid(inode, sd_v2_gid(sd));
> + btrfs_set_stack_timespec_sec(&inode->atime, sd_v2_atime(sd));
> + btrfs_set_stack_timespec_sec(&inode->ctime, sd_v2_ctime(sd));
> + btrfs_set_stack_timespec_sec(&inode->mtime, sd_v2_mtime(sd));
> +
> + if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
> + rdev = new_decode_dev(sd_v2_rdev(sd));
> +
> + if (copy_inode_flags)
> + reiserfs_convert_inode_flags(inode, sd);
> +
> + }
> + if (S_ISDIR(mode)) {
> + btrfs_set_stack_inode_size(inode, 0);
> + btrfs_set_stack_inode_nlink(inode, 1);
> + }
> + btrfs_set_stack_inode_mode(inode, mode);
> + btrfs_set_stack_inode_rdev(inode, rdev);
> +
> +}
> +
> +struct reiserfs_blk_iterate_data {
> + struct blk_iterate_data blk_data;
> + int indirect;
> + char *inline_data;
> + u64 inline_offset;
> + u32 inline_length;
> +};
> +
> +static void init_reiserfs_blk_iterate_data(
> + struct reiserfs_blk_iterate_data *data,
> + struct btrfs_trans_handle *trans,
> + struct btrfs_root *root,
> + struct btrfs_inode_item *inode,
> + u64 objectid, u32 convert_flags)
> +{
> + init_blk_iterate_data(&data->blk_data, trans, root, inode, objectid,
> + convert_flags & CONVERT_FLAG_DATACSUM);
> + data->indirect = 0;
> + data->inline_data = NULL;
> + data->inline_offset = (u64)-1;
> + data->inline_length = 0;
> +}
> +
> +static int reiserfs_record_indirect_extent(reiserfs_filsys_t fs, u64 position,
> + u64 size, int num_ptrs,
> + u32 *ptrs, void *data)
> +{
> + struct reiserfs_blk_iterate_data *bdata = data;
> + u32 file_block = position / fs->fs_blocksize;
> + int i;
> + int ret = 0;
> +
> + bdata->indirect = 1;
> +
> + for (i = 0; i < num_ptrs; i++, file_block++) {
> + u32 block = d32_get(ptrs, i);
> +
> + if (!block)
> + continue;
> +
> + ret = block_iterate_proc(block, file_block, &bdata->blk_data);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int reiserfs_record_direct_extent(reiserfs_filsys_t fs, __u64 position,
> + __u64 size, const char *body,
> + size_t len, void *data)
> +{
> + struct reiserfs_blk_iterate_data *bdata = data;
> + char *inline_data;
> +
> + if (bdata->inline_offset == (u64)-1)
> + bdata->inline_offset = position;
> +
> + inline_data = realloc(bdata->inline_data, bdata->inline_length + len);
> + if (!inline_data)
> + return -ENOMEM;
> + bdata->inline_data = inline_data;
> +
> + memcpy(bdata->inline_data + bdata->inline_length, body, len);
> + bdata->inline_length += len;
> +
> + return 0;
> +}
> +
> +static int convert_direct(struct btrfs_trans_handle *trans,
> + struct btrfs_root *root, u64 objectid,
> + struct btrfs_inode_item *inode, const char *body,
> + u32 length, u64 offset, u32 convert_flags)
> +{
> + struct btrfs_key key;
> + u32 sectorsize = root->sectorsize;
> + int ret;
> + struct extent_buffer *eb;
> +
> + BUG_ON(length > sectorsize);
> + ret = btrfs_reserve_extent(trans, root, sectorsize,
> + 0, 0, -1ULL, &key, 1);
> + if (ret)
> + return ret;
> +
> + eb = alloc_extent_buffer(&root->fs_info->extent_cache, key.objectid,
> + sectorsize);
> +
> + if (!eb)
> + return -ENOMEM;
> +
> + write_extent_buffer(eb, body, 0, length);
> + ret = write_and_map_eb(root, eb);
> + free_extent_buffer(eb);
> + if (ret)
> + return ret;
> +
> + return btrfs_record_file_extent(trans, root, objectid, inode, offset,
> + key.objectid, sectorsize);
> +}
> +
> +static int reiserfs_record_file_extents(reiserfs_filsys_t fs,
> + struct btrfs_trans_handle *trans,
> + struct btrfs_root *root,
> + u64 objectid,
> + struct btrfs_inode_item *inode,
> + struct reiserfs_key *sd_key,
> + u32 convert_flags)
> +
> +{
> + int ret;
> + u32 last_block;
> + u32 sectorsize = root->sectorsize;
> + u64 inode_size = btrfs_stack_inode_size(inode);
> + struct reiserfs_blk_iterate_data data;
> +
> + init_reiserfs_blk_iterate_data(&data, trans, root, inode,
> + objectid, convert_flags);
> +
> + ret = reiserfs_iterate_file_data(fs, sd_key,
> + reiserfs_record_indirect_extent,
> + reiserfs_record_direct_extent, &data);
> + if (ret)
> + return ret;
> +
> + if (data.indirect && data.blk_data.num_blocks) {
> + ret = record_file_blocks(&data.blk_data,
> + data.blk_data.first_block,
> + data.blk_data.disk_block,
> + data.blk_data.num_blocks);
> + if (ret)
> + goto fail;
> + }
> +
> + data.blk_data.first_block += data.blk_data.num_blocks;
> + last_block = (inode_size + sectorsize - 1) / sectorsize;
> + if (last_block > data.blk_data.first_block) {
> + ret = record_file_blocks(&data.blk_data,
> + data.blk_data.first_block, 0,
> + last_block - data.blk_data.first_block);
> + if (ret)
> + goto fail;
> + }
> +
> + if (data.inline_length) {
> + if (data.inline_length < BTRFS_MAX_INLINE_DATA_SIZE(root)) {
> + int isize;
> + ret = btrfs_insert_inline_extent(trans, root,
> + objectid,
> + data.inline_offset,
> + data.inline_data,
> + data.inline_length);
> + if (ret)
> + goto fail;
> +
> + isize = btrfs_stack_inode_nbytes(inode);
> + btrfs_set_stack_inode_nbytes(inode,
> + isize + data.inline_length);
> + } else {
> + ret = convert_direct(trans, root, objectid, inode,
> + data.inline_data,
> + data.inline_length,
> + data.inline_offset, convert_flags);
> + if (ret)
> + goto fail;
> + }
> + }
> +
> + ret = 0;
> +fail:
> + return ret;
> +}
> +
> +#define OID_OFFSET (BTRFS_FIRST_FREE_OBJECTID - REISERFS_ROOT_OBJECTID)
> +static int reiserfs_copy_meta(reiserfs_filsys_t fs, struct btrfs_root *root,
> + u32 convert_flags, u32 deh_dirid,
> + u32 deh_objectid, u8 *type);
> +
> +struct reiserfs_dirent_data {
> + u64 index;
> + u32 convert_flags;
> + struct btrfs_inode_item *inode;
> + struct btrfs_root *root;
> +};
> +
> +static int reiserfs_copy_dirent(reiserfs_filsys_t fs,
> + const struct reiserfs_key *dir_short_key,
> + const char *name, size_t len,
> + __u32 deh_dirid, __u32 deh_objectid,
> + void *cb_data)
> +{
> + int ret;
> + u8 type;
> + struct btrfs_trans_handle *trans;
> + u64 objectid = deh_objectid + OID_OFFSET;
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + struct reiserfs_dirent_data *dirent_data = cb_data;
> + struct btrfs_root *root = dirent_data->root;
> + __u32 dir_objectid = get_key_objectid(dir_short_key) + OID_OFFSET;
> +
> + /*
> + * These are the extended attributes and shouldn't appear as files
> + * in the converted file systems.
> + */
> + if (deh_objectid == get_key_objectid(&info->privroot_key))
> + return 0;
> +
> + ret = reiserfs_copy_meta(fs, root, dirent_data->convert_flags,
> + deh_dirid, deh_objectid, &type);
> + if (ret)
> + return ret;
> + trans = btrfs_start_transaction(root, 1);
> + if (!trans)
> + return -ENOMEM;
> +
> + ret = convert_insert_dirent(trans, root, name, len, dir_objectid,
> + objectid, type, dirent_data->index++,
> + dirent_data->inode);
> + return btrfs_commit_transaction(trans, root);
> +}
> +
> +static int reiserfs_copy_symlink(struct btrfs_trans_handle *trans,
> + struct btrfs_root *root, u64 objectid,
> + struct btrfs_inode_item *btrfs_inode,
> + reiserfs_filsys_t fs,
> + struct reiserfs_path *sd_path)
> +{
> + INITIALIZE_REISERFS_PATH(path);
> + struct item_head *ih = tp_item_head(sd_path);
> + struct reiserfs_key key = ih->ih_key;
> + int ret;
> + char *symlink;
> + int len;
> +
> + set_key_uniqueness(&key, type2uniqueness(TYPE_DIRECT));
> + set_key_offset_v1(&key, 1);
> +
> + ret = reiserfs_search_by_key_3(fs, &key, &path);
> + if (ret != ITEM_FOUND) {
> + ret = -ENOENT;
> + goto fail;
> + }
> +
> + symlink = tp_item_body(&path);
> + len = get_ih_item_len(tp_item_head(&path));
> +
> + ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
> + symlink, len + 1);
> + btrfs_set_stack_inode_nbytes(btrfs_inode, len + 1);
> +fail:
> + pathrelse(&path);
> + return ret;
> +}
> +
> +static int reiserfs_copy_meta(reiserfs_filsys_t fs, struct btrfs_root *root,
> + u32 convert_flags, u32 deh_dirid,
> + u32 deh_objectid, u8 *type)
> +{
> + INITIALIZE_REISERFS_PATH(path);
> + int ret = 0;
> + struct item_head *ih;
> + struct reiserfs_key key;
> + struct btrfs_inode_item btrfs_inode;
> + struct btrfs_trans_handle *trans = NULL;
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + u32 mode;
> + u64 objectid = deh_objectid + OID_OFFSET;
> + u64 parent = deh_dirid + OID_OFFSET;
> + struct reiserfs_dirent_data dirent_data = {
> + .index = 2,
> + .convert_flags = convert_flags,
> + .inode = &btrfs_inode,
> + .root = root,
> + };
> +
> + /* The root directory's dirid in reiserfs points to an object
> + * that does't exist. In btrfs it's self-referential.
> + */
> + if (deh_dirid == REISERFS_ROOT_PARENT_OBJECTID)
> + parent = objectid;
> +
> + set_key_dirid(&key, deh_dirid);
> + set_key_objectid(&key, deh_objectid);
> + set_key_offset_v2(&key, 0);
> + set_key_type_v2(&key, TYPE_STAT_DATA);
> +
> + ret = reiserfs_search_by_key_3(fs, &key, &path);
> + if (ret != ITEM_FOUND) {
> + ret = -ENOENT;
> + goto fail;
> + }
> +
> + ih = tp_item_head(&path);
> + if (!is_stat_data_ih(ih)) {
> + ret = -EINVAL;
> + goto fail;
> + }
> +
> + reiserfs_copy_inode_item(&btrfs_inode, ih, tp_item_body(&path),
> + info->copy_attrs);
> + mode = btrfs_stack_inode_mode(&btrfs_inode);
> + *type = mode_to_file_type(mode);
> +
> + if (S_ISREG(mode)) {
> + /* Inodes with hardlinks should only be inserted once */
> + if (btrfs_stack_inode_nlink(&btrfs_inode) > 1) {
> + if (lookup_cached_objectid(fs, deh_objectid)) {
> + ret = 0;
> + goto fail; /* Not a failure */
> + }
> + ret = insert_cached_objectid(fs, deh_objectid);
> + if (ret)
> + goto fail;
> + }
> +
> + }
> +
> + if (!(convert_flags & CONVERT_FLAG_DATACSUM)) {
> + u32 flags = btrfs_stack_inode_flags(&btrfs_inode) |
> + BTRFS_INODE_NODATASUM;
> + btrfs_set_stack_inode_flags(&btrfs_inode, flags);
> + }
> +
> + switch (mode & S_IFMT) {
> + case S_IFREG:
> + trans = btrfs_start_transaction(root, 1);
> + if (!trans) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> + ret = reiserfs_record_file_extents(fs, trans, root, objectid,
> + &btrfs_inode, &ih->ih_key,
> + convert_flags);
> + if (ret)
> + goto fail;
> + break;
> + case S_IFDIR:
> + ret = reiserfs_iterate_dir(fs, &ih->ih_key,
> + reiserfs_copy_dirent, &dirent_data);
> + if (ret)
> + goto fail;
> + trans = btrfs_start_transaction(root, 1);
> + if (!trans) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> +
> + ret = btrfs_insert_inode_ref(trans, root, "..", 2, parent,
> + objectid, 0);
> + break;
> + case S_IFLNK:
> + trans = btrfs_start_transaction(root, 1);
> + if (!trans) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> + ret = reiserfs_copy_symlink(trans, root, objectid,
> + &btrfs_inode, fs, &path);
> + if (ret)
> + goto fail;
> + break;
> + default:
> + trans = btrfs_start_transaction(root, 1);
> + if (!trans) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> + }
> +
> + ret = btrfs_insert_inode(trans, root, objectid, &btrfs_inode);
> + if (ret)
> + goto fail;
> + ret = btrfs_commit_transaction(trans, root);
> + info->progress->cur_copy_inodes++;
> +
> +fail:
> + pathrelse(&path);
> + return ret;
> +}
> +
> +struct reiserfs_xattr_data {
> + struct btrfs_root *root;
> + struct btrfs_trans_handle *trans;
> + u64 target_oid;
> + const char *name;
> + size_t namelen;
> + void *body;
> + size_t len;
> +};
> +
> +static int reiserfs_xattr_indirect_fn(reiserfs_filsys_t fs, u64 position,
> + u64 size, int num_blocks,
> + u32 *blocks, void *data)
> +{
> + int i;
> + struct reiserfs_xattr_data *xa_data = data;
> + size_t alloc = min(position + num_blocks * fs->fs_blocksize, size);
> + char *body;
> +
> + if (size > BTRFS_LEAF_DATA_SIZE(xa_data->root) -
> + sizeof(struct btrfs_item) - sizeof(struct btrfs_dir_item)) {
> + fprintf(stderr, "skip large xattr on objectid %llu name %.*s\n",
> + xa_data->target_oid, (int)xa_data->namelen,
> + xa_data->name);
> + return -E2BIG;
> + }
> +
> + body = realloc(xa_data->body, alloc);
> + if (!body)
> + return -ENOMEM;
> +
> + xa_data->body = body;
> + xa_data->len = alloc;
> +
> + for (i = 0; i < num_blocks; i++) {
> + int ret;
> + u32 block = d32_get(blocks, i);
> + u64 offset = (u64)block * fs->fs_blocksize;
> + size_t chunk = min_t(u64, size - position, fs->fs_blocksize);
> + char *buffer = xa_data->body + position;
> + ret = read_disk_extent(xa_data->root, offset, chunk, buffer);
> + if (ret)
> + return ret;
> + position += chunk;
> + }
> +
> + return 0;
> +}
> +
> +static int reiserfs_xattr_direct_fn(reiserfs_filsys_t fs, __u64 position,
> + __u64 size, const char *body, size_t len,
> + void *data)
> +{
> + struct reiserfs_xattr_data *xa_data = data;
> + char *newbody;
> +
> + if (size > BTRFS_LEAF_DATA_SIZE(xa_data->root) -
> + sizeof(struct btrfs_item) - sizeof(struct btrfs_dir_item)) {
> + fprintf(stderr, "skip large xattr on objectid %llu name %.*s\n",
> + xa_data->target_oid, (int)xa_data->namelen,
> + xa_data->name);
> + return -E2BIG;
> + }
> +
> + newbody = realloc(xa_data->body, position + len);
> + if (!newbody)
> + return -ENOMEM;
> + xa_data->body = newbody;
> + xa_data->len = position + len;
> + memcpy(xa_data->body + position, body, len);
> + return 0;
> +}
> +
> +static int reiserfs_acl_to_xattr(void *dst, const void *src,
> + size_t dst_size, size_t src_size)
> +{
> + int i, count;
> + const void *end = src + src_size;
> + acl_ea_header *ext_acl = (acl_ea_header *)dst;
> + acl_ea_entry *dst_entry = ext_acl->a_entries;
> + struct reiserfs_acl_entry *src_entry;
> +
> + if (src_size < sizeof(struct reiserfs_acl_header))
> + goto fail;
> + if (((struct reiserfs_acl_header *)src)->a_version !=
> + cpu_to_le32(REISERFS_ACL_VERSION))
> + goto fail;
> + src += sizeof(struct reiserfs_acl_header);
> + count = reiserfs_acl_count(src_size);
> + if (count <= 0)
> + goto fail;
> +
> + BUG_ON(dst_size < acl_ea_size(count));
> + ext_acl->a_version = cpu_to_le32(ACL_EA_VERSION);
> + for (i = 0; i < count; i++, dst_entry++) {
> + src_entry = (struct reiserfs_acl_entry *)src;
> + if (src + sizeof(struct reiserfs_acl_entry_short) > end)
> + goto fail;
> + dst_entry->e_tag = src_entry->e_tag;
> + dst_entry->e_perm = src_entry->e_perm;
> + switch (le16_to_cpu(src_entry->e_tag)) {
> + case ACL_USER_OBJ:
> + case ACL_GROUP_OBJ:
> + case ACL_MASK:
> + case ACL_OTHER:
> + src += sizeof(struct reiserfs_acl_entry_short);
> + dst_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
> + break;
> + case ACL_USER:
> + case ACL_GROUP:
> + src += sizeof(struct reiserfs_acl_entry);
> + if (src > end)
> + goto fail;
> + dst_entry->e_id = src_entry->e_id;
> + break;
> + default:
> + goto fail;
> + }
> + }
> + if (src != end)
> + goto fail;
> + return 0;
> +fail:
> + return -EINVAL;
> +}
> +
> +static int reiserfs_copy_one_xattr(reiserfs_filsys_t fs,
> + const struct reiserfs_key *dir_short_key,
> + const char *name, size_t namelen,
> + __u32 deh_dirid,
> + __u32 deh_objectid, void *cb_data)
> +{
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + struct reiserfs_xattr_data *xa_data = cb_data;
> + struct reiserfs_key key = {
> + .k2_dir_id = deh_dirid,
> + .k2_objectid = deh_objectid,
> + };
> + void *body = NULL;
> + int len;
> + int ret;
> +
> + xa_data->name = name;
> + xa_data->namelen = namelen;
> +
> + ret = reiserfs_iterate_file_data(fs, &key, reiserfs_xattr_indirect_fn,
> + reiserfs_xattr_direct_fn, cb_data);
> + if (ret)
> + goto out;
> +
> + if (!reiserfs_check_xattr(xa_data->body, xa_data->len)) {
> + fprintf(stderr,
> + "skip corrupted xattr on objectid %u name %.*s\n",
> + deh_objectid, (int)xa_data->namelen,
> + xa_data->name);
> + goto out;
> + }
> +
> + body = xa_data->body + sizeof(struct reiserfs_xattr_header);
> + len = xa_data->len - sizeof(struct reiserfs_xattr_header);
> +
> + if (!strncmp("system.posix_acl_default", name, namelen) ||
> + !strncmp("system.posix_acl_access", name, namelen)) {
> + size_t bufsize = acl_ea_size(ext2_acl_count(len));
> + char *databuf = malloc(bufsize);
> + if (!databuf)
> + goto out;
> + ret = reiserfs_acl_to_xattr(databuf, body, bufsize, len);
> + if (ret)
> + goto out;
> + body = databuf;
> + len = bufsize;
> + }
> +
> + ret = btrfs_insert_xattr_item(xa_data->trans, xa_data->root,
> + name, namelen, body, len,
> + xa_data->target_oid);
> +
> + info->progress->cur_copy_inodes++;
> +out:
> + if (body &&
> + body != xa_data->body + sizeof(struct reiserfs_xattr_header))
> + free(body);
> + if (xa_data->body)
> + free(xa_data->body);
> + xa_data->body = NULL;
> + xa_data->len = 0;
> +
> + return ret;
> +}
> +
> +static int reiserfs_copy_xattr_dir(reiserfs_filsys_t fs,
> + const struct reiserfs_key *dir_short_key,
> + const char *name, size_t len,
> + __u32 deh_dirid, __u32 deh_objectid,
> + void *cb_data)
> +{
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + struct reiserfs_xattr_data *xa_data = cb_data;
> + struct reiserfs_key dir_key = {
> + .k2_dir_id = deh_dirid,
> + .k2_objectid = deh_objectid,
> + };
> + int ret, err;
> +
> + errno = 0;
> + xa_data->target_oid = strtoull(name, NULL, 16);
> + if (xa_data->target_oid == ULLONG_MAX && errno)
> + return -errno;
> +
> + xa_data->target_oid += OID_OFFSET;
> +
> + xa_data->trans = btrfs_start_transaction(xa_data->root, 1);
> + if (!xa_data->trans)
> + return -ENOMEM;
> +
> + ret = reiserfs_iterate_dir(fs, &dir_key,
> + reiserfs_copy_one_xattr, xa_data);
> +
> + err = btrfs_commit_transaction(xa_data->trans, xa_data->root);
> + info->progress->cur_copy_inodes++;
> + xa_data->trans = NULL;
> + return ret ?: err;
> +}
> +
> +static int reiserfs_copy_xattrs(reiserfs_filsys_t fs, struct btrfs_root *root)
> +{
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + struct reiserfs_xattr_data data = {
> + .root = root,
> + };
> +
> + if (info->xattr_key.k2_objectid == 0)
> + return 0;
> +
> + return reiserfs_iterate_dir(fs, &info->xattr_key,
> + reiserfs_copy_xattr_dir, &data);
> +}
> +
> +static int reiserfs_copy_inodes(struct btrfs_convert_context *cxt,
> + struct btrfs_root *root,
> + u32 convert_flags,
> + struct task_ctx *p)
> +{
> + reiserfs_filsys_t fs = cxt->fs_data;
> + struct reiserfs_convert_info *info = fs->fs_vp;
> + int ret;
> + u8 type;
> +
> + info->progress = p;
> +
> + ret = reiserfs_locate_privroot(fs);
> + if (ret)
> + goto out;
> +
> + ret = reiserfs_copy_meta(fs, root, convert_flags,
> + REISERFS_ROOT_PARENT_OBJECTID,
> + REISERFS_ROOT_OBJECTID, &type);
> + if (ret)
> + goto out;
> +
> + if (convert_flags & CONVERT_FLAG_XATTR)
> + ret = reiserfs_copy_xattrs(fs, root);
> +
> +out:
> + info->progress = NULL;
> + return ret;
> +}
> +
> +static int read_used_space(struct btrfs_convert_context *cxt)
> +{
> + reiserfs_filsys_t fs = cxt->fs_data;
> + u64 start, end = 0;
> + unsigned int size = get_sb_block_count(fs->fs_ondisk_sb);
> + unsigned long *bitmap = (unsigned long *)fs->fs_bitmap2->bm_map;
> + int ret = 0;
> +
> + /* We have the entire bitmap loaded so we can just ping pong with
> + * ffz and ffs
> + */
> +
> + while (end < size) {
> + u64 offset, length;
> + start = find_next_bit(bitmap, size, end);
> + if (start >= size)
> + break;
> + end = find_next_zero_bit(bitmap, size, start);
> + if (end > size)
> + end = size;
> + offset = start * fs->fs_blocksize;
> + length = (end - start) * fs->fs_blocksize;
> + ret = add_merge_cache_extent(&cxt->used_space, offset, length);
> + if (ret < 0)
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int reiserfs_check_state(struct btrfs_convert_context *cxt)
> +{
> + return 0;
> +}
> +
> +const struct btrfs_convert_operations reiserfs_convert_ops = {
> + .name = "reiserfs",
> + .open_fs = reiserfs_open_fs,
> + .read_used_space = read_used_space,
> + .copy_inodes = reiserfs_copy_inodes,
> + .close_fs = reiserfs_close_fs,
> + .check_state = reiserfs_check_state,
> +};
> +
> +#endif /* BTRFSCONVERT_REISERFS */
> diff --git a/convert/source-reiserfs.h b/convert/source-reiserfs.h
> new file mode 100644
> index 0000000..f6cdf78
> --- /dev/null
> +++ b/convert/source-reiserfs.h
> @@ -0,0 +1,105 @@
> +/*
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License v2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with this program; if not, write to the
> + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
> + * Boston, MA 021110-1307, USA.
> + */
> +
> +#ifndef __BTRFS_CONVERT_SOURCE_REISERFS_H__
> +#define __BTRFS_CONVERT_SOURCE_REISERFS_H__
> +
> +#if BTRFSCONVERT_REISERFS
> +
> +#include "kerncompat.h"
> +#include <reiserfs/misc.h>
> +#include <reiserfs/io.h>
> +#include <reiserfs/reiserfs_lib.h>
> +#include <reiserfs/reiserfs_fs.h>
> +#include <linux/kdev_t.h>
> +#include "convert/source-fs.h"
> +
> +#define REISERFS_ACL_VERSION 0x0001
> +
> +/* 23.2.5 acl_tag_t values */
> +
> +#define ACL_UNDEFINED_TAG (0x00)
> +#define ACL_USER_OBJ (0x01)
> +#define ACL_USER (0x02)
> +#define ACL_GROUP_OBJ (0x04)
> +#define ACL_GROUP (0x08)
> +#define ACL_MASK (0x10)
> +#define ACL_OTHER (0x20)
> +
> +/* 23.2.7 ACL qualifier constants */
> +
> +#define ACL_UNDEFINED_ID ((id_t)-1)
> +
> +typedef struct {
> + __le16 e_tag;
> + __le16 e_perm;
> + __le32 e_id;
> +} ext2_acl_entry;
> +
> +typedef struct {
> + __le16 e_tag;
> + __le16 e_perm;
> +} ext2_acl_entry_short;
> +
> +typedef struct {
> + __le32 a_version;
> +} ext2_acl_header;
> +
> +#define ACL_EA_VERSION 0x0002
> +
> +typedef struct {
> + __le16 e_tag;
> + __le16 e_perm;
> + __le32 e_id;
> +} acl_ea_entry;
> +
> +typedef struct {
> + __le32 a_version;
> + acl_ea_entry a_entries[0];
> +} acl_ea_header;
> +
> +static inline int ext2_acl_count(size_t size)
> +{
> + ssize_t s;
> + size -= sizeof(ext2_acl_header);
> + s = size - 4 * sizeof(ext2_acl_entry_short);
> + if (s < 0) {
> + if (size % sizeof(ext2_acl_entry_short))
> + return -1;
> + return size / sizeof(ext2_acl_entry_short);
> + } else {
> + if (s % sizeof(ext2_acl_entry))
> + return -1;
> + return s / sizeof(ext2_acl_entry) + 4;
> + }
> +}
> +
> +
> +static inline size_t acl_ea_size(int count)
> +{
> + return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
> +}
> +
> +static inline dev_t new_decode_dev(u32 dev)
> +{
> + unsigned major = (dev & 0xfff00) >> 8;
> + unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
> +
> + return MKDEV(major, minor);
> +}
> +
> +#endif /* BTRFSCONVERT_REISERFS */
> +#endif
> diff --git a/tests/common.convert b/tests/common.convert
> index 8c9242e..6c525d1 100644
> --- a/tests/common.convert
> +++ b/tests/common.convert
> @@ -17,7 +17,7 @@ convert_test_preamble() {
> msg="$2"
> shift 3
> echo " [TEST/conv] $msg, btrfs" "${features:-defaults}"
> - echo "creating ext image with: $@" >> "$RESULTS"
> + echo "creating test image with: $@" >> "$RESULTS"
> }
>
> # prepare TEST_DEV before conversion, create filesystem and mount it, image
> @@ -29,10 +29,18 @@ convert_test_prep_fs() {
> run_check truncate -s 0 "$TEST_DEV"
> # 256MB is the smallest acceptable btrfs image.
> run_check truncate -s 512M "$TEST_DEV"
> - run_check "$@" -F "$TEST_DEV"
> + force=
> + mountopts=
> + case "$@" in
> + *mke2fs*)
> + force=-F ;;
> + *mkreiserfs*)
> + force=-ff; mountopts="-o acl,user_xattr,attrs" ;;
> + esac
> + run_check "$@" $force "$TEST_DEV"
>
> # create a file to check btrfs-convert can convert regular file correct
> - run_check_mount_test_dev
> + run_check_mount_test_dev $mountopts
>
> # create a file inside the fs before convert, to make sure there is
> # data covering btrfs backup superblock range (64M)
> diff --git a/tests/convert-tests/010-reiserfs-basic/test.sh b/tests/convert-tests/010-reiserfs-basic/test.sh
> new file mode 100755
> index 0000000..8f80965
> --- /dev/null
> +++ b/tests/convert-tests/010-reiserfs-basic/test.sh
> @@ -0,0 +1,16 @@
> +#!/bin/bash
> +
> +source "$TOP/tests/common"
> +source "$TOP/tests/common.convert"
> +
> +setup_root_helper
> +prepare_test_dev 512M
> +check_prereq btrfs-convert
> +
> +for feature in '' 'extref' 'skinny-metadata' 'no-holes'; do
> + convert_test "$feature" "reiserfs 4k nodesize" 4096 mkreiserfs -b 4096
> + convert_test "$feature" "reiserfs 8k nodesize" 8192 mkreiserfs -b 4096
> + convert_test "$feature" "reiserfs 16k nodesize" 16384 mkreiserfs -b 4096
> + convert_test "$feature" "reiserfs 32k nodesize" 32768 mkreiserfs -b 4096
> + convert_test "$feature" "reiserfs 64k nodesize" 65536 mkreiserfs -b 4096
> +done
> diff --git a/tests/convert-tests/011-reiserfs-delete-all-rollback/test.sh b/tests/convert-tests/011-reiserfs-delete-all-rollback/test.sh
> new file mode 100755
> index 0000000..d7e7ed6
> --- /dev/null
> +++ b/tests/convert-tests/011-reiserfs-delete-all-rollback/test.sh
> @@ -0,0 +1,67 @@
> +#!/bin/bash
> +# create a base image, convert to btrfs, remove all files, rollback the reiserfs image
> +
> +source "$TOP/tests/common"
> +source "$TOP/tests/common.convert"
> +
> +setup_root_helper
> +prepare_test_dev 512M
> +check_prereq btrfs-convert
> +
> +# simple wrapper for a convert test
> +# $1: btrfs features, argument to -O
> +# $2: message
> +# $3: nodesize value
> +# $4 + rest: command to create the reiserfs image
> +do_test() {
> + local features
> + local msg
> + local nodesize
> + local CHECKSUMTMP
> + local here
> +
> + features="$1"
> + msg="$2"
> + nodesize="$3"
> + shift 3
> + convert_test_preamble "$features" "$msg" "$nodesize" "$@"
> + convert_test_prep_fs "$@"
> + populate_fs
> + CHECKSUMTMP=$(mktemp --tmpdir btrfs-progs-convert.XXXXXXXXXX)
> + convert_test_gen_checksums "$CHECKSUMTMP"
> +
> + run_check_umount_test_dev
> +
> + convert_test_do_convert "$features" "$nodesize"
> +
> + run_check_mount_test_dev
> + convert_test_post_check_checksums "$CHECKSUMTMP"
> +
> + here=$(pwd)
> + cd "$TEST_MNT" || _fail "cannot cd to TEST_MNT"
> + # reiserfs_saved/image must not be deleted
> + run_mayfail $SUDO_HELPER find "$TEST_MNT"/ -mindepth 1 -path '*reiserfs_saved' -prune -o -exec rm -vrf "{}" \;
> + cd "$here"
> + run_check "$TOP/btrfs" filesystem sync "$TEST_MNT"
> + run_check_umount_test_dev
> + convert_test_post_rollback
> +
> + run_check_mount_test_dev
> + convert_test_post_check_checksums "$CHECKSUMTMP"
> + run_check_umount_test_dev
> +
> + # mount again and verify checksums
> + run_check_mount_test_dev
> + convert_test_post_check_checksums "$CHECKSUMTMP"
> + run_check_umount_test_dev
> +
> + rm "$CHECKSUMTMP"
> +}
> +
> +for feature in '' 'extref' 'skinny-metadata' 'no-holes'; do
> + do_test "$feature" "reiserfs 4k nodesize" 4096 mkreiserfs -b 4096
> + do_test "$feature" "reiserfs 8k nodesize" 8192 mkreiserfs -b 4096
> + do_test "$feature" "reiserfs 16k nodesize" 16384 mkreiserfs -b 4096
> + do_test "$feature" "reiserfs 32k nodesize" 32768 mkreiserfs -b 4096
> + do_test "$feature" "reiserfs 64k nodesize" 65536 mkreiserfs -b 4096
> +done
> diff --git a/tests/convert-tests/012-reiserfs-large-hole-extent/test.sh b/tests/convert-tests/012-reiserfs-large-hole-extent/test.sh
> new file mode 100755
> index 0000000..90cd514
> --- /dev/null
> +++ b/tests/convert-tests/012-reiserfs-large-hole-extent/test.sh
> @@ -0,0 +1,23 @@
> +#!/bin/bash
> +# Create a base image with large hole extent, then convert to btrfs,
> +# check the converted image.
> +# Check if btrfs-convert can handle such large hole.
> +# Fast pinpoint regression test. No options combination nor checksum
> +# verification
> +
> +source "$TOP/tests/common"
> +source "$TOP/tests/common.convert"
> +
> +setup_root_helper
> +prepare_test_dev 512M
> +check_prereq btrfs-convert
> +
> +default_mkfs="mkreiserfs -b 4096"
> +convert_test_preamble '' 'large hole extent test' 16k "$default_mkfs"
> +convert_test_prep_fs $default_mkfs
> +
> +run_check $SUDO_HELPER dd if=/dev/zero of="$TEST_MNT/file" bs=1M \
> + count=1 seek=1024 > /dev/null 2>&1
> +
> +run_check_umount_test_dev
> +convert_test_do_convert
> diff --git a/tests/convert-tests/013-reiserfs-common-inode-flags/test.sh b/tests/convert-tests/013-reiserfs-common-inode-flags/test.sh
> new file mode 100755
> index 0000000..b3948b3
> --- /dev/null
> +++ b/tests/convert-tests/013-reiserfs-common-inode-flags/test.sh
> @@ -0,0 +1,35 @@
> +#!/bin/bash
> +# Check if btrfs-convert can copy common inode flags like SYNC/IMMUTABLE
> +
> +source "$TOP/tests/common"
> +source "$TOP/tests/common.convert"
> +
> +setup_root_helper
> +prepare_test_dev 512M
> +check_prereq btrfs-convert
> +
> +fail=0
> +default_mkfs="mkreiserfs -b 4096"
> +convert_test_preamble '' 'common inode flags test' 16k "$default_mkfs"
> +convert_test_prep_fs $default_mkfs
> +
> +# create file with specific flags
> +run_check $SUDO_HELPER touch "$TEST_MNT/flag_test"
> +run_check $SUDO_HELPER chattr +aAdSi "$TEST_MNT/flag_test"
> +run_check lsattr "$TEST_MNT/flag_test"
> +
> +run_check_umount_test_dev
> +convert_test_do_convert
> +run_check_mount_test_dev
> +
> +# Log the status
> +run_check lsattr "$TEST_MNT/flag_test"
> +# Above flags should be copied to btrfs flags, and lsattr should get them
> +run_check_stdout lsattr "$TEST_MNT/flag_test" | cut -f1 -d\ | grep "[aAdiS]" -q
> +if [ $? -ne 0 ]; then
> + rm tmp_output
> + _fail "no common inode flags are copied after convert"
> +fi
> +
> +run_check_umount_test_dev
> +convert_test_post_rollback
>
--
Jeff Mahoney
SUSE Labs
Attachment:
signature.asc
Description: OpenPGP digital signature
