From patchwork Wed Dec 1 20:10:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 372411 X-Patchwork-Delegate: Trond.Myklebust@netapp.com 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 oB1KAuwM024673 for ; Wed, 1 Dec 2010 20:10:56 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756568Ab0LAUKy (ORCPT ); Wed, 1 Dec 2010 15:10:54 -0500 Received: from mx2.netapp.com ([216.240.18.37]:9826 "EHLO mx2.netapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756186Ab0LAUKx convert rfc822-to-8bit (ORCPT ); Wed, 1 Dec 2010 15:10:53 -0500 X-IronPort-AV: E=Sophos;i="4.59,284,1288594800"; d="scan'208";a="489663845" Received: from smtp1.corp.netapp.com ([10.57.156.124]) by mx2-out.netapp.com with ESMTP; 01 Dec 2010 12:10:53 -0800 Received: from sacrsexc2-prd.hq.netapp.com (sacrsexc2-prd.hq.netapp.com [10.99.115.28]) by smtp1.corp.netapp.com (8.13.1/8.13.1/NTAP-1.6) with ESMTP id oB1KApCm018201; Wed, 1 Dec 2010 12:10:53 -0800 (PST) Received: from SACMVEXC2-PRD.hq.netapp.com ([10.99.115.17]) by sacrsexc2-prd.hq.netapp.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 1 Dec 2010 12:10:52 -0800 Received: from 10.58.52.59 ([10.58.52.59]) by SACMVEXC2-PRD.hq.netapp.com ([10.99.115.16]) with Microsoft Exchange Server HTTP-DAV ; Wed, 1 Dec 2010 20:10:51 +0000 Received: from heimdal.trondhjem.org by SACMVEXC2-PRD.hq.netapp.com; 01 Dec 2010 15:10:51 -0500 Subject: Re: [PATCH v2 3/3] NFS: Fix a memory leak in nfs_readdir From: Trond Myklebust To: Linus Torvalds Cc: Nick Bowler , Linux Kernel Mailing List , linux-nfs@vger.kernel.org, Andrew Morton , Hugh Dickins , Rik van Riel , Christoph Hellwig , Al Viro In-Reply-To: References: <1291217804-11257-1-git-send-email-Trond.Myklebust@netapp.com> <1291217804-11257-2-git-send-email-Trond.Myklebust@netapp.com> <20101201150428.GA2879@elliptictech.com> <1291217804-11257-3-git-send-email-Trond.Myklebust@netapp.com> <1291217804-11257-4-git-send-email-Trond.Myklebust@netapp.com> <1291229669.6609.24.camel@heimdal.trondhjem.org> Organization: NetApp Inc Date: Wed, 01 Dec 2010 15:10:50 -0500 Message-ID: <1291234251.6609.39.camel@heimdal.trondhjem.org> Mime-Version: 1.0 X-Mailer: Evolution 2.32.1 (2.32.1-1.fc14) X-OriginalArrivalTime: 01 Dec 2010 20:10:52.0350 (UTC) FILETIME=[DA9355E0:01CB9193] 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]); Wed, 01 Dec 2010 20:10:56 +0000 (UTC) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index a91f308..06d6b71 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -173,6 +173,7 @@ prototypes: sector_t (*bmap)(struct address_space *, sector_t); int (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, int); + void (*freepage)(struct page *); int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); int (*launder_page) (struct page *); @@ -193,6 +194,7 @@ perform_write: no n/a yes bmap: no invalidatepage: no yes releasepage: no yes +freepage: no yes direct_IO: no launder_page: no yes @@ -288,6 +290,9 @@ buffers from the page in preparation for freeing it. It returns zero to indicate that the buffers are (or may be) freeable. If ->releasepage is zero, the kernel assumes that the fs has no private interest in the buffers. + ->freepage() is called when the kernel is done dropping the page +from the page cache. + ->launder_page() may be called prior to releasing a page if it is still found to be dirty. It returns zero if the page was successfully cleaned, or an error value if not. Note that in order to prevent the page diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index ed7e5ef..76de6fd 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -534,6 +534,7 @@ struct address_space_operations { sector_t (*bmap)(struct address_space *, sector_t); int (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, int); + void (*freepage)(struct page *); ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); struct page* (*get_xip_page)(struct address_space *, sector_t, @@ -679,6 +680,10 @@ struct address_space_operations { need to ensure this. Possibly it can clear the PageUptodate bit if it cannot free private data yet. + freepage: freepage is called once the page is no longer visible in + the page cache in order to allow the cleanup of any private + data. + direct_IO: called by the generic read/write routines to perform direct_IO - that is IO requests which bypass the page cache and transfer data directly between the storage and the diff --git a/include/linux/fs.h b/include/linux/fs.h index c9e06cc..090f0ea 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -602,6 +602,7 @@ struct address_space_operations { sector_t (*bmap)(struct address_space *, sector_t); void (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, gfp_t); + void (*freepage)(struct page *); ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); int (*get_xip_mem)(struct address_space *, pgoff_t, int, diff --git a/mm/truncate.c b/mm/truncate.c index ba887bf..76ab2a8 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -108,6 +108,10 @@ truncate_complete_page(struct address_space *mapping, struct page *page) clear_page_mlock(page); remove_from_page_cache(page); ClearPageMappedToDisk(page); + + if (mapping->a_ops->freepage) + mapping->a_ops->freepage(page); + page_cache_release(page); /* pagecache ref */ return 0; } @@ -390,6 +394,10 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page) __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); + + if (mapping->a_ops->freepage) + mapping->a_ops->freepage(page); + page_cache_release(page); /* pagecache ref */ return 1; failed: diff --git a/mm/vmscan.c b/mm/vmscan.c index d31d7ce..c6fc55d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -497,6 +497,9 @@ static int __remove_mapping(struct address_space *mapping, struct page *page) __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); + + if (mapping->a_ops->freepage) + mapping->a_ops->freepage(page); } return 1;