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 2015 Gary Mills
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
29 * DESCRIPTION: Contains code supporting the 'update in progress' flag. This is
30 * a near copy of lock flag code (in
31 * usr/src/cmd/ypcmd/shared/lockmp.c) If we implement a clean
32 * version of the locking code this file will probably disappear.
34 * These locks are held while a map is being updated from the
35 * DIT. They prevent a second update being started while this is
36 * in progress. This is independant from the `lockmap` mechanism
37 * which protects maps, generally for a much shorter period,
38 * while their control structures are modified.
51 #include "../ldap_util.h"
53 #define LOCKFILE "/var/run/yp_mapupdate"
55 mutex_t updatenode
[MAXHASH
];
57 typedef struct updatearray updatearray
;
60 * Cross-process robust mutex locks.
61 * Provide synchronization between YP processes
62 * by implementing an exclusive locking mechanism
63 * via a memory-mapped file.
65 static struct updatearray
*shmupdatearray
;
69 init_update_locks_mem()
75 * Initialize cross-process locks in memory-mapped file.
77 for (iiter
= 0; iiter
< MAXHASH
; iiter
++) {
78 if ((rc
= mutex_init(&(shmupdatearray
->updatenode
[iiter
]),
79 USYNC_PROCESS
| LOCK_ROBUST
, 0)) != 0) {
83 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
84 "init_update_locks_mem():mutex_init():"
92 * EBUSY for all locks OK, it means another process
93 * has already initialized locks.
95 if ((ebusy_cnt
> 0) && (ebusy_cnt
!= MAXHASH
)) {
96 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
97 "%s inconsistent. Remove this file and restart NIS (YP)",
105 init_update_lock_map()
107 char buff
[ sizeof (updatearray
) ];
108 int write_cnt
, lf_size
;
112 * Locking file initialization algorithm, with recovery mechanism.
113 * This mechanism has been devised to ensure proper creation
114 * of a memory-mapped lock file containing mutexes for robust,
115 * inter-process communication.
116 * File name is /var/run/yp_mapupate (LOCKFILE). It might or might
120 * Try to open the file. If file doesn't exist, or size is too small,
121 * create/rewrite the file, m-map it into memory and initialize the
123 * If file exists and size is at least large enough, assume it's a
124 * good file, and m-map the lock structure directly to it.
126 * Recovery from inconsistent state is easy - simply delete the file
127 * and restart NIS (YP).
130 lockfile
= open(LOCKFILE
, O_RDWR
|O_CREAT
, 0600);
131 if (lockfile
!= -1) {
132 if (lockf(lockfile
, F_LOCK
, 0) == 0) {
133 if (fstat(lockfile
, &fdata
) == 0) {
134 lf_size
= fdata
.st_size
;
135 if (lf_size
< sizeof (updatearray
)) {
136 bzero(buff
, sizeof (buff
));
137 if ((write_cnt
= write(lockfile
, buff
,
138 sizeof (buff
)) != sizeof (buff
))) {
140 logmsg(MSG_NOTIMECHECK
,
142 "write(%s) => errno=%d",
145 logmsg(MSG_NOTIMECHECK
,
147 "write(%s) => %d!=%d: wrong number of bytes written",
152 lockf(lockfile
, F_ULOCK
, 0);
158 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
159 "fstat(%s) => errno=%d", LOCKFILE
, errno
);
160 lockf(lockfile
, F_ULOCK
, 0);
165 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
166 "lockf(%s,F_LOCK) => errno=%d", LOCKFILE
, errno
);
171 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
172 "open(%s) => errno=%d", LOCKFILE
, errno
);
177 * File exists with correct size, is open, and we're holding
180 shmupdatearray
= (updatearray
*)mmap((caddr_t
)0, sizeof (updatearray
),
181 PROT_READ
| PROT_WRITE
, MAP_SHARED
, lockfile
, 0);
182 if (shmupdatearray
== MAP_FAILED
) {
183 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
184 "mmap(%s) => errno=%d", LOCKFILE
, errno
);
185 lockf(lockfile
, F_ULOCK
, 0);
191 * If we wrote zeroes to the file, we also need to initialize
194 if (lf_size
< sizeof (updatearray
)) {
195 if (init_update_locks_mem() == FALSE
) {
196 lockf(lockfile
, F_ULOCK
, 0);
198 if (remove(LOCKFILE
) != 0) {
199 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
200 "remove(%s) => errno=%d: Please delete file",
207 if (lockf(lockfile
, F_ULOCK
, 0) != 0) {
208 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
209 "lockf(%s,F_ULOCK) => errno=%d", LOCKFILE
, errno
);
214 if (close(lockfile
) == 0) {
217 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
218 "close(%s) => errno=%d", LOCKFILE
, errno
);
224 lock_map_update(map_ctrl
*map
)
226 int hashval
= map
->hash_val
;
230 * Robust, cross-process lock implementation
232 rc
= mutex_lock(&(shmupdatearray
->updatenode
[hashval
]));
237 * Previous lock owner died, resetting lock
238 * to recover from error.
240 rc
= mutex_consistent(
241 &(shmupdatearray
->updatenode
[hashval
]));
243 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
244 "mutex_consistent(): error=%d", rc
);
248 &(shmupdatearray
->updatenode
[hashval
]));
250 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
251 "mutex_unlock(): error=%d", rc
);
257 * Unrecoverable problem - nothing to do
258 * but exit YP and delete lock file.
260 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
261 "mutex_lock(): error=%d", rc
);
262 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
263 "Please restart NIS (ypstop/ypstart)");
264 if (remove(LOCKFILE
) != 0) {
265 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
266 "remove(%s) => errno=%d: Please delete file",
271 rc
= mutex_lock(&(shmupdatearray
->updatenode
[hashval
]));
280 unlock_map_update(map_ctrl
*map
)
282 int hashval
= map
->hash_val
;
285 rc
= mutex_unlock(&(shmupdatearray
->updatenode
[hashval
]));
287 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
288 "mutex_unlock(): error=%d", rc
);
289 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
290 "Please restart NIS (ypstop/ypstart)");
291 if (remove(LOCKFILE
) != 0) {
292 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
293 "remove(%s) => errno=%d: Please delete file",
304 * FUNCTION : is_map_updating()
306 * DESCRIPTION: Determines if a map is currently locked for update
308 * GIVEN : Pointer to map_ctrl structure
310 * RETURNS : TRUE = Map is locked
311 * FALSE = Map is not locked
314 is_map_updating(map_ctrl
*map
)
318 /* It appears not to be possible to just read a mutex. Try to lock it */
319 ret
= mutex_trylock(&(shmupdatearray
->updatenode
[map
->hash_val
]));
322 /* Didn't get the lock ... was already locked */
326 /* Didn't need the lock so free it again */
327 mutex_unlock(&(shmupdatearray
->updatenode
[map
->hash_val
]));
332 * FUNCTION : try_lock_map_update()
334 * DESCRIPTION: Tries to to lock a map for update.
336 * GIVEN : Pointer to the map to lock
338 * RETURNS : 0 = The map is now locked
339 * EBUSY = The map was already locked lock not obtained.
340 * Other = There was an error
343 try_lock_map_update(map_ctrl
*map
)
345 int hashval
= map
->hash_val
;
349 * Robust, cross-process lock implementation
351 * Keep trying until either lock is obtained or somebody else gets it.
354 rc
= mutex_trylock(&(shmupdatearray
->updatenode
[hashval
]));
360 /* Either got it or somebody else has it */
365 * Previous lock owner died, resetting lock
366 * to recover from error.
368 rc
= mutex_consistent(
369 &(shmupdatearray
->updatenode
[hashval
]));
371 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
372 "mutex_consistent(): error=%d", rc
);
376 &(shmupdatearray
->updatenode
[hashval
]));
378 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
379 "mutex_unlock(): error=%d", rc
);
385 * Unrecoverable problem - nothing to do
386 * but exit YP and delete lock file.
388 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
389 "mutex_lock(): error=%d", rc
);
390 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
391 "Please restart NIS (ypstop/ypstart)");
392 if (remove(LOCKFILE
) != 0) {
393 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
394 "remove(%s) => errno=%d: Please delete file",