]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/disk-io.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[karo-tx-linux.git] / fs / btrfs / disk-io.c
index 20c49b16b759fc53c39f5c4a321f379f805f4b9e..62e0cafd6e250d5d1717656d3d5821e2d1bfec42 100644 (file)
@@ -407,7 +407,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
                        break;
        }
 
-       if (failed && !ret)
+       if (failed && !ret && failed_mirror)
                repair_eb_io_failure(root, eb, failed_mirror);
 
        return ret;
@@ -1114,7 +1114,7 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                                spin_unlock(&root->fs_info->delalloc_lock);
                                btrfs_panic(root->fs_info, -EOVERFLOW,
                                          "Can't clear %lu bytes from "
-                                         " dirty_mdatadata_bytes (%lu)",
+                                         " dirty_mdatadata_bytes (%llu)",
                                          buf->len,
                                          root->fs_info->dirty_metadata_bytes);
                        }
@@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->defrag_running = 0;
        root->root_key.objectid = objectid;
        root->anon_dev = 0;
+
+       spin_lock_init(&root->root_times_lock);
 }
 
 static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
@@ -1225,6 +1227,82 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
        return root;
 }
 
+struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
+                                    struct btrfs_fs_info *fs_info,
+                                    u64 objectid)
+{
+       struct extent_buffer *leaf;
+       struct btrfs_root *tree_root = fs_info->tree_root;
+       struct btrfs_root *root;
+       struct btrfs_key key;
+       int ret = 0;
+       u64 bytenr;
+
+       root = btrfs_alloc_root(fs_info);
+       if (!root)
+               return ERR_PTR(-ENOMEM);
+
+       __setup_root(tree_root->nodesize, tree_root->leafsize,
+                    tree_root->sectorsize, tree_root->stripesize,
+                    root, fs_info, objectid);
+       root->root_key.objectid = objectid;
+       root->root_key.type = BTRFS_ROOT_ITEM_KEY;
+       root->root_key.offset = 0;
+
+       leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
+                                     0, objectid, NULL, 0, 0, 0);
+       if (IS_ERR(leaf)) {
+               ret = PTR_ERR(leaf);
+               goto fail;
+       }
+
+       bytenr = leaf->start;
+       memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
+       btrfs_set_header_bytenr(leaf, leaf->start);
+       btrfs_set_header_generation(leaf, trans->transid);
+       btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
+       btrfs_set_header_owner(leaf, objectid);
+       root->node = leaf;
+
+       write_extent_buffer(leaf, fs_info->fsid,
+                           (unsigned long)btrfs_header_fsid(leaf),
+                           BTRFS_FSID_SIZE);
+       write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
+                           (unsigned long)btrfs_header_chunk_tree_uuid(leaf),
+                           BTRFS_UUID_SIZE);
+       btrfs_mark_buffer_dirty(leaf);
+
+       root->commit_root = btrfs_root_node(root);
+       root->track_dirty = 1;
+
+
+       root->root_item.flags = 0;
+       root->root_item.byte_limit = 0;
+       btrfs_set_root_bytenr(&root->root_item, leaf->start);
+       btrfs_set_root_generation(&root->root_item, trans->transid);
+       btrfs_set_root_level(&root->root_item, 0);
+       btrfs_set_root_refs(&root->root_item, 1);
+       btrfs_set_root_used(&root->root_item, leaf->len);
+       btrfs_set_root_last_snapshot(&root->root_item, 0);
+       btrfs_set_root_dirid(&root->root_item, 0);
+       root->root_item.drop_level = 0;
+
+       key.objectid = objectid;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       key.offset = 0;
+       ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item);
+       if (ret)
+               goto fail;
+
+       btrfs_tree_unlock(leaf);
+
+fail:
+       if (ret)
+               return ERR_PTR(ret);
+
+       return root;
+}
+
 static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info)
 {
@@ -1326,6 +1404,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
        u64 generation;
        u32 blocksize;
        int ret = 0;
+       int slot;
 
        root = btrfs_alloc_root(fs_info);
        if (!root)
@@ -1352,9 +1431,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
        ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
        if (ret == 0) {
                l = path->nodes[0];
-               read_extent_buffer(l, &root->root_item,
-                               btrfs_item_ptr_offset(l, path->slots[0]),
-                               sizeof(root->root_item));
+               slot = path->slots[0];
+               btrfs_read_root_item(tree_root, l, slot, &root->root_item);
                memcpy(&root->root_key, location, sizeof(*location));
        }
        btrfs_free_path(path);
@@ -1396,6 +1474,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
                return fs_info->dev_root;
        if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
                return fs_info->csum_root;
+       if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
+               return fs_info->quota_root ? fs_info->quota_root :
+                                            ERR_PTR(-ENOENT);
 again:
        spin_lock(&fs_info->fs_roots_radix_lock);
        root = radix_tree_lookup(&fs_info->fs_roots_radix,
@@ -1820,6 +1901,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
        free_extent_buffer(info->extent_root->commit_root);
        free_extent_buffer(info->csum_root->node);
        free_extent_buffer(info->csum_root->commit_root);
+       if (info->quota_root) {
+               free_extent_buffer(info->quota_root->node);
+               free_extent_buffer(info->quota_root->commit_root);
+       }
 
        info->tree_root->node = NULL;
        info->tree_root->commit_root = NULL;
@@ -1829,6 +1914,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
        info->extent_root->commit_root = NULL;
        info->csum_root->node = NULL;
        info->csum_root->commit_root = NULL;
+       if (info->quota_root) {
+               info->quota_root->node = NULL;
+               info->quota_root->commit_root = NULL;
+       }
 
        if (chunk_root) {
                free_extent_buffer(info->chunk_root->node);
@@ -1859,6 +1948,7 @@ int open_ctree(struct super_block *sb,
        struct btrfs_root *csum_root;
        struct btrfs_root *chunk_root;
        struct btrfs_root *dev_root;
+       struct btrfs_root *quota_root;
        struct btrfs_root *log_tree_root;
        int ret;
        int err = -EINVAL;
@@ -1870,9 +1960,10 @@ int open_ctree(struct super_block *sb,
        csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info);
        chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
        dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info);
+       quota_root = fs_info->quota_root = btrfs_alloc_root(fs_info);
 
        if (!tree_root || !extent_root || !csum_root ||
-           !chunk_root || !dev_root) {
+           !chunk_root || !dev_root || !quota_root) {
                err = -ENOMEM;
                goto fail;
        }
@@ -1941,6 +2032,8 @@ int open_ctree(struct super_block *sb,
        fs_info->free_chunk_space = 0;
        fs_info->tree_mod_log = RB_ROOT;
 
+       init_waitqueue_head(&fs_info->tree_mod_seq_wait);
+
        /* readahead state */
        INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
        spin_lock_init(&fs_info->reada_lock);
@@ -2029,6 +2122,13 @@ int open_ctree(struct super_block *sb,
        init_rwsem(&fs_info->cleanup_work_sem);
        init_rwsem(&fs_info->subvol_sem);
 
+       spin_lock_init(&fs_info->qgroup_lock);
+       fs_info->qgroup_tree = RB_ROOT;
+       INIT_LIST_HEAD(&fs_info->dirty_qgroups);
+       fs_info->qgroup_seq = 1;
+       fs_info->quota_enabled = 0;
+       fs_info->pending_quota_state = 0;
+
        btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
        btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
 
@@ -2241,7 +2341,7 @@ int open_ctree(struct super_block *sb,
        ret |= btrfs_start_workers(&fs_info->caching_workers);
        ret |= btrfs_start_workers(&fs_info->readahead_workers);
        if (ret) {
-               ret = -ENOMEM;
+               err = -ENOMEM;
                goto fail_sb_buffer;
        }
 
@@ -2353,6 +2453,17 @@ retry_root_backup:
                goto recovery_tree_root;
        csum_root->track_dirty = 1;
 
+       ret = find_and_setup_root(tree_root, fs_info,
+                                 BTRFS_QUOTA_TREE_OBJECTID, quota_root);
+       if (ret) {
+               kfree(quota_root);
+               quota_root = fs_info->quota_root = NULL;
+       } else {
+               quota_root->track_dirty = 1;
+               fs_info->quota_enabled = 1;
+               fs_info->pending_quota_state = 1;
+       }
+
        fs_info->generation = generation;
        fs_info->last_trans_committed = generation;
 
@@ -2412,6 +2523,9 @@ retry_root_backup:
                               " integrity check module %s\n", sb->s_id);
        }
 #endif
+       ret = btrfs_read_qgroup_config(fs_info);
+       if (ret)
+               goto fail_trans_kthread;
 
        /* do not make disk changes in broken FS */
        if (btrfs_super_log_root(disk_super) != 0 &&
@@ -2422,7 +2536,7 @@ retry_root_backup:
                        printk(KERN_WARNING "Btrfs log replay required "
                               "on RO media\n");
                        err = -EIO;
-                       goto fail_trans_kthread;
+                       goto fail_qgroup;
                }
                blocksize =
                     btrfs_level_size(tree_root,
@@ -2431,7 +2545,7 @@ retry_root_backup:
                log_tree_root = btrfs_alloc_root(fs_info);
                if (!log_tree_root) {
                        err = -ENOMEM;
-                       goto fail_trans_kthread;
+                       goto fail_qgroup;
                }
 
                __setup_root(nodesize, leafsize, sectorsize, stripesize,
@@ -2463,15 +2577,15 @@ retry_root_backup:
 
        if (!(sb->s_flags & MS_RDONLY)) {
                ret = btrfs_cleanup_fs_roots(fs_info);
-               if (ret) {
-                       }
+               if (ret)
+                       goto fail_trans_kthread;
 
                ret = btrfs_recover_relocation(tree_root);
                if (ret < 0) {
                        printk(KERN_WARNING
                               "btrfs: failed to recover relocation\n");
                        err = -EINVAL;
-                       goto fail_trans_kthread;
+                       goto fail_qgroup;
                }
        }
 
@@ -2481,10 +2595,10 @@ retry_root_backup:
 
        fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
        if (!fs_info->fs_root)
-               goto fail_trans_kthread;
+               goto fail_qgroup;
        if (IS_ERR(fs_info->fs_root)) {
                err = PTR_ERR(fs_info->fs_root);
-               goto fail_trans_kthread;
+               goto fail_qgroup;
        }
 
        if (sb->s_flags & MS_RDONLY)
@@ -2508,6 +2622,8 @@ retry_root_backup:
 
        return 0;
 
+fail_qgroup:
+       btrfs_free_qgroup_config(fs_info);
 fail_trans_kthread:
        kthread_stop(fs_info->transaction_kthread);
 fail_cleaner:
@@ -3106,6 +3222,8 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 2;
        smp_mb();
 
+       btrfs_free_qgroup_config(root->fs_info);
+
        if (fs_info->delalloc_bytes) {
                printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
                       (unsigned long long)fs_info->delalloc_bytes);
@@ -3125,6 +3243,10 @@ int close_ctree(struct btrfs_root *root)
        free_extent_buffer(fs_info->dev_root->commit_root);
        free_extent_buffer(fs_info->csum_root->node);
        free_extent_buffer(fs_info->csum_root->commit_root);
+       if (fs_info->quota_root) {
+               free_extent_buffer(fs_info->quota_root->node);
+               free_extent_buffer(fs_info->quota_root->commit_root);
+       }
 
        btrfs_free_block_groups(fs_info);
 
@@ -3255,7 +3377,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
        return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
 }
 
-static int btree_lock_page_hook(struct page *page, void *data,
+int btree_lock_page_hook(struct page *page, void *data,
                                void (*flush_fn)(void *))
 {
        struct inode *inode = page->mapping->host;