]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Feb 2013 01:06:46 +0000 (12:06 +1100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Feb 2013 01:06:46 +0000 (12:06 +1100)
Pull btrfs fixes from Chris Mason:
 "We've got corner cases for updating i_size that ceph was hitting,
  error handling for quotas when we run out of space, a very subtle
  snapshot deletion race, a crash while removing devices, and one
  deadlock between subvolume creation and the sb_internal code (thanks
  lockdep)."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: move d_instantiate outside the transaction during mksubvol
  Btrfs: fix EDQUOT handling in btrfs_delalloc_reserve_metadata
  Btrfs: fix possible stale data exposure
  Btrfs: fix missing i_size update
  Btrfs: fix race between snapshot deletion and getting inode
  Btrfs: fix missing release of the space/qgroup reservation in start_transaction()
  Btrfs: fix wrong sync_writers decrement in btrfs_file_aio_write()
  Btrfs: do not merge logged extents if we've removed them from the tree
  btrfs: don't try to notify udev about missing devices

1  2 
fs/btrfs/extent-tree.c
fs/btrfs/extent_map.c
fs/btrfs/file.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/extent-tree.c
index a8b8adc0507059137898cae2e058570e11843291,61da9d0bb805aee0272b2a642808f4e757020e35..5a3327b8f90d557db144b360b3df4ec9bce9ff50
@@@ -3898,7 -3898,7 +3898,7 @@@ static int flush_space(struct btrfs_roo
   * @root - the root we're allocating for
   * @block_rsv - the block_rsv we're allocating for
   * @orig_bytes - the number of bytes we want
 - * @flush - wether or not we can flush to make our reservation
 + * @flush - whether or not we can flush to make our reservation
   *
   * This will reserve orgi_bytes number of bytes from the space info associated
   * with the block_rsv.  If there is not enough space it will make an attempt to
@@@ -4534,7 -4534,7 +4534,7 @@@ int btrfs_delalloc_reserve_metadata(str
        unsigned nr_extents = 0;
        int extra_reserve = 0;
        enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
-       int ret;
+       int ret = 0;
        bool delalloc_lock = true;
  
        /* If we are a free space inode we need to not flush since we will be in
        csum_bytes = BTRFS_I(inode)->csum_bytes;
        spin_unlock(&BTRFS_I(inode)->lock);
  
-       if (root->fs_info->quota_enabled) {
+       if (root->fs_info->quota_enabled)
                ret = btrfs_qgroup_reserve(root, num_bytes +
                                           nr_extents * root->leafsize);
-               if (ret) {
-                       spin_lock(&BTRFS_I(inode)->lock);
-                       calc_csum_metadata_size(inode, num_bytes, 0);
-                       spin_unlock(&BTRFS_I(inode)->lock);
-                       if (delalloc_lock)
-                               mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
-                       return ret;
-               }
-       }
  
-       ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
+       /*
+        * ret != 0 here means the qgroup reservation failed, we go straight to
+        * the shared error handling then.
+        */
+       if (ret == 0)
+               ret = reserve_metadata_bytes(root, block_rsv,
+                                            to_reserve, flush);
        if (ret) {
                u64 to_free = 0;
                unsigned dropped;
diff --combined fs/btrfs/extent_map.c
index 2e8cae63d247929613ddc77e6d01761e35b04753,9759911dd34e12365c0bc57e2a943d55c00a126c..fdb7a8db3b5748911e5820f9b588c5a264a6a8bc
@@@ -234,11 -234,12 +234,11 @@@ static void try_merge_map(struct extent
  }
  
  /**
 - * unpint_extent_cache - unpin an extent from the cache
 + * unpin_extent_cache - unpin an extent from the cache
   * @tree:     tree to unpin the extent in
   * @start:    logical offset in the file
   * @len:      length of the extent
   * @gen:      generation that this extent has been modified in
 - * @prealloc: if this is set we need to clear the prealloc flag
   *
   * Called after an extent has been written to disk properly.  Set the generation
   * to the generation that actually added the file item to the inode so we know
@@@ -288,7 -289,8 +288,8 @@@ out
  void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em)
  {
        clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
-       try_merge_map(tree, em);
+       if (em->in_tree)
+               try_merge_map(tree, em);
  }
  
  /**
diff --combined fs/btrfs/file.c
index f76b1fd160d446fb4c92fd56b8cc0ea14acc6f9a,b06d289f998f310390527324368513fceadafb19..aeb84469d2c4c0621b002084617578f7ac5f49b1
@@@ -293,15 -293,24 +293,24 @@@ static int __btrfs_run_defrag_inode(str
        struct btrfs_key key;
        struct btrfs_ioctl_defrag_range_args range;
        int num_defrag;
+       int index;
+       int ret;
  
        /* get the inode */
        key.objectid = defrag->root;
        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
        key.offset = (u64)-1;
+       index = srcu_read_lock(&fs_info->subvol_srcu);
        inode_root = btrfs_read_fs_root_no_name(fs_info, &key);
        if (IS_ERR(inode_root)) {
-               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
-               return PTR_ERR(inode_root);
+               ret = PTR_ERR(inode_root);
+               goto cleanup;
+       }
+       if (btrfs_root_refs(&inode_root->root_item) == 0) {
+               ret = -ENOENT;
+               goto cleanup;
        }
  
        key.objectid = defrag->ino;
        key.offset = 0;
        inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
        if (IS_ERR(inode)) {
-               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
-               return PTR_ERR(inode);
+               ret = PTR_ERR(inode);
+               goto cleanup;
        }
+       srcu_read_unlock(&fs_info->subvol_srcu, index);
  
        /* do a chunk of defrag */
        clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
  
        iput(inode);
        return 0;
+ cleanup:
+       srcu_read_unlock(&fs_info->subvol_srcu, index);
+       kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+       return ret;
  }
  
  /*
@@@ -1412,7 -1426,8 +1426,7 @@@ static noinline ssize_t __btrfs_buffere
  
                cond_resched();
  
 -              balance_dirty_pages_ratelimited_nr(inode->i_mapping,
 -                                                 dirty_pages);
 +              balance_dirty_pages_ratelimited(inode->i_mapping);
                if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
                        btrfs_btree_balance_dirty(root);
  
@@@ -1594,9 -1609,10 +1608,10 @@@ static ssize_t btrfs_file_aio_write(str
                if (err < 0 && num_written > 0)
                        num_written = err;
        }
- out:
        if (sync)
                atomic_dec(&BTRFS_I(inode)->sync_writers);
+ out:
        sb_end_write(inode->i_sb);
        current->backing_dev_info = NULL;
        return num_written ? num_written : err;
@@@ -2224,7 -2240,7 +2239,7 @@@ out
        return ret;
  }
  
 -static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
 +static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_map *em;
         * before the position we want in case there is outstanding delalloc
         * going on here.
         */
 -      if (origin == SEEK_HOLE && start != 0) {
 +      if (whence == SEEK_HOLE && start != 0) {
                if (start <= root->sectorsize)
                        em = btrfs_get_extent_fiemap(inode, NULL, 0, 0,
                                                     root->sectorsize, 0);
                                }
                        }
  
 -                      if (origin == SEEK_HOLE) {
 +                      if (whence == SEEK_HOLE) {
                                *offset = start;
                                free_extent_map(em);
                                break;
                        }
                } else {
 -                      if (origin == SEEK_DATA) {
 +                      if (whence == SEEK_DATA) {
                                if (em->block_start == EXTENT_MAP_DELALLOC) {
                                        if (start >= inode->i_size) {
                                                free_extent_map(em);
        return ret;
  }
  
 -static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
 +static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
  {
        struct inode *inode = file->f_mapping->host;
        int ret;
  
        mutex_lock(&inode->i_mutex);
 -      switch (origin) {
 +      switch (whence) {
        case SEEK_END:
        case SEEK_CUR:
 -              offset = generic_file_llseek(file, offset, origin);
 +              offset = generic_file_llseek(file, offset, whence);
                goto out;
        case SEEK_DATA:
        case SEEK_HOLE:
                        return -ENXIO;
                }
  
 -              ret = find_desired_extent(inode, &offset, origin);
 +              ret = find_desired_extent(inode, &offset, whence);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
                        return ret;
diff --combined fs/btrfs/ioctl.c
index 5b22d45d3c6a232aeed49b24cf34bb374a96ecc9,a31cd931d36efa5bf6be0325d2a64ed39a84684d..338f2597bf7f8da2215e0d87289b01c94f9cfe7c
@@@ -515,7 -515,6 +515,6 @@@ static noinline int create_subvol(struc
  
        BUG_ON(ret);
  
-       d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
  fail:
        if (async_transid) {
                *async_transid = trans->transid;
        }
        if (err && !ret)
                ret = err;
+       if (!ret)
+               d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
        return ret;
  }
  
@@@ -1243,7 -1246,7 +1246,7 @@@ int btrfs_defrag_file(struct inode *ino
                }
  
                defrag_count += ret;
 -              balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret);
 +              balance_dirty_pages_ratelimited(inode->i_mapping);
                mutex_unlock(&inode->i_mutex);
  
                if (newer_than) {