summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ypcmd/shared/lockmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/ypcmd/shared/lockmap.c')
-rw-r--r--usr/src/cmd/ypcmd/shared/lockmap.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/usr/src/cmd/ypcmd/shared/lockmap.c b/usr/src/cmd/ypcmd/shared/lockmap.c
new file mode 100644
index 0000000000..209ecad5a1
--- /dev/null
+++ b/usr/src/cmd/ypcmd/shared/lockmap.c
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/mman.h>
+#include <thread.h>
+#include <synch.h>
+#include <ndbm.h>
+#include "../ypsym.h"
+#include "../ypdefs.h"
+
+/*
+ * These routines provide mutual exclusion between ypserv and ypxfr.
+ * Mutual exclusion is needed so that ypxfr doesn't try to rename
+ * dbm files while ypserv is trying to open them. After ypserv has
+ * opened a dbm file, it is safe to rename it because ypserv still
+ * has access to the file through its file descriptor.
+ */
+
+#define LOCKFILE "/var/run/yp_maplock"
+struct lockarray {
+ mutex_t locknode[MAXHASH];
+};
+typedef struct lockarray lockarray;
+
+/*
+ * Cross-process robust mutex locks.
+ * Provide synchronization between YP processes
+ * by implementing an exclusive locking mechanism
+ * via a memory-mapped file.
+ */
+static struct lockarray *shmlockarray;
+static int lockfile;
+
+int
+hash(char *s)
+{
+ int n = 0;
+ int i;
+
+ for (i = 1; *s; i += 10, s++) {
+ n += i * (*s);
+ }
+ n %= MAXHASH;
+ return (n);
+}
+
+bool
+init_locks_mem()
+{
+ int iiter, rc;
+ int ebusy_cnt = 0;
+
+ /*
+ * Initialize cross-process locks in memory-mapped file.
+ */
+ for (iiter = 0; iiter < MAXHASH; iiter++) {
+ if (rc = mutex_init(&(shmlockarray->locknode[iiter]),
+ USYNC_PROCESS_ROBUST, 0)) {
+ if (rc == EBUSY) {
+ ebusy_cnt++;
+ } else {
+ syslog(LOG_ERR,
+ "init_locks_mem():mutex_init():error=%d",
+ rc);
+ return (FALSE);
+ }
+ }
+ }
+
+ /*
+ * EBUSY for all locks OK, it means another process
+ * has already initialized locks.
+ */
+ if ((ebusy_cnt > 0) && (ebusy_cnt != MAXHASH)) {
+ syslog(LOG_ERR,
+ "%s inconsistent. Remove and restart NIS (YP).", LOCKFILE);
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool
+init_lock_map()
+{
+ char buff[ sizeof (lockarray) ];
+ int write_cnt, lf_size;
+ struct stat fdata;
+
+ /*
+ * Locking file initialization algorithm, with recovery mechanism.
+ * This mechanism has been devised to ensure proper creation
+ * of a memory-mapped lock file containing mutexes for robust,
+ * inter-process communication.
+ * File name is /var/run/yp_maplock (LOCKFILE). It might or might
+ * not exist.
+ *
+ * Algorithm:
+ * Try to open the file. If file doesn't exist, or size is too small,
+ * create/rewrite the file, m-map it into memory and initialize the
+ * mutexes in it.
+ * If file exists and size is at least large enough, assume it's a
+ * good file, and m-map the lock structure directly to it.
+ *
+ * Recovery from inconsistent state is easy - simply delete the file
+ * and restart NIS (YP).
+ */
+
+ lockfile = open(LOCKFILE, O_RDWR|O_CREAT, 0600);
+ if (lockfile != -1) {
+ if (lockf(lockfile, F_LOCK, 0) == 0) {
+ if (fstat(lockfile, &fdata) == 0) {
+ lf_size = fdata.st_size;
+ if (lf_size < sizeof (lockarray)) {
+ bzero(buff, sizeof (buff));
+ if ((write_cnt = write(lockfile, buff,
+ sizeof (buff)) != sizeof (buff))) {
+ if (write_cnt < 0) {
+ syslog(LOG_ERR,
+ "write(%s) => errno=%d",
+ LOCKFILE, errno);
+ } else {
+ syslog(LOG_ERR,
+ "write(%s) => %d!=%d: wrong number of bytes written.",
+ LOCKFILE,
+ write_cnt,
+ sizeof (buff));
+ }
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+ }
+ } else {
+ syslog(LOG_ERR,
+ "fstat(%s) => errno=%d", LOCKFILE, errno);
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+ } else {
+ syslog(LOG_ERR,
+ "lockf(%s,F_LOCK) => errno=%d", LOCKFILE, errno);
+ close(lockfile);
+ return (FALSE);
+ }
+ } else {
+ syslog(LOG_ERR,
+ "open(%s) => errno=%d", LOCKFILE, errno);
+ return (FALSE);
+ }
+
+ /*
+ * File exists with correct size, is open, and we're holding
+ * the file lock.
+ */
+ shmlockarray = (lockarray *)mmap((caddr_t) 0, sizeof (lockarray),
+ PROT_READ | PROT_WRITE, MAP_SHARED, lockfile, 0);
+ if (shmlockarray == MAP_FAILED) {
+ syslog(LOG_ERR, "mmap(%s) => errno=%d", LOCKFILE, errno);
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+
+ /*
+ * If we wrote zeroes to the file, we also need to initialize
+ * the mutex locks.
+ */
+ if (lf_size < sizeof (lockarray)) {
+ if (init_locks_mem() == FALSE) {
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (FALSE);
+ }
+ }
+
+ if (lockf(lockfile, F_ULOCK, 0) != 0) {
+ syslog(LOG_ERR,
+ "lockf(%s,F_ULOCK) => errno=%d",
+ LOCKFILE, errno);
+ close(lockfile);
+ return (FALSE);
+ }
+
+ if (close(lockfile) == 0) {
+ return (TRUE);
+ } else {
+ syslog(LOG_ERR,
+ "close(%s) => errno=%d", LOCKFILE, errno);
+ return (FALSE);
+ }
+}
+
+/*
+ * FUNCTION : lock_map()
+ *
+ * DESCRIPTION: Front end to the lock routine taking map name as argument.
+ *
+ * GIVEN : Map name.
+ *
+ * RETURNS : Same as lock_core
+ */
+int
+lock_map(char *mapname)
+{
+ int hashval;
+
+ hashval = hash(mapname);
+
+ return( lock_core(hashval));
+}
+
+/*
+ * FUNCTION : lock_core()
+ *
+ * DESCRIPTION: The core map locking function
+ *
+ * GIVEN : Map hash value
+ *
+ * RETURNS : 0 = Failure
+ * 1 = Success
+ */
+int
+lock_core(int hashval)
+{
+ int rc;
+
+ /*
+ *Robust, cross-process lock implementation
+ */
+ rc = mutex_lock(&(shmlockarray->locknode[hashval]));
+ while (rc != 0) {
+ switch (rc) {
+ case EOWNERDEAD:
+ /*
+ * Previows lock owner died, resetting lock
+ * to recover from error.
+ */
+ rc = mutex_init(&(shmlockarray->locknode[hashval]),
+ USYNC_PROCESS_ROBUST, 0);
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_init(): error=%d", rc);
+ return (0);
+ }
+ rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_unlock(): error=%d", rc);
+ return (0);
+ }
+ break;
+ default:
+ /*
+ * Unrecoverable problem - nothing to do
+ * but exit YP and delete lock file.
+ */
+ syslog(LOG_ERR,
+ "mutex_lock(): error=%d", rc);
+ syslog(LOG_ERR,
+ "Please restart NIS (ypstop/ypstart).");
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (0);
+ }
+ rc = mutex_lock(&(shmlockarray->locknode[hashval]));
+ }
+
+ /* Success */
+ return (1);
+}
+
+
+/*
+ * FUNCTION : unlock_map()
+ *
+ * DESCRIPTION: Front end to the unlock routine taking map name as argument.
+ *
+ * GIVEN : Map name.
+ *
+ * RETURNS : Same as unlock_core
+ */
+int
+unlock_map(char *mapname)
+{
+ int hashval;
+
+ hashval = hash(mapname);
+
+ return( unlock_core( hashval ));
+}
+
+/*
+ * FUNCTION : unlock_core()
+ *
+ * DESCRIPTION: The core map locking function
+ *
+ * GIVEN : Map hash value
+ *
+ * RETURNS : 0 = Failure
+ * 1 = Success
+ */
+int
+unlock_core(int hashval)
+{
+ int rc;
+
+ rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_unlock(): error=%d", rc);
+ syslog(LOG_ERR,
+ "Please restart NIS (ypstop/ypstart).");
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (0);
+ }
+
+ /* Success */
+ return (1);
+}