struct btrfs_root *root, int datacsum,
int packing, int noxattr, struct task_ctx *p);
void (*close_fs)(struct btrfs_convert_context *cctx);
+ int (*check_state)(struct btrfs_convert_context *cctx);
};
static void init_convert_context(struct btrfs_convert_context *cctx)
cctx->convert_ops->close_fs(cctx);
}
+static inline int convert_check_state(struct btrfs_convert_context *cctx)
+{
+ return cctx->convert_ops->check_state(cctx);
+}
+
static int intersect_with_sb(u64 bytenr, u64 num_bytes)
{
int i;
int ret = 0;
struct btrfs_root *root = data->root;
struct btrfs_root *convert_root = data->convert_root;
- struct btrfs_path *path;
+ struct btrfs_path path;
u64 file_pos = file_block * root->sectorsize;
u64 old_disk_bytenr = disk_block * root->sectorsize;
u64 num_bytes = num_blocks * root->sectorsize;
data->objectid, data->inode, file_pos, 0,
num_bytes);
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
+ btrfs_init_path(&path);
/*
* Search real disk bytenr from convert root
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = cur_off;
- ret = btrfs_search_slot(NULL, convert_root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
if (ret < 0)
break;
if (ret > 0) {
- ret = btrfs_previous_item(convert_root, path,
+ ret = btrfs_previous_item(convert_root, &path,
data->convert_ino,
BTRFS_EXTENT_DATA_KEY);
if (ret < 0)
break;
}
}
- node = path->nodes[0];
- slot = path->slots[0];
+ node = path.nodes[0];
+ slot = path.slots[0];
btrfs_item_key_to_cpu(node, &key, slot);
BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
key.objectid != data->convert_ino ||
extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
extent_num_bytes = btrfs_file_extent_disk_num_bytes(node, fi);
BUG_ON(cur_off - key.offset >= extent_num_bytes);
- btrfs_release_path(path);
+ btrfs_release_path(&path);
if (extent_disk_bytenr)
real_disk_bytenr = cur_off - key.offset +
* need to waste CPU cycles now.
*/
}
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return ret;
}
int i;
int ret;
- BUG_ON(bytenr != round_down(bytenr, root->sectorsize));
- BUG_ON(len != round_down(len, root->sectorsize));
+ if (bytenr != round_down(bytenr, root->sectorsize)) {
+ error("bytenr not sectorsize aligned: %llu",
+ (unsigned long long)bytenr);
+ return -EINVAL;
+ }
+ if (len != round_down(len, root->sectorsize)) {
+ error("length not sectorsize aligned: %llu",
+ (unsigned long long)len);
+ return -EINVAL;
+ }
len = min_t(u64, len, BTRFS_MAX_EXTENT_SIZE);
/*
bg_cache->key.offset - bytenr);
}
- BUG_ON(len != round_down(len, root->sectorsize));
+ if (len != round_down(len, root->sectorsize)) {
+ error("remaining length not sectorsize aligned: %llu",
+ (unsigned long long)len);
+ return -EINVAL;
+ }
ret = btrfs_record_file_extent(trans, root, ino, inode, bytenr,
disk_bytenr, len);
if (ret < 0)
{
struct btrfs_inode_item buf;
struct btrfs_trans_handle *trans;
- struct btrfs_path *path = NULL;
+ struct btrfs_path path;
struct btrfs_key key;
struct cache_extent *cache;
struct cache_tree used_tmp;
return -ENOMEM;
cache_tree_init(&used_tmp);
+ btrfs_init_path(&path);
ret = btrfs_find_free_objectid(trans, root, BTRFS_FIRST_FREE_OBJECTID,
&ino);
if (ret < 0)
goto out;
- path = btrfs_alloc_path();
- if (!path) {
- ret = -ENOMEM;
- goto out;
- }
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
if (ret) {
ret = (ret > 0 ? -ENOENT : ret);
goto out;
}
- read_extent_buffer(path->nodes[0], &buf,
- btrfs_item_ptr_offset(path->nodes[0], path->slots[0]),
+ read_extent_buffer(path.nodes[0], &buf,
+ btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
sizeof(buf));
- btrfs_release_path(path);
+ btrfs_release_path(&path);
/*
* Create a new used space cache, which doesn't contain the reserved
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
if (ret) {
ret = (ret > 0 ? -ENOENT : ret);
goto out;
}
btrfs_set_stack_inode_size(&buf, cfg->num_bytes);
- write_extent_buffer(path->nodes[0], &buf,
- btrfs_item_ptr_offset(path->nodes[0], path->slots[0]),
+ write_extent_buffer(path.nodes[0], &buf,
+ btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
sizeof(buf));
out:
free_extent_cache_tree(&used_tmp);
- btrfs_free_path(path);
+ btrfs_release_path(&path);
btrfs_commit_transaction(trans, root);
return ret;
}
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *new_root = NULL;
- struct btrfs_path *path;
+ struct btrfs_path path;
struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf;
struct btrfs_key key;
if (len == 0 || len > BTRFS_NAME_LEN)
return NULL;
- path = btrfs_alloc_path();
- if (!path)
- return NULL;
-
+ btrfs_init_path(&path);
key.objectid = dirid;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = (u64)-1;
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret <= 0) {
error("search for DIR_INDEX dirid %llu failed: %d",
(unsigned long long)dirid, ret);
goto fail;
}
- if (path->slots[0] > 0) {
- path->slots[0]--;
- btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (path.slots[0] > 0) {
+ path.slots[0]--;
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
if (key.objectid == dirid && key.type == BTRFS_DIR_INDEX_KEY)
index = key.offset + 1;
}
- btrfs_release_path(path);
+ btrfs_release_path(&path);
trans = btrfs_start_transaction(root, 1);
if (!trans) {
key.offset = 0;
key.type = BTRFS_INODE_ITEM_KEY;
- ret = btrfs_lookup_inode(trans, root, path, &key, 1);
+ ret = btrfs_lookup_inode(trans, root, &path, &key, 1);
if (ret) {
error("search for INODE_ITEM %llu failed: %d",
(unsigned long long)dirid, ret);
goto fail;
}
- leaf = path->nodes[0];
- inode_item = btrfs_item_ptr(leaf, path->slots[0],
+ leaf = path.nodes[0];
+ inode_item = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_inode_item);
key.objectid = root_objectid;
btrfs_set_inode_size(leaf, inode_item, len * 2 +
btrfs_inode_size(leaf, inode_item));
btrfs_mark_buffer_dirty(leaf);
- btrfs_release_path(path);
+ btrfs_release_path(&path);
/* add the backref first */
ret = btrfs_add_root_ref(trans, tree_root, root_objectid,
new_root = NULL;
}
fail:
- btrfs_free_path(path);
+ btrfs_init_path(&path);
return new_root;
}
if (!(ext2_fs->super->s_feature_incompat &
EXT2_FEATURE_INCOMPAT_FILETYPE)) {
- fprintf(stderr, "filetype feature is missing\n");
+ error("filetype feature is missing");
goto fail;
}
}
memset(&dst->reserved, 0, sizeof(dst->reserved));
}
+static int ext2_check_state(struct btrfs_convert_context *cctx)
+{
+ ext2_filsys fs = cctx->fs_data;
+
+ if (!(fs->super->s_state & EXT2_VALID_FS))
+ return 1;
+ else if (fs->super->s_state & EXT2_ERROR_FS)
+ return 1;
+ else
+ return 0;
+}
+
+/* EXT2_*_FL to BTRFS_INODE_FLAG_* stringification helper */
+#define COPY_ONE_EXT2_FLAG(flags, ext2_inode, name) ({ \
+ if (ext2_inode->i_flags & EXT2_##name##_FL) \
+ flags |= BTRFS_INODE_##name; \
+})
+
+/*
+ * Convert EXT2_*_FL to corresponding BTRFS_INODE_* flags
+ *
+ * Only a subset of EXT_*_FL is supported in btrfs.
+ */
+static void ext2_convert_inode_flags(struct btrfs_inode_item *dst,
+ struct ext2_inode *src)
+{
+ u64 flags = 0;
+
+ COPY_ONE_EXT2_FLAG(flags, src, APPEND);
+ COPY_ONE_EXT2_FLAG(flags, src, SYNC);
+ COPY_ONE_EXT2_FLAG(flags, src, IMMUTABLE);
+ COPY_ONE_EXT2_FLAG(flags, src, NODUMP);
+ COPY_ONE_EXT2_FLAG(flags, src, NOATIME);
+ COPY_ONE_EXT2_FLAG(flags, src, DIRSYNC);
+ btrfs_set_stack_inode_flags(dst, flags);
+}
/*
* copy a single inode. do all the required works, such as cloning
BTRFS_INODE_NODATASUM;
btrfs_set_stack_inode_flags(&btrfs_inode, flags);
}
+ ext2_convert_inode_flags(&btrfs_inode, ext2_inode);
switch (ext2_inode->i_mode & S_IFMT) {
case S_IFREG:
.read_used_space = ext2_read_used_space,
.copy_inodes = ext2_copy_inodes,
.close_fs = ext2_close_fs,
+ .check_state = ext2_check_state,
};
#endif
}
}
- fprintf(stderr, "No file system found to convert.\n");
+ error("no file system found to convert");
return -1;
}
ret = convert_open_fs(devname, &cctx);
if (ret)
goto fail;
+ ret = convert_check_state(&cctx);
+ if (ret)
+ warning(
+ "source filesystem is not clean, running filesystem check is recommended");
ret = convert_read_used_space(&cctx);
if (ret)
goto fail;
mkfs_cfg.stripesize = blocksize;
mkfs_cfg.features = features;
/* New convert need these space */
- mkfs_cfg.fs_uuid = malloc(BTRFS_UUID_UNPARSED_SIZE);
- mkfs_cfg.chunk_uuid = malloc(BTRFS_UUID_UNPARSED_SIZE);
- *(mkfs_cfg.fs_uuid) = '\0';
- *(mkfs_cfg.chunk_uuid) = '\0';
+ memset(mkfs_cfg.chunk_uuid, 0, BTRFS_UUID_UNPARSED_SIZE);
+ memset(mkfs_cfg.fs_uuid, 0, BTRFS_UUID_UNPARSED_SIZE);
ret = make_btrfs(fd, &mkfs_cfg, &cctx);
if (ret) {
num_stripes = multi->num_stripes;
physical = multi->stripes[0].physical;
- kfree(multi);
+ free(multi);
if (num_stripes != 1) {
error("num stripes for bytenr %llu is not 1", bytenr);
key.objectid = objectid;
key.offset = 0;
- btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
+ key.type = BTRFS_EXTENT_DATA_KEY;
ret = btrfs_search_slot(NULL, image_root, &key, &path, 0, 0);
if (ret != 0) {
error("unable to find first file extent: %d", ret);
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
if (key.objectid != objectid || key.offset != offset ||
- btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
+ key.type != BTRFS_EXTENT_DATA_KEY)
break;
fi = btrfs_item_ptr(leaf, path.slots[0],
/* force no allocation from system block group */
root->fs_info->system_allocs = -1;
trans = btrfs_start_transaction(root, 1);
- BUG_ON(!trans);
+ if (!trans) {
+ error("unable to start transaction");
+ goto fail;
+ }
/*
* recow the whole chunk tree, this will remove all chunk tree blocks
* from system block group
}
ret = btrfs_commit_transaction(trans, root);
- BUG_ON(ret);
+ if (ret) {
+ error("transaction commit failed: %d", ret);
+ goto fail;
+ }
ret = close_ctree(root);
if (ret) {
printf("\t-O|--features LIST comma separated list of filesystem features\n");
printf("\t--no-progress show only overview, not the detailed progress\n");
printf("\n");
- printf("Suported filesystems:\n");
+ printf("Supported filesystems:\n");
printf("\text2/3/4: %s\n", BTRFSCONVERT_EXT2 ? "yes" : "no");
}
case 'l':
copylabel = -1;
if (strlen(optarg) >= BTRFS_LABEL_SIZE) {
- fprintf(stderr,
- "WARNING: label too long, trimmed to %d bytes\n",
+ warning(
+ "label too long, trimmed to %d bytes",
BTRFS_LABEL_SIZE - 1);
}
__strncpy_null(fslabel, optarg, BTRFS_LABEL_SIZE - 1);
tmp = btrfs_parse_fs_features(tmp, &features);
if (tmp) {
- fprintf(stderr,
- "Unrecognized filesystem feature '%s'\n",
+ error("unrecognized filesystem feature: %s",
tmp);
free(orig);
exit(1);
btrfs_parse_features_to_string(buf,
features & ~BTRFS_CONVERT_ALLOWED_FEATURES);
- fprintf(stderr,
- "ERROR: features not allowed for convert: %s\n",
+ error("features not allowed for convert: %s",
buf);
exit(1);
}
file = argv[optind];
ret = check_mounted(file);
if (ret < 0) {
- fprintf(stderr, "Could not check mount status: %s\n",
- strerror(-ret));
+ error("could not check mount status: %s", strerror(-ret));
return 1;
} else if (ret) {
- fprintf(stderr, "%s is mounted\n", file);
+ error("%s is mounted", file);
return 1;
}