]> Git Repo - linux.git/commitdiff
Merge tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <[email protected]>
Sun, 4 Mar 2018 19:04:27 +0000 (11:04 -0800)
committerLinus Torvalds <[email protected]>
Sun, 4 Mar 2018 19:04:27 +0000 (11:04 -0800)
Pull btrfs fixes from David Sterba:

 - when NR_CPUS is large, a SRCU structure can significantly inflate
   size of the main filesystem structure that would not be possible to
   allocate by kmalloc, so the kvalloc fallback is used

 - improved error handling

 - fix endiannes when printing some filesystem attributes via sysfs,
   this is could happen when a filesystem is moved between different
   endianity hosts

 - send fixes: the NO_HOLE mode should not send a write operation for a
   file hole

 - fix log replay for for special files followed by file hardlinks

 - fix log replay failure after unlink and link combination

 - fix max chunk size calculation for DUP allocation

* tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  Btrfs: fix log replay failure after unlink and link combination
  Btrfs: fix log replay failure after linking special file and fsync
  Btrfs: send, fix issuing write op when processing hole in no data mode
  btrfs: use proper endianness accessors for super_copy
  btrfs: alloc_chunk: fix DUP stripe size handling
  btrfs: Handle btrfs_set_extent_delalloc failure in relocate_file_extent_cluster
  btrfs: handle failure of add_pending_csums
  btrfs: use kvzalloc to allocate btrfs_fs_info

1  2 
fs/btrfs/inode.c
fs/btrfs/tree-log.c

diff --combined fs/btrfs/inode.c
index a79299a89b7d0285328e29cecaaff51ff82c5be7,8f7d41fcfbff62487c8271494ce780a00318ba5d..f53470112670b2de73343e635e4304fd08816468
@@@ -43,7 -43,6 +43,7 @@@
  #include <linux/posix_acl_xattr.h>
  #include <linux/uio.h>
  #include <linux/magic.h>
 +#include <linux/iversion.h>
  #include "ctree.h"
  #include "disk-io.h"
  #include "transaction.h"
@@@ -2043,12 -2042,15 +2043,15 @@@ static noinline int add_pending_csums(s
                             struct inode *inode, struct list_head *list)
  {
        struct btrfs_ordered_sum *sum;
+       int ret;
  
        list_for_each_entry(sum, list, list) {
                trans->adding_csums = true;
-               btrfs_csum_file_blocks(trans,
+               ret = btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
                trans->adding_csums = false;
+               if (ret)
+                       return ret;
        }
        return 0;
  }
@@@ -3062,7 -3064,11 +3065,11 @@@ static int btrfs_finish_ordered_io(stru
                goto out;
        }
  
-       add_pending_csums(trans, inode, &ordered_extent->list);
+       ret = add_pending_csums(trans, inode, &ordered_extent->list);
+       if (ret) {
+               btrfs_abort_transaction(trans, ret);
+               goto out;
+       }
  
        btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        ret = btrfs_update_inode_fallback(trans, root, inode);
@@@ -3814,8 -3820,7 +3821,8 @@@ static int btrfs_read_locked_inode(stru
        BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
        BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item);
  
 -      inode->i_version = btrfs_inode_sequence(leaf, inode_item);
 +      inode_set_iversion_queried(inode,
 +                                 btrfs_inode_sequence(leaf, inode_item));
        inode->i_generation = BTRFS_I(inode)->generation;
        inode->i_rdev = 0;
        rdev = btrfs_inode_rdev(leaf, inode_item);
@@@ -3983,8 -3988,7 +3990,8 @@@ static void fill_inode_item(struct btrf
                                     &token);
        btrfs_set_token_inode_generation(leaf, item, BTRFS_I(inode)->generation,
                                         &token);
 -      btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token);
 +      btrfs_set_token_inode_sequence(leaf, item, inode_peek_iversion(inode),
 +                                     &token);
        btrfs_set_token_inode_transid(leaf, item, trans->transid, &token);
        btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token);
        btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token);
@@@ -6136,20 -6140,19 +6143,20 @@@ static int btrfs_update_time(struct ino
                             int flags)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
 +      bool dirty = flags & ~S_VERSION;
  
        if (btrfs_root_readonly(root))
                return -EROFS;
  
        if (flags & S_VERSION)
 -              inode_inc_iversion(inode);
 +              dirty |= inode_maybe_inc_iversion(inode, dirty);
        if (flags & S_CTIME)
                inode->i_ctime = *now;
        if (flags & S_MTIME)
                inode->i_mtime = *now;
        if (flags & S_ATIME)
                inode->i_atime = *now;
 -      return btrfs_dirty_inode(inode);
 +      return dirty ? btrfs_dirty_inode(inode) : 0;
  }
  
  /*
@@@ -7907,7 -7910,6 +7914,7 @@@ static blk_status_t dio_read_error(stru
        int segs;
        int ret;
        blk_status_t status;
 +      struct bio_vec bvec;
  
        BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
  
        }
  
        segs = bio_segments(failed_bio);
 +      bio_get_first_bvec(failed_bio, &bvec);
        if (segs > 1 ||
 -          (failed_bio->bi_io_vec->bv_len > btrfs_inode_sectorsize(inode)))
 +          (bvec.bv_len > btrfs_inode_sectorsize(inode)))
                read_mode |= REQ_FAILFAST_DEV;
  
        isector = start - btrfs_io_bio(failed_bio)->logical;
@@@ -7968,7 -7969,7 +7975,7 @@@ static void btrfs_retry_endio_nocsum(st
        ASSERT(bio->bi_vcnt == 1);
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
 -      ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode));
 +      ASSERT(bio_first_bvec_all(bio)->bv_len == btrfs_inode_sectorsize(inode));
  
        done->uptodate = 1;
        ASSERT(!bio_flagged(bio, BIO_CLONED));
@@@ -8058,7 -8059,7 +8065,7 @@@ static void btrfs_retry_endio(struct bi
        uptodate = 1;
  
        ASSERT(bio->bi_vcnt == 1);
 -      ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(done->inode));
 +      ASSERT(bio_first_bvec_all(bio)->bv_len == btrfs_inode_sectorsize(done->inode));
  
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
diff --combined fs/btrfs/tree-log.c
index 4fd19b4d667557f8b45b1ec61ef48f79ebb5f1cf,4c50f823949c01cdb1d8d1fecd4af2005a412c09..434457794c279463872a593adf600783f82390cf
@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/slab.h>
  #include <linux/blkdev.h>
  #include <linux/list_sort.h>
 +#include <linux/iversion.h>
  #include "tree-log.h"
  #include "disk-io.h"
  #include "locking.h"
@@@ -967,7 -966,9 +967,9 @@@ static noinline int backref_in_log(stru
        ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
  
        if (key->type == BTRFS_INODE_EXTREF_KEY) {
-               if (btrfs_find_name_in_ext_backref(path, ref_objectid,
+               if (btrfs_find_name_in_ext_backref(path->nodes[0],
+                                                  path->slots[0],
+                                                  ref_objectid,
                                                   name, namelen, NULL))
                        match = 1;
  
@@@ -1191,7 -1192,8 +1193,8 @@@ static int extref_get_fields(struct ext
        read_extent_buffer(eb, *name, (unsigned long)&extref->name,
                           *namelen);
  
-       *index = btrfs_inode_extref_index(eb, extref);
+       if (index)
+               *index = btrfs_inode_extref_index(eb, extref);
        if (parent_objectid)
                *parent_objectid = btrfs_inode_extref_parent(eb, extref);
  
@@@ -1212,11 -1214,101 +1215,101 @@@ static int ref_get_fields(struct extent
  
        read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
  
-       *index = btrfs_inode_ref_index(eb, ref);
+       if (index)
+               *index = btrfs_inode_ref_index(eb, ref);
  
        return 0;
  }
  
+ /*
+  * Take an inode reference item from the log tree and iterate all names from the
+  * inode reference item in the subvolume tree with the same key (if it exists).
+  * For any name that is not in the inode reference item from the log tree, do a
+  * proper unlink of that name (that is, remove its entry from the inode
+  * reference item and both dir index keys).
+  */
+ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path,
+                                struct btrfs_inode *inode,
+                                struct extent_buffer *log_eb,
+                                int log_slot,
+                                struct btrfs_key *key)
+ {
+       int ret;
+       unsigned long ref_ptr;
+       unsigned long ref_end;
+       struct extent_buffer *eb;
+ again:
+       btrfs_release_path(path);
+       ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+       if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+       if (ret < 0)
+               goto out;
+       eb = path->nodes[0];
+       ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
+       ref_end = ref_ptr + btrfs_item_size_nr(eb, path->slots[0]);
+       while (ref_ptr < ref_end) {
+               char *name = NULL;
+               int namelen;
+               u64 parent_id;
+               if (key->type == BTRFS_INODE_EXTREF_KEY) {
+                       ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
+                                               NULL, &parent_id);
+               } else {
+                       parent_id = key->offset;
+                       ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
+                                            NULL);
+               }
+               if (ret)
+                       goto out;
+               if (key->type == BTRFS_INODE_EXTREF_KEY)
+                       ret = btrfs_find_name_in_ext_backref(log_eb, log_slot,
+                                                            parent_id, name,
+                                                            namelen, NULL);
+               else
+                       ret = btrfs_find_name_in_backref(log_eb, log_slot, name,
+                                                        namelen, NULL);
+               if (!ret) {
+                       struct inode *dir;
+                       btrfs_release_path(path);
+                       dir = read_one_inode(root, parent_id);
+                       if (!dir) {
+                               ret = -ENOENT;
+                               kfree(name);
+                               goto out;
+                       }
+                       ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir),
+                                                inode, name, namelen);
+                       kfree(name);
+                       iput(dir);
+                       if (ret)
+                               goto out;
+                       goto again;
+               }
+               kfree(name);
+               ref_ptr += namelen;
+               if (key->type == BTRFS_INODE_EXTREF_KEY)
+                       ref_ptr += sizeof(struct btrfs_inode_extref);
+               else
+                       ref_ptr += sizeof(struct btrfs_inode_ref);
+       }
+       ret = 0;
+  out:
+       btrfs_release_path(path);
+       return ret;
+ }
  /*
   * replay one inode back reference item found in the log tree.
   * eb, slot and key refer to the buffer and key found in the log tree.
@@@ -1345,6 -1437,19 +1438,19 @@@ static noinline int add_inode_ref(struc
                }
        }
  
+       /*
+        * Before we overwrite the inode reference item in the subvolume tree
+        * with the item from the log tree, we must unlink all names from the
+        * parent directory that are in the subvolume's tree inode reference
+        * item, otherwise we end up with an inconsistent subvolume tree where
+        * dir index entries exist for a name but there is no inode reference
+        * item with the same name.
+        */
+       ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot,
+                                   key);
+       if (ret)
+               goto out;
        /* finally write the back reference in the inode */
        ret = overwrite_item(trans, root, path, eb, slot, key);
  out:
@@@ -3598,8 -3703,7 +3704,8 @@@ static void fill_inode_item(struct btrf
        btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode),
                                     &token);
  
 -      btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token);
 +      btrfs_set_token_inode_sequence(leaf, item,
 +                                     inode_peek_iversion(inode), &token);
        btrfs_set_token_inode_transid(leaf, item, trans->transid, &token);
        btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token);
        btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token);
@@@ -5853,7 -5957,7 +5959,7 @@@ int btrfs_log_new_name(struct btrfs_tra
         * this will force the logging code to walk the dentry chain
         * up for the file
         */
-       if (S_ISREG(inode->vfs_inode.i_mode))
+       if (!S_ISDIR(inode->vfs_inode.i_mode))
                inode->last_unlink_trans = trans->transid;
  
        /*
This page took 0.115267 seconds and 4 git commands to generate.