Btrfs: Handle data checksumming on bios that span multiple ordered extents
authorChris Mason <chris.mason@oracle.com>
Fri, 18 Jul 2008 10:17:13 +0000 (06:17 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:05 +0000 (11:04 -0400)
Data checksumming is done right before the bio is sent down the IO stack,
which means a single bio might span more than one ordered extent.  In
this case, the checksumming data is split between two ordered extents.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/file-item.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h

index acbce542d291bb6c6f5c10922bf5b1dacbe12078..96ab2797c09a44a741a72b34ec05a1343d449a18 100644 (file)
@@ -1579,8 +1579,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, struct inode *inode,
                           struct btrfs_ordered_sum *sums);
-int btrfs_csum_one_bio(struct btrfs_root *root,
-                      struct bio *bio, struct btrfs_ordered_sum **sums_ret);
+int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
+                      struct bio *bio);
 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path,
index 345caf8ff516f5a7da85c15af667c480ce94ca64..e02f1e5acb0af8eee6281259cceab53908014985 100644 (file)
@@ -134,26 +134,53 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-int btrfs_csum_one_bio(struct btrfs_root *root,
-                      struct bio *bio, struct btrfs_ordered_sum **sums_ret)
+int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
+                      struct bio *bio)
 {
        struct btrfs_ordered_sum *sums;
        struct btrfs_sector_sum *sector_sum;
+       struct btrfs_ordered_extent *ordered;
        char *data;
        struct bio_vec *bvec = bio->bi_io_vec;
        int bio_index = 0;
+       unsigned long total_bytes = 0;
+       unsigned long this_sum_bytes = 0;
+       u64 offset;
 
        WARN_ON(bio->bi_vcnt <= 0);
        sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
        if (!sums)
                return -ENOMEM;
-       *sums_ret = sums;
+
        sector_sum = &sums->sums;
-       sums->file_offset = page_offset(bvec->bv_page);
+       sums->file_offset = page_offset(bvec->bv_page) + bvec->bv_offset;
        sums->len = bio->bi_size;
        INIT_LIST_HEAD(&sums->list);
+       ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset);
+       BUG_ON(!ordered);
 
        while(bio_index < bio->bi_vcnt) {
+               offset = page_offset(bvec->bv_page) + bvec->bv_offset;
+               if (offset >= ordered->file_offset + ordered->len) {
+                       unsigned long bytes_left;
+                       sums->len = this_sum_bytes;
+                       this_sum_bytes = 0;
+                       btrfs_add_ordered_sum(inode, ordered, sums);
+                       btrfs_put_ordered_extent(ordered);
+
+                       bytes_left = bio->bi_size - total_bytes;
+
+                       sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
+                                      GFP_NOFS);
+                       BUG_ON(!sums);
+                       sector_sum = &sums->sums;
+                       sums->len = bytes_left;
+                       sums->file_offset = offset;
+                       ordered = btrfs_lookup_ordered_extent(inode,
+                                                     sums->file_offset);
+                       BUG_ON(!ordered);
+               }
+
                data = kmap_atomic(bvec->bv_page, KM_USER0);
                sector_sum->sum = ~(u32)0;
                sector_sum->sum = btrfs_csum_data(root,
@@ -165,10 +192,18 @@ int btrfs_csum_one_bio(struct btrfs_root *root,
                                 (char *)&sector_sum->sum);
                sector_sum->offset = page_offset(bvec->bv_page) +
                        bvec->bv_offset;
+
                sector_sum++;
                bio_index++;
+               total_bytes += bvec->bv_len;
+               this_sum_bytes += bvec->bv_len;
                bvec++;
        }
+       btrfs_add_ordered_sum(inode, ordered, sums);
+       btrfs_put_ordered_extent(ordered);
+       if (total_bytes != bio->bi_size) {
+printk("warning, total bytes %lu bio size %u\n", total_bytes, bio->bi_size);
+       }
        return 0;
 }
 
index f37e09e724f79c580f8eff810221ccf545ff8890..4d729d90d2b88957660467afc55b176c630d5310 100644 (file)
@@ -351,12 +351,8 @@ int __btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret = 0;
-       struct btrfs_ordered_sum *sums;
 
-       ret = btrfs_csum_one_bio(root, bio, &sums);
-       BUG_ON(ret);
-
-       ret = btrfs_add_ordered_sum(inode, sums);
+       ret = btrfs_csum_one_bio(root, inode, bio);
        BUG_ON(ret);
 
        return btrfs_map_bio(root, rw, bio, mirror_num, 1);
index 230fd3ca6b2c0e1277abf2b4d9372296f0a6f203..1ddb7bceea996538cd57bf28a042ae20364d020f 100644 (file)
@@ -186,22 +186,17 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
 
 /*
  * Add a struct btrfs_ordered_sum into the list of checksums to be inserted
- * when an ordered extent is finished.
+ * when an ordered extent is finished.  If the list covers more than one
+ * ordered extent, it is split across multiples.
  */
-int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum)
+int btrfs_add_ordered_sum(struct inode *inode,
+                         struct btrfs_ordered_extent *entry,
+                         struct btrfs_ordered_sum *sum)
 {
        struct btrfs_ordered_inode_tree *tree;
-       struct rb_node *node;
-       struct btrfs_ordered_extent *entry;
 
        tree = &BTRFS_I(inode)->ordered_tree;
        mutex_lock(&tree->mutex);
-       node = tree_search(tree, sum->file_offset);
-       BUG_ON(!node);
-
-       entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
-       BUG_ON(!offset_in_entry(entry, sum->file_offset));
-
        list_add_tail(&sum->list, &entry->list);
        mutex_unlock(&tree->mutex);
        return 0;
@@ -524,8 +519,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
        struct btrfs_ordered_extent *ordered;
        struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
        struct list_head *cur;
+       unsigned long num_sectors;
+       unsigned long i;
+       u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
        int ret = 1;
-       int index;
 
        ordered = btrfs_lookup_ordered_extent(inode, offset);
        if (!ordered)
@@ -534,14 +531,17 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
        mutex_lock(&tree->mutex);
        list_for_each_prev(cur, &ordered->list) {
                ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
-               if (offset >= ordered_sum->file_offset &&
-                   offset < ordered_sum->file_offset + ordered_sum->len) {
-                       index = (offset - ordered_sum->file_offset) /
-                               BTRFS_I(inode)->root->sectorsize;;
+               if (offset >= ordered_sum->file_offset) {
+                       num_sectors = ordered_sum->len / sectorsize;
                        sector_sums = &ordered_sum->sums;
-                       *sum = sector_sums[index].sum;
-                       ret = 0;
-                       goto out;
+                       for (i = 0; i < num_sectors; i++) {
+                               if (sector_sums[i].offset == offset) {
+printk("find ordered sum inode %lu offset %Lu\n", inode->i_ino, offset);
+                                       *sum = sector_sums[i].sum;
+                                       ret = 0;
+                                       goto out;
+                               }
+                       }
                }
        }
 out:
index 98f491d1022b419881d1146c61ca60465d46d6e9..1794efd13ca3fab8d0884801b248dcf0730d17c2 100644 (file)
@@ -39,7 +39,11 @@ struct btrfs_sector_sum {
 
 struct btrfs_ordered_sum {
        u64 file_offset;
-       u64 len;
+       /*
+        * this is the length in bytes covered by the sums array below.
+        * But, the sums array may not be contiguous in the file.
+        */
+       unsigned long len;
        struct list_head list;
        /* last field is a variable length array of btrfs_sector_sums */
        struct btrfs_sector_sum sums;
@@ -95,6 +99,7 @@ static inline int btrfs_ordered_sum_size(struct btrfs_root *root, u64 bytes)
 {
        unsigned long num_sectors = (bytes + root->sectorsize - 1) /
                root->sectorsize;
+       num_sectors++;
        return sizeof(struct btrfs_ordered_sum) +
                num_sectors * sizeof(struct btrfs_sector_sum);
 }
@@ -114,7 +119,9 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
                                       u64 file_offset, u64 io_size);
 int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
                             u64 start, u64 len);
-int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum);
+int btrfs_add_ordered_sum(struct inode *inode,
+                         struct btrfs_ordered_extent *entry,
+                         struct btrfs_ordered_sum *sum);
 struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
                                                         u64 file_offset);
 void btrfs_start_ordered_extent(struct inode *inode,