Merge branch 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (45 commits) Btrfs: fix __btrfs_map_block on 32 bit machines btrfs: fix possible deadlock by clearing __GFP_FS flag btrfs: check link counter overflow in link(2) btrfs: don't mess with i_nlink of unlocked inode in rename() Btrfs: check return value of btrfs_alloc_path() Btrfs: fix OOPS of empty filesystem after balance Btrfs: fix memory leak of empty filesystem after balance Btrfs: fix return value of setflags ioctl Btrfs: fix uncheck memory allocations btrfs: make inode ref log recovery faster Btrfs: add btrfs_trim_fs() to handle FITRIM Btrfs: adjust btrfs_discard_extent() return errors and trimmed bytes Btrfs: make btrfs_map_block() return entire free extent for each device of RAID0/1/10/DUP Btrfs: make update_reserved_bytes() public btrfs: return EXDEV when linking from different subvolumes Btrfs: Per file/directory controls for COW and compression Btrfs: add datacow flag in inode flag btrfs: use GFP_NOFS instead of GFP_KERNEL Btrfs: check return value of read_tree_block() btrfs: properly access unaligned checksum buffer ... Fix up trivial conflicts in fs/btrfs/volumes.c due to plug removal in the block layer.
This commit is contained in:
366
fs/btrfs/inode.c
366
fs/btrfs/inode.c
@@ -50,6 +50,7 @@
|
||||
#include "tree-log.h"
|
||||
#include "compression.h"
|
||||
#include "locking.h"
|
||||
#include "free-space-cache.h"
|
||||
|
||||
struct btrfs_iget_args {
|
||||
u64 ino;
|
||||
@@ -70,6 +71,7 @@ static struct kmem_cache *btrfs_inode_cachep;
|
||||
struct kmem_cache *btrfs_trans_handle_cachep;
|
||||
struct kmem_cache *btrfs_transaction_cachep;
|
||||
struct kmem_cache *btrfs_path_cachep;
|
||||
struct kmem_cache *btrfs_free_space_cachep;
|
||||
|
||||
#define S_SHIFT 12
|
||||
static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
|
||||
@@ -82,7 +84,8 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
|
||||
[S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK,
|
||||
};
|
||||
|
||||
static void btrfs_truncate(struct inode *inode);
|
||||
static int btrfs_setsize(struct inode *inode, loff_t newsize);
|
||||
static int btrfs_truncate(struct inode *inode);
|
||||
static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end);
|
||||
static noinline int cow_file_range(struct inode *inode,
|
||||
struct page *locked_page,
|
||||
@@ -288,6 +291,7 @@ static noinline int add_async_extent(struct async_cow *cow,
|
||||
struct async_extent *async_extent;
|
||||
|
||||
async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
|
||||
BUG_ON(!async_extent);
|
||||
async_extent->start = start;
|
||||
async_extent->ram_size = ram_size;
|
||||
async_extent->compressed_size = compressed_size;
|
||||
@@ -382,9 +386,11 @@ again:
|
||||
*/
|
||||
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) &&
|
||||
(btrfs_test_opt(root, COMPRESS) ||
|
||||
(BTRFS_I(inode)->force_compress))) {
|
||||
(BTRFS_I(inode)->force_compress) ||
|
||||
(BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS))) {
|
||||
WARN_ON(pages);
|
||||
pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
|
||||
BUG_ON(!pages);
|
||||
|
||||
if (BTRFS_I(inode)->force_compress)
|
||||
compress_type = BTRFS_I(inode)->force_compress;
|
||||
@@ -1254,7 +1260,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
|
||||
ret = run_delalloc_nocow(inode, locked_page, start, end,
|
||||
page_started, 0, nr_written);
|
||||
else if (!btrfs_test_opt(root, COMPRESS) &&
|
||||
!(BTRFS_I(inode)->force_compress))
|
||||
!(BTRFS_I(inode)->force_compress) &&
|
||||
!(BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS))
|
||||
ret = cow_file_range(inode, locked_page, start, end,
|
||||
page_started, nr_written, 1);
|
||||
else
|
||||
@@ -1461,8 +1468,11 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||
if (bio_flags & EXTENT_BIO_COMPRESSED) {
|
||||
return btrfs_submit_compressed_read(inode, bio,
|
||||
mirror_num, bio_flags);
|
||||
} else if (!skip_sum)
|
||||
btrfs_lookup_bio_sums(root, inode, bio, NULL);
|
||||
} else if (!skip_sum) {
|
||||
ret = btrfs_lookup_bio_sums(root, inode, bio, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
goto mapit;
|
||||
} else if (!skip_sum) {
|
||||
/* csum items have already been cloned */
|
||||
@@ -1785,6 +1795,8 @@ out:
|
||||
static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||
struct extent_state *state, int uptodate)
|
||||
{
|
||||
trace_btrfs_writepage_end_io_hook(page, start, end, uptodate);
|
||||
|
||||
ClearPagePrivate2(page);
|
||||
return btrfs_finish_ordered_io(page->mapping->host, start, end);
|
||||
}
|
||||
@@ -1895,10 +1907,10 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
|
||||
else
|
||||
rw = READ;
|
||||
|
||||
BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio,
|
||||
ret = BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio,
|
||||
failrec->last_mirror,
|
||||
failrec->bio_flags, 0);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2282,7 +2294,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
|
||||
* this cleans up any orphans that may be left on the list from the last use
|
||||
* of this root.
|
||||
*/
|
||||
void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *leaf;
|
||||
@@ -2292,10 +2304,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
int ret = 0, nr_unlink = 0, nr_truncate = 0;
|
||||
|
||||
if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
path->reada = -1;
|
||||
|
||||
key.objectid = BTRFS_ORPHAN_OBJECTID;
|
||||
@@ -2304,11 +2319,8 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
|
||||
while (1) {
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Error searching slot for orphan: %d"
|
||||
"\n", ret);
|
||||
break;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* if ret == 0 means we found what we were searching for, which
|
||||
@@ -2316,6 +2328,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
* find the key and see if we have stuff that matches
|
||||
*/
|
||||
if (ret > 0) {
|
||||
ret = 0;
|
||||
if (path->slots[0] == 0)
|
||||
break;
|
||||
path->slots[0]--;
|
||||
@@ -2343,7 +2356,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
found_key.type = BTRFS_INODE_ITEM_KEY;
|
||||
found_key.offset = 0;
|
||||
inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
|
||||
BUG_ON(IS_ERR(inode));
|
||||
if (IS_ERR(inode)) {
|
||||
ret = PTR_ERR(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* add this inode to the orphan list so btrfs_orphan_del does
|
||||
@@ -2361,7 +2377,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
*/
|
||||
if (is_bad_inode(inode)) {
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
goto out;
|
||||
}
|
||||
btrfs_orphan_del(trans, inode);
|
||||
btrfs_end_transaction(trans, root);
|
||||
iput(inode);
|
||||
@@ -2370,17 +2389,22 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
|
||||
/* if we have links, this was a truncate, lets do that */
|
||||
if (inode->i_nlink) {
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
WARN_ON(1);
|
||||
iput(inode);
|
||||
continue;
|
||||
}
|
||||
nr_truncate++;
|
||||
btrfs_truncate(inode);
|
||||
ret = btrfs_truncate(inode);
|
||||
} else {
|
||||
nr_unlink++;
|
||||
}
|
||||
|
||||
/* this will do delete_inode and everything for us */
|
||||
iput(inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
btrfs_free_path(path);
|
||||
|
||||
root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
|
||||
|
||||
if (root->orphan_block_rsv)
|
||||
@@ -2389,14 +2413,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
|
||||
if (root->orphan_block_rsv || root->orphan_item_inserted) {
|
||||
trans = btrfs_join_transaction(root, 1);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (!IS_ERR(trans))
|
||||
btrfs_end_transaction(trans, root);
|
||||
}
|
||||
|
||||
if (nr_unlink)
|
||||
printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
|
||||
if (nr_truncate)
|
||||
printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
printk(KERN_CRIT "btrfs: could not do orphan cleanup %d\n", ret);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2507,6 +2537,8 @@ static void btrfs_read_locked_inode(struct inode *inode)
|
||||
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
|
||||
|
||||
alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
|
||||
if (location.objectid == BTRFS_FREE_SPACE_OBJECTID)
|
||||
inode->i_mapping->flags &= ~__GFP_FS;
|
||||
|
||||
/*
|
||||
* try to precache a NULL acl entry for files that don't have
|
||||
@@ -2635,10 +2667,10 @@ failed:
|
||||
* recovery code. It remove a link in a directory with a given name, and
|
||||
* also drops the back refs in the inode to the directory
|
||||
*/
|
||||
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)
|
||||
static 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;
|
||||
int ret = 0;
|
||||
@@ -2710,12 +2742,25 @@ err:
|
||||
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);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
|
||||
if (!ret) {
|
||||
btrfs_drop_nlink(inode);
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* helper to check if there is any shared block in the path */
|
||||
static int check_path_shared(struct btrfs_root *root,
|
||||
struct btrfs_path *path)
|
||||
@@ -3537,7 +3582,13 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_cont_expand(struct inode *inode, loff_t size)
|
||||
/*
|
||||
* This function puts in dummy file extents for the area we're creating a hole
|
||||
* for. So if we are truncating this file to a larger size we need to insert
|
||||
* these file extents so that btrfs_get_extent will return a EXTENT_MAP_HOLE for
|
||||
* the range between oldsize and size
|
||||
*/
|
||||
int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
@@ -3545,7 +3596,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
|
||||
struct extent_map *em = NULL;
|
||||
struct extent_state *cached_state = NULL;
|
||||
u64 mask = root->sectorsize - 1;
|
||||
u64 hole_start = (inode->i_size + mask) & ~mask;
|
||||
u64 hole_start = (oldsize + mask) & ~mask;
|
||||
u64 block_end = (size + mask) & ~mask;
|
||||
u64 last_byte;
|
||||
u64 cur_offset;
|
||||
@@ -3590,13 +3641,15 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
|
||||
err = btrfs_drop_extents(trans, inode, cur_offset,
|
||||
cur_offset + hole_size,
|
||||
&hint_byte, 1);
|
||||
BUG_ON(err);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
err = btrfs_insert_file_extent(trans, root,
|
||||
inode->i_ino, cur_offset, 0,
|
||||
0, hole_size, 0, hole_size,
|
||||
0, 0, 0);
|
||||
BUG_ON(err);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
btrfs_drop_extent_cache(inode, hole_start,
|
||||
last_byte - 1, 0);
|
||||
@@ -3616,81 +3669,41 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
|
||||
static int btrfs_setsize(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
unsigned long nr;
|
||||
loff_t oldsize = i_size_read(inode);
|
||||
int ret;
|
||||
|
||||
if (attr->ia_size == inode->i_size)
|
||||
if (newsize == oldsize)
|
||||
return 0;
|
||||
|
||||
if (attr->ia_size > inode->i_size) {
|
||||
unsigned long limit;
|
||||
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
|
||||
if (attr->ia_size > inode->i_sb->s_maxbytes)
|
||||
return -EFBIG;
|
||||
if (limit != RLIM_INFINITY && attr->ia_size > limit) {
|
||||
send_sig(SIGXFSZ, current, 0);
|
||||
return -EFBIG;
|
||||
}
|
||||
}
|
||||
|
||||
trans = btrfs_start_transaction(root, 5);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
|
||||
ret = btrfs_orphan_add(trans, inode);
|
||||
BUG_ON(ret);
|
||||
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
|
||||
if (attr->ia_size > inode->i_size) {
|
||||
ret = btrfs_cont_expand(inode, attr->ia_size);
|
||||
if (newsize > oldsize) {
|
||||
i_size_write(inode, newsize);
|
||||
btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
|
||||
truncate_pagecache(inode, oldsize, newsize);
|
||||
ret = btrfs_cont_expand(inode, oldsize, newsize);
|
||||
if (ret) {
|
||||
btrfs_truncate(inode);
|
||||
btrfs_setsize(inode, oldsize);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i_size_write(inode, attr->ia_size);
|
||||
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
|
||||
mark_inode_dirty(inode);
|
||||
} else {
|
||||
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
trans->block_rsv = root->orphan_block_rsv;
|
||||
BUG_ON(!trans->block_rsv);
|
||||
/*
|
||||
* We're truncating a file that used to have good data down to
|
||||
* zero. Make sure it gets into the ordered flush list so that
|
||||
* any new writes get down to disk quickly.
|
||||
*/
|
||||
if (newsize == 0)
|
||||
BTRFS_I(inode)->ordered_data_close = 1;
|
||||
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
BUG_ON(ret);
|
||||
if (inode->i_nlink > 0) {
|
||||
ret = btrfs_orphan_del(trans, inode);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
return 0;
|
||||
/* we don't support swapfiles, so vmtruncate shouldn't fail */
|
||||
truncate_setsize(inode, newsize);
|
||||
ret = btrfs_truncate(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* We're truncating a file that used to have good data down to
|
||||
* zero. Make sure it gets into the ordered flush list so that
|
||||
* any new writes get down to disk quickly.
|
||||
*/
|
||||
if (attr->ia_size == 0)
|
||||
BTRFS_I(inode)->ordered_data_close = 1;
|
||||
|
||||
/* we don't support swapfiles, so vmtruncate shouldn't fail */
|
||||
ret = vmtruncate(inode, attr->ia_size);
|
||||
BUG_ON(ret);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
@@ -3707,7 +3720,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
return err;
|
||||
|
||||
if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
|
||||
err = btrfs_setattr_size(inode, attr);
|
||||
err = btrfs_setsize(inode, attr->ia_size);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -3730,6 +3743,8 @@ void btrfs_evict_inode(struct inode *inode)
|
||||
unsigned long nr;
|
||||
int ret;
|
||||
|
||||
trace_btrfs_inode_evict(inode);
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
|
||||
root == root->fs_info->tree_root))
|
||||
@@ -4072,7 +4087,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
|
||||
BTRFS_I(inode)->root = root;
|
||||
memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
|
||||
btrfs_read_locked_inode(inode);
|
||||
|
||||
inode_tree_add(inode);
|
||||
unlock_new_inode(inode);
|
||||
if (new)
|
||||
@@ -4147,8 +4161,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
||||
if (!IS_ERR(inode) && root != sub_root) {
|
||||
down_read(&root->fs_info->cleanup_work_sem);
|
||||
if (!(inode->i_sb->s_flags & MS_RDONLY))
|
||||
btrfs_orphan_cleanup(sub_root);
|
||||
ret = btrfs_orphan_cleanup(sub_root);
|
||||
up_read(&root->fs_info->cleanup_work_sem);
|
||||
if (ret)
|
||||
inode = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return inode;
|
||||
@@ -4282,6 +4298,9 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||
while (di_cur < di_total) {
|
||||
struct btrfs_key location;
|
||||
|
||||
if (verify_dir_item(root, leaf, di))
|
||||
break;
|
||||
|
||||
name_len = btrfs_dir_name_len(leaf, di);
|
||||
if (name_len <= sizeof(tmp_name)) {
|
||||
name_ptr = tmp_name;
|
||||
@@ -4517,6 +4536,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (dir) {
|
||||
trace_btrfs_inode_request(dir);
|
||||
|
||||
ret = btrfs_set_inode_index(dir, index);
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
@@ -4585,12 +4606,16 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
if ((mode & S_IFREG)) {
|
||||
if (btrfs_test_opt(root, NODATASUM))
|
||||
BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
|
||||
if (btrfs_test_opt(root, NODATACOW))
|
||||
if (btrfs_test_opt(root, NODATACOW) ||
|
||||
(BTRFS_I(dir)->flags & BTRFS_INODE_NODATACOW))
|
||||
BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
|
||||
}
|
||||
|
||||
insert_inode_hash(inode);
|
||||
inode_tree_add(inode);
|
||||
|
||||
trace_btrfs_inode_new(inode);
|
||||
|
||||
return inode;
|
||||
fail:
|
||||
if (dir)
|
||||
@@ -4809,7 +4834,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
|
||||
/* do not allow sys_link's with other subvols of the same device */
|
||||
if (root->objectid != BTRFS_I(inode)->root->objectid)
|
||||
return -EPERM;
|
||||
return -EXDEV;
|
||||
|
||||
if (inode->i_nlink == ~0U)
|
||||
return -EMLINK;
|
||||
|
||||
btrfs_inc_nlink(inode);
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
@@ -5265,6 +5293,9 @@ insert:
|
||||
}
|
||||
write_unlock(&em_tree->lock);
|
||||
out:
|
||||
|
||||
trace_btrfs_get_extent(root, em);
|
||||
|
||||
if (path)
|
||||
btrfs_free_path(path);
|
||||
if (trans) {
|
||||
@@ -5748,6 +5779,10 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
|
||||
|
||||
kfree(dip->csums);
|
||||
kfree(dip);
|
||||
|
||||
/* If we had a csum failure make sure to clear the uptodate flag */
|
||||
if (err)
|
||||
clear_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||
dio_end_io(bio, err);
|
||||
}
|
||||
|
||||
@@ -5849,6 +5884,10 @@ out_done:
|
||||
|
||||
kfree(dip->csums);
|
||||
kfree(dip);
|
||||
|
||||
/* If we had an error make sure to clear the uptodate flag */
|
||||
if (err)
|
||||
clear_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||
dio_end_io(bio, err);
|
||||
}
|
||||
|
||||
@@ -5922,9 +5961,12 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
||||
__btrfs_submit_bio_start_direct_io,
|
||||
__btrfs_submit_bio_done);
|
||||
goto err;
|
||||
} else if (!skip_sum)
|
||||
btrfs_lookup_bio_sums_dio(root, inode, bio,
|
||||
} else if (!skip_sum) {
|
||||
ret = btrfs_lookup_bio_sums_dio(root, inode, bio,
|
||||
file_offset, csums);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = btrfs_map_bio(root, rw, bio, 0, 1);
|
||||
err:
|
||||
@@ -5948,6 +5990,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
||||
int nr_pages = 0;
|
||||
u32 *csums = dip->csums;
|
||||
int ret = 0;
|
||||
int write = rw & REQ_WRITE;
|
||||
|
||||
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
|
||||
if (!bio)
|
||||
@@ -5984,7 +6027,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!skip_sum)
|
||||
/* Write's use the ordered csums */
|
||||
if (!write && !skip_sum)
|
||||
csums = csums + nr_pages;
|
||||
start_sector += submit_len >> 9;
|
||||
file_offset += submit_len;
|
||||
@@ -6052,7 +6096,8 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
|
||||
}
|
||||
dip->csums = NULL;
|
||||
|
||||
if (!skip_sum) {
|
||||
/* Write's use the ordered csum stuff, so we don't need dip->csums */
|
||||
if (!write && !skip_sum) {
|
||||
dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS);
|
||||
if (!dip->csums) {
|
||||
kfree(dip);
|
||||
@@ -6474,28 +6519,42 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void btrfs_truncate(struct inode *inode)
|
||||
static int btrfs_truncate(struct inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret;
|
||||
int err = 0;
|
||||
struct btrfs_trans_handle *trans;
|
||||
unsigned long nr;
|
||||
u64 mask = root->sectorsize - 1;
|
||||
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
|
||||
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
|
||||
|
||||
trans = btrfs_start_transaction(root, 5);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
|
||||
ret = btrfs_orphan_add(trans, inode);
|
||||
if (ret) {
|
||||
btrfs_end_transaction(trans, root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
|
||||
/* Now start a transaction for the truncate */
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
trans->block_rsv = root->orphan_block_rsv;
|
||||
|
||||
@@ -6522,29 +6581,38 @@ static void btrfs_truncate(struct inode *inode)
|
||||
while (1) {
|
||||
if (!trans) {
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
trans->block_rsv = root->orphan_block_rsv;
|
||||
}
|
||||
|
||||
ret = btrfs_block_rsv_check(trans, root,
|
||||
root->orphan_block_rsv, 0, 5);
|
||||
if (ret) {
|
||||
BUG_ON(ret != -EAGAIN);
|
||||
if (ret == -EAGAIN) {
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
trans = NULL;
|
||||
continue;
|
||||
} else if (ret) {
|
||||
err = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = btrfs_truncate_inode_items(trans, root, inode,
|
||||
inode->i_size,
|
||||
BTRFS_EXTENT_DATA_KEY);
|
||||
if (ret != -EAGAIN)
|
||||
if (ret != -EAGAIN) {
|
||||
err = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
BUG_ON(ret);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction(trans, root);
|
||||
@@ -6554,16 +6622,27 @@ static void btrfs_truncate(struct inode *inode)
|
||||
|
||||
if (ret == 0 && inode->i_nlink > 0) {
|
||||
ret = btrfs_orphan_del(trans, inode);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
err = ret;
|
||||
} else if (ret && inode->i_nlink > 0) {
|
||||
/*
|
||||
* Failed to do the truncate, remove us from the in memory
|
||||
* orphan list.
|
||||
*/
|
||||
ret = btrfs_orphan_del(NULL, inode);
|
||||
}
|
||||
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
BUG_ON(ret);
|
||||
if (ret && !err)
|
||||
err = ret;
|
||||
|
||||
nr = trans->blocks_used;
|
||||
ret = btrfs_end_transaction_throttle(trans, root);
|
||||
BUG_ON(ret);
|
||||
if (ret && !err)
|
||||
err = ret;
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6630,9 +6709,8 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
||||
ei->index_cnt = (u64)-1;
|
||||
ei->last_unlink_trans = 0;
|
||||
|
||||
spin_lock_init(&ei->accounting_lock);
|
||||
atomic_set(&ei->outstanding_extents, 0);
|
||||
ei->reserved_extents = 0;
|
||||
atomic_set(&ei->reserved_extents, 0);
|
||||
|
||||
ei->ordered_data_close = 0;
|
||||
ei->orphan_meta_reserved = 0;
|
||||
@@ -6668,7 +6746,7 @@ void btrfs_destroy_inode(struct inode *inode)
|
||||
WARN_ON(!list_empty(&inode->i_dentry));
|
||||
WARN_ON(inode->i_data.nrpages);
|
||||
WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents));
|
||||
WARN_ON(BTRFS_I(inode)->reserved_extents);
|
||||
WARN_ON(atomic_read(&BTRFS_I(inode)->reserved_extents));
|
||||
|
||||
/*
|
||||
* This can happen where we create an inode, but somebody else also
|
||||
@@ -6760,6 +6838,8 @@ void btrfs_destroy_cachep(void)
|
||||
kmem_cache_destroy(btrfs_transaction_cachep);
|
||||
if (btrfs_path_cachep)
|
||||
kmem_cache_destroy(btrfs_path_cachep);
|
||||
if (btrfs_free_space_cachep)
|
||||
kmem_cache_destroy(btrfs_free_space_cachep);
|
||||
}
|
||||
|
||||
int btrfs_init_cachep(void)
|
||||
@@ -6788,6 +6868,12 @@ int btrfs_init_cachep(void)
|
||||
if (!btrfs_path_cachep)
|
||||
goto fail;
|
||||
|
||||
btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space_cache",
|
||||
sizeof(struct btrfs_free_space), 0,
|
||||
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
|
||||
if (!btrfs_free_space_cachep)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
btrfs_destroy_cachep();
|
||||
@@ -6806,6 +6892,26 @@ static int btrfs_getattr(struct vfsmount *mnt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a file is moved, it will inherit the cow and compression flags of the new
|
||||
* directory.
|
||||
*/
|
||||
static void fixup_inode_flags(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
struct btrfs_inode *b_dir = BTRFS_I(dir);
|
||||
struct btrfs_inode *b_inode = BTRFS_I(inode);
|
||||
|
||||
if (b_dir->flags & BTRFS_INODE_NODATACOW)
|
||||
b_inode->flags |= BTRFS_INODE_NODATACOW;
|
||||
else
|
||||
b_inode->flags &= ~BTRFS_INODE_NODATACOW;
|
||||
|
||||
if (b_dir->flags & BTRFS_INODE_COMPRESS)
|
||||
b_inode->flags |= BTRFS_INODE_COMPRESS;
|
||||
else
|
||||
b_inode->flags &= ~BTRFS_INODE_COMPRESS;
|
||||
}
|
||||
|
||||
static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
@@ -6908,11 +7014,12 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
old_dentry->d_name.name,
|
||||
old_dentry->d_name.len);
|
||||
} else {
|
||||
btrfs_inc_nlink(old_dentry->d_inode);
|
||||
ret = btrfs_unlink_inode(trans, root, old_dir,
|
||||
old_dentry->d_inode,
|
||||
old_dentry->d_name.name,
|
||||
old_dentry->d_name.len);
|
||||
ret = __btrfs_unlink_inode(trans, root, old_dir,
|
||||
old_dentry->d_inode,
|
||||
old_dentry->d_name.name,
|
||||
old_dentry->d_name.len);
|
||||
if (!ret)
|
||||
ret = btrfs_update_inode(trans, root, old_inode);
|
||||
}
|
||||
BUG_ON(ret);
|
||||
|
||||
@@ -6939,6 +7046,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
}
|
||||
}
|
||||
|
||||
fixup_inode_flags(new_dir, old_inode);
|
||||
|
||||
ret = btrfs_add_link(trans, new_dir, old_inode,
|
||||
new_dentry->d_name.name,
|
||||
new_dentry->d_name.len, 0, index);
|
||||
@@ -7355,7 +7464,6 @@ static const struct address_space_operations btrfs_symlink_aops = {
|
||||
};
|
||||
|
||||
static const struct inode_operations btrfs_file_inode_operations = {
|
||||
.truncate = btrfs_truncate,
|
||||
.getattr = btrfs_getattr,
|
||||
.setattr = btrfs_setattr,
|
||||
.setxattr = btrfs_setxattr,
|
||||
|
Reference in New Issue
Block a user