From patchwork Thu Jan 16 01:24:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 311509 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 9AB7A2C009E for ; Thu, 16 Jan 2014 12:25:00 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752204AbaAPBY7 (ORCPT ); Wed, 15 Jan 2014 20:24:59 -0500 Received: from mga02.intel.com ([134.134.136.20]:49044 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750900AbaAPBY6 (ORCPT ); Wed, 15 Jan 2014 20:24:58 -0500 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 15 Jan 2014 17:24:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.95,666,1384329600"; d="scan'208";a="459548173" Received: from unknown (HELO rizzo.int.wil.cx) ([10.255.12.202]) by fmsmga001.fm.intel.com with ESMTP; 15 Jan 2014 17:24:55 -0800 Received: by rizzo.int.wil.cx (Postfix, from userid 1000) id 78AE517213E; Wed, 15 Jan 2014 20:24:55 -0500 (EST) From: Matthew Wilcox To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, linux-ext4@vger.kernel.org Cc: Matthew Wilcox Subject: [PATCH v5 01/22] Fix XIP fault vs truncate race Date: Wed, 15 Jan 2014 20:24:19 -0500 Message-Id: X-Mailer: git-send-email 1.8.5.2 In-Reply-To: References: In-Reply-To: References: Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Pagecache faults recheck i_size after taking the page lock to ensure that the fault didn't race against a truncate. We don't have a page to lock in the XIP case, so use the i_mmap_mutex instead. It is locked in the truncate path in unmap_mapping_range() after updating i_size. So while we hold it in the fault path, we are guaranteed that either i_size has already been updated in the truncate path, or that the truncate will subsequently call zap_page_range_single() and so remove the mapping we have just inserted. There is a window of time in which i_size has been reduced and the thread has a mapping to a page which will be removed from the file, but this is harmless as the page will not be allocated to a different purpose before the thread's access to it is revoked. Signed-off-by: Matthew Wilcox --- mm/filemap_xip.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index d8d9fe3..c8d23e9 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c @@ -260,8 +260,17 @@ again: __xip_unmap(mapping, vmf->pgoff); found: + /* We must recheck i_size under i_mmap_mutex */ + mutex_lock(&mapping->i_mmap_mutex); + size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + if (unlikely(vmf->pgoff >= size)) { + mutex_unlock(&mapping->i_mmap_mutex); + return VM_FAULT_SIGBUS; + } err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, xip_pfn); + mutex_unlock(&mapping->i_mmap_mutex); if (err == -ENOMEM) return VM_FAULT_OOM; /* @@ -285,16 +294,27 @@ found: } if (error != -ENODATA) goto out; + + /* We must recheck i_size under i_mmap_mutex */ + mutex_lock(&mapping->i_mmap_mutex); + size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + if (unlikely(vmf->pgoff >= size)) { + ret = VM_FAULT_SIGBUS; + goto unlock; + } /* not shared and writable, use xip_sparse_page() */ page = xip_sparse_page(); if (!page) - goto out; + goto unlock; err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); if (err == -ENOMEM) - goto out; + goto unlock; ret = VM_FAULT_NOPAGE; +unlock: + mutex_unlock(&mapping->i_mmap_mutex); out: write_seqcount_end(&xip_sparse_seq); mutex_unlock(&xip_sparse_mutex);