aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-05-24 13:35:57 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-05-24 13:35:57 -0400
commit3a686375629da5d2e2ad019265b66ef113c87455 (patch)
tree1fbbedfcb92aeea38d90955ef11975187ddcc6f3
parent2b8d99a723a3186a69b5bd941a272dbecae9205b (diff)
Btrfs: sparse files!
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent-tree.c14
-rw-r--r--fs/btrfs/file-item.c11
-rw-r--r--fs/btrfs/super.c121
4 files changed, 116 insertions, 31 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 3330004af1a6..e8f741167c6b 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1180,6 +1180,7 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
1180int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 1180int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
1181 struct btrfs_root *root, 1181 struct btrfs_root *root,
1182 u64 objectid, u64 pos, u64 offset, 1182 u64 objectid, u64 pos, u64 offset,
1183 u64 disk_num_blocks,
1183 u64 num_blocks); 1184 u64 num_blocks);
1184int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 1185int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
1185 struct btrfs_root *root, 1186 struct btrfs_root *root,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e3c6bfea3751..a366415e03a6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -443,6 +443,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
443 buf_leaf = btrfs_buffer_leaf(buf); 443 buf_leaf = btrfs_buffer_leaf(buf);
444 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) { 444 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
445 if (leaf) { 445 if (leaf) {
446 u64 disk_blocknr;
446 key = &buf_leaf->items[i].key; 447 key = &buf_leaf->items[i].key;
447 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY) 448 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
448 continue; 449 continue;
@@ -451,8 +452,10 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
451 if (btrfs_file_extent_type(fi) == 452 if (btrfs_file_extent_type(fi) ==
452 BTRFS_FILE_EXTENT_INLINE) 453 BTRFS_FILE_EXTENT_INLINE)
453 continue; 454 continue;
454 ret = btrfs_inc_extent_ref(trans, root, 455 disk_blocknr = btrfs_file_extent_disk_blocknr(fi);
455 btrfs_file_extent_disk_blocknr(fi), 456 if (disk_blocknr == 0)
457 continue;
458 ret = btrfs_inc_extent_ref(trans, root, disk_blocknr,
456 btrfs_file_extent_disk_num_blocks(fi)); 459 btrfs_file_extent_disk_num_blocks(fi));
457 BUG_ON(ret); 460 BUG_ON(ret);
458 } else { 461 } else {
@@ -1248,6 +1251,7 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
1248 leaf = btrfs_buffer_leaf(cur); 1251 leaf = btrfs_buffer_leaf(cur);
1249 nritems = btrfs_header_nritems(&leaf->header); 1252 nritems = btrfs_header_nritems(&leaf->header);
1250 for (i = 0; i < nritems; i++) { 1253 for (i = 0; i < nritems; i++) {
1254 u64 disk_blocknr;
1251 key = &leaf->items[i].key; 1255 key = &leaf->items[i].key;
1252 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY) 1256 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
1253 continue; 1257 continue;
@@ -1258,8 +1262,10 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
1258 * FIXME make sure to insert a trans record that 1262 * FIXME make sure to insert a trans record that
1259 * repeats the snapshot del on crash 1263 * repeats the snapshot del on crash
1260 */ 1264 */
1261 ret = btrfs_free_extent(trans, root, 1265 disk_blocknr = btrfs_file_extent_disk_blocknr(fi);
1262 btrfs_file_extent_disk_blocknr(fi), 1266 if (disk_blocknr == 0)
1267 continue;
1268 ret = btrfs_free_extent(trans, root, disk_blocknr,
1263 btrfs_file_extent_disk_num_blocks(fi), 1269 btrfs_file_extent_disk_num_blocks(fi),
1264 0); 1270 0);
1265 BUG_ON(ret); 1271 BUG_ON(ret);
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index a66709e6d036..7990b5742114 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -9,7 +9,8 @@
9int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 9int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
10 struct btrfs_root *root, 10 struct btrfs_root *root,
11 u64 objectid, u64 pos, 11 u64 objectid, u64 pos,
12 u64 offset, u64 num_blocks) 12 u64 offset, u64 disk_num_blocks,
13 u64 num_blocks)
13{ 14{
14 int ret = 0; 15 int ret = 0;
15 struct btrfs_file_extent_item *item; 16 struct btrfs_file_extent_item *item;
@@ -30,7 +31,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
30 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], 31 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
31 struct btrfs_file_extent_item); 32 struct btrfs_file_extent_item);
32 btrfs_set_file_extent_disk_blocknr(item, offset); 33 btrfs_set_file_extent_disk_blocknr(item, offset);
33 btrfs_set_file_extent_disk_num_blocks(item, num_blocks); 34 btrfs_set_file_extent_disk_num_blocks(item, disk_num_blocks);
34 btrfs_set_file_extent_offset(item, 0); 35 btrfs_set_file_extent_offset(item, 0);
35 btrfs_set_file_extent_num_blocks(item, num_blocks); 36 btrfs_set_file_extent_num_blocks(item, num_blocks);
36 btrfs_set_file_extent_generation(item, trans->transid); 37 btrfs_set_file_extent_generation(item, trans->transid);
@@ -176,14 +177,14 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
176 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || 177 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
177 found_key.objectid != objectid || 178 found_key.objectid != objectid ||
178 csum_offset >= MAX_CSUM_ITEMS(root)) { 179 csum_offset >= MAX_CSUM_ITEMS(root)) {
179 WARN_ON(1);
180 goto insert; 180 goto insert;
181 } 181 }
182 if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) / 182 if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
183 BTRFS_CRC32_SIZE) { 183 BTRFS_CRC32_SIZE) {
184 u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE; 184 u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
185 diff = diff - btrfs_item_size(leaf->items + path->slots[0]); 185 diff = diff - btrfs_item_size(leaf->items + path->slots[0]);
186 WARN_ON(diff != BTRFS_CRC32_SIZE); 186 if (diff != BTRFS_CRC32_SIZE)
187 goto insert;
187 ret = btrfs_extend_item(trans, root, path, diff); 188 ret = btrfs_extend_item(trans, root, path, diff);
188 BUG_ON(ret); 189 BUG_ON(ret);
189 goto csum; 190 goto csum;
@@ -241,7 +242,7 @@ int btrfs_csum_verify_file_block(struct btrfs_root *root,
241 ret = PTR_ERR(item); 242 ret = PTR_ERR(item);
242 /* a csum that isn't present is a preallocated region. */ 243 /* a csum that isn't present is a preallocated region. */
243 if (ret == -ENOENT || ret == -EFBIG) 244 if (ret == -ENOENT || ret == -EFBIG)
244 ret = 1; 245 ret = -ENOENT;
245 goto fail; 246 goto fail;
246 } 247 }
247 248
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index c1a0adde9b1c..5b87c4e9d491 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -17,6 +17,7 @@
17#include "transaction.h" 17#include "transaction.h"
18#include "btrfs_inode.h" 18#include "btrfs_inode.h"
19#include "ioctl.h" 19#include "ioctl.h"
20#include "print-tree.h"
20 21
21struct btrfs_iget_args { 22struct btrfs_iget_args {
22 u64 ino; 23 u64 ino;
@@ -421,14 +422,17 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
421 struct btrfs_file_extent_item); 422 struct btrfs_file_extent_item);
422 if (btrfs_file_extent_type(fi) != 423 if (btrfs_file_extent_type(fi) !=
423 BTRFS_FILE_EXTENT_INLINE) { 424 BTRFS_FILE_EXTENT_INLINE) {
425 u64 num_dec;
424 extent_start = 426 extent_start =
425 btrfs_file_extent_disk_blocknr(fi); 427 btrfs_file_extent_disk_blocknr(fi);
426 extent_num_blocks = 428 extent_num_blocks =
427 btrfs_file_extent_disk_num_blocks(fi); 429 btrfs_file_extent_disk_num_blocks(fi);
428 /* FIXME blocksize != 4096 */ 430 /* FIXME blocksize != 4096 */
429 inode->i_blocks -= 431 num_dec = btrfs_file_extent_num_blocks(fi) << 3;
430 btrfs_file_extent_num_blocks(fi) << 3; 432 if (extent_start != 0) {
431 found_extent = 1; 433 found_extent = 1;
434 inode->i_blocks -= num_dec;
435 }
432 } 436 }
433 } 437 }
434 ret = btrfs_del_item(trans, root, path); 438 ret = btrfs_del_item(trans, root, path);
@@ -448,6 +452,43 @@ error:
448 return ret; 452 return ret;
449} 453}
450 454
455static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
456{
457 struct inode *inode = dentry->d_inode;
458 int err;
459
460 err = inode_change_ok(inode, attr);
461 if (err)
462 return err;
463
464 if (S_ISREG(inode->i_mode) &&
465 attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
466 struct btrfs_trans_handle *trans;
467 struct btrfs_root *root = BTRFS_I(inode)->root;
468 u64 mask = root->blocksize - 1;
469 u64 pos = (inode->i_size + mask) & ~mask;
470 u64 hole_size;
471
472 if (attr->ia_size < pos)
473 goto out;
474 hole_size = (attr->ia_size - pos + mask) & ~mask;
475 hole_size >>= inode->i_blkbits;
476
477 mutex_lock(&root->fs_info->fs_mutex);
478 trans = btrfs_start_transaction(root, 1);
479 btrfs_set_trans_block_group(trans, inode);
480 err = btrfs_insert_file_extent(trans, root, inode->i_ino,
481 pos, 0, 0, hole_size);
482 BUG_ON(err);
483 btrfs_end_transaction(trans, root);
484 mutex_unlock(&root->fs_info->fs_mutex);
485 }
486
487 err = inode_setattr(inode, attr);
488
489out:
490 return err;
491}
451static void btrfs_delete_inode(struct inode *inode) 492static void btrfs_delete_inode(struct inode *inode)
452{ 493{
453 struct btrfs_trans_handle *trans; 494 struct btrfs_trans_handle *trans;
@@ -1169,8 +1210,10 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
1169 if (found_type == BTRFS_FILE_EXTENT_REG) { 1210 if (found_type == BTRFS_FILE_EXTENT_REG) {
1170 extent_start = extent_start >> inode->i_blkbits; 1211 extent_start = extent_start >> inode->i_blkbits;
1171 extent_end = extent_start + btrfs_file_extent_num_blocks(item); 1212 extent_end = extent_start + btrfs_file_extent_num_blocks(item);
1213 err = 0;
1214 if (blocknr == 0)
1215 goto out;
1172 if (iblock >= extent_start && iblock < extent_end) { 1216 if (iblock >= extent_start && iblock < extent_end) {
1173 err = 0;
1174 btrfs_map_bh_to_logical(root, result, blocknr + 1217 btrfs_map_bh_to_logical(root, result, blocknr +
1175 iblock - extent_start); 1218 iblock - extent_start);
1176 goto out; 1219 goto out;
@@ -1591,7 +1634,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
1591 ptr, bh->b_data, offset + write_bytes); 1634 ptr, bh->b_data, offset + write_bytes);
1592 mark_buffer_dirty(path->nodes[0]); 1635 mark_buffer_dirty(path->nodes[0]);
1593 btrfs_free_path(path); 1636 btrfs_free_path(path);
1594 } else { 1637 } else if (buffer_mapped(bh)) {
1595 btrfs_csum_file_block(trans, root, inode->i_ino, 1638 btrfs_csum_file_block(trans, root, inode->i_ino,
1596 pages[i]->index << PAGE_CACHE_SHIFT, 1639 pages[i]->index << PAGE_CACHE_SHIFT,
1597 kmap(pages[i]), PAGE_CACHE_SIZE); 1640 kmap(pages[i]), PAGE_CACHE_SIZE);
@@ -1693,15 +1736,24 @@ static int drop_extents(struct btrfs_trans_handle *trans,
1693 goto out; 1736 goto out;
1694 } 1737 }
1695 1738
1696 search_start = extent_end; 1739 if (found_inline) {
1740 u64 mask = root->blocksize - 1;
1741 search_start = (extent_end + mask) & ~mask;
1742 } else
1743 search_start = extent_end;
1697 1744
1698 if (end < extent_end && end >= key.offset) { 1745 if (end < extent_end && end >= key.offset) {
1699 if (found_extent) { 1746 if (found_extent) {
1747 u64 disk_blocknr =
1748 btrfs_file_extent_disk_blocknr(extent);
1749 u64 disk_num_blocks =
1750 btrfs_file_extent_disk_num_blocks(extent);
1700 memcpy(&old, extent, sizeof(old)); 1751 memcpy(&old, extent, sizeof(old));
1701 ret = btrfs_inc_extent_ref(trans, root, 1752 if (disk_blocknr != 0) {
1702 btrfs_file_extent_disk_blocknr(&old), 1753 ret = btrfs_inc_extent_ref(trans, root,
1703 btrfs_file_extent_disk_num_blocks(&old)); 1754 disk_blocknr, disk_num_blocks);
1704 BUG_ON(ret); 1755 BUG_ON(ret);
1756 }
1705 } 1757 }
1706 WARN_ON(found_inline); 1758 WARN_ON(found_inline);
1707 bookend = 1; 1759 bookend = 1;
@@ -1719,7 +1771,10 @@ static int drop_extents(struct btrfs_trans_handle *trans,
1719 old_num = btrfs_file_extent_num_blocks(extent); 1771 old_num = btrfs_file_extent_num_blocks(extent);
1720 *hint_block = 1772 *hint_block =
1721 btrfs_file_extent_disk_blocknr(extent); 1773 btrfs_file_extent_disk_blocknr(extent);
1722 inode->i_blocks -= (old_num - new_num) << 3; 1774 if (btrfs_file_extent_disk_blocknr(extent)) {
1775 inode->i_blocks -=
1776 (old_num - new_num) << 3;
1777 }
1723 btrfs_set_file_extent_num_blocks(extent, 1778 btrfs_set_file_extent_num_blocks(extent,
1724 new_num); 1779 new_num);
1725 mark_buffer_dirty(path->nodes[0]); 1780 mark_buffer_dirty(path->nodes[0]);
@@ -1745,7 +1800,7 @@ static int drop_extents(struct btrfs_trans_handle *trans,
1745 BUG_ON(ret); 1800 BUG_ON(ret);
1746 btrfs_release_path(root, path); 1801 btrfs_release_path(root, path);
1747 extent = NULL; 1802 extent = NULL;
1748 if (found_extent) { 1803 if (found_extent && disk_blocknr != 0) {
1749 inode->i_blocks -= extent_num_blocks << 3; 1804 inode->i_blocks -= extent_num_blocks << 3;
1750 ret = btrfs_free_extent(trans, root, 1805 ret = btrfs_free_extent(trans, root,
1751 disk_blocknr, 1806 disk_blocknr,
@@ -1785,18 +1840,19 @@ static int drop_extents(struct btrfs_trans_handle *trans,
1785 btrfs_file_extent_offset(&old) + 1840 btrfs_file_extent_offset(&old) +
1786 ((end - key.offset) >> inode->i_blkbits)); 1841 ((end - key.offset) >> inode->i_blkbits));
1787 WARN_ON(btrfs_file_extent_num_blocks(&old) < 1842 WARN_ON(btrfs_file_extent_num_blocks(&old) <
1788 (end - key.offset) >> inode->i_blkbits); 1843 (extent_end - end) >> inode->i_blkbits);
1789 btrfs_set_file_extent_num_blocks(extent, 1844 btrfs_set_file_extent_num_blocks(extent,
1790 btrfs_file_extent_num_blocks(&old) - 1845 (extent_end - end) >> inode->i_blkbits);
1791 ((end - key.offset) >> inode->i_blkbits));
1792 1846
1793 btrfs_set_file_extent_type(extent, 1847 btrfs_set_file_extent_type(extent,
1794 BTRFS_FILE_EXTENT_REG); 1848 BTRFS_FILE_EXTENT_REG);
1795 btrfs_set_file_extent_generation(extent, 1849 btrfs_set_file_extent_generation(extent,
1796 btrfs_file_extent_generation(&old)); 1850 btrfs_file_extent_generation(&old));
1797 btrfs_mark_buffer_dirty(path->nodes[0]); 1851 btrfs_mark_buffer_dirty(path->nodes[0]);
1798 inode->i_blocks += 1852 if (btrfs_file_extent_disk_blocknr(&old) != 0) {
1799 btrfs_file_extent_num_blocks(extent) << 3; 1853 inode->i_blocks +=
1854 btrfs_file_extent_num_blocks(extent) << 3;
1855 }
1800 ret = 0; 1856 ret = 0;
1801 goto out; 1857 goto out;
1802 } 1858 }
@@ -1960,6 +2016,21 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1960 ~((u64)root->blocksize - 1), &hint_block); 2016 ~((u64)root->blocksize - 1), &hint_block);
1961 BUG_ON(ret); 2017 BUG_ON(ret);
1962 } 2018 }
2019 if (inode->i_size < start_pos) {
2020 u64 last_pos_in_file;
2021 u64 hole_size;
2022 u64 mask = root->blocksize - 1;
2023 last_pos_in_file = (inode->i_size + mask) & ~mask;
2024 hole_size = (start_pos - last_pos_in_file + mask) & ~mask;
2025 hole_size >>= inode->i_blkbits;
2026 if (last_pos_in_file < start_pos) {
2027 ret = btrfs_insert_file_extent(trans, root,
2028 inode->i_ino,
2029 last_pos_in_file,
2030 0, 0, hole_size);
2031 }
2032 BUG_ON(ret);
2033 }
1963 if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || 2034 if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size ||
1964 pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { 2035 pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) {
1965 ret = btrfs_alloc_extent(trans, root, inode->i_ino, 2036 ret = btrfs_alloc_extent(trans, root, inode->i_ino,
@@ -1967,7 +2038,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1967 &ins, 1); 2038 &ins, 1);
1968 BUG_ON(ret); 2039 BUG_ON(ret);
1969 ret = btrfs_insert_file_extent(trans, root, inode->i_ino, 2040 ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
1970 start_pos, ins.objectid, ins.offset); 2041 start_pos, ins.objectid, ins.offset,
2042 ins.offset);
1971 BUG_ON(ret); 2043 BUG_ON(ret);
1972 } else { 2044 } else {
1973 ins.offset = 0; 2045 ins.offset = 0;
@@ -2044,10 +2116,13 @@ static int btrfs_read_actor(read_descriptor_t *desc, struct page *page,
2044 page->index << PAGE_CACHE_SHIFT, 2116 page->index << PAGE_CACHE_SHIFT,
2045 kmap(page), PAGE_CACHE_SIZE); 2117 kmap(page), PAGE_CACHE_SIZE);
2046 if (ret) { 2118 if (ret) {
2047 printk("failed to verify ino %lu page %lu\n", 2119 if (ret != -ENOENT) {
2048 page->mapping->host->i_ino, 2120 printk("failed to verify ino %lu page %lu\n",
2049 page->index); 2121 page->mapping->host->i_ino,
2050 memset(page_address(page), 0, PAGE_CACHE_SIZE); 2122 page->index);
2123 memset(page_address(page), 0, PAGE_CACHE_SIZE);
2124 flush_dcache_page(page);
2125 }
2051 } 2126 }
2052 SetPageChecked(page); 2127 SetPageChecked(page);
2053 kunmap(page); 2128 kunmap(page);
@@ -2759,6 +2834,7 @@ static struct inode_operations btrfs_dir_inode_operations = {
2759 .rmdir = btrfs_rmdir, 2834 .rmdir = btrfs_rmdir,
2760 .rename = btrfs_rename, 2835 .rename = btrfs_rename,
2761 .symlink = btrfs_symlink, 2836 .symlink = btrfs_symlink,
2837 .setattr = btrfs_setattr,
2762}; 2838};
2763 2839
2764static struct inode_operations btrfs_dir_ro_inode_operations = { 2840static struct inode_operations btrfs_dir_ro_inode_operations = {
@@ -2788,6 +2864,7 @@ static struct address_space_operations btrfs_symlink_aops = {
2788static struct inode_operations btrfs_file_inode_operations = { 2864static struct inode_operations btrfs_file_inode_operations = {
2789 .truncate = btrfs_truncate, 2865 .truncate = btrfs_truncate,
2790 .getattr = btrfs_getattr, 2866 .getattr = btrfs_getattr,
2867 .setattr = btrfs_setattr,
2791}; 2868};
2792 2869
2793static struct file_operations btrfs_file_operations = { 2870static struct file_operations btrfs_file_operations = {