]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Mar 2013 18:13:25 +0000 (11:13 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Mar 2013 18:13:25 +0000 (11:13 -0700)
Pull btrfs fixes from Chris Mason:
 "We've had a busy two weeks of bug fixing.  The biggest patches in here
  are some long standing early-enospc problems (Josef) and a very old
  race where compression and mmap combine forces to lose writes (me).
  I'm fairly sure the mmap bug goes all the way back to the introduction
  of the compression code, which is proof that fsx doesn't trigger every
  possible mmap corner after all.

  I'm sure you'll notice one of these is from this morning, it's a small
  and isolated use-after-free fix in our scrub error reporting.  I
  double checked it here."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: don't drop path when printing out tree errors in scrub
  Btrfs: fix wrong return value of btrfs_lookup_csum()
  Btrfs: fix wrong reservation of csums
  Btrfs: fix double free in the btrfs_qgroup_account_ref()
  Btrfs: limit the global reserve to 512mb
  Btrfs: hold the ordered operations mutex when waiting on ordered extents
  Btrfs: fix space accounting for unlink and rename
  Btrfs: fix space leak when we fail to reserve metadata space
  Btrfs: fix EIO from btrfs send in is_extent_unchanged for punched holes
  Btrfs: fix race between mmap writes and compression
  Btrfs: fix memory leak in btrfs_create_tree()
  Btrfs: fix locking on ROOT_REPLACE operations in tree mod log
  Btrfs: fix missing qgroup reservation before fallocating
  Btrfs: handle a bogus chunk tree nicely
  Btrfs: update to use fs_state bit

1  2 
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/send.c

diff --combined fs/btrfs/extent-tree.c
index 9ac2eca681ebb09c605612dd563bc4417e4fc587,0d8478700d7867bf72c4a903249fc04fd2fbb5a7..3d551231cabae9e43c7a1e90385f22fd25891239
@@@ -257,7 -257,8 +257,8 @@@ static int exclude_super_stripes(struc
                cache->bytes_super += stripe_len;
                ret = add_excluded_extent(root, cache->key.objectid,
                                          stripe_len);
-               BUG_ON(ret); /* -ENOMEM */
+               if (ret)
+                       return ret;
        }
  
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
                                       cache->key.objectid, bytenr,
                                       0, &logical, &nr, &stripe_len);
-               BUG_ON(ret); /* -ENOMEM */
+               if (ret)
+                       return ret;
  
                while (nr--) {
                        cache->bytes_super += stripe_len;
                        ret = add_excluded_extent(root, logical[nr],
                                                  stripe_len);
-                       BUG_ON(ret); /* -ENOMEM */
+                       if (ret) {
+                               kfree(logical);
+                               return ret;
+                       }
                }
  
                kfree(logical);
@@@ -3803,6 -3808,23 +3808,6 @@@ static int can_overcommit(struct btrfs_
        return 0;
  }
  
 -static inline int writeback_inodes_sb_nr_if_idle_safe(struct super_block *sb,
 -                                                    unsigned long nr_pages,
 -                                                    enum wb_reason reason)
 -{
 -      /* the flusher is dealing with the dirty inodes now. */
 -      if (writeback_in_progress(sb->s_bdi))
 -              return 1;
 -
 -      if (down_read_trylock(&sb->s_umount)) {
 -              writeback_inodes_sb_nr(sb, nr_pages, reason);
 -              up_read(&sb->s_umount);
 -              return 1;
 -      }
 -
 -      return 0;
 -}
 -
  void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
                                  unsigned long nr_pages)
  {
        int started;
  
        /* If we can not start writeback, just sync all the delalloc file. */
 -      started = writeback_inodes_sb_nr_if_idle_safe(sb, nr_pages,
 +      started = try_to_writeback_inodes_sb_nr(sb, nr_pages,
                                                      WB_REASON_FS_FREE_SPACE);
        if (!started) {
                /*
@@@ -4438,7 -4460,7 +4443,7 @@@ static void update_global_block_rsv(str
        spin_lock(&sinfo->lock);
        spin_lock(&block_rsv->lock);
  
-       block_rsv->size = num_bytes;
+       block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024);
  
        num_bytes = sinfo->bytes_used + sinfo->bytes_pinned +
                    sinfo->bytes_reserved + sinfo->bytes_readonly +
@@@ -4793,14 -4815,49 +4798,49 @@@ out_fail
         * 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.
         */
-       if (BTRFS_I(inode)->csum_bytes == csum_bytes)
+       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);
+       } else {
+               u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes;
+               u64 bytes;
+               /*
+                * This is tricky, but first we need to figure out how much we
+                * free'd from any free-ers that occured during this
+                * reservation, so we reset ->csum_bytes to the csum_bytes
+                * before we dropped our lock, and then call the free for the
+                * number of bytes that were freed while we were trying our
+                * reservation.
+                */
+               bytes = csum_bytes - BTRFS_I(inode)->csum_bytes;
+               BTRFS_I(inode)->csum_bytes = csum_bytes;
+               to_free = calc_csum_metadata_size(inode, bytes, 0);
+               /*
+                * Now we need to see how much we would have freed had we not
+                * been making this reservation and our ->csum_bytes were not
+                * artificially inflated.
+                */
+               BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes;
+               bytes = csum_bytes - orig_csum_bytes;
+               bytes = calc_csum_metadata_size(inode, bytes, 0);
+               /*
+                * Now reset ->csum_bytes to what it should be.  If bytes is
+                * more than to_free then we would have free'd more space had we
+                * not had an artificially high ->csum_bytes, so we need to free
+                * the remainder.  If bytes is the same or less then we don't
+                * need to do anything, the other free-ers did the correct
+                * thing.
+                */
+               BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes;
+               if (bytes > to_free)
+                       to_free = bytes - to_free;
+               else
+                       to_free = 0;
+       }
        spin_unlock(&BTRFS_I(inode)->lock);
        if (dropped)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
@@@ -6702,7 -6759,7 +6742,7 @@@ reada
  }
  
  /*
 - * hepler to process tree block while walking down the tree.
 + * helper to process tree block while walking down the tree.
   *
   * when wc->stage == UPDATE_BACKREF, this function updates
   * back refs for pointers in the block.
@@@ -6777,7 -6834,7 +6817,7 @@@ static noinline int walk_down_proc(stru
  }
  
  /*
 - * hepler to process tree block pointer.
 + * helper to process tree block pointer.
   *
   * when wc->stage == DROP_REFERENCE, this function checks
   * reference count of the block pointed to. if the block
@@@ -6915,7 -6972,7 +6955,7 @@@ skip
  }
  
  /*
 - * hepler to process tree block while walking up the tree.
 + * helper to process tree block while walking up the tree.
   *
   * when wc->stage == DROP_REFERENCE, this function drops
   * reference count on the block.
@@@ -7947,7 -8004,17 +7987,17 @@@ int btrfs_read_block_groups(struct btrf
                 * info has super bytes accounted for, otherwise we'll think
                 * we have more space than we actually do.
                 */
-               exclude_super_stripes(root, cache);
+               ret = exclude_super_stripes(root, cache);
+               if (ret) {
+                       /*
+                        * We may have excluded something, so call this just in
+                        * case.
+                        */
+                       free_excluded_extents(root, cache);
+                       kfree(cache->free_space_ctl);
+                       kfree(cache);
+                       goto error;
+               }
  
                /*
                 * check for two cases, either we are full, and therefore
@@@ -8089,7 -8156,17 +8139,17 @@@ int btrfs_make_block_group(struct btrfs
  
        cache->last_byte_to_unpin = (u64)-1;
        cache->cached = BTRFS_CACHE_FINISHED;
-       exclude_super_stripes(root, cache);
+       ret = exclude_super_stripes(root, cache);
+       if (ret) {
+               /*
+                * We may have excluded something, so call this just in
+                * case.
+                */
+               free_excluded_extents(root, cache);
+               kfree(cache->free_space_ctl);
+               kfree(cache);
+               return ret;
+       }
  
        add_new_free_space(cache, root->fs_info, chunk_offset,
                           chunk_offset + size);
diff --combined fs/btrfs/file.c
index 5b4ea5f55b8f47d0bf9a90992dd9da2d33880e14,1be25b92d63c8f283d109fa5ead9e8b80de76d2a..ade03e6f7bd2706bbaac3406f1bcc31cf70cb578
@@@ -1230,7 -1230,7 +1230,7 @@@ static noinline int prepare_pages(struc
        struct extent_state *cached_state = NULL;
        int i;
        unsigned long index = pos >> PAGE_CACHE_SHIFT;
 -      struct inode *inode = fdentry(file)->d_inode;
 +      struct inode *inode = file_inode(file);
        gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
        int err = 0;
        int faili = 0;
@@@ -1317,7 -1317,7 +1317,7 @@@ static noinline ssize_t __btrfs_buffere
                                               struct iov_iter *i,
                                               loff_t pos)
  {
 -      struct inode *inode = fdentry(file)->d_inode;
 +      struct inode *inode = file_inode(file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct page **pages = NULL;
        unsigned long first_index;
@@@ -1505,7 -1505,7 +1505,7 @@@ static ssize_t btrfs_file_aio_write(str
                                    unsigned long nr_segs, loff_t pos)
  {
        struct file *file = iocb->ki_filp;
 -      struct inode *inode = fdentry(file)->d_inode;
 +      struct inode *inode = file_inode(file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        loff_t *ppos = &iocb->ki_pos;
        u64 start_pos;
@@@ -2140,8 -2140,9 +2140,9 @@@ out
  static long btrfs_fallocate(struct file *file, int mode,
                            loff_t offset, loff_t len)
  {
 -      struct inode *inode = file->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(file);
        struct extent_state *cached_state = NULL;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 cur_offset;
        u64 last_byte;
        u64 alloc_start;
        ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
        if (ret)
                return ret;
+       if (root->fs_info->quota_enabled) {
+               ret = btrfs_qgroup_reserve(root, alloc_end - alloc_start);
+               if (ret)
+                       goto out_reserve_fail;
+       }
  
        /*
         * wait for ordered IO before we have any locks.  We'll loop again
                             &cached_state, GFP_NOFS);
  out:
        mutex_unlock(&inode->i_mutex);
+       if (root->fs_info->quota_enabled)
+               btrfs_qgroup_free(root, alloc_end - alloc_start);
+ out_reserve_fail:
        /* Let go of our reservation. */
        btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
        return ret;
diff --combined fs/btrfs/inode.c
index ca1b767d51f760672f8de72c48efbf3df8e58a75,b88381582dabe3d5169d9d0877b08c5fc0d914ec..09c58a35b429d6a82dc261014df2875e7c15f920
@@@ -353,6 -353,7 +353,7 @@@ static noinline int compress_file_range
        int i;
        int will_compress;
        int compress_type = root->fs_info->compress_type;
+       int redirty = 0;
  
        /* if this is a small write inside eof, kick off a defrag */
        if ((end - start + 1) < 16 * 1024 &&
@@@ -415,6 -416,17 +416,17 @@@ again
                if (BTRFS_I(inode)->force_compress)
                        compress_type = BTRFS_I(inode)->force_compress;
  
+               /*
+                * we need to call clear_page_dirty_for_io on each
+                * page in the range.  Otherwise applications with the file
+                * mmap'd can wander in and change the page contents while
+                * we are compressing them.
+                *
+                * If the compression fails for any reason, we set the pages
+                * dirty again later on.
+                */
+               extent_range_clear_dirty_for_io(inode, start, end);
+               redirty = 1;
                ret = btrfs_compress_pages(compress_type,
                                           inode->i_mapping, start,
                                           total_compressed, pages,
@@@ -554,6 -566,8 +566,8 @@@ cleanup_and_bail_uncompressed
                        __set_page_dirty_nobuffers(locked_page);
                        /* unlocked later on in the async handlers */
                }
+               if (redirty)
+                       extent_range_redirty_for_io(inode, start, end);
                add_async_extent(async_cow, start, end - start + 1,
                                 0, NULL, 0, BTRFS_COMPRESS_NONE);
                *num_added += 1;
@@@ -1743,8 -1757,10 +1757,10 @@@ static noinline int add_pending_csums(s
        struct btrfs_ordered_sum *sum;
  
        list_for_each_entry(sum, list, list) {
+               trans->adding_csums = 1;
                btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
+               trans->adding_csums = 0;
        }
        return 0;
  }
@@@ -3679,11 -3695,9 +3695,9 @@@ static struct btrfs_trans_handle *__unl
         * 1 for the dir item
         * 1 for the dir index
         * 1 for the inode ref
-        * 1 for the inode ref in the tree log
-        * 2 for the dir entries in the log
         * 1 for the inode
         */
-       trans = btrfs_start_transaction(root, 8);
+       trans = btrfs_start_transaction(root, 5);
        if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
                return trans;
  
@@@ -5110,7 -5124,7 +5124,7 @@@ unsigned char btrfs_filetype_table[] = 
  static int btrfs_real_readdir(struct file *filp, void *dirent,
                              filldir_t filldir)
  {
 -      struct inode *inode = filp->f_dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_item *item;
        struct btrfs_dir_item *di;
@@@ -7532,7 -7546,7 +7546,7 @@@ static void btrfs_invalidatepage(struc
  int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
        struct page *page = vmf->page;
 -      struct inode *inode = fdentry(vma->vm_file)->d_inode;
 +      struct inode *inode = file_inode(vma->vm_file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_ordered_extent *ordered;
@@@ -8127,7 -8141,7 +8141,7 @@@ static int btrfs_rename(struct inode *o
         * inodes.  So 5 * 2 is 10, plus 1 for the new link, so 11 total items
         * should cover the worst case number of items we'll modify.
         */
-       trans = btrfs_start_transaction(root, 20);
+       trans = btrfs_start_transaction(root, 11);
        if (IS_ERR(trans)) {
                  ret = PTR_ERR(trans);
                  goto out_notrans;
diff --combined fs/btrfs/send.c
index f7a8b861058b5234094d24e9fc35a49d9e78fe1c,ed897dc113568b3e49c1a16db4a37ea21714b99d..c85e7c6b4598af950d240582f648224570889ca4
@@@ -3945,12 -3945,10 +3945,10 @@@ static int is_extent_unchanged(struct s
                    found_key.type != key.type) {
                        key.offset += right_len;
                        break;
-               } else {
-                       if (found_key.offset != key.offset + right_len) {
-                               /* Should really not happen */
-                               ret = -EIO;
-                               goto out;
-                       }
+               }
+               if (found_key.offset != key.offset + right_len) {
+                       ret = 0;
+                       goto out;
                }
                key = found_key;
        }
@@@ -4578,7 -4576,7 +4576,7 @@@ long btrfs_ioctl_send(struct file *mnt_
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
  
 -      send_root = BTRFS_I(fdentry(mnt_file)->d_inode)->root;
 +      send_root = BTRFS_I(file_inode(mnt_file))->root;
        fs_info = send_root->fs_info;
  
        arg = memdup_user(arg_, sizeof(*arg));