]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/btrfs/file-item.c
Btrfs: early work to file_write in big extents
[linux-2.6-omap-h63xx.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)) / \
8                                 sizeof(struct btrfs_csum_item)) - 1))
9 int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
10                                struct btrfs_root *root,
11                                u64 objectid, u64 offset,
12                                u64 num_blocks, u64 hint_block,
13                                u64 *result)
14 {
15         struct btrfs_key ins;
16         int ret = 0;
17         struct btrfs_file_extent_item *item;
18         struct btrfs_key file_key;
19         struct btrfs_path *path;
20
21         path = btrfs_alloc_path();
22         BUG_ON(!path);
23         btrfs_init_path(path);
24         ret = btrfs_alloc_extent(trans, root, num_blocks, hint_block,
25                                  (u64)-1, &ins);
26         BUG_ON(ret);
27         file_key.objectid = objectid;
28         file_key.offset = offset;
29         file_key.flags = 0;
30         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
31
32         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
33                                       sizeof(*item));
34         BUG_ON(ret);
35         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
36                               struct btrfs_file_extent_item);
37         btrfs_set_file_extent_disk_blocknr(item, ins.objectid);
38         btrfs_set_file_extent_disk_num_blocks(item, ins.offset);
39         btrfs_set_file_extent_offset(item, 0);
40         btrfs_set_file_extent_num_blocks(item, ins.offset);
41         btrfs_set_file_extent_generation(item, trans->transid);
42         btrfs_mark_buffer_dirty(path->nodes[0]);
43         *result = ins.objectid;
44         btrfs_release_path(root, path);
45         btrfs_free_path(path);
46         return 0;
47 }
48
49 static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root,
50                                                   struct btrfs_path *path,
51                                                   u64 objectid, u64 offset)
52 {
53         int ret;
54         struct btrfs_key file_key;
55         struct btrfs_key found_key;
56         struct btrfs_csum_item *item;
57         struct btrfs_leaf *leaf;
58         u64 csum_offset = 0;
59
60         file_key.objectid = objectid;
61         file_key.offset = offset;
62         file_key.flags = 0;
63         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
64         ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0);
65         if (ret < 0)
66                 goto fail;
67         leaf = btrfs_buffer_leaf(path->nodes[0]);
68         if (ret > 0) {
69                 ret = 1;
70                 if (path->slots[0] == 0)
71                         goto fail;
72                 path->slots[0]--;
73                 btrfs_disk_key_to_cpu(&found_key,
74                                       &leaf->items[path->slots[0]].key);
75                 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
76                     found_key.objectid != objectid) {
77                         goto fail;
78                 }
79                 csum_offset = (offset - found_key.offset) >>
80                                 root->fs_info->sb->s_blocksize_bits;
81                 if (csum_offset >=
82                     btrfs_item_size(leaf->items + path->slots[0]) /
83                     sizeof(struct btrfs_csum_item)) {
84                         goto fail;
85                 }
86         }
87         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
88         item += csum_offset;
89         return item;
90 fail:
91         if (ret > 0)
92                 ret = -EIO;
93         return ERR_PTR(ret);
94 }
95
96
97 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
98                              struct btrfs_root *root,
99                              struct btrfs_path *path, u64 objectid,
100                              u64 offset, int mod)
101 {
102         int ret;
103         struct btrfs_key file_key;
104         int ins_len = mod < 0 ? -1 : 0;
105         int cow = mod != 0;
106         struct btrfs_csum_item *csum_item;
107
108         csum_item = __lookup_csum_item(root, path, objectid, offset);
109         if (IS_ERR(csum_item))
110                 return PTR_ERR(csum_item);
111         file_key.objectid = objectid;
112         file_key.offset = btrfs_csum_extent_offset(csum_item);
113         file_key.flags = 0;
114         btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
115         btrfs_release_path(root, path);
116         ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
117         return ret;
118 }
119
120 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
121                           struct btrfs_root *root,
122                           u64 objectid, u64 offset,
123                           u64 extent_offset,
124                           char *data, size_t len)
125 {
126         int ret;
127         struct btrfs_key file_key;
128         struct btrfs_key found_key;
129         struct btrfs_path *path;
130         struct btrfs_csum_item *item;
131         struct btrfs_leaf *leaf;
132         u64 csum_offset;
133
134         path = btrfs_alloc_path();
135         BUG_ON(!path);
136         btrfs_init_path(path);
137         file_key.objectid = objectid;
138         file_key.offset = offset;
139         file_key.flags = 0;
140         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
141         ret = btrfs_search_slot(trans, root, &file_key, path,
142                                 sizeof(struct btrfs_csum_item), 1);
143         if (ret < 0)
144                 goto fail;
145         if (ret == 0) {
146                 csum_offset = 0;
147                 goto csum;
148         }
149         if (path->slots[0] == 0) {
150                 btrfs_release_path(root, path);
151                 goto insert;
152         }
153         path->slots[0]--;
154         leaf = btrfs_buffer_leaf(path->nodes[0]);
155         btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
156         csum_offset = (offset - found_key.offset) >>
157                         root->fs_info->sb->s_blocksize_bits;
158         if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
159             found_key.objectid != objectid ||
160             csum_offset >= MAX_CSUM_ITEMS(root)) {
161                 btrfs_release_path(root, path);
162                 goto insert;
163         }
164         if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
165             sizeof(struct btrfs_csum_item)) {
166                 ret = btrfs_extend_item(trans, root, path,
167                                         sizeof(struct btrfs_csum_item));
168                 BUG_ON(ret);
169                 goto csum;
170         }
171
172 insert:
173         csum_offset = 0;
174         ret = btrfs_insert_empty_item(trans, root, path, &file_key,
175                                       sizeof(struct btrfs_csum_item));
176         if (ret != 0 && ret != -EEXIST)
177                 goto fail;
178 csum:
179         item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
180                               struct btrfs_csum_item);
181         ret = 0;
182         item += csum_offset;
183         ret = btrfs_csum_data(root, data, len, item->csum);
184         btrfs_set_csum_extent_offset(item, extent_offset);
185         btrfs_mark_buffer_dirty(path->nodes[0]);
186 fail:
187         btrfs_release_path(root, path);
188         btrfs_free_path(path);
189         return ret;
190 }
191
192 int btrfs_csum_verify_file_block(struct btrfs_root *root,
193                                  u64 objectid, u64 offset,
194                                  char *data, size_t len)
195 {
196         int ret;
197         struct btrfs_key file_key;
198         struct btrfs_path *path;
199         struct btrfs_csum_item *item;
200         char result[BTRFS_CSUM_SIZE];
201
202         path = btrfs_alloc_path();
203         BUG_ON(!path);
204         btrfs_init_path(path);
205         file_key.objectid = objectid;
206         file_key.offset = offset;
207         file_key.flags = 0;
208         btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
209         mutex_lock(&root->fs_info->fs_mutex);
210
211         item = __lookup_csum_item(root, path, objectid, offset);
212         if (IS_ERR(item)) {
213                 ret = PTR_ERR(item);
214                 goto fail;
215         }
216
217         ret = btrfs_csum_data(root, data, len, result);
218         WARN_ON(ret);
219         if (memcmp(result, item->csum, BTRFS_CSUM_SIZE))
220                 ret = 1;
221 fail:
222         btrfs_release_path(root, path);
223         btrfs_free_path(path);
224         mutex_unlock(&root->fs_info->fs_mutex);
225         return ret;
226 }
227