[PATCH 08/19] mm/shmem: expose driver overridable huge option

Matthew Auld matthew.auld at intel.com
Thu May 11 14:12:21 UTC 2017


In its current form huge-pages through shmemfs are controlled at the
super-block level, and are currently disabled by default, so to enable
huge-pages for a shmem backed gem object we would need to re-mount the
fs with the huge= argument, but for drm the mount is not user visible,
so good luck with that. The other option is the global sysfs knob
shmem_enabled which exposes the same huge= options, with the addition of
DENY and FORCE.

Neither option seems really workable, what we probably want is to able
to control the use of huge-pages at the time of pinning the backing
storage for a particular gem object, and only where it makes sense given
the size of the object. One caveat is when we write into the page cache
prior to pinning the backing storage. I played around with a bunch of
ideas but in the end just settled with driver overridable huge option
embedded in shmem_inode_info. Thoughts?

Signed-off-by: Matthew Auld <matthew.auld at intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Dave Hansen <dave.hansen at intel.com>
Cc: Daniel Vetter <daniel at ffwll.ch>
Cc: Hugh Dickins <hughd at google.com>
Cc: linux-mm at kvack.org
---
 include/linux/shmem_fs.h | 20 ++++++++++++++++++++
 mm/shmem.c               | 37 +++++++++++++++----------------------
 2 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index a7d6bd2a918f..c9cb3b1735c2 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -21,8 +21,28 @@ struct shmem_inode_info {
 	struct shared_policy	policy;		/* NUMA memory alloc policy */
 	struct simple_xattrs	xattrs;		/* list of xattrs */
 	struct inode		vfs_inode;
+	unsigned char		huge;           /* driver override shm_mnt huge option */
 };
 
+/*
+ * Definitions for "huge tmpfs": tmpfs mounted with the huge= option
+ *
+ * SHMEM_HUGE_NEVER:
+ *	disables huge pages for the mount;
+ * SHMEM_HUGE_ALWAYS:
+ *	enables huge pages for the mount;
+ * SHMEM_HUGE_WITHIN_SIZE:
+ *	only allocate huge pages if the page will be fully within i_size,
+ *	also respect fadvise()/madvise() hints;
+ * SHMEM_HUGE_ADVISE:
+ *	only allocate huge pages if requested with fadvise()/madvise();
+ */
+
+#define SHMEM_HUGE_NEVER	0
+#define SHMEM_HUGE_ALWAYS	1
+#define SHMEM_HUGE_WITHIN_SIZE	2
+#define SHMEM_HUGE_ADVISE	3
+
 struct shmem_sb_info {
 	unsigned long max_blocks;   /* How many blocks are allowed */
 	struct percpu_counter used_blocks;  /* How many are allocated */
diff --git a/mm/shmem.c b/mm/shmem.c
index e67d6ba4e98e..871a2dd35625 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -346,25 +346,6 @@ static bool shmem_confirm_swap(struct address_space *mapping,
 }
 
 /*
- * Definitions for "huge tmpfs": tmpfs mounted with the huge= option
- *
- * SHMEM_HUGE_NEVER:
- *	disables huge pages for the mount;
- * SHMEM_HUGE_ALWAYS:
- *	enables huge pages for the mount;
- * SHMEM_HUGE_WITHIN_SIZE:
- *	only allocate huge pages if the page will be fully within i_size,
- *	also respect fadvise()/madvise() hints;
- * SHMEM_HUGE_ADVISE:
- *	only allocate huge pages if requested with fadvise()/madvise();
- */
-
-#define SHMEM_HUGE_NEVER	0
-#define SHMEM_HUGE_ALWAYS	1
-#define SHMEM_HUGE_WITHIN_SIZE	2
-#define SHMEM_HUGE_ADVISE	3
-
-/*
  * Special values.
  * Only can be set via /sys/kernel/mm/transparent_hugepage/shmem_enabled:
  *
@@ -1715,6 +1696,8 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
 		swap_free(swap);
 
 	} else {
+		unsigned char sbinfo_huge = sbinfo->huge;
+
 		if (vma && userfaultfd_missing(vma)) {
 			*fault_type = handle_userfault(vmf, VM_UFFD_MISSING);
 			return 0;
@@ -1727,7 +1710,10 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
 			goto alloc_nohuge;
 		if (shmem_huge == SHMEM_HUGE_FORCE)
 			goto alloc_huge;
-		switch (sbinfo->huge) {
+		/* driver override the kernel mounted shm_mnt sbinfo->huge */
+		if (info->huge)
+			sbinfo_huge = info->huge;
+		switch (sbinfo_huge) {
 			loff_t i_size;
 			pgoff_t off;
 		case SHMEM_HUGE_NEVER:
@@ -2032,10 +2018,13 @@ unsigned long shmem_get_unmapped_area(struct file *file,
 
 	if (shmem_huge != SHMEM_HUGE_FORCE) {
 		struct super_block *sb;
+		unsigned char sbinfo_huge = 0;
 
 		if (file) {
 			VM_BUG_ON(file->f_op != &shmem_file_operations);
 			sb = file_inode(file)->i_sb;
+			/* driver override the kernel mounted shm_mnt sbinfo->huge */
+			sbinfo_huge = SHMEM_I(file_inode(file))->huge;
 		} else {
 			/*
 			 * Called directly from mm/mmap.c, or drivers/char/mem.c
@@ -2045,7 +2034,8 @@ unsigned long shmem_get_unmapped_area(struct file *file,
 				return addr;
 			sb = shm_mnt->mnt_sb;
 		}
-		if (SHMEM_SB(sb)->huge == SHMEM_HUGE_NEVER)
+		if (SHMEM_SB(sb)->huge == SHMEM_HUGE_NEVER &&
+		    sbinfo_huge == SHMEM_HUGE_NEVER)
 			return addr;
 	}
 
@@ -4031,6 +4021,7 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
 {
 	struct inode *inode = file_inode(vma->vm_file);
 	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+	unsigned char sbinfo_huge = sbinfo->huge;
 	loff_t i_size;
 	pgoff_t off;
 
@@ -4038,7 +4029,9 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
 		return true;
 	if (shmem_huge == SHMEM_HUGE_DENY)
 		return false;
-	switch (sbinfo->huge) {
+	if (SHMEM_I(inode)->huge)
+		sbinfo_huge = SHMEM_I(inode)->huge;
+	switch (sbinfo_huge) {
 		case SHMEM_HUGE_NEVER:
 			return false;
 		case SHMEM_HUGE_ALWAYS:
-- 
2.9.3



More information about the Intel-gfx-trybot mailing list