lkml.org 
[lkml]   [2015]   [Aug]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.14 37/44] dentry_kill(): dont try to remove from shrink list
    Date
    3.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Al Viro <viro@zeniv.linux.org.uk>

    commit 41edf278fc2f042f4e22a12ed87d19c5201210e1 upstream.

    If the victim in on the shrink list, don't remove it from there.
    If shrink_dentry_list() manages to remove it from the list before
    we are done - fine, we'll just free it as usual. If not - mark
    it with new flag (DCACHE_MAY_FREE) and leave it there.

    Eventually, shrink_dentry_list() will get to it, remove the sucker
    from shrink list and call dentry_kill(dentry, 0). Which is where
    we'll deal with freeing.

    Since now dentry_kill(dentry, 0) may happen after or during
    dentry_kill(dentry, 1), we need to recognize that (by seeing
    DCACHE_DENTRY_KILLED already set), unlock everything
    and either free the sucker (in case DCACHE_MAY_FREE has been
    set) or leave it for ongoing dentry_kill(dentry, 1) to deal with.

    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
    Cc: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/dcache.c | 27 +++++++++++++++++++--------
    include/linux/dcache.h | 2 ++
    2 files changed, 21 insertions(+), 8 deletions(-)

    --- a/fs/dcache.c
    +++ b/fs/dcache.c
    @@ -466,7 +466,14 @@ dentry_kill(struct dentry *dentry, int u
    __releases(dentry->d_lock)
    {
    struct inode *inode;
    - struct dentry *parent;
    + struct dentry *parent = NULL;
    + bool can_free = true;
    +
    + if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
    + can_free = dentry->d_flags & DCACHE_MAY_FREE;
    + spin_unlock(&dentry->d_lock);
    + goto out;
    + }

    inode = dentry->d_inode;
    if (inode && !spin_trylock(&inode->i_lock)) {
    @@ -477,9 +484,7 @@ relock:
    }
    return dentry; /* try again with same dentry */
    }
    - if (IS_ROOT(dentry))
    - parent = NULL;
    - else
    + if (!IS_ROOT(dentry))
    parent = dentry->d_parent;
    if (parent && !spin_trylock(&parent->d_lock)) {
    if (inode)
    @@ -502,8 +507,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);
    @@ -525,7 +528,15 @@ 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;
    + can_free = false;
    + }
    + spin_unlock(&dentry->d_lock);
    +out:
    + if (likely(can_free))
    + dentry_free(dentry);
    return parent;
    }

    @@ -830,7 +841,7 @@ static void shrink_dentry_list(struct li
    * We found an inuse dentry which was not removed from
    * the LRU because of laziness during lookup. Do not free it.
    */
    - if (dentry->d_lockref.count) {
    + if ((int)dentry->d_lockref.count > 0) {
    spin_unlock(&dentry->d_lock);
    continue;
    }
    --- 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: 2015-08-14 20:21    [W:7.162 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site