From patchwork Mon Jan 3 20:55:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "J. Bruce Fields" X-Patchwork-Id: 449061 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p03KuXCx007033 for ; Mon, 3 Jan 2011 20:56:33 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752623Ab1ACU4c (ORCPT ); Mon, 3 Jan 2011 15:56:32 -0500 Received: from fieldses.org ([174.143.236.118]:42409 "EHLO fieldses.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754239Ab1ACUzR (ORCPT ); Mon, 3 Jan 2011 15:55:17 -0500 Received: from bfields by fieldses.org with local (Exim 4.72) (envelope-from ) id 1PZrQx-0005y5-Dp; Mon, 03 Jan 2011 15:55:15 -0500 Date: Mon, 3 Jan 2011 15:55:14 -0500 From: "J. Bruce Fields" To: Neil Brown Cc: linux-nfs@vger.kernel.org Subject: Re: [PATCH] svcrpc: modifying positive sunrpc cache entries is racy Message-ID: <20110103205514.GB18056@fieldses.org> References: <20101229204752.GC12218@fieldses.org> <20101229205942.GD12218@fieldses.org> <20101230121940.3f48223a@notabene.brown> <20101230015719.GA27614@fieldses.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20101230015719.GA27614@fieldses.org> User-Agent: Mutt/1.5.20 (2009-06-14) Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Mon, 03 Jan 2011 20:56:34 +0000 (UTC) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 0d6002f..2105b40 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -200,8 +200,9 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) return cd->cache_upcall(cd, h); } -static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) +static int __cache_is_valid(struct cache_detail *detail, struct cache_head *h) { + if (!test_bit(CACHE_VALID, &h->flags)) return -EAGAIN; else { @@ -213,6 +214,33 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head } } +static int cache_is_valid(struct cache_detail *detail, struct cache_head *h) +{ + int rv; + + read_lock(&detail->hash_lock); + rv = __cache_is_valid(detail, h); + read_unlock(&detail->hash_lock); + return rv; +} + +static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h) +{ + int rv; + + write_lock(&detail->hash_lock); + rv = __cache_is_valid(detail, h); + if (rv != -EAGAIN) { + write_unlock(&detail->hash_lock); + return rv; + } + set_bit(CACHE_NEGATIVE, &h->flags); + cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); + write_unlock(&detail->hash_lock); + cache_fresh_unlocked(h, detail); + return -ENOENT; +} + /* * This is the generic cache management routine for all * the authentication caches. @@ -251,14 +279,8 @@ int cache_check(struct cache_detail *detail, case -EINVAL: clear_bit(CACHE_PENDING, &h->flags); cache_revisit_request(h); - if (rv == -EAGAIN) { - set_bit(CACHE_NEGATIVE, &h->flags); - cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); - cache_fresh_unlocked(h, detail); - rv = -ENOENT; - } + rv = try_to_negate_entry(detail, h); break; - case -EAGAIN: clear_bit(CACHE_PENDING, &h->flags); cache_revisit_request(h);