A user reported a hang on mount and it looks like we are waiting for the inode
cache to fill up.  The caching thread will stop if it sees that we are
committing a transaction every time it has to move leaves and then it will
re-search.  But we call btrfs_find_free_ino() inside of a transaction so if the
transaction goes to commit it will be held open while we wait for an inode to
show up.  This will make the caching thread take for freaking ever and appear to
lock up the box.  The other thing this patch fixes is that if we have an error
creating the inode we won't properly free up the inode number we just took, so
we could leak inode numbers if we have inode caching on in this case.  Thanks,

Signed-off-by: Josef Bacik <jba...@fusionio.com>
---
 fs/btrfs/inode.c |   52 ++++++++++++++++++++++++++++++++--------------------
 1 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b883815..725e268 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5713,23 +5713,26 @@ static int btrfs_mknod(struct inode *dir, struct dentry 
*dentry,
        if (!new_valid_dev(rdev))
                return -EINVAL;
 
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 for inode item and ref
         * 2 for dir items
         * 1 for xattr if selinux is on
         */
        trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
+       if (IS_ERR(trans)) {
+               btrfs_return_ino(root, objectid);
                return PTR_ERR(trans);
-
-       err = btrfs_find_free_ino(root, &objectid);
-       if (err)
-               goto out_unlock;
+       }
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
                                mode, &index);
        if (IS_ERR(inode)) {
+               btrfs_return_ino(root, objectid);
                err = PTR_ERR(inode);
                goto out_unlock;
        }
@@ -5777,23 +5780,26 @@ static int btrfs_create(struct inode *dir, struct 
dentry *dentry,
        u64 objectid;
        u64 index = 0;
 
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 for inode item and ref
         * 2 for dir items
         * 1 for xattr if selinux is on
         */
        trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
+       if (IS_ERR(trans)) {
+               btrfs_return_ino(root, objectid);
                return PTR_ERR(trans);
-
-       err = btrfs_find_free_ino(root, &objectid);
-       if (err)
-               goto out_unlock;
+       }
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
                                mode, &index);
        if (IS_ERR(inode)) {
+               btrfs_return_ino(root, objectid);
                err = PTR_ERR(inode);
                goto out_unlock;
        }
@@ -5906,24 +5912,27 @@ static int btrfs_mkdir(struct inode *dir, struct dentry 
*dentry, umode_t mode)
        u64 objectid = 0;
        u64 index = 0;
 
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 items for inode and ref
         * 2 items for dir items
         * 1 for xattr if selinux is on
         */
        trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
+       if (IS_ERR(trans)) {
+               btrfs_return_ino(root, objectid);
                return PTR_ERR(trans);
-
-       err = btrfs_find_free_ino(root, &objectid);
-       if (err)
-               goto out_fail;
+       }
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
                                S_IFDIR | mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
+               btrfs_return_ino(root, objectid);
                goto out_fail;
        }
 
@@ -8407,23 +8416,26 @@ static int btrfs_symlink(struct inode *dir, struct 
dentry *dentry,
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
 
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               return err;
+
        /*
         * 2 items for inode item and ref
         * 2 items for dir items
         * 1 item for xattr if selinux is on
         */
        trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
+       if (IS_ERR(trans)) {
+               btrfs_return_ino(root, objectid);
                return PTR_ERR(trans);
-
-       err = btrfs_find_free_ino(root, &objectid);
-       if (err)
-               goto out_unlock;
+       }
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
                                S_IFLNK|S_IRWXUGO, &index);
        if (IS_ERR(inode)) {
+               btrfs_return_ino(root, objectid);
                err = PTR_ERR(inode);
                goto out_unlock;
        }
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to