misc/96999: procfs reports incorrect information about private resident memory size

Shine Wang shine at juniper.net
Mon May 8 23:20:22 UTC 2006


>Number:         96999
>Category:       misc
>Synopsis:       procfs reports incorrect information about private resident memory size
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 08 23:20:15 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Shine Wang
>Release:        4.10
>Organization:
Juniper Networks
>Environment:
FreeBSD 4.10
>Description:
There are a few problems concerning how procfs_domap()
figures out the size of 'privateresident':

1. It is incorrect to think that the 'obj->shadow_count == 1'
   condition represents a private object.  The code which checks
   for 'obj->shadow_count == 1' should check for
   'obj->flags & OBJ_ONEMAPPING' instead.

   The following is a sample output which exhibits the problem.
   Note that 'privateresident' always shows up as 0.

0x8048000 0x811d000 141 0 0xce0395a0 r-x 4 2 0x0 COW NC vnode
0x811d000 0x8121000 4 0 0xce12ba80 rw- 1 0 0x2180 COW NNC vnode
0x8121000 0x813b000 4 0 0xce12b300 rw- 2 0 0x2180 NCOW NNC default
0x813b000 0x814e000 19 0 0xce12b300 rwx 2 0 0x2180 NCOW NNC default
0x4811d000 0x4812d000 14 0 0xc04cce80 r-x 81 40 0x4 COW NC vnode
0x4812d000 0x4812e000 1 0 0xce12b0c0 rw- 1 0 0x2180 COW NNC vnode
0x4812e000 0x4812f000 1 0 0xce067f00 rw- 2 0 0x2180 NCOW NNC default
0x4812f000 0x48137000 6 0 0xce067f00 rwx 2 0 0x2180 NCOW NNC default
0x48137000 0x48140000 8 0 0xc04cc160 r-x 42 21 0x0 COW NC vnode
0x48140000 0x48141000 1 0 0xce12b840 rwx 1 0 0x2180 COW NNC vnode
0x48141000 0x48143000 2 0 0xc04c9940 r-x 16 8 0x0 COW NC vnode
0x48143000 0x48144000 1 0 0xce12b7e0 rwx 1 0 0x2180 COW NNC vnode
0x48144000 0x481c0000 53 0 0xc04ccac0 r-x 82 41 0x4 COW NC vnode
0x481c0000 0x481c5000 5 0 0xce12b2a0 rwx 1 0 0x2180 COW NNC vnode
0x481c5000 0x481f9000 5 0 0xce129060 rwx 1 0 0x2180 NCOW NNC default
0xbfbe0000 0xbfc00000 2 0 0xce12b180 rwx 1 0 0x2180 NCOW NNC default

2. It is incorrect to assume that when an object is a
   private object, the entire obj->resident_page_count is 
   associated with a single vm_map_entry.  In fact, a single 
   object may be associated with one or more vm map entries
   which represent different address ranges in a process'
   address space.

   The following is a sample output after fixing problem #1 without
   fixing problem #2.  Note that on the third and fourth rows, 
   'privateresident' is greater than 'resident', which is wrong.  
   Also note that these two vm map entries are associated with the same 
   vm object.

0x8048000 0x811d000 141 0 0xce0395a0 r-x 4 2 0x0 COW NC vnode
0x811d000 0x8121000 4 1 0xce143b40 rw- 1 0 0x2180 COW NNC vnode
0x8121000 0x813b000 4 23 0xce143f00 rw- 2 0 0x2180 NCOW NNC default
0x813b000 0x814e000 19 23 0xce143f00 rwx 2 0 0x2180 NCOW NNC default
0x4811d000 0x4812d000 14 0 0xc04cce80 r-x 91 46 0x4 COW NC vnode
0x4812d000 0x4812e000 1 1 0xce143a80 rw- 1 0 0x2180 COW NNC vnode
0x4812e000 0x4812f000 1 7 0xce1438a0 rw- 2 0 0x2180 NCOW NNC default
0x4812f000 0x48137000 6 7 0xce1438a0 rwx 2 0 0x2180 NCOW NNC default
0x48137000 0x48140000 8 0 0xc04cb860 r-x 44 22 0x0 COW NC vnode
0x48140000 0x48141000 1 1 0xce143c60 rwx 1 0 0x2180 COW NNC vnode
0x48141000 0x48143000 2 0 0xc04cc160 r-x 18 9 0x0 COW NC vnode
0x48143000 0x48144000 1 1 0xce12f120 rwx 1 0 0x2180 COW NNC vnode
0x48144000 0x481c0000 53 0 0xc04ccac0 r-x 92 46 0x4 COW NC vnode
0x481c0000 0x481c5000 5 5 0xce143ba0 rwx 1 0 0x2180 COW NNC vnode
0x481c5000 0x481f9000 5 5 0xce1437e0 rwx 1 0 0x2180 NCOW NNC default
0xbfbe0000 0xbfc00000 2 2 0xce143960 rwx 1 0 0x2180 NCOW NNC default
>How-To-Repeat:
Write a program which uses the /proc/pid/map API to 
display the resident and private resident information about
each vm map entry in a process' address space.
>Fix:
                if (obj && (obj->flags & OBJ_ONEMAPPING)) {
                        /*
                         * This object is currently private (i.e., mapped to
                         * a single virtual address space).
                         */
                        if (obj->ref_count == 1) {
                                /*
                                 * In this case, all resident pages in the
                                 * object are associated with only one vm
                                 * map entry (i.e., the current entry).
                                 * Simply set 'privateresident' to the object's
                                 * resident page count.
                                 */
                                privateresident = obj->resident_page_count;
                        } else {
                                int s;
                                vm_pindex_t startidx, endidx;
                                vm_page_t m;

                                /*
                                 * If the object's reference count is greater
                                 * than 1, we can't set 'privateresident'
                                 * to obj->resident_page_count.  This is because
                                 * multiple vm map entries corresponding to
                                 * different address ranges may be associated
                                 * with a single object.  In that case,
                                 * obj->resident_page_count is the sum of
                                 * resident pages in all such entries.
                                 * We'll need to traverse the object's physical
                                 * page list and find out how many of them are
                                 * associated with the current vm map entry.
                                 */
                                startidx = OFF_TO_IDX(entry->offset);
                                endidx = startidx +
                                         OFF_TO_IDX(entry->end - entry->start);
                                s = splvm();
                                m = (vm_page_t) TAILQ_FIRST(&obj->memq);
                                while (m != NULL) {
                                        if (m->pindex >= startidx &&
                                            m->pindex < endidx) {
                                                ++privateresident;
                                                if (privateresident == resident)
                                                        break;
                                        }
                                        m = TAILQ_NEXT(m, listq);
                                }
                                splx(s);
                        }
                }

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list