From patchwork Mon Jan 28 19:41:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 2058141 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 612403FD1A for ; Mon, 28 Jan 2013 19:49:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752431Ab3A1TtG (ORCPT ); Mon, 28 Jan 2013 14:49:06 -0500 Received: from mail-gh0-f180.google.com ([209.85.160.180]:38152 "EHLO mail-gh0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752181Ab3A1TtF (ORCPT ); Mon, 28 Jan 2013 14:49:05 -0500 Received: by mail-gh0-f180.google.com with SMTP id f13so467096ghb.25 for ; Mon, 28 Jan 2013 11:49:04 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=5Zv/Tq4p+B/iVqhOy+Wtttq3AN6K6kSY5nlacKguEEU=; b=GUiFmhY3mp1qry+7NNA3bl1DUBZ5WoPjJNQofXtbrdtkMkrttFbhB+Xbf+nO1Px4Ui 0aKSPr3sRHQOyjL05xtsG36op8uCpLYglypD2EaRsJa2yIeJRtaEqrgDW/2VeT2fEOSB VPbdlvILGC+xNWM/UufbkGQZ9L4awcaX07hikmDsQNPyTlOaY3LHGEI7RHKRg5hlBqXk S9+F0Sg9x9hb/0y9/GGSqH+KZR4R46IWGARVw9EB+s0nmUPnAcjkuLm/sAVcOMgzlhfv h5zHNyow5fun8A/u6cMqcby2jP5pEo3l0IR8mWsDkEFzNBWssaFfvzUnfK665yRHO+O9 2Jqw== X-Received: by 10.236.133.44 with SMTP id p32mr4587803yhi.17.1359402126721; Mon, 28 Jan 2013 11:42:06 -0800 (PST) Received: from salusa.poochiereds.net (cpe-107-015-113-143.nc.res.rr.com. [107.15.113.143]) by mx.google.com with ESMTPS id i24sm9712873ann.16.2013.01.28.11.42.04 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 28 Jan 2013 11:42:05 -0800 (PST) From: Jeff Layton To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org Subject: [PATCH v1 13/16] nfsd: add recurring workqueue job to clean the cache Date: Mon, 28 Jan 2013 14:41:19 -0500 Message-Id: <1359402082-29195-14-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1359402082-29195-1-git-send-email-jlayton@redhat.com> References: <1359402082-29195-1-git-send-email-jlayton@redhat.com> X-Gm-Message-State: ALoCoQm8beCCOmnFuyAzD+dUgmDeW0wgrvCkGnH43BphvOmhCbu0w5o+ychTnGraqN8u00XZ5wsM Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org It's not sufficient to only clean the cache when requests come in. What if we have a flurry of activity and then the server goes idle? Add a workqueue job that will clean the cache every RC_EXPIRE period. Care is taken to only run this when we expect to have entries expiring. Signed-off-by: Jeff Layton --- fs/nfsd/nfscache.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 6b4693c..896e1c0 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -33,6 +33,7 @@ static inline u32 request_hash(u32 xid) } static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); +static void cache_cleaner_func(struct work_struct *unused); /* * locking for the reply cache: @@ -40,6 +41,7 @@ static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); * Otherwise, it when accessing _prev or _next, the lock must be held. */ static DEFINE_SPINLOCK(cache_lock); +static DECLARE_DELAYED_WORK(cache_cleaner, cache_cleaner_func); static struct svc_cacherep * nfsd_reply_cache_alloc(void) @@ -97,6 +99,8 @@ void nfsd_reply_cache_shutdown(void) { struct svc_cacherep *rp; + cancel_delayed_work_sync(&cache_cleaner); + while (!list_empty(&lru_head)) { rp = list_entry(lru_head.next, struct svc_cacherep, c_lru); nfsd_reply_cache_free_locked(rp); @@ -112,13 +116,15 @@ void nfsd_reply_cache_shutdown(void) } /* - * Move cache entry to end of LRU list + * Move cache entry to end of LRU list, and queue the cleaner to run if it's + * not already scheduled. */ static void lru_put_end(struct svc_cacherep *rp) { rp->c_timestamp = jiffies; list_move_tail(&rp->c_lru, &lru_head); + schedule_delayed_work(&cache_cleaner, RC_EXPIRE); } /* @@ -139,6 +145,42 @@ nfsd_cache_entry_expired(struct svc_cacherep *rp) } /* + * Walk the LRU list and prune off entries that are older than RC_EXPIRE + * if we hit one that isn't old enough, then we can stop the walking. Must + * be called with cache_lock held. + */ +static void +prune_old_cache_entries(void) +{ + struct svc_cacherep *rp, *tmp; + + list_for_each_entry_safe(rp, tmp, &lru_head, c_lru) { + if (!nfsd_cache_entry_expired(rp)) + break; + nfsd_reply_cache_free_locked(rp); + } + + /* + * Conditionally rearm the job. If we cleaned out the list, then + * cancel any pending run (since there won't be any work to do). + * Otherwise, we rearm the job or modify the existing one to run in + * RC_EXPIRE since we know that nothing will expire until then. + */ + if (list_empty(&lru_head)) + cancel_delayed_work(&cache_cleaner); + else + mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE); +} + +static void +cache_cleaner_func(struct work_struct *unused) +{ + spin_lock(&cache_lock); + prune_old_cache_entries(); + spin_unlock(&cache_lock); +} + +/* * Search the request hash for an entry that matches the given rqstp. * Must be called with cache_lock held. Returns the found entry or * NULL on failure. @@ -158,7 +200,6 @@ nfsd_cache_search(struct svc_rqst *rqstp) hlist_for_each_entry(rp, hn, rh, c_hash) { if (xid == rp->c_xid && proc == rp->c_proc && proto == rp->c_prot && vers == rp->c_vers && - !nfsd_cache_entry_expired(rp) && rpc_cmp_addr(svc_addr(rqstp), (struct sockaddr *)&rp->c_addr) && rpc_get_port(svc_addr(rqstp)) == rpc_get_port((struct sockaddr *)&rp->c_addr)) return rp; @@ -202,8 +243,11 @@ nfsd_cache_lookup(struct svc_rqst *rqstp) */ if (!list_empty(&lru_head)) { rp = list_first_entry(&lru_head, struct svc_cacherep, c_lru); - if (nfsd_cache_entry_expired(rp)) + if (nfsd_cache_entry_expired(rp)) { + lru_put_end(rp); + prune_old_cache_entries(); goto setup_entry; + } } spin_unlock(&cache_lock);