Files
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

337 lines
7.9 KiB
C

#ifndef lint
static char sccsid[] = "@(#)hash.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* hash.c
* rotuines handle insertion, deletion of hashed monitor, file entries
*/
#include "prot_lock.h"
#define MAX_HASHSIZE 100
extern int debug;
typedef struct lm_vnode cache_fp;
typedef struct lm_vnode cache_me;
cache_me *table_me[MAX_HASHSIZE];
void add_req_to_me();
void upgrade_req_in_me();
void remove_req_in_me();
void add_req_to_list();
struct reclock *del_req_from_list();
extern void merge_lock();
/* FIXME*FIXME*FIXME*FIXME*FIXME*FIXME*FIXME*FIXME*FIXME*FIXME*FIXME
*
* cmp_fh() compares file handles. It is not nice at all in that it
* presupposes to know what a file handle looks like. Basically, this
* is a screaming, last minute hack to keep ecd afloat, but it illustrates
* a weakness with the lock manager implementation. Specifically, the
* file handle was treated as a unique identifier in all of name space
* when in reality it was something quite different.
*/
int
cmp_fh(a,b)
netobj *a, *b;
{
if (a->n_len != b->n_len)
return(FALSE);
if (bcmp(&a->n_bytes[0], &b->n_bytes[0], 20) != 0)
return(FALSE);
else
return(TRUE);
}
/*
* find_me returns the cached entry;
* it returns NULL if not found;
*/
struct lm_vnode *
find_me(svr)
char *svr;
{
cache_me *cp;
cp = table_me[hash(svr)];
while ( cp != NULL) {
if (strcmp(cp->svr, svr) == 0) {
/* found */
return (cp);
}
cp = cp->next;
}
return (NULL);
}
/*
* add_req_to_me() -- add lock request req to the monitor list
*/
void
add_req_to_me(req, status)
struct reclock *req;
{
struct lm_vnode *me;
if (debug)
printf("enter add_req_to_me (reclock %x status %d) ...\n",
req, status);
/* find the monitor entry for this server, it should be found */
/* as the entry is created before the lock request is sent out*/
/* to the server. */
if ((me = find_me(req->lck.server_name)) == NULL) {
printf("rpc.lockd: monitor entry not found for \"%s\", request is not monitored.\n", req->lck.server_name);
return;
}
switch (status) {
/* add request to the appropriate list */
/* exclusive or shared if the request */
/* is granted */
case nlm_granted: if (req->exclusive) {
merge_lock(req, &me->exclusive);
/* if an upgrade lock, we rm the */
/* the lock from the shared list */
lm_unlock_region(req, &me->shared);
} else {
merge_lock(req, &me->shared);
/* if downgrade of lock, we rm the */
/* lock from the exclusive list */
lm_unlock_region(req, &me->exclusive);
}
break;
/* if request is queued at server, add */
/* it to the pending list */
case nlm_blocked: add_req_to_list(req, &me->pending);
break;
}
return;
}
/*
* upgrade_req_in_me() -- will move the lock request req that's in the
* monitor's pending list to exclusive/shared list
*/
void
upgrade_req_in_me(req)
struct reclock *req;
{
struct lm_vnode *me;
if (debug)
printf("enter upgrade_req_in_me (reclock %x) ...\n", req);
/* find the monitor entry for this server, it should be found */
/* as the entry is created before the lock request is sent out*/
/* to the server. */
if ((me = find_me(req->lck.server_name)) == NULL) {
printf("rpc.lockd: monitor entry not found for \"%s\", request is not monitored.\n", req->lck.server_name);
return;
}
/* remove the request from the pending list */
(void) del_req_from_list(&req->lck.lox, &me->pending);
/* add the request to the exclusive/shared list */
if (req->exclusive)
merge_lock(req, &me->exclusive);
else
merge_lock(req, &me->shared);
return;
}
/*
* remove_req_in_me() -- will remove the lock request req from the monitor's
* pending, exclusive or shared list.
* del_req() is used to free the memory of the lock
* request.
*/
void
remove_req_in_me(req)
struct reclock *req;
{
struct lm_vnode *me;
if (debug)
printf("enter remove_req_in_me (reclock %x) ...\n", req);
/* find the monitor entry for this server, it should be found */
/* as the entry is created before the lock request is sent out*/
/* to the server. */
if ((me = find_me(req->lck.server_name)) == NULL) {
printf("rpc.lockd: monitor entry not found for \"%s\", request is not monitored.\n", req->lck.server_name);
return;
}
/* since we don't know which of the monitor list this request reside */
/* we'll try pending, and then exclusive or shared list. */
/* the memory of this lock request req will be freed by del_req() */
if (del_req(req, &me->pending))
return;
else {
lm_unlock_region(req, &me->exclusive);
lm_unlock_region(req, &me->shared);
}
return;
}
/*
* add_req_to_list() -- to add a lock request req to the monitor list listp
*/
void
add_req_to_list(req, list)
struct reclock *req;
struct reclock **list;
{
struct reclock *tmp_p = *list;
if (debug)
printf("enter add_req_to_list (reclock %x list %x) ...\n",
req, *list);
/* if list is empty */
if (tmp_p == NULL) {
*list = req->prev = req->next = req;
return;
}
/* make sure the request is not in the list already, this is possible */
/* due to retransmissions. */
for (tmp_p = *list; tmp_p; tmp_p = tmp_p->next) {
if ((tmp_p == req) ||
(same_lock(req, &(tmp_p->lck.lox)) &&
obj_cmp(&(req->lck.fh), &(tmp_p->lck.fh))))
return;
if (tmp_p->next == *list)
break;
}
/* set up the double linked list to add req to the end of the listp */
tmp_p = *list;
tmp_p->prev->next = req;
req->next = tmp_p;
req->prev = tmp_p->prev;
tmp_p->prev = req;
return;
}
/*
* del_req_from_list() -- will remove the request of the data lock l from the
* doubly linked list listp
* similar to del_req() except it doesn't free reclock
* + arg is data_lock instead of reclock.
* if the req is not found, return NULL; else return the
* reclock.
*/
struct reclock *
del_req_from_list(l, list)
struct data_lock *l;
struct reclock **list;
{
struct reclock *tmp_p = *list;
if (debug)
printf("enter del_req_from_list (lox %x list %x) ...\n",
l, *list);
/* if list is empty */
if (tmp_p == NULL) return (NULL);
/* make sure we find the req */
while (&tmp_p->lck.lox != l) {
if (tmp_p->next == *list)
return (NULL);
else
tmp_p = tmp_p->next;
}
/* re-set the doubly linked list w/ this req removed */
tmp_p->prev->next = tmp_p->next;
tmp_p->next->prev = tmp_p->prev;
if (tmp_p == *list) {
if (tmp_p->next == tmp_p)
*list = NULL;
else
*list = tmp_p->next;
}
return (tmp_p);
}
/*
* del_req() -- similar to del_req_from_list() in that it will remove the
* request req from the linked list listp. difference in that
* del_req() will free the memory of req.
* difference is arg is reclock instead of data lock.
* if the req is not found, return FALSE; else TRUE.
*/
bool_t
del_req(req, list)
struct reclock *req;
struct reclock **list;
{
struct reclock *tmp_p = *list;
if (debug)
printf("enter del_req (reclock %x list %x) ...\n",
req, *list);
/* if list is empty */
if (tmp_p == NULL) return (FALSE);
/* search for the request, return FALSE if not found */
while (!((WITHIN(&(tmp_p->lck.lox), &(req->lck.lox)) ||
same_bound(&(req->lck.lox), &(tmp_p->lck.lox))) &&
SAMEOWNER(&(req->lck.lox), &(tmp_p->lck.lox)) &&
obj_cmp(&(req->lck.fh), &(tmp_p->lck.fh)))) {
if (tmp_p->next == *list)
return (FALSE);
else
tmp_p = tmp_p->next;
}
/* re-set the linked list w/ req removed */
tmp_p->prev->next = tmp_p->next;
tmp_p->next->prev = tmp_p->prev;
if (tmp_p == *list) {
if (tmp_p->next == tmp_p)
*list = NULL;
else
*list = tmp_p->next;
}
/* free the lock request req */
tmp_p->rel = 1;
release_reclock(tmp_p);
return (TRUE);
}
/*
* insert_me() -- add monitor entry to the hash table
*/
void
insert_me(mp)
struct lm_vnode *mp;
{
int h;
h = hash(mp->svr);
mp->next = table_me[h];
table_me[h] = mp;
}