From patchwork Mon Feb 4 13:18:05 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 2091861 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 E7B263FD56 for ; Mon, 4 Feb 2013 13:18:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755198Ab3BDNS0 (ORCPT ); Mon, 4 Feb 2013 08:18:26 -0500 Received: from mail-ye0-f176.google.com ([209.85.213.176]:51207 "EHLO mail-ye0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754819Ab3BDNSZ (ORCPT ); Mon, 4 Feb 2013 08:18:25 -0500 Received: by mail-ye0-f176.google.com with SMTP id m1so1471407yen.7 for ; Mon, 04 Feb 2013 05:18:25 -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=x/PTnpBuxSaHmC58WhgKEtMkdPCuIV+6bC7/3Xx7n2I=; b=emwiCCbxSC8YK/skIotVJjHmHb20VZUDIPICLkt/a99Q0sgervylVLFmXMli/O3xjA wn9qdGqjk8rLmjLZqMsE7br22oeA5PlfhYgHPnMLJprHyfnJ8S8N5btklZxDSIR7XbUv 7/PbiGCKIW3MQH2OWQSA2yIhv/Oc7PXAmhK4017EnlhY2BcFPDzfwhyfWyZafWZmxIan bTHBS0YAMlIE6ObSzWQSKUQjFfTo3iCBruvI558DnCfVW35gPncZMbThCHrfJLz6/xY4 PWaT/wFX0Ub1TSV2Lvz+PHjsfl9QCAjmqln1/qKyFpudm2MWhn0UFxuevEpnYeSwG2lt AlQg== X-Received: by 10.100.246.14 with SMTP id t14mr5664118anh.66.1359983904892; Mon, 04 Feb 2013 05:18:24 -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 d80sm980595yhg.4.2013.02.04.05.18.22 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 04 Feb 2013 05:18:23 -0800 (PST) From: Jeff Layton To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 6/8] nfsd: add recurring workqueue job to clean the cache Date: Mon, 4 Feb 2013 08:18:05 -0500 Message-Id: <1359983887-28535-7-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1359983887-28535-1-git-send-email-jlayton@redhat.com> References: <1359983887-28535-1-git-send-email-jlayton@redhat.com> X-Gm-Message-State: ALoCoQlZEZViSO/3mDhl4qrX7LoCGnQWvCfX8aByqGIFwOxXt6mnj/+CrMfh8oFJswK9W8toiPxg 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 e8ea785..d7b088b 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -36,6 +36,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: @@ -43,6 +44,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); /* * Put a cap on the size of the DRC based on the amount of available @@ -131,6 +133,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); @@ -146,13 +150,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); } /* @@ -173,6 +179,42 @@ nfsd_cache_entry_expired(struct svc_cacherep *rp) } /* + * Walk the LRU list and prune off entries that are older than RC_EXPIRE. + * Also prune the oldest ones when the total exceeds the max number of entries. + */ +static void +prune_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) && + num_drc_entries <= max_drc_entries) + 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 just ran the pruner. + */ + 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_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. @@ -192,7 +234,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; @@ -234,8 +275,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) || - num_drc_entries >= max_drc_entries) + num_drc_entries >= max_drc_entries) { + lru_put_end(rp); + prune_cache_entries(); goto setup_entry; + } } spin_unlock(&cache_lock);