]> git.karo-electronics.de Git - mv-sheeva.git/blob - fs/btrfs/file-item.c
Btrfs: many file_write fixes, inline data
[mv-sheeva.git] / fs / btrfs / file-item.c
1 #include <linux/module.h>
2 #include "ctree.h"
3 #include "disk-io.h"
4 #include "transaction.h"
5
6 #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
7                                  sizeof(struct btrfs_item) * 2) / \
8                                 sizeof(struct btrfs_csum_item)) - 1))
9 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
10                                struct btrfs_root *root,
11                                u64 objectid, u64 pos,
12                                u64 offset, u64 num_blocks)
13 {
14         int ret = 0;
15         struct btrfs_file_extent_item *item;
16         struct btrfs_key file_key;
17         struct btrfs_path *path;
18
19         path = btrfs_alloc_path();
20         BUG_ON(!path);
21         btrfs_init_path(path);
22         file_key.objectid = objectid;
23         file_key.offset = pos;
24         file_key.flags = 0;
25         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
26
27         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
28                                       sizeof(*item));
29         BUG_ON(ret);
30         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
31                               struct btrfs_file_extent_item);
32         btrfs_set_file_extent_disk_blocknr(item, offset);
33         btrfs_set_file_extent_disk_num_blocks(item, num_blocks);
34         btrfs_set_file_extent_offset(item, 0);
35         btrfs_set_file_extent_num_blocks(item, num_blocks);
36         btrfs_set_file_extent_generation(item, trans->transid);
37         btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
38         btrfs_mark_buffer_dirty(path->nodes[0]);
39
40         btrfs_release_path(root, path);
41         btrfs_free_path(path);
42         return 0;
43 }
44
45 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
46                                           struct btrfs_root *root,
47                                           struct btrfs_path *path,
48                                           u64 objectid, u64 offset,
49                                           int cow)
50 {
51         int ret;
52         struct btrfs_key file_key;
53         struct btrfs_key found_key;
54         struct btrfs_csum_item *item;
55         struct btrfs_leaf *leaf;
56         u64 csum_offset = 0;
57         int csums_in_item;
58
59         file_key.objectid = objectid;
60         file_key.offset = offset;
61         file_key.flags = 0;
62         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
63         ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
64         if (ret < 0)
65                 goto fail;
66         leaf = btrfs_buffer_leaf(path->nodes[0]);
67         if (ret > 0) {
68                 ret = 1;
69                 if (path->slots[0] == 0)
70                         goto fail;
71                 path->slots[0]--;
72                 btrfs_disk_key_to_cpu(&found_key,
73                                       &leaf->items[path->slots[0]].key);
74                 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
75                     found_key.objectid != objectid) {
76                         goto fail;
77                 }
78                 csum_offset = (offset - found_key.offset) >>
79                                 root->fs_info->sb->s_blocksize_bits;
80                 csums_in_item = btrfs_item_size(leaf->items + path->slots[0]);
81                 csums_in_item /= sizeof(struct btrfs_csum_item);
82
83                 if (csum_offset >= csums_in_item) {
84                         ret = -EFBIG;
85                         goto fail;
86                 }
87         }
88         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
89         item += csum_offset;
90         return item;
91 fail:
92         if (ret > 0)
93                 ret = -ENOENT;
94         return ERR_PTR(ret);
95 }
96
97
98 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
99                              struct btrfs_root *root,
100                              struct btrfs_path *path, u64 objectid,
101                              u64 offset, int mod)
102 {
103         int ret;
104         struct btrfs_key file_key;
105         int ins_len = mod < 0 ? -1 : 0;
106         int cow = mod != 0;
107
108         file_key.objectid = objectid;
109         file_key.offset = offset;
110         file_key.flags = 0;
111         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
112         ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
113         return ret;
114 }
115
116 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
117                           struct btrfs_root *root,
118                           u64 objectid, u64 offset,
119                           char *data, size_t len)
120 {
121         int ret;
122         struct btrfs_key file_key;
123         struct btrfs_key found_key;
124         struct btrfs_path *path;
125         struct btrfs_csum_item *item;
126         struct btrfs_leaf *leaf;
127         u64 csum_offset;
128
129         path = btrfs_alloc_path();
130         BUG_ON(!path);
131
132         file_key.objectid = objectid;
133         file_key.offset = offset;
134         file_key.flags = 0;
135         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
136
137         item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
138         if (!IS_ERR(item))
139                 goto found;
140         ret = PTR_ERR(item);
141         if (ret == -EFBIG) {
142                 u32 item_size;
143                 /* we found one, but it isn't big enough yet */
144                 leaf = btrfs_buffer_leaf(path->nodes[0]);
145                 item_size = btrfs_item_size(leaf->items + path->slots[0]);
146                 if ((item_size / sizeof(struct btrfs_csum_item)) >=
147                     MAX_CSUM_ITEMS(root)) {
148                         /* already at max size, make a new one */
149                         goto insert;
150                 }
151         } else {
152                 /* we didn't find a csum item, insert one */
153                 goto insert;
154         }
155
156         /*
157          * at this point, we know the tree has an item, but it isn't big
158          * enough yet to put our csum in.  Grow it
159          */
160         btrfs_release_path(root, path);
161         ret = btrfs_search_slot(trans, root, &file_key, path,
162                                 sizeof(struct btrfs_csum_item), 1);
163         if (ret < 0)
164                 goto fail;
165         if (ret == 0) {
166                 BUG();
167         }
168         if (path->slots[0] == 0) {
169                 goto insert;
170         }
171         path->slots[0]--;
172         leaf = btrfs_buffer_leaf(path->nodes[0]);
173         btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
174         csum_offset = (offset - found_key.offset) >>
175                         root->fs_info->sb->s_blocksize_bits;
176         if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
177             found_key.objectid != objectid ||
178             csum_offset >= MAX_CSUM_ITEMS(root)) {
179                 WARN_ON(1);
180                 goto insert;
181         }
182         if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
183             sizeof(struct btrfs_csum_item)) {
184                 u32 diff = (csum_offset + 1) * sizeof(struct btrfs_csum_item);
185                 diff = diff - btrfs_item_size(leaf->items + path->slots[0]);
186                 WARN_ON(diff != sizeof(struct btrfs_csum_item));
187                 ret = btrfs_extend_item(trans, root, path, diff);
188                 BUG_ON(ret);
189                 goto csum;
190         }
191
192 insert:
193         btrfs_release_path(root, path);
194         csum_offset = 0;
195         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
196                                       sizeof(struct btrfs_csum_item));
197         if (ret != 0) {
198                 printk("at insert for %Lu %u %Lu ret is %d\n", file_key.objectid, file_key.flags, file_key.offset, ret);
199                 WARN_ON(1);
200                 goto fail;
201         }
202 csum:
203         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
204                               struct btrfs_csum_item);
205         ret = 0;
206         item += csum_offset;
207 found:
208         btrfs_check_bounds(item->csum, BTRFS_CSUM_SIZE, path->nodes[0]->b_data, root->fs_info->sb->s_blocksize);
209         ret = btrfs_csum_data(root, data, len, item->csum);
210         btrfs_mark_buffer_dirty(path->nodes[0]);
211 fail:
212         btrfs_release_path(root, path);
213         btrfs_free_path(path);
214         return ret;
215 }
216
217 int btrfs_csum_verify_file_block(struct btrfs_root *root,
218                                  u64 objectid, u64 offset,
219                                  char *data, size_t len)
220 {
221         int ret;
222         struct btrfs_key file_key;
223         struct btrfs_path *path;
224         struct btrfs_csum_item *item;
225         char result[BTRFS_CSUM_SIZE];
226
227         path = btrfs_alloc_path();
228         BUG_ON(!path);
229         btrfs_init_path(path);
230         file_key.objectid = objectid;
231         file_key.offset = offset;
232         file_key.flags = 0;
233         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
234         mutex_lock(&root->fs_info->fs_mutex);
235
236         item = btrfs_lookup_csum(NULL, root, path, objectid, offset, 0);
237         if (IS_ERR(item)) {
238                 ret = PTR_ERR(item);
239                 /* a csum that isn't present is a preallocated region. */
240                 if (ret == -ENOENT || ret == -EFBIG)
241                         ret = 1;
242                 goto fail;
243         }
244
245         ret = btrfs_csum_data(root, data, len, result);
246         WARN_ON(ret);
247         if (memcmp(result, item->csum, BTRFS_CSUM_SIZE))
248                 ret = 1;
249 fail:
250         btrfs_release_path(root, path);
251         btrfs_free_path(path);
252         mutex_unlock(&root->fs_info->fs_mutex);
253         return ret;
254 }
255