8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libnisdb / yptol / lock_update.c
blob1f5dcbe5eac0ad17473e2d3b6c62f5bfaba67b00
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
41 #include <unistd.h>
42 #include <syslog.h>
43 #include <sys/mman.h>
44 #include <thread.h>
45 #include <synch.h>
46 #include <ndbm.h>
47 #include <strings.h>
48 #include "ypsym.h"
49 #include "shim.h"
50 #include "yptol.h"
51 #include "../ldap_util.h"
53 #define LOCKFILE "/var/run/yp_mapupdate"
54 struct updatearray {
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;
66 static int lockfile;
68 bool_t
69 init_update_locks_mem()
71 int iiter, rc;
72 int ebusy_cnt = 0;
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) {
80 if (rc == EBUSY) {
81 ebusy_cnt++;
82 } else {
83 logmsg(MSG_NOTIMECHECK, LOG_ERR,
84 "init_update_locks_mem():mutex_init():"
85 "error=%d", rc);
86 return (FALSE);
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)",
98 LOCKFILE);
99 return (FALSE);
101 return (TRUE);
104 bool_t
105 init_update_lock_map()
107 char buff[ sizeof (updatearray) ];
108 int write_cnt, lf_size;
109 struct stat fdata;
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
117 * not exist.
119 * Algorithm:
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
122 * mutexes in it.
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))) {
139 if (write_cnt < 0) {
140 logmsg(MSG_NOTIMECHECK,
141 LOG_ERR,
142 "write(%s) => errno=%d",
143 LOCKFILE, errno);
144 } else {
145 logmsg(MSG_NOTIMECHECK,
146 LOG_ERR,
147 "write(%s) => %d!=%d: wrong number of bytes written",
148 LOCKFILE,
149 write_cnt,
150 sizeof (buff));
152 lockf(lockfile, F_ULOCK, 0);
153 close(lockfile);
154 return (FALSE);
157 } else {
158 logmsg(MSG_NOTIMECHECK, LOG_ERR,
159 "fstat(%s) => errno=%d", LOCKFILE, errno);
160 lockf(lockfile, F_ULOCK, 0);
161 close(lockfile);
162 return (FALSE);
164 } else {
165 logmsg(MSG_NOTIMECHECK, LOG_ERR,
166 "lockf(%s,F_LOCK) => errno=%d", LOCKFILE, errno);
167 close(lockfile);
168 return (FALSE);
170 } else {
171 logmsg(MSG_NOTIMECHECK, LOG_ERR,
172 "open(%s) => errno=%d", LOCKFILE, errno);
173 return (FALSE);
177 * File exists with correct size, is open, and we're holding
178 * the file lock.
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);
186 close(lockfile);
187 return (FALSE);
191 * If we wrote zeroes to the file, we also need to initialize
192 * the mutex locks.
194 if (lf_size < sizeof (updatearray)) {
195 if (init_update_locks_mem() == FALSE) {
196 lockf(lockfile, F_ULOCK, 0);
197 close(lockfile);
198 if (remove(LOCKFILE) != 0) {
199 logmsg(MSG_NOTIMECHECK, LOG_ERR,
200 "remove(%s) => errno=%d: Please delete file",
201 LOCKFILE, errno);
203 return (FALSE);
207 if (lockf(lockfile, F_ULOCK, 0) != 0) {
208 logmsg(MSG_NOTIMECHECK, LOG_ERR,
209 "lockf(%s,F_ULOCK) => errno=%d", LOCKFILE, errno);
210 close(lockfile);
211 return (FALSE);
214 if (close(lockfile) == 0) {
215 return (TRUE);
216 } else {
217 logmsg(MSG_NOTIMECHECK, LOG_ERR,
218 "close(%s) => errno=%d", LOCKFILE, errno);
219 return (FALSE);
223 suc_code
224 lock_map_update(map_ctrl *map)
226 int hashval = map->hash_val;
227 int rc;
230 * Robust, cross-process lock implementation
232 rc = mutex_lock(&(shmupdatearray->updatenode[hashval]));
233 while (rc != 0) {
234 switch (rc) {
235 case EOWNERDEAD:
237 * Previous lock owner died, resetting lock
238 * to recover from error.
240 rc = mutex_consistent(
241 &(shmupdatearray->updatenode[hashval]));
242 if (rc != 0) {
243 logmsg(MSG_NOTIMECHECK, LOG_ERR,
244 "mutex_consistent(): error=%d", rc);
245 return (FAILURE);
247 rc = mutex_unlock(
248 &(shmupdatearray->updatenode[hashval]));
249 if (rc != 0) {
250 logmsg(MSG_NOTIMECHECK, LOG_ERR,
251 "mutex_unlock(): error=%d", rc);
252 return (FAILURE);
254 break;
255 default:
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",
267 LOCKFILE, errno);
269 return (FAILURE);
271 rc = mutex_lock(&(shmupdatearray->updatenode[hashval]));
274 /* Success */
275 return (SUCCESS);
279 suc_code
280 unlock_map_update(map_ctrl *map)
282 int hashval = map->hash_val;
283 int rc;
285 rc = mutex_unlock(&(shmupdatearray->updatenode[hashval]));
286 if (rc != 0) {
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",
294 LOCKFILE, errno);
296 return (FAILURE);
299 /* Success */
300 return (SUCCESS);
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
313 bool_t
314 is_map_updating(map_ctrl *map)
316 int ret;
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]));
321 if (0 != ret) {
322 /* Didn't get the lock ... was already locked */
323 return (TRUE);
326 /* Didn't need the lock so free it again */
327 mutex_unlock(&(shmupdatearray->updatenode[map->hash_val]));
328 return (FALSE);
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;
346 int rc;
349 * Robust, cross-process lock implementation
351 * Keep trying until either lock is obtained or somebody else gets it.
353 while (1) {
354 rc = mutex_trylock(&(shmupdatearray->updatenode[hashval]));
356 switch (rc) {
358 case 0:
359 case EBUSY:
360 /* Either got it or somebody else has it */
361 return (rc);
363 case EOWNERDEAD:
365 * Previous lock owner died, resetting lock
366 * to recover from error.
368 rc = mutex_consistent(
369 &(shmupdatearray->updatenode[hashval]));
370 if (rc != 0) {
371 logmsg(MSG_NOTIMECHECK, LOG_ERR,
372 "mutex_consistent(): error=%d", rc);
373 return (rc);
375 rc = mutex_unlock(
376 &(shmupdatearray->updatenode[hashval]));
377 if (rc != 0) {
378 logmsg(MSG_NOTIMECHECK, LOG_ERR,
379 "mutex_unlock(): error=%d", rc);
380 return (rc);
382 break;
383 default:
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",
395 LOCKFILE, errno);
397 return (rc);