lockd_lock.c revision 165775
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 165775 2007-01-04 20:38:50Z mjacob $"); 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 1198165775Smjacobint 1199165775Smjacobduplicate_block(struct file_lock *fl) 1200165775Smjacob{ 1201165775Smjacob struct file_lock *ifl,*nfl; 1202165775Smjacob int retval = 0; 1203165775Smjacob 1204165775Smjacob debuglog("Entering duplicate_block"); 1205165775Smjacob 1206165775Smjacob /* 1207165775Smjacob * Is this lock request already on the blocking list? 1208165775Smjacob * Condider it a dupe if the file handles, offset, length, 1209165775Smjacob * exclusivity and client match. 1210165775Smjacob */ 1211165775Smjacob LIST_FOREACH(ifl, &blockedlocklist_head, nfslocklist) { 1212165775Smjacob if (!bcmp(&fl->filehandle, &ifl->filehandle, 1213165775Smjacob sizeof(fhandle_t)) && 1214165775Smjacob fl->client.exclusive == ifl->client.exclusive && 1215165775Smjacob fl->client.l_offset == ifl->client.l_offset && 1216165775Smjacob fl->client.l_len == ifl->client.l_len && 1217165775Smjacob same_filelock_identity(fl, ifl)) { 1218165775Smjacob retval = 1; 1219165775Smjacob break; 1220165775Smjacob } 1221165775Smjacob } 1222165775Smjacob 1223165775Smjacob debuglog("Exiting duplicate_block: %s\n", retval ? "already blocked" 1224165775Smjacob : "not already blocked"); 1225165775Smjacob return retval; 1226165775Smjacob} 1227165775Smjacob 122874462Salfredvoid 122987096Salfredadd_blockingfilelock(struct file_lock *fl) 123074462Salfred{ 123187096Salfred debuglog("Entering add_blockingfilelock\n"); 123287096Salfred 123387096Salfred /* 1234165775Smjacob * A blocking lock request _should_ never be duplicated as a client 1235165775Smjacob * that is already blocked shouldn't be able to request another 1236165775Smjacob * lock. Alas, there are some buggy clients that do request the same 1237165775Smjacob * lock repeatedly. Make sure only unique locks are on the blocked 1238165775Smjacob * lock list. 1239165775Smjacob */ 1240165775Smjacob if (duplicate_block(fl)) { 1241165775Smjacob debuglog("Exiting add_blockingfilelock: already blocked\n"); 1242165775Smjacob return; 1243165775Smjacob } 1244165775Smjacob 1245165775Smjacob /* 124687096Salfred * Clear the blocking flag so that it can be reused without 124787096Salfred * adding it to the blocking queue a second time 124887096Salfred */ 124987096Salfred 125087096Salfred fl->blocking = 0; 125187096Salfred LIST_INSERT_HEAD(&blockedlocklist_head, fl, nfslocklist); 125287096Salfred 1253165775Smjacob debuglog("Exiting add_blockingfilelock: added blocked lock\n"); 125474462Salfred} 125574462Salfred 125674462Salfredvoid 125787096Salfredremove_blockingfilelock(struct file_lock *fl) 125874462Salfred{ 125974462Salfred 126087096Salfred debuglog("Entering remove_blockingfilelock\n"); 126187096Salfred 126287096Salfred LIST_REMOVE(fl, nfslocklist); 126387096Salfred 126487096Salfred debuglog("Exiting remove_blockingfilelock\n"); 126587096Salfred} 126687096Salfred 126787096Salfredvoid 126887096Salfredclear_blockingfilelock(const char *hostname) 126987096Salfred{ 127087096Salfred struct file_lock *ifl,*nfl; 127187096Salfred 127287096Salfred /* 127387096Salfred * Normally, LIST_FOREACH is called for, but since 127487096Salfred * the current element *is* the iterator, deleting it 127587096Salfred * would mess up the iteration. Thus, a next element 127687096Salfred * must be used explicitly 127787096Salfred */ 127887096Salfred 127987096Salfred ifl = LIST_FIRST(&blockedlocklist_head); 128087096Salfred 128187096Salfred while (ifl != NULL) { 128287096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 128387096Salfred 128487096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 128587096Salfred remove_blockingfilelock(ifl); 128687096Salfred deallocate_file_lock(ifl); 128774462Salfred } 128887096Salfred 128987096Salfred ifl = nfl; 129087096Salfred } 129187096Salfred} 129287096Salfred 129387096Salfredvoid 129487096Salfredretry_blockingfilelocklist(void) 129587096Salfred{ 129687096Salfred /* Retry all locks in the blocked list */ 1297132254Smr struct file_lock *ifl, *nfl; /* Iterator */ 129887096Salfred enum partialfilelock_status pflstatus; 129987096Salfred 130087096Salfred debuglog("Entering retry_blockingfilelocklist\n"); 130187096Salfred 1302132254Smr LIST_FOREACH_SAFE(ifl, &blockedlocklist_head, nfslocklist, nfl) { 130387096Salfred debuglog("Iterator choice %p\n",ifl); 130487096Salfred debuglog("Next iterator choice %p\n",nfl); 130587096Salfred 130687096Salfred /* 130787096Salfred * SUBTLE BUG: The file_lock must be removed from the 130887096Salfred * old list so that it's list pointers get disconnected 130987096Salfred * before being allowed to participate in the new list 131087096Salfred * which will automatically add it in if necessary. 131187096Salfred */ 131287096Salfred 131387096Salfred LIST_REMOVE(ifl, nfslocklist); 131487096Salfred pflstatus = lock_partialfilelock(ifl); 131587096Salfred 131687096Salfred if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { 131787096Salfred debuglog("Granted blocked lock\n"); 131887096Salfred /* lock granted and is now being used */ 131987096Salfred send_granted(ifl,0); 132087096Salfred } else { 1321132254Smr /* Reinsert lock back into blocked list */ 132287096Salfred debuglog("Replacing blocked lock\n"); 1323132254Smr LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist); 132474462Salfred } 132587096Salfred } 132687096Salfred 132787096Salfred debuglog("Exiting retry_blockingfilelocklist\n"); 132887096Salfred} 132987096Salfred 133087096Salfred/* 133187096Salfred * Below here are routines associated with manipulating all 133287096Salfred * aspects of the partial file locking system (list, hardware, etc.) 133387096Salfred */ 133487096Salfred 133587096Salfred/* 133687096Salfred * Please note that lock monitoring must be done at this level which 133787096Salfred * keeps track of *individual* lock requests on lock and unlock 133887096Salfred * 133987096Salfred * XXX: Split unlocking is going to make the unlock code miserable 134087096Salfred */ 134187096Salfred 134287096Salfred/* 134387096Salfred * lock_partialfilelock: 134487096Salfred * 134587096Salfred * Argument fl gets modified as its list housekeeping entries get modified 134687096Salfred * upon insertion into the NFS lock list 134787096Salfred * 134887096Salfred * This routine makes several assumptions: 134987096Salfred * 1) It (will) pass locks through to flock to lock the entire underlying file 135087096Salfred * and then parcel out NFS locks if it gets control of the file. 135187096Salfred * This matches the old rpc.lockd file semantics (except where it 135287096Salfred * is now more correct). It is the safe solution, but will cause 135387096Salfred * overly restrictive blocking if someone is trying to use the 135487096Salfred * underlying files without using NFS. This appears to be an 135587096Salfred * acceptable tradeoff since most people use standalone NFS servers. 135687096Salfred * XXX: The right solution is probably kevent combined with fcntl 135787096Salfred * 135887096Salfred * 2) Nothing modifies the lock lists between testing and granting 135987096Salfred * I have no idea whether this is a useful assumption or not 136087096Salfred */ 136187096Salfred 136287096Salfredenum partialfilelock_status 136387096Salfredlock_partialfilelock(struct file_lock *fl) 136487096Salfred{ 136587096Salfred enum partialfilelock_status retval; 136687096Salfred enum nfslock_status lnlstatus; 136787096Salfred enum hwlock_status hwstatus; 136887096Salfred 136987096Salfred debuglog("Entering lock_partialfilelock\n"); 137087096Salfred 137187096Salfred retval = PFL_DENIED; 137287096Salfred 137387096Salfred /* 137487096Salfred * Execute the NFS lock first, if possible, as it is significantly 137587096Salfred * easier and less expensive to undo than the filesystem lock 137687096Salfred */ 137787096Salfred 137887096Salfred lnlstatus = lock_nfslock(fl); 137987096Salfred 138087096Salfred switch (lnlstatus) { 138187096Salfred case NFS_GRANTED: 138287096Salfred case NFS_GRANTED_DUPLICATE: 138374462Salfred /* 138487096Salfred * At this point, the NFS lock is allocated and active. 138587096Salfred * Remember to clean it up if the hardware lock fails 138674462Salfred */ 138787096Salfred hwstatus = lock_hwlock(fl); 138887096Salfred 138987096Salfred switch (hwstatus) { 139087096Salfred case HW_GRANTED: 139187096Salfred case HW_GRANTED_DUPLICATE: 139287096Salfred debuglog("HW GRANTED\n"); 139387096Salfred /* 139487096Salfred * XXX: Fixme: Check hwstatus for duplicate when 139587096Salfred * true partial file locking and accounting is 139687096Salfred * done on the hardware 139787096Salfred */ 139887096Salfred if (lnlstatus == NFS_GRANTED_DUPLICATE) { 139987096Salfred retval = PFL_GRANTED_DUPLICATE; 140087096Salfred } else { 140187096Salfred retval = PFL_GRANTED; 140287096Salfred } 140387096Salfred monitor_lock_host(fl->client_name); 140487096Salfred break; 140587096Salfred case HW_RESERR: 140687096Salfred debuglog("HW RESERR\n"); 140787096Salfred retval = PFL_HWRESERR; 140887096Salfred break; 140987096Salfred case HW_DENIED: 141087096Salfred debuglog("HW DENIED\n"); 141187096Salfred retval = PFL_HWDENIED; 141287096Salfred break; 141387096Salfred default: 141487096Salfred debuglog("Unmatched hwstatus %d\n",hwstatus); 141587096Salfred break; 141674462Salfred } 141787096Salfred 141887096Salfred if (retval != PFL_GRANTED && 141987096Salfred retval != PFL_GRANTED_DUPLICATE) { 142087096Salfred /* Clean up the NFS lock */ 142187096Salfred debuglog("Deleting trial NFS lock\n"); 142287096Salfred delete_nfslock(fl); 142387096Salfred } 142487096Salfred break; 142587096Salfred case NFS_DENIED: 142687096Salfred retval = PFL_NFSDENIED; 142787096Salfred break; 142887096Salfred case NFS_RESERR: 142987096Salfred retval = PFL_NFSRESERR; 143087096Salfred default: 143187096Salfred debuglog("Unmatched lnlstatus %d\n"); 143287096Salfred retval = PFL_NFSDENIED_NOLOCK; 143387096Salfred break; 143487096Salfred } 143587096Salfred 143687096Salfred /* 143787096Salfred * By the time fl reaches here, it is completely free again on 143887096Salfred * failure. The NFS lock done before attempting the 143987096Salfred * hardware lock has been backed out 144087096Salfred */ 144187096Salfred 144287096Salfred if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) { 144387096Salfred /* Once last chance to check the lock */ 144487096Salfred if (fl->blocking == 1) { 1445115004Srwatson if (retval == PFL_NFSDENIED) { 1446115004Srwatson /* Queue the lock */ 1447115004Srwatson debuglog("BLOCKING LOCK RECEIVED\n"); 1448115004Srwatson retval = PFL_NFSBLOCKED; 1449115004Srwatson add_blockingfilelock(fl); 1450115004Srwatson dump_filelock(fl); 1451115004Srwatson } else { 1452115004Srwatson /* retval is okay as PFL_HWDENIED */ 1453115004Srwatson debuglog("BLOCKING LOCK DENIED IN HARDWARE\n"); 1454115004Srwatson dump_filelock(fl); 1455115004Srwatson } 145674462Salfred } else { 145787096Salfred /* Leave retval alone, it's already correct */ 145887096Salfred debuglog("Lock denied. Non-blocking failure\n"); 145987096Salfred dump_filelock(fl); 146087096Salfred } 146187096Salfred } 146287096Salfred 146387096Salfred debuglog("Exiting lock_partialfilelock\n"); 146487096Salfred 146587096Salfred return retval; 146687096Salfred} 146787096Salfred 146887096Salfred/* 146987096Salfred * unlock_partialfilelock: 147087096Salfred * 147187096Salfred * Given a file_lock, unlock all locks which match. 147287096Salfred * 147387096Salfred * Note that a given lock might have to unlock ITSELF! See 147487096Salfred * clear_partialfilelock for example. 147587096Salfred */ 147687096Salfred 147787096Salfredenum partialfilelock_status 147887096Salfredunlock_partialfilelock(const struct file_lock *fl) 147987096Salfred{ 148087096Salfred struct file_lock *lfl,*rfl,*releasedfl,*selffl; 148187096Salfred enum partialfilelock_status retval; 148287096Salfred enum nfslock_status unlstatus; 148387096Salfred enum hwlock_status unlhwstatus, lhwstatus; 148487096Salfred 148587096Salfred debuglog("Entering unlock_partialfilelock\n"); 148687096Salfred 148787096Salfred selffl = NULL; 148887096Salfred lfl = NULL; 148987096Salfred rfl = NULL; 149087096Salfred releasedfl = NULL; 149187096Salfred retval = PFL_DENIED; 149287096Salfred 149387096Salfred /* 149487096Salfred * There are significant overlap and atomicity issues 149587096Salfred * with partially releasing a lock. For example, releasing 149687096Salfred * part of an NFS shared lock does *not* always release the 149787096Salfred * corresponding part of the file since there is only one 149887096Salfred * rpc.lockd UID but multiple users could be requesting it 149987096Salfred * from NFS. Also, an unlock request should never allow 150087096Salfred * another process to gain a lock on the remaining parts. 150187096Salfred * ie. Always apply the new locks before releasing the 150287096Salfred * old one 150387096Salfred */ 150487096Salfred 150587096Salfred /* 150687096Salfred * Loop is required since multiple little locks 150787096Salfred * can be allocated and then deallocated with one 150887096Salfred * big unlock. 150987096Salfred * 151087096Salfred * The loop is required to be here so that the nfs & 151187096Salfred * hw subsystems do not need to communicate with one 151287096Salfred * one another 151387096Salfred */ 151487096Salfred 151587096Salfred do { 151687096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 151787096Salfred /* lfl&rfl are created *AND* placed into the NFS lock list if required */ 151887096Salfred unlstatus = unlock_nfslock(fl, &releasedfl, &lfl, &rfl); 151987096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 152087096Salfred 152187096Salfred 152287096Salfred /* XXX: This is grungy. It should be refactored to be cleaner */ 152387096Salfred if (lfl != NULL) { 152487096Salfred lhwstatus = lock_hwlock(lfl); 152587096Salfred if (lhwstatus != HW_GRANTED && 152687096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 152787096Salfred debuglog("HW duplicate lock failure for left split\n"); 152874462Salfred } 152987096Salfred monitor_lock_host(lfl->client_name); 153087096Salfred } 153187096Salfred 153287096Salfred if (rfl != NULL) { 153387096Salfred lhwstatus = lock_hwlock(rfl); 153487096Salfred if (lhwstatus != HW_GRANTED && 153587096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 153687096Salfred debuglog("HW duplicate lock failure for right split\n"); 153787096Salfred } 153887096Salfred monitor_lock_host(rfl->client_name); 153987096Salfred } 154087096Salfred 154187096Salfred switch (unlstatus) { 154287096Salfred case NFS_GRANTED: 154387096Salfred /* Attempt to unlock on the hardware */ 154487096Salfred debuglog("NFS unlock granted. Attempting hardware unlock\n"); 154587096Salfred 154687096Salfred /* This call *MUST NOT* unlock the two newly allocated locks */ 154787096Salfred unlhwstatus = unlock_hwlock(fl); 154887096Salfred debuglog("HW unlock returned with code %d\n",unlhwstatus); 154987096Salfred 155087096Salfred switch (unlhwstatus) { 155187096Salfred case HW_GRANTED: 155287096Salfred debuglog("HW unlock granted\n"); 155387096Salfred unmonitor_lock_host(releasedfl->client_name); 155487096Salfred retval = PFL_GRANTED; 155574462Salfred break; 155687096Salfred case HW_DENIED_NOLOCK: 155787096Salfred /* Huh?!?! This shouldn't happen */ 155887096Salfred debuglog("HW unlock denied no lock\n"); 155987096Salfred retval = PFL_HWRESERR; 156087096Salfred /* Break out of do-while */ 156187096Salfred unlstatus = NFS_RESERR; 156274462Salfred break; 156374462Salfred default: 156487096Salfred debuglog("HW unlock failed\n"); 156587096Salfred retval = PFL_HWRESERR; 156687096Salfred /* Break out of do-while */ 156787096Salfred unlstatus = NFS_RESERR; 156887096Salfred break; 156974462Salfred } 157087096Salfred 157187096Salfred debuglog("Exiting with status retval: %d\n",retval); 157287096Salfred 157387096Salfred retry_blockingfilelocklist(); 157487096Salfred break; 157587096Salfred case NFS_DENIED_NOLOCK: 157687096Salfred retval = PFL_GRANTED; 157787096Salfred debuglog("All locks cleaned out\n"); 157887096Salfred break; 157987096Salfred default: 158087096Salfred retval = PFL_NFSRESERR; 158187096Salfred debuglog("NFS unlock failure\n"); 158287096Salfred dump_filelock(fl); 158387096Salfred break; 158474462Salfred } 158587096Salfred 158687096Salfred if (releasedfl != NULL) { 158787096Salfred if (fl == releasedfl) { 158887096Salfred /* 158987096Salfred * XXX: YECHHH!!! Attempt to unlock self succeeded 159087096Salfred * but we can't deallocate the space yet. This is what 159187096Salfred * happens when you don't write malloc and free together 159287096Salfred */ 159387096Salfred debuglog("Attempt to unlock self\n"); 159487096Salfred selffl = releasedfl; 159587096Salfred } else { 159687096Salfred /* 159787096Salfred * XXX: this deallocation *still* needs to migrate closer 159887096Salfred * to the allocation code way up in get_lock or the allocation 159987096Salfred * code needs to migrate down (violation of "When you write 160087096Salfred * malloc you must write free") 160187096Salfred */ 160287096Salfred 160387096Salfred deallocate_file_lock(releasedfl); 160487096Salfred } 160587096Salfred } 160687096Salfred 160787096Salfred } while (unlstatus == NFS_GRANTED); 160887096Salfred 160987096Salfred if (selffl != NULL) { 161087096Salfred /* 161187096Salfred * This statement wipes out the incoming file lock (fl) 161287096Salfred * in spite of the fact that it is declared const 161387096Salfred */ 161487096Salfred debuglog("WARNING! Destroying incoming lock pointer\n"); 161587096Salfred deallocate_file_lock(selffl); 161674462Salfred } 161787096Salfred 161887096Salfred debuglog("Exiting unlock_partialfilelock\n"); 161987096Salfred 162087096Salfred return retval; 162174462Salfred} 162274462Salfred 162374462Salfred/* 162487096Salfred * clear_partialfilelock 162574462Salfred * 162687096Salfred * Normally called in response to statd state number change. 162787096Salfred * Wipe out all locks held by a host. As a bonus, the act of 162887096Salfred * doing so should automatically clear their statd entries and 162987096Salfred * unmonitor the host. 163074462Salfred */ 163174462Salfred 163287096Salfredvoid 163387096Salfredclear_partialfilelock(const char *hostname) 163487096Salfred{ 163587096Salfred struct file_lock *ifl, *nfl; 163687096Salfred 163787096Salfred /* Clear blocking file lock list */ 163887096Salfred clear_blockingfilelock(hostname); 163987096Salfred 164087096Salfred /* do all required unlocks */ 164187096Salfred /* Note that unlock can smash the current pointer to a lock */ 164287096Salfred 164387096Salfred /* 164487096Salfred * Normally, LIST_FOREACH is called for, but since 164587096Salfred * the current element *is* the iterator, deleting it 164687096Salfred * would mess up the iteration. Thus, a next element 164787096Salfred * must be used explicitly 164887096Salfred */ 164987096Salfred 165087096Salfred ifl = LIST_FIRST(&nfslocklist_head); 165187096Salfred 165287096Salfred while (ifl != NULL) { 165387096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 165487096Salfred 165587096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 165687096Salfred /* Unlock destroys ifl out from underneath */ 165787096Salfred unlock_partialfilelock(ifl); 165887096Salfred /* ifl is NO LONGER VALID AT THIS POINT */ 165987096Salfred } 166087096Salfred ifl = nfl; 166187096Salfred } 166287096Salfred} 166387096Salfred 166487096Salfred/* 166587096Salfred * test_partialfilelock: 166687096Salfred */ 166787096Salfredenum partialfilelock_status 166887096Salfredtest_partialfilelock(const struct file_lock *fl, 166987096Salfred struct file_lock **conflicting_fl) 167087096Salfred{ 167187096Salfred enum partialfilelock_status retval; 167287096Salfred enum nfslock_status teststatus; 167387096Salfred 167487096Salfred debuglog("Entering testpartialfilelock...\n"); 167587096Salfred 167687096Salfred retval = PFL_DENIED; 167787096Salfred 167887096Salfred teststatus = test_nfslock(fl, conflicting_fl); 167987096Salfred debuglog("test_partialfilelock: teststatus %d\n",teststatus); 168087096Salfred 168187096Salfred if (teststatus == NFS_GRANTED || teststatus == NFS_GRANTED_DUPLICATE) { 168287096Salfred /* XXX: Add the underlying filesystem locking code */ 168387096Salfred retval = (teststatus == NFS_GRANTED) ? 168487096Salfred PFL_GRANTED : PFL_GRANTED_DUPLICATE; 168587096Salfred debuglog("Dumping locks...\n"); 168687096Salfred dump_filelock(fl); 168787096Salfred dump_filelock(*conflicting_fl); 168887096Salfred debuglog("Done dumping locks...\n"); 168987096Salfred } else { 169087096Salfred retval = PFL_NFSDENIED; 169187096Salfred debuglog("NFS test denied.\n"); 169287096Salfred dump_filelock(fl); 169387096Salfred debuglog("Conflicting.\n"); 169487096Salfred dump_filelock(*conflicting_fl); 169587096Salfred } 169687096Salfred 169787096Salfred debuglog("Exiting testpartialfilelock...\n"); 169887096Salfred 169987096Salfred return retval; 170087096Salfred} 170187096Salfred 170287096Salfred/* 170387096Salfred * Below here are routines associated with translating the partial file locking 170487096Salfred * codes into useful codes to send back to the NFS RPC messaging system 170587096Salfred */ 170687096Salfred 170787096Salfred/* 170887096Salfred * These routines translate the (relatively) useful return codes back onto 170987096Salfred * the few return codes which the nlm subsystems wishes to trasmit 171087096Salfred */ 171187096Salfred 171274462Salfredenum nlm_stats 171387096Salfreddo_test(struct file_lock *fl, struct file_lock **conflicting_fl) 171474462Salfred{ 171587096Salfred enum partialfilelock_status pfsret; 171687096Salfred enum nlm_stats retval; 171774462Salfred 171887096Salfred debuglog("Entering do_test...\n"); 171987096Salfred 172087096Salfred pfsret = test_partialfilelock(fl,conflicting_fl); 172187096Salfred 172287096Salfred switch (pfsret) { 172387096Salfred case PFL_GRANTED: 172487096Salfred debuglog("PFL test lock granted\n"); 172587096Salfred dump_filelock(fl); 172687096Salfred dump_filelock(*conflicting_fl); 172787096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 172887096Salfred break; 172987096Salfred case PFL_GRANTED_DUPLICATE: 173087096Salfred debuglog("PFL test lock granted--duplicate id detected\n"); 173187096Salfred dump_filelock(fl); 173287096Salfred dump_filelock(*conflicting_fl); 173387096Salfred debuglog("Clearing conflicting_fl for call semantics\n"); 173487096Salfred *conflicting_fl = NULL; 173587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 173687096Salfred break; 173787096Salfred case PFL_NFSDENIED: 173887096Salfred case PFL_HWDENIED: 173987096Salfred debuglog("PFL test lock denied\n"); 174087096Salfred dump_filelock(fl); 174187096Salfred dump_filelock(*conflicting_fl); 174287096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 174387096Salfred break; 174487096Salfred case PFL_NFSRESERR: 174587096Salfred case PFL_HWRESERR: 174687096Salfred debuglog("PFL test lock resource fail\n"); 174787096Salfred dump_filelock(fl); 174887096Salfred dump_filelock(*conflicting_fl); 174987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 175087096Salfred break; 175187096Salfred default: 175287096Salfred debuglog("PFL test lock *FAILED*\n"); 175387096Salfred dump_filelock(fl); 175487096Salfred dump_filelock(*conflicting_fl); 175587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 175687096Salfred break; 175787096Salfred } 175887096Salfred 175987096Salfred debuglog("Exiting do_test...\n"); 176087096Salfred 176187096Salfred return retval; 176287096Salfred} 176387096Salfred 176487096Salfred/* 176587096Salfred * do_lock: Try to acquire a lock 176687096Salfred * 176787096Salfred * This routine makes a distinction between NLM versions. I am pretty 176887096Salfred * convinced that this should be abstracted out and bounced up a level 176987096Salfred */ 177087096Salfred 177187096Salfredenum nlm_stats 177287096Salfreddo_lock(struct file_lock *fl) 177387096Salfred{ 177487096Salfred enum partialfilelock_status pfsret; 177587096Salfred enum nlm_stats retval; 177687096Salfred 177787096Salfred debuglog("Entering do_lock...\n"); 177887096Salfred 177987096Salfred pfsret = lock_partialfilelock(fl); 178087096Salfred 178187096Salfred switch (pfsret) { 178287096Salfred case PFL_GRANTED: 178387096Salfred debuglog("PFL lock granted"); 178487096Salfred dump_filelock(fl); 178587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 178687096Salfred break; 178787096Salfred case PFL_GRANTED_DUPLICATE: 178887096Salfred debuglog("PFL lock granted--duplicate id detected"); 178987096Salfred dump_filelock(fl); 179087096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 179187096Salfred break; 179287096Salfred case PFL_NFSDENIED: 179387096Salfred case PFL_HWDENIED: 179487096Salfred debuglog("PFL_NFS lock denied"); 179587096Salfred dump_filelock(fl); 179687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 179787096Salfred break; 179887096Salfred case PFL_NFSBLOCKED: 179987096Salfred case PFL_HWBLOCKED: 180087096Salfred debuglog("PFL_NFS blocking lock denied. Queued.\n"); 180187096Salfred dump_filelock(fl); 180287096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_blocked : nlm_blocked; 180387096Salfred break; 180487096Salfred case PFL_NFSRESERR: 180587096Salfred case PFL_HWRESERR: 180687096Salfred debuglog("PFL lock resource alocation fail\n"); 180787096Salfred dump_filelock(fl); 180887096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 180987096Salfred break; 181087096Salfred default: 181187096Salfred debuglog("PFL lock *FAILED*"); 181287096Salfred dump_filelock(fl); 181387096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 181487096Salfred break; 181587096Salfred } 181687096Salfred 181787096Salfred debuglog("Exiting do_lock...\n"); 181887096Salfred 181987096Salfred return retval; 182087096Salfred} 182187096Salfred 182287096Salfredenum nlm_stats 182387096Salfreddo_unlock(struct file_lock *fl) 182487096Salfred{ 182587096Salfred enum partialfilelock_status pfsret; 182687096Salfred enum nlm_stats retval; 182787096Salfred 182887096Salfred debuglog("Entering do_unlock...\n"); 182987096Salfred pfsret = unlock_partialfilelock(fl); 183087096Salfred 183187096Salfred switch (pfsret) { 183287096Salfred case PFL_GRANTED: 183387096Salfred debuglog("PFL unlock granted"); 183487096Salfred dump_filelock(fl); 183587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 183687096Salfred break; 183787096Salfred case PFL_NFSDENIED: 183887096Salfred case PFL_HWDENIED: 183987096Salfred debuglog("PFL_NFS unlock denied"); 184087096Salfred dump_filelock(fl); 184187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 184287096Salfred break; 184387096Salfred case PFL_NFSDENIED_NOLOCK: 184487096Salfred case PFL_HWDENIED_NOLOCK: 184587096Salfred debuglog("PFL_NFS no lock found\n"); 184687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 184787096Salfred break; 184887096Salfred case PFL_NFSRESERR: 184987096Salfred case PFL_HWRESERR: 185087096Salfred debuglog("PFL unlock resource failure"); 185187096Salfred dump_filelock(fl); 185287096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 185387096Salfred break; 185487096Salfred default: 185587096Salfred debuglog("PFL unlock *FAILED*"); 185687096Salfred dump_filelock(fl); 185787096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 185887096Salfred break; 185987096Salfred } 186087096Salfred 186187096Salfred debuglog("Exiting do_unlock...\n"); 186287096Salfred 186387096Salfred return retval; 186487096Salfred} 186587096Salfred 186687096Salfred/* 186787096Salfred * do_clear 186887096Salfred * 186987096Salfred * This routine is non-existent because it doesn't have a return code. 187087096Salfred * It is here for completeness in case someone *does* need to do return 187187096Salfred * codes later. A decent compiler should optimize this away. 187287096Salfred */ 187387096Salfred 187487096Salfredvoid 187587096Salfreddo_clear(const char *hostname) 187687096Salfred{ 187787096Salfred 187887096Salfred clear_partialfilelock(hostname); 187987096Salfred} 188087096Salfred 188187096Salfred/* 188287096Salfred * The following routines are all called from the code which the 188387096Salfred * RPC layer invokes 188487096Salfred */ 188587096Salfred 188687096Salfred/* 188787096Salfred * testlock(): inform the caller if the requested lock would be granted 188887096Salfred * 188987096Salfred * returns NULL if lock would granted 189087096Salfred * returns pointer to a conflicting nlm4_holder if not 189187096Salfred */ 189287096Salfred 189387096Salfredstruct nlm4_holder * 189492911Salfredtestlock(struct nlm4_lock *lock, bool_t exclusive, int flags __unused) 189587096Salfred{ 189687096Salfred struct file_lock test_fl, *conflicting_fl; 189787096Salfred 189887096Salfred bzero(&test_fl, sizeof(test_fl)); 189987096Salfred 190087096Salfred bcopy(lock->fh.n_bytes, &(test_fl.filehandle), sizeof(fhandle_t)); 190187096Salfred copy_nlm4_lock_to_nlm4_holder(lock, exclusive, &test_fl.client); 190287096Salfred 190387096Salfred siglock(); 190487096Salfred do_test(&test_fl, &conflicting_fl); 190587096Salfred 190687096Salfred if (conflicting_fl == NULL) { 190787096Salfred debuglog("No conflicting lock found\n"); 190887096Salfred sigunlock(); 190987096Salfred return NULL; 191087096Salfred } else { 191187096Salfred debuglog("Found conflicting lock\n"); 191287096Salfred dump_filelock(conflicting_fl); 191387096Salfred sigunlock(); 191487096Salfred return (&conflicting_fl->client); 191587096Salfred } 191687096Salfred} 191787096Salfred 191887096Salfred/* 191987096Salfred * getlock: try to aquire the lock. 192087096Salfred * If file is already locked and we can sleep, put the lock in the list with 192187096Salfred * status LKST_WAITING; it'll be processed later. 192287096Salfred * Otherwise try to lock. If we're allowed to block, fork a child which 192387096Salfred * will do the blocking lock. 192487096Salfred */ 192587096Salfred 192687096Salfredenum nlm_stats 192787096Salfredgetlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) 192887096Salfred{ 192987096Salfred struct file_lock *newfl; 193087096Salfred enum nlm_stats retval; 193187096Salfred 193287096Salfred debuglog("Entering getlock...\n"); 193387096Salfred 193487096Salfred if (grace_expired == 0 && lckarg->reclaim == 0) 193587096Salfred return (flags & LOCK_V4) ? 193687096Salfred nlm4_denied_grace_period : nlm_denied_grace_period; 193787096Salfred 193887096Salfred /* allocate new file_lock for this request */ 1939132254Smr newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie, 1940132254Smr (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf, lckarg->alock.caller_name); 194187096Salfred if (newfl == NULL) { 194287096Salfred syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); 194387096Salfred /* failed */ 194487096Salfred return (flags & LOCK_V4) ? 194587096Salfred nlm4_denied_nolocks : nlm_denied_nolocks; 194687096Salfred } 194787096Salfred 194887096Salfred if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) { 194987096Salfred debuglog("recieved fhandle size %d, local size %d", 195087096Salfred lckarg->alock.fh.n_len, (int)sizeof(fhandle_t)); 195187096Salfred } 195287096Salfred 195387096Salfred fill_file_lock(newfl, (fhandle_t *)lckarg->alock.fh.n_bytes, 195487199Salfred lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, 195587199Salfred lckarg->alock.l_len, 1956132254Smr lckarg->state, 0, flags, lckarg->block); 195787096Salfred 195887096Salfred /* 195987096Salfred * newfl is now fully constructed and deallocate_file_lock 196087096Salfred * can now be used to delete it 196187096Salfred */ 196287096Salfred 196387096Salfred siglock(); 196487096Salfred debuglog("Pointer to new lock is %p\n",newfl); 196587096Salfred 196687096Salfred retval = do_lock(newfl); 196787096Salfred 196887096Salfred debuglog("Pointer to new lock is %p\n",newfl); 196987096Salfred sigunlock(); 197087096Salfred 197187096Salfred switch (retval) 197287096Salfred { 197387096Salfred case nlm4_granted: 197487096Salfred /* case nlm_granted: is the same as nlm4_granted */ 197587096Salfred /* do_mon(lckarg->alock.caller_name); */ 197674462Salfred break; 197787096Salfred case nlm4_blocked: 197887096Salfred /* case nlm_blocked: is the same as nlm4_blocked */ 197987096Salfred /* do_mon(lckarg->alock.caller_name); */ 198074462Salfred break; 198174462Salfred default: 198287096Salfred deallocate_file_lock(newfl); 198387096Salfred break; 198474462Salfred } 198587096Salfred 198687096Salfred debuglog("Exiting getlock...\n"); 198787096Salfred 198887096Salfred return retval; 198987096Salfred} 199087096Salfred 199187096Salfred 199287096Salfred/* unlock a filehandle */ 199387096Salfredenum nlm_stats 199492911Salfredunlock(nlm4_lock *lock, const int flags __unused) 199587096Salfred{ 199687096Salfred struct file_lock fl; 199787096Salfred enum nlm_stats err; 199887096Salfred 199987096Salfred siglock(); 200087096Salfred 200187096Salfred debuglog("Entering unlock...\n"); 200287096Salfred 200387096Salfred bzero(&fl,sizeof(struct file_lock)); 200487096Salfred bcopy(lock->fh.n_bytes, &fl.filehandle, sizeof(fhandle_t)); 200587096Salfred 200687096Salfred copy_nlm4_lock_to_nlm4_holder(lock, 0, &fl.client); 200787096Salfred 200887096Salfred err = do_unlock(&fl); 200987096Salfred 201087096Salfred sigunlock(); 201187096Salfred 201287096Salfred debuglog("Exiting unlock...\n"); 201387096Salfred 201487096Salfred return err; 201587096Salfred} 201687096Salfred 201787096Salfred/* 201887096Salfred * XXX: The following monitor/unmonitor routines 201987096Salfred * have not been extensively tested (ie. no regression 202087096Salfred * script exists like for the locking sections 202187096Salfred */ 202287096Salfred 202387096Salfred/* 202487096Salfred * monitor_lock_host: monitor lock hosts locally with a ref count and 202587096Salfred * inform statd 202687096Salfred */ 202787096Salfredvoid 202887096Salfredmonitor_lock_host(const char *hostname) 202987096Salfred{ 203087096Salfred struct host *ihp, *nhp; 203187096Salfred struct mon smon; 203287096Salfred struct sm_stat_res sres; 203387096Salfred int rpcret, statflag; 2034132254Smr size_t n; 203587096Salfred 203687096Salfred rpcret = 0; 203787096Salfred statflag = 0; 203887096Salfred 203987096Salfred LIST_FOREACH(ihp, &hostlst_head, hostlst) { 204087096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 204187096Salfred /* Host is already monitored, bump refcount */ 204287096Salfred ++ihp->refcnt; 204387096Salfred /* Host should only be in the monitor list once */ 204487096Salfred return; 204587096Salfred } 204674462Salfred } 204787096Salfred 204887096Salfred /* Host is not yet monitored, add it */ 2049132254Smr n = strnlen(hostname, SM_MAXSTRLEN); 2050132254Smr if (n == SM_MAXSTRLEN) { 2051132254Smr return; 2052132254Smr } 2053132254Smr nhp = malloc(sizeof(*nhp) - sizeof(nhp->name) + n + 1); 205487096Salfred if (nhp == NULL) { 205587096Salfred debuglog("Unable to allocate entry for statd mon\n"); 205687096Salfred return; 205774462Salfred } 205887096Salfred 205987096Salfred /* Allocated new host entry, now fill the fields */ 2060132254Smr memcpy(nhp->name, hostname, n); 2061132254Smr nhp->name[n] = 0; 206287096Salfred nhp->refcnt = 1; 206387096Salfred debuglog("Locally Monitoring host %16s\n",hostname); 206487096Salfred 206587096Salfred debuglog("Attempting to tell statd\n"); 206687096Salfred 206787096Salfred bzero(&smon,sizeof(smon)); 206887096Salfred 206987096Salfred smon.mon_id.mon_name = nhp->name; 2070161231Sthomas smon.mon_id.my_id.my_name = "localhost"; 207187096Salfred smon.mon_id.my_id.my_prog = NLM_PROG; 207287096Salfred smon.mon_id.my_id.my_vers = NLM_SM; 207387096Salfred smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 207487096Salfred 2075121558Speter rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, 2076121558Speter (xdrproc_t)xdr_mon, &smon, 2077121558Speter (xdrproc_t)xdr_sm_stat_res, &sres); 207887096Salfred 207987096Salfred if (rpcret == 0) { 208087096Salfred if (sres.res_stat == stat_fail) { 208187096Salfred debuglog("Statd call failed\n"); 208287096Salfred statflag = 0; 208387096Salfred } else { 208487096Salfred statflag = 1; 208574462Salfred } 208687096Salfred } else { 208787096Salfred debuglog("Rpc call to statd failed with return value: %d\n", 208887096Salfred rpcret); 208987096Salfred statflag = 0; 209074462Salfred } 209187096Salfred 209287096Salfred if (statflag == 1) { 209387096Salfred LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst); 209487096Salfred } else { 209587096Salfred free(nhp); 209687096Salfred } 209787096Salfred 209887096Salfred} 209987096Salfred 210087096Salfred/* 210187096Salfred * unmonitor_lock_host: clear monitor ref counts and inform statd when gone 210287096Salfred */ 210387096Salfredvoid 2104121558Speterunmonitor_lock_host(char *hostname) 210587096Salfred{ 210687096Salfred struct host *ihp; 210787096Salfred struct mon_id smon_id; 210887096Salfred struct sm_stat smstat; 210987096Salfred int rpcret; 211087096Salfred 211187096Salfred rpcret = 0; 211287096Salfred 211387096Salfred for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL; 211487096Salfred ihp=LIST_NEXT(ihp, hostlst)) { 211587096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 211687096Salfred /* Host is monitored, bump refcount */ 211787096Salfred --ihp->refcnt; 211887096Salfred /* Host should only be in the monitor list once */ 211974462Salfred break; 212074462Salfred } 212174462Salfred } 212287096Salfred 212387096Salfred if (ihp == NULL) { 212487096Salfred debuglog("Could not find host %16s in mon list\n", hostname); 212587096Salfred return; 212687096Salfred } 212787096Salfred 212887096Salfred if (ihp->refcnt > 0) 212987096Salfred return; 213087096Salfred 213187096Salfred if (ihp->refcnt < 0) { 213287096Salfred debuglog("Negative refcount!: %d\n", 213387096Salfred ihp->refcnt); 213487096Salfred } 213587096Salfred 213687096Salfred debuglog("Attempting to unmonitor host %16s\n", hostname); 213787096Salfred 213887096Salfred bzero(&smon_id,sizeof(smon_id)); 213987096Salfred 214092975Salfred smon_id.mon_name = hostname; 214187096Salfred smon_id.my_id.my_name = "localhost"; 214287096Salfred smon_id.my_id.my_prog = NLM_PROG; 214387096Salfred smon_id.my_id.my_vers = NLM_SM; 214487096Salfred smon_id.my_id.my_proc = NLM_SM_NOTIFY; 214587096Salfred 2146121558Speter rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, 2147125903Salfred (xdrproc_t)xdr_mon_id, &smon_id, 2148125903Salfred (xdrproc_t)xdr_sm_stat, &smstat); 214987096Salfred 215087096Salfred if (rpcret != 0) { 215187096Salfred debuglog("Rpc call to unmonitor statd failed with " 215287096Salfred " return value: %d\n", rpcret); 215387096Salfred } 215487096Salfred 215587096Salfred LIST_REMOVE(ihp, hostlst); 215687096Salfred free(ihp); 215774462Salfred} 215874462Salfred 215987096Salfred/* 216087096Salfred * notify: Clear all locks from a host if statd complains 216187096Salfred * 216287096Salfred * XXX: This routine has not been thoroughly tested. However, neither 216387096Salfred * had the old one been. It used to compare the statd crash state counter 216487096Salfred * to the current lock state. The upshot of this was that it basically 216587096Salfred * cleared all locks from the specified host 99% of the time (with the 216687096Salfred * other 1% being a bug). Consequently, the assumption is that clearing 216787096Salfred * all locks from a host when notified by statd is acceptable. 216887096Salfred * 216987096Salfred * Please note that this routine skips the usual level of redirection 217087096Salfred * through a do_* type routine. This introduces a possible level of 217187096Salfred * error and might better be written as do_notify and take this one out. 217287096Salfred 217387096Salfred */ 217487096Salfred 217574462Salfredvoid 217687096Salfrednotify(const char *hostname, const int state) 217787096Salfred{ 217887096Salfred debuglog("notify from %s, new state %d", hostname, state); 217987096Salfred 218087096Salfred siglock(); 218187096Salfred do_clear(hostname); 218287096Salfred sigunlock(); 218387096Salfred 218487096Salfred debuglog("Leaving notify\n"); 218587096Salfred} 218687096Salfred 218787096Salfredvoid 218874462Salfredsend_granted(fl, opcode) 218974462Salfred struct file_lock *fl; 219092911Salfred int opcode __unused; 219174462Salfred{ 219274462Salfred CLIENT *cli; 219374462Salfred static char dummy; 219474462Salfred struct timeval timeo; 219574462Salfred int success; 219674462Salfred static struct nlm_res retval; 219774462Salfred static struct nlm4_res retval4; 219874462Salfred 219987096Salfred debuglog("About to send granted on blocked lock\n"); 220087096Salfred 220174462Salfred cli = get_client(fl->addr, 220274462Salfred (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); 220374462Salfred if (cli == NULL) { 220474462Salfred syslog(LOG_NOTICE, "failed to get CLIENT for %s", 220574462Salfred fl->client_name); 220674462Salfred /* 220774462Salfred * We fail to notify remote that the lock has been granted. 220874462Salfred * The client will timeout and retry, the lock will be 220974462Salfred * granted at this time. 221074462Salfred */ 221174462Salfred return; 221274462Salfred } 221374462Salfred timeo.tv_sec = 0; 221474462Salfred timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ 221574462Salfred 221674462Salfred if (fl->flags & LOCK_V4) { 221774462Salfred static nlm4_testargs res; 221874462Salfred res.cookie = fl->client_cookie; 221974462Salfred res.exclusive = fl->client.exclusive; 222074462Salfred res.alock.caller_name = fl->client_name; 222174462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 222274462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 222374462Salfred res.alock.oh = fl->client.oh; 222474462Salfred res.alock.svid = fl->client.svid; 222574462Salfred res.alock.l_offset = fl->client.l_offset; 222674462Salfred res.alock.l_len = fl->client.l_len; 222787096Salfred debuglog("sending v4 reply%s", 222887096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 222974462Salfred if (fl->flags & LOCK_ASYNC) { 223074462Salfred success = clnt_call(cli, NLM4_GRANTED_MSG, 2231121558Speter (xdrproc_t)xdr_nlm4_testargs, &res, 2232121558Speter (xdrproc_t)xdr_void, &dummy, timeo); 223374462Salfred } else { 223474462Salfred success = clnt_call(cli, NLM4_GRANTED, 2235121558Speter (xdrproc_t)xdr_nlm4_testargs, &res, 2236121558Speter (xdrproc_t)xdr_nlm4_res, &retval4, timeo); 223774462Salfred } 223874462Salfred } else { 223974462Salfred static nlm_testargs res; 224074462Salfred 224174462Salfred res.cookie = fl->client_cookie; 224274462Salfred res.exclusive = fl->client.exclusive; 224374462Salfred res.alock.caller_name = fl->client_name; 224474462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 224574462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 224674462Salfred res.alock.oh = fl->client.oh; 224774462Salfred res.alock.svid = fl->client.svid; 224874462Salfred res.alock.l_offset = fl->client.l_offset; 224974462Salfred res.alock.l_len = fl->client.l_len; 225087096Salfred debuglog("sending v1 reply%s", 225187096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 225274462Salfred if (fl->flags & LOCK_ASYNC) { 225374462Salfred success = clnt_call(cli, NLM_GRANTED_MSG, 2254121558Speter (xdrproc_t)xdr_nlm_testargs, &res, 2255121558Speter (xdrproc_t)xdr_void, &dummy, timeo); 225674462Salfred } else { 225774462Salfred success = clnt_call(cli, NLM_GRANTED, 2258121558Speter (xdrproc_t)xdr_nlm_testargs, &res, 2259121558Speter (xdrproc_t)xdr_nlm_res, &retval, timeo); 226074462Salfred } 226174462Salfred } 226274462Salfred if (debug_level > 2) 226387096Salfred debuglog("clnt_call returns %d(%s) for granted", 226487096Salfred success, clnt_sperrno(success)); 226574462Salfred 226674462Salfred} 226774462Salfred 226887096Salfred/* 226987096Salfred * Routines below here have not been modified in the overhaul 227087096Salfred */ 227174462Salfred 227287096Salfred/* 227387096Salfred * Are these two routines still required since lockd is not spawning off 227487096Salfred * children to service locks anymore? Presumably they were originally 227587096Salfred * put in place to prevent a one child from changing the lock list out 227687096Salfred * from under another one. 227787096Salfred */ 227874462Salfred 227974462Salfredvoid 228087096Salfredsiglock(void) 228174462Salfred{ 228287096Salfred sigset_t block; 228374462Salfred 228487096Salfred sigemptyset(&block); 228587096Salfred sigaddset(&block, SIGCHLD); 228674462Salfred 228787096Salfred if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) { 228887096Salfred syslog(LOG_WARNING, "siglock failed: %s", strerror(errno)); 228987096Salfred } 229074462Salfred} 229174462Salfred 229274462Salfredvoid 229387096Salfredsigunlock(void) 229474462Salfred{ 229587096Salfred sigset_t block; 229674462Salfred 229787096Salfred sigemptyset(&block); 229887096Salfred sigaddset(&block, SIGCHLD); 229987096Salfred 230087096Salfred if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) { 230187096Salfred syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno)); 230287096Salfred } 230374462Salfred} 230474462Salfred 230574462Salfred 2306