/* simple helper to fault in pages and copy. This should go away
* and be replaced with calls into generic code.
*/
-static int noinline btrfs_copy_from_user(loff_t pos, int num_pages,
+static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
int write_bytes,
struct page **prepared_pages,
- const char __user * buf)
+ const char __user *buf)
{
long page_fault = 0;
int i;
/*
* unlocks pages after btrfs_file_write is done with them
*/
-static void noinline btrfs_drop_pages(struct page **pages, size_t num_pages)
+static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
{
size_t i;
for (i = 0; i < num_pages; i++) {
* this also makes the decision about creating an inline extent vs
* doing real data extents, marking pages dirty and delalloc as required.
*/
-static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
+static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct file *file,
struct page **pages,
btrfs_set_trans_block_group(trans, inode);
hint_byte = 0;
- if ((end_of_last_block & 4095) == 0) {
- printk("strange end of last %Lu %zu %Lu\n", start_pos, write_bytes, end_of_last_block);
- }
set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS);
/* check for reserved extents on each page, we don't want
len = (u64)-1;
testend = 0;
}
- while(1) {
+ while (1) {
if (!split)
split = alloc_extent_map(GFP_NOFS);
if (!split2)
em->start < start) {
split->start = em->start;
split->len = start - em->start;
+ split->orig_start = em->orig_start;
split->block_start = em->block_start;
if (compressed)
if (compressed) {
split->block_len = em->block_len;
split->block_start = em->block_start;
+ split->orig_start = em->orig_start;
} else {
split->block_len = split->len;
split->block_start = em->block_start + diff;
+ split->orig_start = split->start;
}
ret = add_extent_mapping(em_tree, split);
path = btrfs_alloc_path();
ret = btrfs_lookup_file_extent(NULL, root, path, inode->i_ino,
last_offset, 0);
- while(1) {
+ while (1) {
nritems = btrfs_header_nritems(path->nodes[0]);
if (path->slots[0] >= nritems) {
ret = btrfs_next_leaf(root, path);
if (found_key.offset < last_offset) {
WARN_ON(1);
btrfs_print_leaf(root, leaf);
- printk("inode %lu found offset %Lu expected %Lu\n",
- inode->i_ino, found_key.offset, last_offset);
+ printk(KERN_ERR "inode %lu found offset %llu "
+ "expected %llu\n", inode->i_ino,
+ (unsigned long long)found_key.offset,
+ (unsigned long long)last_offset);
err = 1;
goto out;
}
extent_end = found_key.offset +
btrfs_file_extent_inline_len(leaf, extent);
extent_end = (extent_end + root->sectorsize - 1) &
- ~((u64)root->sectorsize -1 );
+ ~((u64)root->sectorsize - 1);
}
last_offset = extent_end;
path->slots[0]++;
if (0 && last_offset < inode->i_size) {
WARN_ON(1);
btrfs_print_leaf(root, leaf);
- printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino,
- last_offset, inode->i_size);
+ printk(KERN_ERR "inode %lu found offset %llu size %llu\n",
+ inode->i_ino, (unsigned long long)last_offset,
+ (unsigned long long)inode->i_size);
err = 1;
}
* inline_limit is used to tell this code which offsets in the file to keep
* if they contain inline extents.
*/
-int noinline btrfs_drop_extents(struct btrfs_trans_handle *trans,
+noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
u64 start, u64 end, u64 inline_limit, u64 *hint_byte)
{
u64 search_start = start;
u64 leaf_start;
u64 ram_bytes = 0;
+ u64 orig_parent = 0;
+ u64 disk_bytenr = 0;
u8 compression;
u8 encryption;
u16 other_encoding = 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- while(1) {
+ while (1) {
recow = 0;
btrfs_release_path(root, path);
ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
goto out;
}
if (recow) {
- search_start = key.offset;
+ search_start = max(key.offset, start);
continue;
}
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
keep = 1;
}
- if (bookend && found_extent && locked_end < extent_end) {
- ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
- locked_end, extent_end - 1, GFP_NOFS);
- if (!ret) {
- btrfs_release_path(root, path);
- lock_extent(&BTRFS_I(inode)->io_tree,
- locked_end, extent_end - 1, GFP_NOFS);
+ if (bookend && found_extent) {
+ if (locked_end < extent_end) {
+ ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
+ locked_end, extent_end - 1,
+ GFP_NOFS);
+ if (!ret) {
+ btrfs_release_path(root, path);
+ lock_extent(&BTRFS_I(inode)->io_tree,
+ locked_end, extent_end - 1,
+ GFP_NOFS);
+ locked_end = extent_end;
+ continue;
+ }
locked_end = extent_end;
- continue;
}
- locked_end = extent_end;
+ orig_parent = path->nodes[0]->start;
+ disk_bytenr = le64_to_cpu(old.disk_bytenr);
+ if (disk_bytenr != 0) {
+ ret = btrfs_inc_extent_ref(trans, root,
+ disk_bytenr,
+ le64_to_cpu(old.disk_num_bytes),
+ orig_parent, root->root_key.objectid,
+ trans->transid, inode->i_ino);
+ BUG_ON(ret);
+ }
}
if (found_inline) {
inode_sub_bytes(inode, old_num -
new_num);
}
- btrfs_set_file_extent_num_bytes(leaf, extent,
- new_num);
+ btrfs_set_file_extent_num_bytes(leaf,
+ extent, new_num);
btrfs_mark_buffer_dirty(leaf);
} else if (key.offset < inline_limit &&
(end > extent_end) &&
}
/* create bookend, splitting the extent in two */
if (bookend && found_extent) {
- u64 disk_bytenr;
struct btrfs_key ins;
ins.objectid = inode->i_ino;
ins.offset = end;
btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
+
btrfs_release_path(root, path);
ret = btrfs_insert_empty_item(trans, root, path, &ins,
sizeof(*extent));
btrfs_mark_buffer_dirty(path->nodes[0]);
- disk_bytenr = le64_to_cpu(old.disk_bytenr);
if (disk_bytenr != 0) {
- ret = btrfs_inc_extent_ref(trans, root,
- disk_bytenr,
- le64_to_cpu(old.disk_num_bytes),
+ ret = btrfs_update_extent_ref(trans, root,
+ disk_bytenr, orig_parent,
leaf->start,
root->root_key.objectid,
trans->transid, ins.objectid);
+
BUG_ON(ret);
}
btrfs_release_path(root, path);
- if (disk_bytenr != 0) {
+ if (disk_bytenr != 0)
inode_add_bytes(inode, extent_end - end);
- }
}
if (found_extent && !keep) {
- u64 disk_bytenr = le64_to_cpu(old.disk_bytenr);
+ u64 old_disk_bytenr = le64_to_cpu(old.disk_bytenr);
- if (disk_bytenr != 0) {
+ if (old_disk_bytenr != 0) {
inode_sub_bytes(inode,
le64_to_cpu(old.num_bytes));
ret = btrfs_free_extent(trans, root,
- disk_bytenr,
+ old_disk_bytenr,
le64_to_cpu(old.disk_num_bytes),
leaf_start, root_owner,
root_gen, key.objectid, 0);
BUG_ON(ret);
- *hint_byte = disk_bytenr;
+ *hint_byte = old_disk_bytenr;
}
}
u64 other_end;
u64 split = start;
u64 locked_end = end;
+ u64 orig_parent;
int extent_type;
int split_end = 1;
int ret;
}
btrfs_mark_buffer_dirty(leaf);
+
+ orig_parent = leaf->start;
+ ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes,
+ orig_parent, root->root_key.objectid,
+ trans->transid, inode->i_ino);
+ BUG_ON(ret);
btrfs_release_path(root, path);
key.offset = start;
btrfs_set_file_extent_encryption(leaf, fi, 0);
btrfs_set_file_extent_other_encoding(leaf, fi, 0);
- ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes,
- leaf->start, root->root_key.objectid,
- trans->transid, inode->i_ino);
- BUG_ON(ret);
+ if (orig_parent != leaf->start) {
+ ret = btrfs_update_extent_ref(trans, root, bytenr,
+ orig_parent, leaf->start,
+ root->root_key.objectid,
+ trans->transid, inode->i_ino);
+ BUG_ON(ret);
+ }
done:
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(root, path);
* waits for data=ordered extents to finish before allowing the pages to be
* modified.
*/
-static int noinline prepare_pages(struct btrfs_root *root, struct file *file,
+static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
struct page **pages, size_t num_pages,
loff_t pos, unsigned long first_index,
unsigned long last_index, size_t write_bytes)
struct btrfs_ordered_extent *ordered;
lock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS);
- ordered = btrfs_lookup_first_ordered_extent(inode, last_pos -1);
+ ordered = btrfs_lookup_first_ordered_extent(inode,
+ last_pos - 1);
if (ordered &&
ordered->file_offset + ordered->len > start_pos &&
ordered->file_offset < last_pos) {
pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
mutex_lock(&inode->i_mutex);
+ BTRFS_I(inode)->sequence++;
first_index = pos >> PAGE_CACHE_SHIFT;
last_index = (pos + count) >> PAGE_CACHE_SHIFT;
- /*
- * if this is a nodatasum mount, force summing off for the inode
- * all the time. That way a later mount with summing on won't
- * get confused
- */
- if (btrfs_test_opt(root, NODATASUM))
- btrfs_set_flag(inode, NODATASUM);
-
/*
* there are lots of better ways to do this, but this code
* makes sure the first and last page in the file range are
}
}
- while(count > 0) {
+ while (count > 0) {
size_t offset = pos & (PAGE_CACHE_SIZE - 1);
size_t write_bytes = min(count, nrptrs *
(size_t)PAGE_CACHE_SIZE -
PAGE_CACHE_SHIFT;
WARN_ON(num_pages > nrptrs);
- memset(pages, 0, sizeof(pages));
+ memset(pages, 0, sizeof(struct page *) * nrptrs);
ret = btrfs_check_free_space(root, write_bytes, 0);
if (ret)
return num_written ? num_written : err;
}
-int btrfs_release_file(struct inode * inode, struct file * filp)
+int btrfs_release_file(struct inode *inode, struct file *filp)
{
if (filp->private_data)
btrfs_ioctl_trans_end(filp);
mutex_unlock(&root->fs_info->trans_mutex);
root->fs_info->tree_log_batch++;
- filemap_fdatawait(inode->i_mapping);
+ filemap_fdatawrite(inode->i_mapping);
+ btrfs_wait_ordered_range(inode, 0, (u64)-1);
root->fs_info->tree_log_batch++;
/*
}
ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
- if (ret < 0) {
+ if (ret < 0)
goto out;
- }
/* we've logged all the items and now have a consistent
* version of the file in the log. It is possible that