dscfglockd.c revision 570de38f63910201fdd77246630b7aa8f9dc5661
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <signal.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <memory.h>
#include <sys/pathconf.h>
#include <netdir.h>
#include <netconfig.h>
#include <sys/resource.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <locale.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#ifdef DEBUG
#else
#define DPF(m)
#endif
#ifdef TTY_MESSAGES
#define CLOSE_FD 3
#else
#define CLOSE_FD 0
#endif
#define MAX_LOCKQ 1024
#define MAX_DAEMONS 1024
#define MAX_LOCAL 1024
#define MAX_UNLOCK 32
#define MAX_TIMEOUTS 3
#define TIMEOUT_SECS 5
static char program[] = "dscfglockd";
static int debug;
static int lstate;
static int msgtrace;
struct lock_req {
int state; /* for write locks */
} lock_queue[MAX_LOCKQ];
struct unlock_s {
} unlock_buf[MAX_UNLOCK];
int next_req;
#define lock_wanted lock_queue[0]
long ticker = 1l;
#define ALIVE 0x10
#define READ_LOCK 0x11
#define WRITE_LOCK 0x12
#define UNLOCK 0x13
#define GRANTED 0x14
int next_q;
struct {
int nholders;
int state;
struct lockdaemon *remote_daemon;
} the_lock;
#define STATE_CLEAR 0
#define STATE_ASKED 1
#define STATE_OKAYED 2
#define STATE_WANTS 3
#define NORMAL_UNLOCK 0
#define FORCE_UNLOCK 1
struct lockdaemon {
int up;
long timeout;
int inuse;
int state;
unsigned short lock_port = CFG_SERVER_PORT;
int lock_soc = 0;
#define MAXIFS 32
static char *
{
switch (type) {
case LOCK_NOTLOCKED: return "NotLocked";
case LOCK_READ: return "Read";
case LOCK_WRITE: return "Write";
case LOCK_LOCKED: return "Locked";
case LOCK_LOCKEDBY: return "LockedBy";
case LOCK_STAT: return "Stat";
case LOCK_ACK: return "Ack";
default: return "*unknown*";
}
}
static char *
lockd_state(int state)
{
switch (state) {
case STATE_CLEAR: return "Clear";
case STATE_ASKED: return "Asked";
case STATE_OKAYED: return "Okayed";
case STATE_WANTS: return "Wants";
default: return "*unknown*";
}
}
static char *
{
switch (message) {
case ALIVE: return "Alive";
case READ_LOCK: return "ReadLock";
case WRITE_LOCK: return "WriteLock";
case UNLOCK: return "Unlock";
case GRANTED: return "Granted";
}
}
/*
* The following is stolen from autod_nfs.c
*/
static void
{
int sock;
int numifs;
char *buf;
int family;
#ifdef AF_INET6
#else
#endif
#ifdef DEBUG
perror("getmyaddrs(): socket");
#endif
return;
}
#ifdef DEBUG
perror("getmyaddrs(): SIOCGIFNUM");
#endif
}
#ifdef DEBUG
#endif
return;
}
#ifdef DEBUG
perror("getmyaddrs(): SIOCGIFCONF");
#endif
}
}
static int
{
int rc;
return (rc);
}
static int
{
}
static int
{
int n;
int retval = 0;
for (; n > 0; n--, ifr++) {
continue;
/* LINTED pointer alignment */
retval = 1;
/* it's me */
break;
}
}
return (retval);
}
static void
{
struct lock_msg message_buf;
int rc;
}
do {
if (rc == -1)
}
/*
* send an alive message to all configured daemons so that they can tell
* us if they are holding a write lock.
*/
static void
{
struct lockdaemon *ldp;
int i;
break;
}
}
/* find the lock daemon structure for a give daemon address */
static struct lockdaemon *
{
struct lockdaemon *ldp;
int i;
break;
return (ldp);
}
return (NULL);
}
/*
* a messge has been received from daemon, note this and if the daemon
* was previously dead and we have the write lock tell it that we do.
*/
static void
{
struct lockdaemon *ldp;
int i;
break;
"daemon restarted on %s\n",
goto come_up;
}
return;
}
}
/* new daemon has announced itself */
if (i < MAX_DAEMONS) {
} else {
/* problem, more daemons than expected */
i++;
}
}
static void
{
int i;
next_req--;
}
static void
take_lock(int ackmessage)
{
}
static void
{
struct lockdaemon *ldp;
int i;
int wait = 0;
return;
break;
wait = 1;
break;
}
}
}
}
static void
{
struct lockdaemon *ldp;
/* if we already own the lock, throw the msg away */
return;
}
/*
* If the current lock isn't a write lock and we're not
* asking for one
* -OR-
* The current lock is a write lock and it's not owned by us
* -THEN-
* send back an unlocked message.
*/
return;
}
}
}
static int
try_lock()
{
struct lockdaemon *ldp;
int i;
case LOCK_READ:
break;
}
/* write lock has to wait */
break;
case LOCK_WRITE:
/* lock has to wait until write lock is cleared */
break;
case LOCK_NOTLOCKED:
return (1);
}
/* tell everyone I'm locking */
i++, ldp++) {
break;
}
}
return (0);
} else {
/* okay to remote */
}
break;
default:
break;
}
return (0);
}
static void
{
if (next_req < 1)
return; /* no locks queued */
while (try_lock())
;
}
static int
lock_sort(const void *a, const void *b)
{
}
static void
{
int i;
struct lockdaemon *ldp;
/* first check if new lock matches current lock */
/* remote daemon missed locked message */
return;
}
/* next search queue to check for duplicate */
return;
}
/*
* It's a new lock request. Are we in the middle of
* obtaining one for ourselves?
*/
/* did a higher priority request just come in? */
/* requeue our request */
/* let the other lockds know */
i++, ldp++) {
break;
}
}
}
}
lrp = lock_queue;
if (addr) {
}
if (next_req > 1)
}
static void
{
char *lt = "Unknown";
struct lockdaemon *ldp;
int i;
case LOCK_NOTLOCKED:
lt = "not locked";
break;
case LOCK_READ:
lt = "read locked";
break;
case LOCK_WRITE:
lt = "write locked";
break;
}
the_lock.holding_pid[i]);
}
for (i = 0; i < next_req; i++) {
}
break;
}
}
static int
{
int i;
if (!pid) {
return (0);
}
i++, bufp++) {
/* throw message away */
#ifdef DEBUG
"duplicate '%d' request received from %d",
#endif
return (1);
}
}
/* add it to the list */
sizeof (unlock_buf) - sizeof (struct unlock_s));
return (0);
}
static void
{
}
} else {
}
}
static void
{
/* make sure remote knows we are alive */
/* clear out pid as it is meaningless on this node */
}
static void
{
int i;
int diff;
/* search queue to delete ungranted locks */
diff = 0;
diff = 1;
diff = 1;
if (!diff)
continue;
xrp++;
}
}
static void
xxunlock()
{
}
static void
{
struct lockdaemon *ldp;
int i;
return;
}
/* delete reference to pid of reading process */
break;
}
}
}
return;
} else {
/* LOCK_WRITE */
return;
break;
}
}
xxunlock();
}
static void
{
int i;
/* search queue to check for ungranted lock */
return;
}
}
if (addr_is_holder(order)) {
xxunlock();
}
}
static void
{
case LOCK_NOTLOCKED:
break;
case LOCK_READ:
break;
case LOCK_WRITE:
break;
}
}
/* ARGSUSED */
static void
{
int i;
struct lockdaemon *ldp;
ticker++;
/*
* tell any other daemon that has a lock request in our queue that
* this daemon is still alive.
*/
}
/*
* if a remote daemon holds the lock, check it is still alive and
* if the remote daemon is sent it a grant message in case the
* remote daemon missed our original grant.
*/
if (the_lock.remote_daemon) {
xxunlock();
} else {
}
}
/*
* check for response from daemons preventing this daemon
* from taking a write lock by not sending a grant message.
* if the remote daemon is alive send another lock request,
* otherwise mark it as dead.
* send alive message to any live remote daemons if this
* daemon has the write lock.
*/
if (lstate) {
(void) printf(" holding pid:");
}
(void) printf("\n");
}
break;
if (lstate) {
}
if (lockdaemon_dead(ldp)) {
continue;
}
continue;
}
}
}
static void
{
int localhost;
if (localhost) {
"%19.19s recv %-9.9s from %s (%ld)\n", ctime(&t),
} else {
"%19.19s recv %-9.9s from %s order %d (%ld)\n",
}
}
if (!localhost)
else
switch (message) {
case ALIVE:
/* do nothing, general "not localhost" code above does this */
break;
case UNLOCK:
break;
case GRANTED:
break;
case WRITE_LOCK:
break;
case READ_LOCK:
case LOCK_READ:
break;
case LOCK_WRITE:
break;
case LOCK_NOTLOCKED:
}
break;
case LOCK_LOCKEDBY:
break;
case LOCK_STAT:
lock_stat();
break;
case LOCK_ACK:
/* throw message away -- this is an error to receive */
break;
}
}
/*
* unqueue any locks asked for by pid and unlock any locks held by pid.
*/
static void
{
}
/*
* Check for exit or exec of client processes.
* The lock protecting the processes pid in the lockfile will
* be removed by the kernel when a client exits or execs.
*/
static void
{
int i, x;
for (i = 0; (x = cfg_filelock(i, 0)) != CFG_LF_EOF; i++) {
if (x == CFG_LF_AGAIN)
continue; /* can't take lock, must be still alive */
cfg_readpid(i, &pid);
cfg_writepid(i, (pid_t)0);
(void) cfg_fileunlock(i);
}
}
static void
{
char host[1024];
int port;
int i;
struct lockdaemon *ldp;
program, "localhost");
exit(1);
}
(void) endhostent();
return;
}
if (exe) {
"%s: Can't open config program\n", program);
exit(1);
}
} else {
program);
exit(1);
}
}
ldp = daemon_list;
continue;
if (i == 1) {
} else {
continue;
}
}
continue;
}
continue;
}
ldp++;
}
if (exe)
else
(void) endhostent();
}
static void
usage()
{
exit(1);
}
static void
unexpected(int sig)
{
}
static void
{
(void) unlink(CFG_PIDFILE);
sig);
exit(0);
}
static void
{
#endif
int c, i, x;
int rc;
int exe = 0;
/*
* Fork off a child that becomes the daemon.
*/
#ifndef TTY_MESSAGES
exit(0);
else if (rc < 0) {
exit(1);
}
#endif
/*
* In child - become daemon.
*/
/* use closefrom(3C) from PSARC/2000/193 when possible */
#else
(void) close(i);
#endif
#ifdef DEBUG
#ifndef TTY_MESSAGES
(void) dup(0);
(void) dup(0);
#endif
#endif
(void) close(0);
if (debugfile) {
ctime(&t));
}
}
(void) setpgrp();
/*
* Catch as unexpected all signals apart from SIGTERM.
*/
for (i = 1; i < _sys_nsig; i++)
(void) sigset(i, unexpected);
switch (c) {
case 'd':
debug = 1;
break;
case 'e':
exe = 1;
if (cp) {
usage();
}
break;
case 'f':
if (cp) {
usage();
}
break;
default:
usage();
break;
}
}
exit(1);
}
/*
* if (lockdaemonalive()) {
* (void) fprintf(stderr, "%s: %s\n", program,
* gettext("There is already a live lockdaemon"));
* exit(1);
* }
*/
exit(1);
}
/* order should be set to node number within cluster */
order = cfg_iscluster();
cfg_lfinit();
if (!order) {
if (debugfile) {
"is 0 -- changing randomly to %d\n", order);
}
}
c = 0;
for (i = 0; (x = cfg_filelock(i, 0)) != CFG_LF_EOF; i++) {
if (x == CFG_LF_AGAIN) {
cfg_readpid(i, &pid);
if (c++ == 0)
"init .dscfg.lck slot %d pid %d locked",
i, pid);
continue; /* can't take lock, must be still alive */
}
cfg_writepid(i, 0);
(void) cfg_fileunlock(i);
}
next_q = 0;
gettext("failed to create socket"));
perror("socket");
exit(1);
}
if (rc < 0) {
perror("bind");
exit(1);
}
perror("getsockname");
/*
* wait 2 time outs before allowing a lock to find if someone else
* currently has the lock.
*/
}
#ifdef lint
int
#else
int
#endif
{
struct lock_msg message_buf;
int addrlen;
int rc;
int x = 1; /* kludge to stop warnings from compiler */
CRIT_BEGIN();
while (x) {
CRIT_END();
CRIT_BEGIN();
if (rc == sizeof (message_buf))
else
/* if we own the lock, check to see if the process died */
}
CRIT_END();
return (0);
}