root->root_key.objectid = objectid;
}
-static int update_cowonly_root(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- int ret;
- u64 old_root_bytenr;
- struct btrfs_root *tree_root = root->fs_info->tree_root;
-
- btrfs_write_dirty_block_groups(trans, root);
- while(1) {
- old_root_bytenr = btrfs_root_bytenr(&root->root_item);
- if (old_root_bytenr == root->node->start)
- break;
- btrfs_set_root_bytenr(&root->root_item,
- root->node->start);
- btrfs_set_root_generation(&root->root_item,
- trans->transid);
- root->root_item.level = btrfs_header_level(root->node);
- ret = btrfs_update_root(trans, tree_root,
- &root->root_key,
- &root->root_item);
- BUG_ON(ret);
- btrfs_write_dirty_block_groups(trans, root);
- }
- return 0;
-}
-
-static int commit_tree_roots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
-{
- struct btrfs_root *root;
- struct list_head *next;
- struct extent_buffer *eb;
- int ret;
-
- if (fs_info->readonly)
- return 0;
-
- eb = fs_info->tree_root->node;
- extent_buffer_get(eb);
- ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
- free_extent_buffer(eb);
- if (ret)
- return ret;
-
- while(!list_empty(&fs_info->dirty_cowonly_roots)) {
- next = fs_info->dirty_cowonly_roots.next;
- list_del_init(next);
- root = list_entry(next, struct btrfs_root, dirty_list);
- update_cowonly_root(trans, root);
- free_extent_buffer(root->commit_root);
- root->commit_root = NULL;
- }
-
- return 0;
-}
-
-static int __commit_transaction(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- u64 start;
- u64 end;
- struct btrfs_fs_info *fs_info = root->fs_info;
- struct extent_buffer *eb;
- struct extent_io_tree *tree = &fs_info->extent_cache;
- int ret;
-
- while(1) {
- ret = find_first_extent_bit(tree, 0, &start, &end,
- EXTENT_DIRTY);
- if (ret)
- break;
- while(start <= end) {
- eb = find_first_extent_buffer(tree, start);
- BUG_ON(!eb || eb->start != start);
- ret = write_tree_block(trans, fs_info, eb);
- BUG_ON(ret);
- start += eb->len;
- clear_extent_buffer_dirty(eb);
- free_extent_buffer(eb);
- }
- }
- return 0;
-}
-
-int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- u64 transid = trans->transid;
- int ret = 0;
- struct btrfs_fs_info *fs_info = root->fs_info;
-
- if (root->commit_root == root->node)
- goto commit_tree;
- if (root == root->fs_info->tree_root)
- goto commit_tree;
- if (root == root->fs_info->chunk_root)
- goto commit_tree;
-
- free_extent_buffer(root->commit_root);
- root->commit_root = NULL;
-
- btrfs_set_root_bytenr(&root->root_item, root->node->start);
- btrfs_set_root_generation(&root->root_item, trans->transid);
- root->root_item.level = btrfs_header_level(root->node);
- ret = btrfs_update_root(trans, root->fs_info->tree_root,
- &root->root_key, &root->root_item);
- BUG_ON(ret);
-commit_tree:
- ret = commit_tree_roots(trans, fs_info);
- BUG_ON(ret);
- ret = __commit_transaction(trans, root);
- BUG_ON(ret);
- write_ctree_super(trans, fs_info);
- btrfs_finish_extent_commit(trans, fs_info->extent_root,
- &fs_info->pinned_extents);
- kfree(trans);
- free_extent_buffer(root->commit_root);
- root->commit_root = NULL;
- fs_info->running_transaction = NULL;
- fs_info->last_trans_committed = transid;
- return 0;
-}
-
static int find_and_setup_root(struct btrfs_root *tree_root,
struct btrfs_fs_info *fs_info,
u64 objectid, struct btrfs_root *root)
ret = stat(filename, &st);
if (ret < 0) {
- error("cannot stat '%s': %s", filename, strerror(errno));
+ error("cannot stat '%s': %m", filename);
return NULL;
}
if (!(((st.st_mode & S_IFMT) == S_IFREG) || ((st.st_mode & S_IFMT) == S_IFBLK))) {
fp = open(filename, oflags);
if (fp < 0) {
- error("cannot open '%s': %s", filename, strerror(errno));
+ error("cannot open '%s': %m", filename);
return NULL;
}
info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
return -EIO;
}
+/*
+ * btrfs_read_dev_super - read a valid superblock from a block device
+ * @fd: file descriptor of the device
+ * @sb: buffer where the superblock is going to be read in
+ * @sb_bytenr: offset of the particular superblock copy we want
+ * @sbflags: flags controlling how the superblock is read
+ *
+ * This function is used by various btrfs comands to obtain a valid superblock.
+ *
+ * It's mode of operation is controlled by the @sb_bytenr and @sbdflags
+ * parameters. If SBREAD_RECOVER flag is set and @sb_bytenr is
+ * BTRFS_SUPER_INFO_OFFSET then the function reads all 3 superblock copies and
+ * returns the newest one. If SBREAD_RECOVER is not set then only a single
+ * copy is read, which one is decided by @sb_bytenr. If @sb_bytenr !=
+ * BTRFS_SUPER_INFO_OFFSET then the @sbflags is effectively ignored and only a
+ * single copy is read.
+ */
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
unsigned sbflags)
{
if (ret > 0)
fprintf(stderr, "WARNING: failed to write all sb data\n");
else
- fprintf(stderr, "WARNING: failed to write sb: %s\n",
- strerror(errno));
+ fprintf(stderr, "WARNING: failed to write sb: %m\n");
return ret;
}
int write_all_supers(struct btrfs_fs_info *fs_info)
{
- struct list_head *cur;
struct list_head *head = &fs_info->fs_devices->devices;
struct btrfs_device *dev;
struct btrfs_super_block *sb;
sb = fs_info->super_copy;
dev_item = &sb->dev_item;
- list_for_each(cur, head) {
- dev = list_entry(cur, struct btrfs_device, dev_list);
+ list_for_each_entry(dev, head, dev_list) {
if (!dev->writeable)
continue;
int close_ctree_fs_info(struct btrfs_fs_info *fs_info)
{
int ret;
+ int err = 0;
struct btrfs_trans_handle *trans;
struct btrfs_root *root = fs_info->tree_root;
fs_info->generation) {
BUG_ON(!root);
trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ err = PTR_ERR(trans);
+ goto skip_commit;
+ }
btrfs_commit_transaction(trans, root);
trans = btrfs_start_transaction(root, 1);
+ BUG_ON(IS_ERR(trans));
ret = commit_tree_roots(trans, fs_info);
BUG_ON(ret);
ret = __commit_transaction(trans, root);
fprintf(stderr,
"failed to write new super block err %d\n", ret);
}
+
+skip_commit:
btrfs_free_block_groups(fs_info);
free_fs_roots_tree(&fs_info->fs_root_tree);
ret = btrfs_close_devices(fs_info->fs_devices);
btrfs_cleanup_all_caches(fs_info);
btrfs_free_fs_info(fs_info);
- return ret;
+ if (!err)
+ err = ret;
+ return err;
}
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,