Merge branch 'fix' of git://github.com/ycmiao/pxa-linux into fixes
[pandora-kernel.git] / fs / btrfs / disk-io.c
index 23b6776..62afe5c 100644 (file)
@@ -366,7 +366,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
        clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
        io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree;
        while (1) {
-               ret = read_extent_buffer_pages(io_tree, eb, start, 1,
+               ret = read_extent_buffer_pages(io_tree, eb, start,
+                                              WAIT_COMPLETE,
                                               btree_get_extent, mirror_num);
                if (!ret &&
                    !verify_parent_transid(io_tree, eb, parent_transid))
@@ -607,11 +608,48 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        end = min_t(u64, eb->len, PAGE_CACHE_SIZE);
        end = eb->start + end - 1;
 err:
+       if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
+               clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
+               btree_readahead_hook(root, eb, eb->start, ret);
+       }
+
        free_extent_buffer(eb);
 out:
        return ret;
 }
 
+static int btree_io_failed_hook(struct bio *failed_bio,
+                        struct page *page, u64 start, u64 end,
+                        u64 mirror_num, struct extent_state *state)
+{
+       struct extent_io_tree *tree;
+       unsigned long len;
+       struct extent_buffer *eb;
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+
+       tree = &BTRFS_I(page->mapping->host)->io_tree;
+       if (page->private == EXTENT_PAGE_PRIVATE)
+               goto out;
+       if (!page->private)
+               goto out;
+
+       len = page->private >> 2;
+       WARN_ON(len == 0);
+
+       eb = alloc_extent_buffer(tree, start, len, page);
+       if (eb == NULL)
+               goto out;
+
+       if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
+               clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
+               btree_readahead_hook(root, eb, eb->start, -EIO);
+       }
+       free_extent_buffer(eb);
+
+out:
+       return -EIO;    /* we fixed nothing */
+}
+
 static void end_workqueue_bio(struct bio *bio, int err)
 {
        struct end_io_wq *end_io_wq = bio->bi_private;
@@ -907,7 +945,7 @@ static int btree_readpage(struct file *file, struct page *page)
 {
        struct extent_io_tree *tree;
        tree = &BTRFS_I(page->mapping->host)->io_tree;
-       return extent_read_full_page(tree, page, btree_get_extent);
+       return extent_read_full_page(tree, page, btree_get_extent, 0);
 }
 
 static int btree_releasepage(struct page *page, gfp_t gfp_flags)
@@ -973,11 +1011,43 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
        if (!buf)
                return 0;
        read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
-                                buf, 0, 0, btree_get_extent, 0);
+                                buf, 0, WAIT_NONE, btree_get_extent, 0);
        free_extent_buffer(buf);
        return ret;
 }
 
+int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
+                        int mirror_num, struct extent_buffer **eb)
+{
+       struct extent_buffer *buf = NULL;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       struct extent_io_tree *io_tree = &BTRFS_I(btree_inode)->io_tree;
+       int ret;
+
+       buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
+       if (!buf)
+               return 0;
+
+       set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags);
+
+       ret = read_extent_buffer_pages(io_tree, buf, 0, WAIT_PAGE_LOCK,
+                                      btree_get_extent, mirror_num);
+       if (ret) {
+               free_extent_buffer(buf);
+               return ret;
+       }
+
+       if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) {
+               free_extent_buffer(buf);
+               return -EIO;
+       } else if (extent_buffer_uptodate(io_tree, buf, NULL)) {
+               *eb = buf;
+       } else {
+               free_extent_buffer(buf);
+       }
+       return 0;
+}
+
 struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize)
 {
@@ -1684,11 +1754,18 @@ static void backup_super_roots(struct btrfs_fs_info *info)
        btrfs_set_backup_extent_root_level(root_backup,
                               btrfs_header_level(info->extent_root->node));
 
-       btrfs_set_backup_fs_root(root_backup, info->fs_root->node->start);
-       btrfs_set_backup_fs_root_gen(root_backup,
+       /*
+        * we might commit during log recovery, which happens before we set
+        * the fs_root.  Make sure it is valid before we fill it in.
+        */
+       if (info->fs_root && info->fs_root->node) {
+               btrfs_set_backup_fs_root(root_backup,
+                                        info->fs_root->node->start);
+               btrfs_set_backup_fs_root_gen(root_backup,
                               btrfs_header_generation(info->fs_root->node));
-       btrfs_set_backup_fs_root_level(root_backup,
+               btrfs_set_backup_fs_root_level(root_backup,
                               btrfs_header_level(info->fs_root->node));
+       }
 
        btrfs_set_backup_dev_root(root_backup, info->dev_root->node->start);
        btrfs_set_backup_dev_root_gen(root_backup,
@@ -1813,31 +1890,32 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        u64 features;
        struct btrfs_key location;
        struct buffer_head *bh;
-       struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
-                                                GFP_NOFS);
-       struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
-                                                GFP_NOFS);
+       struct btrfs_super_block *disk_super;
        struct btrfs_root *tree_root = btrfs_sb(sb);
-       struct btrfs_fs_info *fs_info = NULL;
-       struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
-                                               GFP_NOFS);
-       struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
-                                             GFP_NOFS);
+       struct btrfs_fs_info *fs_info = tree_root->fs_info;
+       struct btrfs_root *extent_root;
+       struct btrfs_root *csum_root;
+       struct btrfs_root *chunk_root;
+       struct btrfs_root *dev_root;
        struct btrfs_root *log_tree_root;
-
        int ret;
        int err = -EINVAL;
        int num_backups_tried = 0;
        int backup_index = 0;
 
-       struct btrfs_super_block *disk_super;
+       extent_root = fs_info->extent_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       csum_root = fs_info->csum_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       chunk_root = fs_info->chunk_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       dev_root = fs_info->dev_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
 
-       if (!extent_root || !tree_root || !tree_root->fs_info ||
-           !chunk_root || !dev_root || !csum_root) {
+       if (!extent_root || !csum_root || !chunk_root || !dev_root) {
                err = -ENOMEM;
                goto fail;
        }
-       fs_info = tree_root->fs_info;
 
        ret = init_srcu_struct(&fs_info->subvol_srcu);
        if (ret) {
@@ -1877,12 +1955,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        mutex_init(&fs_info->reloc_mutex);
 
        init_completion(&fs_info->kobj_unregister);
-       fs_info->tree_root = tree_root;
-       fs_info->extent_root = extent_root;
-       fs_info->csum_root = csum_root;
-       fs_info->chunk_root = chunk_root;
-       fs_info->dev_root = dev_root;
-       fs_info->fs_devices = fs_devices;
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
        INIT_LIST_HEAD(&fs_info->space_info);
        btrfs_mapping_init(&fs_info->mapping_tree);
@@ -1904,6 +1976,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        fs_info->trans_no_join = 0;
        fs_info->free_chunk_space = 0;
 
+       /* readahead state */
+       INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
+       spin_lock_init(&fs_info->reada_lock);
+
        fs_info->thread_pool_size = min_t(unsigned long,
                                          num_online_cpus() + 2, 8);
 
@@ -1931,7 +2007,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        sb->s_bdi = &fs_info->bdi;
 
        fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID;
-       fs_info->btree_inode->i_nlink = 1;
+       set_nlink(fs_info->btree_inode, 1);
        /*
         * we set the i_size on the btree inode to the max possible int.
         * the real end of the address space is determined by all of
@@ -2103,6 +2179,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta",
                           fs_info->thread_pool_size,
                           &fs_info->generic_worker);
+       btrfs_init_workers(&fs_info->readahead_workers, "readahead",
+                          fs_info->thread_pool_size,
+                          &fs_info->generic_worker);
 
        /*
         * endios are largely parallel and should have a very
@@ -2113,6 +2192,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        fs_info->endio_write_workers.idle_thresh = 2;
        fs_info->endio_meta_write_workers.idle_thresh = 2;
+       fs_info->readahead_workers.idle_thresh = 2;
 
        btrfs_start_workers(&fs_info->workers, 1);
        btrfs_start_workers(&fs_info->generic_worker, 1);
@@ -2126,6 +2206,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
        btrfs_start_workers(&fs_info->delayed_workers, 1);
        btrfs_start_workers(&fs_info->caching_workers, 1);
+       btrfs_start_workers(&fs_info->readahead_workers, 1);
 
        fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
        fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2365,6 +2446,7 @@ fail_tree_roots:
 
 fail_sb_buffer:
        btrfs_stop_workers(&fs_info->generic_worker);
+       btrfs_stop_workers(&fs_info->readahead_workers);
        btrfs_stop_workers(&fs_info->fixup_workers);
        btrfs_stop_workers(&fs_info->delalloc_workers);
        btrfs_stop_workers(&fs_info->workers);
@@ -2378,21 +2460,20 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->caching_workers);
 fail_alloc:
 fail_iput:
+       btrfs_mapping_tree_free(&fs_info->mapping_tree);
+
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        iput(fs_info->btree_inode);
-
-       btrfs_close_devices(fs_info->fs_devices);
-       btrfs_mapping_tree_free(&fs_info->mapping_tree);
 fail_bdi:
        bdi_destroy(&fs_info->bdi);
 fail_srcu:
        cleanup_srcu_struct(&fs_info->subvol_srcu);
 fail:
+       btrfs_close_devices(fs_info->fs_devices);
        free_fs_info(fs_info);
        return ERR_PTR(err);
 
 recovery_tree_root:
-
        if (!btrfs_test_opt(tree_root, RECOVERY))
                goto fail_tree_roots;
 
@@ -2855,6 +2936,7 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->submit_workers);
        btrfs_stop_workers(&fs_info->delayed_workers);
        btrfs_stop_workers(&fs_info->caching_workers);
+       btrfs_stop_workers(&fs_info->readahead_workers);
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@ -3363,6 +3445,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
 static struct extent_io_ops btree_extent_io_ops = {
        .write_cache_pages_lock_hook = btree_lock_page_hook,
        .readpage_end_io_hook = btree_readpage_end_io_hook,
+       .readpage_io_failed_hook = btree_io_failed_hook,
        .submit_bio_hook = btree_submit_bio_hook,
        /* note we're sharing with inode.c for the merge bio hook */
        .merge_bio_hook = btrfs_merge_bio_hook,