#include "print-tree.h"
#include "volumes.h"
#include "ordered-data.h"
+#include "xattr.h"
+#include "compat.h"
+#include "tree-log.h"
struct btrfs_iget_args {
u64 ino;
BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy));
mutex_lock(&BTRFS_I(inode)->extent_mutex);
- btrfs_drop_extent_cache(inode, start, start + num_bytes - 1);
+ btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
while(num_bytes > 0) {
cur_alloc_size = min(num_bytes, root->fs_info->max_extent);
ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
- root->sectorsize, 0, 0,
+ root->sectorsize, 0, alloc_hint,
(u64)-1, &ins, 1);
if (ret) {
WARN_ON(1);
break;
}
btrfs_drop_extent_cache(inode, start,
- start + ins.offset - 1);
+ start + ins.offset - 1, 0);
}
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered_extent;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+ struct btrfs_file_extent_item *extent_item;
+ struct btrfs_path *path = NULL;
+ struct extent_buffer *leaf;
u64 alloc_hint = 0;
struct list_head list;
struct btrfs_key ins;
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
goto nocow;
+ path = btrfs_alloc_path();
+ BUG_ON(!path);
+
lock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1,
GFP_NOFS);
INIT_LIST_HEAD(&list);
- ins.objectid = ordered_extent->start;
- ins.offset = ordered_extent->len;
- ins.type = BTRFS_EXTENT_ITEM_KEY;
-
- ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid,
- trans->transid, inode->i_ino,
- ordered_extent->file_offset, &ins);
- BUG_ON(ret);
-
mutex_lock(&BTRFS_I(inode)->extent_mutex);
ret = btrfs_drop_extents(trans, root, inode,
ordered_extent->len,
ordered_extent->file_offset, &alloc_hint);
BUG_ON(ret);
- ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
- ordered_extent->file_offset,
- ordered_extent->start,
- ordered_extent->len,
- ordered_extent->len, 0);
+
+ ins.objectid = inode->i_ino;
+ ins.offset = ordered_extent->file_offset;
+ ins.type = BTRFS_EXTENT_DATA_KEY;
+ ret = btrfs_insert_empty_item(trans, root, path, &ins,
+ sizeof(*extent_item));
BUG_ON(ret);
+ leaf = path->nodes[0];
+ extent_item = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ btrfs_set_file_extent_generation(leaf, extent_item, trans->transid);
+ btrfs_set_file_extent_type(leaf, extent_item, BTRFS_FILE_EXTENT_REG);
+ btrfs_set_file_extent_disk_bytenr(leaf, extent_item,
+ ordered_extent->start);
+ btrfs_set_file_extent_disk_num_bytes(leaf, extent_item,
+ ordered_extent->len);
+ btrfs_set_file_extent_offset(leaf, extent_item, 0);
+ btrfs_set_file_extent_num_bytes(leaf, extent_item,
+ ordered_extent->len);
+ btrfs_mark_buffer_dirty(leaf);
btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
ordered_extent->file_offset +
- ordered_extent->len - 1);
+ ordered_extent->len - 1, 0);
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
+ ins.objectid = ordered_extent->start;
+ ins.offset = ordered_extent->len;
+ ins.type = BTRFS_EXTENT_ITEM_KEY;
+ ret = btrfs_alloc_reserved_extent(trans, root, leaf->start,
+ root->root_key.objectid,
+ trans->transid, inode->i_ino,
+ ordered_extent->file_offset, &ins);
+ BUG_ON(ret);
+ btrfs_release_path(root, path);
+
inode->i_blocks += ordered_extent->len >> 9;
unlock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1,
add_pending_csums(trans, inode, ordered_extent->file_offset,
&ordered_extent->list);
+ mutex_lock(&BTRFS_I(inode)->extent_mutex);
btrfs_ordered_update_i_size(inode, ordered_extent);
+ btrfs_update_inode(trans, root, inode);
btrfs_remove_ordered_extent(inode, ordered_extent);
+ mutex_unlock(&BTRFS_I(inode)->extent_mutex);
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */
btrfs_put_ordered_extent(ordered_extent);
- btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
+ if (path)
+ btrfs_free_path(path);
return 0;
}
int ret = 0, nr_unlink = 0, nr_truncate = 0;
/* don't do orphan cleanup if the fs is readonly. */
- if (root->inode->i_sb->s_flags & MS_RDONLY)
+ if (root->fs_info->sb->s_flags & MS_RDONLY)
return;
path = btrfs_alloc_path();
btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
key.offset = (u64)-1;
- trans = btrfs_start_transaction(root, 1);
- btrfs_set_trans_block_group(trans, root->inode);
while (1) {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
* crossing root thing. we store the inode number in the
* offset of the orphan item.
*/
- inode = btrfs_iget_locked(root->inode->i_sb,
+ inode = btrfs_iget_locked(root->fs_info->sb,
found_key.offset, root);
if (!inode)
break;
* do a destroy_inode
*/
if (is_bad_inode(inode)) {
+ trans = btrfs_start_transaction(root, 1);
btrfs_orphan_del(trans, inode);
+ btrfs_end_transaction(trans, root);
iput(inode);
continue;
}
printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate);
btrfs_free_path(path);
- btrfs_end_transaction(trans, root);
}
void btrfs_read_locked_inode(struct inode *inode)
inode->i_ctime.tv_nsec = btrfs_timespec_nsec(leaf, tspec);
inode->i_blocks = btrfs_inode_nblocks(leaf, inode_item);
- inode->i_generation = btrfs_inode_generation(leaf, inode_item);
+ BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
+ inode->i_generation = BTRFS_I(inode)->generation;
inode->i_rdev = 0;
rdev = btrfs_inode_rdev(leaf, inode_item);
make_bad_inode(inode);
}
-static void fill_inode_item(struct extent_buffer *leaf,
+static void fill_inode_item(struct btrfs_trans_handle *trans,
+ struct extent_buffer *leaf,
struct btrfs_inode_item *item,
struct inode *inode)
{
inode->i_ctime.tv_nsec);
btrfs_set_inode_nblocks(leaf, item, inode->i_blocks);
- btrfs_set_inode_generation(leaf, item, inode->i_generation);
+ btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
+ btrfs_set_inode_transid(leaf, item, trans->transid);
btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
btrfs_set_inode_block_group(leaf, item,
inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item);
- fill_inode_item(leaf, inode_item, inode);
+ fill_inode_item(trans, leaf, inode_item, inode);
btrfs_mark_buffer_dirty(leaf);
btrfs_set_inode_last_trans(trans, inode);
ret = 0;
}
-static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct inode *dir,
- struct dentry *dentry)
+int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct inode *dir, struct inode *inode,
+ const char *name, int name_len)
{
struct btrfs_path *path;
- const char *name = dentry->d_name.name;
- int name_len = dentry->d_name.len;
int ret = 0;
struct extent_buffer *leaf;
struct btrfs_dir_item *di;
btrfs_release_path(root, path);
ret = btrfs_del_inode_ref(trans, root, name, name_len,
- dentry->d_inode->i_ino,
- dentry->d_parent->d_inode->i_ino, &index);
+ inode->i_ino,
+ dir->i_ino, &index);
if (ret) {
printk("failed to delete reference to %.*s, "
"inode %lu parent %lu\n", name_len, name,
- dentry->d_inode->i_ino,
- dentry->d_parent->d_inode->i_ino);
+ inode->i_ino, dir->i_ino);
goto err;
}
ret = btrfs_delete_one_dir_name(trans, root, path, di);
btrfs_release_path(root, path);
- dentry->d_inode->i_ctime = dir->i_ctime;
+ ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
+ inode, dir->i_ino);
+ BUG_ON(ret != 0 && ret != -ENOENT);
+ if (ret != -ENOENT)
+ BTRFS_I(dir)->log_dirty_trans = trans->transid;
+
+ ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
+ dir, index);
+ BUG_ON(ret);
err:
btrfs_free_path(path);
- if (!ret) {
- btrfs_i_size_write(dir, dir->i_size - name_len * 2);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- btrfs_update_inode(trans, root, dir);
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
- dentry->d_inode->i_nlink--;
-#else
- drop_nlink(dentry->d_inode);
-#endif
- ret = btrfs_update_inode(trans, root, dentry->d_inode);
- dir->i_sb->s_dirt = 1;
- }
+ if (ret)
+ goto out;
+
+ btrfs_i_size_write(dir, dir->i_size - name_len * 2);
+ inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ btrfs_update_inode(trans, root, dir);
+ btrfs_drop_nlink(inode);
+ ret = btrfs_update_inode(trans, root, inode);
+ dir->i_sb->s_dirt = 1;
+out:
return ret;
}
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, dir);
- ret = btrfs_unlink_trans(trans, root, dir, dentry);
+ ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
+ dentry->d_name.name, dentry->d_name.len);
if (inode->i_nlink == 0)
ret = btrfs_orphan_add(trans, inode);
goto fail_trans;
/* now the directory is empty */
- err = btrfs_unlink_trans(trans, root, dir, dentry);
+ err = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
+ dentry->d_name.name, dentry->d_name.len);
if (!err) {
btrfs_i_size_write(inode, 0);
}
* min_type is the minimum key type to truncate down to. If set to 0, this
* will kill all the items on this inode, including the INODE_ITEM_KEY.
*/
-static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct inode *inode,
- u32 min_type)
+noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct inode *inode,
+ u64 new_size, u32 min_type)
{
int ret;
struct btrfs_path *path;
int extent_type = -1;
u64 mask = root->sectorsize - 1;
- btrfs_drop_extent_cache(inode, inode->i_size & (~mask), (u64)-1);
+ if (root->ref_cows)
+ btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
path = btrfs_alloc_path();
path->reada = -1;
BUG_ON(!path);
goto error;
}
if (ret > 0) {
- BUG_ON(path->slots[0] == 0);
+ /* there are no items in the tree for us to truncate, we're
+ * done
+ */
+ if (path->slots[0] == 0) {
+ ret = 0;
+ goto error;
+ }
path->slots[0]--;
}
}
if (found_type == BTRFS_CSUM_ITEM_KEY) {
ret = btrfs_csum_truncate(trans, root, path,
- inode->i_size);
+ new_size);
BUG_ON(ret);
}
- if (item_end < inode->i_size) {
+ if (item_end < new_size) {
if (found_type == BTRFS_DIR_ITEM_KEY) {
found_type = BTRFS_INODE_ITEM_KEY;
} else if (found_type == BTRFS_EXTENT_ITEM_KEY) {
btrfs_set_key_type(&key, found_type);
goto next;
}
- if (found_key.offset >= inode->i_size)
+ if (found_key.offset >= new_size)
del_item = 1;
else
del_item = 0;
if (!del_item) {
u64 orig_num_bytes =
btrfs_file_extent_num_bytes(leaf, fi);
- extent_num_bytes = inode->i_size -
+ extent_num_bytes = new_size -
found_key.offset + root->sectorsize - 1;
extent_num_bytes = extent_num_bytes &
~((u64)root->sectorsize - 1);
extent_num_bytes);
num_dec = (orig_num_bytes -
extent_num_bytes);
- if (extent_start != 0)
+ if (root->ref_cows && extent_start != 0)
dec_i_blocks(inode, num_dec);
btrfs_mark_buffer_dirty(leaf);
} else {
num_dec = btrfs_file_extent_num_bytes(leaf, fi);
if (extent_start != 0) {
found_extent = 1;
- dec_i_blocks(inode, num_dec);
+ if (root->ref_cows)
+ dec_i_blocks(inode, num_dec);
}
root_gen = btrfs_header_generation(leaf);
root_owner = btrfs_header_owner(leaf);
}
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
if (!del_item) {
- u32 newsize = inode->i_size - found_key.offset;
- dec_i_blocks(inode, item_end + 1 -
- found_key.offset - newsize);
- newsize =
- btrfs_file_extent_calc_inline_size(newsize);
+ u32 size = new_size - found_key.offset;
+
+ if (root->ref_cows) {
+ dec_i_blocks(inode, item_end + 1 -
+ found_key.offset - size);
+ }
+ size =
+ btrfs_file_extent_calc_inline_size(size);
ret = btrfs_truncate_item(trans, root, path,
- newsize, 1);
+ size, 1);
BUG_ON(ret);
- } else {
+ } else if (root->ref_cows) {
dec_i_blocks(inode, item_end + 1 -
found_key.offset);
}
if (found_extent) {
ret = btrfs_free_extent(trans, root, extent_start,
extent_num_bytes,
- root_owner,
+ leaf->start, root_owner,
root_gen, inode->i_ino,
found_key.offset, 0);
BUG_ON(ret);
hole_start, 0, 0,
hole_size, 0);
btrfs_drop_extent_cache(inode, hole_start,
- (u64)-1);
+ (u64)-1, 0);
btrfs_check_file(root, inode);
}
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
- ret = btrfs_truncate_in_trans(trans, root, inode, 0);
+ ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, 0);
if (ret) {
btrfs_orphan_del(NULL, inode);
goto no_delete_lock;
return 0;
}
-static int btrfs_init_locked_inode(struct inode *inode, void *p)
+static noinline void init_btrfs_i(struct inode *inode)
{
- struct btrfs_iget_args *args = p;
- inode->i_ino = args->ino;
- BTRFS_I(inode)->root = args->root;
- BTRFS_I(inode)->delalloc_bytes = 0;
- inode->i_mapping->writeback_index = 0;
- BTRFS_I(inode)->disk_i_size = 0;
- BTRFS_I(inode)->index_cnt = (u64)-1;
+ struct btrfs_inode *bi = BTRFS_I(inode);
+
+ bi->i_acl = NULL;
+ bi->i_default_acl = NULL;
+
+ bi->generation = 0;
+ bi->last_trans = 0;
+ bi->logged_trans = 0;
+ bi->delalloc_bytes = 0;
+ bi->disk_i_size = 0;
+ bi->flags = 0;
+ bi->index_cnt = (u64)-1;
+ bi->log_dirty_trans = 0;
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
inode->i_mapping, GFP_NOFS);
btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
mutex_init(&BTRFS_I(inode)->csum_mutex);
mutex_init(&BTRFS_I(inode)->extent_mutex);
+ mutex_init(&BTRFS_I(inode)->log_mutex);
+}
+
+static int btrfs_init_locked_inode(struct inode *inode, void *p)
+{
+ struct btrfs_iget_args *args = p;
+ inode->i_ino = args->ino;
+ init_btrfs_i(inode);
+ BTRFS_I(inode)->root = args->root;
return 0;
}
}
struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
- u64 root_objectid)
+ struct btrfs_root *root, int wait)
{
+ struct inode *inode;
struct btrfs_iget_args args;
args.ino = objectid;
- args.root = btrfs_lookup_fs_root(btrfs_sb(s)->fs_info, root_objectid);
-
- if (!args.root)
- return NULL;
+ args.root = root;
- return ilookup5(s, objectid, btrfs_find_actor, (void *)&args);
+ if (wait) {
+ inode = ilookup5(s, objectid, btrfs_find_actor,
+ (void *)&args);
+ } else {
+ inode = ilookup5_nowait(s, objectid, btrfs_find_actor,
+ (void *)&args);
+ }
+ return inode;
}
struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
return ret;
}
-/* Kernels earlier than 2.6.28 still have the NFS deadlock where nfsd
- will call the file system's ->lookup() method from within its
- filldir callback, which in turn was called from the file system's
- ->readdir() method. And will deadlock for many file systems. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-
-struct nfshack_dirent {
- u64 ino;
- loff_t offset;
- int namlen;
- unsigned int d_type;
- char name[];
-};
-
-struct nfshack_readdir {
- char *dirent;
- size_t used;
-};
-
-
-
-static int btrfs_nfshack_filldir(void *__buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct nfshack_readdir *buf = __buf;
- struct nfshack_dirent *de = (void *)(buf->dirent + buf->used);
- unsigned int reclen;
-
- reclen = ALIGN(sizeof(struct nfshack_dirent) + namlen, sizeof(u64));
- if (buf->used + reclen > PAGE_SIZE)
- return -EINVAL;
-
- de->namlen = namlen;
- de->offset = offset;
- de->ino = ino;
- de->d_type = d_type;
- memcpy(de->name, name, namlen);
- buf->used += reclen;
-
- return 0;
-}
-
-static int btrfs_nfshack_readdir(struct file *file, void *dirent,
- filldir_t filldir)
-{
- struct nfshack_readdir buf;
- struct nfshack_dirent *de;
- int err;
- int size;
- loff_t offset;
-
- buf.dirent = (void *)__get_free_page(GFP_KERNEL);
- if (!buf.dirent)
- return -ENOMEM;
-
- offset = file->f_pos;
-
- while (1) {
- unsigned int reclen;
-
- buf.used = 0;
-
- err = btrfs_real_readdir(file, &buf, btrfs_nfshack_filldir);
- if (err)
- break;
-
- size = buf.used;
-
- if (!size)
- break;
-
- de = (struct nfshack_dirent *)buf.dirent;
- while (size > 0) {
- offset = de->offset;
-
- if (filldir(dirent, de->name, de->namlen, de->offset,
- de->ino, de->d_type))
- goto done;
- offset = file->f_pos;
-
- reclen = ALIGN(sizeof(*de) + de->namlen,
- sizeof(u64));
- size -= reclen;
- de = (struct nfshack_dirent *)((char *)de + reclen);
- }
- }
-
- done:
- free_page((unsigned long)buf.dirent);
- file->f_pos = offset;
-
- return err;
-}
-#endif
-
int btrfs_write_inode(struct inode *inode, int wait)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
if (BTRFS_I(dir)->index_cnt == (u64)-1) {
ret = btrfs_set_inode_index_count(dir);
- if (ret)
+ if (ret) {
return ret;
+ }
}
*index = BTRFS_I(dir)->index_cnt;
* btrfs_get_inode_index_count has an explanation for the magic
* number
*/
+ init_btrfs_i(inode);
BTRFS_I(inode)->index_cnt = 2;
-
- extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_tree,
- inode->i_mapping, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
- inode->i_mapping, GFP_NOFS);
- btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
- INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
- mutex_init(&BTRFS_I(inode)->csum_mutex);
- mutex_init(&BTRFS_I(inode)->extent_mutex);
- BTRFS_I(inode)->delalloc_bytes = 0;
- inode->i_mapping->writeback_index = 0;
- BTRFS_I(inode)->disk_i_size = 0;
BTRFS_I(inode)->root = root;
+ BTRFS_I(inode)->generation = trans->transid;
if (mode & S_IFDIR)
owner = 0;
new_inode_group = group;
}
BTRFS_I(inode)->block_group = new_inode_group;
- BTRFS_I(inode)->flags = 0;
key[0].objectid = objectid;
btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_item);
- fill_inode_item(path->nodes[0], inode_item, inode);
+ fill_inode_item(trans, path->nodes[0], inode_item, inode);
ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
struct btrfs_inode_ref);
return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
}
-static int btrfs_add_link(struct btrfs_trans_handle *trans,
- struct dentry *dentry, struct inode *inode,
- int add_backref, u64 index)
+int btrfs_add_link(struct btrfs_trans_handle *trans,
+ struct inode *parent_inode, struct inode *inode,
+ const char *name, int name_len, int add_backref, u64 index)
{
int ret;
struct btrfs_key key;
- struct btrfs_root *root = BTRFS_I(dentry->d_parent->d_inode)->root;
- struct inode *parent_inode = dentry->d_parent->d_inode;
+ struct btrfs_root *root = BTRFS_I(parent_inode)->root;
key.objectid = inode->i_ino;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0;
- ret = btrfs_insert_dir_item(trans, root,
- dentry->d_name.name, dentry->d_name.len,
- dentry->d_parent->d_inode->i_ino,
+ ret = btrfs_insert_dir_item(trans, root, name, name_len,
+ parent_inode->i_ino,
&key, btrfs_inode_type(inode),
index);
if (ret == 0) {
if (add_backref) {
ret = btrfs_insert_inode_ref(trans, root,
- dentry->d_name.name,
- dentry->d_name.len,
- inode->i_ino,
- parent_inode->i_ino,
- index);
+ name, name_len,
+ inode->i_ino,
+ parent_inode->i_ino,
+ index);
}
btrfs_i_size_write(parent_inode, parent_inode->i_size +
- dentry->d_name.len * 2);
+ name_len * 2);
parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
- ret = btrfs_update_inode(trans, root,
- dentry->d_parent->d_inode);
+ ret = btrfs_update_inode(trans, root, parent_inode);
}
return ret;
}
struct dentry *dentry, struct inode *inode,
int backref, u64 index)
{
- int err = btrfs_add_link(trans, dentry, inode, backref, index);
+ int err = btrfs_add_link(trans, dentry->d_parent->d_inode,
+ inode, dentry->d_name.name,
+ dentry->d_name.len, backref, index);
if (!err) {
d_instantiate(dentry, inode);
return 0;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_file_inode_operations;
- extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_tree,
- inode->i_mapping, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
- inode->i_mapping, GFP_NOFS);
- INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
- mutex_init(&BTRFS_I(inode)->csum_mutex);
- mutex_init(&BTRFS_I(inode)->extent_mutex);
- BTRFS_I(inode)->delalloc_bytes = 0;
- BTRFS_I(inode)->disk_i_size = 0;
- inode->i_mapping->writeback_index = 0;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
- btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
}
dir->i_sb->s_dirt = 1;
btrfs_update_inode_block_group(trans, inode);
if (inode->i_nlink == 0)
return -ENOENT;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
- inode->i_nlink++;
-#else
- inc_nlink(inode);
-#endif
+ btrfs_inc_nlink(inode);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto fail;
if (err)
goto out_fail;
- err = btrfs_add_link(trans, dentry, inode, 0, index);
+ err = btrfs_add_link(trans, dentry->d_parent->d_inode,
+ inode, dentry->d_name.name,
+ dentry->d_name.len, 0, index);
if (err)
goto out_fail;
static int btrfs_releasepage(struct page *page, gfp_t gfp_flags)
{
+ if (PageWriteback(page) || PageDirty(page))
+ return 0;
return __btrfs_releasepage(page, gfp_flags);
}
if (ret)
goto out;
/* FIXME, add redo link to tree so we don't leak on crash */
- ret = btrfs_truncate_in_trans(trans, root, inode,
+ ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size,
BTRFS_EXTENT_DATA_KEY);
btrfs_update_inode(trans, root, inode);
{
pgoff_t req_size = last_index - offset + 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
- offset = page_cache_readahead(mapping, ra, file, offset, req_size);
- return offset;
-#else
page_cache_sync_readahead(mapping, ra, file, offset, req_size);
return offset + req_size;
-#endif
}
struct inode *btrfs_alloc_inode(struct super_block *sb)
if (!ei)
return NULL;
ei->last_trans = 0;
+ ei->logged_trans = 0;
btrfs_ordered_inode_tree_init(&ei->ordered_tree);
ei->i_acl = BTRFS_ACL_NOT_CACHED;
ei->i_default_acl = BTRFS_ACL_NOT_CACHED;
btrfs_put_ordered_extent(ordered);
}
}
- btrfs_drop_extent_cache(inode, 0, (u64)-1);
+ btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
static void init_once(void *foo)
-#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
-static void init_once(struct kmem_cache * cachep, void *foo)
-#else
-static void init_once(void * foo, struct kmem_cache * cachep,
- unsigned long flags)
-#endif
{
struct btrfs_inode *ei = (struct btrfs_inode *) foo;
struct kmem_cache *btrfs_cache_create(const char *name, size_t size,
unsigned long extra_flags,
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
- void (*ctor)(void *)
-#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
- void (*ctor)(struct kmem_cache *, void *)
-#else
- void (*ctor)(void *, struct kmem_cache *,
- unsigned long)
-#endif
- )
+ void (*ctor)(void *))
{
return kmem_cache_create(name, size, 0, (SLAB_RECLAIM_ACCOUNT |
- SLAB_MEM_SPREAD | extra_flags), ctor
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
- ,NULL
-#endif
- );
+ SLAB_MEM_SPREAD | extra_flags), ctor);
}
int btrfs_init_cachep(void)
btrfs_set_trans_block_group(trans, new_dir);
- old_dentry->d_inode->i_nlink++;
+ btrfs_inc_nlink(old_dentry->d_inode);
old_dir->i_ctime = old_dir->i_mtime = ctime;
new_dir->i_ctime = new_dir->i_mtime = ctime;
old_inode->i_ctime = ctime;
- ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry);
+ ret = btrfs_unlink_inode(trans, root, old_dir, old_dentry->d_inode,
+ old_dentry->d_name.name,
+ old_dentry->d_name.len);
if (ret)
goto out_fail;
if (new_inode) {
new_inode->i_ctime = CURRENT_TIME;
- ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry);
+ ret = btrfs_unlink_inode(trans, root, new_dir,
+ new_dentry->d_inode,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len);
if (ret)
goto out_fail;
if (new_inode->i_nlink == 0) {
- ret = btrfs_orphan_add(trans, new_inode);
+ ret = btrfs_orphan_add(trans, new_dentry->d_inode);
if (ret)
goto out_fail;
}
+
}
ret = btrfs_set_inode_index(new_dir, old_inode, &index);
if (ret)
goto out_fail;
- ret = btrfs_add_link(trans, new_dentry, old_inode, 1, index);
+ ret = btrfs_add_link(trans, new_dentry->d_parent->d_inode,
+ old_inode, new_dentry->d_name.name,
+ new_dentry->d_name.len, 1, index);
if (ret)
goto out_fail;
{
struct list_head *head = &root->fs_info->delalloc_inodes;
struct btrfs_inode *binode;
+ struct inode *inode;
unsigned long flags;
spin_lock_irqsave(&root->fs_info->delalloc_lock, flags);
while(!list_empty(head)) {
binode = list_entry(head->next, struct btrfs_inode,
delalloc_inodes);
- atomic_inc(&binode->vfs_inode.i_count);
+ inode = igrab(&binode->vfs_inode);
+ if (!inode)
+ list_del_init(&binode->delalloc_inodes);
spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags);
- filemap_write_and_wait(binode->vfs_inode.i_mapping);
- iput(&binode->vfs_inode);
+ if (inode) {
+ filemap_flush(inode->i_mapping);
+ iput(inode);
+ }
+ cond_resched();
spin_lock_irqsave(&root->fs_info->delalloc_lock, flags);
}
spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags);
+
+ /* the filemap_flush will queue IO into the worker threads, but
+ * we have to make sure the IO is actually started and that
+ * ordered extents get created before we return
+ */
+ atomic_inc(&root->fs_info->async_submit_draining);
+ while(atomic_read(&root->fs_info->nr_async_submits)) {
+ wait_event(root->fs_info->async_submit_wait,
+ (atomic_read(&root->fs_info->nr_async_submits) == 0));
+ }
+ atomic_dec(&root->fs_info->async_submit_draining);
return 0;
}
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_file_inode_operations;
- extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_tree,
- inode->i_mapping, GFP_NOFS);
- extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
- inode->i_mapping, GFP_NOFS);
- INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
- mutex_init(&BTRFS_I(inode)->csum_mutex);
- mutex_init(&BTRFS_I(inode)->extent_mutex);
- BTRFS_I(inode)->delalloc_bytes = 0;
- BTRFS_I(inode)->disk_i_size = 0;
- inode->i_mapping->writeback_index = 0;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
- btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
}
dir->i_sb->s_dirt = 1;
btrfs_update_inode_block_group(trans, inode);
return __set_page_dirty_nobuffers(page);
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
static int btrfs_permission(struct inode *inode, int mask)
-#else
-static int btrfs_permission(struct inode *inode, int mask,
- struct nameidata *nd)
-#endif
{
if (btrfs_test_flag(inode, READONLY) && (mask & MAY_WRITE))
return -EACCES;
.symlink = btrfs_symlink,
.setattr = btrfs_setattr,
.mknod = btrfs_mknod,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
+ .setxattr = btrfs_setxattr,
+ .getxattr = btrfs_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
+ .removexattr = btrfs_removexattr,
.permission = btrfs_permission,
};
static struct inode_operations btrfs_dir_ro_inode_operations = {
static struct file_operations btrfs_dir_file_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- .readdir = btrfs_nfshack_readdir,
-#else /* NFSd readdir/lookup deadlock is fixed */
.readdir = btrfs_real_readdir,
-#endif
.unlocked_ioctl = btrfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = btrfs_ioctl,
#endif
.release = btrfs_release_file,
+ .fsync = btrfs_sync_file,
};
static struct extent_io_ops btrfs_extent_io_ops = {
.truncate = btrfs_truncate,
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
+ .setxattr = btrfs_setxattr,
+ .getxattr = btrfs_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
+ .removexattr = btrfs_removexattr,
.permission = btrfs_permission,
};
static struct inode_operations btrfs_special_inode_operations = {
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
+ .setxattr = btrfs_setxattr,
+ .getxattr = btrfs_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
+ .removexattr = btrfs_removexattr,
};
static struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink,