diff mbox

[05/12] vrange: Support file based shared volatile ranges

Message ID 1367605636-18284-6-git-send-email-john.stultz@linaro.org
State Superseded
Headers show

Commit Message

John Stultz May 3, 2013, 6:27 p.m. UTC
Extend vrange syscall to properly support VRANGE_MODE_SHARED
behavior on file pages.

Signed-off-by: John Stultz <john.stultz@linaro.org>
---
 fs/file_table.c                        |  5 ++
 fs/inode.c                             |  2 +
 include/linux/fs.h                     |  2 +
 include/linux/vrange.h                 |  1 +
 include/uapi/asm-generic/mman-common.h |  2 +
 mm/vrange.c                            | 92 ++++++++++++++++++++++++++++++++--
 6 files changed, 99 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/fs/file_table.c b/fs/file_table.c
index cd4d87a..94e2cd3 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -26,6 +26,7 @@ 
 #include <linux/hardirq.h>
 #include <linux/task_work.h>
 #include <linux/ima.h>
+#include <linux/vrange.h>
 
 #include <linux/atomic.h>
 
@@ -244,6 +245,10 @@  static void __fput(struct file *file)
 			file->f_op->fasync(-1, file, 0);
 	}
 	ima_file_free(file);
+
+	/* drop all vranges on last close */
+	vrange_root_cleanup(&inode->i_mapping->vroot);
+
 	if (file->f_op && file->f_op->release)
 		file->f_op->release(inode, file);
 	security_file_free(file);
diff --git a/fs/inode.c b/fs/inode.c
index a898b3d..7171313 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -17,6 +17,7 @@ 
 #include <linux/prefetch.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
+#include <linux/vrange.h>
 #include "internal.h"
 
 /*
@@ -350,6 +351,7 @@  void address_space_init_once(struct address_space *mapping)
 	spin_lock_init(&mapping->private_lock);
 	mapping->i_mmap = RB_ROOT;
 	INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
+	vrange_root_init(&mapping->vroot, VRANGE_FILE);
 }
 EXPORT_SYMBOL(address_space_init_once);
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2c28271..6f86c7c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -27,6 +27,7 @@ 
 #include <linux/lockdep.h>
 #include <linux/percpu-rwsem.h>
 #include <linux/blk_types.h>
+#include <linux/vrange_types.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -411,6 +412,7 @@  struct address_space {
 	struct rb_root		i_mmap;		/* tree of private and shared mappings */
 	struct list_head	i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
 	struct mutex		i_mmap_mutex;	/* protect tree, count, list */
+	struct vrange_root	vroot;
 	/* Protected by tree_lock together with the radix tree */
 	unsigned long		nrpages;	/* number of total pages */
 	pgoff_t			writeback_index;/* writeback starts here */
diff --git a/include/linux/vrange.h b/include/linux/vrange.h
index 4424b8d..38ca5d4 100644
--- a/include/linux/vrange.h
+++ b/include/linux/vrange.h
@@ -3,6 +3,7 @@ 
 
 #include <linux/vrange_types.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
 
 #define vrange_entry(ptr) \
 	container_of(ptr, struct vrange, node.rb)
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 9be120b..60cc65b 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -69,4 +69,6 @@ 
 #define VRANGE_VOLATILE		0	/* unpin pages so VM can discard them */
 #define VRANGE_NONVOLATILE	1	/* pin pages so VM can't discard them */
 
+#define VRANGE_MODE_SHARED	0x1	/* Volatility is shared on files */
+
 #endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff --git a/mm/vrange.c b/mm/vrange.c
index 4949152..800287d 100644
--- a/mm/vrange.c
+++ b/mm/vrange.c
@@ -6,6 +6,7 @@ 
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
+#include <linux/file.h>
 
 static struct kmem_cache *vrange_cachep;
 
@@ -235,6 +236,75 @@  static int vrange_private(struct mm_struct *mm,
 	return end-start;
 }
 
+static int vrange_shared(struct mm_struct *mm,
+			unsigned long start, unsigned long end,
+			int mode, int *purged)
+{
+	struct vm_area_struct *vma;
+	int count = 0, ret = 0, orig_start = start;
+
+	down_write(&mm->mmap_sem);
+
+	vma = find_vma(mm, start);
+	for (;;) {
+		struct vrange_root *vroot;
+		unsigned long tmp, vstart, vend;
+
+		if (!vma)
+			goto out;
+
+		/* make sure start is at the front of the current vma*/
+		if (start < vma->vm_start) {
+			start = vma->vm_start;
+			if (start >= end)
+				goto out;
+		}
+
+		/* bound tmp to closer of vm_end & end */
+		tmp = vma->vm_end;
+		if (end < tmp)
+			tmp = end;
+
+		if (vma->vm_file) {
+			/* Convert to file relative offsets */
+			vroot = &vma->vm_file->f_mapping->vroot;
+			vstart = vma->vm_pgoff + start - vma->vm_start;
+			vend = vma->vm_pgoff + tmp - vma->vm_start;
+		} else {
+			vroot = &mm->vroot;
+			vstart = start;
+			vend = tmp;
+		}
+
+		/* mark or unmark */
+		if (mode == VRANGE_VOLATILE)
+			ret = vrange_add(vroot, vstart, vend - 1);
+		else if (mode == VRANGE_NONVOLATILE)
+			ret = vrange_remove(vroot, vstart, vend - 1, purged);
+
+		if (ret)
+			goto out;
+
+		/* update count to distance covered so far*/
+		count = tmp - orig_start;
+
+		/* move start up to the end of the vma*/
+		start = vma->vm_end;
+		if (start >= end)
+			goto out;
+		/* move to the next vma */
+		vma = vma->vm_next;
+	}
+out:
+	up_write(&mm->mmap_sem);
+
+	/* report bytes successfully marked, even if we're exiting on error */
+	if (count)
+		return count;
+
+	return ret;
+}
+
 /*
  * The vrange(2) system call.
  *
@@ -250,7 +320,15 @@  static int vrange_private(struct mm_struct *mm,
  *  VRANGE_NONVOLATILE - Removes any volatile hints previous specified in that
  *		range.
  *
- * behavior values (bitflags): None yet supported.
+ * behavior values (bitflags):
+ * VRANGE_MODE_SHARED - By default, all volatile ranges are private to the
+ *		process. Thus no pages will be purged unless all processes
+ *		that have that page mapped agree that it is volatile.
+ *		The VRANGE_MODE_SHARED flag allows the volatility to be shared
+ *		with any other process mapping those files in a shared fasion
+ *		Thus if any process marks a page as volatile, it can be purged
+ *		from any other process that maps that file (similar to the
+ *		MAP_SHARED semantics for mmap).
  *
  * purged ptr:
  *  Returns 1 if any page in the range being marked nonvolatile has been purged.
@@ -269,8 +347,8 @@  SYSCALL_DEFINE5(vrange, unsigned long, start,
 	struct mm_struct *mm = current->mm;
 	int ret = -EINVAL;
 
-	/* We don't yet support any behavior modes */
-	if (behavior)
+	/* We only support SHARED behavior mode */
+	if (behavior & ~VRANGE_MODE_SHARED)
 		return -ENOTSUPP;
 
 	if (start & ~PAGE_MASK)
@@ -287,8 +365,12 @@  SYSCALL_DEFINE5(vrange, unsigned long, start,
 	if (start >= TASK_SIZE)
 		goto out;
 
-	ret = vrange_private(mm, start, end, mode, purged);
-
+	if (behavior & VRANGE_MODE_SHARED)
+		ret = vrange_shared(mm, start, end, mode, purged);
+	else
+		ret = vrange_private(mm, start, end, mode, purged);
 out:
 	return ret;
 }
+
+