lockd_lock.c revision 146445
174462Salfred/* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */ 274462Salfred 374462Salfred/* 487096Salfred * Copyright (c) 2001 Andrew P. Lentvorski, Jr. 574462Salfred * Copyright (c) 2000 Manuel Bouyer. 674462Salfred * 774462Salfred * Redistribution and use in source and binary forms, with or without 874462Salfred * modification, are permitted provided that the following conditions 974462Salfred * are met: 1074462Salfred * 1. Redistributions of source code must retain the above copyright 1174462Salfred * notice, this list of conditions and the following disclaimer. 1274462Salfred * 2. Redistributions in binary form must reproduce the above copyright 1374462Salfred * notice, this list of conditions and the following disclaimer in the 1474462Salfred * documentation and/or other materials provided with the distribution. 1574462Salfred * 3. All advertising materials mentioning features or use of this software 1674462Salfred * must display the following acknowledgement: 1774462Salfred * This product includes software developed by the University of 1874462Salfred * California, Berkeley and its contributors. 1974462Salfred * 4. Neither the name of the University nor the names of its contributors 2074462Salfred * may be used to endorse or promote products derived from this software 2174462Salfred * without specific prior written permission. 2274462Salfred * 2374462Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2474462Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2574462Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2674462Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2774462Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2874462Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2974462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3074462Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3174462Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3274462Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3374462Salfred * SUCH DAMAGE. 3474462Salfred * 3574462Salfred */ 3674462Salfred 37146445Scharnier#include <sys/cdefs.h> 38146445Scharnier__FBSDID("$FreeBSD: head/usr.sbin/rpc.lockd/lockd_lock.c 146445 2005-05-20 13:01:47Z charnier $"); 39146445Scharnier 4087096Salfred#define LOCKD_DEBUG 4187096Salfred 4274462Salfred#include <stdio.h> 4387096Salfred#ifdef LOCKD_DEBUG 4487096Salfred#include <stdarg.h> 4587096Salfred#endif 4674462Salfred#include <stdlib.h> 4774462Salfred#include <unistd.h> 4874462Salfred#include <fcntl.h> 4974462Salfred#include <syslog.h> 5074462Salfred#include <errno.h> 5174462Salfred#include <string.h> 5274462Salfred#include <signal.h> 5374462Salfred#include <rpc/rpc.h> 5474462Salfred#include <sys/types.h> 5574462Salfred#include <sys/stat.h> 5674462Salfred#include <sys/socket.h> 5774462Salfred#include <sys/param.h> 5874462Salfred#include <sys/mount.h> 5974462Salfred#include <sys/wait.h> 6074462Salfred#include <rpcsvc/sm_inter.h> 6174462Salfred#include <rpcsvc/nlm_prot.h> 6274462Salfred#include "lockd_lock.h" 6374462Salfred#include "lockd.h" 6474462Salfred 6587096Salfred#define MAXOBJECTSIZE 64 6687096Salfred#define MAXBUFFERSIZE 1024 6787096Salfred 6884923Salfred/* 6984923Salfred * A set of utilities for managing file locking 7084923Salfred * 7184923Salfred * XXX: All locks are in a linked list, a better structure should be used 7284923Salfred * to improve search/access effeciency. 7384923Salfred */ 7474462Salfred 7574462Salfred/* struct describing a lock */ 7674462Salfredstruct file_lock { 7787096Salfred LIST_ENTRY(file_lock) nfslocklist; 7874462Salfred fhandle_t filehandle; /* NFS filehandle */ 7974462Salfred struct sockaddr *addr; 8074462Salfred struct nlm4_holder client; /* lock holder */ 8187096Salfred /* XXX: client_cookie used *only* in send_granted */ 8274462Salfred netobj client_cookie; /* cookie sent by the client */ 8374462Salfred int nsm_status; /* status from the remote lock manager */ 8474462Salfred int status; /* lock status, see below */ 8574462Salfred int flags; /* lock flags, see lockd_lock.h */ 8687096Salfred int blocking; /* blocking lock or not */ 87132254Smr char client_name[SM_MAXSTRLEN]; /* client_name is really variable 88132254Smr length and must be last! */ 8974462Salfred}; 9074462Salfred 9187096SalfredLIST_HEAD(nfslocklist_head, file_lock); 9287096Salfredstruct nfslocklist_head nfslocklist_head = LIST_HEAD_INITIALIZER(nfslocklist_head); 9387096Salfred 9487096SalfredLIST_HEAD(blockedlocklist_head, file_lock); 9587096Salfredstruct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blockedlocklist_head); 9687096Salfred 9774462Salfred/* lock status */ 9874462Salfred#define LKST_LOCKED 1 /* lock is locked */ 9984923Salfred/* XXX: Is this flag file specific or lock specific? */ 10074462Salfred#define LKST_WAITING 2 /* file is already locked by another host */ 10174462Salfred#define LKST_PROCESSING 3 /* child is trying to aquire the lock */ 10274462Salfred#define LKST_DYING 4 /* must dies when we get news from the child */ 10374462Salfred 10487096Salfred/* struct describing a monitored host */ 10574462Salfredstruct host { 10674462Salfred LIST_ENTRY(host) hostlst; 10774462Salfred int refcnt; 108132254Smr char name[SM_MAXSTRLEN]; /* name is really variable length and 109132254Smr must be last! */ 11074462Salfred}; 11187096Salfred/* list of hosts we monitor */ 11287096SalfredLIST_HEAD(hostlst_head, host); 11387096Salfredstruct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); 11474462Salfred 11587096Salfred/* 11687096Salfred * File monitoring handlers 11787096Salfred * XXX: These might be able to be removed when kevent support 11887096Salfred * is placed into the hardware lock/unlock routines. (ie. 11987096Salfred * let the kernel do all the file monitoring) 12087096Salfred */ 12174462Salfred 12287096Salfred/* Struct describing a monitored file */ 12387096Salfredstruct monfile { 12487096Salfred LIST_ENTRY(monfile) monfilelist; 12587096Salfred fhandle_t filehandle; /* Local access filehandle */ 12687096Salfred int fd; /* file descriptor: remains open until unlock! */ 12787096Salfred int refcount; 12887096Salfred int exclusive; 12987096Salfred}; 13087096Salfred 13187096Salfred/* List of files we monitor */ 13287096SalfredLIST_HEAD(monfilelist_head, monfile); 13387096Salfredstruct monfilelist_head monfilelist_head = LIST_HEAD_INITIALIZER(monfilelist_head); 13487096Salfred 13587096Salfredstatic int debugdelay = 0; 13687096Salfred 13787096Salfredenum nfslock_status { NFS_GRANTED = 0, NFS_GRANTED_DUPLICATE, 13887096Salfred NFS_DENIED, NFS_DENIED_NOLOCK, 13987096Salfred NFS_RESERR }; 14087096Salfred 14187096Salfredenum hwlock_status { HW_GRANTED = 0, HW_GRANTED_DUPLICATE, 14287096Salfred HW_DENIED, HW_DENIED_NOLOCK, 14387096Salfred HW_STALEFH, HW_READONLY, HW_RESERR }; 14487096Salfred 14587096Salfredenum partialfilelock_status { PFL_GRANTED=0, PFL_GRANTED_DUPLICATE, PFL_DENIED, 14687096Salfred PFL_NFSDENIED, PFL_NFSBLOCKED, PFL_NFSDENIED_NOLOCK, PFL_NFSRESERR, 14787096Salfred PFL_HWDENIED, PFL_HWBLOCKED, PFL_HWDENIED_NOLOCK, PFL_HWRESERR}; 14887096Salfred 14987096Salfredenum LFLAGS {LEDGE_LEFT, LEDGE_LBOUNDARY, LEDGE_INSIDE, LEDGE_RBOUNDARY, LEDGE_RIGHT}; 15087096Salfredenum RFLAGS {REDGE_LEFT, REDGE_LBOUNDARY, REDGE_INSIDE, REDGE_RBOUNDARY, REDGE_RIGHT}; 15187096Salfred/* XXX: WARNING! I HAVE OVERLOADED THIS STATUS ENUM! SPLIT IT APART INTO TWO */ 15287096Salfredenum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SPL_RESERR=8}; 15387096Salfred 15487096Salfredenum partialfilelock_status lock_partialfilelock(struct file_lock *fl); 15587096Salfred 15687096Salfredvoid send_granted(struct file_lock *fl, int opcode); 15787096Salfredvoid siglock(void); 15887096Salfredvoid sigunlock(void); 15987096Salfredvoid monitor_lock_host(const char *hostname); 160121558Spetervoid unmonitor_lock_host(char *hostname); 16187096Salfred 16287096Salfredvoid copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, 16387096Salfred const bool_t exclusive, struct nlm4_holder *dest); 16487199Salfredstruct file_lock * allocate_file_lock(const netobj *lockowner, 165132254Smr const netobj *matchcookie, 166132254Smr const struct sockaddr *addr, 167132254Smr const char *caller_name); 16887096Salfredvoid deallocate_file_lock(struct file_lock *fl); 16987199Salfredvoid fill_file_lock(struct file_lock *fl, const fhandle_t *fh, 170132254Smr const bool_t exclusive, const int32_t svid, 171132254Smr const u_int64_t offset, const u_int64_t len, 17287199Salfred const int state, const int status, const int flags, const int blocking); 17387096Salfredint regions_overlap(const u_int64_t start1, const u_int64_t len1, 174129302Sstefanf const u_int64_t start2, const u_int64_t len2); 17587096Salfredenum split_status region_compare(const u_int64_t starte, const u_int64_t lene, 17687096Salfred const u_int64_t startu, const u_int64_t lenu, 17787096Salfred u_int64_t *start1, u_int64_t *len1, u_int64_t *start2, u_int64_t *len2); 17887096Salfredint same_netobj(const netobj *n0, const netobj *n1); 17987096Salfredint same_filelock_identity(const struct file_lock *fl0, 18087096Salfred const struct file_lock *fl2); 18187096Salfred 18287096Salfredstatic void debuglog(char const *fmt, ...); 18387096Salfredvoid dump_static_object(const unsigned char* object, const int sizeof_object, 18487096Salfred unsigned char* hbuff, const int sizeof_hbuff, 18587096Salfred unsigned char* cbuff, const int sizeof_cbuff); 18687096Salfredvoid dump_netobj(const struct netobj *nobj); 18787096Salfredvoid dump_filelock(const struct file_lock *fl); 18887096Salfredstruct file_lock * get_lock_matching_unlock(const struct file_lock *fl); 18987096Salfredenum nfslock_status test_nfslock(const struct file_lock *fl, 19087096Salfred struct file_lock **conflicting_fl); 19187096Salfredenum nfslock_status lock_nfslock(struct file_lock *fl); 19287096Salfredenum nfslock_status delete_nfslock(struct file_lock *fl); 19387096Salfredenum nfslock_status unlock_nfslock(const struct file_lock *fl, 19487096Salfred struct file_lock **released_lock, struct file_lock **left_lock, 19587096Salfred struct file_lock **right_lock); 19687096Salfredenum hwlock_status lock_hwlock(struct file_lock *fl); 19787096Salfredenum split_status split_nfslock(const struct file_lock *exist_lock, 19887096Salfred const struct file_lock *unlock_lock, struct file_lock **left_lock, 19987096Salfred struct file_lock **right_lock); 20087096Salfredvoid add_blockingfilelock(struct file_lock *fl); 20187096Salfredenum hwlock_status unlock_hwlock(const struct file_lock *fl); 20287096Salfredenum hwlock_status test_hwlock(const struct file_lock *fl, 20387096Salfred struct file_lock **conflicting_fl); 20487096Salfredvoid remove_blockingfilelock(struct file_lock *fl); 20587096Salfredvoid clear_blockingfilelock(const char *hostname); 20687096Salfredvoid retry_blockingfilelocklist(void); 20787096Salfredenum partialfilelock_status unlock_partialfilelock( 20887096Salfred const struct file_lock *fl); 20987096Salfredvoid clear_partialfilelock(const char *hostname); 21087096Salfredenum partialfilelock_status test_partialfilelock( 21187096Salfred const struct file_lock *fl, struct file_lock **conflicting_fl); 21287096Salfredenum nlm_stats do_test(struct file_lock *fl, 21387096Salfred struct file_lock **conflicting_fl); 21487096Salfredenum nlm_stats do_unlock(struct file_lock *fl); 21587096Salfredenum nlm_stats do_lock(struct file_lock *fl); 21687096Salfredvoid do_clear(const char *hostname); 217146445Scharniersize_t strnlen(const char *, size_t); 21887096Salfred 21987096Salfredvoid 22087096Salfreddebuglog(char const *fmt, ...) 22187096Salfred{ 22287096Salfred va_list ap; 22387096Salfred 22487096Salfred if (debug_level < 1) { 22587096Salfred return; 22687096Salfred } 22787096Salfred 22887096Salfred sleep(debugdelay); 22987096Salfred 23087096Salfred va_start(ap, fmt); 23187096Salfred vsyslog(LOG_DEBUG, fmt, ap); 23287096Salfred va_end(ap); 23387096Salfred} 23487096Salfred 23587096Salfredvoid 23687096Salfreddump_static_object(object, size_object, hbuff, size_hbuff, cbuff, size_cbuff) 23787096Salfred const unsigned char *object; 23887096Salfred const int size_object; 23987096Salfred unsigned char *hbuff; 24087096Salfred const int size_hbuff; 24187096Salfred unsigned char *cbuff; 24287096Salfred const int size_cbuff; 24387096Salfred{ 24487096Salfred int i, objectsize; 24587096Salfred 24687096Salfred if (debug_level < 2) { 24787096Salfred return; 24887096Salfred } 24987096Salfred 25087096Salfred objectsize = size_object; 25187096Salfred 25287096Salfred if (objectsize == 0) { 25387096Salfred debuglog("object is size 0\n"); 25487096Salfred } else { 25587096Salfred if (objectsize > MAXOBJECTSIZE) { 25687096Salfred debuglog("Object of size %d being clamped" 25787096Salfred "to size %d\n", objectsize, MAXOBJECTSIZE); 25887096Salfred objectsize = MAXOBJECTSIZE; 25987096Salfred } 26087096Salfred 26187096Salfred if (hbuff != NULL) { 26287096Salfred if (size_hbuff < objectsize*2+1) { 26387096Salfred debuglog("Hbuff not large enough." 26487096Salfred " Increase size\n"); 26587096Salfred } else { 26687096Salfred for(i=0;i<objectsize;i++) { 26787096Salfred sprintf(hbuff+i*2,"%02x",*(object+i)); 26887096Salfred } 26987096Salfred *(hbuff+i*2) = '\0'; 27087096Salfred } 27187096Salfred } 27287096Salfred 27387096Salfred if (cbuff != NULL) { 27487096Salfred if (size_cbuff < objectsize+1) { 27587096Salfred debuglog("Cbuff not large enough." 27687096Salfred " Increase Size\n"); 27787096Salfred } 27887096Salfred 27987096Salfred for(i=0;i<objectsize;i++) { 28087096Salfred if (*(object+i) >= 32 && *(object+i) <= 127) { 28187096Salfred *(cbuff+i) = *(object+i); 28287096Salfred } else { 28387096Salfred *(cbuff+i) = '.'; 28487096Salfred } 28587096Salfred } 28687096Salfred *(cbuff+i) = '\0'; 28787096Salfred } 28887096Salfred } 28987096Salfred} 29087096Salfred 29187096Salfredvoid 29287096Salfreddump_netobj(const struct netobj *nobj) 29387096Salfred{ 29487096Salfred char hbuff[MAXBUFFERSIZE*2]; 29587096Salfred char cbuff[MAXBUFFERSIZE]; 29687096Salfred 29787096Salfred if (debug_level < 2) { 29887096Salfred return; 29987096Salfred } 30087096Salfred 30187096Salfred if (nobj == NULL) { 30287096Salfred debuglog("Null netobj pointer\n"); 30387096Salfred } 30487096Salfred else if (nobj->n_len == 0) { 30587096Salfred debuglog("Size zero netobj\n"); 30687096Salfred } else { 30787096Salfred dump_static_object(nobj->n_bytes, nobj->n_len, 30887096Salfred hbuff, sizeof(hbuff), cbuff, sizeof(cbuff)); 30987096Salfred debuglog("netobj: len: %d data: %s ::: %s\n", 31087096Salfred nobj->n_len, hbuff, cbuff); 31187096Salfred } 31287096Salfred} 31387096Salfred 31492911Salfred/* #define DUMP_FILELOCK_VERBOSE */ 31587096Salfredvoid 31687096Salfreddump_filelock(const struct file_lock *fl) 31787096Salfred{ 31892911Salfred#ifdef DUMP_FILELOCK_VERBOSE 31987096Salfred char hbuff[MAXBUFFERSIZE*2]; 32087096Salfred char cbuff[MAXBUFFERSIZE]; 32192911Salfred#endif 32287096Salfred 32387096Salfred if (debug_level < 2) { 32487096Salfred return; 32587096Salfred } 32687096Salfred 32787096Salfred if (fl != NULL) { 32887096Salfred debuglog("Dumping file lock structure @ %p\n", fl); 32987096Salfred 33092911Salfred#ifdef DUMP_FILELOCK_VERBOSE 33187096Salfred dump_static_object((unsigned char *)&fl->filehandle, 33287096Salfred sizeof(fl->filehandle), hbuff, sizeof(hbuff), 33387096Salfred cbuff, sizeof(cbuff)); 33487096Salfred debuglog("Filehandle: %8s ::: %8s\n", hbuff, cbuff); 33592911Salfred#endif 33687096Salfred 33787096Salfred debuglog("Dumping nlm4_holder:\n" 33887096Salfred "exc: %x svid: %x offset:len %llx:%llx\n", 33987096Salfred fl->client.exclusive, fl->client.svid, 34087096Salfred fl->client.l_offset, fl->client.l_len); 34187096Salfred 34292911Salfred#ifdef DUMP_FILELOCK_VERBOSE 34387096Salfred debuglog("Dumping client identity:\n"); 34487096Salfred dump_netobj(&fl->client.oh); 34587096Salfred 34687096Salfred debuglog("Dumping client cookie:\n"); 34787096Salfred dump_netobj(&fl->client_cookie); 34887096Salfred 34987096Salfred debuglog("nsm: %d status: %d flags: %d locker: %d" 35087096Salfred " fd: %d\n", fl->nsm_status, fl->status, 35187096Salfred fl->flags, fl->locker, fl->fd); 35292911Salfred#endif 35387096Salfred } else { 35487096Salfred debuglog("NULL file lock structure\n"); 35587096Salfred } 35687096Salfred} 35787096Salfred 35887096Salfredvoid 35987096Salfredcopy_nlm4_lock_to_nlm4_holder(src, exclusive, dest) 36087096Salfred const struct nlm4_lock *src; 36187096Salfred const bool_t exclusive; 36287096Salfred struct nlm4_holder *dest; 36387096Salfred{ 36487096Salfred 36587096Salfred dest->exclusive = exclusive; 36687096Salfred dest->oh.n_len = src->oh.n_len; 36787096Salfred dest->oh.n_bytes = src->oh.n_bytes; 36887096Salfred dest->svid = src->svid; 36987096Salfred dest->l_offset = src->l_offset; 37087096Salfred dest->l_len = src->l_len; 37187096Salfred} 37287096Salfred 37387096Salfred 374132254Smrsize_t 375132254Smrstrnlen(const char *s, size_t len) 376132254Smr{ 377132254Smr size_t n; 378132254Smr 379132254Smr for (n = 0; s[n] != 0 && n < len; n++) 380132254Smr ; 381132254Smr return n; 382132254Smr} 383132254Smr 38474462Salfred/* 38587096Salfred * allocate_file_lock: Create a lock with the given parameters 38684923Salfred */ 38787096Salfred 38887096Salfredstruct file_lock * 389132254Smrallocate_file_lock(const netobj *lockowner, const netobj *matchcookie, 390132254Smr const struct sockaddr *addr, const char *caller_name) 39187096Salfred{ 39287096Salfred struct file_lock *newfl; 393132254Smr size_t n; 39487096Salfred 395132254Smr /* Beware of rubbish input! */ 396132254Smr n = strnlen(caller_name, SM_MAXSTRLEN); 397132254Smr if (n == SM_MAXSTRLEN) { 398132254Smr return NULL; 399132254Smr } 400132254Smr 401132254Smr newfl = malloc(sizeof(*newfl) - sizeof(newfl->client_name) + n + 1); 40287096Salfred if (newfl == NULL) { 40387096Salfred return NULL; 40487096Salfred } 405132254Smr bzero(newfl, sizeof(*newfl) - sizeof(newfl->client_name)); 406132254Smr memcpy(newfl->client_name, caller_name, n); 407132254Smr newfl->client_name[n] = 0; 40887096Salfred 40987096Salfred newfl->client.oh.n_bytes = malloc(lockowner->n_len); 41087096Salfred if (newfl->client.oh.n_bytes == NULL) { 41187096Salfred free(newfl); 41287096Salfred return NULL; 41387096Salfred } 41487096Salfred newfl->client.oh.n_len = lockowner->n_len; 41587096Salfred bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len); 41687096Salfred 41787096Salfred newfl->client_cookie.n_bytes = malloc(matchcookie->n_len); 41887096Salfred if (newfl->client_cookie.n_bytes == NULL) { 41987096Salfred free(newfl->client.oh.n_bytes); 42087096Salfred free(newfl); 42187096Salfred return NULL; 42287096Salfred } 42387096Salfred newfl->client_cookie.n_len = matchcookie->n_len; 42487096Salfred bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len); 42587096Salfred 426132254Smr newfl->addr = malloc(addr->sa_len); 427132254Smr if (newfl->addr == NULL) { 428132254Smr free(newfl->client_cookie.n_bytes); 429132254Smr free(newfl->client.oh.n_bytes); 430132254Smr free(newfl); 431132254Smr return NULL; 432132254Smr } 433132254Smr memcpy(newfl->addr, addr, addr->sa_len); 434132254Smr 43587096Salfred return newfl; 43687096Salfred} 43787096Salfred 43887096Salfred/* 43987096Salfred * file_file_lock: Force creation of a valid file lock 44087096Salfred */ 44187096Salfredvoid 44287199Salfredfill_file_lock(struct file_lock *fl, const fhandle_t *fh, 443132254Smr const bool_t exclusive, const int32_t svid, 444132254Smr const u_int64_t offset, const u_int64_t len, 44587199Salfred const int state, const int status, const int flags, const int blocking) 44687096Salfred{ 44787096Salfred bcopy(fh, &fl->filehandle, sizeof(fhandle_t)); 44887096Salfred 44987096Salfred fl->client.exclusive = exclusive; 45087096Salfred fl->client.svid = svid; 45187096Salfred fl->client.l_offset = offset; 45287096Salfred fl->client.l_len = len; 45387096Salfred 45487096Salfred fl->nsm_status = state; 45587096Salfred fl->status = status; 45687096Salfred fl->flags = flags; 45787096Salfred fl->blocking = blocking; 45887096Salfred} 45987096Salfred 46087096Salfred/* 46187096Salfred * deallocate_file_lock: Free all storage associated with a file lock 46287096Salfred */ 46387096Salfredvoid 46487096Salfreddeallocate_file_lock(struct file_lock *fl) 46587096Salfred{ 466132254Smr free(fl->addr); 46787096Salfred free(fl->client.oh.n_bytes); 46887096Salfred free(fl->client_cookie.n_bytes); 46987096Salfred free(fl); 47087096Salfred} 47187096Salfred 47287096Salfred/* 47387096Salfred * regions_overlap(): This function examines the two provided regions for 47487096Salfred * overlap. 47587096Salfred */ 47684923Salfredint 47784923Salfredregions_overlap(start1, len1, start2, len2) 47887096Salfred const u_int64_t start1, len1, start2, len2; 47984923Salfred{ 48087096Salfred u_int64_t d1,d2,d3,d4; 48187096Salfred enum split_status result; 48284923Salfred 48387096Salfred debuglog("Entering region overlap with vals: %llu:%llu--%llu:%llu\n", 48487096Salfred start1, len1, start2, len2); 48587096Salfred 48687096Salfred result = region_compare(start1, len1, start2, len2, 48787096Salfred &d1, &d2, &d3, &d4); 48887096Salfred 48987096Salfred debuglog("Exiting region overlap with val: %d\n",result); 49087096Salfred 49187096Salfred if (result == SPL_DISJOINT) { 49287096Salfred return 0; 49384923Salfred } else { 49487096Salfred return 1; 49584923Salfred } 49687096Salfred 49784923Salfred return (result); 49884923Salfred} 49987096Salfred 50084923Salfred/* 50187096Salfred * region_compare(): Examine lock regions and split appropriately 50287096Salfred * 50387096Salfred * XXX: Fix 64 bit overflow problems 50487096Salfred * XXX: Check to make sure I got *ALL* the cases. 50587096Salfred * XXX: This DESPERATELY needs a regression test. 50674462Salfred */ 50787096Salfredenum split_status 50887096Salfredregion_compare(starte, lene, startu, lenu, 50987096Salfred start1, len1, start2, len2) 51087096Salfred const u_int64_t starte, lene, startu, lenu; 51187096Salfred u_int64_t *start1, *len1, *start2, *len2; 51287096Salfred{ 51387096Salfred /* 51487096Salfred * Please pay attention to the sequential exclusions 51587096Salfred * of the if statements!!! 51687096Salfred */ 51787096Salfred enum LFLAGS lflags; 51887096Salfred enum RFLAGS rflags; 51987096Salfred enum split_status retval; 52074462Salfred 52187096Salfred retval = SPL_DISJOINT; 52287096Salfred 52387096Salfred if (lene == 0 && lenu == 0) { 52487096Salfred /* Examine left edge of locker */ 525146445Scharnier lflags = LEDGE_INSIDE; 52687096Salfred if (startu < starte) { 52787096Salfred lflags = LEDGE_LEFT; 52887096Salfred } else if (startu == starte) { 52987096Salfred lflags = LEDGE_LBOUNDARY; 53087096Salfred } 53187096Salfred 53287096Salfred rflags = REDGE_RBOUNDARY; /* Both are infiinite */ 53387096Salfred 53487096Salfred if (lflags == LEDGE_INSIDE) { 53587096Salfred *start1 = starte; 53687096Salfred *len1 = startu - starte; 53787096Salfred } 53887096Salfred 53987096Salfred if (lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) { 54087096Salfred retval = SPL_CONTAINED; 54187096Salfred } else { 54287096Salfred retval = SPL_LOCK1; 54387096Salfred } 54487096Salfred } else if (lene == 0 && lenu != 0) { 54587096Salfred /* Established lock is infinite */ 54687096Salfred /* Examine left edge of unlocker */ 547146445Scharnier lflags = LEDGE_INSIDE; 54887096Salfred if (startu < starte) { 54987096Salfred lflags = LEDGE_LEFT; 55087096Salfred } else if (startu == starte) { 55187096Salfred lflags = LEDGE_LBOUNDARY; 55287096Salfred } 55387096Salfred 55487096Salfred /* Examine right edge of unlocker */ 55587096Salfred if (startu + lenu < starte) { 55687096Salfred /* Right edge of unlocker left of established lock */ 55787096Salfred rflags = REDGE_LEFT; 55887096Salfred return SPL_DISJOINT; 55987096Salfred } else if (startu + lenu == starte) { 56087096Salfred /* Right edge of unlocker on start of established lock */ 56187096Salfred rflags = REDGE_LBOUNDARY; 56287096Salfred return SPL_DISJOINT; 56387096Salfred } else { /* Infinifty is right of finity */ 56487096Salfred /* Right edge of unlocker inside established lock */ 56587096Salfred rflags = REDGE_INSIDE; 56687096Salfred } 56787096Salfred 56887096Salfred if (lflags == LEDGE_INSIDE) { 56987096Salfred *start1 = starte; 57087096Salfred *len1 = startu - starte; 57187096Salfred retval |= SPL_LOCK1; 57287096Salfred } 57387096Salfred 57487096Salfred if (rflags == REDGE_INSIDE) { 57587096Salfred /* Create right lock */ 57687096Salfred *start2 = startu+lenu; 57787096Salfred *len2 = 0; 57887096Salfred retval |= SPL_LOCK2; 57987096Salfred } 58087096Salfred } else if (lene != 0 && lenu == 0) { 58187096Salfred /* Unlocker is infinite */ 58287096Salfred /* Examine left edge of unlocker */ 583146445Scharnier lflags = LEDGE_RIGHT; 58487096Salfred if (startu < starte) { 58587096Salfred lflags = LEDGE_LEFT; 58687096Salfred retval = SPL_CONTAINED; 58787096Salfred return retval; 58887096Salfred } else if (startu == starte) { 58987096Salfred lflags = LEDGE_LBOUNDARY; 59087096Salfred retval = SPL_CONTAINED; 59187096Salfred return retval; 59287096Salfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 59387096Salfred lflags = LEDGE_INSIDE; 59487096Salfred } else if (startu == starte + lene - 1) { 59587096Salfred lflags = LEDGE_RBOUNDARY; 59687096Salfred } else { /* startu > starte + lene -1 */ 59787096Salfred lflags = LEDGE_RIGHT; 59887096Salfred return SPL_DISJOINT; 59987096Salfred } 60087096Salfred 60187096Salfred rflags = REDGE_RIGHT; /* Infinity is right of finity */ 60287096Salfred 60387096Salfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 60487096Salfred *start1 = starte; 60587096Salfred *len1 = startu - starte; 60687096Salfred retval |= SPL_LOCK1; 60787096Salfred return retval; 60887096Salfred } 60987096Salfred } else { 61087096Salfred /* Both locks are finite */ 61187096Salfred 61287096Salfred /* Examine left edge of unlocker */ 613146445Scharnier lflags = LEDGE_RIGHT; 61487096Salfred if (startu < starte) { 61587096Salfred lflags = LEDGE_LEFT; 61687096Salfred } else if (startu == starte) { 61787096Salfred lflags = LEDGE_LBOUNDARY; 61887096Salfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 61987096Salfred lflags = LEDGE_INSIDE; 62087096Salfred } else if (startu == starte + lene - 1) { 62187096Salfred lflags = LEDGE_RBOUNDARY; 62287096Salfred } else { /* startu > starte + lene -1 */ 62387096Salfred lflags = LEDGE_RIGHT; 62487096Salfred return SPL_DISJOINT; 62587096Salfred } 62687096Salfred 62787096Salfred /* Examine right edge of unlocker */ 62887096Salfred if (startu + lenu < starte) { 62987096Salfred /* Right edge of unlocker left of established lock */ 63087096Salfred rflags = REDGE_LEFT; 63187096Salfred return SPL_DISJOINT; 63287096Salfred } else if (startu + lenu == starte) { 63387096Salfred /* Right edge of unlocker on start of established lock */ 63487096Salfred rflags = REDGE_LBOUNDARY; 63587096Salfred return SPL_DISJOINT; 63687096Salfred } else if (startu + lenu < starte + lene) { 63787096Salfred /* Right edge of unlocker inside established lock */ 63887096Salfred rflags = REDGE_INSIDE; 63987096Salfred } else if (startu + lenu == starte + lene) { 64087096Salfred /* Right edge of unlocker on right edge of established lock */ 64187096Salfred rflags = REDGE_RBOUNDARY; 64287096Salfred } else { /* startu + lenu > starte + lene */ 64387096Salfred /* Right edge of unlocker is right of established lock */ 64487096Salfred rflags = REDGE_RIGHT; 64587096Salfred } 64687096Salfred 64787096Salfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 64887096Salfred /* Create left lock */ 64987096Salfred *start1 = starte; 65087096Salfred *len1 = (startu - starte); 65187096Salfred retval |= SPL_LOCK1; 65287096Salfred } 65387096Salfred 65487096Salfred if (rflags == REDGE_INSIDE) { 65587096Salfred /* Create right lock */ 65687096Salfred *start2 = startu+lenu; 65787096Salfred *len2 = starte+lene-(startu+lenu); 65887096Salfred retval |= SPL_LOCK2; 65987096Salfred } 66087096Salfred 66187096Salfred if ((lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) && 66287096Salfred (rflags == REDGE_RBOUNDARY || rflags == REDGE_RIGHT)) { 66387096Salfred retval = SPL_CONTAINED; 66487096Salfred } 66587096Salfred } 66687096Salfred return retval; 66787096Salfred} 66887096Salfred 66987096Salfred/* 67087096Salfred * same_netobj: Compares the apprpriate bits of a netobj for identity 67187096Salfred */ 67287096Salfredint 67387096Salfredsame_netobj(const netobj *n0, const netobj *n1) 67474462Salfred{ 67587096Salfred int retval; 67674462Salfred 67787096Salfred retval = 0; 67874462Salfred 67987096Salfred debuglog("Entering netobj identity check\n"); 68087096Salfred 68187096Salfred if (n0->n_len == n1->n_len) { 68287096Salfred debuglog("Preliminary length check passed\n"); 68387096Salfred retval = !bcmp(n0->n_bytes, n1->n_bytes, n0->n_len); 68487096Salfred debuglog("netobj %smatch\n", retval ? "" : "mis"); 68587096Salfred } 68687096Salfred 68787096Salfred return (retval); 68887096Salfred} 68987096Salfred 69087096Salfred/* 69187096Salfred * same_filelock_identity: Compares the appropriate bits of a file_lock 69287096Salfred */ 69387096Salfredint 69487096Salfredsame_filelock_identity(fl0, fl1) 69587096Salfred const struct file_lock *fl0, *fl1; 69687096Salfred{ 69787096Salfred int retval; 69887096Salfred 69987096Salfred retval = 0; 70087096Salfred 70187096Salfred debuglog("Checking filelock identity\n"); 70287096Salfred 70387096Salfred /* 70487096Salfred * Check process ids and host information. 70587096Salfred */ 70687096Salfred retval = (fl0->client.svid == fl1->client.svid && 70787096Salfred same_netobj(&(fl0->client.oh), &(fl1->client.oh))); 70887096Salfred 70987096Salfred debuglog("Exiting checking filelock identity: retval: %d\n",retval); 71087096Salfred 71187096Salfred return (retval); 71287096Salfred} 71387096Salfred 71487096Salfred/* 71587096Salfred * Below here are routines associated with manipulating the NFS 71687096Salfred * lock list. 71787096Salfred */ 71887096Salfred 71987096Salfred/* 72087096Salfred * get_lock_matching_unlock: Return a lock which matches the given unlock lock 72187096Salfred * or NULL otehrwise 72287096Salfred * XXX: It is a shame that this duplicates so much code from test_nfslock. 72387096Salfred */ 72487096Salfredstruct file_lock * 72587096Salfredget_lock_matching_unlock(const struct file_lock *fl) 72687096Salfred{ 72787096Salfred struct file_lock *ifl; /* Iterator */ 72887096Salfred 72987096Salfred debuglog("Entering lock_matching_unlock\n"); 73087096Salfred debuglog("********Dump of fl*****************\n"); 73187096Salfred dump_filelock(fl); 73287096Salfred 73387096Salfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 73487096Salfred debuglog("Pointer to file lock: %p\n",ifl); 73587096Salfred 73687096Salfred debuglog("****Dump of ifl****\n"); 73787096Salfred dump_filelock(ifl); 73887096Salfred debuglog("*******************\n"); 73987096Salfred 74087096Salfred /* 74187096Salfred * XXX: It is conceivable that someone could use the NLM RPC 74287096Salfred * system to directly access filehandles. This may be a 74387096Salfred * security hazard as the filehandle code may bypass normal 74487096Salfred * file access controls 74587096Salfred */ 74687096Salfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 74774462Salfred continue; 74887096Salfred 74987096Salfred debuglog("matching_unlock: Filehandles match, " 75087096Salfred "checking regions\n"); 75187096Salfred 75287096Salfred /* Filehandles match, check for region overlap */ 75387096Salfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 75487096Salfred ifl->client.l_offset, ifl->client.l_len)) 75587096Salfred continue; 75687096Salfred 75787096Salfred debuglog("matching_unlock: Region overlap" 75887096Salfred " found %llu : %llu -- %llu : %llu\n", 75987096Salfred fl->client.l_offset,fl->client.l_len, 76087096Salfred ifl->client.l_offset,ifl->client.l_len); 76187096Salfred 76287096Salfred /* Regions overlap, check the identity */ 76387096Salfred if (!same_filelock_identity(fl,ifl)) 76487096Salfred continue; 76587096Salfred 76687096Salfred debuglog("matching_unlock: Duplicate lock id. Granting\n"); 76787096Salfred return (ifl); 76887096Salfred } 76987096Salfred 77087096Salfred debuglog("Exiting lock_matching_unlock\n"); 77187096Salfred 77287096Salfred return (NULL); 77387096Salfred} 77487096Salfred 77587096Salfred/* 77687096Salfred * test_nfslock: check for NFS lock in lock list 77787096Salfred * 77887096Salfred * This routine makes the following assumptions: 77987096Salfred * 1) Nothing will adjust the lock list during a lookup 78087096Salfred * 78187096Salfred * This routine has an intersting quirk which bit me hard. 78287096Salfred * The conflicting_fl is the pointer to the conflicting lock. 78387096Salfred * However, to modify the "*pointer* to the conflicting lock" rather 78487096Salfred * that the "conflicting lock itself" one must pass in a "pointer to 78587096Salfred * the pointer of the conflicting lock". Gross. 78687096Salfred */ 78787096Salfred 78887096Salfredenum nfslock_status 78987096Salfredtest_nfslock(const struct file_lock *fl, struct file_lock **conflicting_fl) 79087096Salfred{ 79187096Salfred struct file_lock *ifl; /* Iterator */ 79287096Salfred enum nfslock_status retval; 79387096Salfred 79487096Salfred debuglog("Entering test_nfslock\n"); 79587096Salfred 79687096Salfred retval = NFS_GRANTED; 79787096Salfred (*conflicting_fl) = NULL; 79887096Salfred 79987096Salfred debuglog("Entering lock search loop\n"); 80087096Salfred 80187096Salfred debuglog("***********************************\n"); 80287096Salfred debuglog("Dumping match filelock\n"); 80387096Salfred debuglog("***********************************\n"); 80487096Salfred dump_filelock(fl); 80587096Salfred debuglog("***********************************\n"); 80687096Salfred 80787096Salfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 80887096Salfred if (retval == NFS_DENIED) 80987096Salfred break; 81087096Salfred 81187096Salfred debuglog("Top of lock loop\n"); 81287096Salfred debuglog("Pointer to file lock: %p\n",ifl); 81387096Salfred 81487096Salfred debuglog("***********************************\n"); 81587096Salfred debuglog("Dumping test filelock\n"); 81687096Salfred debuglog("***********************************\n"); 81787096Salfred dump_filelock(ifl); 81887096Salfred debuglog("***********************************\n"); 81987096Salfred 82084923Salfred /* 82187096Salfred * XXX: It is conceivable that someone could use the NLM RPC 82287096Salfred * system to directly access filehandles. This may be a 82387096Salfred * security hazard as the filehandle code may bypass normal 82487096Salfred * file access controls 82584923Salfred */ 82687096Salfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 82774462Salfred continue; 82887096Salfred 82987096Salfred debuglog("test_nfslock: filehandle match found\n"); 83087096Salfred 83187096Salfred /* Filehandles match, check for region overlap */ 83287096Salfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 83387096Salfred ifl->client.l_offset, ifl->client.l_len)) 83487096Salfred continue; 83587096Salfred 83687096Salfred debuglog("test_nfslock: Region overlap found" 83787096Salfred " %llu : %llu -- %llu : %llu\n", 83887096Salfred fl->client.l_offset,fl->client.l_len, 83987096Salfred ifl->client.l_offset,ifl->client.l_len); 84087096Salfred 84187096Salfred /* Regions overlap, check the exclusivity */ 84287096Salfred if (!(fl->client.exclusive || ifl->client.exclusive)) 84387096Salfred continue; 84487096Salfred 84587096Salfred debuglog("test_nfslock: Exclusivity failure: %d %d\n", 84687096Salfred fl->client.exclusive, 84787096Salfred ifl->client.exclusive); 84887096Salfred 84987096Salfred if (same_filelock_identity(fl,ifl)) { 85087096Salfred debuglog("test_nfslock: Duplicate id. Granting\n"); 85187096Salfred (*conflicting_fl) = ifl; 85287096Salfred retval = NFS_GRANTED_DUPLICATE; 85387096Salfred } else { 85487096Salfred /* locking attempt fails */ 85587096Salfred debuglog("test_nfslock: Lock attempt failed\n"); 85687096Salfred debuglog("Desired lock\n"); 85787096Salfred dump_filelock(fl); 85887096Salfred debuglog("Conflicting lock\n"); 85987096Salfred dump_filelock(ifl); 86087096Salfred (*conflicting_fl) = ifl; 86187096Salfred retval = NFS_DENIED; 86284923Salfred } 86384923Salfred } 86487096Salfred 86587096Salfred debuglog("Dumping file locks\n"); 86687096Salfred debuglog("Exiting test_nfslock\n"); 86787096Salfred 86887096Salfred return (retval); 86987096Salfred} 87087096Salfred 87187096Salfred/* 87287096Salfred * lock_nfslock: attempt to create a lock in the NFS lock list 87387096Salfred * 87487096Salfred * This routine tests whether the lock will be granted and then adds 87587096Salfred * the entry to the lock list if so. 87687096Salfred * 87787096Salfred * Argument fl gets modified as its list housekeeping entries get modified 87887096Salfred * upon insertion into the NFS lock list 87987096Salfred * 88087096Salfred * This routine makes several assumptions: 88187096Salfred * 1) It is perfectly happy to grant a duplicate lock from the same pid. 88287096Salfred * While this seems to be intuitively wrong, it is required for proper 88387096Salfred * Posix semantics during unlock. It is absolutely imperative to not 88487096Salfred * unlock the main lock before the two child locks are established. Thus, 88587096Salfred * one has be be able to create duplicate locks over an existing lock 88687096Salfred * 2) It currently accepts duplicate locks from the same id,pid 88787096Salfred */ 88887096Salfred 88987096Salfredenum nfslock_status 89087096Salfredlock_nfslock(struct file_lock *fl) 89187096Salfred{ 89287096Salfred enum nfslock_status retval; 89387096Salfred struct file_lock *dummy_fl; 89487096Salfred 89587096Salfred dummy_fl = NULL; 89687096Salfred 89787096Salfred debuglog("Entering lock_nfslock...\n"); 89887096Salfred 89987096Salfred retval = test_nfslock(fl,&dummy_fl); 90087096Salfred 90187096Salfred if (retval == NFS_GRANTED || retval == NFS_GRANTED_DUPLICATE) { 90287096Salfred debuglog("Inserting lock...\n"); 90387096Salfred dump_filelock(fl); 90487096Salfred LIST_INSERT_HEAD(&nfslocklist_head, fl, nfslocklist); 90574462Salfred } 90687096Salfred 90787096Salfred debuglog("Exiting lock_nfslock...\n"); 90887096Salfred 90987096Salfred return (retval); 91074462Salfred} 91174462Salfred 91274462Salfred/* 91387096Salfred * delete_nfslock: delete an NFS lock list entry 91487096Salfred * 91587096Salfred * This routine is used to delete a lock out of the NFS lock list 91687096Salfred * without regard to status, underlying locks, regions or anything else 91787096Salfred * 91887096Salfred * Note that this routine *does not deallocate memory* of the lock. 91987096Salfred * It just disconnects it from the list. The lock can then be used 92087096Salfred * by other routines without fear of trashing the list. 92174462Salfred */ 92287096Salfred 92387096Salfredenum nfslock_status 92487096Salfreddelete_nfslock(struct file_lock *fl) 92574462Salfred{ 92674462Salfred 92787096Salfred LIST_REMOVE(fl, nfslocklist); 92887096Salfred 92987096Salfred return (NFS_GRANTED); 93087096Salfred} 93187096Salfred 93287096Salfredenum split_status 93387096Salfredsplit_nfslock(exist_lock, unlock_lock, left_lock, right_lock) 93487096Salfred const struct file_lock *exist_lock, *unlock_lock; 93587096Salfred struct file_lock **left_lock, **right_lock; 93687096Salfred{ 93787096Salfred u_int64_t start1, len1, start2, len2; 93887096Salfred enum split_status spstatus; 93987096Salfred 94087096Salfred spstatus = region_compare(exist_lock->client.l_offset, exist_lock->client.l_len, 94187096Salfred unlock_lock->client.l_offset, unlock_lock->client.l_len, 94287096Salfred &start1, &len1, &start2, &len2); 94387096Salfred 94487096Salfred if ((spstatus & SPL_LOCK1) != 0) { 945132254Smr *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 94687096Salfred if (*left_lock == NULL) { 94787096Salfred debuglog("Unable to allocate resource for split 1\n"); 94887096Salfred return SPL_RESERR; 94987096Salfred } 95087096Salfred 95187199Salfred fill_file_lock(*left_lock, &exist_lock->filehandle, 95287096Salfred exist_lock->client.exclusive, exist_lock->client.svid, 95387096Salfred start1, len1, 954132254Smr exist_lock->nsm_status, 95587096Salfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 95674462Salfred } 95787096Salfred 95887096Salfred if ((spstatus & SPL_LOCK2) != 0) { 959132254Smr *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 96087096Salfred if (*right_lock == NULL) { 96187096Salfred debuglog("Unable to allocate resource for split 1\n"); 96287096Salfred if (*left_lock != NULL) { 96387096Salfred deallocate_file_lock(*left_lock); 96487096Salfred } 96587096Salfred return SPL_RESERR; 96687096Salfred } 96787096Salfred 96887199Salfred fill_file_lock(*right_lock, &exist_lock->filehandle, 96987096Salfred exist_lock->client.exclusive, exist_lock->client.svid, 97087096Salfred start2, len2, 971132254Smr exist_lock->nsm_status, 97287096Salfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 97374462Salfred } 97487096Salfred 97587096Salfred return spstatus; 97687096Salfred} 97787096Salfred 97887096Salfredenum nfslock_status 97987096Salfredunlock_nfslock(fl, released_lock, left_lock, right_lock) 98087096Salfred const struct file_lock *fl; 98187096Salfred struct file_lock **released_lock; 98287096Salfred struct file_lock **left_lock; 98387096Salfred struct file_lock **right_lock; 98487096Salfred{ 98587096Salfred struct file_lock *mfl; /* Matching file lock */ 98687096Salfred enum nfslock_status retval; 98787096Salfred enum split_status spstatus; 98887096Salfred 98987096Salfred debuglog("Entering unlock_nfslock\n"); 99087096Salfred 99187096Salfred *released_lock = NULL; 99287096Salfred *left_lock = NULL; 99387096Salfred *right_lock = NULL; 99487096Salfred 99587096Salfred retval = NFS_DENIED_NOLOCK; 99687096Salfred 997132254Smr debuglog("Attempting to match lock...\n"); 99887096Salfred mfl = get_lock_matching_unlock(fl); 99987096Salfred 100087096Salfred if (mfl != NULL) { 100187096Salfred debuglog("Unlock matched. Querying for split\n"); 100287096Salfred 100387096Salfred spstatus = split_nfslock(mfl, fl, left_lock, right_lock); 100487096Salfred 100587096Salfred debuglog("Split returned %d %p %p %p %p\n",spstatus,mfl,fl,*left_lock,*right_lock); 100687096Salfred debuglog("********Split dumps********"); 100787096Salfred dump_filelock(mfl); 100887096Salfred dump_filelock(fl); 100987096Salfred dump_filelock(*left_lock); 101087096Salfred dump_filelock(*right_lock); 101187096Salfred debuglog("********End Split dumps********"); 101287096Salfred 101387096Salfred if (spstatus == SPL_RESERR) { 101487096Salfred if (*left_lock != NULL) { 101587096Salfred deallocate_file_lock(*left_lock); 101687096Salfred *left_lock = NULL; 101774462Salfred } 101887096Salfred 101987096Salfred if (*right_lock != NULL) { 102087096Salfred deallocate_file_lock(*right_lock); 102187096Salfred *right_lock = NULL; 102274462Salfred } 102387096Salfred 102487096Salfred return NFS_RESERR; 102574462Salfred } 102687096Salfred 102787096Salfred /* Insert new locks from split if required */ 102887096Salfred if (*left_lock != NULL) { 102987096Salfred debuglog("Split left activated\n"); 103087096Salfred LIST_INSERT_HEAD(&nfslocklist_head, *left_lock, nfslocklist); 103187096Salfred } 103287096Salfred 103387096Salfred if (*right_lock != NULL) { 103487096Salfred debuglog("Split right activated\n"); 103587096Salfred LIST_INSERT_HEAD(&nfslocklist_head, *right_lock, nfslocklist); 103687096Salfred } 103787096Salfred 103887096Salfred /* Unlock the lock since it matches identity */ 103987096Salfred LIST_REMOVE(mfl, nfslocklist); 104087096Salfred *released_lock = mfl; 104187096Salfred retval = NFS_GRANTED; 104274462Salfred } 104387096Salfred 104487096Salfred debuglog("Exiting unlock_nfslock\n"); 104587096Salfred 104674462Salfred return retval; 104774462Salfred} 104874462Salfred 104987096Salfred/* 105087096Salfred * Below here are the routines for manipulating the file lock directly 105187096Salfred * on the disk hardware itself 105287096Salfred */ 105387096Salfredenum hwlock_status 105487096Salfredlock_hwlock(struct file_lock *fl) 105574462Salfred{ 105687096Salfred struct monfile *imf,*nmf; 105787096Salfred int lflags, flerror; 105874462Salfred 105987096Salfred /* Scan to see if filehandle already present */ 106087096Salfred LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 106187096Salfred if (bcmp(&fl->filehandle, &imf->filehandle, 106287096Salfred sizeof(fl->filehandle)) == 0) { 106387096Salfred /* imf is the correct filehandle */ 106474462Salfred break; 106587096Salfred } 106687096Salfred } 106787096Salfred 106887096Salfred /* 106987096Salfred * Filehandle already exists (we control the file) 107087096Salfred * *AND* NFS has already cleared the lock for availability 107187096Salfred * Grant it and bump the refcount. 107287096Salfred */ 107387096Salfred if (imf != NULL) { 107487096Salfred ++(imf->refcount); 107587096Salfred return (HW_GRANTED); 107687096Salfred } 107787096Salfred 107887096Salfred /* No filehandle found, create and go */ 107987096Salfred nmf = malloc(sizeof(struct monfile)); 108087096Salfred if (nmf == NULL) { 108187096Salfred debuglog("hwlock resource allocation failure\n"); 108287096Salfred return (HW_RESERR); 108387096Salfred } 108487096Salfred 108587096Salfred /* XXX: Is O_RDWR always the correct mode? */ 108687096Salfred nmf->fd = fhopen(&fl->filehandle, O_RDWR); 108787096Salfred if (nmf->fd < 0) { 108887096Salfred debuglog("fhopen failed (from %16s): %32s\n", 108987096Salfred fl->client_name, strerror(errno)); 109087096Salfred free(nmf); 109187096Salfred switch (errno) { 109287096Salfred case ESTALE: 109387096Salfred return (HW_STALEFH); 109487096Salfred case EROFS: 109587096Salfred return (HW_READONLY); 109687096Salfred default: 109787096Salfred return (HW_RESERR); 109887096Salfred } 109987096Salfred } 110087096Salfred 110187096Salfred /* File opened correctly, fill the monitor struct */ 110287096Salfred bcopy(&fl->filehandle, &nmf->filehandle, sizeof(fl->filehandle)); 110387096Salfred nmf->refcount = 1; 110487096Salfred nmf->exclusive = fl->client.exclusive; 110587096Salfred 110687096Salfred lflags = (nmf->exclusive == 1) ? 110787096Salfred (LOCK_EX | LOCK_NB) : (LOCK_SH | LOCK_NB); 110887096Salfred 110987096Salfred flerror = flock(nmf->fd, lflags); 111087096Salfred 111187096Salfred if (flerror != 0) { 111287096Salfred debuglog("flock failed (from %16s): %32s\n", 111387096Salfred fl->client_name, strerror(errno)); 111487096Salfred close(nmf->fd); 111587096Salfred free(nmf); 111687096Salfred switch (errno) { 111787096Salfred case EAGAIN: 111887096Salfred return (HW_DENIED); 111987096Salfred case ESTALE: 112087096Salfred return (HW_STALEFH); 112187096Salfred case EROFS: 112287096Salfred return (HW_READONLY); 112387096Salfred default: 112487096Salfred return (HW_RESERR); 112574462Salfred break; 112687096Salfred } 112787096Salfred } 112887096Salfred 112987096Salfred /* File opened and locked */ 113087096Salfred LIST_INSERT_HEAD(&monfilelist_head, nmf, monfilelist); 113187096Salfred 113287096Salfred debuglog("flock succeeded (from %16s)\n", fl->client_name); 113387096Salfred return (HW_GRANTED); 113487096Salfred} 113587096Salfred 113687096Salfredenum hwlock_status 113787096Salfredunlock_hwlock(const struct file_lock *fl) 113887096Salfred{ 113987096Salfred struct monfile *imf; 114087096Salfred 114187096Salfred debuglog("Entering unlock_hwlock\n"); 114287096Salfred debuglog("Entering loop interation\n"); 114387096Salfred 114487096Salfred /* Scan to see if filehandle already present */ 114587096Salfred LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 114687096Salfred if (bcmp(&fl->filehandle, &imf->filehandle, 114787096Salfred sizeof(fl->filehandle)) == 0) { 114887096Salfred /* imf is the correct filehandle */ 114974462Salfred break; 115074462Salfred } 115174462Salfred } 115287096Salfred 115387096Salfred debuglog("Completed iteration. Proceeding\n"); 115487096Salfred 115587096Salfred if (imf == NULL) { 115687096Salfred /* No lock found */ 115787096Salfred debuglog("Exiting unlock_hwlock (HW_DENIED_NOLOCK)\n"); 115887096Salfred return (HW_DENIED_NOLOCK); 115987096Salfred } 116087096Salfred 116187096Salfred /* Lock found */ 116287096Salfred --imf->refcount; 116387096Salfred 116487096Salfred if (imf->refcount < 0) { 116587096Salfred debuglog("Negative hardware reference count\n"); 116687096Salfred } 116787096Salfred 116887096Salfred if (imf->refcount <= 0) { 116987096Salfred close(imf->fd); 117087096Salfred LIST_REMOVE(imf, monfilelist); 117187096Salfred free(imf); 117287096Salfred } 117387096Salfred debuglog("Exiting unlock_hwlock (HW_GRANTED)\n"); 117487096Salfred return (HW_GRANTED); 117574462Salfred} 117674462Salfred 117787096Salfredenum hwlock_status 117892911Salfredtest_hwlock(fl, conflicting_fl) 117992911Salfred const struct file_lock *fl __unused; 118092911Salfred struct file_lock **conflicting_fl __unused; 118187096Salfred{ 118287096Salfred 118387096Salfred /* 118487096Salfred * XXX: lock tests on hardware are not required until 118587096Salfred * true partial file testing is done on the underlying file 118687096Salfred */ 118787096Salfred return (HW_RESERR); 118887096Salfred} 118987096Salfred 119087096Salfred 119187096Salfred 119287096Salfred/* 119387096Salfred * Below here are routines for manipulating blocked lock requests 119487096Salfred * They should only be called from the XXX_partialfilelock routines 119587096Salfred * if at all possible 119687096Salfred */ 119787096Salfred 119874462Salfredvoid 119987096Salfredadd_blockingfilelock(struct file_lock *fl) 120074462Salfred{ 120187096Salfred 120287096Salfred debuglog("Entering add_blockingfilelock\n"); 120387096Salfred 120487096Salfred /* 120587096Salfred * Clear the blocking flag so that it can be reused without 120687096Salfred * adding it to the blocking queue a second time 120787096Salfred */ 120887096Salfred 120987096Salfred fl->blocking = 0; 121087096Salfred LIST_INSERT_HEAD(&blockedlocklist_head, fl, nfslocklist); 121187096Salfred 121287096Salfred debuglog("Exiting add_blockingfilelock\n"); 121374462Salfred} 121474462Salfred 121574462Salfredvoid 121687096Salfredremove_blockingfilelock(struct file_lock *fl) 121774462Salfred{ 121874462Salfred 121987096Salfred debuglog("Entering remove_blockingfilelock\n"); 122087096Salfred 122187096Salfred LIST_REMOVE(fl, nfslocklist); 122287096Salfred 122387096Salfred debuglog("Exiting remove_blockingfilelock\n"); 122487096Salfred} 122587096Salfred 122687096Salfredvoid 122787096Salfredclear_blockingfilelock(const char *hostname) 122887096Salfred{ 122987096Salfred struct file_lock *ifl,*nfl; 123087096Salfred 123187096Salfred /* 123287096Salfred * Normally, LIST_FOREACH is called for, but since 123387096Salfred * the current element *is* the iterator, deleting it 123487096Salfred * would mess up the iteration. Thus, a next element 123587096Salfred * must be used explicitly 123687096Salfred */ 123787096Salfred 123887096Salfred ifl = LIST_FIRST(&blockedlocklist_head); 123987096Salfred 124087096Salfred while (ifl != NULL) { 124187096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 124287096Salfred 124387096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 124487096Salfred remove_blockingfilelock(ifl); 124587096Salfred deallocate_file_lock(ifl); 124674462Salfred } 124787096Salfred 124887096Salfred ifl = nfl; 124987096Salfred } 125087096Salfred} 125187096Salfred 125287096Salfredvoid 125387096Salfredretry_blockingfilelocklist(void) 125487096Salfred{ 125587096Salfred /* Retry all locks in the blocked list */ 1256132254Smr struct file_lock *ifl, *nfl; /* Iterator */ 125787096Salfred enum partialfilelock_status pflstatus; 125887096Salfred 125987096Salfred debuglog("Entering retry_blockingfilelocklist\n"); 126087096Salfred 1261132254Smr LIST_FOREACH_SAFE(ifl, &blockedlocklist_head, nfslocklist, nfl) { 126287096Salfred debuglog("Iterator choice %p\n",ifl); 126387096Salfred debuglog("Next iterator choice %p\n",nfl); 126487096Salfred 126587096Salfred /* 126687096Salfred * SUBTLE BUG: The file_lock must be removed from the 126787096Salfred * old list so that it's list pointers get disconnected 126887096Salfred * before being allowed to participate in the new list 126987096Salfred * which will automatically add it in if necessary. 127087096Salfred */ 127187096Salfred 127287096Salfred LIST_REMOVE(ifl, nfslocklist); 127387096Salfred pflstatus = lock_partialfilelock(ifl); 127487096Salfred 127587096Salfred if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { 127687096Salfred debuglog("Granted blocked lock\n"); 127787096Salfred /* lock granted and is now being used */ 127887096Salfred send_granted(ifl,0); 127987096Salfred } else { 1280132254Smr /* Reinsert lock back into blocked list */ 128187096Salfred debuglog("Replacing blocked lock\n"); 1282132254Smr LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist); 128374462Salfred } 128487096Salfred } 128587096Salfred 128687096Salfred debuglog("Exiting retry_blockingfilelocklist\n"); 128787096Salfred} 128887096Salfred 128987096Salfred/* 129087096Salfred * Below here are routines associated with manipulating all 129187096Salfred * aspects of the partial file locking system (list, hardware, etc.) 129287096Salfred */ 129387096Salfred 129487096Salfred/* 129587096Salfred * Please note that lock monitoring must be done at this level which 129687096Salfred * keeps track of *individual* lock requests on lock and unlock 129787096Salfred * 129887096Salfred * XXX: Split unlocking is going to make the unlock code miserable 129987096Salfred */ 130087096Salfred 130187096Salfred/* 130287096Salfred * lock_partialfilelock: 130387096Salfred * 130487096Salfred * Argument fl gets modified as its list housekeeping entries get modified 130587096Salfred * upon insertion into the NFS lock list 130687096Salfred * 130787096Salfred * This routine makes several assumptions: 130887096Salfred * 1) It (will) pass locks through to flock to lock the entire underlying file 130987096Salfred * and then parcel out NFS locks if it gets control of the file. 131087096Salfred * This matches the old rpc.lockd file semantics (except where it 131187096Salfred * is now more correct). It is the safe solution, but will cause 131287096Salfred * overly restrictive blocking if someone is trying to use the 131387096Salfred * underlying files without using NFS. This appears to be an 131487096Salfred * acceptable tradeoff since most people use standalone NFS servers. 131587096Salfred * XXX: The right solution is probably kevent combined with fcntl 131687096Salfred * 131787096Salfred * 2) Nothing modifies the lock lists between testing and granting 131887096Salfred * I have no idea whether this is a useful assumption or not 131987096Salfred */ 132087096Salfred 132187096Salfredenum partialfilelock_status 132287096Salfredlock_partialfilelock(struct file_lock *fl) 132387096Salfred{ 132487096Salfred enum partialfilelock_status retval; 132587096Salfred enum nfslock_status lnlstatus; 132687096Salfred enum hwlock_status hwstatus; 132787096Salfred 132887096Salfred debuglog("Entering lock_partialfilelock\n"); 132987096Salfred 133087096Salfred retval = PFL_DENIED; 133187096Salfred 133287096Salfred /* 133387096Salfred * Execute the NFS lock first, if possible, as it is significantly 133487096Salfred * easier and less expensive to undo than the filesystem lock 133587096Salfred */ 133687096Salfred 133787096Salfred lnlstatus = lock_nfslock(fl); 133887096Salfred 133987096Salfred switch (lnlstatus) { 134087096Salfred case NFS_GRANTED: 134187096Salfred case NFS_GRANTED_DUPLICATE: 134274462Salfred /* 134387096Salfred * At this point, the NFS lock is allocated and active. 134487096Salfred * Remember to clean it up if the hardware lock fails 134574462Salfred */ 134687096Salfred hwstatus = lock_hwlock(fl); 134787096Salfred 134887096Salfred switch (hwstatus) { 134987096Salfred case HW_GRANTED: 135087096Salfred case HW_GRANTED_DUPLICATE: 135187096Salfred debuglog("HW GRANTED\n"); 135287096Salfred /* 135387096Salfred * XXX: Fixme: Check hwstatus for duplicate when 135487096Salfred * true partial file locking and accounting is 135587096Salfred * done on the hardware 135687096Salfred */ 135787096Salfred if (lnlstatus == NFS_GRANTED_DUPLICATE) { 135887096Salfred retval = PFL_GRANTED_DUPLICATE; 135987096Salfred } else { 136087096Salfred retval = PFL_GRANTED; 136187096Salfred } 136287096Salfred monitor_lock_host(fl->client_name); 136387096Salfred break; 136487096Salfred case HW_RESERR: 136587096Salfred debuglog("HW RESERR\n"); 136687096Salfred retval = PFL_HWRESERR; 136787096Salfred break; 136887096Salfred case HW_DENIED: 136987096Salfred debuglog("HW DENIED\n"); 137087096Salfred retval = PFL_HWDENIED; 137187096Salfred break; 137287096Salfred default: 137387096Salfred debuglog("Unmatched hwstatus %d\n",hwstatus); 137487096Salfred break; 137574462Salfred } 137687096Salfred 137787096Salfred if (retval != PFL_GRANTED && 137887096Salfred retval != PFL_GRANTED_DUPLICATE) { 137987096Salfred /* Clean up the NFS lock */ 138087096Salfred debuglog("Deleting trial NFS lock\n"); 138187096Salfred delete_nfslock(fl); 138287096Salfred } 138387096Salfred break; 138487096Salfred case NFS_DENIED: 138587096Salfred retval = PFL_NFSDENIED; 138687096Salfred break; 138787096Salfred case NFS_RESERR: 138887096Salfred retval = PFL_NFSRESERR; 138987096Salfred default: 139087096Salfred debuglog("Unmatched lnlstatus %d\n"); 139187096Salfred retval = PFL_NFSDENIED_NOLOCK; 139287096Salfred break; 139387096Salfred } 139487096Salfred 139587096Salfred /* 139687096Salfred * By the time fl reaches here, it is completely free again on 139787096Salfred * failure. The NFS lock done before attempting the 139887096Salfred * hardware lock has been backed out 139987096Salfred */ 140087096Salfred 140187096Salfred if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) { 140287096Salfred /* Once last chance to check the lock */ 140387096Salfred if (fl->blocking == 1) { 1404115004Srwatson if (retval == PFL_NFSDENIED) { 1405115004Srwatson /* Queue the lock */ 1406115004Srwatson debuglog("BLOCKING LOCK RECEIVED\n"); 1407115004Srwatson retval = PFL_NFSBLOCKED; 1408115004Srwatson add_blockingfilelock(fl); 1409115004Srwatson dump_filelock(fl); 1410115004Srwatson } else { 1411115004Srwatson /* retval is okay as PFL_HWDENIED */ 1412115004Srwatson debuglog("BLOCKING LOCK DENIED IN HARDWARE\n"); 1413115004Srwatson dump_filelock(fl); 1414115004Srwatson } 141574462Salfred } else { 141687096Salfred /* Leave retval alone, it's already correct */ 141787096Salfred debuglog("Lock denied. Non-blocking failure\n"); 141887096Salfred dump_filelock(fl); 141987096Salfred } 142087096Salfred } 142187096Salfred 142287096Salfred debuglog("Exiting lock_partialfilelock\n"); 142387096Salfred 142487096Salfred return retval; 142587096Salfred} 142687096Salfred 142787096Salfred/* 142887096Salfred * unlock_partialfilelock: 142987096Salfred * 143087096Salfred * Given a file_lock, unlock all locks which match. 143187096Salfred * 143287096Salfred * Note that a given lock might have to unlock ITSELF! See 143387096Salfred * clear_partialfilelock for example. 143487096Salfred */ 143587096Salfred 143687096Salfredenum partialfilelock_status 143787096Salfredunlock_partialfilelock(const struct file_lock *fl) 143887096Salfred{ 143987096Salfred struct file_lock *lfl,*rfl,*releasedfl,*selffl; 144087096Salfred enum partialfilelock_status retval; 144187096Salfred enum nfslock_status unlstatus; 144287096Salfred enum hwlock_status unlhwstatus, lhwstatus; 144387096Salfred 144487096Salfred debuglog("Entering unlock_partialfilelock\n"); 144587096Salfred 144687096Salfred selffl = NULL; 144787096Salfred lfl = NULL; 144887096Salfred rfl = NULL; 144987096Salfred releasedfl = NULL; 145087096Salfred retval = PFL_DENIED; 145187096Salfred 145287096Salfred /* 145387096Salfred * There are significant overlap and atomicity issues 145487096Salfred * with partially releasing a lock. For example, releasing 145587096Salfred * part of an NFS shared lock does *not* always release the 145687096Salfred * corresponding part of the file since there is only one 145787096Salfred * rpc.lockd UID but multiple users could be requesting it 145887096Salfred * from NFS. Also, an unlock request should never allow 145987096Salfred * another process to gain a lock on the remaining parts. 146087096Salfred * ie. Always apply the new locks before releasing the 146187096Salfred * old one 146287096Salfred */ 146387096Salfred 146487096Salfred /* 146587096Salfred * Loop is required since multiple little locks 146687096Salfred * can be allocated and then deallocated with one 146787096Salfred * big unlock. 146887096Salfred * 146987096Salfred * The loop is required to be here so that the nfs & 147087096Salfred * hw subsystems do not need to communicate with one 147187096Salfred * one another 147287096Salfred */ 147387096Salfred 147487096Salfred do { 147587096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 147687096Salfred /* lfl&rfl are created *AND* placed into the NFS lock list if required */ 147787096Salfred unlstatus = unlock_nfslock(fl, &releasedfl, &lfl, &rfl); 147887096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 147987096Salfred 148087096Salfred 148187096Salfred /* XXX: This is grungy. It should be refactored to be cleaner */ 148287096Salfred if (lfl != NULL) { 148387096Salfred lhwstatus = lock_hwlock(lfl); 148487096Salfred if (lhwstatus != HW_GRANTED && 148587096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 148687096Salfred debuglog("HW duplicate lock failure for left split\n"); 148774462Salfred } 148887096Salfred monitor_lock_host(lfl->client_name); 148987096Salfred } 149087096Salfred 149187096Salfred if (rfl != NULL) { 149287096Salfred lhwstatus = lock_hwlock(rfl); 149387096Salfred if (lhwstatus != HW_GRANTED && 149487096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 149587096Salfred debuglog("HW duplicate lock failure for right split\n"); 149687096Salfred } 149787096Salfred monitor_lock_host(rfl->client_name); 149887096Salfred } 149987096Salfred 150087096Salfred switch (unlstatus) { 150187096Salfred case NFS_GRANTED: 150287096Salfred /* Attempt to unlock on the hardware */ 150387096Salfred debuglog("NFS unlock granted. Attempting hardware unlock\n"); 150487096Salfred 150587096Salfred /* This call *MUST NOT* unlock the two newly allocated locks */ 150687096Salfred unlhwstatus = unlock_hwlock(fl); 150787096Salfred debuglog("HW unlock returned with code %d\n",unlhwstatus); 150887096Salfred 150987096Salfred switch (unlhwstatus) { 151087096Salfred case HW_GRANTED: 151187096Salfred debuglog("HW unlock granted\n"); 151287096Salfred unmonitor_lock_host(releasedfl->client_name); 151387096Salfred retval = PFL_GRANTED; 151474462Salfred break; 151587096Salfred case HW_DENIED_NOLOCK: 151687096Salfred /* Huh?!?! This shouldn't happen */ 151787096Salfred debuglog("HW unlock denied no lock\n"); 151887096Salfred retval = PFL_HWRESERR; 151987096Salfred /* Break out of do-while */ 152087096Salfred unlstatus = NFS_RESERR; 152174462Salfred break; 152274462Salfred default: 152387096Salfred debuglog("HW unlock failed\n"); 152487096Salfred retval = PFL_HWRESERR; 152587096Salfred /* Break out of do-while */ 152687096Salfred unlstatus = NFS_RESERR; 152787096Salfred break; 152874462Salfred } 152987096Salfred 153087096Salfred debuglog("Exiting with status retval: %d\n",retval); 153187096Salfred 153287096Salfred retry_blockingfilelocklist(); 153387096Salfred break; 153487096Salfred case NFS_DENIED_NOLOCK: 153587096Salfred retval = PFL_GRANTED; 153687096Salfred debuglog("All locks cleaned out\n"); 153787096Salfred break; 153887096Salfred default: 153987096Salfred retval = PFL_NFSRESERR; 154087096Salfred debuglog("NFS unlock failure\n"); 154187096Salfred dump_filelock(fl); 154287096Salfred break; 154374462Salfred } 154487096Salfred 154587096Salfred if (releasedfl != NULL) { 154687096Salfred if (fl == releasedfl) { 154787096Salfred /* 154887096Salfred * XXX: YECHHH!!! Attempt to unlock self succeeded 154987096Salfred * but we can't deallocate the space yet. This is what 155087096Salfred * happens when you don't write malloc and free together 155187096Salfred */ 155287096Salfred debuglog("Attempt to unlock self\n"); 155387096Salfred selffl = releasedfl; 155487096Salfred } else { 155587096Salfred /* 155687096Salfred * XXX: this deallocation *still* needs to migrate closer 155787096Salfred * to the allocation code way up in get_lock or the allocation 155887096Salfred * code needs to migrate down (violation of "When you write 155987096Salfred * malloc you must write free") 156087096Salfred */ 156187096Salfred 156287096Salfred deallocate_file_lock(releasedfl); 156387096Salfred } 156487096Salfred } 156587096Salfred 156687096Salfred } while (unlstatus == NFS_GRANTED); 156787096Salfred 156887096Salfred if (selffl != NULL) { 156987096Salfred /* 157087096Salfred * This statement wipes out the incoming file lock (fl) 157187096Salfred * in spite of the fact that it is declared const 157287096Salfred */ 157387096Salfred debuglog("WARNING! Destroying incoming lock pointer\n"); 157487096Salfred deallocate_file_lock(selffl); 157574462Salfred } 157687096Salfred 157787096Salfred debuglog("Exiting unlock_partialfilelock\n"); 157887096Salfred 157987096Salfred return retval; 158074462Salfred} 158174462Salfred 158274462Salfred/* 158387096Salfred * clear_partialfilelock 158474462Salfred * 158587096Salfred * Normally called in response to statd state number change. 158687096Salfred * Wipe out all locks held by a host. As a bonus, the act of 158787096Salfred * doing so should automatically clear their statd entries and 158887096Salfred * unmonitor the host. 158974462Salfred */ 159074462Salfred 159187096Salfredvoid 159287096Salfredclear_partialfilelock(const char *hostname) 159387096Salfred{ 159487096Salfred struct file_lock *ifl, *nfl; 159587096Salfred 159687096Salfred /* Clear blocking file lock list */ 159787096Salfred clear_blockingfilelock(hostname); 159887096Salfred 159987096Salfred /* do all required unlocks */ 160087096Salfred /* Note that unlock can smash the current pointer to a lock */ 160187096Salfred 160287096Salfred /* 160387096Salfred * Normally, LIST_FOREACH is called for, but since 160487096Salfred * the current element *is* the iterator, deleting it 160587096Salfred * would mess up the iteration. Thus, a next element 160687096Salfred * must be used explicitly 160787096Salfred */ 160887096Salfred 160987096Salfred ifl = LIST_FIRST(&nfslocklist_head); 161087096Salfred 161187096Salfred while (ifl != NULL) { 161287096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 161387096Salfred 161487096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 161587096Salfred /* Unlock destroys ifl out from underneath */ 161687096Salfred unlock_partialfilelock(ifl); 161787096Salfred /* ifl is NO LONGER VALID AT THIS POINT */ 161887096Salfred } 161987096Salfred ifl = nfl; 162087096Salfred } 162187096Salfred} 162287096Salfred 162387096Salfred/* 162487096Salfred * test_partialfilelock: 162587096Salfred */ 162687096Salfredenum partialfilelock_status 162787096Salfredtest_partialfilelock(const struct file_lock *fl, 162887096Salfred struct file_lock **conflicting_fl) 162987096Salfred{ 163087096Salfred enum partialfilelock_status retval; 163187096Salfred enum nfslock_status teststatus; 163287096Salfred 163387096Salfred debuglog("Entering testpartialfilelock...\n"); 163487096Salfred 163587096Salfred retval = PFL_DENIED; 163687096Salfred 163787096Salfred teststatus = test_nfslock(fl, conflicting_fl); 163887096Salfred debuglog("test_partialfilelock: teststatus %d\n",teststatus); 163987096Salfred 164087096Salfred if (teststatus == NFS_GRANTED || teststatus == NFS_GRANTED_DUPLICATE) { 164187096Salfred /* XXX: Add the underlying filesystem locking code */ 164287096Salfred retval = (teststatus == NFS_GRANTED) ? 164387096Salfred PFL_GRANTED : PFL_GRANTED_DUPLICATE; 164487096Salfred debuglog("Dumping locks...\n"); 164587096Salfred dump_filelock(fl); 164687096Salfred dump_filelock(*conflicting_fl); 164787096Salfred debuglog("Done dumping locks...\n"); 164887096Salfred } else { 164987096Salfred retval = PFL_NFSDENIED; 165087096Salfred debuglog("NFS test denied.\n"); 165187096Salfred dump_filelock(fl); 165287096Salfred debuglog("Conflicting.\n"); 165387096Salfred dump_filelock(*conflicting_fl); 165487096Salfred } 165587096Salfred 165687096Salfred debuglog("Exiting testpartialfilelock...\n"); 165787096Salfred 165887096Salfred return retval; 165987096Salfred} 166087096Salfred 166187096Salfred/* 166287096Salfred * Below here are routines associated with translating the partial file locking 166387096Salfred * codes into useful codes to send back to the NFS RPC messaging system 166487096Salfred */ 166587096Salfred 166687096Salfred/* 166787096Salfred * These routines translate the (relatively) useful return codes back onto 166887096Salfred * the few return codes which the nlm subsystems wishes to trasmit 166987096Salfred */ 167087096Salfred 167174462Salfredenum nlm_stats 167287096Salfreddo_test(struct file_lock *fl, struct file_lock **conflicting_fl) 167374462Salfred{ 167487096Salfred enum partialfilelock_status pfsret; 167587096Salfred enum nlm_stats retval; 167674462Salfred 167787096Salfred debuglog("Entering do_test...\n"); 167887096Salfred 167987096Salfred pfsret = test_partialfilelock(fl,conflicting_fl); 168087096Salfred 168187096Salfred switch (pfsret) { 168287096Salfred case PFL_GRANTED: 168387096Salfred debuglog("PFL test lock granted\n"); 168487096Salfred dump_filelock(fl); 168587096Salfred dump_filelock(*conflicting_fl); 168687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 168787096Salfred break; 168887096Salfred case PFL_GRANTED_DUPLICATE: 168987096Salfred debuglog("PFL test lock granted--duplicate id detected\n"); 169087096Salfred dump_filelock(fl); 169187096Salfred dump_filelock(*conflicting_fl); 169287096Salfred debuglog("Clearing conflicting_fl for call semantics\n"); 169387096Salfred *conflicting_fl = NULL; 169487096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 169587096Salfred break; 169687096Salfred case PFL_NFSDENIED: 169787096Salfred case PFL_HWDENIED: 169887096Salfred debuglog("PFL test lock denied\n"); 169987096Salfred dump_filelock(fl); 170087096Salfred dump_filelock(*conflicting_fl); 170187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 170287096Salfred break; 170387096Salfred case PFL_NFSRESERR: 170487096Salfred case PFL_HWRESERR: 170587096Salfred debuglog("PFL test lock resource fail\n"); 170687096Salfred dump_filelock(fl); 170787096Salfred dump_filelock(*conflicting_fl); 170887096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 170987096Salfred break; 171087096Salfred default: 171187096Salfred debuglog("PFL test lock *FAILED*\n"); 171287096Salfred dump_filelock(fl); 171387096Salfred dump_filelock(*conflicting_fl); 171487096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 171587096Salfred break; 171687096Salfred } 171787096Salfred 171887096Salfred debuglog("Exiting do_test...\n"); 171987096Salfred 172087096Salfred return retval; 172187096Salfred} 172287096Salfred 172387096Salfred/* 172487096Salfred * do_lock: Try to acquire a lock 172587096Salfred * 172687096Salfred * This routine makes a distinction between NLM versions. I am pretty 172787096Salfred * convinced that this should be abstracted out and bounced up a level 172887096Salfred */ 172987096Salfred 173087096Salfredenum nlm_stats 173187096Salfreddo_lock(struct file_lock *fl) 173287096Salfred{ 173387096Salfred enum partialfilelock_status pfsret; 173487096Salfred enum nlm_stats retval; 173587096Salfred 173687096Salfred debuglog("Entering do_lock...\n"); 173787096Salfred 173887096Salfred pfsret = lock_partialfilelock(fl); 173987096Salfred 174087096Salfred switch (pfsret) { 174187096Salfred case PFL_GRANTED: 174287096Salfred debuglog("PFL lock granted"); 174387096Salfred dump_filelock(fl); 174487096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 174587096Salfred break; 174687096Salfred case PFL_GRANTED_DUPLICATE: 174787096Salfred debuglog("PFL lock granted--duplicate id detected"); 174887096Salfred dump_filelock(fl); 174987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 175087096Salfred break; 175187096Salfred case PFL_NFSDENIED: 175287096Salfred case PFL_HWDENIED: 175387096Salfred debuglog("PFL_NFS lock denied"); 175487096Salfred dump_filelock(fl); 175587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 175687096Salfred break; 175787096Salfred case PFL_NFSBLOCKED: 175887096Salfred case PFL_HWBLOCKED: 175987096Salfred debuglog("PFL_NFS blocking lock denied. Queued.\n"); 176087096Salfred dump_filelock(fl); 176187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_blocked : nlm_blocked; 176287096Salfred break; 176387096Salfred case PFL_NFSRESERR: 176487096Salfred case PFL_HWRESERR: 176587096Salfred debuglog("PFL lock resource alocation fail\n"); 176687096Salfred dump_filelock(fl); 176787096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 176887096Salfred break; 176987096Salfred default: 177087096Salfred debuglog("PFL lock *FAILED*"); 177187096Salfred dump_filelock(fl); 177287096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 177387096Salfred break; 177487096Salfred } 177587096Salfred 177687096Salfred debuglog("Exiting do_lock...\n"); 177787096Salfred 177887096Salfred return retval; 177987096Salfred} 178087096Salfred 178187096Salfredenum nlm_stats 178287096Salfreddo_unlock(struct file_lock *fl) 178387096Salfred{ 178487096Salfred enum partialfilelock_status pfsret; 178587096Salfred enum nlm_stats retval; 178687096Salfred 178787096Salfred debuglog("Entering do_unlock...\n"); 178887096Salfred pfsret = unlock_partialfilelock(fl); 178987096Salfred 179087096Salfred switch (pfsret) { 179187096Salfred case PFL_GRANTED: 179287096Salfred debuglog("PFL unlock granted"); 179387096Salfred dump_filelock(fl); 179487096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 179587096Salfred break; 179687096Salfred case PFL_NFSDENIED: 179787096Salfred case PFL_HWDENIED: 179887096Salfred debuglog("PFL_NFS unlock denied"); 179987096Salfred dump_filelock(fl); 180087096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 180187096Salfred break; 180287096Salfred case PFL_NFSDENIED_NOLOCK: 180387096Salfred case PFL_HWDENIED_NOLOCK: 180487096Salfred debuglog("PFL_NFS no lock found\n"); 180587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 180687096Salfred break; 180787096Salfred case PFL_NFSRESERR: 180887096Salfred case PFL_HWRESERR: 180987096Salfred debuglog("PFL unlock resource failure"); 181087096Salfred dump_filelock(fl); 181187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 181287096Salfred break; 181387096Salfred default: 181487096Salfred debuglog("PFL unlock *FAILED*"); 181587096Salfred dump_filelock(fl); 181687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 181787096Salfred break; 181887096Salfred } 181987096Salfred 182087096Salfred debuglog("Exiting do_unlock...\n"); 182187096Salfred 182287096Salfred return retval; 182387096Salfred} 182487096Salfred 182587096Salfred/* 182687096Salfred * do_clear 182787096Salfred * 182887096Salfred * This routine is non-existent because it doesn't have a return code. 182987096Salfred * It is here for completeness in case someone *does* need to do return 183087096Salfred * codes later. A decent compiler should optimize this away. 183187096Salfred */ 183287096Salfred 183387096Salfredvoid 183487096Salfreddo_clear(const char *hostname) 183587096Salfred{ 183687096Salfred 183787096Salfred clear_partialfilelock(hostname); 183887096Salfred} 183987096Salfred 184087096Salfred/* 184187096Salfred * The following routines are all called from the code which the 184287096Salfred * RPC layer invokes 184387096Salfred */ 184487096Salfred 184587096Salfred/* 184687096Salfred * testlock(): inform the caller if the requested lock would be granted 184787096Salfred * 184887096Salfred * returns NULL if lock would granted 184987096Salfred * returns pointer to a conflicting nlm4_holder if not 185087096Salfred */ 185187096Salfred 185287096Salfredstruct nlm4_holder * 185392911Salfredtestlock(struct nlm4_lock *lock, bool_t exclusive, int flags __unused) 185487096Salfred{ 185587096Salfred struct file_lock test_fl, *conflicting_fl; 185687096Salfred 185787096Salfred bzero(&test_fl, sizeof(test_fl)); 185887096Salfred 185987096Salfred bcopy(lock->fh.n_bytes, &(test_fl.filehandle), sizeof(fhandle_t)); 186087096Salfred copy_nlm4_lock_to_nlm4_holder(lock, exclusive, &test_fl.client); 186187096Salfred 186287096Salfred siglock(); 186387096Salfred do_test(&test_fl, &conflicting_fl); 186487096Salfred 186587096Salfred if (conflicting_fl == NULL) { 186687096Salfred debuglog("No conflicting lock found\n"); 186787096Salfred sigunlock(); 186887096Salfred return NULL; 186987096Salfred } else { 187087096Salfred debuglog("Found conflicting lock\n"); 187187096Salfred dump_filelock(conflicting_fl); 187287096Salfred sigunlock(); 187387096Salfred return (&conflicting_fl->client); 187487096Salfred } 187587096Salfred} 187687096Salfred 187787096Salfred/* 187887096Salfred * getlock: try to aquire the lock. 187987096Salfred * If file is already locked and we can sleep, put the lock in the list with 188087096Salfred * status LKST_WAITING; it'll be processed later. 188187096Salfred * Otherwise try to lock. If we're allowed to block, fork a child which 188287096Salfred * will do the blocking lock. 188387096Salfred */ 188487096Salfred 188587096Salfredenum nlm_stats 188687096Salfredgetlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) 188787096Salfred{ 188887096Salfred struct file_lock *newfl; 188987096Salfred enum nlm_stats retval; 189087096Salfred 189187096Salfred debuglog("Entering getlock...\n"); 189287096Salfred 189387096Salfred if (grace_expired == 0 && lckarg->reclaim == 0) 189487096Salfred return (flags & LOCK_V4) ? 189587096Salfred nlm4_denied_grace_period : nlm_denied_grace_period; 189687096Salfred 189787096Salfred /* allocate new file_lock for this request */ 1898132254Smr newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie, 1899132254Smr (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf, lckarg->alock.caller_name); 190087096Salfred if (newfl == NULL) { 190187096Salfred syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); 190287096Salfred /* failed */ 190387096Salfred return (flags & LOCK_V4) ? 190487096Salfred nlm4_denied_nolocks : nlm_denied_nolocks; 190587096Salfred } 190687096Salfred 190787096Salfred if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) { 190887096Salfred debuglog("recieved fhandle size %d, local size %d", 190987096Salfred lckarg->alock.fh.n_len, (int)sizeof(fhandle_t)); 191087096Salfred } 191187096Salfred 191287096Salfred fill_file_lock(newfl, (fhandle_t *)lckarg->alock.fh.n_bytes, 191387199Salfred lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, 191487199Salfred lckarg->alock.l_len, 1915132254Smr lckarg->state, 0, flags, lckarg->block); 191687096Salfred 191787096Salfred /* 191887096Salfred * newfl is now fully constructed and deallocate_file_lock 191987096Salfred * can now be used to delete it 192087096Salfred */ 192187096Salfred 192287096Salfred siglock(); 192387096Salfred debuglog("Pointer to new lock is %p\n",newfl); 192487096Salfred 192587096Salfred retval = do_lock(newfl); 192687096Salfred 192787096Salfred debuglog("Pointer to new lock is %p\n",newfl); 192887096Salfred sigunlock(); 192987096Salfred 193087096Salfred switch (retval) 193187096Salfred { 193287096Salfred case nlm4_granted: 193387096Salfred /* case nlm_granted: is the same as nlm4_granted */ 193487096Salfred /* do_mon(lckarg->alock.caller_name); */ 193574462Salfred break; 193687096Salfred case nlm4_blocked: 193787096Salfred /* case nlm_blocked: is the same as nlm4_blocked */ 193887096Salfred /* do_mon(lckarg->alock.caller_name); */ 193974462Salfred break; 194074462Salfred default: 194187096Salfred deallocate_file_lock(newfl); 194287096Salfred break; 194374462Salfred } 194487096Salfred 194587096Salfred debuglog("Exiting getlock...\n"); 194687096Salfred 194787096Salfred return retval; 194887096Salfred} 194987096Salfred 195087096Salfred 195187096Salfred/* unlock a filehandle */ 195287096Salfredenum nlm_stats 195392911Salfredunlock(nlm4_lock *lock, const int flags __unused) 195487096Salfred{ 195587096Salfred struct file_lock fl; 195687096Salfred enum nlm_stats err; 195787096Salfred 195887096Salfred siglock(); 195987096Salfred 196087096Salfred debuglog("Entering unlock...\n"); 196187096Salfred 196287096Salfred bzero(&fl,sizeof(struct file_lock)); 196387096Salfred bcopy(lock->fh.n_bytes, &fl.filehandle, sizeof(fhandle_t)); 196487096Salfred 196587096Salfred copy_nlm4_lock_to_nlm4_holder(lock, 0, &fl.client); 196687096Salfred 196787096Salfred err = do_unlock(&fl); 196887096Salfred 196987096Salfred sigunlock(); 197087096Salfred 197187096Salfred debuglog("Exiting unlock...\n"); 197287096Salfred 197387096Salfred return err; 197487096Salfred} 197587096Salfred 197687096Salfred/* 197787096Salfred * XXX: The following monitor/unmonitor routines 197887096Salfred * have not been extensively tested (ie. no regression 197987096Salfred * script exists like for the locking sections 198087096Salfred */ 198187096Salfred 198287096Salfred/* 198387096Salfred * monitor_lock_host: monitor lock hosts locally with a ref count and 198487096Salfred * inform statd 198587096Salfred */ 198687096Salfredvoid 198787096Salfredmonitor_lock_host(const char *hostname) 198887096Salfred{ 198987096Salfred struct host *ihp, *nhp; 199087096Salfred struct mon smon; 199187096Salfred struct sm_stat_res sres; 199287096Salfred int rpcret, statflag; 1993132254Smr size_t n; 199487096Salfred 199587096Salfred rpcret = 0; 199687096Salfred statflag = 0; 199787096Salfred 199887096Salfred LIST_FOREACH(ihp, &hostlst_head, hostlst) { 199987096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 200087096Salfred /* Host is already monitored, bump refcount */ 200187096Salfred ++ihp->refcnt; 200287096Salfred /* Host should only be in the monitor list once */ 200387096Salfred return; 200487096Salfred } 200574462Salfred } 200687096Salfred 200787096Salfred /* Host is not yet monitored, add it */ 2008132254Smr n = strnlen(hostname, SM_MAXSTRLEN); 2009132254Smr if (n == SM_MAXSTRLEN) { 2010132254Smr return; 2011132254Smr } 2012132254Smr nhp = malloc(sizeof(*nhp) - sizeof(nhp->name) + n + 1); 201387096Salfred if (nhp == NULL) { 201487096Salfred debuglog("Unable to allocate entry for statd mon\n"); 201587096Salfred return; 201674462Salfred } 201787096Salfred 201887096Salfred /* Allocated new host entry, now fill the fields */ 2019132254Smr memcpy(nhp->name, hostname, n); 2020132254Smr nhp->name[n] = 0; 202187096Salfred nhp->refcnt = 1; 202287096Salfred debuglog("Locally Monitoring host %16s\n",hostname); 202387096Salfred 202487096Salfred debuglog("Attempting to tell statd\n"); 202587096Salfred 202687096Salfred bzero(&smon,sizeof(smon)); 202787096Salfred 202887096Salfred smon.mon_id.mon_name = nhp->name; 202987096Salfred smon.mon_id.my_id.my_name = "localhost\0"; 203087096Salfred 203187096Salfred smon.mon_id.my_id.my_prog = NLM_PROG; 203287096Salfred smon.mon_id.my_id.my_vers = NLM_SM; 203387096Salfred smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 203487096Salfred 2035121558Speter rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, 2036121558Speter (xdrproc_t)xdr_mon, &smon, 2037121558Speter (xdrproc_t)xdr_sm_stat_res, &sres); 203887096Salfred 203987096Salfred if (rpcret == 0) { 204087096Salfred if (sres.res_stat == stat_fail) { 204187096Salfred debuglog("Statd call failed\n"); 204287096Salfred statflag = 0; 204387096Salfred } else { 204487096Salfred statflag = 1; 204574462Salfred } 204687096Salfred } else { 204787096Salfred debuglog("Rpc call to statd failed with return value: %d\n", 204887096Salfred rpcret); 204987096Salfred statflag = 0; 205074462Salfred } 205187096Salfred 205287096Salfred if (statflag == 1) { 205387096Salfred LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst); 205487096Salfred } else { 205587096Salfred free(nhp); 205687096Salfred } 205787096Salfred 205887096Salfred} 205987096Salfred 206087096Salfred/* 206187096Salfred * unmonitor_lock_host: clear monitor ref counts and inform statd when gone 206287096Salfred */ 206387096Salfredvoid 2064121558Speterunmonitor_lock_host(char *hostname) 206587096Salfred{ 206687096Salfred struct host *ihp; 206787096Salfred struct mon_id smon_id; 206887096Salfred struct sm_stat smstat; 206987096Salfred int rpcret; 207087096Salfred 207187096Salfred rpcret = 0; 207287096Salfred 207387096Salfred for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL; 207487096Salfred ihp=LIST_NEXT(ihp, hostlst)) { 207587096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 207687096Salfred /* Host is monitored, bump refcount */ 207787096Salfred --ihp->refcnt; 207887096Salfred /* Host should only be in the monitor list once */ 207974462Salfred break; 208074462Salfred } 208174462Salfred } 208287096Salfred 208387096Salfred if (ihp == NULL) { 208487096Salfred debuglog("Could not find host %16s in mon list\n", hostname); 208587096Salfred return; 208687096Salfred } 208787096Salfred 208887096Salfred if (ihp->refcnt > 0) 208987096Salfred return; 209087096Salfred 209187096Salfred if (ihp->refcnt < 0) { 209287096Salfred debuglog("Negative refcount!: %d\n", 209387096Salfred ihp->refcnt); 209487096Salfred } 209587096Salfred 209687096Salfred debuglog("Attempting to unmonitor host %16s\n", hostname); 209787096Salfred 209887096Salfred bzero(&smon_id,sizeof(smon_id)); 209987096Salfred 210092975Salfred smon_id.mon_name = hostname; 210187096Salfred smon_id.my_id.my_name = "localhost"; 210287096Salfred smon_id.my_id.my_prog = NLM_PROG; 210387096Salfred smon_id.my_id.my_vers = NLM_SM; 210487096Salfred smon_id.my_id.my_proc = NLM_SM_NOTIFY; 210587096Salfred 2106121558Speter rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, 2107125903Salfred (xdrproc_t)xdr_mon_id, &smon_id, 2108125903Salfred (xdrproc_t)xdr_sm_stat, &smstat); 210987096Salfred 211087096Salfred if (rpcret != 0) { 211187096Salfred debuglog("Rpc call to unmonitor statd failed with " 211287096Salfred " return value: %d\n", rpcret); 211387096Salfred } 211487096Salfred 211587096Salfred LIST_REMOVE(ihp, hostlst); 211687096Salfred free(ihp); 211774462Salfred} 211874462Salfred 211987096Salfred/* 212087096Salfred * notify: Clear all locks from a host if statd complains 212187096Salfred * 212287096Salfred * XXX: This routine has not been thoroughly tested. However, neither 212387096Salfred * had the old one been. It used to compare the statd crash state counter 212487096Salfred * to the current lock state. The upshot of this was that it basically 212587096Salfred * cleared all locks from the specified host 99% of the time (with the 212687096Salfred * other 1% being a bug). Consequently, the assumption is that clearing 212787096Salfred * all locks from a host when notified by statd is acceptable. 212887096Salfred * 212987096Salfred * Please note that this routine skips the usual level of redirection 213087096Salfred * through a do_* type routine. This introduces a possible level of 213187096Salfred * error and might better be written as do_notify and take this one out. 213287096Salfred 213387096Salfred */ 213487096Salfred 213574462Salfredvoid 213687096Salfrednotify(const char *hostname, const int state) 213787096Salfred{ 213887096Salfred debuglog("notify from %s, new state %d", hostname, state); 213987096Salfred 214087096Salfred siglock(); 214187096Salfred do_clear(hostname); 214287096Salfred sigunlock(); 214387096Salfred 214487096Salfred debuglog("Leaving notify\n"); 214587096Salfred} 214687096Salfred 214787096Salfredvoid 214874462Salfredsend_granted(fl, opcode) 214974462Salfred struct file_lock *fl; 215092911Salfred int opcode __unused; 215174462Salfred{ 215274462Salfred CLIENT *cli; 215374462Salfred static char dummy; 215474462Salfred struct timeval timeo; 215574462Salfred int success; 215674462Salfred static struct nlm_res retval; 215774462Salfred static struct nlm4_res retval4; 215874462Salfred 215987096Salfred debuglog("About to send granted on blocked lock\n"); 216087096Salfred 216174462Salfred cli = get_client(fl->addr, 216274462Salfred (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); 216374462Salfred if (cli == NULL) { 216474462Salfred syslog(LOG_NOTICE, "failed to get CLIENT for %s", 216574462Salfred fl->client_name); 216674462Salfred /* 216774462Salfred * We fail to notify remote that the lock has been granted. 216874462Salfred * The client will timeout and retry, the lock will be 216974462Salfred * granted at this time. 217074462Salfred */ 217174462Salfred return; 217274462Salfred } 217374462Salfred timeo.tv_sec = 0; 217474462Salfred timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ 217574462Salfred 217674462Salfred if (fl->flags & LOCK_V4) { 217774462Salfred static nlm4_testargs res; 217874462Salfred res.cookie = fl->client_cookie; 217974462Salfred res.exclusive = fl->client.exclusive; 218074462Salfred res.alock.caller_name = fl->client_name; 218174462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 218274462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 218374462Salfred res.alock.oh = fl->client.oh; 218474462Salfred res.alock.svid = fl->client.svid; 218574462Salfred res.alock.l_offset = fl->client.l_offset; 218674462Salfred res.alock.l_len = fl->client.l_len; 218787096Salfred debuglog("sending v4 reply%s", 218887096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 218974462Salfred if (fl->flags & LOCK_ASYNC) { 219074462Salfred success = clnt_call(cli, NLM4_GRANTED_MSG, 2191121558Speter (xdrproc_t)xdr_nlm4_testargs, &res, 2192121558Speter (xdrproc_t)xdr_void, &dummy, timeo); 219374462Salfred } else { 219474462Salfred success = clnt_call(cli, NLM4_GRANTED, 2195121558Speter (xdrproc_t)xdr_nlm4_testargs, &res, 2196121558Speter (xdrproc_t)xdr_nlm4_res, &retval4, timeo); 219774462Salfred } 219874462Salfred } else { 219974462Salfred static nlm_testargs res; 220074462Salfred 220174462Salfred res.cookie = fl->client_cookie; 220274462Salfred res.exclusive = fl->client.exclusive; 220374462Salfred res.alock.caller_name = fl->client_name; 220474462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 220574462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 220674462Salfred res.alock.oh = fl->client.oh; 220774462Salfred res.alock.svid = fl->client.svid; 220874462Salfred res.alock.l_offset = fl->client.l_offset; 220974462Salfred res.alock.l_len = fl->client.l_len; 221087096Salfred debuglog("sending v1 reply%s", 221187096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 221274462Salfred if (fl->flags & LOCK_ASYNC) { 221374462Salfred success = clnt_call(cli, NLM_GRANTED_MSG, 2214121558Speter (xdrproc_t)xdr_nlm_testargs, &res, 2215121558Speter (xdrproc_t)xdr_void, &dummy, timeo); 221674462Salfred } else { 221774462Salfred success = clnt_call(cli, NLM_GRANTED, 2218121558Speter (xdrproc_t)xdr_nlm_testargs, &res, 2219121558Speter (xdrproc_t)xdr_nlm_res, &retval, timeo); 222074462Salfred } 222174462Salfred } 222274462Salfred if (debug_level > 2) 222387096Salfred debuglog("clnt_call returns %d(%s) for granted", 222487096Salfred success, clnt_sperrno(success)); 222574462Salfred 222674462Salfred} 222774462Salfred 222887096Salfred/* 222987096Salfred * Routines below here have not been modified in the overhaul 223087096Salfred */ 223174462Salfred 223287096Salfred/* 223387096Salfred * Are these two routines still required since lockd is not spawning off 223487096Salfred * children to service locks anymore? Presumably they were originally 223587096Salfred * put in place to prevent a one child from changing the lock list out 223687096Salfred * from under another one. 223787096Salfred */ 223874462Salfred 223974462Salfredvoid 224087096Salfredsiglock(void) 224174462Salfred{ 224287096Salfred sigset_t block; 224374462Salfred 224487096Salfred sigemptyset(&block); 224587096Salfred sigaddset(&block, SIGCHLD); 224674462Salfred 224787096Salfred if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) { 224887096Salfred syslog(LOG_WARNING, "siglock failed: %s", strerror(errno)); 224987096Salfred } 225074462Salfred} 225174462Salfred 225274462Salfredvoid 225387096Salfredsigunlock(void) 225474462Salfred{ 225587096Salfred sigset_t block; 225674462Salfred 225787096Salfred sigemptyset(&block); 225887096Salfred sigaddset(&block, SIGCHLD); 225987096Salfred 226087096Salfred if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) { 226187096Salfred syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno)); 226287096Salfred } 226374462Salfred} 226474462Salfred 226574462Salfred 2266