]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/btrfs/disk-io.c
Btrfs: get forced transaction commits via workqueue
[mv-sheeva.git] / fs / btrfs / disk-io.c
index 7aff6bb55d9138546f8e7ce5aa812733d4219670..751069c0e9f57318e38b696cbcd5ea1e4352bb2f 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/scatterlist.h>
 #include <linux/swap.h>
 #include <linux/radix-tree.h>
+#include <linux/writeback.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -94,9 +95,6 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr)
        } while (bh != head);
 out_unlock:
        unlock_page(page);
-       if (ret) {
-               touch_buffer(ret);
-       }
        page_cache_release(page);
        return ret;
 }
@@ -198,14 +196,14 @@ int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
        ret = crypto_hash_digest(&desc, &sg, 1, result);
        spin_unlock(&root->fs_info->hash_lock);
        if (ret) {
-               printk("sha256 digest failed\n");
+               printk("digest failed\n");
        }
        return ret;
 }
 static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
                           int verify)
 {
-       char result[BTRFS_CSUM_SIZE];
+       char result[BTRFS_CRC32_SIZE];
        int ret;
        struct btrfs_node *node;
 
@@ -214,14 +212,14 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
        if (ret)
                return ret;
        if (verify) {
-               if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) {
+               if (memcmp(bh->b_data, result, BTRFS_CRC32_SIZE)) {
                        printk("checksum verify failed on %Lu\n",
                               bh_blocknr(bh));
                        return 1;
                }
        } else {
                node = btrfs_buffer_node(bh);
-               memcpy(node->header.csum, result, BTRFS_CSUM_SIZE);
+               memcpy(node->header.csum, result, BTRFS_CRC32_SIZE);
        }
        return 0;
 }
@@ -256,6 +254,35 @@ static struct address_space_operations btree_aops = {
        .sync_page      = block_sync_page,
 };
 
+int readahead_tree_block(struct btrfs_root *root, u64 blocknr)
+{
+       struct buffer_head *bh = NULL;
+       int ret = 0;
+
+       bh = btrfs_find_create_tree_block(root, blocknr);
+       if (!bh)
+               return 0;
+       if (buffer_uptodate(bh)) {
+               ret = 1;
+               goto done;
+       }
+       if (test_set_buffer_locked(bh)) {
+               ret = 1;
+               goto done;
+       }
+       if (!buffer_uptodate(bh)) {
+               get_bh(bh);
+               bh->b_end_io = end_buffer_read_sync;
+               submit_bh(READ, bh);
+       } else {
+               unlock_buffer(bh);
+               ret = 1;
+       }
+done:
+       brelse(bh);
+       return ret;
+}
+
 struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
 {
        struct buffer_head *bh = NULL;
@@ -273,11 +300,14 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh))
                        goto fail;
-               csum_tree_block(root, bh, 1);
        } else {
                unlock_buffer(bh);
        }
 uptodate:
+       if (!buffer_checked(bh)) {
+               csum_tree_block(root, bh, 1);
+               set_buffer_checked(bh);
+       }
        if (check_tree_block(root, bh))
                BUG();
        return bh;
@@ -527,9 +557,13 @@ struct btrfs_root *open_ctree(struct super_block *sb)
 
        init_bit_radix(&fs_info->pinned_radix);
        init_bit_radix(&fs_info->pending_del_radix);
+       init_bit_radix(&fs_info->extent_map_radix);
        INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS);
        INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS);
+       INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL);
+       INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL);
        INIT_LIST_HEAD(&fs_info->trans_list);
+       INIT_LIST_HEAD(&fs_info->dead_roots);
        sb_set_blocksize(sb, 4096);
        fs_info->running_transaction = NULL;
        fs_info->tree_root = tree_root;
@@ -542,21 +576,24 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
        fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
        fs_info->do_barriers = 1;
+       fs_info->extent_tree_insert_nr = 0;
+       fs_info->extent_tree_prealloc_nr = 0;
+       fs_info->closing = 0;
+
+       INIT_DELAYED_WORK(&fs_info->trans_work, btrfs_transaction_cleaner);
        BTRFS_I(fs_info->btree_inode)->root = tree_root;
        memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
               sizeof(struct btrfs_key));
        insert_inode_hash(fs_info->btree_inode);
        mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
-       fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+       fs_info->hash_tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC);
        spin_lock_init(&fs_info->hash_lock);
        if (!fs_info->hash_tfm || IS_ERR(fs_info->hash_tfm)) {
-               printk("failed to allocate sha256 hash\n");
+               printk("failed to allocate digest hash\n");
                return NULL;
        }
        mutex_init(&fs_info->trans_mutex);
        mutex_init(&fs_info->fs_mutex);
-       memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert));
-       memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
 
        __setup_root(sb->s_blocksize, dev_root,
                     fs_info, BTRFS_DEV_TREE_OBJECTID);
@@ -612,11 +649,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
                                  BTRFS_EXTENT_TREE_OBJECTID, extent_root);
        BUG_ON(ret);
 
+       btrfs_read_block_groups(extent_root);
+
        fs_info->generation = btrfs_super_generation(disk_super) + 1;
-       memset(&fs_info->kobj, 0, sizeof(fs_info->kobj));
-       kobj_set_kset_s(fs_info, btrfs_subsys);
-       kobject_set_name(&fs_info->kobj, "%s", sb->s_id);
-       kobject_register(&fs_info->kobj);
        mutex_unlock(&fs_info->fs_mutex);
        return tree_root;
 }
@@ -666,7 +701,7 @@ static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
        return 0;
 }
 
-int del_fs_roots(struct btrfs_fs_info *fs_info)
+static int del_fs_roots(struct btrfs_fs_info *fs_info)
 {
        int ret;
        struct btrfs_root *gang[8];
@@ -714,6 +749,8 @@ int close_ctree(struct btrfs_root *root)
        struct btrfs_trans_handle *trans;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
+       fs_info->closing = 1;
+       btrfs_transaction_flush_work(root);
        mutex_lock(&fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
        btrfs_commit_transaction(trans, root);
@@ -740,10 +777,10 @@ int close_ctree(struct btrfs_root *root)
        iput(fs_info->btree_inode);
 
        free_dev_radix(fs_info);
+       btrfs_free_block_groups(root->fs_info);
        del_fs_roots(fs_info);
        kfree(fs_info->extent_root);
        kfree(fs_info->tree_root);
-       kobject_unregister(&fs_info->kobj);
        return 0;
 }
 
@@ -752,3 +789,7 @@ void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
        brelse(buf);
 }
 
+void btrfs_btree_balance_dirty(struct btrfs_root *root)
+{
+       balance_dirty_pages_ratelimited(root->fs_info->btree_inode->i_mapping);
+}