Merge branches 'for-linus' and 'for-linus-3.2' of git://git.kernel.org/pub/scm/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Dec 2011 20:15:50 +0000 (12:15 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Dec 2011 20:15:50 +0000 (12:15 -0800)
* '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

1  2  3 
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/super.c

diff --combined fs/btrfs/delayed-inode.c
@@@@ -640,8 -640,8 -640,8 +640,8 @@@@ static int btrfs_delayed_inode_reserve_
         * 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
@@@@ -1719,7 -1719,7 -1719,7 +1719,7 @@@@ int btrfs_fill_inode(struct inode *inod
        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);
diff --combined fs/btrfs/disk-io.c
@@@@ -2007,7 -2007,7 -2007,7 +2007,7 @@@@ struct btrfs_root *open_ctree(struct su
        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,
diff --combined fs/btrfs/extent-tree.c
@@@@ -2822,7 -2822,7 -2822,7 +2822,7 @@@@ out_free
        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);
@@@@ -3416,8 -3416,7 -3416,8 +3416,8 @@@@ static int shrink_delalloc(struct btrfs
                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)
@@@@ -4204,12 -4203,17 -4204,12 +4204,17 @@@@ int btrfs_delalloc_reserve_metadata(str
        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;
diff --combined fs/btrfs/file.c
@@@@ -1167,6 -1167,6 -1167,8 +1167,8 @@@@ static noinline ssize_t __btrfs_buffere
        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;
@@@@ -1387,7 -1387,11 -1389,7 +1389,11 @@@@ static ssize_t btrfs_file_aio_write(str
                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);
@@@@ -1832,7 -1836,7 -1834,7 +1838,7 @@@@ static loff_t btrfs_file_llseek(struct 
        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:
diff --combined fs/btrfs/inode.c
   #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"
@@@@ -2031,7 -2032,7 -2031,7 +2032,7 @@@@ int btrfs_orphan_add(struct btrfs_trans
        /* 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 */
@@@@ -2158,6 -2159,38 -2158,6 +2159,38 @@@@ int btrfs_orphan_cleanup(struct btrfs_r
                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++;
                }
@@@@ -2318,7 -2358,7 -2318,7 +2358,7 @@@@ static void btrfs_read_locked_inode(str
        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));
@@@@ -3327,7 -3367,7 -3327,7 +3367,7 @@@@ int btrfs_cont_expand(struct inode *ino
                        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 {
   
                /*
@@@@ -3426,9 -3474,9 -3426,9 +3474,9 @@@@ static int btrfs_setattr(struct dentry 
   
        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);
        }
   
@@@@ -4204,42 -4252,80 -4204,42 +4252,80 @@@@ int btrfs_write_inode(struct inode *ino
    * 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;
   }
   
   /*
@@@@ -4555,11 -4641,18 -4555,11 +4641,18 @@@@ static int btrfs_mknod(struct inode *di
                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);
        }
@@@@ -4613,14 -4706,21 -4613,14 +4706,21 @@@@ static int btrfs_create(struct inode *d
                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:
@@@@ -6303,7 -6403,12 -6303,7 +6403,12 @@@@ int btrfs_page_mkwrite(struct vm_area_s
        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;
@@@@ -6515,8 -6620,9 -6515,8 +6620,9 @@@@ static int btrfs_truncate(struct inode 
                        /* 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;
                        }
                }
   
@@@@ -6593,7 -6699,7 -6593,7 +6699,7 @@@@ int btrfs_create_subvol_root(struct btr
        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);
@@@@ -7076,14 -7182,21 -7076,14 +7182,21 @@@@ static int btrfs_symlink(struct 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)
@@@@ -7353,6 -7466,7 -7353,6 +7466,7 @@@@ static const struct inode_operations bt
        .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,
diff --combined fs/btrfs/super.c
   #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"
@@@@ -825,9 -826,13 -825,9 +826,9 @@@@ static char *setup_root_args(char *args
   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;
   }
   
@@@@ -1053,7 -1080,7 -1053,7 +1054,7 @@@@ static int btrfs_calc_avail_data_space(
        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--;
@@@@ -1264,6 -1298,16 -1264,6 +1272,16 @@@@ static int btrfs_unfreeze(struct super_
        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,