kern/122744: hostcache bug: supervisor read, page not present

Oleg Koreshkov okor at zone.salut.ru
Mon Apr 14 10:00:10 UTC 2008


>Number:         122744
>Category:       kern
>Synopsis:       hostcache bug: supervisor read, page not present
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Apr 14 10:00:09 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Oleg Koreshkov
>Release:        FreeBSD 6.3-RELEASE-p1 i386
>Organization:
-
>Environment:
FreeBSD d09.domain.tld 6.3-RELEASE-p1 FreeBSD 6.3-RELEASE-p1 #0: Tue Mar 18 10:13:59 MSK 2008 root at d-us9.kaspersky-labs.com:/usr/obj/usr/src/sys/D09 i386
>Description:
After setting sysctl net.inet.tcp.hostcache.hashsize to value higher than default -- system panics when hostcache limit reached.

% kgdb /usr/obj/usr/src/sys/D09/kernel.debug /var/crash/vmcore.1
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".

Unread portion of the kernel message buffer:


Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address   = 0x0
fault code              = supervisor read, page not present
instruction pointer     = 0x20:0x805afa78
stack pointer           = 0x28:0xda928b38
frame pointer           = 0x28:0xda928b44
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, def32 1, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 12 (swi1: net)
trap number             = 12
panic: page fault
cpuid = 0
Uptime: 19h28m24s
Dumping 3317 MB (2 chunks)
  chunk 0: 1MB (159 pages) ... ok
  chunk 1: 3317MB (849120 pages) 3301 3285 3269 3253 3237 3221 3205 3189 3173 3157 3141 3125 3109 3093 3077 3061 3045 3029 3013 2997 2981 2965 2949 2933 2917 2901 2885 2869 2853 2837 2821 2805 2789 2773 2757 2741 2725 2709 2693 2677 2661 2645 2629 2613 2597 2581 2565 2549 2533 2517 2501 2485 2469 2453 2437 2421 2405 2389 2373 2357 2341 2325 2309 2293 2277 2261 2245 2229 2213 2197 2181 2165 2149 2133 2117 2101 2085 2069 2053 2037 2021 2005 1989 1973 1957 1941 1925 1909 1893 1877 1861 1845 1829 1813 1797 1781 1765 1749 1733 1717 1701 1685 1669 1653 1637 1621 1605 1589 1573 1557 1541 1525 1509 1493 1477 1461 1445 1429 1413 1397 1381 1365 1349 1333 1317 1301 1285 1269 1253 1237 1221 1205 1189 1173 1157 1141 1125 1109 1093 1077 1061 1045 1029 1013 997 981 965 949 933 917 901 885 869 853 837 821 805 789 773 757 741 725 709 693 677 661 645 629 613 597 581 565 549 533 517 501 485 469 453 437 421 405 389 373 357 341 325 309 293 277 261 245 229 213 197 181 165 149 133 117 101 85 69 53 
 37 21 5

#0  doadump () at pcpu.h:165
165     pcpu.h: No such file or directory.
        in pcpu.h
(kgdb) bt
#0  doadump () at pcpu.h:165
#1  0x80516e6a in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2  0x80517191 in panic (fmt=0x80672364 "%s") at /usr/src/sys/kern/kern_shutdown.c:565
#3  0x806441f8 in trap_fatal (frame=0xda928af8, eva=0) at /usr/src/sys/i386/i386/trap.c:838
#4  0x80643f37 in trap_pfault (frame=0xda928af8, usermode=0, eva=0) at /usr/src/sys/i386/i386/trap.c:745
#5  0x80643b99 in trap (frame=
      {tf_fs = 8, tf_es = -2141519832, tf_ds = -1901920216, tf_edi = 5325, tf_esi = -2009774480, tf_ebp = -627930300, tf_isp = -627930332, tf_ebx = 0, tf_edx = -2014394112, tf_ecx = 4, tf_eax = -2009774480, tf_trapno = 12, tf_err = 0, tf_eip = -2141521288, tf_cs = 32, tf_eflags = 66118, tf_esp = 0, tf_ss = -627930256}) at /usr/src/sys/i386/i386/trap.c:435
#6  0x8062f36a in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7  0x805afa78 in tcp_hc_insert (inc=0x8ee0b44c) at /usr/src/sys/netinet/tcp_hostcache.c:353
#8  0x805afd69 in tcp_hc_update (inc=0x8ee0b44c, hcml=0xda928b70) at /usr/src/sys/netinet/tcp_hostcache.c:514
#9  0x805b5ab4 in tcp_discardcb (tp=0x8eadc570) at /usr/src/sys/netinet/tcp_subr.c:815
#10 0x805b5b4c in tcp_close (tp=0x88354670) at /usr/src/sys/netinet/tcp_subr.c:851
#11 0x805b1c85 in tcp_input (m=0x8e984400, off0=20) at /usr/src/sys/netinet/tcp_input.c:1691
#12 0x805a9aa2 in ip_input (m=0x8e984400) at /usr/src/sys/netinet/ip_input.c:791
#13 0x8059212f in netisr_processqueue (ni=0x806e9cf8) at /usr/src/sys/net/netisr.c:236
#14 0x805922e6 in swi_net (dummy=0x0) at /usr/src/sys/net/netisr.c:343
#15 0x805005ed in ithread_execute_handlers (p=0x87eeb860, ie=0x88102100) at /usr/src/sys/kern/kern_intr.c:682
#16 0x8050070d in ithread_loop (arg=0x87ecd8a0) at /usr/src/sys/kern/kern_intr.c:766
#17 0x804ff3a1 in fork_exit (callout=0x805006b8 <ithread_loop>, arg=0x87ecd8a0, frame=0xda928d38) at /usr/src/sys/kern/kern_fork.c:788
#18 0x8062f3cc in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:208
(kgdb) frame 7
#7  0x805afa78 in tcp_hc_insert (inc=0x8ee0b44c) at /usr/src/sys/netinet/tcp_hostcache.c:353
353                     hc_entry = TAILQ_LAST(&hc_head->hch_bucket, hc_qhead);
(kgdb) list
348             /*
349              * If the bucket limit is reached reuse the least used element
350              */
351             if (hc_head->hch_length >= tcp_hostcache.bucket_limit ||
352                 tcp_hostcache.cache_count >= tcp_hostcache.cache_limit) {
353                     hc_entry = TAILQ_LAST(&hc_head->hch_bucket, hc_qhead);
354                     /*
355                      * At first we were dropping the last element, just to
356                      * reaquire it in the next two lines again which ain't
357                      * very efficient. Instead just reuse the least used element.
(kgdb) print hc_head->hch_length
$1 = 0
(kgdb) print tcp_hostcache.bucket_limit
$2 = 30
(kgdb) print tcp_hostcache.cache_count
$3 = 15360
(kgdb) print tcp_hostcache.cache_limit
$4 = 15360
(kgdb) print hc_head->hch_bucket
$5 = {tqh_first = 0x0, tqh_last = 0x88354670}
(kgdb) print *hc_head
$6 = {hch_bucket = {tqh_first = 0x0, tqh_last = 0x88354670}, hch_length = 0, hch_mtx = {mtx_object = {lo_class = 0x806bafc4, 
      lo_name = 0x8067f92d "tcp_hc_entry", lo_type = 0x8067f92d "tcp_hc_entry", lo_flags = 196608, lo_list = {tqe_next = 0x0, tqe_prev = 0x0}, 
      lo_witness = 0x0}, mtx_lock = 2280573184, mtx_recurse = 0}}
(kgdb) print hc_head->hch_bucket->tqh_last
$7 = (struct hc_metrics **) 0x88354670
(kgdb) print *hc_head->hch_bucket->tqh_last
$8 = (struct hc_metrics *) 0x0

#define TAILQ_LAST(head, headname)                                      \
        (*(((struct headname *)((head)->tqh_last))->tqh_last))

So system panics dereferencing this pointer:
hc_head->hch_bucket->tqh_last->tqh_last


>How-To-Repeat:
sysctl net.inet.tcp.hostcache.hashsize=8192

Do fill hostcache.
>Fix:

There should be one of below:

1.
--- tcp_hostcache.c     2008-04-14 13:41:06.000000000 +0400
+++ tcp_hostcache.c     2008-04-14 13:41:33.000000000 +0400
@@ -226,6 +226,8 @@
                tcp_hostcache.hashsize = TCP_HOSTCACHE_HASHSIZE; /* default */
        }
        tcp_hostcache.hashmask = tcp_hostcache.hashsize - 1;
+       tcp_hostcache.cache_limit = MAX(tcp_hostcache.cache_limit,
+           (tcp_hostcache.hashsize * tcp_hostcache.bucket_limit));
 
        /*
         * Allocate the hash table


-- or --

2.

--- tcp_hostcache.c     2008-04-14 13:41:06.000000000 +0400
+++ tcp_hostcache.c     2008-04-14 13:43:02.000000000 +0400
@@ -348,8 +348,7 @@
        /*
         * If the bucket limit is reached reuse the least used element
         */
-       if (hc_head->hch_length >= tcp_hostcache.bucket_limit ||
-           tcp_hostcache.cache_count >= tcp_hostcache.cache_limit) {
+       if (hc_head->hch_length >= tcp_hostcache.bucket_limit) {
                hc_entry = TAILQ_LAST(&hc_head->hch_bucket, hc_qhead);
                /*
                 * At first we were dropping the last element, just to



-- or -- 

OR may be completely different logic checking hostcache limits.

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


More information about the freebsd-bugs mailing list