[lkml]   [2011]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[PATCH 12/13] dcache: remove dentries from LRU before putting on dispose list
    From: Dave Chinner <>

    One of the big problems with modifying the way the dcache shrinker
    and LRU implementation works is that the LRU is abused in several
    ways. One of these is shrinker_dentry_list().

    Basically, we can move a dentry off the LRU onto a different list
    without doing any accounting changes, and then use dentry_lru_del()
    to remove it from what-ever list it is now on to do the LRU
    accounting at that point.

    This makes it -really hard- to change the LRU implementation. The
    use of the per-sb LRU lock serialises movement of the dentries
    between the different lists and the removal of them, and this is the
    only reason that it works. If we want to break up the dentry LRU
    lock and lists into, say, per-node lists, we remove the only
    serialisation that allows this lru list/dispose list abuse to work.

    To make this work effectively, the dispose list has to be isolated
    from the LRU list - dentries have to be removed from the LRU
    *before* being placed on the dispose list. This means that the LRU
    accounting and isolation is completed before disposal is started,
    and that means we can change the LRU implementation freely in

    Signed-off-by: Dave Chinner <>
    fs/dcache.c | 25 ++++++++++++++++++++-----
    1 files changed, 20 insertions(+), 5 deletions(-)

    diff --git a/fs/dcache.c b/fs/dcache.c
    index b931415..79bf47c 100644
    --- a/fs/dcache.c
    +++ b/fs/dcache.c
    @@ -269,10 +269,10 @@ static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
    if (list_empty(&dentry->d_lru)) {
    list_add_tail(&dentry->d_lru, list);
    - dentry->d_sb->s_nr_dentry_unused++;
    - this_cpu_inc(nr_dentry_unused);
    } else {
    list_move_tail(&dentry->d_lru, list);
    + dentry->d_sb->s_nr_dentry_unused--;
    + this_cpu_dec(nr_dentry_unused);
    @@ -732,12 +732,17 @@ static void shrink_dentry_list(struct list_head *list)

    + * The dispose list is isolated and dentries are not accounted
    + * to the LRU here, so we can simply remove it from the list
    + * here regardless of whether it is referenced or not.
    + */
    + list_del_init(&dentry->d_lru);
    + /*
    * We found an inuse dentry which was not removed from
    - * the LRU because of laziness during lookup. Do not free
    - * it - just keep it off the LRU list.
    + * the LRU because of laziness during lookup. Do not free it.
    if (dentry->d_count) {
    - dentry_lru_del(dentry);
    @@ -789,6 +794,8 @@ relock:
    } else {
    list_move_tail(&dentry->d_lru, &tmp);
    + this_cpu_dec(nr_dentry_unused);
    + sb->s_nr_dentry_unused--;
    if (!--nr_to_scan)
    @@ -818,6 +825,14 @@ void shrink_dcache_sb(struct super_block *sb)
    while (!list_empty(&sb->s_dentry_lru)) {
    list_splice_init(&sb->s_dentry_lru, &tmp);
    + /*
    + * account for removal here so we don't need to handle it later
    + * even though the dentry is no longer on the lru list.
    + */
    + this_cpu_sub(nr_dentry_unused, sb->s_nr_dentry_unused);
    + sb->s_nr_dentry_unused = 0;

     \ /
      Last update: 2011-08-23 10:59    [W:0.023 / U:1.852 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site