diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 98 |
1 files changed, 95 insertions, 3 deletions
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; | |||
52 | static struct address_space_operations btrfs_aops; | 52 | static struct address_space_operations btrfs_aops; |
53 | static struct address_space_operations btrfs_symlink_aops; | 53 | static struct address_space_operations btrfs_symlink_aops; |
54 | static struct file_operations btrfs_dir_file_operations; | 54 | static struct file_operations btrfs_dir_file_operations; |
55 | static struct extent_map_ops btrfs_extent_map_ops; | ||
55 | 56 | ||
56 | static struct kmem_cache *btrfs_inode_cachep; | 57 | static struct kmem_cache *btrfs_inode_cachep; |
57 | struct kmem_cache *btrfs_trans_handle_cachep; | 58 | struct kmem_cache *btrfs_trans_handle_cachep; |
@@ -103,6 +104,90 @@ out: | |||
103 | return ret; | 104 | return ret; |
104 | } | 105 | } |
105 | 106 | ||
107 | int 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 | |||
130 | int 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); | ||
153 | out: | ||
154 | if (path) | ||
155 | btrfs_free_path(path); | ||
156 | mutex_unlock(&root->fs_info->fs_mutex); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | int 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 | |||
184 | zeroit: | ||
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 | ||
107 | void btrfs_read_locked_inode(struct inode *inode) | 192 | void 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 | ||
2450 | static 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 | |||
2365 | static struct address_space_operations btrfs_aops = { | 2457 | static struct address_space_operations btrfs_aops = { |
2366 | .readpage = btrfs_readpage, | 2458 | .readpage = btrfs_readpage, |
2367 | .writepage = btrfs_writepage, | 2459 | .writepage = btrfs_writepage, |