]> granicus.if.org Git - procps-ng/commitdiff
library: exploit linux-4.5 resident memory enhancement
authorJim Warner <james.warner@comcast.net>
Wed, 13 Apr 2016 05:00:00 +0000 (00:00 -0500)
committerCraig Small <csmall@dropbear.xyz>
Tue, 7 Jun 2016 10:49:30 +0000 (20:49 +1000)
Since support already exists in the newlib branch this
represents an equivalent master branch implementation,
and this commit message is shared with 2 more patches.

Beginning with linux-4.5, the following new fields are
being added under that /proc/<pid>/status pseudo file:
 . RssAnon - size of resident anonymous memory
 . RssFile - size of resident file mappings
 . RssShmem - size of resident shared memory

p.s. Locked resident memory support was also added but
isn't directly related to the kernel 4.5 enhancements.

p.p.s. Archlinux, Debian-stretch and Fedora-23 already
are currently using a 4.5 linux kernel (as of 6/2/16).

Signed-off-by: Jim Warner <james.warner@comcast.net>
proc/readproc.c
proc/readproc.h

index f5d89cf852d3282d3c36f166047f8d6c177daf50..e06bd0ff8918cc22e3505fc3bd28d6c1c374bb85 100644 (file)
@@ -113,7 +113,7 @@ static inline void free_acquired (proc_t *p, int reuse) {
 ///////////////////////////////////////////////////////////////////////////
 
 typedef struct status_table_struct {
-    unsigned char name[7];        // /proc/*/status field name
+    unsigned char name[8];        // /proc/*/status field name
     unsigned char len;            // name length
 #ifdef LABEL_OFFSET
     long offset;                  // jump address offset
@@ -129,8 +129,11 @@ typedef struct status_table_struct {
 #endif
 #define NUL  {"", 0, 0},
 
+#define GPERF_TABLE_SIZE 128
+
 // Derived from:
 // gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
+// ( --key-positions verified by omission & reported "Computed positions" )
 //
 // Suggested method:
 // Grep this file for "case_", then strip those down to the name.
@@ -144,8 +147,8 @@ typedef struct status_table_struct {
 // the F macro and replacing empty strings with the NUL define.
 //
 // In the status_table_struct watch out for name size (grrr, expanding)
-// and the number of entries (we mask with 63 for now). The table
-// must be padded out to 64 entries, maybe 128 in the future.
+// and the number of entries. Currently, the table is padded to 128
+// entries and we therefore mask with 127.
 
 static void status2proc(char *S, proc_t *restrict P, int is_proc){
     long Threads = 0;
@@ -155,78 +158,76 @@ static void status2proc(char *S, proc_t *restrict P, int is_proc){
   // 128 entries because we trust the kernel to use ASCII names
   static const unsigned char asso[] =
     {
-      64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-      64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-      64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-      64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-      64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-      64, 64, 64, 64, 64, 64, 64, 64, 28, 64,
-      64, 64, 64, 64, 64, 64,  8, 25, 23, 25,
-       6, 25,  0,  3, 64, 64,  3, 64, 25, 64,
-      20,  1,  1,  5,  0, 30,  0,  0, 64, 64,
-      64, 64, 64, 64, 64, 64, 64,  3, 64,  0,
-       0, 18, 64, 10, 64, 10, 64, 64, 64, 20,
-      64, 20,  0, 64, 25, 64,  3, 15, 64,  0,
-      30, 64, 64, 64, 64, 64, 64, 64
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101,   6, 101,
+      101, 101, 101, 101, 101,  45,  55,  25,  31,  50,
+       50,  10,   0,  35, 101, 101,  21, 101,  30, 101,
+       20,  36,   0,   5,   0,  40,   0,   0, 101, 101,
+      101, 101, 101, 101, 101, 101, 101,  30, 101,  15,
+        0,   1, 101,  10, 101,  10, 101, 101, 101,  25,
+      101,  40,   0, 101,   0,  50,   6,  40, 101,   1,
+       35, 101, 101, 101, 101, 101, 101, 101
     };
 
-    static const status_table_struct table[] = {
+    static const status_table_struct table[GPERF_TABLE_SIZE] = {
       F(VmHWM)
-      NUL NUL
-      F(VmLck)
-      NUL
-      F(VmSwap)
+      F(Threads)
+      NUL NUL NUL
       F(VmRSS)
-      NUL
-      F(VmStk)
-      NUL
+      F(VmSwap)
+      NUL NUL NUL
       F(Tgid)
-      F(State)
-      NUL
-      F(VmLib)
-      NUL
+      F(VmStk)
+      NUL NUL NUL
       F(VmSize)
-      F(SigQ)
-      NUL
-      F(SigIgn)
-      NUL
+      F(Gid)
+      NUL NUL NUL
       F(VmPTE)
-      F(FDSize)
-      NUL
-      F(SigBlk)
-      NUL
+      F(VmPeak)
+      NUL NUL NUL
       F(ShdPnd)
-      F(VmData)
-      NUL
-      F(CapInh)
-      NUL
+      F(Pid)
+      NUL NUL NUL
       F(PPid)
-      NUL NUL
-      F(CapBnd)
-      NUL
+      F(VmLib)
+      NUL NUL NUL
       F(SigPnd)
-      NUL NUL
-      F(VmPeak)
-      NUL
+      F(VmLck)
+      NUL NUL NUL
       F(SigCgt)
-      NUL NUL
-      F(Threads)
-      NUL
+      F(State)
+      NUL NUL NUL
       F(CapPrm)
-      NUL NUL
-      F(Pid)
-      NUL
+      F(Uid)
+      NUL NUL NUL
+      F(SigIgn)
+      F(SigQ)
+      NUL NUL NUL
+      F(RssShmem)
+      F(Name)
+      NUL NUL NUL
+      F(CapInh)
+      F(VmData)
+      NUL NUL NUL
+      F(FDSize)
+      NUL NUL NUL NUL
+      F(SigBlk)
+      NUL NUL NUL NUL
       F(CapEff)
-      NUL NUL
-      F(Gid)
-      NUL
+      NUL NUL NUL NUL
+      F(CapBnd)
+      NUL NUL NUL NUL
       F(VmExe)
-      NUL NUL
-      F(Uid)
-      NUL
+      NUL NUL NUL NUL
       F(Groups)
-      NUL NUL
-      F(Name)
+      NUL NUL NUL NUL
+      F(RssAnon)
+      NUL NUL NUL NUL
+      F(RssFile)
     };
 
 #undef F
@@ -248,7 +249,7 @@ ENTER(0x220);
         // examine a field name (hash and compare)
     base:
         if(unlikely(!*S)) break;
-        entry = table[63 & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])];
+        entry = table[(GPERF_TABLE_SIZE -1) & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])];
         colon = strchr(S, ':');
         if(unlikely(!colon)) break;
         if(unlikely(colon[1]!='\t')) break;
@@ -361,6 +362,15 @@ ENTER(0x220);
     case_VmRSS:
         P->vm_rss = strtol(S,&S,10);
         continue;
+    case_RssAnon:       // subset of VmRSS, linux-4.5
+        P->vm_rss_anon = strtol(S,&S,10);
+        continue;
+    case_RssFile:       // subset of VmRSS, linux-4.5
+        P->vm_rss_file = strtol(S,&S,10);
+        continue;
+    case_RssShmem:      // subset of VmRSS, linux-4.5
+        P->vm_rss_shared = strtol(S,&S,10);
+        continue;
     case_VmSize:
         P->vm_size = strtol(S,&S,10);
         continue;
@@ -436,6 +446,7 @@ ENTER(0x220);
 
 LEAVE(0x220);
 }
+#undef GPERF_TABLE_SIZE
 
 static void supgrps_from_supgids (proc_t *p) {
     char *g, *s;
index fb9b703a499eae2218fe49e259303d0009a9a515..f87b0e9f841d0a61165216ae4b05819779a80605 100644 (file)
@@ -116,6 +116,9 @@ typedef struct proc_t {
        vm_size,        // status          equals 'size' (as kb)
        vm_lock,        // status          locked pages (as kb)
        vm_rss,         // status          equals 'rss' and/or 'resident' (as kb)
+       vm_rss_anon,    // status          the 'anonymous' portion of vm_rss (as kb)
+       vm_rss_file,    // status          the 'file-backed' portion of vm_rss (as kb)
+       vm_rss_shared,  // status          the 'shared' portion of vm_rss (as kb)
        vm_data,        // status          data only size (as kb)
        vm_stack,       // status          stack only size (as kb)
        vm_swap,        // status          based on linux-2.6.34 "swap ents" (as kb)