#include "ordered-data.h"
#include "ioctl.h"
#include "print-tree.h"
+#include "compat.h"
static int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes,
err = btrfs_insert_file_extent(trans, root,
inode->i_ino,
last_pos_in_file,
- 0, 0, hole_size);
+ 0, 0, hole_size, 0);
btrfs_drop_extent_cache(inode, last_pos_in_file,
last_pos_in_file + hole_size -1);
btrfs_check_file(root, inode);
(inline_size & (root->sectorsize -1)) == 0 ||
inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
u64 last_end;
- u64 existing_delalloc = 0;
for (i = 0; i < num_pages; i++) {
struct page *p = pages[i];
last_end = (u64)(pages[num_pages -1]->index) <<
PAGE_CACHE_SHIFT;
last_end += PAGE_CACHE_SIZE - 1;
- if (start_pos < isize) {
- u64 delalloc_start = start_pos;
- existing_delalloc = count_range_bits(io_tree,
- &delalloc_start,
- end_of_last_block, (u64)-1,
- EXTENT_DELALLOC);
- }
set_extent_delalloc(io_tree, start_pos, end_of_last_block,
GFP_NOFS);
btrfs_add_ordered_inode(inode);
int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
{
struct extent_map *em;
+ struct extent_map *split = NULL;
+ struct extent_map *split2 = NULL;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
u64 len = end - start + 1;
+ int ret;
+ int testend = 1;
- if (end == (u64)-1)
+ if (end == (u64)-1) {
len = (u64)-1;
+ testend = 0;
+ }
while(1) {
+ if (!split)
+ split = alloc_extent_map(GFP_NOFS);
+ if (!split2)
+ split2 = alloc_extent_map(GFP_NOFS);
+
spin_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
if (!em) {
break;
}
remove_extent_mapping(em_tree, em);
+
+ if (em->block_start < EXTENT_MAP_LAST_BYTE &&
+ em->start < start) {
+ split->start = em->start;
+ split->len = start - em->start;
+ split->block_start = em->block_start;
+ split->bdev = em->bdev;
+ split->flags = em->flags;
+ ret = add_extent_mapping(em_tree, split);
+ BUG_ON(ret);
+ free_extent_map(split);
+ split = split2;
+ split2 = NULL;
+ }
+ if (em->block_start < EXTENT_MAP_LAST_BYTE &&
+ testend && em->start + em->len > start + len) {
+ u64 diff = start + len - em->start;
+
+ split->start = start + len;
+ split->len = em->start + em->len - (start + len);
+ split->bdev = em->bdev;
+ split->flags = em->flags;
+
+ split->block_start = em->block_start + diff;
+
+ ret = add_extent_mapping(em_tree, split);
+ BUG_ON(ret);
+ free_extent_map(split);
+ split = NULL;
+ }
spin_unlock(&em_tree->lock);
/* once for us */
/* once for the tree*/
free_extent_map(em);
}
+ if (split)
+ free_extent_map(split);
+ if (split2)
+ free_extent_map(split2);
return 0;
}
}
if (start_pos < inode->i_size) {
u64 last_pos;
- last_pos = (index + num_pages) << PAGE_CACHE_SHIFT;
+ last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
+ lock_extent(&BTRFS_I(inode)->io_tree,
+ start_pos, last_pos - 1, GFP_NOFS);
clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos,
last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC,
GFP_NOFS);
+ unlock_extent(&BTRFS_I(inode)->io_tree,
+ start_pos, last_pos - 1, GFP_NOFS);
}
return 0;
}
PAGE_CACHE_SIZE / (sizeof(struct page *)));
pinned[0] = NULL;
pinned[1] = NULL;
- if (file->f_flags & O_DIRECT)
- return -EINVAL;
pos = *ppos;
start_pos = pos;
goto out_nolock;
if (count == 0)
goto out_nolock;
+#ifdef REMOVE_SUID_PATH
+ err = remove_suid(&file->f_path);
+#else
err = remove_suid(fdentry(file));
+#endif
if (err)
goto out_nolock;
file_update_time(file);
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
* up to date and ready for cow
start_pos, num_written);
if (err < 0)
num_written = err;
+ } else if (num_written > 0 && (file->f_flags & O_DIRECT)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ do_sync_file_range(file, start_pos,
+ start_pos + num_written - 1,
+ SYNC_FILE_RANGE_WRITE |
+ SYNC_FILE_RANGE_WAIT_AFTER);
+#else
+ do_sync_mapping_range(inode->i_mapping, start_pos,
+ start_pos + num_written - 1,
+ SYNC_FILE_RANGE_WRITE |
+ SYNC_FILE_RANGE_WAIT_AFTER);
+#endif
+ invalidate_mapping_pages(inode->i_mapping,
+ start_pos >> PAGE_CACHE_SHIFT,
+ (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
}
current->backing_dev_info = NULL;
+ btrfs_ordered_throttle(root, inode);
return num_written ? num_written : err;
}
+static int btrfs_release_file (struct inode * inode, struct file * filp)
+{
+ btrfs_del_ordered_inode(inode);
+ return 0;
+}
+
static int btrfs_sync_file(struct file *file,
struct dentry *dentry, int datasync)
{
.write = btrfs_file_write,
.mmap = btrfs_file_mmap,
.open = generic_file_open,
+ .release = btrfs_release_file,
.fsync = btrfs_sync_file,
.unlocked_ioctl = btrfs_ioctl,
#ifdef CONFIG_COMPAT