changeset 13088:e0735b974926

6973928 mdb_page_lookup() broken by 6778289; breaks ::pmap
author Jonathan Adams <Jonathan.Adams@Sun.COM>
date Wed, 11 Aug 2010 14:15:45 -0700
parents 71556dfac9dc
children 9ff7ff6709c5
files usr/src/cmd/mdb/common/mdb/mdb_param.h usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c usr/src/uts/common/sys/param.h usr/src/uts/common/vm/page.h
diffstat 4 files changed, 102 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/mdb/mdb_param.h	Wed Aug 11 12:59:10 2010 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_param.h	Wed Aug 11 14:15:45 2010 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,15 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_MDB_PARAM_H
 #define	_MDB_PARAM_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -112,6 +108,8 @@
 extern unsigned long _mdb_ks_msg_bsize;
 extern unsigned long _mdb_ks_defaultstksz;
 extern int _mdb_ks_ncpu;
+extern int _mdb_ks_ncpu_log2;
+extern int _mdb_ks_ncpu_p2;
 
 /*
  * Now derive all the macros using the global variables defined in
@@ -134,6 +132,8 @@
 #define	MSG_BSIZE	_mdb_ks_msg_bsize
 #define	DEFAULTSTKSZ	_mdb_ks_defaultstksz
 #define	NCPU		_mdb_ks_ncpu
+#define	NCPU_LOG2	_mdb_ks_ncpu_log2
+#define	NCPU_P2		_mdb_ks_ncpu_p2
 
 #define	_STRING_H	/* Do not re-include <string.h> */
 
--- a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c	Wed Aug 11 12:59:10 2010 -0700
+++ b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c	Wed Aug 11 14:15:45 2010 -0700
@@ -31,7 +31,6 @@
  * to zero.
  */
 
-
 #include <mdb/mdb_target.h>
 #include <mdb/mdb_param.h>
 #include <mdb/mdb_modapi.h>
@@ -88,6 +87,8 @@
 unsigned long _mdb_ks_msg_bsize;
 unsigned long _mdb_ks_defaultstksz;
 int _mdb_ks_ncpu;
+int _mdb_ks_ncpu_log2;
+int _mdb_ks_ncpu_p2;
 
 /*
  * In-core copy of DNLC information:
@@ -97,8 +98,17 @@
 #define	MDB_DNLC_NCACHE_SZ(ncp) (sizeof (ncache_t) + (ncp)->namlen)
 #define	MDB_DNLC_MAX_RETRY 4
 
+static ncache_t **dnlc_hash;	/* mdbs hash array of dnlc entries */
 
-static ncache_t **dnlc_hash;	/* mdbs hash array of dnlc entries */
+/*
+ * copy of page_hash-related data
+ */
+static int page_hash_loaded;
+static long mdb_page_hashsz;
+static uint_t mdb_page_hashsz_shift;	/* Needed for PAGE_HASH_FUNC */
+static uintptr_t mdb_page_hash;		/* base address of page hash */
+#define	page_hashsz		mdb_page_hashsz
+#define	page_hashsz_shift	mdb_page_hashsz_shift
 
 /*
  * This will be the location of the vnodeops pointer for "autofs_vnodeops"
@@ -624,32 +634,78 @@
 	return (cpu);
 }
 
+static int
+page_hash_load(void)
+{
+	if (page_hash_loaded) {
+		return (1);
+	}
+
+	if (mdb_readvar(&mdb_page_hashsz, "page_hashsz") == -1) {
+		mdb_warn("unable to read page_hashsz");
+		return (0);
+	}
+	if (mdb_readvar(&mdb_page_hashsz_shift, "page_hashsz_shift") == -1) {
+		mdb_warn("unable to read page_hashsz_shift");
+		return (0);
+	}
+	if (mdb_readvar(&mdb_page_hash, "page_hash") == -1) {
+		mdb_warn("unable to read page_hash");
+		return (0);
+	}
+
+	page_hash_loaded = 1;	/* zeroed on state change */
+	return (1);
+}
+
 uintptr_t
 mdb_page_lookup(uintptr_t vp, u_offset_t offset)
 {
-	long page_hashsz, ndx;
-	int page_hashsz_shift;	/* Needed for PAGE_HASH_FUNC */
-	uintptr_t page_hash, pp;
+	size_t ndx;
+	uintptr_t page_hash_entry, pp;
 
-	if (mdb_readvar(&page_hashsz, "page_hashsz") == -1 ||
-	    mdb_readvar(&page_hashsz_shift, "page_hashsz_shift") == -1 ||
-	    mdb_readvar(&page_hash, "page_hash") == -1)
+	if (!page_hash_loaded && !page_hash_load()) {
 		return (NULL);
+	}
 
 	ndx = PAGE_HASH_FUNC(vp, offset);
-	page_hash += ndx * sizeof (uintptr_t);
+	page_hash_entry = mdb_page_hash + ndx * sizeof (uintptr_t);
 
-	mdb_vread(&pp, sizeof (pp), page_hash);
+	if (mdb_vread(&pp, sizeof (pp), page_hash_entry) < 0) {
+		mdb_warn("unable to read page_hash[%ld] (%p)", ndx,
+		    page_hash_entry);
+		return (NULL);
+	}
 
 	while (pp != NULL) {
 		page_t page;
+		long nndx;
 
-		mdb_vread(&page, sizeof (page), pp);
+		if (mdb_vread(&page, sizeof (page), pp) < 0) {
+			mdb_warn("unable to read page_t at %p", pp);
+			return (NULL);
+		}
 
 		if ((uintptr_t)page.p_vnode == vp &&
 		    (uint64_t)page.p_offset == offset)
 			return (pp);
 
+		/*
+		 * Double check that the pages actually hash to the
+		 * bucket we're searching.  If not, our version of
+		 * PAGE_HASH_FUNC() doesn't match the kernel's, and we're
+		 * not going to be able to find the page.  The most
+		 * likely reason for this that mdb_ks doesn't match the
+		 * kernel we're running against.
+		 */
+		nndx = PAGE_HASH_FUNC(page.p_vnode, page.p_offset);
+		if (page.p_vnode != NULL && nndx != ndx) {
+			mdb_warn("mdb_page_lookup: mdb_ks PAGE_HASH_FUNC() "
+			    "mismatch: in bucket %ld, but page %p hashes to "
+			    "bucket %ld\n", ndx, pp, nndx);
+			return (NULL);
+		}
+
 		pp = (uintptr_t)page.p_hash;
 	}
 
@@ -1164,6 +1220,10 @@
 	(void) mdb_readvar(&_mdb_ks_msg_bsize, "_msg_bsize");
 	(void) mdb_readvar(&_mdb_ks_defaultstksz, "_defaultstksz");
 	(void) mdb_readvar(&_mdb_ks_ncpu, "_ncpu");
+	(void) mdb_readvar(&_mdb_ks_ncpu_log2, "_ncpu_log2");
+	(void) mdb_readvar(&_mdb_ks_ncpu_p2, "_ncpu_p2");
+
+	page_hash_loaded = 0;	/* invalidate cached page_hash state */
 }
 
 const mdb_modinfo_t *
--- a/usr/src/uts/common/sys/param.h	Wed Aug 11 12:59:10 2010 -0700
+++ b/usr/src/uts/common/sys/param.h	Wed Aug 11 14:15:45 2010 -0700
@@ -384,6 +384,7 @@
 extern const int _clsize;
 #endif	/* defined(_KERNEL) && !defined(_ASM) */
 
+/* Any additions to these #defines must be reflected in mdb_param.h+mdb_ks.c */
 #define	PAGESIZE	_pagesize
 #define	PAGESHIFT	_pageshift
 #define	PAGEOFFSET	_pageoffset
--- a/usr/src/uts/common/vm/page.h	Wed Aug 11 12:59:10 2010 -0700
+++ b/usr/src/uts/common/vm/page.h	Wed Aug 11 14:15:45 2010 -0700
@@ -104,13 +104,15 @@
 /*
  * PAGE_LLOCK_SIZE is 2 * NCPU, but no smaller than 128.
  * PAGE_LLOCK_SHIFT is log2(PAGE_LLOCK_SIZE).
+ *
+ * We use ? : instead of #if because <vm/page.h> is included everywhere;
+ * NCPU_P2 is only a constant in the "unix" module.
+ *
  */
-#if ((2*NCPU_P2) > 128)
-#define	PAGE_LLOCK_SHIFT	((unsigned)(NCPU_LOG2 + 1))
-#else
-#define	PAGE_LLOCK_SHIFT	7U
-#endif
-#define	PAGE_LLOCK_SIZE (1 << PAGE_LLOCK_SHIFT)
+#define	PAGE_LLOCK_SHIFT \
+	    ((unsigned)(((2*NCPU_P2) > 128) ? NCPU_LOG2 + 1 : 7))
+
+#define	PAGE_LLOCK_SIZE (1ul << PAGE_LLOCK_SHIFT)
 
 /*
  * The number of low order 0 (or less variable) bits in the page_t address.
@@ -573,28 +575,17 @@
  * PH_SHIFT_SIZE is the amount to use for the successive shifts in the hash
  * function below.  The actual value is LOG2(PH_TABLE_SIZE), so that as many
  * bits as possible will filter thru PAGE_HASH_FUNC() and PAGE_HASH_MUTEX().
+ *
+ * We use ? : instead of #if because <vm/page.h> is included everywhere;
+ * NCPU maps to a global variable outside of the "unix" module.
  */
 #if defined(_LP64)
-
-#if NCPU < 4
-#define	PH_TABLE_SIZE	128
-#define	PH_SHIFT_SIZE	7
-#else
-#define	PH_TABLE_SIZE	(2 * NCPU_P2)
-#define	PH_SHIFT_SIZE	(NCPU_LOG2 + 1)
-#endif
-
+#define	PH_SHIFT_SIZE	((NCPU < 4) ? 7		: (NCPU_LOG2 + 1))
 #else	/* 32 bits */
+#define	PH_SHIFT_SIZE	((NCPU < 4) ? 4		: 7)
+#endif	/* _LP64 */
 
-#if NCPU < 4
-#define	PH_TABLE_SIZE	16
-#define	PH_SHIFT_SIZE	4
-#else
-#define	PH_TABLE_SIZE	128
-#define	PH_SHIFT_SIZE	7
-#endif
-
-#endif	/* _LP64 */
+#define	PH_TABLE_SIZE	(1ul << PH_SHIFT_SIZE)
 
 /*
  *
@@ -618,13 +609,14 @@
 #define	PAGE_HASHAVELEN		4
 #define	PAGE_HASH_FUNC(vp, off) \
 	(((((uintptr_t)(off) >> PAGESHIFT) ^ \
-		((uintptr_t)(off) >> (PAGESHIFT + PH_SHIFT_SIZE))) ^ \
-		(((uintptr_t)(vp) >> 3) ^ \
-		((uintptr_t)(vp) >> (3 + PH_SHIFT_SIZE)) ^ \
-		((uintptr_t)(vp) >> (3 + 2 * PH_SHIFT_SIZE)) ^ \
-		((uintptr_t)(vp) << \
-		(page_hashsz_shift - AN_VPSHIFT - VNODE_ALIGN_LOG2)))) & \
-		(PAGE_HASHSZ - 1))
+	    ((uintptr_t)(off) >> (PAGESHIFT + PH_SHIFT_SIZE))) ^ \
+	    (((uintptr_t)(vp) >> 3) ^ \
+	    ((uintptr_t)(vp) >> (3 + PH_SHIFT_SIZE)) ^ \
+	    ((uintptr_t)(vp) >> (3 + 2 * PH_SHIFT_SIZE)) ^ \
+	    ((uintptr_t)(vp) << \
+	    (page_hashsz_shift - AN_VPSHIFT - VNODE_ALIGN_LOG2)))) & \
+	    (PAGE_HASHSZ - 1))
+
 #ifdef _KERNEL
 
 /*