Files
Arquivotheca.SunOS-4.1.4/etc/rpc.lockd/prot_proc.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

907 lines
20 KiB
C

#ifndef lint
static char sccsid[] = "@(#)prot_proc.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* prot_proc.c
* consists all local, remote, and continuation routines:
* local_xxx, remote_xxx, and cont_xxx.
*/
#include <stdio.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include "prot_lock.h"
#include "lockf.h"
remote_result nlm_result; /* local nlm result */
remote_result *nlm_resp = &nlm_result; /* ptr to klm result */
remote_result *get_res();
remote_result *remote_cancel();
remote_result *remote_lock();
remote_result *remote_test();
remote_result *remote_unlock();
remote_result *local_test();
remote_result *local_lock();
remote_result *local_unlock();
remote_result *cont_test();
remote_result *cont_lock();
remote_result *cont_unlock();
remote_result *cont_cancel();
remote_result *cont_reclaim();
extern msg_entry *retransmitted();
extern int debug, errno;
extern msg_entry *msg_q;
extern bool_t obj_cmp();
extern int obj_copy();
extern struct reclock *find_block_req();
extern void dequeue_block_req();
extern char *xmalloc();
extern struct fd_table *fd_table;
static void remove_fd();
static int used_fd = 0;
static int lastfd = 0;
print_fdtable()
{
struct fd_table *t;
int i, j;
printf("In print_fdtable()....used_fd=%d, lastfd=%d\n",
used_fd, lastfd);
for (t = fd_table, j = 0; j <= lastfd; t++, j++) {
if (t->fd) {
printf("ID=%d\n", t->fd);
for (i = 0; i < t->fh.n_len; i++) {
printf("%02x", (t->fh.n_bytes[i] & 0xff));
}
printf("\n");
}
}
}
/*
* Remove the fd_table entry for the given file descriptor and put it on
* the free list.
*/
static void
remove_fd(fd)
int fd;
{
struct fd_table *t;
int i;
if (debug)
printf("remove_fd(%d) ...\n", fd);
if (fd == 0) {
printf("rpc.lockd: trying to close fd 0.\n");
return;
}
t = &fd_table[fd];
if (t->fh.n_len) {
if (debug) {
for (i = 0; i < t->fh.n_len; i++) {
printf("%02x",
(t->fh.n_bytes[i] & 0xff));
}
printf("\n");
}
bzero(t->fh.n_bytes, sizeof (t->fh.n_bytes));
xfree(&(t->fh.n_bytes));
t->fh.n_len = 0;
t->fd = 0;
used_fd--;
if (fd == lastfd)
lastfd--;
}
if (debug)
print_fdtable();
}
int
get_fd(a)
struct reclock *a;
{
struct fd_table *t;
int fd, cmd, i;
int j;
struct {
char *fh;
int filemode;
} fa;
if (debug) {
printf("enter get_fd ....\n");
}
for (t = fd_table, j = 0; j <= lastfd; t++, j++) {
if (t->fd && obj_cmp(&(t->fh), &(a->lck.fh))) {
if (debug) {
printf("Found fd entry : a = ");
for (i = 0; i < a->lck.fh.n_len; i++) {
printf("%02x",
(a->lck.fh.n_bytes[i] & 0xff));
}
printf("\nfd_table->fh = ");
for (i = 0; i < 32; i++) {
printf("%02x",
(t->fh.n_bytes[i] & 0xff));
}
printf("\n");
}
return (t->fd);
}
}
/*
* convert fh to fd
*/
cmd = F_CNVT;
fa.fh = a->lck.fh.n_bytes;
if (debug) {
printf("Convert fd entry : ");
for (i = 0; i < a->lck.fh.n_len; i++) {
printf("%02x", (a->lck.fh.n_bytes[i] & 0xff));
}
printf("\n");
}
fa.filemode = O_RDWR;
{
int err = 0;
if ((fd = fcntl(0, cmd, &fa)) == -1) {
err = errno;
}
if (err == EROFS && a->exclusive == 0) {
fa.filemode = O_RDONLY;
fa.fh = a->lck.fh.n_bytes;
err = 0;
if ((fd = fcntl(0, cmd, &fa)) == -1) {
err = errno;
}
}
if (err != 0) {
errno = err;
perror("fcntl");
printf("rpc.lockd: unable to do cnvt.\n");
if ((errno == ENOLCK)||(errno == ESTALE))
return (-1);
else
return (-2);
}
}
if (lastfd < fd)
lastfd = fd;
t = &fd_table[fd];
obj_copy(&t->fh, &a->lck.fh);
t->fd = fd;
used_fd++;
if (debug)
print_fdtable();
return (fd);
}
/*
* If *grant_lock_flag is FALSE: make a local (server-side) lock request
* for the given lock. Sets *grant_lock_flag to TRUE if the request causes
* one or more blocked locks to be granted. Returns the status of the
* request (success, denied, etc.). Note: if *grant_lock_flag gets set to
* TRUE, the caller is expected to call again with *grant_lock_flag left as
* TRUE. It is important that the caller not process any additional RPC
* requests before making this second call (e.g., to avoid possible file
* descriptor leaks).
*
* If *grant_lock_flag is TRUE: query the kernel for all newly granted
* locks and inform the appropriate clients of the locks' new status.
* Returns NULL.
*/
remote_result *
local_lock(a, grant_lock_flag)
struct reclock *a;
int *grant_lock_flag;
{
int cmd;
remote_result *remote_grant();
struct reclock grant_lock;
static struct eflock ld;
static int fd;
/* if there r locks to be granted, keep calling fcntl() to get */
/* info on these locks & send each of these granted locks to */
/* the respective lock mgr, NOTICE that only locks that r held */
/* by lockmgr is being replied here, granting of local blocking */
/* locks is handled by the kernel. */
if (*grant_lock_flag) {
if (debug)
printf("granting locks...\n");
ld.l_type = F_RDLCK;
ld.l_xxx = GRANT_LOCK_FLAG;
while (fcntl(fd, F_RSETLKW, &ld) != -1) {
grant_lock.block = TRUE;
grant_lock.exclusive = FALSE;
grant_lock.lck.lox.base = ld.l_start;
grant_lock.lck.lox.length = ld.l_len;
grant_lock.lck.lox.pid = ld.l_pid;
grant_lock.lck.lox.rpid = ld.l_rpid;
grant_lock.lck.lox.rsys = ld.l_rsys;
grant_lock.lck.lox.type = ld.l_type;
grant_lock.rel = 0;
/* send this granted lock to the respective remote */
/* lock mgr */
remote_grant(&grant_lock, MSG);
/* no more granted locks, quit */
if (ld.l_xxx < 0) break;
ld.l_type = F_RDLCK;
ld.l_xxx = GRANT_LOCK_FLAG;
}
*grant_lock_flag = FALSE;
return(NULL);
}
/*
* convert fh to fd
*/
if ((fd = get_fd(a)) < 0) {
if (fd == -1)
nlm_resp->lstat = nlm_denied_nolocks;
else
nlm_resp->lstat = denied;
return (nlm_resp);
}
/*
* set the lock
*/
if (debug) {
printf("enter local_lock...FD=%d\n", fd);
pr_lock(a);
(void) fflush(stdout);
}
if (a->block)
cmd = F_RSETLKW;
else
cmd = F_RSETLK;
if (a->exclusive)
ld.l_type = F_WRLCK;
else
ld.l_type = F_RDLCK;
ld.l_whence = 0;
ld.l_start = a->lck.lox.base;
ld.l_len = a->lck.lox.length;
ld.l_pid = a->lck.lox.pid;
ld.l_rpid = a->lck.lox.rpid;
ld.l_rsys = a->lck.lox.rsys;
ld.l_xxx = 0;
if (debug) {
printf("ld.l_start=%d ld.l_len=%d ld.l_rpid=%d ld.l_rsys=%x\n",
ld.l_start, ld.l_len, ld.l_rpid, ld.l_rsys);
}
if (fcntl(fd, cmd, &ld) == -1) {
if (errno == EINTR) {
nlm_resp->lstat = blocking;
a->w_flag = 1;
} else if (errno == EDEADLK) {
perror("fcntl");
nlm_resp->lstat = deadlck;
a->w_flag = 0;
} else if (errno == ENOLCK) {
perror("fcntl");
printf("rpc.lockd: out of lock.\n");
nlm_resp->lstat = nlm_denied_nolocks;
} else if (((cmd == F_SETLK) || (cmd == F_RSETLK)) && (errno == EACCES)) {
nlm_resp->lstat = denied;
} else {
perror("fcntl");
printf("rpc.lockd: unable to set a lock. \n");
nlm_resp->lstat = denied;
}
} else
nlm_resp->lstat = nlm_granted;
if (ld.l_xxx == GRANT_LOCK_FLAG)
*grant_lock_flag = TRUE;
return (nlm_resp);
}
/*
* choice == RPC; rpc calls to remote;
* choice == MSG; msg passing calls to remote;
*/
remote_result *
remote_lock(a, choice)
struct reclock *a;
int choice;
{
if (debug) {
printf("enter remote_lock\n");
pr_lock(a);
(void) fflush(stdout);
}
if (choice == MSG) { /* msg passing */
if (nlm_call(NLM_LOCK_MSG, a, 0) == -1)
a->rel = 1;
}
return(NULL);
}
/*
* If *grant_lock_flag is FALSE: make a local (server-side) unlock request
* for the given lock. Sets *grant_lock_flag to TRUE if the request causes
* one or more blocked locks to be granted. Returns the status of the
* request (success, denied, etc.). If this lock is the last remote lock
* for the file, the file is closed and its descriptor is removed from the
* descriptor table. Note: if *grant_lock_flag gets set to TRUE, the
* caller is expected to call again with *grant_lock_flag left as TRUE. It
* is important that the caller not process any additional RPC requests
* before making this second call (e.g., to avoid possible file descriptor
* leaks).
*
* If *grant_lock_flag is TRUE: query the kernel for all newly granted
* locks and inform the appropriate clients of the locks' new status.
* Returns NULL.
*/
remote_result *
local_unlock(a, grant_lock_flag)
struct reclock *a;
int *grant_lock_flag;
{
int cmd;
static struct eflock ld;
remote_result *remote_grant();
struct reclock grant_lock;
static int fd;
if (debug)
printf("enter local_unlock...................\n");
/* if there r locks to be granted, keep calling fcntl() to get */
/* info on these locks & send each of these granted locks to */
/* the respective lock mgr, NOTICE that only locks that r held */
/* by lockmgr is being replied here, granting of local blocking */
/* locks is handled by the kernel. */
if (*grant_lock_flag) {
if (debug)
printf("granting locks...\n");
ld.l_type = F_UNLCK;
ld.l_xxx = GRANT_LOCK_FLAG;
while (fcntl(fd, F_RSETLKW, &ld) != -1) {
grant_lock.block = TRUE;
grant_lock.exclusive = TRUE;
grant_lock.lck.lox.base = ld.l_start;
grant_lock.lck.lox.length = ld.l_len;
grant_lock.lck.lox.pid = ld.l_pid;
grant_lock.lck.lox.rpid = ld.l_rpid;
grant_lock.lck.lox.rsys = ld.l_rsys;
grant_lock.lck.lox.type = ld.l_type;
grant_lock.rel = 0;
/* send this granted lock to the respective remote */
/* lock mgr */
remote_grant(&grant_lock, MSG);
/* no more granted locks, quit */
if (ld.l_xxx < 0) break;
ld.l_type = F_UNLCK;
ld.l_xxx = GRANT_LOCK_FLAG;
}
*grant_lock_flag = FALSE;
return(NULL);
}
*grant_lock_flag = FALSE;
/*
* convert fh to fd
*/
if ((fd = get_fd(a)) < 0) {
if (fd == -1)
nlm_resp->lstat = nlm_denied_nolocks;
else
nlm_resp->lstat = nlm_denied;
return (nlm_resp);
}
/*
* set the lock
*/
if (a->block)
cmd = F_RSETLKW;
else
cmd = F_RSETLK;
ld.l_type = F_UNLCK;
ld.l_whence = 0;
ld.l_start = a->lck.lox.base;
ld.l_len = a->lck.lox.length;
ld.l_pid = a->lck.lox.pid;
ld.l_rpid = a->lck.lox.rpid;
ld.l_rsys = a->lck.lox.rsys;
ld.l_xxx = 0;
if (debug) {
printf("ld.l_start=%d ld.l_len=%d ld.l_pid=%d ld.l_rpid=%d ld.l_rsys=%x\n",
ld.l_start, ld.l_len, ld.l_pid, ld.l_rpid, ld.l_rsys);
}
if (fcntl(fd, cmd, &ld) == -1) {
if (errno == EINTR) {
nlm_resp->lstat = blocking;
a->w_flag = 1;
} else if (errno == ENOLCK) {
perror("fcntl");
printf("rpc.lockd: out of lock.\n");
nlm_resp->lstat = nlm_denied_nolocks;
} else {
perror("fcntl");
printf("rpc.lockd: unable to unlock a lock. \n");
nlm_resp->lstat = nlm_denied;
}
if (ld.l_xxx == GRANT_LOCK_FLAG)
*grant_lock_flag = TRUE;
} else {
/* if fcntl() returned w/ l_xxx >0, means kernel tells us */
/* that this unlock request results in some locks to be */
/* granted, & we need to call fcntl() again to get these */
/* granted locks. we call fcntl() again in the beginning */
/* of this routine by chking grant_lock_flag. */
/* DO NOT close the fd & reset the ld 'cause it will be */
/* re-used */
if (ld.l_xxx == GRANT_LOCK_FLAG)
*grant_lock_flag = TRUE;
else if (ld.l_xxx == LOCKD_LAST_REF) {
remove_fd(fd);
close(fd);
}
nlm_resp->lstat = nlm_granted;
}
return (nlm_resp);
}
remote_result *
remote_unlock(a, choice)
struct reclock *a;
int choice;
{
if (debug)
printf("enter remote_unlock\n");
if (choice == MSG) {
if (nlm_call(NLM_UNLOCK_MSG, a, 0) == -1)
a->rel = 1; /* rpc error, discard */
} else {
printf("rpc not supported\n");
a->rel = 1; /* rpc error, discard */
}
(void) remove_req_in_me(a);
return (NULL); /* no reply available */
}
remote_result *
local_test(a)
struct reclock *a;
{
int fd, cmd;
struct eflock ld;
int nofd = used_fd; /* Save the previous no of used */
/* fd, used to check if this */
/* file is opened or not */
/*
* convert fh to fd
*/
if ((fd = get_fd(a)) < 0) {
if (fd == -1)
nlm_resp->lstat = nlm_denied_nolocks;
else
nlm_resp->lstat = nlm_denied;
return (nlm_resp);
}
/*
* test the lock
*/
cmd = F_RGETLK;
if (a->exclusive)
ld.l_type = F_WRLCK;
else
ld.l_type = F_RDLCK;
ld.l_whence = 0;
ld.l_start = (a->lck.lox.base >= 0) ? a->lck.lox.base : 0;
ld.l_len = a->lck.lox.length;
ld.l_pid = a->lck.lox.pid;
ld.l_rpid = a->lck.lox.rpid;
ld.l_rsys = a->lck.lox.rsys;
ld.l_xxx = 0;
if (fcntl(fd, cmd, &ld) == -1) {
if (errno == EINTR) {
nlm_resp->lstat = blocking;
a->w_flag = 1;
} else if (errno == ENOLCK) {
perror("fcntl");
printf("rpc.lockd: out of lock.\n");
nlm_resp->lstat = nlm_denied_nolocks;
} else {
perror("fcntl");
printf("rpc.lockd: unable to test a lock. \n");
nlm_resp->lstat = nlm_denied;
}
} else {
if (ld.l_type == F_UNLCK) {
nlm_resp->lstat = nlm_granted;
a->lck.lox.type = ld.l_type;
} else {
nlm_resp->lstat = nlm_denied;
a->lck.lox.type = ld.l_type;
a->lck.lox.base = ld.l_start;
a->lck.lox.length = ld.l_len;
a->lck.lox.pid = ld.l_pid;
a->lck.lox.rpid = ld.l_rpid;
a->lck.lox.rsys = ld.l_rsys;
}
}
if (debug) {
printf("ld.l_start=%d ld.l_len=%d ld.l_rpid=%d ld.l_rsys=%x\n",
ld.l_start, ld.l_len, ld.l_rpid, ld.l_rsys);
}
/*
* It is a new fd, so we close it. Or we leave it open.
*/
if (ld.l_xxx == LOCKD_LAST_REF) {
remove_fd(fd);
close(fd);
}
return (nlm_resp);
}
remote_result *
remote_test(a, choice)
struct reclock *a;
int choice;
{
if (debug)
printf("enter remote_test\n");
if (choice == MSG) {
if (nlm_call(NLM_TEST_MSG, a, 0) == -1)
a->rel = 1;
} else {
printf("rpc not supported\n");
a->rel = 1;
}
return (NULL);
}
remote_result *
remote_cancel(a, choice)
struct reclock *a;
int choice;
{
msg_entry *msgp;
if (debug)
printf("enter remote_cancel(%x)\n", a);
if (choice == MSG){
if (nlm_call(NLM_CANCEL_MSG, a, 0) == -1)
a->rel = 1;
} else { /* rpc case */
printf("rpc not supported\n");
a->rel = 1;
}
if ((msgp = retransmitted(a, KLM_LOCK)) != NULL) {
/* msg is being processed */
if (debug)
printf("remove msg (%x) due to remote cancel\n",
msgp->req);
/* don't free the reclock here as remove_req_in_me() will do */
/* that. */
msgp->req->rel = 0;
dequeue(msgp);
}
remove_req_in_me(a);
return (NULL);
}
remote_result *
local_grant(a)
struct reclock *a;
{
msg_entry *msgp;
remote_result *resp;
if (debug)
printf("enter local_grant(%x)...\n", a);
msgp = msg_q;
while (msgp != NULL) {
if (same_bound(&(msgp->req->alock.lox), &(a->alock.lox)) &&
same_type(&(msgp->req->alock.lox), &(a->alock.lox)) &&
(msgp->req->alock.lox.pid == a->alock.lox.pid)) {
/* upgrade request from pending to granted in */
/* monitoring list for recovery */
(void) upgrade_req_in_me(msgp->req);
/*
* if the reply is for older request, set the
* reply result so that the nxt poll by the kernel
* will get this result
*/
if (msgp->reply != NULL) {
msgp->reply->lstat = klm_granted;
/* if no reply is set before, lets save this reply */
} else if ((resp = get_res()) != NULL) {
resp->lstat = klm_granted;
msgp->reply = resp;
}
break;
}
msgp = msgp->nxt;
}
nlm_resp->lstat = nlm_granted;
return (nlm_resp);
}
remote_result *
remote_grant(a, choice)
struct reclock *a;
int choice;
{
struct reclock *req;
if (debug)
printf("enter remote_grant...\n");
/* reply to the granted lock that was queued in our blocking lock */
/* list */
if ((req = find_block_req(a)) != NULL) {
if (choice == MSG) {
if (nlm_call(NLM_GRANTED_MSG, req, 0) != -1)
dequeue_block_req(req);
} else {
printf("rpc not supported\n");
}
}
return (NULL);
}
remote_result *
cont_lock(a, resp)
struct reclock *a;
remote_result *resp;
{
if (debug) {
printf("enter cont_lock (%x) ID=%d \n", a, a->lck.lox.LockID);
}
switch (resp->lstat) {
case nlm_granted:
a->rel = 0;
if (add_mon(a, 1) == -1)
printf("rpc.lockd: add_mon failed in cont_lock.\n");
return (resp);
case denied:
case nolocks:
a->rel = 1;
a->block = FALSE;
a->lck.lox.granted = 0;
return (resp);
case deadlck:
a->rel = 1;
a->block = TRUE;
a->lck.lox.granted = 0;
return (resp);
case blocking:
a->rel = 0;
a->w_flag = 1;
a->block = TRUE;
return (resp);
case grace:
a->rel = 0;
release_res(resp);
return (NULL);
default:
a->rel = 1;
release_res(resp);
printf("unknown lock return: %d\n", resp->lstat);
return (NULL);
}
}
remote_result *
cont_unlock(a, resp)
struct reclock *a;
remote_result *resp;
{
if (debug)
printf("enter cont_unlock\n");
a->rel = 1;
switch (resp->lstat) {
case nlm_granted:
return (resp);
case denied: /* impossible */
case nolocks:
return (resp);
case blocking: /* impossible */
a->w_flag = 1;
return (resp);
case grace:
a->rel = 0;
release_res(resp);
return (NULL);
default:
a->rel = 0;
release_res(resp);
fprintf(stderr,
"rpc.lockd: unkown rpc_unlock return: %d\n",
resp->lstat);
return (NULL);
}
}
remote_result *
cont_test(a, resp)
struct reclock *a;
remote_result *resp;
{
if (debug)
printf("enter cont_test\n");
a->rel = 1;
switch (resp->lstat) {
case grace:
a->rel = 0;
release_res(resp);
return (NULL);
case nlm_granted:
case denied:
if (debug)
printf("lock blocked by %d, (%d, %d)\n",
resp->lholder.svid, resp->lholder.l_offset,
resp->lholder.l_len);
return (resp);
case nolocks:
return (resp);
case blocking:
a->w_flag = 1;
return (resp);
default:
fprintf(stderr, "rpc.lockd: cont_test: unknown return: %d\n",
resp->lstat);
release_res(resp);
return (NULL);
}
}
remote_result *
cont_cancel(a, resp)
struct reclock *a;
remote_result *resp;
{
if (debug)
printf("enter cont_cancel\n");
return(cont_unlock(a, resp));
}
remote_result *
cont_reclaim(a, resp)
struct reclock *a;
remote_result *resp;
{
remote_result *local;
if (debug)
printf("enter cont_reclaim\n");
switch (resp->lstat) {
case nlm_granted:
case denied:
case nolocks:
case blocking:
local = resp;
break;
case grace:
if (a->reclaim)
fprintf(stderr, "rpc.lockd: reclaim lock req(%x) is returned due to grace period, impossible\n", a);
local = NULL;
break;
default:
printf("unknown cont_reclaim return: %d\n", resp->lstat);
local = NULL;
break;
}
if (local == NULL)
release_res(resp);
return (local);
}
remote_result *
cont_grant(a, resp)
struct reclock *a;
remote_result *resp;
{
if (debug)
printf("enter cont_grant...\n");
return (resp);
}
/*
* Run through the list of file descriptors and close any that are no
* longer in use. This is typically done after a client reboot.
*/
void
check_fds()
{
struct fd_table *t;
struct eflock ld;
int i;
if (debug)
printf("Checking for files to close...\n");
for (t = fd_table, i = 0; i <= lastfd; t++, i++) {
if (t->fd > 0) {
ld.l_type = F_RDLCK;
ld.l_whence = 0;
ld.l_start = 0;
ld.l_len = 0;
ld.l_pid = getpid();
ld.l_rpid = getpid();
/*
* Make the rsys be non-zero, to avoid triggering possible
* kernel checks that lockd calls have non-zero rsys's.
*/
ld.l_rsys = 42;
ld.l_xxx = 0;
if (fcntl(t->fd, F_RGETLK, &ld) < 0) {
perror("fcntl");
printf("rpc.lockd: couldn't check for unneeded files\n");
} else {
if (ld.l_xxx == LOCKD_LAST_REF) {
if (debug)
printf("close(%d)\n", t->fd);
close(t->fd);
remove_fd(t->fd);
}
}
}
}
if (debug)
printf("...done checking for files to close.\n");
}