diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-16 09:22:45 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-16 09:22:45 -0400 |
commit | 6567e837df07e43bffc08ac40858af8133a007bf (patch) | |
tree | 3bf186544e5cd5d4ef5c755e1e3b8f678f6df198 | |
parent | b4100d64241fed93a3f821ddf59d11ab4443a3ba (diff) |
Btrfs: early work to file_write in big extents
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.c | 54 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 15 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 111 | ||||
-rw-r--r-- | fs/btrfs/super.c | 75 |
4 files changed, 232 insertions, 23 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index e2fc6f0d0243..6b76fd967153 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1249,6 +1249,60 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1249 | return ret; | 1249 | return ret; |
1250 | } | 1250 | } |
1251 | 1251 | ||
1252 | int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||
1253 | *root, struct btrfs_path *path, u32 data_size) | ||
1254 | { | ||
1255 | int ret = 0; | ||
1256 | int slot; | ||
1257 | int slot_orig; | ||
1258 | struct btrfs_leaf *leaf; | ||
1259 | struct buffer_head *leaf_buf; | ||
1260 | u32 nritems; | ||
1261 | unsigned int data_end; | ||
1262 | unsigned int old_data; | ||
1263 | unsigned int old_size; | ||
1264 | int i; | ||
1265 | |||
1266 | slot_orig = path->slots[0]; | ||
1267 | leaf_buf = path->nodes[0]; | ||
1268 | leaf = btrfs_buffer_leaf(leaf_buf); | ||
1269 | |||
1270 | nritems = btrfs_header_nritems(&leaf->header); | ||
1271 | data_end = leaf_data_end(root, leaf); | ||
1272 | |||
1273 | if (btrfs_leaf_free_space(root, leaf) < data_size) | ||
1274 | BUG(); | ||
1275 | slot = path->slots[0]; | ||
1276 | old_data = btrfs_item_end(leaf->items + slot); | ||
1277 | |||
1278 | BUG_ON(slot < 0); | ||
1279 | BUG_ON(slot >= nritems); | ||
1280 | |||
1281 | /* | ||
1282 | * item0..itemN ... dataN.offset..dataN.size .. data0.size | ||
1283 | */ | ||
1284 | /* first correct the data pointers */ | ||
1285 | for (i = slot; i < nritems; i++) { | ||
1286 | u32 ioff = btrfs_item_offset(leaf->items + i); | ||
1287 | btrfs_set_item_offset(leaf->items + i, | ||
1288 | ioff - data_size); | ||
1289 | } | ||
1290 | /* shift the data */ | ||
1291 | btrfs_memmove(root, leaf, btrfs_leaf_data(leaf) + | ||
1292 | data_end - data_size, btrfs_leaf_data(leaf) + | ||
1293 | data_end, old_data - data_end); | ||
1294 | data_end = old_data; | ||
1295 | old_size = btrfs_item_size(leaf->items + slot); | ||
1296 | btrfs_set_item_size(leaf->items + slot, old_size + data_size); | ||
1297 | btrfs_mark_buffer_dirty(leaf_buf); | ||
1298 | |||
1299 | ret = 0; | ||
1300 | if (btrfs_leaf_free_space(root, leaf) < 0) | ||
1301 | BUG(); | ||
1302 | check_leaf(root, path, 0); | ||
1303 | return ret; | ||
1304 | } | ||
1305 | |||
1252 | /* | 1306 | /* |
1253 | * Given a key and some data, insert an item into the tree. | 1307 | * Given a key and some data, insert an item into the tree. |
1254 | * This does all the path init required, making room in the tree if needed. | 1308 | * This does all the path init required, making room in the tree if needed. |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ef3583cf74d6..796f19d03ab5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -227,6 +227,7 @@ struct btrfs_file_extent_item { | |||
227 | } __attribute__ ((__packed__)); | 227 | } __attribute__ ((__packed__)); |
228 | 228 | ||
229 | struct btrfs_csum_item { | 229 | struct btrfs_csum_item { |
230 | __le64 extent_offset; | ||
230 | u8 csum[BTRFS_CSUM_SIZE]; | 231 | u8 csum[BTRFS_CSUM_SIZE]; |
231 | } __attribute__ ((__packed__)); | 232 | } __attribute__ ((__packed__)); |
232 | 233 | ||
@@ -924,6 +925,17 @@ static inline void btrfs_set_file_extent_num_blocks(struct | |||
924 | e->num_blocks = cpu_to_le64(val); | 925 | e->num_blocks = cpu_to_le64(val); |
925 | } | 926 | } |
926 | 927 | ||
928 | static inline u64 btrfs_csum_extent_offset(struct btrfs_csum_item *c) | ||
929 | { | ||
930 | return le64_to_cpu(c->extent_offset); | ||
931 | } | ||
932 | |||
933 | static inline void btrfs_set_csum_extent_offset(struct btrfs_csum_item *c, | ||
934 | u64 val) | ||
935 | { | ||
936 | c->extent_offset = cpu_to_le64(val); | ||
937 | } | ||
938 | |||
927 | static inline u16 btrfs_device_pathlen(struct btrfs_device_item *d) | 939 | static inline u16 btrfs_device_pathlen(struct btrfs_device_item *d) |
928 | { | 940 | { |
929 | return le16_to_cpu(d->pathlen); | 941 | return le16_to_cpu(d->pathlen); |
@@ -1002,6 +1014,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1002 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 1014 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct |
1003 | btrfs_root *root); | 1015 | btrfs_root *root); |
1004 | /* ctree.c */ | 1016 | /* ctree.c */ |
1017 | int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||
1018 | *root, struct btrfs_path *path, u32 data_size); | ||
1005 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | 1019 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root |
1006 | *root, struct btrfs_key *key, struct btrfs_path *p, int | 1020 | *root, struct btrfs_key *key, struct btrfs_path *p, int |
1007 | ins_len, int cow); | 1021 | ins_len, int cow); |
@@ -1071,6 +1085,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
1071 | int btrfs_csum_file_block(struct btrfs_trans_handle *trans, | 1085 | int btrfs_csum_file_block(struct btrfs_trans_handle *trans, |
1072 | struct btrfs_root *root, | 1086 | struct btrfs_root *root, |
1073 | u64 objectid, u64 offset, | 1087 | u64 objectid, u64 offset, |
1088 | u64 extent_offset, | ||
1074 | char *data, size_t len); | 1089 | char *data, size_t len); |
1075 | int btrfs_csum_verify_file_block(struct btrfs_root *root, | 1090 | int btrfs_csum_verify_file_block(struct btrfs_root *root, |
1076 | u64 objectid, u64 offset, | 1091 | u64 objectid, u64 offset, |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index d9fd7f4d3794..93d42d650820 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -3,6 +3,9 @@ | |||
3 | #include "disk-io.h" | 3 | #include "disk-io.h" |
4 | #include "transaction.h" | 4 | #include "transaction.h" |
5 | 5 | ||
6 | #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ | ||
7 | sizeof(struct btrfs_item)) / \ | ||
8 | sizeof(struct btrfs_csum_item)) - 1)) | ||
6 | int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, | 9 | int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, |
7 | struct btrfs_root *root, | 10 | struct btrfs_root *root, |
8 | u64 objectid, u64 offset, | 11 | u64 objectid, u64 offset, |
@@ -43,6 +46,54 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, | |||
43 | return 0; | 46 | return 0; |
44 | } | 47 | } |
45 | 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 | |||
46 | int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | 97 | int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, |
47 | struct btrfs_root *root, | 98 | struct btrfs_root *root, |
48 | struct btrfs_path *path, u64 objectid, | 99 | struct btrfs_path *path, u64 objectid, |
@@ -52,11 +103,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
52 | struct btrfs_key file_key; | 103 | struct btrfs_key file_key; |
53 | int ins_len = mod < 0 ? -1 : 0; | 104 | int ins_len = mod < 0 ? -1 : 0; |
54 | int cow = mod != 0; | 105 | int cow = mod != 0; |
106 | struct btrfs_csum_item *csum_item; | ||
55 | 107 | ||
108 | csum_item = __lookup_csum_item(root, path, objectid, offset); | ||
109 | if (IS_ERR(csum_item)) | ||
110 | return PTR_ERR(csum_item); | ||
56 | file_key.objectid = objectid; | 111 | file_key.objectid = objectid; |
57 | file_key.offset = offset; | 112 | file_key.offset = btrfs_csum_extent_offset(csum_item); |
58 | file_key.flags = 0; | 113 | file_key.flags = 0; |
59 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); | 114 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); |
115 | btrfs_release_path(root, path); | ||
60 | ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); | 116 | ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); |
61 | return ret; | 117 | return ret; |
62 | } | 118 | } |
@@ -64,12 +120,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
64 | int btrfs_csum_file_block(struct btrfs_trans_handle *trans, | 120 | int btrfs_csum_file_block(struct btrfs_trans_handle *trans, |
65 | struct btrfs_root *root, | 121 | struct btrfs_root *root, |
66 | u64 objectid, u64 offset, | 122 | u64 objectid, u64 offset, |
123 | u64 extent_offset, | ||
67 | char *data, size_t len) | 124 | char *data, size_t len) |
68 | { | 125 | { |
69 | int ret; | 126 | int ret; |
70 | struct btrfs_key file_key; | 127 | struct btrfs_key file_key; |
128 | struct btrfs_key found_key; | ||
71 | struct btrfs_path *path; | 129 | struct btrfs_path *path; |
72 | struct btrfs_csum_item *item; | 130 | struct btrfs_csum_item *item; |
131 | struct btrfs_leaf *leaf; | ||
132 | u64 csum_offset; | ||
73 | 133 | ||
74 | path = btrfs_alloc_path(); | 134 | path = btrfs_alloc_path(); |
75 | BUG_ON(!path); | 135 | BUG_ON(!path); |
@@ -78,14 +138,50 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, | |||
78 | file_key.offset = offset; | 138 | file_key.offset = offset; |
79 | file_key.flags = 0; | 139 | file_key.flags = 0; |
80 | btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); | 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; | ||
81 | ret = btrfs_insert_empty_item(trans, root, path, &file_key, | 174 | ret = btrfs_insert_empty_item(trans, root, path, &file_key, |
82 | BTRFS_CSUM_SIZE); | 175 | sizeof(struct btrfs_csum_item)); |
83 | if (ret != 0 && ret != -EEXIST) | 176 | if (ret != 0 && ret != -EEXIST) |
84 | goto fail; | 177 | goto fail; |
178 | csum: | ||
85 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 179 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
86 | struct btrfs_csum_item); | 180 | struct btrfs_csum_item); |
87 | ret = 0; | 181 | ret = 0; |
182 | item += csum_offset; | ||
88 | ret = btrfs_csum_data(root, data, len, item->csum); | 183 | ret = btrfs_csum_data(root, data, len, item->csum); |
184 | btrfs_set_csum_extent_offset(item, extent_offset); | ||
89 | btrfs_mark_buffer_dirty(path->nodes[0]); | 185 | btrfs_mark_buffer_dirty(path->nodes[0]); |
90 | fail: | 186 | fail: |
91 | btrfs_release_path(root, path); | 187 | btrfs_release_path(root, path); |
@@ -111,12 +207,13 @@ int btrfs_csum_verify_file_block(struct btrfs_root *root, | |||
111 | file_key.flags = 0; | 207 | file_key.flags = 0; |
112 | btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); | 208 | btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); |
113 | mutex_lock(&root->fs_info->fs_mutex); | 209 | mutex_lock(&root->fs_info->fs_mutex); |
114 | ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0); | 210 | |
115 | if (ret) | 211 | item = __lookup_csum_item(root, path, objectid, offset); |
212 | if (IS_ERR(item)) { | ||
213 | ret = PTR_ERR(item); | ||
116 | goto fail; | 214 | goto fail; |
117 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 215 | } |
118 | struct btrfs_csum_item); | 216 | |
119 | ret = 0; | ||
120 | ret = btrfs_csum_data(root, data, len, result); | 217 | ret = btrfs_csum_data(root, data, len, result); |
121 | WARN_ON(ret); | 218 | WARN_ON(ret); |
122 | if (memcmp(result, item->csum, BTRFS_CSUM_SIZE)) | 219 | if (memcmp(result, item->csum, BTRFS_CSUM_SIZE)) |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 8dcf600e39ef..ec689992fdf4 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -1027,8 +1027,10 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1027 | path = btrfs_alloc_path(); | 1027 | path = btrfs_alloc_path(); |
1028 | BUG_ON(!path); | 1028 | BUG_ON(!path); |
1029 | btrfs_init_path(path); | 1029 | btrfs_init_path(path); |
1030 | if (create) | 1030 | if (create) { |
1031 | trans = btrfs_start_transaction(root, 1); | 1031 | trans = btrfs_start_transaction(root, 1); |
1032 | WARN_ON(1); | ||
1033 | } | ||
1032 | 1034 | ||
1033 | ret = btrfs_lookup_file_extent(trans, root, path, | 1035 | ret = btrfs_lookup_file_extent(trans, root, path, |
1034 | inode->i_ino, | 1036 | inode->i_ino, |
@@ -1055,9 +1057,8 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1055 | /* exact match found, use it, FIXME, deal with extents | 1057 | /* exact match found, use it, FIXME, deal with extents |
1056 | * other than the page size | 1058 | * other than the page size |
1057 | */ | 1059 | */ |
1058 | if (ret == 0) { | 1060 | if (0 && ret == 0) { |
1059 | err = 0; | 1061 | err = 0; |
1060 | BUG_ON(btrfs_file_extent_disk_num_blocks(item) != 1); | ||
1061 | if (create && | 1062 | if (create && |
1062 | btrfs_file_extent_generation(item) != trans->transid) { | 1063 | btrfs_file_extent_generation(item) != trans->transid) { |
1063 | struct btrfs_key ins; | 1064 | struct btrfs_key ins; |
@@ -1072,7 +1073,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1072 | blocknr = ins.objectid; | 1073 | blocknr = ins.objectid; |
1073 | 1074 | ||
1074 | } | 1075 | } |
1075 | map_bh(result, inode->i_sb, blocknr); | ||
1076 | btrfs_map_bh_to_logical(root, result, blocknr); | 1076 | btrfs_map_bh_to_logical(root, result, blocknr); |
1077 | goto out; | 1077 | goto out; |
1078 | } | 1078 | } |
@@ -1231,6 +1231,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
1231 | struct file *file, | 1231 | struct file *file, |
1232 | struct page **pages, | 1232 | struct page **pages, |
1233 | size_t num_pages, | 1233 | size_t num_pages, |
1234 | u64 extent_offset, | ||
1234 | loff_t pos, | 1235 | loff_t pos, |
1235 | size_t write_bytes) | 1236 | size_t write_bytes) |
1236 | { | 1237 | { |
@@ -1250,6 +1251,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
1250 | trans = btrfs_start_transaction(root, 1); | 1251 | trans = btrfs_start_transaction(root, 1); |
1251 | btrfs_csum_file_block(trans, root, inode->i_ino, | 1252 | btrfs_csum_file_block(trans, root, inode->i_ino, |
1252 | pages[i]->index << PAGE_CACHE_SHIFT, | 1253 | pages[i]->index << PAGE_CACHE_SHIFT, |
1254 | extent_offset, | ||
1253 | kmap(pages[i]), PAGE_CACHE_SIZE); | 1255 | kmap(pages[i]), PAGE_CACHE_SIZE); |
1254 | kunmap(pages[i]); | 1256 | kunmap(pages[i]); |
1255 | SetPageChecked(pages[i]); | 1257 | SetPageChecked(pages[i]); |
@@ -1279,7 +1281,8 @@ static int prepare_pages(struct btrfs_trans_handle *trans, | |||
1279 | loff_t pos, | 1281 | loff_t pos, |
1280 | unsigned long first_index, | 1282 | unsigned long first_index, |
1281 | unsigned long last_index, | 1283 | unsigned long last_index, |
1282 | size_t write_bytes) | 1284 | size_t write_bytes, |
1285 | u64 alloc_extent_start) | ||
1283 | { | 1286 | { |
1284 | int i; | 1287 | int i; |
1285 | unsigned long index = pos >> PAGE_CACHE_SHIFT; | 1288 | unsigned long index = pos >> PAGE_CACHE_SHIFT; |
@@ -1288,6 +1291,8 @@ static int prepare_pages(struct btrfs_trans_handle *trans, | |||
1288 | int err = 0; | 1291 | int err = 0; |
1289 | int ret; | 1292 | int ret; |
1290 | int this_write; | 1293 | int this_write; |
1294 | struct buffer_head *bh; | ||
1295 | struct buffer_head *head; | ||
1291 | loff_t isize = i_size_read(inode); | 1296 | loff_t isize = i_size_read(inode); |
1292 | 1297 | ||
1293 | memset(pages, 0, num_pages * sizeof(struct page *)); | 1298 | memset(pages, 0, num_pages * sizeof(struct page *)); |
@@ -1307,14 +1312,20 @@ static int prepare_pages(struct btrfs_trans_handle *trans, | |||
1307 | BUG_ON(ret); | 1312 | BUG_ON(ret); |
1308 | lock_page(pages[i]); | 1313 | lock_page(pages[i]); |
1309 | } | 1314 | } |
1310 | ret = nobh_prepare_write(pages[i], offset, | 1315 | create_empty_buffers(pages[i], root->fs_info->sb->s_blocksize, |
1311 | offset + this_write, | 1316 | (1 << BH_Uptodate)); |
1312 | btrfs_get_block); | 1317 | head = page_buffers(pages[i]); |
1318 | bh = head; | ||
1319 | do { | ||
1320 | err = btrfs_map_bh_to_logical(root, bh, | ||
1321 | alloc_extent_start); | ||
1322 | BUG_ON(err); | ||
1323 | if (err) | ||
1324 | goto failed_truncate; | ||
1325 | bh = bh->b_this_page; | ||
1326 | alloc_extent_start++; | ||
1327 | } while (bh != head); | ||
1313 | pos += this_write; | 1328 | pos += this_write; |
1314 | if (ret) { | ||
1315 | err = ret; | ||
1316 | goto failed_truncate; | ||
1317 | } | ||
1318 | WARN_ON(this_write > write_bytes); | 1329 | WARN_ON(this_write > write_bytes); |
1319 | write_bytes -= this_write; | 1330 | write_bytes -= this_write; |
1320 | } | 1331 | } |
@@ -1343,11 +1354,23 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1343 | struct page *pages[1]; | 1354 | struct page *pages[1]; |
1344 | unsigned long first_index; | 1355 | unsigned long first_index; |
1345 | unsigned long last_index; | 1356 | unsigned long last_index; |
1357 | u64 start_pos; | ||
1358 | u64 num_blocks; | ||
1359 | u64 alloc_extent_start; | ||
1360 | u64 orig_extent_start; | ||
1361 | struct btrfs_trans_handle *trans; | ||
1346 | 1362 | ||
1347 | if (file->f_flags & O_DIRECT) | 1363 | if (file->f_flags & O_DIRECT) |
1348 | return -EINVAL; | 1364 | return -EINVAL; |
1349 | pos = *ppos; | 1365 | pos = *ppos; |
1350 | 1366 | ||
1367 | start_pos = pos & ~(root->blocksize - 1); | ||
1368 | /* FIXME */ | ||
1369 | if (start_pos != pos) | ||
1370 | return -EINVAL; | ||
1371 | num_blocks = (count + pos - start_pos + root->blocksize - 1) >> | ||
1372 | inode->i_blkbits; | ||
1373 | |||
1351 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | 1374 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); |
1352 | current->backing_dev_info = inode->i_mapping->backing_dev_info; | 1375 | current->backing_dev_info = inode->i_mapping->backing_dev_info; |
1353 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | 1376 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); |
@@ -1362,20 +1385,41 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1362 | mutex_lock(&inode->i_mutex); | 1385 | mutex_lock(&inode->i_mutex); |
1363 | first_index = pos >> PAGE_CACHE_SHIFT; | 1386 | first_index = pos >> PAGE_CACHE_SHIFT; |
1364 | last_index = (pos + count) >> PAGE_CACHE_SHIFT; | 1387 | last_index = (pos + count) >> PAGE_CACHE_SHIFT; |
1388 | |||
1389 | mutex_lock(&root->fs_info->fs_mutex); | ||
1390 | trans = btrfs_start_transaction(root, 1); | ||
1391 | if (!trans) { | ||
1392 | err = -ENOMEM; | ||
1393 | goto out_unlock; | ||
1394 | } | ||
1395 | ret = btrfs_alloc_file_extent(trans, root, inode->i_ino, | ||
1396 | start_pos, num_blocks, 1, | ||
1397 | &alloc_extent_start); | ||
1398 | BUG_ON(ret); | ||
1399 | |||
1400 | orig_extent_start = start_pos; | ||
1401 | ret = btrfs_end_transaction(trans, root); | ||
1402 | BUG_ON(ret); | ||
1403 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1404 | |||
1365 | while(count > 0) { | 1405 | while(count > 0) { |
1366 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); | 1406 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); |
1367 | size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset); | 1407 | size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset); |
1368 | size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >> | 1408 | size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >> |
1369 | PAGE_CACHE_SHIFT; | 1409 | PAGE_CACHE_SHIFT; |
1370 | ret = prepare_pages(NULL, root, file, pages, num_pages, | 1410 | ret = prepare_pages(NULL, root, file, pages, num_pages, |
1371 | pos, first_index, last_index, write_bytes); | 1411 | pos, first_index, last_index, |
1412 | write_bytes, alloc_extent_start); | ||
1372 | BUG_ON(ret); | 1413 | BUG_ON(ret); |
1414 | /* FIXME blocks != pagesize */ | ||
1415 | alloc_extent_start += num_pages; | ||
1373 | ret = btrfs_copy_from_user(pos, num_pages, | 1416 | ret = btrfs_copy_from_user(pos, num_pages, |
1374 | write_bytes, pages, buf); | 1417 | write_bytes, pages, buf); |
1375 | BUG_ON(ret); | 1418 | BUG_ON(ret); |
1376 | 1419 | ||
1377 | ret = dirty_and_release_pages(NULL, root, file, pages, | 1420 | ret = dirty_and_release_pages(NULL, root, file, pages, |
1378 | num_pages, pos, write_bytes); | 1421 | num_pages, orig_extent_start, |
1422 | pos, write_bytes); | ||
1379 | BUG_ON(ret); | 1423 | BUG_ON(ret); |
1380 | btrfs_drop_pages(pages, num_pages); | 1424 | btrfs_drop_pages(pages, num_pages); |
1381 | 1425 | ||
@@ -1387,6 +1431,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1387 | balance_dirty_pages_ratelimited(inode->i_mapping); | 1431 | balance_dirty_pages_ratelimited(inode->i_mapping); |
1388 | cond_resched(); | 1432 | cond_resched(); |
1389 | } | 1433 | } |
1434 | out_unlock: | ||
1390 | mutex_unlock(&inode->i_mutex); | 1435 | mutex_unlock(&inode->i_mutex); |
1391 | out: | 1436 | out: |
1392 | *ppos = pos; | 1437 | *ppos = pos; |
@@ -1806,8 +1851,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1806 | &new_root_item); | 1851 | &new_root_item); |
1807 | BUG_ON(ret); | 1852 | BUG_ON(ret); |
1808 | 1853 | ||
1809 | printk("adding snapshot name %.*s root %Lu %Lu %u\n", namelen, name, key.objectid, key.offset, key.flags); | ||
1810 | |||
1811 | /* | 1854 | /* |
1812 | * insert the directory item | 1855 | * insert the directory item |
1813 | */ | 1856 | */ |