From patchwork Fri May 25 19:17:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 8984 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id E159C23F04 for ; Fri, 25 May 2012 19:18:34 +0000 (UTC) Received: from mail-yw0-f52.google.com (mail-yw0-f52.google.com [209.85.213.52]) by fiordland.canonical.com (Postfix) with ESMTP id 9B155A181F7 for ; Fri, 25 May 2012 19:18:34 +0000 (UTC) Received: by yhpp61 with SMTP id p61so1063127yhp.11 for ; Fri, 25 May 2012 12:18:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-content-scanned:x-cbid:x-gm-message-state; bh=n87A42vAPBAUJU9JIzEkIYP6fRaT9xaSfRjFDWmQ0GU=; b=SQVXgfISnL2NflN6dbAPWlCC9+vHOgPHvB5eA4imfZCtQNUSAwAs/xugjEasGDlF9B kti4vup4MKwBoT3xZcsZBX2Va4wQlMQBK3pdrKJVg6BuSaeS9WnQ/jaWgYfef+tt8Avc AUG9cQQwS/u4fkcJe9FobD1QJ5rMA7/haOl2It3sFNZDUe8A9YLz8njOUqBYSUA7TQE7 CT4XWDWHzN1BZ5Bk0kDr46WqqMoyiwmm0gQkqcJ99/dfJSYFtWzQhVh/lvIdO+cCLtTT rFtLvzbjrwdl6f4BXA3y2QPSdQ5ZllXXlN8DCZtFbUZr+3VZYoDYvM7tRQNBpp/mBHBA ZJog== Received: by 10.50.222.202 with SMTP id qo10mr157443igc.0.1337973513931; Fri, 25 May 2012 12:18:33 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp42725ibb; Fri, 25 May 2012 12:18:33 -0700 (PDT) Received: by 10.50.140.5 with SMTP id rc5mr87095igb.40.1337973513379; Fri, 25 May 2012 12:18:33 -0700 (PDT) Received: from e7.ny.us.ibm.com (e7.ny.us.ibm.com. [32.97.182.137]) by mx.google.com with ESMTPS id ex6si26062526igc.22.2012.05.25.12.18.33 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 25 May 2012 12:18:33 -0700 (PDT) Received-SPF: pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.137 as permitted sender) client-ip=32.97.182.137; Authentication-Results: mx.google.com; spf=pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.137 as permitted sender) smtp.mail=jstultz@us.ibm.com Received: from /spool/local by e7.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 25 May 2012 15:18:30 -0400 Received: from d01dlp02.pok.ibm.com (9.56.224.85) by e7.ny.us.ibm.com (192.168.1.107) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 25 May 2012 15:17:52 -0400 Received: from d01relay05.pok.ibm.com (d01relay05.pok.ibm.com [9.56.227.237]) by d01dlp02.pok.ibm.com (Postfix) with ESMTP id 28EB36E804F; Fri, 25 May 2012 15:17:52 -0400 (EDT) Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay05.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q4PJHpYF112570; Fri, 25 May 2012 15:17:51 -0400 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q4PJHoDN009437; Fri, 25 May 2012 15:17:51 -0400 Received: from kernel.beaverton.ibm.com (kernel.beaverton.ibm.com [9.47.67.96]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q4PJHlFR009090; Fri, 25 May 2012 15:17:47 -0400 Received: by kernel.beaverton.ibm.com (Postfix, from userid 1056) id 40497C0625; Fri, 25 May 2012 12:17:46 -0700 (PDT) From: John Stultz To: LKML Cc: John Stultz , Andrew Morton , Android Kernel Team , Robert Love , Mel Gorman , Hugh Dickins , Dave Hansen , Rik van Riel , Dmitry Adamushko , Dave Chinner , Neil Brown , Andrea Righi , "Aneesh Kumar K.V" , Taras Glek , Mike Hommey Subject: [PATCH 4/4] [RFC] tmpfs: Add FALLOC_FL_MARK_VOLATILE/UNMARK_VOLATILE handlers Date: Fri, 25 May 2012 12:17:36 -0700 Message-Id: <1337973456-19533-5-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.3.2.146.gca209 In-Reply-To: <1337973456-19533-1-git-send-email-john.stultz@linaro.org> References: <1337973456-19533-1-git-send-email-john.stultz@linaro.org> X-Content-Scanned: Fidelis XPS MAILER x-cbid: 12052519-5806-0000-0000-000015919100 X-Gm-Message-State: ALoCoQmCQDeaXGjeeKWBU0N/WZ4Em+sm0ddugeOTx8oDtcuMOK0yYeSMVlo8D9qJm/44+tTOaA5/ This patch enables FALLOC_FL_MARK_VOLATILE/UNMARK_VOLATILE functionality for tmpfs making use of the volatile range management code. Conceptually, FALLOC_FL_MARK_VOLATILE is like a delayed FALLOC_FL_PUNCH_HOLE. This allows applications that have data caches that can be re-created to tell the kernel that some memory contains data that is useful in the future, but can be recreated if needed, so if the kernel needs, it can zap the memory without having to swap it out. In use, applications use FALLOC_FL_MARK_VOLATILE to mark page ranges as volatile when they are not in use. Then later if they wants to reuse the data, they use FALLOC_FL_UNMARK_VOLATILE, which will return an error if the data has been purged. This is very much influenced by the Android Ashmem interface by Robert Love so credits to him and the Android developers. In many cases the code & logic come directly from the ashmem patch. The intent of this patch is to allow for ashmem-like behavior, but embeds the idea a little deeper into the VM code. This is a reworked version of the fadvise volatile idea submitted earlier to the list. Thanks to Dave Chinner for suggesting to rework the idea in this fashion. Also thanks to Dmitry Adamushko for continued review and bug reporting, and Dave Hansen for help with the original design and mentoring me in the VM code. CC: Andrew Morton CC: Android Kernel Team CC: Robert Love CC: Mel Gorman CC: Hugh Dickins CC: Dave Hansen CC: Rik van Riel CC: Dmitry Adamushko CC: Dave Chinner CC: Neil Brown CC: Andrea Righi CC: Aneesh Kumar K.V CC: Taras Glek CC: Mike Hommey Signed-off-by: John Stultz --- fs/open.c | 3 +- include/linux/falloc.h | 7 ++- mm/shmem.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/fs/open.c b/fs/open.c index d543012..448ed5a 100644 --- a/fs/open.c +++ b/fs/open.c @@ -223,7 +223,8 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) return -EINVAL; /* Return error if mode is not supported */ - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | + FALLOC_FL_MARK_VOLATILE | FALLOC_FL_UNMARK_VOLATILE)) return -EOPNOTSUPP; /* Punch hole must have keep size set */ diff --git a/include/linux/falloc.h b/include/linux/falloc.h index 73e0b62..3e47ad5 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h @@ -1,9 +1,10 @@ #ifndef _FALLOC_H_ #define _FALLOC_H_ -#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ -#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ - +#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ +#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ +#define FALLOC_FL_MARK_VOLATILE 0x04 /* mark range volatile */ +#define FALLOC_FL_UNMARK_VOLATILE 0x08 /* mark range non-volatile */ #ifdef __KERNEL__ /* diff --git a/mm/shmem.c b/mm/shmem.c index 9b1c6b4..a0911ba 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -64,6 +64,7 @@ static struct vfsmount *shm_mnt; #include #include #include +#include #include #include @@ -594,11 +595,109 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) return error; } +static DEFINE_VOLATILE_FS_HEAD(shmem_volatile_head); + +static int shmem_mark_volatile(struct inode *inode, loff_t offset, loff_t len) +{ + loff_t lstart, lend; + int ret; + + lstart = offset >> PAGE_CACHE_SHIFT; + lend = (offset+len) >> PAGE_CACHE_SHIFT; + + volatile_range_lock(&shmem_volatile_head); + ret = volatile_range_add(&shmem_volatile_head, &inode->i_data, + lstart, lend); + if (ret > 0) { /* immdiately purge */ + shmem_truncate_range(inode, lstart<> PAGE_CACHE_SHIFT; + lend = (offset+len) >> PAGE_CACHE_SHIFT; + + volatile_range_lock(&shmem_volatile_head); + ret = volatile_range_remove(&shmem_volatile_head, + &inode->i_data, + lstart, lend); + volatile_range_unlock(&shmem_volatile_head); + + return ret; +} + +static void shmem_clear_volatile(struct inode *inode) +{ + volatile_range_lock(&shmem_volatile_head); + volatile_range_clear(&shmem_volatile_head, &inode->i_data); + volatile_range_unlock(&shmem_volatile_head); +} + +static +int shmem_volatile_shrink(struct shrinker *ignored, struct shrink_control *sc) +{ + s64 nr_to_scan = sc->nr_to_scan; + const gfp_t gfp_mask = sc->gfp_mask; + struct address_space *mapping; + loff_t start, end; + int ret; + s64 page_count; + + if (nr_to_scan && !(gfp_mask & __GFP_FS)) + return -1; + + volatile_range_lock(&shmem_volatile_head); + page_count = volatile_range_lru_size(&shmem_volatile_head); + if (!nr_to_scan) + goto out; + + do { + ret = volatile_ranges_get_last_used(&shmem_volatile_head, + &mapping, &start, &end); + if (ret) { + shmem_truncate_range(mapping->host, + start< 0)); + +out: + volatile_range_unlock(&shmem_volatile_head); + + return page_count; +} + +static struct shrinker shmem_volatile_shrinker = { + .shrink = shmem_volatile_shrink, + .seeks = DEFAULT_SEEKS, +}; + +static int __init shmem_shrinker_init(void) +{ + register_shrinker(&shmem_volatile_shrinker); + return 0; +} +arch_initcall(shmem_shrinker_init); + + static void shmem_evict_inode(struct inode *inode) { struct shmem_inode_info *info = SHMEM_I(inode); struct shmem_xattr *xattr, *nxattr; + shmem_clear_volatile(inode); + if (inode->i_mapping->a_ops == &shmem_aops) { shmem_unacct_size(info->flags, inode->i_size); inode->i_size = 0; @@ -1501,10 +1600,18 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, shmem_truncate_range(inode, offset, offset + len - 1); /* No need to unmap again: hole-punching leaves COWed pages */ error = 0; + } else if (mode & FALLOC_FL_MARK_VOLATILE) { + /* Mark pages volatile, sort of delayed hole punching */ + error = shmem_mark_volatile(inode, offset, len); + } else if (mode & FALLOC_FL_UNMARK_VOLATILE) { + /* Mark pages non-volatile, return error if pages were purged */ + error = shmem_unmark_volatile(inode, offset, len); } mutex_unlock(&inode->i_mutex); return error; + + } static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)