X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=disk-io.c;h=76958aef239e511c21e072c757c0f5e2e23aea59;hb=82a1442e9cd025436be8ae65e684fd6b2701efbb;hp=f969c9b5c27189c9a3197cda8e977f38758529f3;hpb=448999d84ddc2eaf36938176fb5091d2c2029e2f;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/disk-io.c b/disk-io.c index f969c9b..76958ae 100644 --- a/disk-io.c +++ b/disk-io.c @@ -481,129 +481,6 @@ void btrfs_setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, 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) @@ -1335,7 +1212,7 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename, 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))) { @@ -1348,7 +1225,7 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename, 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, @@ -1542,6 +1419,23 @@ error_out: 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) { @@ -1672,14 +1566,12 @@ write_err: 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; @@ -1689,8 +1581,7 @@ int write_all_supers(struct btrfs_fs_info *fs_info) 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; @@ -1746,6 +1637,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, 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; @@ -1753,7 +1645,10 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) fs_info->generation) { BUG_ON(!root); trans = btrfs_start_transaction(root, 1); - BUG_ON(IS_ERR(trans)); + 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)); @@ -1773,6 +1668,8 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) 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); @@ -1781,7 +1678,9 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) 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,