aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2013-07-03 18:01:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:26 -0400
commit541c237c0923f567c9c4cabb8a81635baadc713f (patch)
tree5f544cd43acff9e09c6f126f678e2d7c89920bbf
parent0f8975ec4db2c8b5bd111b211292ca9be0feb6b8 (diff)
pagemap: prepare to reuse constant bits with page-shift
In order to reuse bits from pagemap entries gracefully, we leave the entries as is but on pagemap open emit a warning in dmesg, that bits 55-60 are about to change in a couple of releases. Next, if a user issues soft-dirty clear command via the clear_refs file (it was disabled before v3.9) we assume that he's aware of the new pagemap format, note that fact and report the bits in pagemap in the new manner. The "migration strategy" looks like this then: 1. existing users are not affected -- they don't touch soft-dirty feature, thus see old bits in pagemap, but are warned and have time to fix themselves 2. those who use soft-dirty know about new pagemap format 3. some time soon we get rid of any signs of page-shift in pagemap as well as this trick with clear-soft-dirty affecting pagemap format. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Cc: Matt Mackall <mpm@selenic.com> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Cc: Glauber Costa <glommer@parallels.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/vm/pagemap.txt3
-rw-r--r--fs/proc/task_mmu.c35
2 files changed, 36 insertions, 2 deletions
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt
index 7587493c67f1..fd7c3cfddd8e 100644
--- a/Documentation/vm/pagemap.txt
+++ b/Documentation/vm/pagemap.txt
@@ -15,7 +15,8 @@ There are three components to pagemap:
15 * Bits 0-54 page frame number (PFN) if present 15 * Bits 0-54 page frame number (PFN) if present
16 * Bits 0-4 swap type if swapped 16 * Bits 0-4 swap type if swapped
17 * Bits 5-54 swap offset if swapped 17 * Bits 5-54 swap offset if swapped
18 * Bits 55-60 page shift (page size = 1<<page shift) 18 * Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
19 * Bits 56-60 zero
19 * Bit 61 page is file-page or shared-anon 20 * Bit 61 page is file-page or shared-anon
20 * Bit 62 page swapped 21 * Bit 62 page swapped
21 * Bit 63 page present 22 * Bit 63 page present
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index a18e065c1c3e..dbf61f6174f0 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -689,6 +689,23 @@ const struct file_operations proc_tid_smaps_operations = {
689 .release = seq_release_private, 689 .release = seq_release_private,
690}; 690};
691 691
692/*
693 * We do not want to have constant page-shift bits sitting in
694 * pagemap entries and are about to reuse them some time soon.
695 *
696 * Here's the "migration strategy":
697 * 1. when the system boots these bits remain what they are,
698 * but a warning about future change is printed in log;
699 * 2. once anyone clears soft-dirty bits via clear_refs file,
700 * these flag is set to denote, that user is aware of the
701 * new API and those page-shift bits change their meaning.
702 * The respective warning is printed in dmesg;
703 * 3. In a couple of releases we will remove all the mentions
704 * of page-shift in pagemap entries.
705 */
706
707static bool soft_dirty_cleared __read_mostly;
708
692enum clear_refs_types { 709enum clear_refs_types {
693 CLEAR_REFS_ALL = 1, 710 CLEAR_REFS_ALL = 1,
694 CLEAR_REFS_ANON, 711 CLEAR_REFS_ANON,
@@ -778,6 +795,13 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
778 type = (enum clear_refs_types)itype; 795 type = (enum clear_refs_types)itype;
779 if (type < CLEAR_REFS_ALL || type >= CLEAR_REFS_LAST) 796 if (type < CLEAR_REFS_ALL || type >= CLEAR_REFS_LAST)
780 return -EINVAL; 797 return -EINVAL;
798
799 if (type == CLEAR_REFS_SOFT_DIRTY) {
800 soft_dirty_cleared = true;
801 pr_warn_once("The pagemap bits 55-60 has changed their meaning! "
802 "See the linux/Documentation/vm/pagemap.txt for details.\n");
803 }
804
781 task = get_proc_task(file_inode(file)); 805 task = get_proc_task(file_inode(file));
782 if (!task) 806 if (!task)
783 return -ESRCH; 807 return -ESRCH;
@@ -1091,7 +1115,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
1091 if (!count) 1115 if (!count)
1092 goto out_task; 1116 goto out_task;
1093 1117
1094 pm.v2 = false; 1118 pm.v2 = soft_dirty_cleared;
1095 pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); 1119 pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
1096 pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); 1120 pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
1097 ret = -ENOMEM; 1121 ret = -ENOMEM;
@@ -1164,9 +1188,18 @@ out:
1164 return ret; 1188 return ret;
1165} 1189}
1166 1190
1191static int pagemap_open(struct inode *inode, struct file *file)
1192{
1193 pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
1194 "to stop being page-shift some time soon. See the "
1195 "linux/Documentation/vm/pagemap.txt for details.\n");
1196 return 0;
1197}
1198
1167const struct file_operations proc_pagemap_operations = { 1199const struct file_operations proc_pagemap_operations = {
1168 .llseek = mem_lseek, /* borrow this */ 1200 .llseek = mem_lseek, /* borrow this */
1169 .read = pagemap_read, 1201 .read = pagemap_read,
1202 .open = pagemap_open,
1170}; 1203};
1171#endif /* CONFIG_PROC_PAGE_MONITOR */ 1204#endif /* CONFIG_PROC_PAGE_MONITOR */
1172 1205