aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Mackall <mpm@selenic.com>2008-02-05 01:29:06 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:17 -0500
commit304daa8132a95e998b6716d4b7bd8bd76aa152b2 (patch)
tree21f37f8eb40518b3300b5c0967cf3867c7f18aae
parent161f47bf41c5ece90ac53cbb6a4cb9bf74ce0ef6 (diff)
maps4: add /proc/kpageflags interface
This makes a subset of physical page flags available to userspace. Together with /proc/pid/kpagemap, this allows tracking of a wide variety of VM behaviors. Exported flags are decoupled from the kernel's internal flags. This allows us to reorder flag bits, and synthesize any bits that get redefined in terms of other bits. [akpm@linux-foundation.org: remove unneeded access_ok()] [akpm@linux-foundation.org: s/0/NULL/] Signed-off-by: Matt Mackall <mpm@selenic.com> Cc: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/proc_misc.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 19b69f931bef..fd751ea37fce 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -699,7 +699,10 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
699 return -EIO; 699 return -EIO;
700 700
701 while (count > 0) { 701 while (count > 0) {
702 ppage = pfn_to_page(pfn++); 702 ppage = NULL;
703 if (pfn_valid(pfn))
704 ppage = pfn_to_page(pfn);
705 pfn++;
703 if (!ppage) 706 if (!ppage)
704 pcount = 0; 707 pcount = 0;
705 else 708 else
@@ -724,6 +727,84 @@ static struct file_operations proc_kpagecount_operations = {
724 .read = kpagecount_read, 727 .read = kpagecount_read,
725}; 728};
726 729
730/* /proc/kpageflags - an array exposing page flags
731 *
732 * Each entry is a u64 representing the corresponding
733 * physical page flags.
734 */
735
736/* These macros are used to decouple internal flags from exported ones */
737
738#define KPF_LOCKED 0
739#define KPF_ERROR 1
740#define KPF_REFERENCED 2
741#define KPF_UPTODATE 3
742#define KPF_DIRTY 4
743#define KPF_LRU 5
744#define KPF_ACTIVE 6
745#define KPF_SLAB 7
746#define KPF_WRITEBACK 8
747#define KPF_RECLAIM 9
748#define KPF_BUDDY 10
749
750#define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos)
751
752static ssize_t kpageflags_read(struct file *file, char __user *buf,
753 size_t count, loff_t *ppos)
754{
755 u64 __user *out = (u64 __user *)buf;
756 struct page *ppage;
757 unsigned long src = *ppos;
758 unsigned long pfn;
759 ssize_t ret = 0;
760 u64 kflags, uflags;
761
762 pfn = src / KPMSIZE;
763 count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
764 if (src & KPMMASK || count & KPMMASK)
765 return -EIO;
766
767 while (count > 0) {
768 ppage = NULL;
769 if (pfn_valid(pfn))
770 ppage = pfn_to_page(pfn);
771 pfn++;
772 if (!ppage)
773 kflags = 0;
774 else
775 kflags = ppage->flags;
776
777 uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) |
778 kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
779 kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
780 kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
781 kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) |
782 kpf_copy_bit(kflags, KPF_LRU, PG_lru) |
783 kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) |
784 kpf_copy_bit(kflags, KPF_SLAB, PG_slab) |
785 kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) |
786 kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) |
787 kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy);
788
789 if (put_user(uflags, out++)) {
790 ret = -EFAULT;
791 break;
792 }
793
794 count -= KPMSIZE;
795 }
796
797 *ppos += (char __user *)out - buf;
798 if (!ret)
799 ret = (char __user *)out - buf;
800 return ret;
801}
802
803static struct file_operations proc_kpageflags_operations = {
804 .llseek = mem_lseek,
805 .read = kpageflags_read,
806};
807
727struct proc_dir_entry *proc_root_kcore; 808struct proc_dir_entry *proc_root_kcore;
728 809
729void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) 810void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
@@ -805,6 +886,7 @@ void __init proc_misc_init(void)
805 } 886 }
806#endif 887#endif
807 create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations); 888 create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations);
889 create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations);
808#ifdef CONFIG_PROC_VMCORE 890#ifdef CONFIG_PROC_VMCORE
809 proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); 891 proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
810 if (proc_vmcore) 892 if (proc_vmcore)