lkml.org 
[lkml]   [2014]   [Apr]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: dcache shrink list corruption?
    On Wed, Apr 30, 2014 at 08:42:01PM +0200, Miklos Szeredi wrote:

    > Message-ID: <20140430154958.GC3113@tucsk.piliscsaba.szeredi.hu>

    I see... Several points:
    * I still think that it's better to do handling of "we see
    DCACHE_DENTRY_KILLED already set" in dentry_kill() itself.
    * in dentry_kill(dentry, 0) we *know* that it's not on a shrink
    list - the caller has just removed it from there and we'd kept ->d_lock
    since that point. What's more, with that scheme we don't need to bother
    with can_free at all - just grab ->d_lock after ->d_release() call and check
    DCACHE_SHRINK_LIST. No sense trying to avoid that - in case where we
    could just go ahead and free the sucker, there's neither contention nor
    anybody else interested in that cacheline, so spin_lock(&dentry->d_lock)
    is pretty much free.

    IOW, I'd prefer to do the following (completely untested) on top of 1/6--4/6:

    diff --git a/fs/dcache.c b/fs/dcache.c
    index e482775..82d8eb4 100644
    --- a/fs/dcache.c
    +++ b/fs/dcache.c
    @@ -489,6 +489,17 @@ relock:
    goto relock;
    }

    + if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
    + if (parent)
    + spin_unlock(&parent->d_lock);
    + if (dentry->d_flags & DCACHE_MAY_FREE) {
    + spin_unlock(&dentry->d_lock);
    + dentry_free(dentry);
    + } else {
    + spin_unlock(&dentry->d_lock);
    + }
    + return parent;
    + }
    /*
    * The dentry is now unrecoverably dead to the world.
    */
    @@ -504,8 +515,6 @@ relock:
    if (dentry->d_flags & DCACHE_LRU_LIST) {
    if (!(dentry->d_flags & DCACHE_SHRINK_LIST))
    d_lru_del(dentry);
    - else
    - d_shrink_del(dentry);
    }
    /* if it was on the hash then remove it */
    __d_drop(dentry);
    @@ -527,7 +536,14 @@ relock:
    if (dentry->d_op && dentry->d_op->d_release)
    dentry->d_op->d_release(dentry);

    - dentry_free(dentry);
    + spin_lock(&dentry->d_lock);
    + if (dentry->d_flags & DCACHE_SHRINK_LIST) {
    + dentry->d_flags |= DCACHE_MAY_FREE;
    + spin_unlock(&dentry->d_lock);
    + } else {
    + spin_unlock(&dentry->d_lock);
    + dentry_free(dentry);
    + }
    return parent;
    }

    diff --git a/include/linux/dcache.h b/include/linux/dcache.h
    index 3b9bfdb..3c7ec32 100644
    --- a/include/linux/dcache.h
    +++ b/include/linux/dcache.h
    @@ -221,6 +221,8 @@ struct dentry_operations {
    #define DCACHE_SYMLINK_TYPE 0x00300000 /* Symlink */
    #define DCACHE_FILE_TYPE 0x00400000 /* Other file type */

    +#define DCACHE_MAY_FREE 0x00800000
    +
    extern seqlock_t rename_lock;

    static inline int dname_external(const struct dentry *dentry)

    \
     
     \ /
      Last update: 2014-04-30 21:41    [W:5.777 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site