[LU-6794] memory leak in Lustre NFS support code, LASSERT() at unmount Created: 02/Jul/15  Updated: 14/Sep/15  Resolved: 16/Jul/15

Status: Resolved
Project: Lustre
Component/s: None
Affects Version/s: Lustre 2.8.0
Fix Version/s: Lustre 2.8.0

Type: Bug Priority: Critical
Reporter: Andrew Perepechko Assignee: Zhenyu Xu
Resolution: Fixed Votes: 0
Labels: patch

Issue Links:
Related
is related to LU-4272 lu_device_fini()) ASSERTION( cfs_atom... Resolved
Severity: 3
Rank (Obsolete): 9223372036854775807

 Description   

There is an unbalanced iput() call in Lustre NFS support code.

A possible symptom is a kernel crash with
ASSERTION( atomic_read(&d->ld_ref) == 0 ) failed

A fix will be uploaded shortly.



 Comments   
Comment by Gerrit Updater [ 02/Jul/15 ]

Andrew Perepechko (andrew.perepechko@seagate.com) uploaded a new patch: http://review.whamcloud.com/15480
Subject: LU-6794 nfs: ASSERTION( atomic_read(&d->ld_ref) == 0 ) failed
Project: fs/lustre-release
Branch: master
Current Patch Set: 1
Commit: 43a8fb75c98ba0d677eaa1297e21e0a4de2ec16f

Comment by Peter Jones [ 03/Jul/15 ]

Bobijam

Could you please take care of this patch?

Thanks

Peter

Comment by Andrew Perepechko [ 03/Jul/15 ]

Based on vanilla linux.git, d_obtain_alias() has had the feature of releasing inode on error from its introduction up to now:

commit 4ea3ada2955e4519befa98ff55dd62d6dfbd1705
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Aug 11 15:48:57 2008 +0200

    [PATCH] new helper: d_obtain_alias
    
    The calling conventions of d_alloc_anon are rather unfortunate for all
    users, and it's name is not very descriptive either.
    
    Add d_obtain_alias as a new exported helper that drops the inode
    reference in the failure case, too and allows to pass-through NULL
    pointers and inodes to allow for tail-calls in the export operations.
    
    Incidentally this helper already existed as a private function in
    libfs.c as exportfs_d_alloc so kill that one and switch the callers
    to d_obtain_alias.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

diff --git a/fs/dcache.c b/fs/dcache.c
index e7a1a99..46fc782 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1174,6 +1174,41 @@ struct dentry * d_alloc_anon(struct inode *inode)
        return res;
 }
 
+/**
+ * d_obtain_alias - find or allocate a dentry for a given inode
+ * @inode: inode to allocate the dentry for
+ *
+ * Obtain a dentry for an inode resulting from NFS filehandle conversion or
+ * similar open by handle operations.  The returned dentry may be anonymous,
+ * or may have a full name (if the inode was already in the cache).
+ *
+ * When called on a directory inode, we must ensure that the inode only ever
+ * has one dentry.  If a dentry is found, that is returned instead of
+ * allocating a new one.
+ *
+ * On successful return, the reference to the inode has been transferred
+ * to the dentry.  If %NULL is returned (indicating kmalloc failure),
+ * the reference on the inode has been released.  To make it easier
+ * to use in export operations a NULL or IS_ERR inode may be passed in
+ * and will be casted to the corresponding NULL or IS_ERR dentry.
+ */
+struct dentry *d_obtain_alias(struct inode *inode)
+{
+       struct dentry *dentry;
+
+       if (!inode)
+               return NULL;
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+
+       dentry = d_alloc_anon(inode);
+       if (!dentry) {
+               iput(inode);
+               dentry = ERR_PTR(-ENOMEM);
+       }
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(d_obtain_alias);

current code is:

static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
{
        static const struct qstr anonstring = QSTR_INIT("/", 1);
        struct dentry *tmp;
        struct dentry *res;
        unsigned add_flags;

        if (!inode)
                return ERR_PTR(-ESTALE);
        if (IS_ERR(inode))
                return ERR_CAST(inode);

        res = d_find_any_alias(inode);
        if (res)
                goto out_iput;

        tmp = __d_alloc(inode->i_sb, &anonstring);
        if (!tmp) {
                res = ERR_PTR(-ENOMEM);
                goto out_iput;
        }

        spin_lock(&inode->i_lock);
        res = __d_find_any_alias(inode);
        if (res) {
                spin_unlock(&inode->i_lock);
                dput(tmp);
                goto out_iput;
        }

        /* attach a disconnected dentry */
        add_flags = d_flags_for_inode(inode);

        if (disconnected)
                add_flags |= DCACHE_DISCONNECTED;

        spin_lock(&tmp->d_lock);
        __d_set_inode_and_type(tmp, inode, add_flags);
        hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
        hlist_bl_lock(&tmp->d_sb->s_anon);
        hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
        hlist_bl_unlock(&tmp->d_sb->s_anon);
        spin_unlock(&tmp->d_lock);
        spin_unlock(&inode->i_lock);
        security_d_instantiate(tmp, inode);

        return tmp;

 out_iput:
        if (res && !IS_ERR(res))
                security_d_instantiate(res, inode);
        iput(inode);
        return res;
}
Comment by Gerrit Updater [ 16/Jul/15 ]

Oleg Drokin (oleg.drokin@intel.com) merged in patch http://review.whamcloud.com/15480/
Subject: LU-6794 nfs: ASSERTION( atomic_read(&d->ld_ref) == 0 ) failed
Project: fs/lustre-release
Branch: master
Current Patch Set:
Commit: a37a5a9e5e309f87db9497d187df41d0fede8d29

Comment by Peter Jones [ 16/Jul/15 ]

Landed for 2.8

Generated at Sat Feb 10 02:03:18 UTC 2024 using Jira 9.4.14#940014-sha1:734e6822bbf0d45eff9af51f82432957f73aa32c.