aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-08-30 08:50:51 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-08-30 08:50:51 -0400
commit07157aacb1ecd394a5494910b5f80d7e7d407d37 (patch)
treedc27c45e8b24167b13d89b0e7c3c3a94b293ce29
parent95e0528919cb0c7635b37496e0ad1c41e4c0dd7c (diff)
Btrfs: Add file data csums back in via hooks in the extent map code
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/extent_map.c94
-rw-r--r--fs/btrfs/extent_map.h15
-rw-r--r--fs/btrfs/inode.c98
3 files changed, 193 insertions, 14 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index a9c7419615b9..6053f9db0739 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -57,7 +57,7 @@ void extent_map_tree_init(struct extent_map_tree *tree,
57{ 57{
58 tree->map.rb_node = NULL; 58 tree->map.rb_node = NULL;
59 tree->state.rb_node = NULL; 59 tree->state.rb_node = NULL;
60 tree->fill_delalloc = NULL; 60 tree->ops = NULL;
61 rwlock_init(&tree->lock); 61 rwlock_init(&tree->lock);
62 tree->mapping = mapping; 62 tree->mapping = mapping;
63} 63}
@@ -93,6 +93,7 @@ struct extent_state *alloc_extent_state(gfp_t mask)
93 return state; 93 return state;
94 state->state = 0; 94 state->state = 0;
95 state->in_tree = 0; 95 state->in_tree = 0;
96 state->private = 0;
96 atomic_set(&state->refs, 1); 97 atomic_set(&state->refs, 1);
97 init_waitqueue_head(&state->wq); 98 init_waitqueue_head(&state->wq);
98 return state; 99 return state;
@@ -1034,6 +1035,61 @@ int unlock_range(struct extent_map_tree *tree, u64 start, u64 end)
1034} 1035}
1035EXPORT_SYMBOL(unlock_range); 1036EXPORT_SYMBOL(unlock_range);
1036 1037
1038int set_state_private(struct extent_map_tree *tree, u64 start, u64 private)
1039{
1040 struct rb_node *node;
1041 struct extent_state *state;
1042 int ret = 0;
1043
1044 write_lock_irq(&tree->lock);
1045 /*
1046 * this search will find all the extents that end after
1047 * our range starts.
1048 */
1049 node = tree_search(&tree->state, start);
1050 if (!node || IS_ERR(node)) {
1051 ret = -ENOENT;
1052 goto out;
1053 }
1054 state = rb_entry(node, struct extent_state, rb_node);
1055 if (state->start != start) {
1056 ret = -ENOENT;
1057 goto out;
1058 }
1059 state->private = private;
1060out:
1061 write_unlock_irq(&tree->lock);
1062 return ret;
1063
1064}
1065
1066int get_state_private(struct extent_map_tree *tree, u64 start, u64 *private)
1067{
1068 struct rb_node *node;
1069 struct extent_state *state;
1070 int ret = 0;
1071
1072 read_lock_irq(&tree->lock);
1073 /*
1074 * this search will find all the extents that end after
1075 * our range starts.
1076 */
1077 node = tree_search(&tree->state, start);
1078 if (!node || IS_ERR(node)) {
1079 ret = -ENOENT;
1080 goto out;
1081 }
1082 state = rb_entry(node, struct extent_state, rb_node);
1083 if (state->start != start) {
1084 ret = -ENOENT;
1085 goto out;
1086 }
1087 *private = state->private;
1088out:
1089 read_unlock_irq(&tree->lock);
1090 return ret;
1091}
1092
1037/* 1093/*
1038 * searches a range in the state tree for a given mask. 1094 * searches a range in the state tree for a given mask.
1039 * If 'filled' == 1, this returns 1 only if ever extent in the tree 1095 * If 'filled' == 1, this returns 1 only if ever extent in the tree
@@ -1185,12 +1241,13 @@ static int end_bio_extent_writepage(struct bio *bio,
1185static int end_bio_extent_readpage(struct bio *bio, 1241static int end_bio_extent_readpage(struct bio *bio,
1186 unsigned int bytes_done, int err) 1242 unsigned int bytes_done, int err)
1187{ 1243{
1188 const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); 1244 int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
1189 struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; 1245 struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
1190 struct extent_map_tree *tree = bio->bi_private; 1246 struct extent_map_tree *tree = bio->bi_private;
1191 u64 start; 1247 u64 start;
1192 u64 end; 1248 u64 end;
1193 int whole_page; 1249 int whole_page;
1250 int ret;
1194 1251
1195 if (bio->bi_size) 1252 if (bio->bi_size)
1196 return 1; 1253 return 1;
@@ -1208,6 +1265,11 @@ static int end_bio_extent_readpage(struct bio *bio,
1208 if (--bvec >= bio->bi_io_vec) 1265 if (--bvec >= bio->bi_io_vec)
1209 prefetchw(&bvec->bv_page->flags); 1266 prefetchw(&bvec->bv_page->flags);
1210 1267
1268 if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
1269 ret = tree->ops->readpage_end_io_hook(page, start, end);
1270 if (ret)
1271 uptodate = 0;
1272 }
1211 if (uptodate) { 1273 if (uptodate) {
1212 set_extent_uptodate(tree, start, end, GFP_ATOMIC); 1274 set_extent_uptodate(tree, start, end, GFP_ATOMIC);
1213 if (whole_page) 1275 if (whole_page)
@@ -1388,9 +1450,16 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page,
1388 continue; 1450 continue;
1389 } 1451 }
1390 1452
1391 ret = submit_extent_page(READ, tree, page, 1453 ret = 0;
1392 sector, iosize, page_offset, bdev, 1454 if (tree->ops && tree->ops->readpage_io_hook) {
1393 end_bio_extent_readpage); 1455 ret = tree->ops->readpage_io_hook(page, cur,
1456 cur + iosize - 1);
1457 }
1458 if (!ret) {
1459 ret = submit_extent_page(READ, tree, page,
1460 sector, iosize, page_offset,
1461 bdev, end_bio_extent_readpage);
1462 }
1394 if (ret) 1463 if (ret)
1395 SetPageError(page); 1464 SetPageError(page);
1396 cur = cur + iosize; 1465 cur = cur + iosize;
@@ -1462,7 +1531,7 @@ int extent_write_full_page(struct extent_map_tree *tree, struct page *page,
1462 &delalloc_end, 1531 &delalloc_end,
1463 128 * 1024 * 1024); 1532 128 * 1024 * 1024);
1464 if (nr_delalloc) { 1533 if (nr_delalloc) {
1465 tree->fill_delalloc(inode, start, delalloc_end); 1534 tree->ops->fill_delalloc(inode, start, delalloc_end);
1466 if (delalloc_end >= page_end + 1) { 1535 if (delalloc_end >= page_end + 1) {
1467 clear_extent_bit(tree, page_end + 1, delalloc_end, 1536 clear_extent_bit(tree, page_end + 1, delalloc_end,
1468 EXTENT_LOCKED | EXTENT_DELALLOC, 1537 EXTENT_LOCKED | EXTENT_DELALLOC,
@@ -1528,12 +1597,17 @@ int extent_write_full_page(struct extent_map_tree *tree, struct page *page,
1528 continue; 1597 continue;
1529 } 1598 }
1530 clear_extent_dirty(tree, cur, cur + iosize - 1, GFP_NOFS); 1599 clear_extent_dirty(tree, cur, cur + iosize - 1, GFP_NOFS);
1531 set_range_writeback(tree, cur, cur + iosize - 1); 1600 ret = tree->ops->writepage_io_hook(page, cur, cur + iosize - 1);
1532 ret = submit_extent_page(WRITE, tree, page,
1533 sector, iosize, page_offset, bdev,
1534 end_bio_extent_writepage);
1535 if (ret) 1601 if (ret)
1536 SetPageError(page); 1602 SetPageError(page);
1603 else {
1604 set_range_writeback(tree, cur, cur + iosize - 1);
1605 ret = submit_extent_page(WRITE, tree, page, sector,
1606 iosize, page_offset, bdev,
1607 end_bio_extent_writepage);
1608 if (ret)
1609 SetPageError(page);
1610 }
1537 cur = cur + iosize; 1611 cur = cur + iosize;
1538 page_offset += iosize; 1612 page_offset += iosize;
1539 nr++; 1613 nr++;
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index e91a2e9619ee..0eae6c420acb 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -6,12 +6,19 @@
6#define EXTENT_MAP_INLINE (u64)-2 6#define EXTENT_MAP_INLINE (u64)-2
7#define EXTENT_MAP_DELALLOC (u64)-1 7#define EXTENT_MAP_DELALLOC (u64)-1
8 8
9struct extent_map_ops {
10 int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
11 int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
12 int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
13 int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end);
14};
15
9struct extent_map_tree { 16struct extent_map_tree {
10 struct rb_root map; 17 struct rb_root map;
11 struct rb_root state; 18 struct rb_root state;
12 struct address_space *mapping; 19 struct address_space *mapping;
13 rwlock_t lock; 20 rwlock_t lock;
14 int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); 21 struct extent_map_ops *ops;
15}; 22};
16 23
17/* note, this must start with the same fields as fs/extent_map.c:tree_entry */ 24/* note, this must start with the same fields as fs/extent_map.c:tree_entry */
@@ -36,6 +43,10 @@ struct extent_state {
36 wait_queue_head_t wq; 43 wait_queue_head_t wq;
37 atomic_t refs; 44 atomic_t refs;
38 unsigned long state; 45 unsigned long state;
46
47 /* for use by the FS */
48 u64 private;
49
39 struct list_head list; 50 struct list_head list;
40}; 51};
41 52
@@ -89,4 +100,6 @@ int extent_commit_write(struct extent_map_tree *tree,
89 struct inode *inode, struct page *page, 100 struct inode *inode, struct page *page,
90 unsigned from, unsigned to); 101 unsigned from, unsigned to);
91int set_range_dirty(struct extent_map_tree *tree, u64 start, u64 end); 102int set_range_dirty(struct extent_map_tree *tree, u64 start, u64 end);
103int set_state_private(struct extent_map_tree *tree, u64 start, u64 private);
104int get_state_private(struct extent_map_tree *tree, u64 start, u64 *private);
92#endif 105#endif
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 483eea69b0a6..3ee6b2fadf58 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -52,6 +52,7 @@ static struct inode_operations btrfs_file_inode_operations;
52static struct address_space_operations btrfs_aops; 52static struct address_space_operations btrfs_aops;
53static struct address_space_operations btrfs_symlink_aops; 53static struct address_space_operations btrfs_symlink_aops;
54static struct file_operations btrfs_dir_file_operations; 54static struct file_operations btrfs_dir_file_operations;
55static struct extent_map_ops btrfs_extent_map_ops;
55 56
56static struct kmem_cache *btrfs_inode_cachep; 57static struct kmem_cache *btrfs_inode_cachep;
57struct kmem_cache *btrfs_trans_handle_cachep; 58struct kmem_cache *btrfs_trans_handle_cachep;
@@ -103,6 +104,90 @@ out:
103 return ret; 104 return ret;
104} 105}
105 106
107int btrfs_writepage_io_hook(struct page *page, u64 start, u64 end)
108{
109 struct inode *inode = page->mapping->host;
110 struct btrfs_root *root = BTRFS_I(inode)->root;
111 struct btrfs_trans_handle *trans;
112 char *kaddr;
113 int ret;
114 u64 page_start = page->index << PAGE_CACHE_SHIFT;
115 size_t offset = start - page_start;
116
117 mutex_lock(&root->fs_info->fs_mutex);
118 trans = btrfs_start_transaction(root, 1);
119 btrfs_set_trans_block_group(trans, inode);
120 kaddr = kmap(page);
121 btrfs_csum_file_block(trans, root, inode->i_ino,
122 start, kaddr + offset, end - start + 1);
123 kunmap(page);
124 ret = btrfs_end_transaction(trans, root);
125 BUG_ON(ret);
126 mutex_unlock(&root->fs_info->fs_mutex);
127 return ret;
128}
129
130int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
131{
132 int ret = 0;
133 struct inode *inode = page->mapping->host;
134 struct btrfs_root *root = BTRFS_I(inode)->root;
135 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
136 struct btrfs_csum_item *item;
137 struct btrfs_path *path = NULL;
138 u64 private;
139
140 mutex_lock(&root->fs_info->fs_mutex);
141 path = btrfs_alloc_path();
142 item = btrfs_lookup_csum(NULL, root, path, inode->i_ino, start, 0);
143 if (IS_ERR(item)) {
144 ret = PTR_ERR(item);
145 /* a csum that isn't present is a preallocated region. */
146 if (ret == -ENOENT || ret == -EFBIG)
147 ret = 0;
148 private = 0;
149 goto out;
150 }
151 memcpy((char *)&private, &item->csum, BTRFS_CRC32_SIZE);
152 set_state_private(em_tree, start, private);
153out:
154 if (path)
155 btrfs_free_path(path);
156 mutex_unlock(&root->fs_info->fs_mutex);
157 return ret;
158}
159
160int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end)
161{
162 char csum[BTRFS_CRC32_SIZE];
163 size_t offset = start - (page->index << PAGE_CACHE_SHIFT);
164 struct inode *inode = page->mapping->host;
165 struct btrfs_root *root = BTRFS_I(inode)->root;
166 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
167 char *kaddr;
168 u64 private;
169 int ret;
170
171 ret = get_state_private(em_tree, start, &private);
172 kaddr = kmap_atomic(page, KM_IRQ0);
173 if (ret) {
174 goto zeroit;
175 }
176 ret = btrfs_csum_data(root, kaddr + offset, end - start + 1, csum);
177 BUG_ON(ret);
178 if (memcmp(csum, &private, BTRFS_CRC32_SIZE)) {
179 goto zeroit;
180 }
181 kunmap_atomic(kaddr, KM_IRQ0);
182 return 0;
183
184zeroit:
185 printk("btrfs csum failed ino %lu off %llu\n",
186 page->mapping->host->i_ino, (unsigned long long)start);
187 memset(kaddr + offset, 1, end - start + 1); flush_dcache_page(page);
188 kunmap_atomic(kaddr, KM_IRQ0);
189 return 0;
190}
106 191
107void btrfs_read_locked_inode(struct inode *inode) 192void btrfs_read_locked_inode(struct inode *inode)
108{ 193{
@@ -155,7 +240,7 @@ void btrfs_read_locked_inode(struct inode *inode)
155 switch (inode->i_mode & S_IFMT) { 240 switch (inode->i_mode & S_IFMT) {
156 case S_IFREG: 241 case S_IFREG:
157 inode->i_mapping->a_ops = &btrfs_aops; 242 inode->i_mapping->a_ops = &btrfs_aops;
158 BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; 243 BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
159 inode->i_fop = &btrfs_file_operations; 244 inode->i_fop = &btrfs_file_operations;
160 inode->i_op = &btrfs_file_inode_operations; 245 inode->i_op = &btrfs_file_inode_operations;
161 break; 246 break;
@@ -1148,7 +1233,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
1148 inode->i_op = &btrfs_file_inode_operations; 1233 inode->i_op = &btrfs_file_inode_operations;
1149 extent_map_tree_init(&BTRFS_I(inode)->extent_tree, 1234 extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
1150 inode->i_mapping, GFP_NOFS); 1235 inode->i_mapping, GFP_NOFS);
1151 BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; 1236 BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
1152 } 1237 }
1153 dir->i_sb->s_dirt = 1; 1238 dir->i_sb->s_dirt = 1;
1154 btrfs_update_inode_block_group(trans, inode); 1239 btrfs_update_inode_block_group(trans, inode);
@@ -2286,7 +2371,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
2286 inode->i_op = &btrfs_file_inode_operations; 2371 inode->i_op = &btrfs_file_inode_operations;
2287 extent_map_tree_init(&BTRFS_I(inode)->extent_tree, 2372 extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
2288 inode->i_mapping, GFP_NOFS); 2373 inode->i_mapping, GFP_NOFS);
2289 BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; 2374 BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
2290 } 2375 }
2291 dir->i_sb->s_dirt = 1; 2376 dir->i_sb->s_dirt = 1;
2292 btrfs_update_inode_block_group(trans, inode); 2377 btrfs_update_inode_block_group(trans, inode);
@@ -2362,6 +2447,13 @@ static struct file_operations btrfs_dir_file_operations = {
2362#endif 2447#endif
2363}; 2448};
2364 2449
2450static struct extent_map_ops btrfs_extent_map_ops = {
2451 .fill_delalloc = run_delalloc_range,
2452 .writepage_io_hook = btrfs_writepage_io_hook,
2453 .readpage_io_hook = btrfs_readpage_io_hook,
2454 .readpage_end_io_hook = btrfs_readpage_end_io_hook,
2455};
2456
2365static struct address_space_operations btrfs_aops = { 2457static struct address_space_operations btrfs_aops = {
2366 .readpage = btrfs_readpage, 2458 .readpage = btrfs_readpage,
2367 .writepage = btrfs_writepage, 2459 .writepage = btrfs_writepage,