]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/inode.c
Btrfs: unlock extent and pages on error in cow_file_range
[karo-tx-linux.git] / fs / btrfs / inode.c
index 7b61ea3141e51dd877d856eb6b11dba25ce67fc9..5b892500309087b78875918608fa3289578a5a04 100644 (file)
@@ -61,7 +61,7 @@
 #include "props.h"
 
 struct btrfs_iget_args {
-       u64 ino;
+       struct btrfs_key *location;
        struct btrfs_root *root;
 };
 
@@ -864,7 +864,8 @@ static noinline int cow_file_range(struct inode *inode,
 
        if (btrfs_is_free_space_inode(inode)) {
                WARN_ON_ONCE(1);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_unlock;
        }
 
        num_bytes = ALIGN(end - start + 1, blocksize);
@@ -1281,7 +1282,8 @@ next_slot:
                        nocow = 1;
                } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                        extent_end = found_key.offset +
-                               btrfs_file_extent_inline_len(leaf, fi);
+                               btrfs_file_extent_inline_len(leaf,
+                                                    path->slots[0], fi);
                        extent_end = ALIGN(extent_end, root->sectorsize);
                } else {
                        BUG_ON(1);
@@ -2314,7 +2316,7 @@ again:
                u64 extent_len;
                struct btrfs_key found_key;
 
-               ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
+               ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
                if (ret < 0)
                        goto out_free_path;
 
@@ -2628,7 +2630,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                        EXTENT_DEFRAG, 1, cached_state);
        if (ret) {
                u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item);
-               if (last_snapshot >= BTRFS_I(inode)->generation)
+               if (0 && last_snapshot >= BTRFS_I(inode)->generation)
                        /* the inode is shared */
                        new = record_old_file_extents(inode, ordered_extent);
 
@@ -4023,7 +4025,7 @@ search_again:
                                    btrfs_file_extent_num_bytes(leaf, fi);
                        } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                                item_end += btrfs_file_extent_inline_len(leaf,
-                                                                        fi);
+                                                        path->slots[0], fi);
                        }
                        item_end--;
                }
@@ -4093,6 +4095,12 @@ search_again:
                                        inode_sub_bytes(inode, item_end + 1 -
                                                        new_size);
                                }
+
+                               /*
+                                * update the ram bytes to properly reflect
+                                * the new size of our item
+                                */
+                               btrfs_set_file_extent_ram_bytes(leaf, fi, size);
                                size =
                                    btrfs_file_extent_calc_inline_size(size);
                                btrfs_truncate_item(root, path, size, 1);
@@ -4970,7 +4978,9 @@ again:
 static int btrfs_init_locked_inode(struct inode *inode, void *p)
 {
        struct btrfs_iget_args *args = p;
-       inode->i_ino = args->ino;
+       inode->i_ino = args->location->objectid;
+       memcpy(&BTRFS_I(inode)->location, args->location,
+              sizeof(*args->location));
        BTRFS_I(inode)->root = args->root;
        return 0;
 }
@@ -4978,19 +4988,19 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
 static int btrfs_find_actor(struct inode *inode, void *opaque)
 {
        struct btrfs_iget_args *args = opaque;
-       return args->ino == btrfs_ino(inode) &&
+       return args->location->objectid == BTRFS_I(inode)->location.objectid &&
                args->root == BTRFS_I(inode)->root;
 }
 
 static struct inode *btrfs_iget_locked(struct super_block *s,
-                                      u64 objectid,
+                                      struct btrfs_key *location,
                                       struct btrfs_root *root)
 {
        struct inode *inode;
        struct btrfs_iget_args args;
-       unsigned long hashval = btrfs_inode_hash(objectid, root);
+       unsigned long hashval = btrfs_inode_hash(location->objectid, root);
 
-       args.ino = objectid;
+       args.location = location;
        args.root = root;
 
        inode = iget5_locked(s, hashval, btrfs_find_actor,
@@ -5007,13 +5017,11 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
 {
        struct inode *inode;
 
-       inode = btrfs_iget_locked(s, location->objectid, root);
+       inode = btrfs_iget_locked(s, location, root);
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
        if (inode->i_state & I_NEW) {
-               BTRFS_I(inode)->root = root;
-               memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
                btrfs_read_locked_inode(inode);
                if (!is_bad_inode(inode)) {
                        inode_tree_add(inode);
@@ -5143,7 +5151,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                        return ERR_CAST(inode);
        }
 
-       return d_splice_alias(inode, dentry);
+       return d_materialise_unique(dentry, inode);
 }
 
 unsigned char btrfs_filetype_table[] = {
@@ -5788,6 +5796,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        }
 out_unlock:
        btrfs_end_transaction(trans, root);
+       btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        if (drop_inode) {
                inode_dec_link_count(inode);
@@ -5861,6 +5870,7 @@ out_unlock:
                inode_dec_link_count(inode);
                iput(inode);
        }
+       btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return err;
 }
@@ -5919,6 +5929,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        }
 
        btrfs_end_transaction(trans, root);
+       btrfs_balance_delayed_items(root);
 fail:
        if (drop_inode) {
                inode_dec_link_count(inode);
@@ -5985,6 +5996,7 @@ out_fail:
        btrfs_end_transaction(trans, root);
        if (drop_on_err)
                iput(inode);
+       btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return err;
 }
@@ -6162,7 +6174,7 @@ again:
                       btrfs_file_extent_num_bytes(leaf, item);
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                size_t size;
-               size = btrfs_file_extent_inline_len(leaf, item);
+               size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
                extent_end = ALIGN(extent_start + size, root->sectorsize);
        }
 next:
@@ -6231,7 +6243,7 @@ next:
                        goto out;
                }
 
-               size = btrfs_file_extent_inline_len(leaf, item);
+               size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
                extent_offset = page_offset(page) + pg_offset - extent_start;
                copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset,
                                size - extent_offset);