From patchwork Fri Aug 16 23:22:10 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Lutomirski X-Patchwork-Id: 267934 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 885122C011E for ; Sat, 17 Aug 2013 10:19:18 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754408Ab3HQATP (ORCPT ); Fri, 16 Aug 2013 20:19:15 -0400 Received: from mail-pa0-f53.google.com ([209.85.220.53]:41654 "EHLO mail-pa0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753957Ab3HQATM (ORCPT ); Fri, 16 Aug 2013 20:19:12 -0400 Received: by mail-pa0-f53.google.com with SMTP id lb1so2433355pab.40 for ; Fri, 16 Aug 2013 17:19:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=6sHYQEA8xLY878js0gDFz8oIB2Z39ZY09ekhNC1TBzY=; b=mogE14bjAYdupb9HUNnDuZc4d9INj9JISDB/n5qFGAVQL/atg8dKfmOmbza9vwLeMl CHd1GgQJlwT5akSAWXbQEMen5gHYBJIZ5B6WldG/5gDl8lEA73Xg0NHV2Fel8ed7gj0M srKmNWIwKzy6/90xzUxMaK4c7TvUxJQ+ervSpE1oClQJ1S92+gU0Nk7qEqTHf3tCWtTB lLdTBzKPfvkxUybZ5LFiXXnm3fKrGuO3QC5ktS5x2hWEDcGbqo5syQwm8nd4zo8ldvl7 zTjExqPuH670KOSvFnZRW1PPZBh3uSJD7ORO+clrGoIYTgu2QplcJ5RqMV/Qc4+7U62W dOcQ== X-Gm-Message-State: ALoCoQlmXEAhkwdPE2Tt2A6EbRCPpnHysPNTenJnJyzkNLhfyLuwTnLNIFYq3PqzO39Ro9cuLFNo X-Received: by 10.68.182.131 with SMTP id ee3mr4055285pbc.71.1376695347363; Fri, 16 Aug 2013 16:22:27 -0700 (PDT) Received: from localhost (50-76-60-73-ip-static.hfc.comcastbusiness.net. [50.76.60.73]) by mx.google.com with ESMTPSA id py4sm103883pbc.14.1969.12.31.16.00.00 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 16 Aug 2013 16:22:26 -0700 (PDT) From: Andy Lutomirski To: linux-kernel@vger.kernel.org Cc: linux-ext4@vger.kernel.org, Dave Chinner , Theodore Ts'o , Dave Hansen , xfs@oss.sgi.com, Jan Kara , Tim Chen , Christoph Hellwig , Andy Lutomirski Subject: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update Date: Fri, 16 Aug 2013 16:22:10 -0700 Message-Id: X-Mailer: git-send-email 1.8.3.1 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 Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping: - The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages. - munmap is called or the mapping is removed when the process exits - msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling. Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this. It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered). This patch does not implement the MS_ASYNC case; that's in the next patch. Signed-off-by: Andy Lutomirski --- include/linux/fs.h | 9 +++++++++ include/linux/writeback.h | 1 + mm/mmap.c | 9 ++++++++- mm/page-writeback.c | 26 ++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 86cf0a4..f224155 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -350,6 +350,15 @@ struct address_space_operations { /* Write back some dirty pages from this mapping. */ int (*writepages)(struct address_space *, struct writeback_control *); + /* + * Userspace expects certain system calls to update cmtime if + * a file has been recently written using a shared vma. In + * cases where cmtime may need to be updated but writepages is + * not called, this is called instead. (Implementations + * should call mapping_test_clear_cmtime.) + */ + void (*flush_cmtime)(struct address_space *); + /* Set a page dirty. Return true if this dirtied it */ int (*set_page_dirty)(struct page *page); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 4e198ca..f6e8261 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -174,6 +174,7 @@ typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc, int generic_writepages(struct address_space *mapping, struct writeback_control *wbc); +void generic_flush_cmtime(struct address_space *mapping); void tag_pages_for_writeback(struct address_space *mapping, pgoff_t start, pgoff_t end); int write_cache_pages(struct address_space *mapping, diff --git a/mm/mmap.c b/mm/mmap.c index 1edbaa3..7ed7700 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1,3 +1,4 @@ + /* * mm/mmap.c * @@ -249,8 +250,14 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) might_sleep(); if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); - if (vma->vm_file) + if (vma->vm_file) { + if ((vma->vm_flags & VM_SHARED) && vma->vm_file->f_mapping) { + struct address_space *mapping = vma->vm_file->f_mapping; + if (mapping->a_ops && mapping->a_ops->flush_cmtime) + mapping->a_ops->flush_cmtime(mapping); + } fput(vma->vm_file); + } mpol_put(vma_policy(vma)); kmem_cache_free(vm_area_cachep, vma); return next; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 3f0c895..9ab8c9e 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1928,6 +1928,18 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc) ret = mapping->a_ops->writepages(mapping, wbc); else ret = generic_writepages(mapping, wbc); + + /* + * ->writepages will call clear_page_dirty_for_io, which may, in turn, + * mark the mapping for deferred cmtime update. As an optimization, + * a filesystem can flush the update at the end of ->writepages + * (possibly avoiding a journal transaction, for example), but, + * for simplicity, let filesystems skip that part and just implement + * ->flush_cmtime. + */ + if (mapping->a_ops->flush_cmtime) + mapping->a_ops->flush_cmtime(mapping); + return ret; } @@ -1970,6 +1982,20 @@ int write_one_page(struct page *page, int wait) } EXPORT_SYMBOL(write_one_page); +/** + * generic_flush_cmtime - perform a deferred cmtime update if needed + * @mapping: address space structure + * + * This is a library function, which implements the flush_cmtime() + * address_space_operation. + */ +void generic_flush_cmtime(struct address_space *mapping) +{ + if (mapping_test_clear_cmtime(mapping)) + inode_update_time_writable(mapping->host); +} +EXPORT_SYMBOL(generic_flush_cmtime); + /* * For address_spaces which do not use buffers nor write back. */