From patchwork Wed Dec 29 20:47:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "J. Bruce Fields" X-Patchwork-Id: 439881 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 oBUMBEks000490 for ; Thu, 30 Dec 2010 22:11:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752565Ab0L2Ury (ORCPT ); Wed, 29 Dec 2010 15:47:54 -0500 Received: from fieldses.org ([174.143.236.118]:54691 "EHLO fieldses.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752440Ab0L2Ury (ORCPT ); Wed, 29 Dec 2010 15:47:54 -0500 Received: from bfields by fieldses.org with local (Exim 4.72) (envelope-from ) id 1PY2w5-0004UX-9a; Wed, 29 Dec 2010 15:47:53 -0500 Date: Wed, 29 Dec 2010 15:47:52 -0500 To: linux-nfs@vger.kernel.org Cc: Neil Brown Subject: [PATCH] svcrpc: modifying positive sunrpc cache entries is racy Message-ID: <20101229204752.GC12218@fieldses.org> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) From: "J. Bruce Fields" 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]); Thu, 30 Dec 2010 22:11:50 +0000 (UTC) diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index a04ac91..70586ad 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -386,6 +386,21 @@ int auth_unix_forget_old(struct auth_domain *dom) } EXPORT_SYMBOL_GPL(auth_unix_forget_old); +static void auth_unix_invalidate_ip_map(struct cache_detail *cd, struct ip_map *ipm) +{ + struct cache_head *ch; + struct ip_map ip; + + ip.m_client = ipm->m_client; + ip.h.flags = CACHE_NEGATIVE; + ip.h.expiry_time = ipm->h.expiry_time; + ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, + hash_str(ipm->m_class, IP_HASHBITS) ^ + hash_ip6(ipm->m_addr)); + if (ch) + cache_put(ch, cd); +} + struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr) { struct ip_map *ipm; @@ -401,8 +416,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr) return NULL; if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { - if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0) - auth_domain_put(&ipm->m_client->h); + auth_unix_invalidate_ip_map(sn->ip_map_cache, ipm); rv = NULL; } else { rv = &ipm->m_client->h;