aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:18:25 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:56 -0400
commit3326d1b07c0cb6a2ff5b835b7a2cffa54124d074 (patch)
tree16db275e3e8edb35e46fdd9f9a0f3a1c377ada5f
parent4dc119046d0d8501afa4346472917fb05586ad9c (diff)
Btrfs: Allow tails larger than one page
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.c24
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/file.c152
-rw-r--r--fs/btrfs/inode.c32
-rw-r--r--fs/btrfs/super.c2
5 files changed, 156 insertions, 56 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index bef61ee883e1..f691542dfa15 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1766,8 +1766,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1766 1766
1767 /* first try to make some room by pushing left and right */ 1767 /* first try to make some room by pushing left and right */
1768 wret = push_leaf_left(trans, root, path, data_size); 1768 wret = push_leaf_left(trans, root, path, data_size);
1769 if (wret < 0) 1769 if (wret < 0) {
1770 return wret; 1770 return wret;
1771 }
1771 if (wret) { 1772 if (wret) {
1772 wret = push_leaf_right(trans, root, path, data_size); 1773 wret = push_leaf_right(trans, root, path, data_size);
1773 if (wret < 0) 1774 if (wret < 0)
@@ -1777,8 +1778,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1777 1778
1778 /* did the pushes work? */ 1779 /* did the pushes work? */
1779 if (btrfs_leaf_free_space(root, l) >= 1780 if (btrfs_leaf_free_space(root, l) >=
1780 sizeof(struct btrfs_item) + data_size) 1781 sizeof(struct btrfs_item) + data_size) {
1781 return 0; 1782 return 0;
1783 }
1782 1784
1783 if (!path->nodes[1]) { 1785 if (!path->nodes[1]) {
1784 ret = insert_new_root(trans, root, path, 1); 1786 ret = insert_new_root(trans, root, path, 1);
@@ -1822,7 +1824,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1822 return ret; 1824 return ret;
1823 } 1825 }
1824 mid = slot; 1826 mid = slot;
1825 double_split = 1; 1827 if (mid != nritems &&
1828 leaf_space_used(l, mid, nritems - mid) +
1829 space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
1830 double_split = 1;
1831 }
1826 } 1832 }
1827 } else { 1833 } else {
1828 if (leaf_space_used(l, 0, mid + 1) + space_needed > 1834 if (leaf_space_used(l, 0, mid + 1) + space_needed >
@@ -1910,8 +1916,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1910 1916
1911 BUG_ON(path->slots[0] < 0); 1917 BUG_ON(path->slots[0] < 0);
1912 1918
1913 if (!double_split) 1919 if (!double_split) {
1914 return ret; 1920 return ret;
1921 }
1915 1922
1916 right = btrfs_alloc_free_block(trans, root, root->leafsize, 1923 right = btrfs_alloc_free_block(trans, root, root->leafsize,
1917 l->start, 0); 1924 l->start, 0);
@@ -2048,7 +2055,11 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
2048 old_data = btrfs_item_end_nr(leaf, slot); 2055 old_data = btrfs_item_end_nr(leaf, slot);
2049 2056
2050 BUG_ON(slot < 0); 2057 BUG_ON(slot < 0);
2051 BUG_ON(slot >= nritems); 2058 if (slot >= nritems) {
2059 btrfs_print_leaf(root, leaf);
2060 printk("slot %d too large, nritems %d\n", slot, nritems);
2061 BUG_ON(1);
2062 }
2052 2063
2053 /* 2064 /*
2054 * item0..itemN ... dataN.offset..dataN.size .. data0.size 2065 * item0..itemN ... dataN.offset..dataN.size .. data0.size
@@ -2132,6 +2143,9 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
2132 2143
2133 if (btrfs_leaf_free_space(root, leaf) < 2144 if (btrfs_leaf_free_space(root, leaf) <
2134 sizeof(struct btrfs_item) + data_size) { 2145 sizeof(struct btrfs_item) + data_size) {
2146 btrfs_print_leaf(root, leaf);
2147 printk("not enough freespace need %u have %d\n",
2148 data_size, btrfs_leaf_free_space(root, leaf));
2135 BUG(); 2149 BUG();
2136 } 2150 }
2137 2151
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 54c754dd9a14..18994c53106c 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1137,7 +1137,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end);
1137extern struct file_operations btrfs_file_operations; 1137extern struct file_operations btrfs_file_operations;
1138int btrfs_drop_extents(struct btrfs_trans_handle *trans, 1138int btrfs_drop_extents(struct btrfs_trans_handle *trans,
1139 struct btrfs_root *root, struct inode *inode, 1139 struct btrfs_root *root, struct inode *inode,
1140 u64 start, u64 end, u64 *hint_block); 1140 u64 start, u64 end, u64 inline_end, u64 *hint_block);
1141/* tree-defrag.c */ 1141/* tree-defrag.c */
1142int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, 1142int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
1143 struct btrfs_root *root, int cache_only); 1143 struct btrfs_root *root, int cache_only);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 844d8807e44a..1af2b6534dad 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -82,8 +82,9 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages)
82 82
83static int insert_inline_extent(struct btrfs_trans_handle *trans, 83static int insert_inline_extent(struct btrfs_trans_handle *trans,
84 struct btrfs_root *root, struct inode *inode, 84 struct btrfs_root *root, struct inode *inode,
85 u64 offset, ssize_t size, 85 u64 offset, size_t size,
86 struct page *page, size_t page_offset) 86 struct page **pages, size_t page_offset,
87 int num_pages)
87{ 88{
88 struct btrfs_key key; 89 struct btrfs_key key;
89 struct btrfs_path *path; 90 struct btrfs_path *path;
@@ -91,9 +92,12 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
91 char *kaddr; 92 char *kaddr;
92 unsigned long ptr; 93 unsigned long ptr;
93 struct btrfs_file_extent_item *ei; 94 struct btrfs_file_extent_item *ei;
95 struct page *page;
94 u32 datasize; 96 u32 datasize;
95 int err = 0; 97 int err = 0;
96 int ret; 98 int ret;
99 int i;
100 ssize_t cur_size;
97 101
98 path = btrfs_alloc_path(); 102 path = btrfs_alloc_path();
99 if (!path) 103 if (!path)
@@ -104,25 +108,97 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
104 key.objectid = inode->i_ino; 108 key.objectid = inode->i_ino;
105 key.offset = offset; 109 key.offset = offset;
106 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); 110 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
107 BUG_ON(size >= PAGE_CACHE_SIZE); 111 datasize = btrfs_file_extent_calc_inline_size(offset + size);
108 datasize = btrfs_file_extent_calc_inline_size(size);
109 112
110 ret = btrfs_insert_empty_item(trans, root, path, &key, 113 ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
111 datasize); 114 if (ret < 0) {
112 if (ret) {
113 err = ret; 115 err = ret;
114 goto fail; 116 goto fail;
115 } 117 }
116 leaf = path->nodes[0]; 118 if (ret == 1) {
117 ei = btrfs_item_ptr(leaf, path->slots[0], 119 path->slots[0]--;
118 struct btrfs_file_extent_item); 120 leaf = path->nodes[0];
119 btrfs_set_file_extent_generation(leaf, ei, trans->transid); 121 ei = btrfs_item_ptr(leaf, path->slots[0],
120 btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); 122 struct btrfs_file_extent_item);
121 ptr = btrfs_file_extent_inline_start(ei); 123
122 124 if (btrfs_file_extent_type(leaf, ei) !=
123 kaddr = kmap_atomic(page, KM_USER1); 125 BTRFS_FILE_EXTENT_INLINE) {
124 write_extent_buffer(leaf, kaddr + page_offset, ptr, size); 126 goto insert;
125 kunmap_atomic(kaddr, KM_USER1); 127 }
128 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
129 ret = 0;
130 }
131 if (ret == 0) {
132 u32 found_size;
133 u64 found_start;
134
135 leaf = path->nodes[0];
136 ei = btrfs_item_ptr(leaf, path->slots[0],
137 struct btrfs_file_extent_item);
138
139 if (btrfs_file_extent_type(leaf, ei) !=
140 BTRFS_FILE_EXTENT_INLINE) {
141 err = ret;
142 btrfs_print_leaf(root, leaf);
143 printk("found wasn't inline offset %Lu inode %lu\n",
144 offset, inode->i_ino);
145 goto fail;
146 }
147 found_start = key.offset;
148 found_size = btrfs_file_extent_inline_len(leaf,
149 btrfs_item_nr(leaf, path->slots[0]));
150
151 if (found_size < offset + size) {
152 btrfs_release_path(root, path);
153 ret = btrfs_search_slot(trans, root, &key, path,
154 offset + size - found_size -
155 found_start, 1);
156 BUG_ON(ret != 0);
157 ret = btrfs_extend_item(trans, root, path,
158 offset + size - found_size -
159 found_start);
160 if (ret) {
161 err = ret;
162 goto fail;
163 }
164 leaf = path->nodes[0];
165 ei = btrfs_item_ptr(leaf, path->slots[0],
166 struct btrfs_file_extent_item);
167 }
168 } else {
169insert:
170 btrfs_release_path(root, path);
171 ret = btrfs_insert_empty_item(trans, root, path, &key,
172 datasize);
173 if (ret) {
174 err = ret;
175 printk("got bad ret %d\n", ret);
176 goto fail;
177 }
178 leaf = path->nodes[0];
179 ei = btrfs_item_ptr(leaf, path->slots[0],
180 struct btrfs_file_extent_item);
181 btrfs_set_file_extent_generation(leaf, ei, trans->transid);
182 btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
183 }
184 ptr = btrfs_file_extent_inline_start(ei) + offset;
185
186 cur_size = size;
187 i = 0;
188 while (size > 0) {
189 page = pages[i];
190 kaddr = kmap_atomic(page, KM_USER0);
191 cur_size = min(PAGE_CACHE_SIZE - page_offset, size);
192 write_extent_buffer(leaf, kaddr + page_offset, ptr, cur_size);
193 kunmap_atomic(kaddr, KM_USER0);
194 page_offset = 0;
195 ptr += cur_size;
196 size -= cur_size;
197 if (i >= num_pages) {
198 printk("i %d num_pages %d\n", i, num_pages);
199 }
200 i++;
201 }
126 btrfs_mark_buffer_dirty(leaf); 202 btrfs_mark_buffer_dirty(leaf);
127fail: 203fail:
128 btrfs_free_path(path); 204 btrfs_free_path(path);
@@ -193,6 +269,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
193 err = btrfs_drop_extents(trans, root, inode, 269 err = btrfs_drop_extents(trans, root, inode,
194 last_pos_in_file, 270 last_pos_in_file,
195 last_pos_in_file + hole_size, 271 last_pos_in_file + hole_size,
272 last_pos_in_file,
196 &hint_byte); 273 &hint_byte);
197 if (err) 274 if (err)
198 goto failed; 275 goto failed;
@@ -210,11 +287,12 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
210 * either allocate an extent for the new bytes or setup the key 287 * either allocate an extent for the new bytes or setup the key
211 * to show we are doing inline data in the extent 288 * to show we are doing inline data in the extent
212 */ 289 */
213 inline_size = end_pos - start_pos; 290 inline_size = end_pos;
214 if (isize >= PAGE_CACHE_SIZE || pos + write_bytes < inode->i_size || 291 if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
215 inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root) || 292 inline_size > 16384 ||
216 inline_size >= PAGE_CACHE_SIZE) { 293 inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
217 u64 last_end; 294 u64 last_end;
295
218 for (i = 0; i < num_pages; i++) { 296 for (i = 0; i < num_pages; i++) {
219 struct page *p = pages[i]; 297 struct page *p = pages[i];
220 SetPageUptodate(p); 298 SetPageUptodate(p);
@@ -225,22 +303,18 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
225 set_extent_delalloc(em_tree, start_pos, end_of_last_block, 303 set_extent_delalloc(em_tree, start_pos, end_of_last_block,
226 GFP_NOFS); 304 GFP_NOFS);
227 } else { 305 } else {
228 struct page *p = pages[0]; 306 u64 aligned_end;
229 /* step one, delete the existing extents in this range */ 307 /* step one, delete the existing extents in this range */
308 aligned_end = (pos + write_bytes + root->sectorsize - 1) &
309 ~((u64)root->sectorsize - 1);
230 err = btrfs_drop_extents(trans, root, inode, start_pos, 310 err = btrfs_drop_extents(trans, root, inode, start_pos,
231 (pos + write_bytes + root->sectorsize -1) & 311 aligned_end, end_pos, &hint_byte);
232 ~((u64)root->sectorsize - 1), &hint_byte);
233 if (err) 312 if (err)
234 goto failed; 313 goto failed;
235
236 err = insert_inline_extent(trans, root, inode, start_pos, 314 err = insert_inline_extent(trans, root, inode, start_pos,
237 end_pos - start_pos, p, 0); 315 end_pos - start_pos, pages, 0,
316 num_pages);
238 BUG_ON(err); 317 BUG_ON(err);
239 em->start = start_pos;
240 em->end = end_pos - 1;
241 em->block_start = EXTENT_MAP_INLINE;
242 em->block_end = EXTENT_MAP_INLINE;
243 add_extent_mapping(em_tree, em);
244 } 318 }
245 if (end_pos > isize) { 319 if (end_pos > isize) {
246 i_size_write(inode, end_pos); 320 i_size_write(inode, end_pos);
@@ -285,7 +359,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
285 */ 359 */
286int btrfs_drop_extents(struct btrfs_trans_handle *trans, 360int btrfs_drop_extents(struct btrfs_trans_handle *trans,
287 struct btrfs_root *root, struct inode *inode, 361 struct btrfs_root *root, struct inode *inode,
288 u64 start, u64 end, u64 *hint_byte) 362 u64 start, u64 end, u64 inline_end, u64 *hint_byte)
289{ 363{
290 int ret; 364 int ret;
291 struct btrfs_key key; 365 struct btrfs_key key;
@@ -401,8 +475,8 @@ next_slot:
401 BUG_ON(ret); 475 BUG_ON(ret);
402 } 476 }
403 } 477 }
404 WARN_ON(found_inline); 478 if (!found_inline)
405 bookend = 1; 479 bookend = 1;
406 } 480 }
407 /* truncate existing extent */ 481 /* truncate existing extent */
408 if (start > key.offset) { 482 if (start > key.offset) {
@@ -425,8 +499,14 @@ next_slot:
425 btrfs_set_file_extent_num_bytes(leaf, extent, 499 btrfs_set_file_extent_num_bytes(leaf, extent,
426 new_num); 500 new_num);
427 btrfs_mark_buffer_dirty(leaf); 501 btrfs_mark_buffer_dirty(leaf);
428 } else { 502 } else if (end > extent_end &&
429 WARN_ON(1); 503 key.offset < inline_end &&
504 inline_end < extent_end) {
505 u32 new_size;
506 new_size = btrfs_file_extent_calc_inline_size(
507 inline_end - key.offset);
508 btrfs_truncate_item(trans, root, path,
509 new_size);
430 } 510 }
431 } 511 }
432 /* delete the entire extent */ 512 /* delete the entire extent */
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d6b3a55ed8e0..84f496c838c9 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -87,7 +87,7 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
87 BUG_ON(!trans); 87 BUG_ON(!trans);
88 num_bytes = (end - start + blocksize) & ~(blocksize - 1); 88 num_bytes = (end - start + blocksize) & ~(blocksize - 1);
89 ret = btrfs_drop_extents(trans, root, inode, 89 ret = btrfs_drop_extents(trans, root, inode,
90 start, start + num_bytes, &alloc_hint); 90 start, start + num_bytes, start, &alloc_hint);
91 91
92 ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0, 92 ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0,
93 alloc_hint, (u64)-1, &ins, 1); 93 alloc_hint, (u64)-1, &ins, 1);
@@ -776,7 +776,8 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
776 trans = btrfs_start_transaction(root, 1); 776 trans = btrfs_start_transaction(root, 1);
777 btrfs_set_trans_block_group(trans, inode); 777 btrfs_set_trans_block_group(trans, inode);
778 err = btrfs_drop_extents(trans, root, inode, 778 err = btrfs_drop_extents(trans, root, inode,
779 pos, pos + hole_size, &alloc_hint); 779 pos, pos + hole_size, pos,
780 &alloc_hint);
780 781
781 err = btrfs_insert_file_extent(trans, root, inode->i_ino, 782 err = btrfs_insert_file_extent(trans, root, inode->i_ino,
782 pos, 0, 0, hole_size); 783 pos, 0, 0, hole_size);
@@ -1581,7 +1582,9 @@ again:
1581 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { 1582 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
1582 unsigned long ptr; 1583 unsigned long ptr;
1583 char *map; 1584 char *map;
1584 u32 size; 1585 size_t size;
1586 size_t extent_offset;
1587 size_t copy_size;
1585 1588
1586 size = btrfs_file_extent_inline_len(leaf, btrfs_item_nr(leaf, 1589 size = btrfs_file_extent_inline_len(leaf, btrfs_item_nr(leaf,
1587 path->slots[0])); 1590 path->slots[0]));
@@ -1600,26 +1603,31 @@ again:
1600 goto not_found_em; 1603 goto not_found_em;
1601 } 1604 }
1602 1605
1606 extent_offset = (page->index << PAGE_CACHE_SHIFT) -
1607 extent_start;
1608 ptr = btrfs_file_extent_inline_start(item) + extent_offset;
1609 map = kmap(page);
1610 copy_size = min(PAGE_CACHE_SIZE - page_offset,
1611 size - extent_offset);
1612
1603 em->block_start = EXTENT_MAP_INLINE; 1613 em->block_start = EXTENT_MAP_INLINE;
1604 em->block_end = EXTENT_MAP_INLINE; 1614 em->block_end = EXTENT_MAP_INLINE;
1605 em->start = extent_start; 1615 em->start = extent_start + extent_offset;
1606 em->end = extent_end; 1616 em->end = (em->start + copy_size -1) |
1617 ((u64)root->sectorsize -1);
1607 1618
1608 if (!page) { 1619 if (!page) {
1609 goto insert; 1620 goto insert;
1610 } 1621 }
1611 1622
1612 ptr = btrfs_file_extent_inline_start(item); 1623 read_extent_buffer(leaf, map + page_offset, ptr, copy_size);
1613 map = kmap(page);
1614 read_extent_buffer(leaf, map + page_offset, ptr, size);
1615 /* 1624 /*
1616 memset(map + page_offset + size, 0, 1625 memset(map + page_offset + copy_size, 0,
1617 root->sectorsize - (page_offset + size)); 1626 PAGE_CACHE_SIZE - copy_size - page_offset);
1618 */ 1627 */
1619 flush_dcache_page(page); 1628 flush_dcache_page(page);
1620 kunmap(page); 1629 kunmap(page);
1621 set_extent_uptodate(em_tree, extent_start, 1630 set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS);
1622 extent_end, GFP_NOFS);
1623 goto insert; 1631 goto insert;
1624 } else { 1632 } else {
1625 printk("unkknown found_type %d\n", found_type); 1633 printk("unkknown found_type %d\n", found_type);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 5c4370f3a5b8..f94aa1f97a0a 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -280,7 +280,6 @@ error_s:
280error_bdev: 280error_bdev:
281 close_bdev_excl(bdev); 281 close_bdev_excl(bdev);
282error: 282error:
283printk("get_sb failed\n");
284 return error; 283 return error;
285} 284}
286/* end copy & paste */ 285/* end copy & paste */
@@ -295,7 +294,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
295 ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, 294 ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
296 btrfs_fill_super, mnt, 295 btrfs_fill_super, mnt,
297 subvol_name ? subvol_name : "default"); 296 subvol_name ? subvol_name : "default");
298printk("btrfs_get_sb returns %d\n", ret);
299 return ret; 297 return ret;
300} 298}
301 299