aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c131
1 files changed, 81 insertions, 50 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 23f029359688..fef7ba1e707f 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -81,6 +81,62 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages)
81 } 81 }
82} 82}
83 83
84static int insert_inline_extent(struct btrfs_root *root, struct inode *inode,
85 u64 offset, ssize_t size,
86 struct buffer_head *bh)
87{
88 struct btrfs_key key;
89 struct btrfs_path *path;
90 char *ptr, *kaddr;
91 struct btrfs_trans_handle *trans;
92 struct btrfs_file_extent_item *ei;
93 u32 datasize;
94 int err = 0;
95 int ret;
96
97 path = btrfs_alloc_path();
98 if (!path)
99 return -ENOMEM;
100
101 mutex_lock(&root->fs_info->fs_mutex);
102 trans = btrfs_start_transaction(root, 1);
103 btrfs_set_trans_block_group(trans, inode);
104
105 key.objectid = inode->i_ino;
106 key.offset = offset;
107 key.flags = 0;
108 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
109 BUG_ON(size >= PAGE_CACHE_SIZE);
110 datasize = btrfs_file_extent_calc_inline_size(size);
111
112 ret = btrfs_insert_empty_item(trans, root, path, &key,
113 datasize);
114 if (ret) {
115 err = ret;
116 goto fail;
117 }
118 ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
119 path->slots[0], struct btrfs_file_extent_item);
120 btrfs_set_file_extent_generation(ei, trans->transid);
121 btrfs_set_file_extent_type(ei,
122 BTRFS_FILE_EXTENT_INLINE);
123 ptr = btrfs_file_extent_inline_start(ei);
124
125 kaddr = kmap_atomic(bh->b_page, KM_USER0);
126 btrfs_memcpy(root, path->nodes[0]->b_data,
127 ptr, kaddr + bh_offset(bh),
128 size);
129 kunmap_atomic(kaddr, KM_USER0);
130 mark_buffer_dirty(path->nodes[0]);
131fail:
132 btrfs_free_path(path);
133 ret = btrfs_end_transaction(trans, root);
134 if (ret && !err)
135 err = ret;
136 mutex_unlock(&root->fs_info->fs_mutex);
137 return err;
138}
139
84static int dirty_and_release_pages(struct btrfs_trans_handle *trans, 140static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
85 struct btrfs_root *root, 141 struct btrfs_root *root,
86 struct file *file, 142 struct file *file,
@@ -96,57 +152,22 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
96 int this_write; 152 int this_write;
97 struct inode *inode = file->f_path.dentry->d_inode; 153 struct inode *inode = file->f_path.dentry->d_inode;
98 struct buffer_head *bh; 154 struct buffer_head *bh;
99 struct btrfs_file_extent_item *ei;
100 155
101 for (i = 0; i < num_pages; i++) { 156 for (i = 0; i < num_pages; i++) {
102 offset = pos & (PAGE_CACHE_SIZE -1); 157 offset = pos & (PAGE_CACHE_SIZE -1);
103 this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes); 158 this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes);
104 /* FIXME, one block at a time */
105 159
160 /* FIXME, one block at a time */
106 bh = page_buffers(pages[i]); 161 bh = page_buffers(pages[i]);
107 162
108 if (buffer_mapped(bh) && bh->b_blocknr == 0) { 163 if (buffer_mapped(bh) && bh->b_blocknr == 0) {
109 struct btrfs_key key; 164 ret = insert_inline_extent(root, inode,
110 struct btrfs_path *path; 165 pages[i]->index << PAGE_CACHE_SHIFT,
111 char *ptr, *kaddr; 166 offset + this_write, bh);
112 u32 datasize; 167 if (ret) {
113 168 err = ret;
114 mutex_lock(&root->fs_info->fs_mutex); 169 goto failed;
115 trans = btrfs_start_transaction(root, 1); 170 }
116 btrfs_set_trans_block_group(trans, inode);
117
118 /* create an inline extent, and copy the data in */
119 path = btrfs_alloc_path();
120 BUG_ON(!path);
121 key.objectid = inode->i_ino;
122 key.offset = pages[i]->index << PAGE_CACHE_SHIFT;
123 key.flags = 0;
124 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
125 BUG_ON(write_bytes >= PAGE_CACHE_SIZE);
126 datasize = offset +
127 btrfs_file_extent_calc_inline_size(write_bytes);
128
129 ret = btrfs_insert_empty_item(trans, root, path, &key,
130 datasize);
131 BUG_ON(ret);
132 ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
133 path->slots[0], struct btrfs_file_extent_item);
134 btrfs_set_file_extent_generation(ei, trans->transid);
135 btrfs_set_file_extent_type(ei,
136 BTRFS_FILE_EXTENT_INLINE);
137 ptr = btrfs_file_extent_inline_start(ei);
138
139 kaddr = kmap_atomic(bh->b_page, KM_USER0);
140 btrfs_memcpy(root, path->nodes[0]->b_data,
141 ptr, kaddr + bh_offset(bh),
142 offset + write_bytes);
143 kunmap_atomic(kaddr, KM_USER0);
144
145 mark_buffer_dirty(path->nodes[0]);
146 btrfs_free_path(path);
147 ret = btrfs_end_transaction(trans, root);
148 BUG_ON(ret);
149 mutex_unlock(&root->fs_info->fs_mutex);
150 } 171 }
151 172
152 ret = btrfs_commit_write(file, pages[i], offset, 173 ret = btrfs_commit_write(file, pages[i], offset,
@@ -321,6 +342,7 @@ next_slot:
321 btrfs_file_extent_disk_blocknr(extent); 342 btrfs_file_extent_disk_blocknr(extent);
322 } 343 }
323 ret = btrfs_del_item(trans, root, path); 344 ret = btrfs_del_item(trans, root, path);
345 /* TODO update progress marker and return */
324 BUG_ON(ret); 346 BUG_ON(ret);
325 btrfs_release_path(root, path); 347 btrfs_release_path(root, path);
326 extent = NULL; 348 extent = NULL;
@@ -452,7 +474,8 @@ static int prepare_pages(struct btrfs_root *root,
452 err = btrfs_drop_extents(trans, root, inode, 474 err = btrfs_drop_extents(trans, root, inode,
453 start_pos, (pos + write_bytes + root->blocksize -1) & 475 start_pos, (pos + write_bytes + root->blocksize -1) &
454 ~((u64)root->blocksize - 1), &hint_block); 476 ~((u64)root->blocksize - 1), &hint_block);
455 BUG_ON(err); 477 if (err)
478 goto failed_release;
456 } 479 }
457 480
458 /* insert any holes we need to create */ 481 /* insert any holes we need to create */
@@ -469,7 +492,8 @@ static int prepare_pages(struct btrfs_root *root,
469 last_pos_in_file, 492 last_pos_in_file,
470 0, 0, hole_size); 493 0, 0, hole_size);
471 } 494 }
472 BUG_ON(err); 495 if (err)
496 goto failed_release;
473 } 497 }
474 498
475 /* 499 /*
@@ -481,11 +505,13 @@ static int prepare_pages(struct btrfs_root *root,
481 err = btrfs_alloc_extent(trans, root, inode->i_ino, 505 err = btrfs_alloc_extent(trans, root, inode->i_ino,
482 num_blocks, hint_block, (u64)-1, 506 num_blocks, hint_block, (u64)-1,
483 &ins, 1); 507 &ins, 1);
484 BUG_ON(err); 508 if (err)
509 goto failed_truncate;
485 err = btrfs_insert_file_extent(trans, root, inode->i_ino, 510 err = btrfs_insert_file_extent(trans, root, inode->i_ino,
486 start_pos, ins.objectid, ins.offset, 511 start_pos, ins.objectid, ins.offset,
487 ins.offset); 512 ins.offset);
488 BUG_ON(err); 513 if (err)
514 goto failed_truncate;
489 } else { 515 } else {
490 ins.offset = 0; 516 ins.offset = 0;
491 ins.objectid = 0; 517 ins.objectid = 0;
@@ -618,16 +644,21 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
618 ret = prepare_pages(root, file, pages, num_pages, 644 ret = prepare_pages(root, file, pages, num_pages,
619 pos, first_index, last_index, 645 pos, first_index, last_index,
620 write_bytes); 646 write_bytes);
621 BUG_ON(ret); 647 if (ret)
648 goto out;
622 649
623 ret = btrfs_copy_from_user(pos, num_pages, 650 ret = btrfs_copy_from_user(pos, num_pages,
624 write_bytes, pages, buf); 651 write_bytes, pages, buf);
625 BUG_ON(ret); 652 if (ret) {
653 btrfs_drop_pages(pages, num_pages);
654 goto out;
655 }
626 656
627 ret = dirty_and_release_pages(NULL, root, file, pages, 657 ret = dirty_and_release_pages(NULL, root, file, pages,
628 num_pages, pos, write_bytes); 658 num_pages, pos, write_bytes);
629 BUG_ON(ret);
630 btrfs_drop_pages(pages, num_pages); 659 btrfs_drop_pages(pages, num_pages);
660 if (ret)
661 goto out;
631 662
632 buf += write_bytes; 663 buf += write_bytes;
633 count -= write_bytes; 664 count -= write_bytes;