diff options
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 30 | ||||
-rw-r--r-- | fs/btrfs/super.c | 213 |
3 files changed, 214 insertions, 32 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e8f741167c6b..756ea9d0123b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1198,5 +1198,8 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | |||
1198 | struct btrfs_path *path, | 1198 | struct btrfs_path *path, |
1199 | u64 objectid, u64 offset, | 1199 | u64 objectid, u64 offset, |
1200 | int cow); | 1200 | int cow); |
1201 | int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | ||
1202 | struct btrfs_root *root, struct btrfs_path *path, | ||
1203 | u64 isize); | ||
1201 | /* super.c */ | 1204 | /* super.c */ |
1202 | #endif | 1205 | #endif |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 7990b5742114..0782e924ddeb 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "ctree.h" | 2 | #include "ctree.h" |
3 | #include "disk-io.h" | 3 | #include "disk-io.h" |
4 | #include "transaction.h" | 4 | #include "transaction.h" |
5 | #include "print-tree.h" | ||
5 | 6 | ||
6 | #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ | 7 | #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ |
7 | sizeof(struct btrfs_item) * 2) / \ | 8 | sizeof(struct btrfs_item) * 2) / \ |
@@ -27,6 +28,10 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, | |||
27 | 28 | ||
28 | ret = btrfs_insert_empty_item(trans, root, path, &file_key, | 29 | ret = btrfs_insert_empty_item(trans, root, path, &file_key, |
29 | sizeof(*item)); | 30 | sizeof(*item)); |
31 | if (ret) { | ||
32 | printk("failed to insert %Lu %Lu ret %d\n", objectid, pos, ret); | ||
33 | btrfs_print_leaf(root, btrfs_buffer_leaf(path->nodes[0])); | ||
34 | } | ||
30 | BUG_ON(ret); | 35 | BUG_ON(ret); |
31 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 36 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
32 | struct btrfs_file_extent_item); | 37 | struct btrfs_file_extent_item); |
@@ -218,6 +223,31 @@ fail: | |||
218 | return ret; | 223 | return ret; |
219 | } | 224 | } |
220 | 225 | ||
226 | int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | ||
227 | struct btrfs_root *root, struct btrfs_path *path, | ||
228 | u64 isize) | ||
229 | { | ||
230 | struct btrfs_key key; | ||
231 | struct btrfs_leaf *leaf = btrfs_buffer_leaf(path->nodes[0]); | ||
232 | int slot = path->slots[0]; | ||
233 | int ret; | ||
234 | u32 new_item_size; | ||
235 | u64 new_item_span; | ||
236 | u64 blocks; | ||
237 | |||
238 | btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key); | ||
239 | if (isize <= key.offset) | ||
240 | return 0; | ||
241 | new_item_span = isize - key.offset; | ||
242 | blocks = (new_item_span + root->blocksize - 1) / root->blocksize; | ||
243 | new_item_size = blocks * BTRFS_CRC32_SIZE; | ||
244 | if (new_item_size >= btrfs_item_size(leaf->items + slot)) | ||
245 | return 0; | ||
246 | ret = btrfs_truncate_item(trans, root, path, new_item_size); | ||
247 | BUG_ON(ret); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
221 | int btrfs_csum_verify_file_block(struct btrfs_root *root, | 251 | int btrfs_csum_verify_file_block(struct btrfs_root *root, |
222 | u64 objectid, u64 offset, | 252 | u64 objectid, u64 offset, |
223 | char *data, size_t len) | 253 | char *data, size_t len) |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 5b87c4e9d491..0eb64d6eaf9d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -36,6 +36,13 @@ static struct address_space_operations btrfs_aops; | |||
36 | static struct address_space_operations btrfs_symlink_aops; | 36 | static struct address_space_operations btrfs_symlink_aops; |
37 | static struct file_operations btrfs_file_operations; | 37 | static struct file_operations btrfs_file_operations; |
38 | 38 | ||
39 | static int drop_extents(struct btrfs_trans_handle *trans, | ||
40 | struct btrfs_root *root, | ||
41 | struct inode *inode, | ||
42 | u64 start, u64 end, u64 *hint_block); | ||
43 | static int btrfs_get_block(struct inode *inode, sector_t iblock, | ||
44 | struct buffer_head *result, int create); | ||
45 | |||
39 | static void btrfs_read_locked_inode(struct inode *inode) | 46 | static void btrfs_read_locked_inode(struct inode *inode) |
40 | { | 47 | { |
41 | struct btrfs_path *path; | 48 | struct btrfs_path *path; |
@@ -381,10 +388,12 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
381 | struct btrfs_disk_key *found_key; | 388 | struct btrfs_disk_key *found_key; |
382 | u32 found_type; | 389 | u32 found_type; |
383 | struct btrfs_leaf *leaf; | 390 | struct btrfs_leaf *leaf; |
384 | struct btrfs_file_extent_item *fi = NULL; | 391 | struct btrfs_file_extent_item *fi; |
385 | u64 extent_start = 0; | 392 | u64 extent_start = 0; |
386 | u64 extent_num_blocks = 0; | 393 | u64 extent_num_blocks = 0; |
394 | u64 item_end = 0; | ||
387 | int found_extent; | 395 | int found_extent; |
396 | int del_item; | ||
388 | 397 | ||
389 | path = btrfs_alloc_path(); | 398 | path = btrfs_alloc_path(); |
390 | BUG_ON(!path); | 399 | BUG_ON(!path); |
@@ -394,6 +403,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
394 | key.flags = (u32)-1; | 403 | key.flags = (u32)-1; |
395 | while(1) { | 404 | while(1) { |
396 | btrfs_init_path(path); | 405 | btrfs_init_path(path); |
406 | fi = NULL; | ||
397 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 407 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
398 | if (ret < 0) { | 408 | if (ret < 0) { |
399 | goto error; | 409 | goto error; |
@@ -413,16 +423,52 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
413 | found_type != BTRFS_DIR_INDEX_KEY && | 423 | found_type != BTRFS_DIR_INDEX_KEY && |
414 | found_type != BTRFS_EXTENT_DATA_KEY) | 424 | found_type != BTRFS_EXTENT_DATA_KEY) |
415 | break; | 425 | break; |
416 | if (btrfs_disk_key_offset(found_key) < inode->i_size) | 426 | item_end = btrfs_disk_key_offset(found_key); |
417 | break; | 427 | if (found_type == BTRFS_EXTENT_DATA_KEY) { |
418 | found_extent = 0; | ||
419 | if (btrfs_disk_key_type(found_key) == BTRFS_EXTENT_DATA_KEY) { | ||
420 | fi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), | 428 | fi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), |
421 | path->slots[0], | 429 | path->slots[0], |
422 | struct btrfs_file_extent_item); | 430 | struct btrfs_file_extent_item); |
423 | if (btrfs_file_extent_type(fi) != | 431 | if (btrfs_file_extent_type(fi) != |
424 | BTRFS_FILE_EXTENT_INLINE) { | 432 | BTRFS_FILE_EXTENT_INLINE) { |
425 | u64 num_dec; | 433 | item_end += btrfs_file_extent_num_blocks(fi) << |
434 | inode->i_blkbits; | ||
435 | } | ||
436 | } | ||
437 | if (found_type == BTRFS_CSUM_ITEM_KEY) { | ||
438 | ret = btrfs_csum_truncate(trans, root, path, | ||
439 | inode->i_size); | ||
440 | BUG_ON(ret); | ||
441 | } | ||
442 | if (item_end < inode->i_size) { | ||
443 | if (found_type) { | ||
444 | btrfs_set_key_type(&key, found_type - 1); | ||
445 | continue; | ||
446 | } | ||
447 | break; | ||
448 | } | ||
449 | if (btrfs_disk_key_offset(found_key) >= inode->i_size) | ||
450 | del_item = 1; | ||
451 | else | ||
452 | del_item = 0; | ||
453 | found_extent = 0; | ||
454 | |||
455 | if (found_type == BTRFS_EXTENT_DATA_KEY && | ||
456 | btrfs_file_extent_type(fi) != | ||
457 | BTRFS_FILE_EXTENT_INLINE) { | ||
458 | u64 num_dec; | ||
459 | if (!del_item) { | ||
460 | u64 orig_num_blocks = | ||
461 | btrfs_file_extent_num_blocks(fi); | ||
462 | extent_num_blocks = inode->i_size - | ||
463 | btrfs_disk_key_offset(found_key) + | ||
464 | root->blocksize - 1; | ||
465 | extent_num_blocks >>= inode->i_blkbits; | ||
466 | btrfs_set_file_extent_num_blocks(fi, | ||
467 | extent_num_blocks); | ||
468 | inode->i_blocks -= (orig_num_blocks - | ||
469 | extent_num_blocks) << 3; | ||
470 | mark_buffer_dirty(path->nodes[0]); | ||
471 | } else { | ||
426 | extent_start = | 472 | extent_start = |
427 | btrfs_file_extent_disk_blocknr(fi); | 473 | btrfs_file_extent_disk_blocknr(fi); |
428 | extent_num_blocks = | 474 | extent_num_blocks = |
@@ -435,8 +481,12 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
435 | } | 481 | } |
436 | } | 482 | } |
437 | } | 483 | } |
438 | ret = btrfs_del_item(trans, root, path); | 484 | if (del_item) { |
439 | BUG_ON(ret); | 485 | ret = btrfs_del_item(trans, root, path); |
486 | BUG_ON(ret); | ||
487 | } else { | ||
488 | break; | ||
489 | } | ||
440 | btrfs_release_path(root, path); | 490 | btrfs_release_path(root, path); |
441 | if (found_extent) { | 491 | if (found_extent) { |
442 | ret = btrfs_free_extent(trans, root, extent_start, | 492 | ret = btrfs_free_extent(trans, root, extent_start, |
@@ -452,6 +502,68 @@ error: | |||
452 | return ret; | 502 | return ret; |
453 | } | 503 | } |
454 | 504 | ||
505 | static int btrfs_truncate_page(struct address_space *mapping, loff_t from) | ||
506 | { | ||
507 | struct inode *inode = mapping->host; | ||
508 | unsigned blocksize = 1 << inode->i_blkbits; | ||
509 | pgoff_t index = from >> PAGE_CACHE_SHIFT; | ||
510 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
511 | struct page *page; | ||
512 | char *kaddr; | ||
513 | int ret = 0; | ||
514 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
515 | u64 alloc_hint; | ||
516 | struct btrfs_key ins; | ||
517 | struct btrfs_trans_handle *trans; | ||
518 | |||
519 | if ((offset & (blocksize - 1)) == 0) | ||
520 | goto out; | ||
521 | |||
522 | ret = -ENOMEM; | ||
523 | page = grab_cache_page(mapping, index); | ||
524 | if (!page) | ||
525 | goto out; | ||
526 | |||
527 | if (!PageUptodate(page)) { | ||
528 | ret = mpage_readpage(page, btrfs_get_block); | ||
529 | lock_page(page); | ||
530 | if (!PageUptodate(page)) { | ||
531 | ret = -EIO; | ||
532 | goto out; | ||
533 | } | ||
534 | } | ||
535 | mutex_lock(&root->fs_info->fs_mutex); | ||
536 | trans = btrfs_start_transaction(root, 1); | ||
537 | btrfs_set_trans_block_group(trans, inode); | ||
538 | |||
539 | ret = drop_extents(trans, root, inode, page->index << PAGE_CACHE_SHIFT, | ||
540 | (page->index + 1) << PAGE_CACHE_SHIFT, &alloc_hint); | ||
541 | BUG_ON(ret); | ||
542 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, 1, | ||
543 | alloc_hint, (u64)-1, &ins, 1); | ||
544 | BUG_ON(ret); | ||
545 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | ||
546 | page->index << PAGE_CACHE_SHIFT, | ||
547 | ins.objectid, 1, 1); | ||
548 | BUG_ON(ret); | ||
549 | SetPageChecked(page); | ||
550 | kaddr = kmap(page); | ||
551 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | ||
552 | flush_dcache_page(page); | ||
553 | btrfs_csum_file_block(trans, root, inode->i_ino, | ||
554 | page->index << PAGE_CACHE_SHIFT, | ||
555 | kaddr, PAGE_CACHE_SIZE); | ||
556 | kunmap(page); | ||
557 | btrfs_end_transaction(trans, root); | ||
558 | mutex_unlock(&root->fs_info->fs_mutex); | ||
559 | |||
560 | set_page_dirty(page); | ||
561 | unlock_page(page); | ||
562 | page_cache_release(page); | ||
563 | out: | ||
564 | return ret; | ||
565 | } | ||
566 | |||
455 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | 567 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) |
456 | { | 568 | { |
457 | struct inode *inode = dentry->d_inode; | 569 | struct inode *inode = dentry->d_inode; |
@@ -469,8 +581,11 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
469 | u64 pos = (inode->i_size + mask) & ~mask; | 581 | u64 pos = (inode->i_size + mask) & ~mask; |
470 | u64 hole_size; | 582 | u64 hole_size; |
471 | 583 | ||
472 | if (attr->ia_size < pos) | 584 | if (attr->ia_size <= pos) |
473 | goto out; | 585 | goto out; |
586 | |||
587 | btrfs_truncate_page(inode->i_mapping, inode->i_size); | ||
588 | |||
474 | hole_size = (attr->ia_size - pos + mask) & ~mask; | 589 | hole_size = (attr->ia_size - pos + mask) & ~mask; |
475 | hole_size >>= inode->i_blkbits; | 590 | hole_size >>= inode->i_blkbits; |
476 | 591 | ||
@@ -483,10 +598,9 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
483 | btrfs_end_transaction(trans, root); | 598 | btrfs_end_transaction(trans, root); |
484 | mutex_unlock(&root->fs_info->fs_mutex); | 599 | mutex_unlock(&root->fs_info->fs_mutex); |
485 | } | 600 | } |
486 | 601 | out: | |
487 | err = inode_setattr(inode, attr); | 602 | err = inode_setattr(inode, attr); |
488 | 603 | ||
489 | out: | ||
490 | return err; | 604 | return err; |
491 | } | 605 | } |
492 | static void btrfs_delete_inode(struct inode *inode) | 606 | static void btrfs_delete_inode(struct inode *inode) |
@@ -1161,17 +1275,30 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1161 | u64 extent_end = 0; | 1275 | u64 extent_end = 0; |
1162 | u64 objectid = inode->i_ino; | 1276 | u64 objectid = inode->i_ino; |
1163 | u32 found_type; | 1277 | u32 found_type; |
1278 | u64 alloc_hint = 0; | ||
1164 | struct btrfs_path *path; | 1279 | struct btrfs_path *path; |
1165 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1280 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1166 | struct btrfs_file_extent_item *item; | 1281 | struct btrfs_file_extent_item *item; |
1167 | struct btrfs_leaf *leaf; | 1282 | struct btrfs_leaf *leaf; |
1168 | struct btrfs_disk_key *found_key; | 1283 | struct btrfs_disk_key *found_key; |
1284 | struct btrfs_trans_handle *trans = NULL; | ||
1169 | 1285 | ||
1170 | path = btrfs_alloc_path(); | 1286 | path = btrfs_alloc_path(); |
1171 | BUG_ON(!path); | 1287 | BUG_ON(!path); |
1172 | btrfs_init_path(path); | 1288 | btrfs_init_path(path); |
1173 | if (create) { | 1289 | if (create) { |
1174 | WARN_ON(1); | 1290 | WARN_ON(1); |
1291 | /* this almost but not quite works */ | ||
1292 | trans = btrfs_start_transaction(root, 1); | ||
1293 | if (!trans) { | ||
1294 | err = -ENOMEM; | ||
1295 | goto out; | ||
1296 | } | ||
1297 | ret = drop_extents(trans, root, inode, | ||
1298 | iblock << inode->i_blkbits, | ||
1299 | (iblock + 1) << inode->i_blkbits, | ||
1300 | &alloc_hint); | ||
1301 | BUG_ON(ret); | ||
1175 | } | 1302 | } |
1176 | 1303 | ||
1177 | ret = btrfs_lookup_file_extent(NULL, root, path, | 1304 | ret = btrfs_lookup_file_extent(NULL, root, path, |
@@ -1185,7 +1312,7 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1185 | if (ret != 0) { | 1312 | if (ret != 0) { |
1186 | if (path->slots[0] == 0) { | 1313 | if (path->slots[0] == 0) { |
1187 | btrfs_release_path(root, path); | 1314 | btrfs_release_path(root, path); |
1188 | goto out; | 1315 | goto not_found; |
1189 | } | 1316 | } |
1190 | path->slots[0]--; | 1317 | path->slots[0]--; |
1191 | } | 1318 | } |
@@ -1203,7 +1330,7 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1203 | found_type != BTRFS_EXTENT_DATA_KEY) { | 1330 | found_type != BTRFS_EXTENT_DATA_KEY) { |
1204 | extent_end = 0; | 1331 | extent_end = 0; |
1205 | extent_start = 0; | 1332 | extent_start = 0; |
1206 | goto out; | 1333 | goto not_found; |
1207 | } | 1334 | } |
1208 | found_type = btrfs_file_extent_type(item); | 1335 | found_type = btrfs_file_extent_type(item); |
1209 | extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key); | 1336 | extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key); |
@@ -1211,7 +1338,7 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1211 | extent_start = extent_start >> inode->i_blkbits; | 1338 | extent_start = extent_start >> inode->i_blkbits; |
1212 | extent_end = extent_start + btrfs_file_extent_num_blocks(item); | 1339 | extent_end = extent_start + btrfs_file_extent_num_blocks(item); |
1213 | err = 0; | 1340 | err = 0; |
1214 | if (blocknr == 0) | 1341 | if (btrfs_file_extent_disk_blocknr(item) == 0) |
1215 | goto out; | 1342 | goto out; |
1216 | if (iblock >= extent_start && iblock < extent_end) { | 1343 | if (iblock >= extent_start && iblock < extent_end) { |
1217 | btrfs_map_bh_to_logical(root, result, blocknr + | 1344 | btrfs_map_bh_to_logical(root, result, blocknr + |
@@ -1227,7 +1354,7 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1227 | extent_end = (extent_start + size) >> inode->i_blkbits; | 1354 | extent_end = (extent_start + size) >> inode->i_blkbits; |
1228 | extent_start >>= inode->i_blkbits; | 1355 | extent_start >>= inode->i_blkbits; |
1229 | if (iblock < extent_start || iblock > extent_end) { | 1356 | if (iblock < extent_start || iblock > extent_end) { |
1230 | goto out; | 1357 | goto not_found; |
1231 | } | 1358 | } |
1232 | ptr = btrfs_file_extent_inline_start(item); | 1359 | ptr = btrfs_file_extent_inline_start(item); |
1233 | map = kmap(result->b_page); | 1360 | map = kmap(result->b_page); |
@@ -1239,7 +1366,24 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1239 | SetPageChecked(result->b_page); | 1366 | SetPageChecked(result->b_page); |
1240 | btrfs_map_bh_to_logical(root, result, 0); | 1367 | btrfs_map_bh_to_logical(root, result, 0); |
1241 | } | 1368 | } |
1369 | not_found: | ||
1370 | if (create) { | ||
1371 | struct btrfs_key ins; | ||
1372 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, | ||
1373 | 1, alloc_hint, (u64)-1, | ||
1374 | &ins, 1); | ||
1375 | BUG_ON(ret); | ||
1376 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | ||
1377 | iblock << inode->i_blkbits, | ||
1378 | ins.objectid, ins.offset, | ||
1379 | ins.offset); | ||
1380 | BUG_ON(ret); | ||
1381 | SetPageChecked(result->b_page); | ||
1382 | btrfs_map_bh_to_logical(root, result, ins.objectid); | ||
1383 | } | ||
1242 | out: | 1384 | out: |
1385 | if (trans) | ||
1386 | err = btrfs_end_transaction(trans, root); | ||
1243 | btrfs_free_path(path); | 1387 | btrfs_free_path(path); |
1244 | return err; | 1388 | return err; |
1245 | } | 1389 | } |
@@ -1258,7 +1402,7 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, | |||
1258 | static int btrfs_prepare_write(struct file *file, struct page *page, | 1402 | static int btrfs_prepare_write(struct file *file, struct page *page, |
1259 | unsigned from, unsigned to) | 1403 | unsigned from, unsigned to) |
1260 | { | 1404 | { |
1261 | return nobh_prepare_write(page, from, to, btrfs_get_block); | 1405 | return block_prepare_write(page, from, to, btrfs_get_block); |
1262 | } | 1406 | } |
1263 | 1407 | ||
1264 | static void btrfs_write_super(struct super_block *sb) | 1408 | static void btrfs_write_super(struct super_block *sb) |
@@ -1500,12 +1644,13 @@ static void btrfs_truncate(struct inode *inode) | |||
1500 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | 1644 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) |
1501 | return; | 1645 | return; |
1502 | 1646 | ||
1503 | nobh_truncate_page(inode->i_mapping, inode->i_size); | 1647 | btrfs_truncate_page(inode->i_mapping, inode->i_size); |
1504 | 1648 | ||
1505 | /* FIXME, add redo link to tree so we don't leak on crash */ | ||
1506 | mutex_lock(&root->fs_info->fs_mutex); | 1649 | mutex_lock(&root->fs_info->fs_mutex); |
1507 | trans = btrfs_start_transaction(root, 1); | 1650 | trans = btrfs_start_transaction(root, 1); |
1508 | btrfs_set_trans_block_group(trans, inode); | 1651 | btrfs_set_trans_block_group(trans, inode); |
1652 | |||
1653 | /* FIXME, add redo link to tree so we don't leak on crash */ | ||
1509 | ret = btrfs_truncate_in_trans(trans, root, inode); | 1654 | ret = btrfs_truncate_in_trans(trans, root, inode); |
1510 | BUG_ON(ret); | 1655 | BUG_ON(ret); |
1511 | btrfs_update_inode(trans, root, inode); | 1656 | btrfs_update_inode(trans, root, inode); |
@@ -1515,10 +1660,6 @@ static void btrfs_truncate(struct inode *inode) | |||
1515 | btrfs_btree_balance_dirty(root); | 1660 | btrfs_btree_balance_dirty(root); |
1516 | } | 1661 | } |
1517 | 1662 | ||
1518 | /* | ||
1519 | * Make sure any changes to nobh_commit_write() are reflected in | ||
1520 | * nobh_truncate_page(), since it doesn't call commit_write(). | ||
1521 | */ | ||
1522 | static int btrfs_commit_write(struct file *file, struct page *page, | 1663 | static int btrfs_commit_write(struct file *file, struct page *page, |
1523 | unsigned from, unsigned to) | 1664 | unsigned from, unsigned to) |
1524 | { | 1665 | { |
@@ -1528,6 +1669,7 @@ static int btrfs_commit_write(struct file *file, struct page *page, | |||
1528 | 1669 | ||
1529 | SetPageUptodate(page); | 1670 | SetPageUptodate(page); |
1530 | bh = page_buffers(page); | 1671 | bh = page_buffers(page); |
1672 | set_buffer_uptodate(bh); | ||
1531 | if (buffer_mapped(bh) && bh->b_blocknr != 0) { | 1673 | if (buffer_mapped(bh) && bh->b_blocknr != 0) { |
1532 | set_page_dirty(page); | 1674 | set_page_dirty(page); |
1533 | } | 1675 | } |
@@ -1972,8 +2114,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1972 | first_index = pos >> PAGE_CACHE_SHIFT; | 2114 | first_index = pos >> PAGE_CACHE_SHIFT; |
1973 | last_index = (pos + count) >> PAGE_CACHE_SHIFT; | 2115 | last_index = (pos + count) >> PAGE_CACHE_SHIFT; |
1974 | 2116 | ||
1975 | if ((first_index << PAGE_CACHE_SHIFT) < inode->i_size && | 2117 | if ((pos & (PAGE_CACHE_SIZE - 1))) { |
1976 | (pos & (PAGE_CACHE_SIZE - 1))) { | ||
1977 | pinned[0] = grab_cache_page(inode->i_mapping, first_index); | 2118 | pinned[0] = grab_cache_page(inode->i_mapping, first_index); |
1978 | if (!PageUptodate(pinned[0])) { | 2119 | if (!PageUptodate(pinned[0])) { |
1979 | ret = mpage_readpage(pinned[0], btrfs_get_block); | 2120 | ret = mpage_readpage(pinned[0], btrfs_get_block); |
@@ -1983,10 +2124,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1983 | unlock_page(pinned[0]); | 2124 | unlock_page(pinned[0]); |
1984 | } | 2125 | } |
1985 | } | 2126 | } |
1986 | if (first_index != last_index && | 2127 | if ((pos + count) & (PAGE_CACHE_SIZE - 1)) { |
1987 | (last_index << PAGE_CACHE_SHIFT) < inode->i_size && | ||
1988 | pos + count < inode->i_size && | ||
1989 | (count & (PAGE_CACHE_SIZE - 1))) { | ||
1990 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); | 2128 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); |
1991 | if (!PageUptodate(pinned[1])) { | 2129 | if (!PageUptodate(pinned[1])) { |
1992 | ret = mpage_readpage(pinned[1], btrfs_get_block); | 2130 | ret = mpage_readpage(pinned[1], btrfs_get_block); |
@@ -2110,23 +2248,34 @@ static int btrfs_read_actor(read_descriptor_t *desc, struct page *page, | |||
2110 | if (!PageChecked(page)) { | 2248 | if (!PageChecked(page)) { |
2111 | /* FIXME, do it per block */ | 2249 | /* FIXME, do it per block */ |
2112 | struct btrfs_root *root = BTRFS_I(inode)->root; | 2250 | struct btrfs_root *root = BTRFS_I(inode)->root; |
2251 | int ret; | ||
2252 | struct buffer_head *bh; | ||
2253 | |||
2254 | if (page_has_buffers(page)) { | ||
2255 | bh = page_buffers(page); | ||
2256 | if (!buffer_mapped(bh)) { | ||
2257 | SetPageChecked(page); | ||
2258 | goto checked; | ||
2259 | } | ||
2260 | } | ||
2113 | 2261 | ||
2114 | int ret = btrfs_csum_verify_file_block(root, | 2262 | ret = btrfs_csum_verify_file_block(root, |
2115 | page->mapping->host->i_ino, | 2263 | page->mapping->host->i_ino, |
2116 | page->index << PAGE_CACHE_SHIFT, | 2264 | page->index << PAGE_CACHE_SHIFT, |
2117 | kmap(page), PAGE_CACHE_SIZE); | 2265 | kmap(page), PAGE_CACHE_SIZE); |
2118 | if (ret) { | 2266 | if (ret) { |
2119 | if (ret != -ENOENT) { | 2267 | if (ret != -ENOENT) { |
2120 | printk("failed to verify ino %lu page %lu\n", | 2268 | printk("failed to verify ino %lu page %lu ret %d\n", |
2121 | page->mapping->host->i_ino, | 2269 | page->mapping->host->i_ino, |
2122 | page->index); | 2270 | page->index, ret); |
2123 | memset(page_address(page), 0, PAGE_CACHE_SIZE); | 2271 | memset(page_address(page), 1, PAGE_CACHE_SIZE); |
2124 | flush_dcache_page(page); | 2272 | flush_dcache_page(page); |
2125 | } | 2273 | } |
2126 | } | 2274 | } |
2127 | SetPageChecked(page); | 2275 | SetPageChecked(page); |
2128 | kunmap(page); | 2276 | kunmap(page); |
2129 | } | 2277 | } |
2278 | checked: | ||
2130 | /* | 2279 | /* |
2131 | * Faults on the destination of a read are common, so do it before | 2280 | * Faults on the destination of a read are common, so do it before |
2132 | * taking the kmap. | 2281 | * taking the kmap. |