summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorChris Mason2007-04-18 22:15:28 +0200
committerDavid Woodhouse2007-04-18 22:15:28 +0200
commita429e51371eee3c989160c003ee40bc3947c6a76 (patch)
tree863b55de8823be579264260a51407cd90aac103d /fs/btrfs/super.c
parentBtrfs: rework csums and extent item ordering (diff)
downloadkernel-qcow2-linux-a429e51371eee3c989160c003ee40bc3947c6a76.tar.gz
kernel-qcow2-linux-a429e51371eee3c989160c003ee40bc3947c6a76.tar.xz
kernel-qcow2-linux-a429e51371eee3c989160c003ee40bc3947c6a76.zip
Btrfs: working file_write, reorganized key flags
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c118
1 files changed, 63 insertions, 55 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index b2a2220d1352..583cd87a62e2 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -150,11 +150,6 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
BUG_ON(ret);
btrfs_release_path(root, path);
- ret = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
- objectid, -1);
- BUG_ON(ret);
- ret = btrfs_del_item(trans, root, path);
- BUG_ON(ret);
dentry->d_inode->i_ctime = dir->i_ctime;
err:
btrfs_release_path(root, path);
@@ -329,8 +324,9 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
extent_start = btrfs_file_extent_disk_blocknr(fi);
extent_num_blocks =
btrfs_file_extent_disk_num_blocks(fi);
+ /* FIXME blocksize != 4096 */
inode->i_blocks -=
- btrfs_file_extent_num_blocks(fi) >> 9;
+ btrfs_file_extent_num_blocks(fi) << 3;
found_extent = 1;
} else {
found_extent = 0;
@@ -562,7 +558,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (btrfs_disk_key_objectid(&item->key) != key.objectid)
break;
if (btrfs_disk_key_type(&item->key) != key_type)
- continue;
+ break;
if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
continue;
filp->f_pos = btrfs_disk_key_offset(&item->key);
@@ -1285,29 +1281,27 @@ static int drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_path *path;
u64 search_start = start;
int bookend;
-
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
-search_again:
- ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
- search_start, -1);
- if (ret < 0)
- goto out;
- if (ret > 0) {
- if (path->slots[0] == 0) {
- ret = -ENOENT;
+ while(1) {
+ btrfs_release_path(root, path);
+ ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+ search_start, -1);
+ if (ret < 0)
goto out;
+ if (ret > 0) {
+ if (path->slots[0] == 0) {
+ ret = -ENOENT;
+ goto out;
+ }
+ path->slots[0]--;
}
- path->slots[0]--;
- }
- while(1) {
keep = 0;
bookend = 0;
leaf = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0];
btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
-
extent = btrfs_item_ptr(leaf, slot,
struct btrfs_file_extent_item);
extent_end = key.offset +
@@ -1318,7 +1312,10 @@ search_again:
goto out;
}
if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
- goto next_leaf;
+ goto out;
+ if (search_start >= extent_end)
+ goto out;
+ search_start = extent_end;
if (end < extent_end && end >= key.offset) {
memcpy(&old, extent, sizeof(old));
@@ -1331,10 +1328,13 @@ search_again:
if (start > key.offset) {
u64 new_num;
+ u64 old_num;
/* truncate existing extent */
keep = 1;
WARN_ON(start & (root->blocksize - 1));
new_num = (start - key.offset) >> inode->i_blkbits;
+ old_num = btrfs_file_extent_num_blocks(extent);
+ inode->i_blocks -= (old_num - new_num) << 3;
btrfs_set_file_extent_num_blocks(extent, new_num);
mark_buffer_dirty(path->nodes[0]);
}
@@ -1344,13 +1344,11 @@ search_again:
disk_blocknr = btrfs_file_extent_disk_blocknr(extent);
disk_num_blocks =
btrfs_file_extent_disk_num_blocks(extent);
- search_start = key.offset +
- (btrfs_file_extent_num_blocks(extent) <<
- inode->i_blkbits);
ret = btrfs_del_item(trans, root, path);
BUG_ON(ret);
+ inode->i_blocks -=
+ btrfs_file_extent_num_blocks(extent) << 3;
btrfs_release_path(root, path);
-
ret = btrfs_free_extent(trans, root, disk_blocknr,
disk_num_blocks, 0);
@@ -1360,7 +1358,7 @@ search_again:
goto out;
}
if (!bookend)
- goto search_again;
+ continue;
}
if (bookend) {
/* create bookend */
@@ -1395,21 +1393,12 @@ search_again:
btrfs_set_file_extent_generation(extent,
btrfs_file_extent_generation(&old));
btrfs_mark_buffer_dirty(path->nodes[0]);
+ inode->i_blocks +=
+ btrfs_file_extent_num_blocks(extent) << 3;
ret = 0;
goto out;
}
-next_leaf:
- if (slot >= btrfs_header_nritems(&leaf->header) - 1) {
- ret = btrfs_next_leaf(root, path);
- if (ret) {
- ret = 0;
- goto out;
- }
- } else {
- path->slots[0]++;
- }
}
-
out:
btrfs_free_path(path);
return ret;
@@ -1445,15 +1434,6 @@ static int prepare_pages(struct btrfs_root *root,
}
offset = pos & (PAGE_CACHE_SIZE -1);
this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
-#if 0
- if ((pages[i]->index == first_index ||
- pages[i]->index == last_index) && pos < isize &&
- !PageUptodate(pages[i])) {
- ret = mpage_readpage(pages[i], btrfs_get_block);
- BUG_ON(ret);
- lock_page(pages[i]);
- }
-#endif
create_empty_buffers(pages[i], root->fs_info->sb->s_blocksize,
(1 << BH_Uptodate));
head = page_buffers(pages[i]);
@@ -1494,6 +1474,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
struct inode *inode = file->f_path.dentry->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct page *pages[8];
+ struct page *pinned[2] = { NULL, NULL };
unsigned long first_index;
unsigned long last_index;
u64 start_pos;
@@ -1505,14 +1486,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
if (file->f_flags & O_DIRECT)
return -EINVAL;
pos = *ppos;
-
- start_pos = pos & ~(root->blocksize - 1);
- /* FIXME */
- if (start_pos != pos)
- return -EINVAL;
- num_blocks = (count + pos - start_pos + root->blocksize - 1) >>
- inode->i_blkbits;
-
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
current->backing_dev_info = inode->i_mapping->backing_dev_info;
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
@@ -1524,10 +1497,37 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
if (err)
goto out;
file_update_time(file);
+
+ start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
+ num_blocks = (count + pos - start_pos + root->blocksize - 1) >>
+ inode->i_blkbits;
+
mutex_lock(&inode->i_mutex);
first_index = pos >> PAGE_CACHE_SHIFT;
last_index = (pos + count) >> PAGE_CACHE_SHIFT;
+ if ((first_index << PAGE_CACHE_SHIFT) < inode->i_size &&
+ (pos & (PAGE_CACHE_SIZE - 1))) {
+ pinned[0] = grab_cache_page(inode->i_mapping, first_index);
+ if (!PageUptodate(pinned[0])) {
+ ret = mpage_readpage(pinned[0], btrfs_get_block);
+ BUG_ON(ret);
+ } else {
+ unlock_page(pinned[0]);
+ }
+ }
+ if (first_index != last_index &&
+ (last_index << PAGE_CACHE_SHIFT) < inode->i_size &&
+ (count & (PAGE_CACHE_SIZE - 1))) {
+ pinned[1] = grab_cache_page(inode->i_mapping, last_index);
+ if (!PageUptodate(pinned[1])) {
+ ret = mpage_readpage(pinned[1], btrfs_get_block);
+ BUG_ON(ret);
+ } else {
+ unlock_page(pinned[1]);
+ }
+ }
+
mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
if (!trans) {
@@ -1535,11 +1535,14 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
mutex_unlock(&root->fs_info->fs_mutex);
goto out_unlock;
}
+ /* FIXME blocksize != 4096 */
+ inode->i_blocks += num_blocks << 3;
if (start_pos < inode->i_size) {
+ /* FIXME blocksize != pagesize */
ret = drop_extents(trans, root, inode,
start_pos,
(pos + count + root->blocksize -1) &
- ~(root->blocksize - 1));
+ ~((u64)root->blocksize - 1));
}
ret = btrfs_alloc_extent(trans, root, num_blocks, 1,
(u64)-1, &ins);
@@ -1585,8 +1588,13 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
out_unlock:
mutex_unlock(&inode->i_mutex);
out:
+ if (pinned[0])
+ page_cache_release(pinned[0]);
+ if (pinned[1])
+ page_cache_release(pinned[1]);
*ppos = pos;
current->backing_dev_info = NULL;
+ mark_inode_dirty(inode);
return num_written ? num_written : err;
}