4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
37 #include "../ypdefs.h"
41 * These routines provide mutual exclusion between ypserv and ypxfr.
42 * Mutual exclusion is needed so that ypxfr doesn't try to rename
43 * dbm files while ypserv is trying to open them. After ypserv has
44 * opened a dbm file, it is safe to rename it because ypserv still
45 * has access to the file through its file descriptor.
48 #define LOCKFILE "/var/run/yp_maplock"
50 mutex_t locknode
[MAXHASH
];
52 typedef struct lockarray lockarray
;
55 * Cross-process robust mutex locks.
56 * Provide synchronization between YP processes
57 * by implementing an exclusive locking mechanism
58 * via a memory-mapped file.
60 static struct lockarray
*shmlockarray
;
64 * Hash functions, used for by the locking mechanism.
66 * - hash() is the front-end function that gets called.
67 * - get_map_id() returns a unique int value per map.
68 * It is used in N2L mode only.
69 * It is called by hash() in N2L mode.
72 get_map_id(char *map_name
, int index
)
74 map_id_elt_t
*cur_elt
;
76 * Local references to hash table for map lists
77 * and to max number of maps
79 map_id_elt_t
**map_list_p
;
82 /* initializes map_list_p & max_map */
83 get_list_max(&map_list_p
, &max_map
);
85 cur_elt
= map_list_p
[index
];
86 while (cur_elt
!= NULL
) {
87 if (strcmp(map_name
, cur_elt
->map_name
) == 0) {
89 return (cur_elt
->map_id
);
91 cur_elt
= cur_elt
->next
;
93 syslog(LOG_WARNING
, "get_map_id: no hash id found for %s"
94 ", giving max_map value (%d)",
97 * max_map does not match any map id, hence
98 * will not trigger any lock collision
100 * Needed for yp regular locking mechanism.
112 for (i
= 1; *s
; i
+= 10, s
++) {
117 if (yptol_mode
& yptol_newlock
) {
118 return (get_map_id(map_name
, n
));
131 * Initialize cross-process locks in memory-mapped file.
133 for (iiter
= 0; iiter
< MAXHASH
; iiter
++) {
134 if (rc
= mutex_init(&(shmlockarray
->locknode
[iiter
]),
135 USYNC_PROCESS
| LOCK_ROBUST
, 0)) {
140 "init_locks_mem():mutex_init():error=%d",
148 * EBUSY for all locks OK, it means another process
149 * has already initialized locks.
151 if ((ebusy_cnt
> 0) && (ebusy_cnt
!= MAXHASH
)) {
153 "%s inconsistent. Remove and restart NIS (YP).", LOCKFILE
);
162 char buff
[ sizeof (lockarray
) ];
163 int write_cnt
, lf_size
;
167 * Locking file initialization algorithm, with recovery mechanism.
168 * This mechanism has been devised to ensure proper creation
169 * of a memory-mapped lock file containing mutexes for robust,
170 * inter-process communication.
171 * File name is /var/run/yp_maplock (LOCKFILE). It might or might
175 * Try to open the file. If file doesn't exist, or size is too small,
176 * create/rewrite the file, m-map it into memory and initialize the
178 * If file exists and size is at least large enough, assume it's a
179 * good file, and m-map the lock structure directly to it.
181 * Recovery from inconsistent state is easy - simply delete the file
182 * and restart NIS (YP).
185 lockfile
= open(LOCKFILE
, O_RDWR
|O_CREAT
, 0600);
186 if (lockfile
!= -1) {
187 if (lockf(lockfile
, F_LOCK
, 0) == 0) {
188 if (fstat(lockfile
, &fdata
) == 0) {
189 lf_size
= fdata
.st_size
;
190 if (lf_size
< sizeof (lockarray
)) {
191 bzero(buff
, sizeof (buff
));
192 if ((write_cnt
= write(lockfile
, buff
,
193 sizeof (buff
)) != sizeof (buff
))) {
196 "write(%s) => errno=%d",
200 "write(%s) => %d!=%d: wrong number of bytes written.",
205 lockf(lockfile
, F_ULOCK
, 0);
212 "fstat(%s) => errno=%d", LOCKFILE
, errno
);
213 lockf(lockfile
, F_ULOCK
, 0);
219 "lockf(%s,F_LOCK) => errno=%d", LOCKFILE
, errno
);
225 "open(%s) => errno=%d", LOCKFILE
, errno
);
230 * File exists with correct size, is open, and we're holding
233 shmlockarray
= (lockarray
*)mmap((caddr_t
)0, sizeof (lockarray
),
234 PROT_READ
| PROT_WRITE
, MAP_SHARED
, lockfile
, 0);
235 if (shmlockarray
== MAP_FAILED
) {
236 syslog(LOG_ERR
, "mmap(%s) => errno=%d", LOCKFILE
, errno
);
237 lockf(lockfile
, F_ULOCK
, 0);
243 * If we wrote zeroes to the file, we also need to initialize
246 if (lf_size
< sizeof (lockarray
)) {
247 if (init_locks_mem() == FALSE
) {
248 lockf(lockfile
, F_ULOCK
, 0);
250 if (remove(LOCKFILE
) != 0) {
252 "remove(%s) => errno=%d: Please delete file.",
259 if (lockf(lockfile
, F_ULOCK
, 0) != 0) {
261 "lockf(%s,F_ULOCK) => errno=%d",
267 if (close(lockfile
) == 0) {
271 "close(%s) => errno=%d", LOCKFILE
, errno
);
277 * FUNCTION : lock_map()
279 * DESCRIPTION: Front end to the lock routine taking map name as argument.
283 * RETURNS : Same as lock_core
286 lock_map(char *mapname
)
290 hashval
= hash(mapname
);
292 return (lock_core(hashval
));
296 * FUNCTION : lock_core()
298 * DESCRIPTION: The core map locking function
300 * GIVEN : Map hash value
302 * RETURNS : 0 = Failure
306 lock_core(int hashval
)
311 * Robust, cross-process lock implementation
313 rc
= mutex_lock(&(shmlockarray
->locknode
[hashval
]));
318 * Previous lock owner died, resetting lock
319 * to recover from error.
321 rc
= mutex_consistent(
322 &(shmlockarray
->locknode
[hashval
]));
325 "mutex_consistent(): error=%d", rc
);
328 rc
= mutex_unlock(&(shmlockarray
->locknode
[hashval
]));
331 "mutex_unlock(): error=%d", rc
);
337 * Unrecoverable problem - nothing to do
338 * but exit YP and delete lock file.
341 "mutex_lock(): error=%d", rc
);
343 "Please restart NIS (ypstop/ypstart).");
344 if (remove(LOCKFILE
) != 0) {
346 "remove(%s) => errno=%d: Please delete file.",
351 rc
= mutex_lock(&(shmlockarray
->locknode
[hashval
]));
360 * FUNCTION : unlock_map()
362 * DESCRIPTION: Front end to the unlock routine taking map name as argument.
366 * RETURNS : Same as unlock_core
369 unlock_map(char *mapname
)
373 hashval
= hash(mapname
);
375 return (unlock_core(hashval
));
379 * FUNCTION : unlock_core()
381 * DESCRIPTION: The core map locking function
383 * GIVEN : Map hash value
385 * RETURNS : 0 = Failure
389 unlock_core(int hashval
)
393 rc
= mutex_unlock(&(shmlockarray
->locknode
[hashval
]));
396 "mutex_unlock(): error=%d", rc
);
398 "Please restart NIS (ypstop/ypstart).");
399 if (remove(LOCKFILE
) != 0) {
401 "remove(%s) => errno=%d: Please delete file.",