* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
Btrfs: unplug every once and a while
Btrfs: deal with NULL srv_rsv in the delalloc inode reservation code
Btrfs: only set cache_generation if we setup the block group
Btrfs: don't panic if orphan item already exists
Btrfs: fix leaked space in truncate
Btrfs: fix how we do delalloc reservations and how we free reservations on error
Btrfs: deal with enospc from dirtying inodes properly
Btrfs: fix num_workers_starting bug and other bugs in async thread
BTRFS: Establish i_ops before calling d_instantiate
Btrfs: add a cond_resched() into the worker loop
Btrfs: fix ctime update of on-disk inode
btrfs: keep orphans for subvolume deletion
Btrfs: fix inaccurate available space on raid0 profile
Btrfs: fix wrong disk space information of the files
Btrfs: fix wrong i_size when truncating a file to a larger size
Btrfs: fix btrfs_end_bio to deal with write errors to a single mirror
* 'for-linus-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
btrfs: lower the dirty balance poll interval
* Now if src_rsv == delalloc_block_rsv we'll let it just steal since
* we're accounted for.
*/
- - if (!trans->bytes_reserved &&
- - src_rsv != &root->fs_info->delalloc_block_rsv) {
+ + if (!src_rsv || (!trans->bytes_reserved &&
+ + src_rsv != &root->fs_info->delalloc_block_rsv)) {
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
/*
* Since we're under a transaction reserve_metadata_bytes could
inode->i_gid = btrfs_stack_inode_gid(inode_item);
btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item));
inode->i_mode = btrfs_stack_inode_mode(inode_item);
- inode->i_nlink = btrfs_stack_inode_nlink(inode_item);
+ set_nlink(inode, btrfs_stack_inode_nlink(inode_item));
inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item));
BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item);
BTRFS_I(inode)->sequence = btrfs_stack_inode_sequence(inode_item);
sb->s_bdi = &fs_info->bdi;
fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID;
- fs_info->btree_inode->i_nlink = 1;
+ set_nlink(fs_info->btree_inode, 1);
/*
* we set the i_size on the btree inode to the max possible int.
* the real end of the address space is determined by all of
fs_info->endio_meta_write_workers.idle_thresh = 2;
fs_info->readahead_workers.idle_thresh = 2;
- - btrfs_start_workers(&fs_info->workers, 1);
- - btrfs_start_workers(&fs_info->generic_worker, 1);
- - btrfs_start_workers(&fs_info->submit_workers, 1);
- - btrfs_start_workers(&fs_info->delalloc_workers, 1);
- - btrfs_start_workers(&fs_info->fixup_workers, 1);
- - btrfs_start_workers(&fs_info->endio_workers, 1);
- - btrfs_start_workers(&fs_info->endio_meta_workers, 1);
- - btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
- - btrfs_start_workers(&fs_info->endio_write_workers, 1);
- - btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
- - btrfs_start_workers(&fs_info->delayed_workers, 1);
- - btrfs_start_workers(&fs_info->caching_workers, 1);
- - btrfs_start_workers(&fs_info->readahead_workers, 1);
+ + /*
+ + * btrfs_start_workers can really only fail because of ENOMEM so just
+ + * return -ENOMEM if any of these fail.
+ + */
+ + ret = btrfs_start_workers(&fs_info->workers);
+ + ret |= btrfs_start_workers(&fs_info->generic_worker);
+ + ret |= btrfs_start_workers(&fs_info->submit_workers);
+ + ret |= btrfs_start_workers(&fs_info->delalloc_workers);
+ + ret |= btrfs_start_workers(&fs_info->fixup_workers);
+ + ret |= btrfs_start_workers(&fs_info->endio_workers);
+ + ret |= btrfs_start_workers(&fs_info->endio_meta_workers);
+ + ret |= btrfs_start_workers(&fs_info->endio_meta_write_workers);
+ + ret |= btrfs_start_workers(&fs_info->endio_write_workers);
+ + ret |= btrfs_start_workers(&fs_info->endio_freespace_worker);
+ + ret |= btrfs_start_workers(&fs_info->delayed_workers);
+ + ret |= btrfs_start_workers(&fs_info->caching_workers);
+ + ret |= btrfs_start_workers(&fs_info->readahead_workers);
+ + if (ret) {
+ + ret = -ENOMEM;
+ + goto fail_sb_buffer;
+ + }
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
btrfs_release_path(path);
out:
spin_lock(&block_group->lock);
- - if (!ret)
+ + if (!ret && dcs == BTRFS_DC_SETUP)
block_group->cache_generation = trans->transid;
block_group->disk_cache_state = dcs;
spin_unlock(&block_group->lock);
smp_mb();
nr_pages = min_t(unsigned long, nr_pages,
root->fs_info->delalloc_bytes >> PAGE_CACHE_SHIFT);
- writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages);
+ writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages,
+ WB_REASON_FS_FREE_SPACE);
spin_lock(&space_info->lock);
if (reserved > space_info->bytes_may_use)
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
u64 to_reserve = 0;
+ + u64 csum_bytes;
unsigned nr_extents = 0;
+ + int extra_reserve = 0;
int flush = 1;
int ret;
+ + /* Need to be holding the i_mutex here if we aren't free space cache */
if (btrfs_is_free_space_inode(root, inode))
flush = 0;
+ + else
+ + WARN_ON(!mutex_is_locked(&inode->i_mutex));
if (flush && btrfs_transaction_in_commit(root->fs_info))
schedule_timeout(1);
BTRFS_I(inode)->outstanding_extents++;
if (BTRFS_I(inode)->outstanding_extents >
- - BTRFS_I(inode)->reserved_extents) {
+ + BTRFS_I(inode)->reserved_extents)
nr_extents = BTRFS_I(inode)->outstanding_extents -
BTRFS_I(inode)->reserved_extents;
- - BTRFS_I(inode)->reserved_extents += nr_extents;
- - }
/*
* Add an item to reserve for updating the inode when we complete the
*/
if (!BTRFS_I(inode)->delalloc_meta_reserved) {
nr_extents++;
- - BTRFS_I(inode)->delalloc_meta_reserved = 1;
+ + extra_reserve = 1;
}
to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
+ + csum_bytes = BTRFS_I(inode)->csum_bytes;
spin_unlock(&BTRFS_I(inode)->lock);
ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
spin_lock(&BTRFS_I(inode)->lock);
dropped = drop_outstanding_extent(inode);
- - to_free = calc_csum_metadata_size(inode, num_bytes, 0);
- - spin_unlock(&BTRFS_I(inode)->lock);
- - to_free += btrfs_calc_trans_metadata_size(root, dropped);
- -
/*
- - * Somebody could have come in and twiddled with the
- - * reservation, so if we have to free more than we would have
- - * reserved from this reservation go ahead and release those
- - * bytes.
+ + * If the inodes csum_bytes is the same as the original
+ + * csum_bytes then we know we haven't raced with any free()ers
+ + * so we can just reduce our inodes csum bytes and carry on.
+ + * Otherwise we have to do the normal free thing to account for
+ + * the case that the free side didn't free up its reserve
+ + * because of this outstanding reservation.
*/
- - to_free -= to_reserve;
+ + if (BTRFS_I(inode)->csum_bytes == csum_bytes)
+ + calc_csum_metadata_size(inode, num_bytes, 0);
+ + else
+ + to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+ + spin_unlock(&BTRFS_I(inode)->lock);
+ + if (dropped)
+ + to_free += btrfs_calc_trans_metadata_size(root, dropped);
+ +
if (to_free)
btrfs_block_rsv_release(root, block_rsv, to_free);
return ret;
}
+ + spin_lock(&BTRFS_I(inode)->lock);
+ + if (extra_reserve) {
+ + BTRFS_I(inode)->delalloc_meta_reserved = 1;
+ + nr_extents--;
+ + }
+ + BTRFS_I(inode)->reserved_extents += nr_extents;
+ + spin_unlock(&BTRFS_I(inode)->lock);
+ +
block_rsv_add_bytes(block_rsv, to_reserve, 1);
return 0;
nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) /
PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
(sizeof(struct page *)));
++ nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied);
++ nrptrs = max(nrptrs, 8);
pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
goto out;
}
- - file_update_time(file);
+ + err = btrfs_update_time(file);
+ + if (err) {
+ + mutex_unlock(&inode->i_mutex);
+ + goto out;
+ + }
BTRFS_I(inode)->sequence++;
start_pos = round_down(pos, root->sectorsize);
switch (origin) {
case SEEK_END:
case SEEK_CUR:
- offset = generic_file_llseek_unlocked(file, offset, origin);
+ offset = generic_file_llseek(file, offset, origin);
goto out;
case SEEK_DATA:
case SEEK_HOLE:
#include <linux/falloc.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
+ +#include <linux/mount.h>
#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
/* insert an orphan item to track this unlinked/truncated file */
if (insert >= 1) {
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
- - BUG_ON(ret);
+ + BUG_ON(ret && ret != -EEXIST);
}
/* insert an orphan item to track subvolume contains orphan files */
if (ret && ret != -ESTALE)
goto out;
+ + if (ret == -ESTALE && root == root->fs_info->tree_root) {
+ + struct btrfs_root *dead_root;
+ + struct btrfs_fs_info *fs_info = root->fs_info;
+ + int is_dead_root = 0;
+ +
+ + /*
+ + * this is an orphan in the tree root. Currently these
+ + * could come from 2 sources:
+ + * a) a snapshot deletion in progress
+ + * b) a free space cache inode
+ + * We need to distinguish those two, as the snapshot
+ + * orphan must not get deleted.
+ + * find_dead_roots already ran before us, so if this
+ + * is a snapshot deletion, we should find the root
+ + * in the dead_roots list
+ + */
+ + spin_lock(&fs_info->trans_lock);
+ + list_for_each_entry(dead_root, &fs_info->dead_roots,
+ + root_list) {
+ + if (dead_root->root_key.objectid ==
+ + found_key.objectid) {
+ + is_dead_root = 1;
+ + break;
+ + }
+ + }
+ + spin_unlock(&fs_info->trans_lock);
+ + if (is_dead_root) {
+ + /* prevent this orphan from being found again */
+ + key.offset = found_key.objectid - 1;
+ + continue;
+ + }
+ + }
/*
* Inode is already gone but the orphan item is still there,
* kill the orphan item.
continue;
}
nr_truncate++;
+ + /*
+ + * Need to hold the imutex for reservation purposes, not
+ + * a huge deal here but I have a WARN_ON in
+ + * btrfs_delalloc_reserve_space to catch offenders.
+ + */
+ + mutex_lock(&inode->i_mutex);
ret = btrfs_truncate(inode);
+ + mutex_unlock(&inode->i_mutex);
} else {
nr_unlink++;
}
inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item);
inode->i_mode = btrfs_inode_mode(leaf, inode_item);
- inode->i_nlink = btrfs_inode_nlink(leaf, inode_item);
+ set_nlink(inode, btrfs_inode_nlink(leaf, inode_item));
inode->i_uid = btrfs_inode_uid(leaf, inode_item);
inode->i_gid = btrfs_inode_gid(leaf, inode_item);
btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item));
u64 hint_byte = 0;
hole_size = last_byte - cur_offset;
- - trans = btrfs_start_transaction(root, 2);
+ + trans = btrfs_start_transaction(root, 3);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
break;
cur_offset + hole_size,
&hint_byte, 1);
if (err) {
+ + btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
break;
}
0, hole_size, 0, hole_size,
0, 0, 0);
if (err) {
+ + btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
break;
}
btrfs_drop_extent_cache(inode, hole_start,
last_byte - 1, 0);
+ + btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
}
free_extent_map(em);
static int btrfs_setsize(struct inode *inode, loff_t newsize)
{
+ + struct btrfs_root *root = BTRFS_I(inode)->root;
+ + struct btrfs_trans_handle *trans;
loff_t oldsize = i_size_read(inode);
int ret;
return 0;
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_setsize(inode, oldsize);
+ + if (ret)
return ret;
- - }
- - mark_inode_dirty(inode);
+ + trans = btrfs_start_transaction(root, 1);
+ + if (IS_ERR(trans))
+ + return PTR_ERR(trans);
+ +
+ + i_size_write(inode, newsize);
+ + btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
+ + ret = btrfs_update_inode(trans, root, inode);
+ + btrfs_end_transaction_throttle(trans, root);
} else {
/*
if (attr->ia_valid) {
setattr_copy(inode, attr);
- - mark_inode_dirty(inode);
+ + err = btrfs_dirty_inode(inode);
- - if (attr->ia_valid & ATTR_MODE)
+ + if (!err && attr->ia_valid & ATTR_MODE)
err = btrfs_acl_chmod(inode);
}
* FIXME, needs more benchmarking...there are no reasons other than performance
* to keep or drop this code.
*/
- -void btrfs_dirty_inode(struct inode *inode, int flags)
+ +int btrfs_dirty_inode(struct inode *inode)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
int ret;
if (BTRFS_I(inode)->dummy_inode)
- - return;
+ + return 0;
trans = btrfs_join_transaction(root);
- - BUG_ON(IS_ERR(trans));
+ + if (IS_ERR(trans))
+ + return PTR_ERR(trans);
ret = btrfs_update_inode(trans, root, inode);
if (ret && ret == -ENOSPC) {
/* whoops, lets try again with the full transaction */
btrfs_end_transaction(trans, root);
trans = btrfs_start_transaction(root, 1);
- - if (IS_ERR(trans)) {
- - printk_ratelimited(KERN_ERR "btrfs: fail to "
- - "dirty inode %llu error %ld\n",
- - (unsigned long long)btrfs_ino(inode),
- - PTR_ERR(trans));
- - return;
- - }
+ + if (IS_ERR(trans))
+ + return PTR_ERR(trans);
ret = btrfs_update_inode(trans, root, inode);
- - if (ret) {
- - printk_ratelimited(KERN_ERR "btrfs: fail to "
- - "dirty inode %llu error %d\n",
- - (unsigned long long)btrfs_ino(inode),
- - ret);
- - }
}
btrfs_end_transaction(trans, root);
if (BTRFS_I(inode)->delayed_node)
btrfs_balance_delayed_items(root);
+ +
+ + return ret;
+ +}
+ +
+ +/*
+ + * This is a copy of file_update_time. We need this so we can return error on
+ + * ENOSPC for updating the inode in the case of file write and mmap writes.
+ + */
+ +int btrfs_update_time(struct file *file)
+ +{
+ + struct inode *inode = file->f_path.dentry->d_inode;
+ + struct timespec now;
+ + int ret;
+ + enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0;
+ +
+ + /* First try to exhaust all avenues to not sync */
+ + if (IS_NOCMTIME(inode))
+ + return 0;
+ +
+ + now = current_fs_time(inode->i_sb);
+ + if (!timespec_equal(&inode->i_mtime, &now))
+ + sync_it = S_MTIME;
+ +
+ + if (!timespec_equal(&inode->i_ctime, &now))
+ + sync_it |= S_CTIME;
+ +
+ + if (IS_I_VERSION(inode))
+ + sync_it |= S_VERSION;
+ +
+ + if (!sync_it)
+ + return 0;
+ +
+ + /* Finally allowed to write? Takes lock. */
+ + if (mnt_want_write_file(file))
+ + return 0;
+ +
+ + /* Only change inode inside the lock region */
+ + if (sync_it & S_VERSION)
+ + inode_inc_iversion(inode);
+ + if (sync_it & S_CTIME)
+ + inode->i_ctime = now;
+ + if (sync_it & S_MTIME)
+ + inode->i_mtime = now;
+ + ret = btrfs_dirty_inode(inode);
+ + if (!ret)
+ + mark_inode_dirty_sync(inode);
+ + mnt_drop_write(file->f_path.mnt);
+ + return ret;
}
/*
goto out_unlock;
}
+ + /*
+ + * If the active LSM wants to access the inode during
+ + * d_instantiate it needs these. Smack checks to see
+ + * if the filesystem supports xattrs by looking at the
+ + * ops vector.
+ + */
+ +
+ + inode->i_op = &btrfs_special_inode_operations;
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
- - inode->i_op = &btrfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, rdev);
btrfs_update_inode(trans, root, inode);
}
goto out_unlock;
}
+ + /*
+ + * If the active LSM wants to access the inode during
+ + * d_instantiate it needs these. Smack checks to see
+ + * if the filesystem supports xattrs by looking at the
+ + * ops vector.
+ + */
+ + inode->i_fop = &btrfs_file_operations;
+ + inode->i_op = &btrfs_file_inode_operations;
+ +
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
- - inode->i_fop = &btrfs_file_operations;
- - inode->i_op = &btrfs_file_inode_operations;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
}
out_unlock:
u64 page_start;
u64 page_end;
+ + /* Need this to keep space reservations serialized */
+ + mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+ + mutex_unlock(&inode->i_mutex);
+ + if (!ret)
+ + ret = btrfs_update_time(vma->vm_file);
if (ret) {
if (ret == -ENOMEM)
ret = VM_FAULT_OOM;
/* Just need the 1 for updating the inode */
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
- - err = PTR_ERR(trans);
- - goto out;
+ + ret = err = PTR_ERR(trans);
+ + trans = NULL;
+ + break;
}
}
inode->i_op = &btrfs_dir_inode_operations;
inode->i_fop = &btrfs_dir_file_operations;
- inode->i_nlink = 1;
+ set_nlink(inode, 1);
btrfs_i_size_write(inode, 0);
err = btrfs_update_inode(trans, new_root, inode);
goto out_unlock;
}
+ + /*
+ + * If the active LSM wants to access the inode during
+ + * d_instantiate it needs these. Smack checks to see
+ + * if the filesystem supports xattrs by looking at the
+ + * ops vector.
+ + */
+ + inode->i_fop = &btrfs_file_operations;
+ + inode->i_op = &btrfs_file_inode_operations;
+ +
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
- - inode->i_fop = &btrfs_file_operations;
- - inode->i_op = &btrfs_file_inode_operations;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
}
if (drop_inode)
.follow_link = page_follow_link_light,
.put_link = page_put_link,
.getattr = btrfs_getattr,
+ + .setattr = btrfs_setattr,
.permission = btrfs_permission,
.setxattr = btrfs_setxattr,
.getxattr = btrfs_getxattr,
#include <linux/slab.h>
#include <linux/cleancache.h>
#include <linux/mnt_namespace.h>
+ +#include <linux/ratelimit.h>
#include "compat.h"
#include "delayed-inode.h"
#include "ctree.h"
static struct dentry *mount_subvol(const char *subvol_name, int flags,
const char *device_name, char *data)
{
- struct super_block *s;
struct dentry *root;
struct vfsmount *mnt;
- struct mnt_namespace *ns_private;
char *newargs;
- struct path path;
- int error;
newargs = setup_root_args(data);
if (!newargs)
if (IS_ERR(mnt))
return ERR_CAST(mnt);
- ns_private = create_mnt_ns(mnt);
- if (IS_ERR(ns_private)) {
- mntput(mnt);
- return ERR_CAST(ns_private);
- }
+ root = mount_subtree(mnt, subvol_name);
- /*
- * This will trigger the automount of the subvol so we can just
- * drop the mnt we have here and return the dentry that we
- * found.
- */
- error = vfs_path_lookup(mnt->mnt_root, mnt, subvol_name,
- LOOKUP_FOLLOW, &path);
- put_mnt_ns(ns_private);
- if (error)
- return ERR_PTR(error);
-
- if (!is_subvolume_inode(path.dentry->d_inode)) {
- path_put(&path);
- mntput(mnt);
- error = -EINVAL;
+ if (!IS_ERR(root) && !is_subvolume_inode(root->d_inode)) {
+ struct super_block *s = root->d_sb;
+ dput(root);
+ root = ERR_PTR(-EINVAL);
+ deactivate_locked_super(s);
printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n",
subvol_name);
- return ERR_PTR(-EINVAL);
}
- /* Get a ref to the sb and the dentry we found and return it */
- s = path.mnt->mnt_sb;
- atomic_inc(&s->s_active);
- root = dget(path.dentry);
- path_put(&path);
- down_write(&s->s_umount);
-
return root;
}
u64 avail_space;
u64 used_space;
u64 min_stripe_size;
- - int min_stripes = 1;
+ + int min_stripes = 1, num_stripes = 1;
int i = 0, nr_devices;
int ret;
/* calc min stripe number for data space alloction */
type = btrfs_get_alloc_profile(root, 1);
- - if (type & BTRFS_BLOCK_GROUP_RAID0)
+ + if (type & BTRFS_BLOCK_GROUP_RAID0) {
min_stripes = 2;
- - else if (type & BTRFS_BLOCK_GROUP_RAID1)
+ + num_stripes = nr_devices;
+ + } else if (type & BTRFS_BLOCK_GROUP_RAID1) {
min_stripes = 2;
- - else if (type & BTRFS_BLOCK_GROUP_RAID10)
+ + num_stripes = 2;
+ + } else if (type & BTRFS_BLOCK_GROUP_RAID10) {
min_stripes = 4;
+ + num_stripes = 4;
+ + }
if (type & BTRFS_BLOCK_GROUP_DUP)
min_stripe_size = 2 * BTRFS_STRIPE_LEN;
i = nr_devices - 1;
avail_space = 0;
while (nr_devices >= min_stripes) {
+ + if (num_stripes > nr_devices)
+ + num_stripes = nr_devices;
+ +
if (devices_info[i].max_avail >= min_stripe_size) {
int j;
u64 alloc_size;
- - avail_space += devices_info[i].max_avail * min_stripes;
+ + avail_space += devices_info[i].max_avail * num_stripes;
alloc_size = devices_info[i].max_avail;
- - for (j = i + 1 - min_stripes; j <= i; j++)
+ + for (j = i + 1 - num_stripes; j <= i; j++)
devices_info[j].max_avail -= alloc_size;
}
i--;
return 0;
}
+ +static void btrfs_fs_dirty_inode(struct inode *inode, int flags)
+ +{
+ + int ret;
+ +
+ + ret = btrfs_dirty_inode(inode);
+ + if (ret)
+ + printk_ratelimited(KERN_ERR "btrfs: fail to dirty inode %Lu "
+ + "error %d\n", btrfs_ino(inode), ret);
+ +}
+ +
static const struct super_operations btrfs_super_ops = {
.drop_inode = btrfs_drop_inode,
.evict_inode = btrfs_evict_inode,
.sync_fs = btrfs_sync_fs,
.show_options = btrfs_show_options,
.write_inode = btrfs_write_inode,
- - .dirty_inode = btrfs_dirty_inode,
+ + .dirty_inode = btrfs_fs_dirty_inode,
.alloc_inode = btrfs_alloc_inode,
.destroy_inode = btrfs_destroy_inode,
.statfs = btrfs_statfs,