aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2014-01-09 20:28:00 -0500
committerChris Mason <clm@fb.com>2014-01-29 10:06:30 -0500
commit90d3e592e99b8e374ead2b45148abf506493a959 (patch)
tree9e2b61f449524e988dacb04a770b87a2e3fddc23 /fs/btrfs/inode.c
parent514ac8ad8793a097c0c9d89202c642479d6dfa34 (diff)
Btrfs: setup inode location during btrfs_init_inode_locked
We have a race during inode init because the BTRFS_I(inode)->location is setup after the inode hash table lock is dropped. btrfs_find_actor uses the location field, so our search might not find an existing inode in the hash table if we race with the inode init code. This commit changes things to setup the location field sooner. Also the find actor now uses only the location objectid to match inodes. For inode hashing, we just need a unique and stable test, it doesn't have to reflect the inode numbers we show to userland. Signed-off-by: Chris Mason <clm@fb.com> CC: stable@vger.kernel.org
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ad961a598c99..fb74a536add3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -61,7 +61,7 @@
61#include "props.h" 61#include "props.h"
62 62
63struct btrfs_iget_args { 63struct btrfs_iget_args {
64 u64 ino; 64 struct btrfs_key *location;
65 struct btrfs_root *root; 65 struct btrfs_root *root;
66}; 66};
67 67
@@ -4977,7 +4977,9 @@ again:
4977static int btrfs_init_locked_inode(struct inode *inode, void *p) 4977static int btrfs_init_locked_inode(struct inode *inode, void *p)
4978{ 4978{
4979 struct btrfs_iget_args *args = p; 4979 struct btrfs_iget_args *args = p;
4980 inode->i_ino = args->ino; 4980 inode->i_ino = args->location->objectid;
4981 memcpy(&BTRFS_I(inode)->location, args->location,
4982 sizeof(*args->location));
4981 BTRFS_I(inode)->root = args->root; 4983 BTRFS_I(inode)->root = args->root;
4982 return 0; 4984 return 0;
4983} 4985}
@@ -4985,19 +4987,19 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
4985static int btrfs_find_actor(struct inode *inode, void *opaque) 4987static int btrfs_find_actor(struct inode *inode, void *opaque)
4986{ 4988{
4987 struct btrfs_iget_args *args = opaque; 4989 struct btrfs_iget_args *args = opaque;
4988 return args->ino == btrfs_ino(inode) && 4990 return args->location->objectid == BTRFS_I(inode)->location.objectid &&
4989 args->root == BTRFS_I(inode)->root; 4991 args->root == BTRFS_I(inode)->root;
4990} 4992}
4991 4993
4992static struct inode *btrfs_iget_locked(struct super_block *s, 4994static struct inode *btrfs_iget_locked(struct super_block *s,
4993 u64 objectid, 4995 struct btrfs_key *location,
4994 struct btrfs_root *root) 4996 struct btrfs_root *root)
4995{ 4997{
4996 struct inode *inode; 4998 struct inode *inode;
4997 struct btrfs_iget_args args; 4999 struct btrfs_iget_args args;
4998 unsigned long hashval = btrfs_inode_hash(objectid, root); 5000 unsigned long hashval = btrfs_inode_hash(location->objectid, root);
4999 5001
5000 args.ino = objectid; 5002 args.location = location;
5001 args.root = root; 5003 args.root = root;
5002 5004
5003 inode = iget5_locked(s, hashval, btrfs_find_actor, 5005 inode = iget5_locked(s, hashval, btrfs_find_actor,
@@ -5014,13 +5016,11 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
5014{ 5016{
5015 struct inode *inode; 5017 struct inode *inode;
5016 5018
5017 inode = btrfs_iget_locked(s, location->objectid, root); 5019 inode = btrfs_iget_locked(s, location, root);
5018 if (!inode) 5020 if (!inode)
5019 return ERR_PTR(-ENOMEM); 5021 return ERR_PTR(-ENOMEM);
5020 5022
5021 if (inode->i_state & I_NEW) { 5023 if (inode->i_state & I_NEW) {
5022 BTRFS_I(inode)->root = root;
5023 memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
5024 btrfs_read_locked_inode(inode); 5024 btrfs_read_locked_inode(inode);
5025 if (!is_bad_inode(inode)) { 5025 if (!is_bad_inode(inode)) {
5026 inode_tree_add(inode); 5026 inode_tree_add(inode);