xref: /titanic_52/usr/src/cmd/sendmail/db/lock/lock_region.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*-
2*7c478bd9Sstevel@tonic-gate  * See the file LICENSE for redistribution information.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, 1997, 1998
5*7c478bd9Sstevel@tonic-gate  *	Sleepycat Software.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  */
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
9*7c478bd9Sstevel@tonic-gate 
10*7c478bd9Sstevel@tonic-gate #include "config.h"
11*7c478bd9Sstevel@tonic-gate 
12*7c478bd9Sstevel@tonic-gate #ifndef lint
13*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)lock_region.c	10.21 (Sleepycat) 10/19/98";
14*7c478bd9Sstevel@tonic-gate #endif /* not lint */
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
17*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
18*7c478bd9Sstevel@tonic-gate 
19*7c478bd9Sstevel@tonic-gate #include <ctype.h>
20*7c478bd9Sstevel@tonic-gate #include <errno.h>
21*7c478bd9Sstevel@tonic-gate #include <string.h>
22*7c478bd9Sstevel@tonic-gate #endif
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #include "db_int.h"
25*7c478bd9Sstevel@tonic-gate #include "shqueue.h"
26*7c478bd9Sstevel@tonic-gate #include "db_shash.h"
27*7c478bd9Sstevel@tonic-gate #include "lock.h"
28*7c478bd9Sstevel@tonic-gate #include "common_ext.h"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate static u_int32_t __lock_count_locks __P((DB_LOCKREGION *));
31*7c478bd9Sstevel@tonic-gate static u_int32_t __lock_count_objs __P((DB_LOCKREGION *));
32*7c478bd9Sstevel@tonic-gate static void	 __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
33*7c478bd9Sstevel@tonic-gate static void	 __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
34*7c478bd9Sstevel@tonic-gate static const char *
35*7c478bd9Sstevel@tonic-gate 		 __lock_dump_status __P((db_status_t));
36*7c478bd9Sstevel@tonic-gate static void	 __lock_reset_region __P((DB_LOCKTAB *));
37*7c478bd9Sstevel@tonic-gate static int	 __lock_tabinit __P((DB_ENV *, DB_LOCKREGION *));
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate int
40*7c478bd9Sstevel@tonic-gate lock_open(path, flags, mode, dbenv, ltp)
41*7c478bd9Sstevel@tonic-gate 	const char *path;
42*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
43*7c478bd9Sstevel@tonic-gate 	int mode;
44*7c478bd9Sstevel@tonic-gate 	DB_ENV *dbenv;
45*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB **ltp;
46*7c478bd9Sstevel@tonic-gate {
47*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
48*7c478bd9Sstevel@tonic-gate 	u_int32_t lock_modes, maxlocks, regflags;
49*7c478bd9Sstevel@tonic-gate 	int ret;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate 	/* Validate arguments. */
52*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS
53*7c478bd9Sstevel@tonic-gate #define	OKFLAGS	(DB_CREATE | DB_THREAD)
54*7c478bd9Sstevel@tonic-gate #else
55*7c478bd9Sstevel@tonic-gate #define	OKFLAGS	(DB_CREATE)
56*7c478bd9Sstevel@tonic-gate #endif
57*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_fchk(dbenv, "lock_open", flags, OKFLAGS)) != 0)
58*7c478bd9Sstevel@tonic-gate 		return (ret);
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 	/* Create the lock table structure. */
61*7c478bd9Sstevel@tonic-gate 	if ((ret = __os_calloc(1, sizeof(DB_LOCKTAB), &lt)) != 0)
62*7c478bd9Sstevel@tonic-gate 		return (ret);
63*7c478bd9Sstevel@tonic-gate 	lt->dbenv = dbenv;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	/* Grab the values that we need to compute the region size. */
66*7c478bd9Sstevel@tonic-gate 	lock_modes = DB_LOCK_RW_N;
67*7c478bd9Sstevel@tonic-gate 	maxlocks = DB_LOCK_DEFAULT_N;
68*7c478bd9Sstevel@tonic-gate 	regflags = REGION_SIZEDEF;
69*7c478bd9Sstevel@tonic-gate 	if (dbenv != NULL) {
70*7c478bd9Sstevel@tonic-gate 		if (dbenv->lk_modes != 0) {
71*7c478bd9Sstevel@tonic-gate 			lock_modes = dbenv->lk_modes;
72*7c478bd9Sstevel@tonic-gate 			regflags = 0;
73*7c478bd9Sstevel@tonic-gate 		}
74*7c478bd9Sstevel@tonic-gate 		if (dbenv->lk_max != 0) {
75*7c478bd9Sstevel@tonic-gate 			maxlocks = dbenv->lk_max;
76*7c478bd9Sstevel@tonic-gate 			regflags = 0;
77*7c478bd9Sstevel@tonic-gate 		}
78*7c478bd9Sstevel@tonic-gate 	}
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 	/* Join/create the lock region. */
81*7c478bd9Sstevel@tonic-gate 	lt->reginfo.dbenv = dbenv;
82*7c478bd9Sstevel@tonic-gate 	lt->reginfo.appname = DB_APP_NONE;
83*7c478bd9Sstevel@tonic-gate 	if (path == NULL)
84*7c478bd9Sstevel@tonic-gate 		lt->reginfo.path = NULL;
85*7c478bd9Sstevel@tonic-gate 	else
86*7c478bd9Sstevel@tonic-gate 		if ((ret = __os_strdup(path, &lt->reginfo.path)) != 0)
87*7c478bd9Sstevel@tonic-gate 			goto err;
88*7c478bd9Sstevel@tonic-gate 	lt->reginfo.file = DB_DEFAULT_LOCK_FILE;
89*7c478bd9Sstevel@tonic-gate 	lt->reginfo.mode = mode;
90*7c478bd9Sstevel@tonic-gate 	lt->reginfo.size =
91*7c478bd9Sstevel@tonic-gate 	    LOCK_REGION_SIZE(lock_modes, maxlocks, __db_tablesize(maxlocks));
92*7c478bd9Sstevel@tonic-gate 	lt->reginfo.dbflags = flags;
93*7c478bd9Sstevel@tonic-gate 	lt->reginfo.addr = NULL;
94*7c478bd9Sstevel@tonic-gate 	lt->reginfo.fd = -1;
95*7c478bd9Sstevel@tonic-gate 	lt->reginfo.flags = regflags;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_rattach(&lt->reginfo)) != 0)
98*7c478bd9Sstevel@tonic-gate 		goto err;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	/* Now set up the pointer to the region. */
101*7c478bd9Sstevel@tonic-gate 	lt->region = lt->reginfo.addr;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	/* Initialize the region if we created it. */
104*7c478bd9Sstevel@tonic-gate 	if (F_ISSET(&lt->reginfo, REGION_CREATED)) {
105*7c478bd9Sstevel@tonic-gate 		lt->region->maxlocks = maxlocks;
106*7c478bd9Sstevel@tonic-gate 		lt->region->nmodes = lock_modes;
107*7c478bd9Sstevel@tonic-gate 		if ((ret = __lock_tabinit(dbenv, lt->region)) != 0)
108*7c478bd9Sstevel@tonic-gate 			goto err;
109*7c478bd9Sstevel@tonic-gate 	} else {
110*7c478bd9Sstevel@tonic-gate 		/* Check for an unexpected region. */
111*7c478bd9Sstevel@tonic-gate 		if (lt->region->magic != DB_LOCKMAGIC) {
112*7c478bd9Sstevel@tonic-gate 			__db_err(dbenv,
113*7c478bd9Sstevel@tonic-gate 			    "lock_open: %s: bad magic number", path);
114*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
115*7c478bd9Sstevel@tonic-gate 			goto err;
116*7c478bd9Sstevel@tonic-gate 		}
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	/* Check for automatic deadlock detection. */
120*7c478bd9Sstevel@tonic-gate 	if (dbenv != NULL && dbenv->lk_detect != DB_LOCK_NORUN) {
121*7c478bd9Sstevel@tonic-gate 		if (lt->region->detect != DB_LOCK_NORUN &&
122*7c478bd9Sstevel@tonic-gate 		    dbenv->lk_detect != DB_LOCK_DEFAULT &&
123*7c478bd9Sstevel@tonic-gate 		    lt->region->detect != dbenv->lk_detect) {
124*7c478bd9Sstevel@tonic-gate 			__db_err(dbenv,
125*7c478bd9Sstevel@tonic-gate 		    "lock_open: incompatible deadlock detector mode");
126*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
127*7c478bd9Sstevel@tonic-gate 			goto err;
128*7c478bd9Sstevel@tonic-gate 		}
129*7c478bd9Sstevel@tonic-gate 		if (lt->region->detect == DB_LOCK_NORUN)
130*7c478bd9Sstevel@tonic-gate 			lt->region->detect = dbenv->lk_detect;
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	/* Set up remaining pointers into region. */
134*7c478bd9Sstevel@tonic-gate 	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
135*7c478bd9Sstevel@tonic-gate 	lt->hashtab =
136*7c478bd9Sstevel@tonic-gate 	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
137*7c478bd9Sstevel@tonic-gate 	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
140*7c478bd9Sstevel@tonic-gate 	*ltp = lt;
141*7c478bd9Sstevel@tonic-gate 	return (0);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate err:	if (lt->reginfo.addr != NULL) {
144*7c478bd9Sstevel@tonic-gate 		UNLOCK_LOCKREGION(lt);
145*7c478bd9Sstevel@tonic-gate 		(void)__db_rdetach(&lt->reginfo);
146*7c478bd9Sstevel@tonic-gate 		if (F_ISSET(&lt->reginfo, REGION_CREATED))
147*7c478bd9Sstevel@tonic-gate 			(void)lock_unlink(path, 1, dbenv);
148*7c478bd9Sstevel@tonic-gate 	}
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (lt->reginfo.path != NULL)
151*7c478bd9Sstevel@tonic-gate 		__os_freestr(lt->reginfo.path);
152*7c478bd9Sstevel@tonic-gate 	__os_free(lt, sizeof(*lt));
153*7c478bd9Sstevel@tonic-gate 	return (ret);
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate /*
157*7c478bd9Sstevel@tonic-gate  * __lock_panic --
158*7c478bd9Sstevel@tonic-gate  *	Panic a lock region.
159*7c478bd9Sstevel@tonic-gate  *
160*7c478bd9Sstevel@tonic-gate  * PUBLIC: void __lock_panic __P((DB_ENV *));
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate void
163*7c478bd9Sstevel@tonic-gate __lock_panic(dbenv)
164*7c478bd9Sstevel@tonic-gate 	DB_ENV *dbenv;
165*7c478bd9Sstevel@tonic-gate {
166*7c478bd9Sstevel@tonic-gate 	if (dbenv->lk_info != NULL)
167*7c478bd9Sstevel@tonic-gate 		dbenv->lk_info->region->hdr.panic = 1;
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate /*
172*7c478bd9Sstevel@tonic-gate  * __lock_tabinit --
173*7c478bd9Sstevel@tonic-gate  *	Initialize the lock region.
174*7c478bd9Sstevel@tonic-gate  */
175*7c478bd9Sstevel@tonic-gate static int
176*7c478bd9Sstevel@tonic-gate __lock_tabinit(dbenv, lrp)
177*7c478bd9Sstevel@tonic-gate 	DB_ENV *dbenv;
178*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
181*7c478bd9Sstevel@tonic-gate 	struct lock_header *tq_head;
182*7c478bd9Sstevel@tonic-gate 	struct obj_header *obj_head;
183*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *op;
184*7c478bd9Sstevel@tonic-gate 	u_int32_t i, nelements;
185*7c478bd9Sstevel@tonic-gate 	const u_int8_t *conflicts;
186*7c478bd9Sstevel@tonic-gate 	u_int8_t *curaddr;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	conflicts = dbenv == NULL || dbenv->lk_conflicts == NULL ?
189*7c478bd9Sstevel@tonic-gate 	    db_rw_conflicts : dbenv->lk_conflicts;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	lrp->table_size = __db_tablesize(lrp->maxlocks);
192*7c478bd9Sstevel@tonic-gate 	lrp->magic = DB_LOCKMAGIC;
193*7c478bd9Sstevel@tonic-gate 	lrp->version = DB_LOCKVERSION;
194*7c478bd9Sstevel@tonic-gate 	lrp->id = 0;
195*7c478bd9Sstevel@tonic-gate 	/*
196*7c478bd9Sstevel@tonic-gate 	 * These fields (lrp->maxlocks, lrp->nmodes) are initialized
197*7c478bd9Sstevel@tonic-gate 	 * in the caller, since we had to grab those values to size
198*7c478bd9Sstevel@tonic-gate 	 * the region.
199*7c478bd9Sstevel@tonic-gate 	 */
200*7c478bd9Sstevel@tonic-gate 	lrp->need_dd = 0;
201*7c478bd9Sstevel@tonic-gate 	lrp->detect = DB_LOCK_NORUN;
202*7c478bd9Sstevel@tonic-gate 	lrp->numobjs = lrp->maxlocks;
203*7c478bd9Sstevel@tonic-gate 	lrp->nlockers = 0;
204*7c478bd9Sstevel@tonic-gate 	lrp->mem_bytes = ALIGN(STRING_SIZE(lrp->maxlocks), sizeof(size_t));
205*7c478bd9Sstevel@tonic-gate 	lrp->increment = lrp->hdr.size / 2;
206*7c478bd9Sstevel@tonic-gate 	lrp->nconflicts = 0;
207*7c478bd9Sstevel@tonic-gate 	lrp->nrequests = 0;
208*7c478bd9Sstevel@tonic-gate 	lrp->nreleases = 0;
209*7c478bd9Sstevel@tonic-gate 	lrp->ndeadlocks = 0;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	/*
212*7c478bd9Sstevel@tonic-gate 	 * As we write the region, we've got to maintain the alignment
213*7c478bd9Sstevel@tonic-gate 	 * for the structures that follow each chunk.  This information
214*7c478bd9Sstevel@tonic-gate 	 * ends up being encapsulated both in here as well as in the
215*7c478bd9Sstevel@tonic-gate 	 * lock.h file for the XXX_SIZE macros.
216*7c478bd9Sstevel@tonic-gate 	 */
217*7c478bd9Sstevel@tonic-gate 	/* Initialize conflict matrix. */
218*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)lrp + sizeof(DB_LOCKREGION);
219*7c478bd9Sstevel@tonic-gate 	memcpy(curaddr, conflicts, lrp->nmodes * lrp->nmodes);
220*7c478bd9Sstevel@tonic-gate 	curaddr += lrp->nmodes * lrp->nmodes;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	/*
223*7c478bd9Sstevel@tonic-gate 	 * Initialize hash table.
224*7c478bd9Sstevel@tonic-gate 	 */
225*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)ALIGNP(curaddr, LOCK_HASH_ALIGN);
226*7c478bd9Sstevel@tonic-gate 	lrp->hash_off = curaddr - (u_int8_t *)lrp;
227*7c478bd9Sstevel@tonic-gate 	nelements = lrp->table_size;
228*7c478bd9Sstevel@tonic-gate 	__db_hashinit(curaddr, nelements);
229*7c478bd9Sstevel@tonic-gate 	curaddr += nelements * sizeof(DB_HASHTAB);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/*
232*7c478bd9Sstevel@tonic-gate 	 * Initialize locks onto a free list. Since locks contains mutexes,
233*7c478bd9Sstevel@tonic-gate 	 * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT
234*7c478bd9Sstevel@tonic-gate 	 * boundary.
235*7c478bd9Sstevel@tonic-gate 	 */
236*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
237*7c478bd9Sstevel@tonic-gate 	tq_head = &lrp->free_locks;
238*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_INIT(tq_head);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	for (i = 0; i++ < lrp->maxlocks;
241*7c478bd9Sstevel@tonic-gate 	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
242*7c478bd9Sstevel@tonic-gate 		lp = (struct __db_lock *)curaddr;
243*7c478bd9Sstevel@tonic-gate 		lp->status = DB_LSTAT_FREE;
244*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(tq_head, lp, links, __db_lock);
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/* Initialize objects onto a free list.  */
248*7c478bd9Sstevel@tonic-gate 	obj_head = &lrp->free_objs;
249*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_INIT(obj_head);
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	for (i = 0; i++ < lrp->maxlocks; curaddr += sizeof(DB_LOCKOBJ)) {
252*7c478bd9Sstevel@tonic-gate 		op = (DB_LOCKOBJ *)curaddr;
253*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	/*
257*7c478bd9Sstevel@tonic-gate 	 * Initialize the string space; as for all shared memory allocation
258*7c478bd9Sstevel@tonic-gate 	 * regions, this requires size_t alignment, since we store the
259*7c478bd9Sstevel@tonic-gate 	 * lengths of malloc'd areas in the area.
260*7c478bd9Sstevel@tonic-gate 	 */
261*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)ALIGNP(curaddr, sizeof(size_t));
262*7c478bd9Sstevel@tonic-gate 	lrp->mem_off = curaddr - (u_int8_t *)lrp;
263*7c478bd9Sstevel@tonic-gate 	__db_shalloc_init(curaddr, lrp->mem_bytes);
264*7c478bd9Sstevel@tonic-gate 	return (0);
265*7c478bd9Sstevel@tonic-gate }
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate int
268*7c478bd9Sstevel@tonic-gate lock_close(lt)
269*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	int ret;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_rdetach(&lt->reginfo)) != 0)
276*7c478bd9Sstevel@tonic-gate 		return (ret);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	if (lt->reginfo.path != NULL)
279*7c478bd9Sstevel@tonic-gate 		__os_freestr(lt->reginfo.path);
280*7c478bd9Sstevel@tonic-gate 	__os_free(lt, sizeof(*lt));
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	return (0);
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate int
286*7c478bd9Sstevel@tonic-gate lock_unlink(path, force, dbenv)
287*7c478bd9Sstevel@tonic-gate 	const char *path;
288*7c478bd9Sstevel@tonic-gate 	int force;
289*7c478bd9Sstevel@tonic-gate 	DB_ENV *dbenv;
290*7c478bd9Sstevel@tonic-gate {
291*7c478bd9Sstevel@tonic-gate 	REGINFO reginfo;
292*7c478bd9Sstevel@tonic-gate 	int ret;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	memset(&reginfo, 0, sizeof(reginfo));
295*7c478bd9Sstevel@tonic-gate 	reginfo.dbenv = dbenv;
296*7c478bd9Sstevel@tonic-gate 	reginfo.appname = DB_APP_NONE;
297*7c478bd9Sstevel@tonic-gate 	if (path != NULL && (ret = __os_strdup(path, &reginfo.path)) != 0)
298*7c478bd9Sstevel@tonic-gate 		return (ret);
299*7c478bd9Sstevel@tonic-gate 	reginfo.file = DB_DEFAULT_LOCK_FILE;
300*7c478bd9Sstevel@tonic-gate 	ret = __db_runlink(&reginfo, force);
301*7c478bd9Sstevel@tonic-gate 	if (reginfo.path != NULL)
302*7c478bd9Sstevel@tonic-gate 		__os_freestr(reginfo.path);
303*7c478bd9Sstevel@tonic-gate 	return (ret);
304*7c478bd9Sstevel@tonic-gate }
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate /*
307*7c478bd9Sstevel@tonic-gate  * __lock_validate_region --
308*7c478bd9Sstevel@tonic-gate  *	Called at every interface to verify if the region has changed size,
309*7c478bd9Sstevel@tonic-gate  *	and if so, to remap the region in and reset the process' pointers.
310*7c478bd9Sstevel@tonic-gate  *
311*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __lock_validate_region __P((DB_LOCKTAB *));
312*7c478bd9Sstevel@tonic-gate  */
313*7c478bd9Sstevel@tonic-gate int
314*7c478bd9Sstevel@tonic-gate __lock_validate_region(lt)
315*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
316*7c478bd9Sstevel@tonic-gate {
317*7c478bd9Sstevel@tonic-gate 	int ret;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	if (lt->reginfo.size == lt->region->hdr.size)
320*7c478bd9Sstevel@tonic-gate 		return (0);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	/* Detach/reattach the region. */
323*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_rreattach(&lt->reginfo, lt->region->hdr.size)) != 0)
324*7c478bd9Sstevel@tonic-gate 		return (ret);
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	/* Reset region information. */
327*7c478bd9Sstevel@tonic-gate 	lt->region = lt->reginfo.addr;
328*7c478bd9Sstevel@tonic-gate 	__lock_reset_region(lt);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	return (0);
331*7c478bd9Sstevel@tonic-gate }
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate /*
334*7c478bd9Sstevel@tonic-gate  * __lock_grow_region --
335*7c478bd9Sstevel@tonic-gate  *	We have run out of space; time to grow the region.
336*7c478bd9Sstevel@tonic-gate  *
337*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __lock_grow_region __P((DB_LOCKTAB *, int, size_t));
338*7c478bd9Sstevel@tonic-gate  */
339*7c478bd9Sstevel@tonic-gate int
340*7c478bd9Sstevel@tonic-gate __lock_grow_region(lt, which, howmuch)
341*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
342*7c478bd9Sstevel@tonic-gate 	int which;
343*7c478bd9Sstevel@tonic-gate 	size_t howmuch;
344*7c478bd9Sstevel@tonic-gate {
345*7c478bd9Sstevel@tonic-gate 	struct __db_lock *newl;
346*7c478bd9Sstevel@tonic-gate 	struct lock_header *lock_head;
347*7c478bd9Sstevel@tonic-gate 	struct obj_header *obj_head;
348*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *op;
349*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
350*7c478bd9Sstevel@tonic-gate 	float lock_ratio, obj_ratio;
351*7c478bd9Sstevel@tonic-gate 	size_t incr, oldsize, used, usedmem;
352*7c478bd9Sstevel@tonic-gate 	u_int32_t i, newlocks, newmem, newobjs, usedlocks, usedobjs;
353*7c478bd9Sstevel@tonic-gate 	u_int8_t *curaddr;
354*7c478bd9Sstevel@tonic-gate 	int ret;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
357*7c478bd9Sstevel@tonic-gate 	oldsize = lrp->hdr.size;
358*7c478bd9Sstevel@tonic-gate 	incr = lrp->increment;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	/* Figure out how much of each sort of space we have. */
361*7c478bd9Sstevel@tonic-gate 	usedmem = lrp->mem_bytes - __db_shalloc_count(lt->mem);
362*7c478bd9Sstevel@tonic-gate 	usedobjs = lrp->numobjs - __lock_count_objs(lrp);
363*7c478bd9Sstevel@tonic-gate 	usedlocks = lrp->maxlocks - __lock_count_locks(lrp);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	/*
366*7c478bd9Sstevel@tonic-gate 	 * Figure out what fraction of the used space belongs to each
367*7c478bd9Sstevel@tonic-gate 	 * different type of "thing" in the region.  Then partition the
368*7c478bd9Sstevel@tonic-gate 	 * new space up according to this ratio.
369*7c478bd9Sstevel@tonic-gate 	 */
370*7c478bd9Sstevel@tonic-gate 	used = usedmem +
371*7c478bd9Sstevel@tonic-gate 	    usedlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) +
372*7c478bd9Sstevel@tonic-gate 	    usedobjs * sizeof(DB_LOCKOBJ);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	lock_ratio = usedlocks *
375*7c478bd9Sstevel@tonic-gate 	    ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) / (float)used;
376*7c478bd9Sstevel@tonic-gate 	obj_ratio = usedobjs * sizeof(DB_LOCKOBJ) / (float)used;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	newlocks = (u_int32_t)(lock_ratio *
379*7c478bd9Sstevel@tonic-gate 	    incr / ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
380*7c478bd9Sstevel@tonic-gate 	newobjs = (u_int32_t)(obj_ratio * incr / sizeof(DB_LOCKOBJ));
381*7c478bd9Sstevel@tonic-gate 	newmem = incr -
382*7c478bd9Sstevel@tonic-gate 	    (newobjs * sizeof(DB_LOCKOBJ) +
383*7c478bd9Sstevel@tonic-gate 	    newlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	/*
386*7c478bd9Sstevel@tonic-gate 	 * Make sure we allocate enough memory for the object being
387*7c478bd9Sstevel@tonic-gate 	 * requested.
388*7c478bd9Sstevel@tonic-gate 	 */
389*7c478bd9Sstevel@tonic-gate 	switch (which) {
390*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_LOCK:
391*7c478bd9Sstevel@tonic-gate 		if (newlocks == 0) {
392*7c478bd9Sstevel@tonic-gate 			newlocks = 10;
393*7c478bd9Sstevel@tonic-gate 			incr += newlocks * sizeof(struct __db_lock);
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 		break;
396*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_OBJ:
397*7c478bd9Sstevel@tonic-gate 		if (newobjs == 0) {
398*7c478bd9Sstevel@tonic-gate 			newobjs = 10;
399*7c478bd9Sstevel@tonic-gate 			incr += newobjs * sizeof(DB_LOCKOBJ);
400*7c478bd9Sstevel@tonic-gate 		}
401*7c478bd9Sstevel@tonic-gate 		break;
402*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_MEM:
403*7c478bd9Sstevel@tonic-gate 		if (newmem < howmuch * 2) {
404*7c478bd9Sstevel@tonic-gate 			incr += howmuch * 2 - newmem;
405*7c478bd9Sstevel@tonic-gate 			newmem = howmuch * 2;
406*7c478bd9Sstevel@tonic-gate 		}
407*7c478bd9Sstevel@tonic-gate 		break;
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	newmem += ALIGN(incr, sizeof(size_t)) - incr;
411*7c478bd9Sstevel@tonic-gate 	incr = ALIGN(incr, sizeof(size_t));
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	/*
414*7c478bd9Sstevel@tonic-gate 	 * Since we are going to be allocating locks at the beginning of the
415*7c478bd9Sstevel@tonic-gate 	 * new chunk, we need to make sure that the chunk is MUTEX_ALIGNMENT
416*7c478bd9Sstevel@tonic-gate 	 * aligned.  We did not guarantee this when we created the region, so
417*7c478bd9Sstevel@tonic-gate 	 * we may need to pad the old region by extra bytes to ensure this
418*7c478bd9Sstevel@tonic-gate 	 * alignment.
419*7c478bd9Sstevel@tonic-gate 	 */
420*7c478bd9Sstevel@tonic-gate 	incr += ALIGN(oldsize, MUTEX_ALIGNMENT) - oldsize;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	__db_err(lt->dbenv,
423*7c478bd9Sstevel@tonic-gate 	    "Growing lock region: %lu locks %lu objs %lu bytes",
424*7c478bd9Sstevel@tonic-gate 	    (u_long)newlocks, (u_long)newobjs, (u_long)newmem);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_rgrow(&lt->reginfo, oldsize + incr)) != 0)
427*7c478bd9Sstevel@tonic-gate 		return (ret);
428*7c478bd9Sstevel@tonic-gate 	lt->region = lt->reginfo.addr;
429*7c478bd9Sstevel@tonic-gate 	__lock_reset_region(lt);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	/* Update region parameters. */
432*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
433*7c478bd9Sstevel@tonic-gate 	lrp->increment = incr << 1;
434*7c478bd9Sstevel@tonic-gate 	lrp->maxlocks += newlocks;
435*7c478bd9Sstevel@tonic-gate 	lrp->numobjs += newobjs;
436*7c478bd9Sstevel@tonic-gate 	lrp->mem_bytes += newmem;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)lrp + oldsize;
439*7c478bd9Sstevel@tonic-gate 	curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	/* Put new locks onto the free list. */
442*7c478bd9Sstevel@tonic-gate 	lock_head = &lrp->free_locks;
443*7c478bd9Sstevel@tonic-gate 	for (i = 0; i++ < newlocks;
444*7c478bd9Sstevel@tonic-gate 	    curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
445*7c478bd9Sstevel@tonic-gate 		newl = (struct __db_lock *)curaddr;
446*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(lock_head, newl, links, __db_lock);
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	/* Put new objects onto the free list.  */
450*7c478bd9Sstevel@tonic-gate 	obj_head = &lrp->free_objs;
451*7c478bd9Sstevel@tonic-gate 	for (i = 0; i++ < newobjs; curaddr += sizeof(DB_LOCKOBJ)) {
452*7c478bd9Sstevel@tonic-gate 		op = (DB_LOCKOBJ *)curaddr;
453*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	*((size_t *)curaddr) = newmem - sizeof(size_t);
457*7c478bd9Sstevel@tonic-gate 	curaddr += sizeof(size_t);
458*7c478bd9Sstevel@tonic-gate 	__db_shalloc_free(lt->mem, curaddr);
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	return (0);
461*7c478bd9Sstevel@tonic-gate }
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate static void
464*7c478bd9Sstevel@tonic-gate __lock_reset_region(lt)
465*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
466*7c478bd9Sstevel@tonic-gate {
467*7c478bd9Sstevel@tonic-gate 	lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
468*7c478bd9Sstevel@tonic-gate 	lt->hashtab =
469*7c478bd9Sstevel@tonic-gate 	    (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
470*7c478bd9Sstevel@tonic-gate 	lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate  * lock_stat --
475*7c478bd9Sstevel@tonic-gate  *	Return LOCK statistics.
476*7c478bd9Sstevel@tonic-gate  */
477*7c478bd9Sstevel@tonic-gate int
478*7c478bd9Sstevel@tonic-gate lock_stat(lt, gspp, db_malloc)
479*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
480*7c478bd9Sstevel@tonic-gate 	DB_LOCK_STAT **gspp;
481*7c478bd9Sstevel@tonic-gate 	void *(*db_malloc) __P((size_t));
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *rp;
484*7c478bd9Sstevel@tonic-gate 	int ret;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	*gspp = NULL;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
491*7c478bd9Sstevel@tonic-gate 		return (ret);
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	/* Copy out the global statistics. */
494*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	rp = lt->region;
497*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_magic = rp->magic;
498*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_version = rp->version;
499*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_maxlocks = rp->maxlocks;
500*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_nmodes = rp->nmodes;
501*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_numobjs = rp->numobjs;
502*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_nlockers = rp->nlockers;
503*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_nconflicts = rp->nconflicts;
504*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_nrequests = rp->nrequests;
505*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_nreleases = rp->nreleases;
506*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_ndeadlocks = rp->ndeadlocks;
507*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_region_nowait = rp->hdr.lock.mutex_set_nowait;
508*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_region_wait = rp->hdr.lock.mutex_set_wait;
509*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_refcnt = rp->hdr.refcnt;
510*7c478bd9Sstevel@tonic-gate 	(*gspp)->st_regsize = rp->hdr.size;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	return (0);
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate static u_int32_t
518*7c478bd9Sstevel@tonic-gate __lock_count_locks(lrp)
519*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
520*7c478bd9Sstevel@tonic-gate {
521*7c478bd9Sstevel@tonic-gate 	struct __db_lock *newl;
522*7c478bd9Sstevel@tonic-gate 	u_int32_t count;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	count = 0;
525*7c478bd9Sstevel@tonic-gate 	for (newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
526*7c478bd9Sstevel@tonic-gate 	    newl != NULL;
527*7c478bd9Sstevel@tonic-gate 	    newl = SH_TAILQ_NEXT(newl, links, __db_lock))
528*7c478bd9Sstevel@tonic-gate 		count++;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	return (count);
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate static u_int32_t
534*7c478bd9Sstevel@tonic-gate __lock_count_objs(lrp)
535*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
536*7c478bd9Sstevel@tonic-gate {
537*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *obj;
538*7c478bd9Sstevel@tonic-gate 	u_int32_t count;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	count = 0;
541*7c478bd9Sstevel@tonic-gate 	for (obj = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
542*7c478bd9Sstevel@tonic-gate 	    obj != NULL;
543*7c478bd9Sstevel@tonic-gate 	    obj = SH_TAILQ_NEXT(obj, links, __db_lockobj))
544*7c478bd9Sstevel@tonic-gate 		count++;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	return (count);
547*7c478bd9Sstevel@tonic-gate }
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_CONF		0x001		/* Conflict matrix. */
550*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_FREE		0x002		/* Display lock free list. */
551*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_LOCKERS	0x004		/* Display lockers. */
552*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_MEM		0x008		/* Display region memory. */
553*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_OBJECTS	0x010		/* Display objects. */
554*7c478bd9Sstevel@tonic-gate #define	LOCK_DUMP_ALL		0x01f		/* Display all. */
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate /*
557*7c478bd9Sstevel@tonic-gate  * __lock_dump_region --
558*7c478bd9Sstevel@tonic-gate  *
559*7c478bd9Sstevel@tonic-gate  * PUBLIC: void __lock_dump_region __P((DB_LOCKTAB *, char *, FILE *));
560*7c478bd9Sstevel@tonic-gate  */
561*7c478bd9Sstevel@tonic-gate void
562*7c478bd9Sstevel@tonic-gate __lock_dump_region(lt, area, fp)
563*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
564*7c478bd9Sstevel@tonic-gate 	char *area;
565*7c478bd9Sstevel@tonic-gate 	FILE *fp;
566*7c478bd9Sstevel@tonic-gate {
567*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
568*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *op;
569*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
570*7c478bd9Sstevel@tonic-gate 	u_int32_t flags, i, j;
571*7c478bd9Sstevel@tonic-gate 	int label;
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	/* Make it easy to call from the debugger. */
574*7c478bd9Sstevel@tonic-gate 	if (fp == NULL)
575*7c478bd9Sstevel@tonic-gate 		fp = stderr;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	for (flags = 0; *area != '\0'; ++area)
578*7c478bd9Sstevel@tonic-gate 		switch (*area) {
579*7c478bd9Sstevel@tonic-gate 		case 'A':
580*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_ALL);
581*7c478bd9Sstevel@tonic-gate 			break;
582*7c478bd9Sstevel@tonic-gate 		case 'c':
583*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_CONF);
584*7c478bd9Sstevel@tonic-gate 			break;
585*7c478bd9Sstevel@tonic-gate 		case 'f':
586*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_FREE);
587*7c478bd9Sstevel@tonic-gate 			break;
588*7c478bd9Sstevel@tonic-gate 		case 'l':
589*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_LOCKERS);
590*7c478bd9Sstevel@tonic-gate 			break;
591*7c478bd9Sstevel@tonic-gate 		case 'm':
592*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_MEM);
593*7c478bd9Sstevel@tonic-gate 			break;
594*7c478bd9Sstevel@tonic-gate 		case 'o':
595*7c478bd9Sstevel@tonic-gate 			LF_SET(LOCK_DUMP_OBJECTS);
596*7c478bd9Sstevel@tonic-gate 			break;
597*7c478bd9Sstevel@tonic-gate 		}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	fprintf(fp, "%s\nLock region parameters\n", DB_LINE);
602*7c478bd9Sstevel@tonic-gate 	fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu\n%s: %lu, %s: %lu\n",
603*7c478bd9Sstevel@tonic-gate 	    "table size", (u_long)lrp->table_size,
604*7c478bd9Sstevel@tonic-gate 	    "hash_off", (u_long)lrp->hash_off,
605*7c478bd9Sstevel@tonic-gate 	    "increment", (u_long)lrp->increment,
606*7c478bd9Sstevel@tonic-gate 	    "mem_off", (u_long)lrp->mem_off,
607*7c478bd9Sstevel@tonic-gate 	    "mem_bytes", (u_long)lrp->mem_bytes,
608*7c478bd9Sstevel@tonic-gate 	    "need_dd", (u_long)lrp->need_dd);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	if (LF_ISSET(LOCK_DUMP_CONF)) {
611*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "\n%s\nConflict matrix\n", DB_LINE);
612*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < lrp->nmodes; i++) {
613*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < lrp->nmodes; j++)
614*7c478bd9Sstevel@tonic-gate 				fprintf(fp, "%lu\t",
615*7c478bd9Sstevel@tonic-gate 				    (u_long)lt->conflicts[i * lrp->nmodes + j]);
616*7c478bd9Sstevel@tonic-gate 			fprintf(fp, "\n");
617*7c478bd9Sstevel@tonic-gate 		}
618*7c478bd9Sstevel@tonic-gate 	}
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	if (LF_ISSET(LOCK_DUMP_LOCKERS | LOCK_DUMP_OBJECTS)) {
621*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "%s\nLock hash buckets\n", DB_LINE);
622*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < lrp->table_size; i++) {
623*7c478bd9Sstevel@tonic-gate 			label = 1;
624*7c478bd9Sstevel@tonic-gate 			for (op = SH_TAILQ_FIRST(&lt->hashtab[i], __db_lockobj);
625*7c478bd9Sstevel@tonic-gate 			    op != NULL;
626*7c478bd9Sstevel@tonic-gate 			    op = SH_TAILQ_NEXT(op, links, __db_lockobj)) {
627*7c478bd9Sstevel@tonic-gate 				if (LF_ISSET(LOCK_DUMP_LOCKERS) &&
628*7c478bd9Sstevel@tonic-gate 				    op->type == DB_LOCK_LOCKER) {
629*7c478bd9Sstevel@tonic-gate 					if (label) {
630*7c478bd9Sstevel@tonic-gate 						fprintf(fp,
631*7c478bd9Sstevel@tonic-gate 						    "Bucket %lu:\n", (u_long)i);
632*7c478bd9Sstevel@tonic-gate 						label = 0;
633*7c478bd9Sstevel@tonic-gate 					}
634*7c478bd9Sstevel@tonic-gate 					__lock_dump_locker(lt, op, fp);
635*7c478bd9Sstevel@tonic-gate 				}
636*7c478bd9Sstevel@tonic-gate 				if (LF_ISSET(LOCK_DUMP_OBJECTS) &&
637*7c478bd9Sstevel@tonic-gate 				    op->type == DB_LOCK_OBJTYPE) {
638*7c478bd9Sstevel@tonic-gate 					if (label) {
639*7c478bd9Sstevel@tonic-gate 						fprintf(fp,
640*7c478bd9Sstevel@tonic-gate 						    "Bucket %lu:\n", (u_long)i);
641*7c478bd9Sstevel@tonic-gate 						label = 0;
642*7c478bd9Sstevel@tonic-gate 					}
643*7c478bd9Sstevel@tonic-gate 					__lock_dump_object(lt, op, fp);
644*7c478bd9Sstevel@tonic-gate 				}
645*7c478bd9Sstevel@tonic-gate 			}
646*7c478bd9Sstevel@tonic-gate 		}
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	if (LF_ISSET(LOCK_DUMP_FREE)) {
650*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "%s\nLock free list\n", DB_LINE);
651*7c478bd9Sstevel@tonic-gate 		for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
652*7c478bd9Sstevel@tonic-gate 		    lp != NULL;
653*7c478bd9Sstevel@tonic-gate 		    lp = SH_TAILQ_NEXT(lp, links, __db_lock))
654*7c478bd9Sstevel@tonic-gate 			fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp,
655*7c478bd9Sstevel@tonic-gate 			    (u_long)lp->holder, (u_long)lp->mode,
656*7c478bd9Sstevel@tonic-gate 			    __lock_dump_status(lp->status), (u_long)lp->obj);
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "%s\nObject free list\n", DB_LINE);
659*7c478bd9Sstevel@tonic-gate 		for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
660*7c478bd9Sstevel@tonic-gate 		    op != NULL;
661*7c478bd9Sstevel@tonic-gate 		    op = SH_TAILQ_NEXT(op, links, __db_lockobj))
662*7c478bd9Sstevel@tonic-gate 			fprintf(fp, "0x%lx\n", (u_long)op);
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	if (LF_ISSET(LOCK_DUMP_MEM))
666*7c478bd9Sstevel@tonic-gate 		__db_shalloc_dump(lt->mem, fp);
667*7c478bd9Sstevel@tonic-gate }
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate static void
670*7c478bd9Sstevel@tonic-gate __lock_dump_locker(lt, op, fp)
671*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
672*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *op;
673*7c478bd9Sstevel@tonic-gate 	FILE *fp;
674*7c478bd9Sstevel@tonic-gate {
675*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
676*7c478bd9Sstevel@tonic-gate 	u_int32_t locker;
677*7c478bd9Sstevel@tonic-gate 	void *ptr;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	ptr = SH_DBT_PTR(&op->lockobj);
680*7c478bd9Sstevel@tonic-gate 	memcpy(&locker, ptr, sizeof(u_int32_t));
681*7c478bd9Sstevel@tonic-gate 	fprintf(fp, "L %lx", (u_long)locker);
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	lp = SH_LIST_FIRST(&op->heldby, __db_lock);
684*7c478bd9Sstevel@tonic-gate 	if (lp == NULL) {
685*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "\n");
686*7c478bd9Sstevel@tonic-gate 		return;
687*7c478bd9Sstevel@tonic-gate 	}
688*7c478bd9Sstevel@tonic-gate 	for (; lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock))
689*7c478bd9Sstevel@tonic-gate 		__lock_printlock(lt, lp, 0);
690*7c478bd9Sstevel@tonic-gate }
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate static void
693*7c478bd9Sstevel@tonic-gate __lock_dump_object(lt, op, fp)
694*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
695*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *op;
696*7c478bd9Sstevel@tonic-gate 	FILE *fp;
697*7c478bd9Sstevel@tonic-gate {
698*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
699*7c478bd9Sstevel@tonic-gate 	u_int32_t j;
700*7c478bd9Sstevel@tonic-gate 	u_int8_t *ptr;
701*7c478bd9Sstevel@tonic-gate 	u_int ch;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	ptr = SH_DBT_PTR(&op->lockobj);
704*7c478bd9Sstevel@tonic-gate 	for (j = 0; j < op->lockobj.size; ptr++, j++) {
705*7c478bd9Sstevel@tonic-gate 		ch = *ptr;
706*7c478bd9Sstevel@tonic-gate 		fprintf(fp, isprint(ch) ? "%c" : "\\%o", ch);
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 	fprintf(fp, "\n");
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	fprintf(fp, "H:");
711*7c478bd9Sstevel@tonic-gate 	for (lp =
712*7c478bd9Sstevel@tonic-gate 	    SH_TAILQ_FIRST(&op->holders, __db_lock);
713*7c478bd9Sstevel@tonic-gate 	    lp != NULL;
714*7c478bd9Sstevel@tonic-gate 	    lp = SH_TAILQ_NEXT(lp, links, __db_lock))
715*7c478bd9Sstevel@tonic-gate 		__lock_printlock(lt, lp, 0);
716*7c478bd9Sstevel@tonic-gate 	lp = SH_TAILQ_FIRST(&op->waiters, __db_lock);
717*7c478bd9Sstevel@tonic-gate 	if (lp != NULL) {
718*7c478bd9Sstevel@tonic-gate 		fprintf(fp, "\nW:");
719*7c478bd9Sstevel@tonic-gate 		for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock))
720*7c478bd9Sstevel@tonic-gate 			__lock_printlock(lt, lp, 0);
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate }
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate static const char *
725*7c478bd9Sstevel@tonic-gate __lock_dump_status(status)
726*7c478bd9Sstevel@tonic-gate 	db_status_t status;
727*7c478bd9Sstevel@tonic-gate {
728*7c478bd9Sstevel@tonic-gate 	switch (status) {
729*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_ABORTED:
730*7c478bd9Sstevel@tonic-gate 		return ("aborted");
731*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_ERR:
732*7c478bd9Sstevel@tonic-gate 		return ("err");
733*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_FREE:
734*7c478bd9Sstevel@tonic-gate 		return ("free");
735*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_HELD:
736*7c478bd9Sstevel@tonic-gate 		return ("held");
737*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_NOGRANT:
738*7c478bd9Sstevel@tonic-gate 		return ("nogrant");
739*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_PENDING:
740*7c478bd9Sstevel@tonic-gate 		return ("pending");
741*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_WAITING:
742*7c478bd9Sstevel@tonic-gate 		return ("waiting");
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 	return ("unknown status");
745*7c478bd9Sstevel@tonic-gate }
746