lockd_lock.c revision 92911
174462Salfred/* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */ 274462Salfred/* $FreeBSD: head/usr.sbin/rpc.lockd/lockd_lock.c 92911 2002-03-21 23:05:13Z alfred $ */ 374462Salfred 474462Salfred/* 587096Salfred * Copyright (c) 2001 Andrew P. Lentvorski, Jr. 674462Salfred * Copyright (c) 2000 Manuel Bouyer. 774462Salfred * 874462Salfred * Redistribution and use in source and binary forms, with or without 974462Salfred * modification, are permitted provided that the following conditions 1074462Salfred * are met: 1174462Salfred * 1. Redistributions of source code must retain the above copyright 1274462Salfred * notice, this list of conditions and the following disclaimer. 1374462Salfred * 2. Redistributions in binary form must reproduce the above copyright 1474462Salfred * notice, this list of conditions and the following disclaimer in the 1574462Salfred * documentation and/or other materials provided with the distribution. 1674462Salfred * 3. All advertising materials mentioning features or use of this software 1774462Salfred * must display the following acknowledgement: 1874462Salfred * This product includes software developed by the University of 1974462Salfred * California, Berkeley and its contributors. 2074462Salfred * 4. Neither the name of the University nor the names of its contributors 2174462Salfred * may be used to endorse or promote products derived from this software 2274462Salfred * without specific prior written permission. 2374462Salfred * 2474462Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2574462Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2674462Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2774462Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2874462Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2974462Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3074462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3174462Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3274462Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3374462Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3474462Salfred * SUCH DAMAGE. 3574462Salfred * 3674462Salfred */ 3774462Salfred 3887096Salfred#define LOCKD_DEBUG 3987096Salfred 4074462Salfred#include <stdio.h> 4187096Salfred#ifdef LOCKD_DEBUG 4287096Salfred#include <stdarg.h> 4387096Salfred#endif 4474462Salfred#include <stdlib.h> 4574462Salfred#include <unistd.h> 4674462Salfred#include <fcntl.h> 4774462Salfred#include <syslog.h> 4874462Salfred#include <errno.h> 4974462Salfred#include <string.h> 5074462Salfred#include <signal.h> 5174462Salfred#include <rpc/rpc.h> 5274462Salfred#include <sys/types.h> 5374462Salfred#include <sys/stat.h> 5474462Salfred#include <sys/socket.h> 5574462Salfred#include <sys/param.h> 5674462Salfred#include <sys/mount.h> 5774462Salfred#include <sys/wait.h> 5874462Salfred#include <rpcsvc/sm_inter.h> 5974462Salfred#include <rpcsvc/nlm_prot.h> 6074462Salfred#include "lockd_lock.h" 6174462Salfred#include "lockd.h" 6274462Salfred 6387096Salfred#define MAXOBJECTSIZE 64 6487096Salfred#define MAXBUFFERSIZE 1024 6587096Salfred 6684923Salfred/* 6787096Salfred * SM_MAXSTRLEN is usually 1024. This means that lock requests and 6887096Salfred * host name monitoring entries are *MUCH* larger than they should be 6987096Salfred */ 7087096Salfred 7187096Salfred/* 7284923Salfred * A set of utilities for managing file locking 7384923Salfred * 7484923Salfred * XXX: All locks are in a linked list, a better structure should be used 7584923Salfred * to improve search/access effeciency. 7684923Salfred */ 7774462Salfred 7874462Salfred/* struct describing a lock */ 7974462Salfredstruct file_lock { 8087096Salfred LIST_ENTRY(file_lock) nfslocklist; 8174462Salfred fhandle_t filehandle; /* NFS filehandle */ 8274462Salfred struct sockaddr *addr; 8374462Salfred struct nlm4_holder client; /* lock holder */ 8487096Salfred /* XXX: client_cookie used *only* in send_granted */ 8574462Salfred netobj client_cookie; /* cookie sent by the client */ 8687096Salfred char client_name[SM_MAXSTRLEN]; 8774462Salfred int nsm_status; /* status from the remote lock manager */ 8874462Salfred int status; /* lock status, see below */ 8974462Salfred int flags; /* lock flags, see lockd_lock.h */ 9087096Salfred int blocking; /* blocking lock or not */ 9174462Salfred pid_t locker; /* pid of the child process trying to get the lock */ 9274462Salfred int fd; /* file descriptor for this lock */ 9374462Salfred}; 9474462Salfred 9587096SalfredLIST_HEAD(nfslocklist_head, file_lock); 9687096Salfredstruct nfslocklist_head nfslocklist_head = LIST_HEAD_INITIALIZER(nfslocklist_head); 9787096Salfred 9887096SalfredLIST_HEAD(blockedlocklist_head, file_lock); 9987096Salfredstruct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blockedlocklist_head); 10087096Salfred 10174462Salfred/* lock status */ 10274462Salfred#define LKST_LOCKED 1 /* lock is locked */ 10384923Salfred/* XXX: Is this flag file specific or lock specific? */ 10474462Salfred#define LKST_WAITING 2 /* file is already locked by another host */ 10574462Salfred#define LKST_PROCESSING 3 /* child is trying to aquire the lock */ 10674462Salfred#define LKST_DYING 4 /* must dies when we get news from the child */ 10774462Salfred 10887096Salfred/* struct describing a monitored host */ 10974462Salfredstruct host { 11074462Salfred LIST_ENTRY(host) hostlst; 11174462Salfred char name[SM_MAXSTRLEN]; 11274462Salfred int refcnt; 11374462Salfred}; 11487096Salfred/* list of hosts we monitor */ 11587096SalfredLIST_HEAD(hostlst_head, host); 11687096Salfredstruct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); 11774462Salfred 11887096Salfred/* 11987096Salfred * File monitoring handlers 12087096Salfred * XXX: These might be able to be removed when kevent support 12187096Salfred * is placed into the hardware lock/unlock routines. (ie. 12287096Salfred * let the kernel do all the file monitoring) 12387096Salfred */ 12474462Salfred 12587096Salfred/* Struct describing a monitored file */ 12687096Salfredstruct monfile { 12787096Salfred LIST_ENTRY(monfile) monfilelist; 12887096Salfred fhandle_t filehandle; /* Local access filehandle */ 12987096Salfred int fd; /* file descriptor: remains open until unlock! */ 13087096Salfred int refcount; 13187096Salfred int exclusive; 13287096Salfred}; 13387096Salfred 13487096Salfred/* List of files we monitor */ 13587096SalfredLIST_HEAD(monfilelist_head, monfile); 13687096Salfredstruct monfilelist_head monfilelist_head = LIST_HEAD_INITIALIZER(monfilelist_head); 13787096Salfred 13887096Salfredstatic int debugdelay = 0; 13987096Salfred 14087096Salfredenum nfslock_status { NFS_GRANTED = 0, NFS_GRANTED_DUPLICATE, 14187096Salfred NFS_DENIED, NFS_DENIED_NOLOCK, 14287096Salfred NFS_RESERR }; 14387096Salfred 14487096Salfredenum hwlock_status { HW_GRANTED = 0, HW_GRANTED_DUPLICATE, 14587096Salfred HW_DENIED, HW_DENIED_NOLOCK, 14687096Salfred HW_STALEFH, HW_READONLY, HW_RESERR }; 14787096Salfred 14887096Salfredenum partialfilelock_status { PFL_GRANTED=0, PFL_GRANTED_DUPLICATE, PFL_DENIED, 14987096Salfred PFL_NFSDENIED, PFL_NFSBLOCKED, PFL_NFSDENIED_NOLOCK, PFL_NFSRESERR, 15087096Salfred PFL_HWDENIED, PFL_HWBLOCKED, PFL_HWDENIED_NOLOCK, PFL_HWRESERR}; 15187096Salfred 15287096Salfredenum LFLAGS {LEDGE_LEFT, LEDGE_LBOUNDARY, LEDGE_INSIDE, LEDGE_RBOUNDARY, LEDGE_RIGHT}; 15387096Salfredenum RFLAGS {REDGE_LEFT, REDGE_LBOUNDARY, REDGE_INSIDE, REDGE_RBOUNDARY, REDGE_RIGHT}; 15487096Salfred/* XXX: WARNING! I HAVE OVERLOADED THIS STATUS ENUM! SPLIT IT APART INTO TWO */ 15587096Salfredenum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SPL_RESERR=8}; 15687096Salfred 15787096Salfredenum partialfilelock_status lock_partialfilelock(struct file_lock *fl); 15887096Salfred 15987096Salfredvoid send_granted(struct file_lock *fl, int opcode); 16087096Salfredvoid siglock(void); 16187096Salfredvoid sigunlock(void); 16287096Salfredvoid monitor_lock_host(const char *hostname); 16387096Salfredvoid unmonitor_lock_host(const char *hostname); 16487096Salfred 16587096Salfredvoid copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, 16687096Salfred const bool_t exclusive, struct nlm4_holder *dest); 16787199Salfredstruct file_lock * allocate_file_lock(const netobj *lockowner, 16887199Salfred const netobj *matchcookie); 16987096Salfredvoid deallocate_file_lock(struct file_lock *fl); 17087199Salfredvoid fill_file_lock(struct file_lock *fl, const fhandle_t *fh, 17187199Salfred struct sockaddr *addr, const bool_t exclusive, const int32_t svid, 17287199Salfred const u_int64_t offset, const u_int64_t len, const char *caller_name, 17387199Salfred const int state, const int status, const int flags, const int blocking); 17487096Salfredint regions_overlap(const u_int64_t start1, const u_int64_t len1, 17587096Salfred const u_int64_t start2, const u_int64_t len2);; 17687096Salfredenum split_status region_compare(const u_int64_t starte, const u_int64_t lene, 17787096Salfred const u_int64_t startu, const u_int64_t lenu, 17887096Salfred u_int64_t *start1, u_int64_t *len1, u_int64_t *start2, u_int64_t *len2); 17987096Salfredint same_netobj(const netobj *n0, const netobj *n1); 18087096Salfredint same_filelock_identity(const struct file_lock *fl0, 18187096Salfred const struct file_lock *fl2); 18287096Salfred 18387096Salfredstatic void debuglog(char const *fmt, ...); 18487096Salfredvoid dump_static_object(const unsigned char* object, const int sizeof_object, 18587096Salfred unsigned char* hbuff, const int sizeof_hbuff, 18687096Salfred unsigned char* cbuff, const int sizeof_cbuff); 18787096Salfredvoid dump_netobj(const struct netobj *nobj); 18887096Salfredvoid dump_filelock(const struct file_lock *fl); 18987096Salfredstruct file_lock * get_lock_matching_unlock(const struct file_lock *fl); 19087096Salfredenum nfslock_status test_nfslock(const struct file_lock *fl, 19187096Salfred struct file_lock **conflicting_fl); 19287096Salfredenum nfslock_status lock_nfslock(struct file_lock *fl); 19387096Salfredenum nfslock_status delete_nfslock(struct file_lock *fl); 19487096Salfredenum nfslock_status unlock_nfslock(const struct file_lock *fl, 19587096Salfred struct file_lock **released_lock, struct file_lock **left_lock, 19687096Salfred struct file_lock **right_lock); 19787096Salfredenum hwlock_status lock_hwlock(struct file_lock *fl); 19887096Salfredenum split_status split_nfslock(const struct file_lock *exist_lock, 19987096Salfred const struct file_lock *unlock_lock, struct file_lock **left_lock, 20087096Salfred struct file_lock **right_lock); 20187096Salfredvoid add_blockingfilelock(struct file_lock *fl); 20287096Salfredenum hwlock_status unlock_hwlock(const struct file_lock *fl); 20387096Salfredenum hwlock_status test_hwlock(const struct file_lock *fl, 20487096Salfred struct file_lock **conflicting_fl); 20587096Salfredvoid remove_blockingfilelock(struct file_lock *fl); 20687096Salfredvoid clear_blockingfilelock(const char *hostname); 20787096Salfredvoid retry_blockingfilelocklist(void); 20887096Salfredenum partialfilelock_status unlock_partialfilelock( 20987096Salfred const struct file_lock *fl); 21087096Salfredvoid clear_partialfilelock(const char *hostname); 21187096Salfredenum partialfilelock_status test_partialfilelock( 21287096Salfred const struct file_lock *fl, struct file_lock **conflicting_fl); 21387096Salfredenum nlm_stats do_test(struct file_lock *fl, 21487096Salfred struct file_lock **conflicting_fl); 21587096Salfredenum nlm_stats do_unlock(struct file_lock *fl); 21687096Salfredenum nlm_stats do_lock(struct file_lock *fl); 21787096Salfredvoid do_clear(const char *hostname); 21887096Salfred 21987096Salfred 22087096Salfredvoid 22187096Salfreddebuglog(char const *fmt, ...) 22287096Salfred{ 22387096Salfred va_list ap; 22487096Salfred 22587096Salfred if (debug_level < 1) { 22687096Salfred return; 22787096Salfred } 22887096Salfred 22987096Salfred sleep(debugdelay); 23087096Salfred 23187096Salfred va_start(ap, fmt); 23287096Salfred vsyslog(LOG_DEBUG, fmt, ap); 23387096Salfred va_end(ap); 23487096Salfred} 23587096Salfred 23687096Salfredvoid 23787096Salfreddump_static_object(object, size_object, hbuff, size_hbuff, cbuff, size_cbuff) 23887096Salfred const unsigned char *object; 23987096Salfred const int size_object; 24087096Salfred unsigned char *hbuff; 24187096Salfred const int size_hbuff; 24287096Salfred unsigned char *cbuff; 24387096Salfred const int size_cbuff; 24487096Salfred{ 24587096Salfred int i, objectsize; 24687096Salfred 24787096Salfred if (debug_level < 2) { 24887096Salfred return; 24987096Salfred } 25087096Salfred 25187096Salfred objectsize = size_object; 25287096Salfred 25387096Salfred if (objectsize == 0) { 25487096Salfred debuglog("object is size 0\n"); 25587096Salfred } else { 25687096Salfred if (objectsize > MAXOBJECTSIZE) { 25787096Salfred debuglog("Object of size %d being clamped" 25887096Salfred "to size %d\n", objectsize, MAXOBJECTSIZE); 25987096Salfred objectsize = MAXOBJECTSIZE; 26087096Salfred } 26187096Salfred 26287096Salfred if (hbuff != NULL) { 26387096Salfred if (size_hbuff < objectsize*2+1) { 26487096Salfred debuglog("Hbuff not large enough." 26587096Salfred " Increase size\n"); 26687096Salfred } else { 26787096Salfred for(i=0;i<objectsize;i++) { 26887096Salfred sprintf(hbuff+i*2,"%02x",*(object+i)); 26987096Salfred } 27087096Salfred *(hbuff+i*2) = '\0'; 27187096Salfred } 27287096Salfred } 27387096Salfred 27487096Salfred if (cbuff != NULL) { 27587096Salfred if (size_cbuff < objectsize+1) { 27687096Salfred debuglog("Cbuff not large enough." 27787096Salfred " Increase Size\n"); 27887096Salfred } 27987096Salfred 28087096Salfred for(i=0;i<objectsize;i++) { 28187096Salfred if (*(object+i) >= 32 && *(object+i) <= 127) { 28287096Salfred *(cbuff+i) = *(object+i); 28387096Salfred } else { 28487096Salfred *(cbuff+i) = '.'; 28587096Salfred } 28687096Salfred } 28787096Salfred *(cbuff+i) = '\0'; 28887096Salfred } 28987096Salfred } 29087096Salfred} 29187096Salfred 29287096Salfredvoid 29387096Salfreddump_netobj(const struct netobj *nobj) 29487096Salfred{ 29587096Salfred char hbuff[MAXBUFFERSIZE*2]; 29687096Salfred char cbuff[MAXBUFFERSIZE]; 29787096Salfred 29887096Salfred if (debug_level < 2) { 29987096Salfred return; 30087096Salfred } 30187096Salfred 30287096Salfred if (nobj == NULL) { 30387096Salfred debuglog("Null netobj pointer\n"); 30487096Salfred } 30587096Salfred else if (nobj->n_len == 0) { 30687096Salfred debuglog("Size zero netobj\n"); 30787096Salfred } else { 30887096Salfred dump_static_object(nobj->n_bytes, nobj->n_len, 30987096Salfred hbuff, sizeof(hbuff), cbuff, sizeof(cbuff)); 31087096Salfred debuglog("netobj: len: %d data: %s ::: %s\n", 31187096Salfred nobj->n_len, hbuff, cbuff); 31287096Salfred } 31387096Salfred} 31487096Salfred 31592911Salfred/* #define DUMP_FILELOCK_VERBOSE */ 31687096Salfredvoid 31787096Salfreddump_filelock(const struct file_lock *fl) 31887096Salfred{ 31992911Salfred#ifdef DUMP_FILELOCK_VERBOSE 32087096Salfred char hbuff[MAXBUFFERSIZE*2]; 32187096Salfred char cbuff[MAXBUFFERSIZE]; 32292911Salfred#endif 32387096Salfred 32487096Salfred if (debug_level < 2) { 32587096Salfred return; 32687096Salfred } 32787096Salfred 32887096Salfred if (fl != NULL) { 32987096Salfred debuglog("Dumping file lock structure @ %p\n", fl); 33087096Salfred 33192911Salfred#ifdef DUMP_FILELOCK_VERBOSE 33287096Salfred dump_static_object((unsigned char *)&fl->filehandle, 33387096Salfred sizeof(fl->filehandle), hbuff, sizeof(hbuff), 33487096Salfred cbuff, sizeof(cbuff)); 33587096Salfred debuglog("Filehandle: %8s ::: %8s\n", hbuff, cbuff); 33692911Salfred#endif 33787096Salfred 33887096Salfred debuglog("Dumping nlm4_holder:\n" 33987096Salfred "exc: %x svid: %x offset:len %llx:%llx\n", 34087096Salfred fl->client.exclusive, fl->client.svid, 34187096Salfred fl->client.l_offset, fl->client.l_len); 34287096Salfred 34392911Salfred#ifdef DUMP_FILELOCK_VERBOSE 34487096Salfred debuglog("Dumping client identity:\n"); 34587096Salfred dump_netobj(&fl->client.oh); 34687096Salfred 34787096Salfred debuglog("Dumping client cookie:\n"); 34887096Salfred dump_netobj(&fl->client_cookie); 34987096Salfred 35087096Salfred debuglog("nsm: %d status: %d flags: %d locker: %d" 35187096Salfred " fd: %d\n", fl->nsm_status, fl->status, 35287096Salfred fl->flags, fl->locker, fl->fd); 35392911Salfred#endif 35487096Salfred } else { 35587096Salfred debuglog("NULL file lock structure\n"); 35687096Salfred } 35787096Salfred} 35887096Salfred 35987096Salfredvoid 36087096Salfredcopy_nlm4_lock_to_nlm4_holder(src, exclusive, dest) 36187096Salfred const struct nlm4_lock *src; 36287096Salfred const bool_t exclusive; 36387096Salfred struct nlm4_holder *dest; 36487096Salfred{ 36587096Salfred 36687096Salfred dest->exclusive = exclusive; 36787096Salfred dest->oh.n_len = src->oh.n_len; 36887096Salfred dest->oh.n_bytes = src->oh.n_bytes; 36987096Salfred dest->svid = src->svid; 37087096Salfred dest->l_offset = src->l_offset; 37187096Salfred dest->l_len = src->l_len; 37287096Salfred} 37387096Salfred 37487096Salfred 37574462Salfred/* 37687096Salfred * allocate_file_lock: Create a lock with the given parameters 37784923Salfred */ 37887096Salfred 37987096Salfredstruct file_lock * 38087096Salfredallocate_file_lock(const netobj *lockowner, const netobj *matchcookie) 38187096Salfred{ 38287096Salfred struct file_lock *newfl; 38387096Salfred 38487096Salfred newfl = malloc(sizeof(struct file_lock)); 38587096Salfred if (newfl == NULL) { 38687096Salfred return NULL; 38787096Salfred } 38887096Salfred bzero(newfl, sizeof(newfl)); 38987096Salfred 39087096Salfred newfl->client.oh.n_bytes = malloc(lockowner->n_len); 39187096Salfred if (newfl->client.oh.n_bytes == NULL) { 39287096Salfred free(newfl); 39387096Salfred return NULL; 39487096Salfred } 39587096Salfred newfl->client.oh.n_len = lockowner->n_len; 39687096Salfred bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len); 39787096Salfred 39887096Salfred newfl->client_cookie.n_bytes = malloc(matchcookie->n_len); 39987096Salfred if (newfl->client_cookie.n_bytes == NULL) { 40087096Salfred free(newfl->client.oh.n_bytes); 40187096Salfred free(newfl); 40287096Salfred return NULL; 40387096Salfred } 40487096Salfred newfl->client_cookie.n_len = matchcookie->n_len; 40587096Salfred bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len); 40687096Salfred 40787096Salfred return newfl; 40887096Salfred} 40987096Salfred 41087096Salfred/* 41187096Salfred * file_file_lock: Force creation of a valid file lock 41287096Salfred */ 41387096Salfredvoid 41487199Salfredfill_file_lock(struct file_lock *fl, const fhandle_t *fh, 41587199Salfred struct sockaddr *addr, const bool_t exclusive, const int32_t svid, 41687199Salfred const u_int64_t offset, const u_int64_t len, const char *caller_name, 41787199Salfred const int state, const int status, const int flags, const int blocking) 41887096Salfred{ 41987096Salfred bcopy(fh, &fl->filehandle, sizeof(fhandle_t)); 42087096Salfred fl->addr = addr; 42187096Salfred 42287096Salfred fl->client.exclusive = exclusive; 42387096Salfred fl->client.svid = svid; 42487096Salfred fl->client.l_offset = offset; 42587096Salfred fl->client.l_len = len; 42687096Salfred 42787096Salfred strncpy(fl->client_name, caller_name, SM_MAXSTRLEN); 42887096Salfred 42987096Salfred fl->nsm_status = state; 43087096Salfred fl->status = status; 43187096Salfred fl->flags = flags; 43287096Salfred fl->blocking = blocking; 43387096Salfred} 43487096Salfred 43587096Salfred/* 43687096Salfred * deallocate_file_lock: Free all storage associated with a file lock 43787096Salfred */ 43887096Salfredvoid 43987096Salfreddeallocate_file_lock(struct file_lock *fl) 44087096Salfred{ 44187096Salfred free(fl->client.oh.n_bytes); 44287096Salfred free(fl->client_cookie.n_bytes); 44387096Salfred free(fl); 44487096Salfred} 44587096Salfred 44687096Salfred/* 44787096Salfred * regions_overlap(): This function examines the two provided regions for 44887096Salfred * overlap. 44987096Salfred */ 45084923Salfredint 45184923Salfredregions_overlap(start1, len1, start2, len2) 45287096Salfred const u_int64_t start1, len1, start2, len2; 45384923Salfred{ 45487096Salfred u_int64_t d1,d2,d3,d4; 45587096Salfred enum split_status result; 45684923Salfred 45787096Salfred debuglog("Entering region overlap with vals: %llu:%llu--%llu:%llu\n", 45887096Salfred start1, len1, start2, len2); 45987096Salfred 46087096Salfred result = region_compare(start1, len1, start2, len2, 46187096Salfred &d1, &d2, &d3, &d4); 46287096Salfred 46387096Salfred debuglog("Exiting region overlap with val: %d\n",result); 46487096Salfred 46587096Salfred if (result == SPL_DISJOINT) { 46687096Salfred return 0; 46784923Salfred } else { 46887096Salfred return 1; 46984923Salfred } 47087096Salfred 47184923Salfred return (result); 47284923Salfred} 47387096Salfred 47484923Salfred/* 47587096Salfred * region_compare(): Examine lock regions and split appropriately 47687096Salfred * 47787096Salfred * XXX: Fix 64 bit overflow problems 47887096Salfred * XXX: Check to make sure I got *ALL* the cases. 47987096Salfred * XXX: This DESPERATELY needs a regression test. 48074462Salfred */ 48187096Salfredenum split_status 48287096Salfredregion_compare(starte, lene, startu, lenu, 48387096Salfred start1, len1, start2, len2) 48487096Salfred const u_int64_t starte, lene, startu, lenu; 48587096Salfred u_int64_t *start1, *len1, *start2, *len2; 48687096Salfred{ 48787096Salfred /* 48887096Salfred * Please pay attention to the sequential exclusions 48987096Salfred * of the if statements!!! 49087096Salfred */ 49187096Salfred enum LFLAGS lflags; 49287096Salfred enum RFLAGS rflags; 49387096Salfred enum split_status retval; 49474462Salfred 49587096Salfred retval = SPL_DISJOINT; 49687096Salfred 49787096Salfred if (lene == 0 && lenu == 0) { 49887096Salfred /* Examine left edge of locker */ 49987096Salfred if (startu < starte) { 50087096Salfred lflags = LEDGE_LEFT; 50187096Salfred } else if (startu == starte) { 50287096Salfred lflags = LEDGE_LBOUNDARY; 50387096Salfred } else { 50487096Salfred lflags = LEDGE_INSIDE; 50587096Salfred } 50687096Salfred 50787096Salfred rflags = REDGE_RBOUNDARY; /* Both are infiinite */ 50887096Salfred 50987096Salfred if (lflags == LEDGE_INSIDE) { 51087096Salfred *start1 = starte; 51187096Salfred *len1 = startu - starte; 51287096Salfred } 51387096Salfred 51487096Salfred if (lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) { 51587096Salfred retval = SPL_CONTAINED; 51687096Salfred } else { 51787096Salfred retval = SPL_LOCK1; 51887096Salfred } 51987096Salfred } else if (lene == 0 && lenu != 0) { 52087096Salfred /* Established lock is infinite */ 52187096Salfred /* Examine left edge of unlocker */ 52287096Salfred if (startu < starte) { 52387096Salfred lflags = LEDGE_LEFT; 52487096Salfred } else if (startu == starte) { 52587096Salfred lflags = LEDGE_LBOUNDARY; 52687096Salfred } else if (startu > starte) { 52787096Salfred lflags = LEDGE_INSIDE; 52887096Salfred } 52987096Salfred 53087096Salfred /* Examine right edge of unlocker */ 53187096Salfred if (startu + lenu < starte) { 53287096Salfred /* Right edge of unlocker left of established lock */ 53387096Salfred rflags = REDGE_LEFT; 53487096Salfred return SPL_DISJOINT; 53587096Salfred } else if (startu + lenu == starte) { 53687096Salfred /* Right edge of unlocker on start of established lock */ 53787096Salfred rflags = REDGE_LBOUNDARY; 53887096Salfred return SPL_DISJOINT; 53987096Salfred } else { /* Infinifty is right of finity */ 54087096Salfred /* Right edge of unlocker inside established lock */ 54187096Salfred rflags = REDGE_INSIDE; 54287096Salfred } 54387096Salfred 54487096Salfred if (lflags == LEDGE_INSIDE) { 54587096Salfred *start1 = starte; 54687096Salfred *len1 = startu - starte; 54787096Salfred retval |= SPL_LOCK1; 54887096Salfred } 54987096Salfred 55087096Salfred if (rflags == REDGE_INSIDE) { 55187096Salfred /* Create right lock */ 55287096Salfred *start2 = startu+lenu; 55387096Salfred *len2 = 0; 55487096Salfred retval |= SPL_LOCK2; 55587096Salfred } 55687096Salfred } else if (lene != 0 && lenu == 0) { 55787096Salfred /* Unlocker is infinite */ 55887096Salfred /* Examine left edge of unlocker */ 55987096Salfred if (startu < starte) { 56087096Salfred lflags = LEDGE_LEFT; 56187096Salfred retval = SPL_CONTAINED; 56287096Salfred return retval; 56387096Salfred } else if (startu == starte) { 56487096Salfred lflags = LEDGE_LBOUNDARY; 56587096Salfred retval = SPL_CONTAINED; 56687096Salfred return retval; 56787096Salfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 56887096Salfred lflags = LEDGE_INSIDE; 56987096Salfred } else if (startu == starte + lene - 1) { 57087096Salfred lflags = LEDGE_RBOUNDARY; 57187096Salfred } else { /* startu > starte + lene -1 */ 57287096Salfred lflags = LEDGE_RIGHT; 57387096Salfred return SPL_DISJOINT; 57487096Salfred } 57587096Salfred 57687096Salfred rflags = REDGE_RIGHT; /* Infinity is right of finity */ 57787096Salfred 57887096Salfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 57987096Salfred *start1 = starte; 58087096Salfred *len1 = startu - starte; 58187096Salfred retval |= SPL_LOCK1; 58287096Salfred return retval; 58387096Salfred } 58487096Salfred 58587096Salfred } else { 58687096Salfred /* Both locks are finite */ 58787096Salfred 58887096Salfred /* Examine left edge of unlocker */ 58987096Salfred if (startu < starte) { 59087096Salfred lflags = LEDGE_LEFT; 59187096Salfred } else if (startu == starte) { 59287096Salfred lflags = LEDGE_LBOUNDARY; 59387096Salfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 59487096Salfred lflags = LEDGE_INSIDE; 59587096Salfred } else if (startu == starte + lene - 1) { 59687096Salfred lflags = LEDGE_RBOUNDARY; 59787096Salfred } else { /* startu > starte + lene -1 */ 59887096Salfred lflags = LEDGE_RIGHT; 59987096Salfred return SPL_DISJOINT; 60087096Salfred } 60187096Salfred 60287096Salfred /* Examine right edge of unlocker */ 60387096Salfred if (startu + lenu < starte) { 60487096Salfred /* Right edge of unlocker left of established lock */ 60587096Salfred rflags = REDGE_LEFT; 60687096Salfred return SPL_DISJOINT; 60787096Salfred } else if (startu + lenu == starte) { 60887096Salfred /* Right edge of unlocker on start of established lock */ 60987096Salfred rflags = REDGE_LBOUNDARY; 61087096Salfred return SPL_DISJOINT; 61187096Salfred } else if (startu + lenu < starte + lene) { 61287096Salfred /* Right edge of unlocker inside established lock */ 61387096Salfred rflags = REDGE_INSIDE; 61487096Salfred } else if (startu + lenu == starte + lene) { 61587096Salfred /* Right edge of unlocker on right edge of established lock */ 61687096Salfred rflags = REDGE_RBOUNDARY; 61787096Salfred } else { /* startu + lenu > starte + lene */ 61887096Salfred /* Right edge of unlocker is right of established lock */ 61987096Salfred rflags = REDGE_RIGHT; 62087096Salfred } 62187096Salfred 62287096Salfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 62387096Salfred /* Create left lock */ 62487096Salfred *start1 = starte; 62587096Salfred *len1 = (startu - starte); 62687096Salfred retval |= SPL_LOCK1; 62787096Salfred } 62887096Salfred 62987096Salfred if (rflags == REDGE_INSIDE) { 63087096Salfred /* Create right lock */ 63187096Salfred *start2 = startu+lenu; 63287096Salfred *len2 = starte+lene-(startu+lenu); 63387096Salfred retval |= SPL_LOCK2; 63487096Salfred } 63587096Salfred 63687096Salfred if ((lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) && 63787096Salfred (rflags == REDGE_RBOUNDARY || rflags == REDGE_RIGHT)) { 63887096Salfred retval = SPL_CONTAINED; 63987096Salfred } 64087096Salfred } 64187096Salfred 64287096Salfred return retval; 64387096Salfred} 64487096Salfred 64587096Salfred/* 64687096Salfred * same_netobj: Compares the apprpriate bits of a netobj for identity 64787096Salfred */ 64887096Salfredint 64987096Salfredsame_netobj(const netobj *n0, const netobj *n1) 65074462Salfred{ 65187096Salfred int retval; 65274462Salfred 65387096Salfred retval = 0; 65474462Salfred 65587096Salfred debuglog("Entering netobj identity check\n"); 65687096Salfred 65787096Salfred if (n0->n_len == n1->n_len) { 65887096Salfred debuglog("Preliminary length check passed\n"); 65987096Salfred retval = !bcmp(n0->n_bytes, n1->n_bytes, n0->n_len); 66087096Salfred debuglog("netobj %smatch\n", retval ? "" : "mis"); 66187096Salfred } 66287096Salfred 66387096Salfred return (retval); 66487096Salfred} 66587096Salfred 66687096Salfred/* 66787096Salfred * same_filelock_identity: Compares the appropriate bits of a file_lock 66887096Salfred */ 66987096Salfredint 67087096Salfredsame_filelock_identity(fl0, fl1) 67187096Salfred const struct file_lock *fl0, *fl1; 67287096Salfred{ 67387096Salfred int retval; 67487096Salfred 67587096Salfred retval = 0; 67687096Salfred 67787096Salfred debuglog("Checking filelock identity\n"); 67887096Salfred 67987096Salfred /* 68087096Salfred * Check process ids and host information. 68187096Salfred */ 68287096Salfred retval = (fl0->client.svid == fl1->client.svid && 68387096Salfred same_netobj(&(fl0->client.oh), &(fl1->client.oh))); 68487096Salfred 68587096Salfred debuglog("Exiting checking filelock identity: retval: %d\n",retval); 68687096Salfred 68787096Salfred return (retval); 68887096Salfred} 68987096Salfred 69087096Salfred/* 69187096Salfred * Below here are routines associated with manipulating the NFS 69287096Salfred * lock list. 69387096Salfred */ 69487096Salfred 69587096Salfred/* 69687096Salfred * get_lock_matching_unlock: Return a lock which matches the given unlock lock 69787096Salfred * or NULL otehrwise 69887096Salfred * XXX: It is a shame that this duplicates so much code from test_nfslock. 69987096Salfred */ 70087096Salfredstruct file_lock * 70187096Salfredget_lock_matching_unlock(const struct file_lock *fl) 70287096Salfred{ 70387096Salfred struct file_lock *ifl; /* Iterator */ 70487096Salfred 70587096Salfred debuglog("Entering lock_matching_unlock\n"); 70687096Salfred debuglog("********Dump of fl*****************\n"); 70787096Salfred dump_filelock(fl); 70887096Salfred 70987096Salfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 71087096Salfred debuglog("Pointer to file lock: %p\n",ifl); 71187096Salfred 71287096Salfred debuglog("****Dump of ifl****\n"); 71387096Salfred dump_filelock(ifl); 71487096Salfred debuglog("*******************\n"); 71587096Salfred 71687096Salfred /* 71787096Salfred * XXX: It is conceivable that someone could use the NLM RPC 71887096Salfred * system to directly access filehandles. This may be a 71987096Salfred * security hazard as the filehandle code may bypass normal 72087096Salfred * file access controls 72187096Salfred */ 72287096Salfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 72374462Salfred continue; 72487096Salfred 72587096Salfred debuglog("matching_unlock: Filehandles match, " 72687096Salfred "checking regions\n"); 72787096Salfred 72887096Salfred /* Filehandles match, check for region overlap */ 72987096Salfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 73087096Salfred ifl->client.l_offset, ifl->client.l_len)) 73187096Salfred continue; 73287096Salfred 73387096Salfred debuglog("matching_unlock: Region overlap" 73487096Salfred " found %llu : %llu -- %llu : %llu\n", 73587096Salfred fl->client.l_offset,fl->client.l_len, 73687096Salfred ifl->client.l_offset,ifl->client.l_len); 73787096Salfred 73887096Salfred /* Regions overlap, check the identity */ 73987096Salfred if (!same_filelock_identity(fl,ifl)) 74087096Salfred continue; 74187096Salfred 74287096Salfred debuglog("matching_unlock: Duplicate lock id. Granting\n"); 74387096Salfred return (ifl); 74487096Salfred } 74587096Salfred 74687096Salfred debuglog("Exiting lock_matching_unlock\n"); 74787096Salfred 74887096Salfred return (NULL); 74987096Salfred} 75087096Salfred 75187096Salfred/* 75287096Salfred * test_nfslock: check for NFS lock in lock list 75387096Salfred * 75487096Salfred * This routine makes the following assumptions: 75587096Salfred * 1) Nothing will adjust the lock list during a lookup 75687096Salfred * 75787096Salfred * This routine has an intersting quirk which bit me hard. 75887096Salfred * The conflicting_fl is the pointer to the conflicting lock. 75987096Salfred * However, to modify the "*pointer* to the conflicting lock" rather 76087096Salfred * that the "conflicting lock itself" one must pass in a "pointer to 76187096Salfred * the pointer of the conflicting lock". Gross. 76287096Salfred */ 76387096Salfred 76487096Salfredenum nfslock_status 76587096Salfredtest_nfslock(const struct file_lock *fl, struct file_lock **conflicting_fl) 76687096Salfred{ 76787096Salfred struct file_lock *ifl; /* Iterator */ 76887096Salfred enum nfslock_status retval; 76987096Salfred 77087096Salfred debuglog("Entering test_nfslock\n"); 77187096Salfred 77287096Salfred retval = NFS_GRANTED; 77387096Salfred (*conflicting_fl) = NULL; 77487096Salfred 77587096Salfred debuglog("Entering lock search loop\n"); 77687096Salfred 77787096Salfred debuglog("***********************************\n"); 77887096Salfred debuglog("Dumping match filelock\n"); 77987096Salfred debuglog("***********************************\n"); 78087096Salfred dump_filelock(fl); 78187096Salfred debuglog("***********************************\n"); 78287096Salfred 78387096Salfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 78487096Salfred if (retval == NFS_DENIED) 78587096Salfred break; 78687096Salfred 78787096Salfred debuglog("Top of lock loop\n"); 78887096Salfred debuglog("Pointer to file lock: %p\n",ifl); 78987096Salfred 79087096Salfred debuglog("***********************************\n"); 79187096Salfred debuglog("Dumping test filelock\n"); 79287096Salfred debuglog("***********************************\n"); 79387096Salfred dump_filelock(ifl); 79487096Salfred debuglog("***********************************\n"); 79587096Salfred 79684923Salfred /* 79787096Salfred * XXX: It is conceivable that someone could use the NLM RPC 79887096Salfred * system to directly access filehandles. This may be a 79987096Salfred * security hazard as the filehandle code may bypass normal 80087096Salfred * file access controls 80184923Salfred */ 80287096Salfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 80374462Salfred continue; 80487096Salfred 80587096Salfred debuglog("test_nfslock: filehandle match found\n"); 80687096Salfred 80787096Salfred /* Filehandles match, check for region overlap */ 80887096Salfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 80987096Salfred ifl->client.l_offset, ifl->client.l_len)) 81087096Salfred continue; 81187096Salfred 81287096Salfred debuglog("test_nfslock: Region overlap found" 81387096Salfred " %llu : %llu -- %llu : %llu\n", 81487096Salfred fl->client.l_offset,fl->client.l_len, 81587096Salfred ifl->client.l_offset,ifl->client.l_len); 81687096Salfred 81787096Salfred /* Regions overlap, check the exclusivity */ 81887096Salfred if (!(fl->client.exclusive || ifl->client.exclusive)) 81987096Salfred continue; 82087096Salfred 82187096Salfred debuglog("test_nfslock: Exclusivity failure: %d %d\n", 82287096Salfred fl->client.exclusive, 82387096Salfred ifl->client.exclusive); 82487096Salfred 82587096Salfred if (same_filelock_identity(fl,ifl)) { 82687096Salfred debuglog("test_nfslock: Duplicate id. Granting\n"); 82787096Salfred (*conflicting_fl) = ifl; 82887096Salfred retval = NFS_GRANTED_DUPLICATE; 82987096Salfred } else { 83087096Salfred /* locking attempt fails */ 83187096Salfred debuglog("test_nfslock: Lock attempt failed\n"); 83287096Salfred debuglog("Desired lock\n"); 83387096Salfred dump_filelock(fl); 83487096Salfred debuglog("Conflicting lock\n"); 83587096Salfred dump_filelock(ifl); 83687096Salfred (*conflicting_fl) = ifl; 83787096Salfred retval = NFS_DENIED; 83884923Salfred } 83984923Salfred } 84087096Salfred 84187096Salfred debuglog("Dumping file locks\n"); 84287096Salfred debuglog("Exiting test_nfslock\n"); 84387096Salfred 84487096Salfred return (retval); 84587096Salfred} 84687096Salfred 84787096Salfred/* 84887096Salfred * lock_nfslock: attempt to create a lock in the NFS lock list 84987096Salfred * 85087096Salfred * This routine tests whether the lock will be granted and then adds 85187096Salfred * the entry to the lock list if so. 85287096Salfred * 85387096Salfred * Argument fl gets modified as its list housekeeping entries get modified 85487096Salfred * upon insertion into the NFS lock list 85587096Salfred * 85687096Salfred * This routine makes several assumptions: 85787096Salfred * 1) It is perfectly happy to grant a duplicate lock from the same pid. 85887096Salfred * While this seems to be intuitively wrong, it is required for proper 85987096Salfred * Posix semantics during unlock. It is absolutely imperative to not 86087096Salfred * unlock the main lock before the two child locks are established. Thus, 86187096Salfred * one has be be able to create duplicate locks over an existing lock 86287096Salfred * 2) It currently accepts duplicate locks from the same id,pid 86387096Salfred */ 86487096Salfred 86587096Salfredenum nfslock_status 86687096Salfredlock_nfslock(struct file_lock *fl) 86787096Salfred{ 86887096Salfred enum nfslock_status retval; 86987096Salfred struct file_lock *dummy_fl; 87087096Salfred 87187096Salfred dummy_fl = NULL; 87287096Salfred 87387096Salfred debuglog("Entering lock_nfslock...\n"); 87487096Salfred 87587096Salfred retval = test_nfslock(fl,&dummy_fl); 87687096Salfred 87787096Salfred if (retval == NFS_GRANTED || retval == NFS_GRANTED_DUPLICATE) { 87887096Salfred debuglog("Inserting lock...\n"); 87987096Salfred dump_filelock(fl); 88087096Salfred LIST_INSERT_HEAD(&nfslocklist_head, fl, nfslocklist); 88174462Salfred } 88287096Salfred 88387096Salfred debuglog("Exiting lock_nfslock...\n"); 88487096Salfred 88587096Salfred return (retval); 88674462Salfred} 88774462Salfred 88874462Salfred/* 88987096Salfred * delete_nfslock: delete an NFS lock list entry 89087096Salfred * 89187096Salfred * This routine is used to delete a lock out of the NFS lock list 89287096Salfred * without regard to status, underlying locks, regions or anything else 89387096Salfred * 89487096Salfred * Note that this routine *does not deallocate memory* of the lock. 89587096Salfred * It just disconnects it from the list. The lock can then be used 89687096Salfred * by other routines without fear of trashing the list. 89774462Salfred */ 89887096Salfred 89987096Salfredenum nfslock_status 90087096Salfreddelete_nfslock(struct file_lock *fl) 90174462Salfred{ 90274462Salfred 90387096Salfred LIST_REMOVE(fl, nfslocklist); 90487096Salfred 90587096Salfred return (NFS_GRANTED); 90687096Salfred} 90787096Salfred 90887096Salfredenum split_status 90987096Salfredsplit_nfslock(exist_lock, unlock_lock, left_lock, right_lock) 91087096Salfred const struct file_lock *exist_lock, *unlock_lock; 91187096Salfred struct file_lock **left_lock, **right_lock; 91287096Salfred{ 91387096Salfred u_int64_t start1, len1, start2, len2; 91487096Salfred enum split_status spstatus; 91587096Salfred 91687096Salfred spstatus = region_compare(exist_lock->client.l_offset, exist_lock->client.l_len, 91787096Salfred unlock_lock->client.l_offset, unlock_lock->client.l_len, 91887096Salfred &start1, &len1, &start2, &len2); 91987096Salfred 92087096Salfred if ((spstatus & SPL_LOCK1) != 0) { 92187096Salfred *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie); 92287096Salfred if (*left_lock == NULL) { 92387096Salfred debuglog("Unable to allocate resource for split 1\n"); 92487096Salfred return SPL_RESERR; 92587096Salfred } 92687096Salfred 92787199Salfred fill_file_lock(*left_lock, &exist_lock->filehandle, 92887199Salfred exist_lock->addr, 92987096Salfred exist_lock->client.exclusive, exist_lock->client.svid, 93087096Salfred start1, len1, 93187096Salfred exist_lock->client_name, exist_lock->nsm_status, 93287096Salfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 93374462Salfred } 93487096Salfred 93587096Salfred if ((spstatus & SPL_LOCK2) != 0) { 93687096Salfred *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie); 93787096Salfred if (*right_lock == NULL) { 93887096Salfred debuglog("Unable to allocate resource for split 1\n"); 93987096Salfred if (*left_lock != NULL) { 94087096Salfred deallocate_file_lock(*left_lock); 94187096Salfred } 94287096Salfred return SPL_RESERR; 94387096Salfred } 94487096Salfred 94587199Salfred fill_file_lock(*right_lock, &exist_lock->filehandle, 94687199Salfred exist_lock->addr, 94787096Salfred exist_lock->client.exclusive, exist_lock->client.svid, 94887096Salfred start2, len2, 94987096Salfred exist_lock->client_name, exist_lock->nsm_status, 95087096Salfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 95174462Salfred } 95287096Salfred 95387096Salfred return spstatus; 95487096Salfred} 95587096Salfred 95687096Salfredenum nfslock_status 95787096Salfredunlock_nfslock(fl, released_lock, left_lock, right_lock) 95887096Salfred const struct file_lock *fl; 95987096Salfred struct file_lock **released_lock; 96087096Salfred struct file_lock **left_lock; 96187096Salfred struct file_lock **right_lock; 96287096Salfred{ 96387096Salfred struct file_lock *mfl; /* Matching file lock */ 96487096Salfred enum nfslock_status retval; 96587096Salfred enum split_status spstatus; 96687096Salfred 96787096Salfred debuglog("Entering unlock_nfslock\n"); 96887096Salfred 96987096Salfred *released_lock = NULL; 97087096Salfred *left_lock = NULL; 97187096Salfred *right_lock = NULL; 97287096Salfred 97387096Salfred retval = NFS_DENIED_NOLOCK; 97487096Salfred 97587096Salfred printf("Attempting to match lock...\n"); 97687096Salfred mfl = get_lock_matching_unlock(fl); 97787096Salfred 97887096Salfred if (mfl != NULL) { 97987096Salfred debuglog("Unlock matched. Querying for split\n"); 98087096Salfred 98187096Salfred spstatus = split_nfslock(mfl, fl, left_lock, right_lock); 98287096Salfred 98387096Salfred debuglog("Split returned %d %p %p %p %p\n",spstatus,mfl,fl,*left_lock,*right_lock); 98487096Salfred debuglog("********Split dumps********"); 98587096Salfred dump_filelock(mfl); 98687096Salfred dump_filelock(fl); 98787096Salfred dump_filelock(*left_lock); 98887096Salfred dump_filelock(*right_lock); 98987096Salfred debuglog("********End Split dumps********"); 99087096Salfred 99187096Salfred if (spstatus == SPL_RESERR) { 99287096Salfred if (*left_lock != NULL) { 99387096Salfred deallocate_file_lock(*left_lock); 99487096Salfred *left_lock = NULL; 99574462Salfred } 99687096Salfred 99787096Salfred if (*right_lock != NULL) { 99887096Salfred deallocate_file_lock(*right_lock); 99987096Salfred *right_lock = NULL; 100074462Salfred } 100187096Salfred 100287096Salfred return NFS_RESERR; 100374462Salfred } 100487096Salfred 100587096Salfred /* Insert new locks from split if required */ 100687096Salfred if (*left_lock != NULL) { 100787096Salfred debuglog("Split left activated\n"); 100887096Salfred LIST_INSERT_HEAD(&nfslocklist_head, *left_lock, nfslocklist); 100987096Salfred } 101087096Salfred 101187096Salfred if (*right_lock != NULL) { 101287096Salfred debuglog("Split right activated\n"); 101387096Salfred LIST_INSERT_HEAD(&nfslocklist_head, *right_lock, nfslocklist); 101487096Salfred } 101587096Salfred 101687096Salfred /* Unlock the lock since it matches identity */ 101787096Salfred LIST_REMOVE(mfl, nfslocklist); 101887096Salfred *released_lock = mfl; 101987096Salfred retval = NFS_GRANTED; 102074462Salfred } 102187096Salfred 102287096Salfred debuglog("Exiting unlock_nfslock\n"); 102387096Salfred 102474462Salfred return retval; 102574462Salfred} 102674462Salfred 102787096Salfred/* 102887096Salfred * Below here are the routines for manipulating the file lock directly 102987096Salfred * on the disk hardware itself 103087096Salfred */ 103187096Salfredenum hwlock_status 103287096Salfredlock_hwlock(struct file_lock *fl) 103374462Salfred{ 103487096Salfred struct monfile *imf,*nmf; 103587096Salfred int lflags, flerror; 103674462Salfred 103787096Salfred /* Scan to see if filehandle already present */ 103887096Salfred LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 103987096Salfred if (bcmp(&fl->filehandle, &imf->filehandle, 104087096Salfred sizeof(fl->filehandle)) == 0) { 104187096Salfred /* imf is the correct filehandle */ 104274462Salfred break; 104387096Salfred } 104487096Salfred } 104587096Salfred 104687096Salfred /* 104787096Salfred * Filehandle already exists (we control the file) 104887096Salfred * *AND* NFS has already cleared the lock for availability 104987096Salfred * Grant it and bump the refcount. 105087096Salfred */ 105187096Salfred if (imf != NULL) { 105287096Salfred ++(imf->refcount); 105387096Salfred return (HW_GRANTED); 105487096Salfred } 105587096Salfred 105687096Salfred /* No filehandle found, create and go */ 105787096Salfred nmf = malloc(sizeof(struct monfile)); 105887096Salfred if (nmf == NULL) { 105987096Salfred debuglog("hwlock resource allocation failure\n"); 106087096Salfred return (HW_RESERR); 106187096Salfred } 106287096Salfred 106387096Salfred /* XXX: Is O_RDWR always the correct mode? */ 106487096Salfred nmf->fd = fhopen(&fl->filehandle, O_RDWR); 106587096Salfred if (nmf->fd < 0) { 106687096Salfred debuglog("fhopen failed (from %16s): %32s\n", 106787096Salfred fl->client_name, strerror(errno)); 106887096Salfred free(nmf); 106987096Salfred switch (errno) { 107087096Salfred case ESTALE: 107187096Salfred return (HW_STALEFH); 107287096Salfred case EROFS: 107387096Salfred return (HW_READONLY); 107487096Salfred default: 107587096Salfred return (HW_RESERR); 107687096Salfred } 107787096Salfred } 107887096Salfred 107987096Salfred /* File opened correctly, fill the monitor struct */ 108087096Salfred bcopy(&fl->filehandle, &nmf->filehandle, sizeof(fl->filehandle)); 108187096Salfred nmf->refcount = 1; 108287096Salfred nmf->exclusive = fl->client.exclusive; 108387096Salfred 108487096Salfred lflags = (nmf->exclusive == 1) ? 108587096Salfred (LOCK_EX | LOCK_NB) : (LOCK_SH | LOCK_NB); 108687096Salfred 108787096Salfred flerror = flock(nmf->fd, lflags); 108887096Salfred 108987096Salfred if (flerror != 0) { 109087096Salfred debuglog("flock failed (from %16s): %32s\n", 109187096Salfred fl->client_name, strerror(errno)); 109287096Salfred close(nmf->fd); 109387096Salfred free(nmf); 109487096Salfred switch (errno) { 109587096Salfred case EAGAIN: 109687096Salfred return (HW_DENIED); 109787096Salfred case ESTALE: 109887096Salfred return (HW_STALEFH); 109987096Salfred case EROFS: 110087096Salfred return (HW_READONLY); 110187096Salfred default: 110287096Salfred return (HW_RESERR); 110374462Salfred break; 110487096Salfred } 110587096Salfred } 110687096Salfred 110787096Salfred /* File opened and locked */ 110887096Salfred LIST_INSERT_HEAD(&monfilelist_head, nmf, monfilelist); 110987096Salfred 111087096Salfred debuglog("flock succeeded (from %16s)\n", fl->client_name); 111187096Salfred return (HW_GRANTED); 111287096Salfred} 111387096Salfred 111487096Salfredenum hwlock_status 111587096Salfredunlock_hwlock(const struct file_lock *fl) 111687096Salfred{ 111787096Salfred struct monfile *imf; 111887096Salfred 111987096Salfred debuglog("Entering unlock_hwlock\n"); 112087096Salfred debuglog("Entering loop interation\n"); 112187096Salfred 112287096Salfred /* Scan to see if filehandle already present */ 112387096Salfred LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 112487096Salfred if (bcmp(&fl->filehandle, &imf->filehandle, 112587096Salfred sizeof(fl->filehandle)) == 0) { 112687096Salfred /* imf is the correct filehandle */ 112774462Salfred break; 112874462Salfred } 112974462Salfred } 113087096Salfred 113187096Salfred debuglog("Completed iteration. Proceeding\n"); 113287096Salfred 113387096Salfred if (imf == NULL) { 113487096Salfred /* No lock found */ 113587096Salfred debuglog("Exiting unlock_hwlock (HW_DENIED_NOLOCK)\n"); 113687096Salfred return (HW_DENIED_NOLOCK); 113787096Salfred } 113887096Salfred 113987096Salfred /* Lock found */ 114087096Salfred --imf->refcount; 114187096Salfred 114287096Salfred if (imf->refcount < 0) { 114387096Salfred debuglog("Negative hardware reference count\n"); 114487096Salfred } 114587096Salfred 114687096Salfred if (imf->refcount <= 0) { 114787096Salfred close(imf->fd); 114887096Salfred LIST_REMOVE(imf, monfilelist); 114987096Salfred free(imf); 115087096Salfred } 115187096Salfred debuglog("Exiting unlock_hwlock (HW_GRANTED)\n"); 115287096Salfred return (HW_GRANTED); 115374462Salfred} 115474462Salfred 115587096Salfredenum hwlock_status 115692911Salfredtest_hwlock(fl, conflicting_fl) 115792911Salfred const struct file_lock *fl __unused; 115892911Salfred struct file_lock **conflicting_fl __unused; 115987096Salfred{ 116087096Salfred 116187096Salfred /* 116287096Salfred * XXX: lock tests on hardware are not required until 116387096Salfred * true partial file testing is done on the underlying file 116487096Salfred */ 116587096Salfred return (HW_RESERR); 116687096Salfred} 116787096Salfred 116887096Salfred 116987096Salfred 117087096Salfred/* 117187096Salfred * Below here are routines for manipulating blocked lock requests 117287096Salfred * They should only be called from the XXX_partialfilelock routines 117387096Salfred * if at all possible 117487096Salfred */ 117587096Salfred 117674462Salfredvoid 117787096Salfredadd_blockingfilelock(struct file_lock *fl) 117874462Salfred{ 117987096Salfred 118087096Salfred debuglog("Entering add_blockingfilelock\n"); 118187096Salfred 118287096Salfred /* 118387096Salfred * Clear the blocking flag so that it can be reused without 118487096Salfred * adding it to the blocking queue a second time 118587096Salfred */ 118687096Salfred 118787096Salfred fl->blocking = 0; 118887096Salfred LIST_INSERT_HEAD(&blockedlocklist_head, fl, nfslocklist); 118987096Salfred 119087096Salfred debuglog("Exiting add_blockingfilelock\n"); 119174462Salfred} 119274462Salfred 119374462Salfredvoid 119487096Salfredremove_blockingfilelock(struct file_lock *fl) 119574462Salfred{ 119674462Salfred 119787096Salfred debuglog("Entering remove_blockingfilelock\n"); 119887096Salfred 119987096Salfred LIST_REMOVE(fl, nfslocklist); 120087096Salfred 120187096Salfred debuglog("Exiting remove_blockingfilelock\n"); 120287096Salfred} 120387096Salfred 120487096Salfredvoid 120587096Salfredclear_blockingfilelock(const char *hostname) 120687096Salfred{ 120787096Salfred struct file_lock *ifl,*nfl; 120887096Salfred 120987096Salfred /* 121087096Salfred * Normally, LIST_FOREACH is called for, but since 121187096Salfred * the current element *is* the iterator, deleting it 121287096Salfred * would mess up the iteration. Thus, a next element 121387096Salfred * must be used explicitly 121487096Salfred */ 121587096Salfred 121687096Salfred ifl = LIST_FIRST(&blockedlocklist_head); 121787096Salfred 121887096Salfred while (ifl != NULL) { 121987096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 122087096Salfred 122187096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 122287096Salfred remove_blockingfilelock(ifl); 122387096Salfred deallocate_file_lock(ifl); 122474462Salfred } 122587096Salfred 122687096Salfred ifl = nfl; 122787096Salfred } 122887096Salfred} 122987096Salfred 123087096Salfredvoid 123187096Salfredretry_blockingfilelocklist(void) 123287096Salfred{ 123387096Salfred /* Retry all locks in the blocked list */ 123489439Salfred struct file_lock *ifl, *nfl, *pfl; /* Iterator */ 123587096Salfred enum partialfilelock_status pflstatus; 123687096Salfred 123787096Salfred debuglog("Entering retry_blockingfilelocklist\n"); 123887096Salfred 123989439Salfred pfl = NULL; 124087096Salfred ifl = LIST_FIRST(&blockedlocklist_head); 124187096Salfred debuglog("Iterator choice %p\n",ifl); 124287096Salfred 124387096Salfred while (ifl != NULL) { 124487096Salfred /* 124587096Salfred * SUBTLE BUG: The next element must be worked out before the 124687096Salfred * current element has been moved 124787096Salfred */ 124887096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 124987096Salfred debuglog("Iterator choice %p\n",ifl); 125089439Salfred debuglog("Prev iterator choice %p\n",pfl); 125187096Salfred debuglog("Next iterator choice %p\n",nfl); 125287096Salfred 125387096Salfred /* 125487096Salfred * SUBTLE BUG: The file_lock must be removed from the 125587096Salfred * old list so that it's list pointers get disconnected 125687096Salfred * before being allowed to participate in the new list 125787096Salfred * which will automatically add it in if necessary. 125887096Salfred */ 125987096Salfred 126087096Salfred LIST_REMOVE(ifl, nfslocklist); 126187096Salfred pflstatus = lock_partialfilelock(ifl); 126287096Salfred 126387096Salfred if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { 126487096Salfred debuglog("Granted blocked lock\n"); 126587096Salfred /* lock granted and is now being used */ 126687096Salfred send_granted(ifl,0); 126787096Salfred } else { 126887096Salfred /* Reinsert lock back into same place in blocked list */ 126987096Salfred debuglog("Replacing blocked lock\n"); 127089439Salfred if (pfl != NULL) 127189439Salfred LIST_INSERT_AFTER(pfl, ifl, nfslocklist); 127289439Salfred else 127389439Salfred /* ifl is the only elem. in the list */ 127489439Salfred LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist); 127574462Salfred } 127687096Salfred 127787096Salfred /* Valid increment behavior regardless of state of ifl */ 127887096Salfred ifl = nfl; 127989439Salfred /* if a lock was granted incrementing pfl would make it nfl */ 128089439Salfred if (pfl != NULL && (LIST_NEXT(pfl, nfslocklist) != nfl)) 128189439Salfred pfl = LIST_NEXT(pfl, nfslocklist); 128289439Salfred else 128389439Salfred pfl = LIST_FIRST(&blockedlocklist_head); 128487096Salfred } 128587096Salfred 128687096Salfred debuglog("Exiting retry_blockingfilelocklist\n"); 128787096Salfred} 128887096Salfred 128987096Salfred/* 129087096Salfred * Below here are routines associated with manipulating all 129187096Salfred * aspects of the partial file locking system (list, hardware, etc.) 129287096Salfred */ 129387096Salfred 129487096Salfred/* 129587096Salfred * Please note that lock monitoring must be done at this level which 129687096Salfred * keeps track of *individual* lock requests on lock and unlock 129787096Salfred * 129887096Salfred * XXX: Split unlocking is going to make the unlock code miserable 129987096Salfred */ 130087096Salfred 130187096Salfred/* 130287096Salfred * lock_partialfilelock: 130387096Salfred * 130487096Salfred * Argument fl gets modified as its list housekeeping entries get modified 130587096Salfred * upon insertion into the NFS lock list 130687096Salfred * 130787096Salfred * This routine makes several assumptions: 130887096Salfred * 1) It (will) pass locks through to flock to lock the entire underlying file 130987096Salfred * and then parcel out NFS locks if it gets control of the file. 131087096Salfred * This matches the old rpc.lockd file semantics (except where it 131187096Salfred * is now more correct). It is the safe solution, but will cause 131287096Salfred * overly restrictive blocking if someone is trying to use the 131387096Salfred * underlying files without using NFS. This appears to be an 131487096Salfred * acceptable tradeoff since most people use standalone NFS servers. 131587096Salfred * XXX: The right solution is probably kevent combined with fcntl 131687096Salfred * 131787096Salfred * 2) Nothing modifies the lock lists between testing and granting 131887096Salfred * I have no idea whether this is a useful assumption or not 131987096Salfred */ 132087096Salfred 132187096Salfredenum partialfilelock_status 132287096Salfredlock_partialfilelock(struct file_lock *fl) 132387096Salfred{ 132487096Salfred enum partialfilelock_status retval; 132587096Salfred enum nfslock_status lnlstatus; 132687096Salfred enum hwlock_status hwstatus; 132787096Salfred 132887096Salfred debuglog("Entering lock_partialfilelock\n"); 132987096Salfred 133087096Salfred retval = PFL_DENIED; 133187096Salfred 133287096Salfred /* 133387096Salfred * Execute the NFS lock first, if possible, as it is significantly 133487096Salfred * easier and less expensive to undo than the filesystem lock 133587096Salfred */ 133687096Salfred 133787096Salfred lnlstatus = lock_nfslock(fl); 133887096Salfred 133987096Salfred switch (lnlstatus) { 134087096Salfred case NFS_GRANTED: 134187096Salfred case NFS_GRANTED_DUPLICATE: 134274462Salfred /* 134387096Salfred * At this point, the NFS lock is allocated and active. 134487096Salfred * Remember to clean it up if the hardware lock fails 134574462Salfred */ 134687096Salfred hwstatus = lock_hwlock(fl); 134787096Salfred 134887096Salfred switch (hwstatus) { 134987096Salfred case HW_GRANTED: 135087096Salfred case HW_GRANTED_DUPLICATE: 135187096Salfred debuglog("HW GRANTED\n"); 135287096Salfred /* 135387096Salfred * XXX: Fixme: Check hwstatus for duplicate when 135487096Salfred * true partial file locking and accounting is 135587096Salfred * done on the hardware 135687096Salfred */ 135787096Salfred if (lnlstatus == NFS_GRANTED_DUPLICATE) { 135887096Salfred retval = PFL_GRANTED_DUPLICATE; 135987096Salfred } else { 136087096Salfred retval = PFL_GRANTED; 136187096Salfred } 136287096Salfred monitor_lock_host(fl->client_name); 136387096Salfred break; 136487096Salfred case HW_RESERR: 136587096Salfred debuglog("HW RESERR\n"); 136687096Salfred retval = PFL_HWRESERR; 136787096Salfred break; 136887096Salfred case HW_DENIED: 136987096Salfred debuglog("HW DENIED\n"); 137087096Salfred retval = PFL_HWDENIED; 137187096Salfred break; 137287096Salfred default: 137387096Salfred debuglog("Unmatched hwstatus %d\n",hwstatus); 137487096Salfred break; 137574462Salfred } 137687096Salfred 137787096Salfred if (retval != PFL_GRANTED && 137887096Salfred retval != PFL_GRANTED_DUPLICATE) { 137987096Salfred /* Clean up the NFS lock */ 138087096Salfred debuglog("Deleting trial NFS lock\n"); 138187096Salfred delete_nfslock(fl); 138287096Salfred } 138387096Salfred break; 138487096Salfred case NFS_DENIED: 138587096Salfred retval = PFL_NFSDENIED; 138687096Salfred break; 138787096Salfred case NFS_RESERR: 138887096Salfred retval = PFL_NFSRESERR; 138987096Salfred default: 139087096Salfred debuglog("Unmatched lnlstatus %d\n"); 139187096Salfred retval = PFL_NFSDENIED_NOLOCK; 139287096Salfred break; 139387096Salfred } 139487096Salfred 139587096Salfred /* 139687096Salfred * By the time fl reaches here, it is completely free again on 139787096Salfred * failure. The NFS lock done before attempting the 139887096Salfred * hardware lock has been backed out 139987096Salfred */ 140087096Salfred 140187096Salfred if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) { 140287096Salfred /* Once last chance to check the lock */ 140387096Salfred if (fl->blocking == 1) { 140487096Salfred /* Queue the lock */ 140587096Salfred debuglog("BLOCKING LOCK RECEIVED\n"); 140687096Salfred retval = (retval == PFL_NFSDENIED ? 140787096Salfred PFL_NFSBLOCKED : PFL_HWBLOCKED); 140887096Salfred add_blockingfilelock(fl); 140987096Salfred dump_filelock(fl); 141074462Salfred } else { 141187096Salfred /* Leave retval alone, it's already correct */ 141287096Salfred debuglog("Lock denied. Non-blocking failure\n"); 141387096Salfred dump_filelock(fl); 141487096Salfred } 141587096Salfred } 141687096Salfred 141787096Salfred debuglog("Exiting lock_partialfilelock\n"); 141887096Salfred 141987096Salfred return retval; 142087096Salfred} 142187096Salfred 142287096Salfred/* 142387096Salfred * unlock_partialfilelock: 142487096Salfred * 142587096Salfred * Given a file_lock, unlock all locks which match. 142687096Salfred * 142787096Salfred * Note that a given lock might have to unlock ITSELF! See 142887096Salfred * clear_partialfilelock for example. 142987096Salfred */ 143087096Salfred 143187096Salfredenum partialfilelock_status 143287096Salfredunlock_partialfilelock(const struct file_lock *fl) 143387096Salfred{ 143487096Salfred struct file_lock *lfl,*rfl,*releasedfl,*selffl; 143587096Salfred enum partialfilelock_status retval; 143687096Salfred enum nfslock_status unlstatus; 143787096Salfred enum hwlock_status unlhwstatus, lhwstatus; 143887096Salfred 143987096Salfred debuglog("Entering unlock_partialfilelock\n"); 144087096Salfred 144187096Salfred selffl = NULL; 144287096Salfred lfl = NULL; 144387096Salfred rfl = NULL; 144487096Salfred releasedfl = NULL; 144587096Salfred retval = PFL_DENIED; 144687096Salfred 144787096Salfred /* 144887096Salfred * There are significant overlap and atomicity issues 144987096Salfred * with partially releasing a lock. For example, releasing 145087096Salfred * part of an NFS shared lock does *not* always release the 145187096Salfred * corresponding part of the file since there is only one 145287096Salfred * rpc.lockd UID but multiple users could be requesting it 145387096Salfred * from NFS. Also, an unlock request should never allow 145487096Salfred * another process to gain a lock on the remaining parts. 145587096Salfred * ie. Always apply the new locks before releasing the 145687096Salfred * old one 145787096Salfred */ 145887096Salfred 145987096Salfred /* 146087096Salfred * Loop is required since multiple little locks 146187096Salfred * can be allocated and then deallocated with one 146287096Salfred * big unlock. 146387096Salfred * 146487096Salfred * The loop is required to be here so that the nfs & 146587096Salfred * hw subsystems do not need to communicate with one 146687096Salfred * one another 146787096Salfred */ 146887096Salfred 146987096Salfred do { 147087096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 147187096Salfred /* lfl&rfl are created *AND* placed into the NFS lock list if required */ 147287096Salfred unlstatus = unlock_nfslock(fl, &releasedfl, &lfl, &rfl); 147387096Salfred debuglog("Value of releasedfl: %p\n",releasedfl); 147487096Salfred 147587096Salfred 147687096Salfred /* XXX: This is grungy. It should be refactored to be cleaner */ 147787096Salfred if (lfl != NULL) { 147887096Salfred lhwstatus = lock_hwlock(lfl); 147987096Salfred if (lhwstatus != HW_GRANTED && 148087096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 148187096Salfred debuglog("HW duplicate lock failure for left split\n"); 148274462Salfred } 148387096Salfred monitor_lock_host(lfl->client_name); 148487096Salfred } 148587096Salfred 148687096Salfred if (rfl != NULL) { 148787096Salfred lhwstatus = lock_hwlock(rfl); 148887096Salfred if (lhwstatus != HW_GRANTED && 148987096Salfred lhwstatus != HW_GRANTED_DUPLICATE) { 149087096Salfred debuglog("HW duplicate lock failure for right split\n"); 149187096Salfred } 149287096Salfred monitor_lock_host(rfl->client_name); 149387096Salfred } 149487096Salfred 149587096Salfred switch (unlstatus) { 149687096Salfred case NFS_GRANTED: 149787096Salfred /* Attempt to unlock on the hardware */ 149887096Salfred debuglog("NFS unlock granted. Attempting hardware unlock\n"); 149987096Salfred 150087096Salfred /* This call *MUST NOT* unlock the two newly allocated locks */ 150187096Salfred unlhwstatus = unlock_hwlock(fl); 150287096Salfred debuglog("HW unlock returned with code %d\n",unlhwstatus); 150387096Salfred 150487096Salfred switch (unlhwstatus) { 150587096Salfred case HW_GRANTED: 150687096Salfred debuglog("HW unlock granted\n"); 150787096Salfred unmonitor_lock_host(releasedfl->client_name); 150887096Salfred retval = PFL_GRANTED; 150974462Salfred break; 151087096Salfred case HW_DENIED_NOLOCK: 151187096Salfred /* Huh?!?! This shouldn't happen */ 151287096Salfred debuglog("HW unlock denied no lock\n"); 151387096Salfred retval = PFL_HWRESERR; 151487096Salfred /* Break out of do-while */ 151587096Salfred unlstatus = NFS_RESERR; 151674462Salfred break; 151774462Salfred default: 151887096Salfred debuglog("HW unlock failed\n"); 151987096Salfred retval = PFL_HWRESERR; 152087096Salfred /* Break out of do-while */ 152187096Salfred unlstatus = NFS_RESERR; 152287096Salfred break; 152374462Salfred } 152487096Salfred 152587096Salfred debuglog("Exiting with status retval: %d\n",retval); 152687096Salfred 152787096Salfred retry_blockingfilelocklist(); 152887096Salfred break; 152987096Salfred case NFS_DENIED_NOLOCK: 153087096Salfred retval = PFL_GRANTED; 153187096Salfred debuglog("All locks cleaned out\n"); 153287096Salfred break; 153387096Salfred default: 153487096Salfred retval = PFL_NFSRESERR; 153587096Salfred debuglog("NFS unlock failure\n"); 153687096Salfred dump_filelock(fl); 153787096Salfred break; 153874462Salfred } 153987096Salfred 154087096Salfred if (releasedfl != NULL) { 154187096Salfred if (fl == releasedfl) { 154287096Salfred /* 154387096Salfred * XXX: YECHHH!!! Attempt to unlock self succeeded 154487096Salfred * but we can't deallocate the space yet. This is what 154587096Salfred * happens when you don't write malloc and free together 154687096Salfred */ 154787096Salfred debuglog("Attempt to unlock self\n"); 154887096Salfred selffl = releasedfl; 154987096Salfred } else { 155087096Salfred /* 155187096Salfred * XXX: this deallocation *still* needs to migrate closer 155287096Salfred * to the allocation code way up in get_lock or the allocation 155387096Salfred * code needs to migrate down (violation of "When you write 155487096Salfred * malloc you must write free") 155587096Salfred */ 155687096Salfred 155787096Salfred deallocate_file_lock(releasedfl); 155887096Salfred } 155987096Salfred } 156087096Salfred 156187096Salfred } while (unlstatus == NFS_GRANTED); 156287096Salfred 156387096Salfred if (selffl != NULL) { 156487096Salfred /* 156587096Salfred * This statement wipes out the incoming file lock (fl) 156687096Salfred * in spite of the fact that it is declared const 156787096Salfred */ 156887096Salfred debuglog("WARNING! Destroying incoming lock pointer\n"); 156987096Salfred deallocate_file_lock(selffl); 157074462Salfred } 157187096Salfred 157287096Salfred debuglog("Exiting unlock_partialfilelock\n"); 157387096Salfred 157487096Salfred return retval; 157574462Salfred} 157674462Salfred 157774462Salfred/* 157887096Salfred * clear_partialfilelock 157974462Salfred * 158087096Salfred * Normally called in response to statd state number change. 158187096Salfred * Wipe out all locks held by a host. As a bonus, the act of 158287096Salfred * doing so should automatically clear their statd entries and 158387096Salfred * unmonitor the host. 158474462Salfred */ 158574462Salfred 158687096Salfredvoid 158787096Salfredclear_partialfilelock(const char *hostname) 158887096Salfred{ 158987096Salfred struct file_lock *ifl, *nfl; 159087096Salfred 159187096Salfred /* Clear blocking file lock list */ 159287096Salfred clear_blockingfilelock(hostname); 159387096Salfred 159487096Salfred /* do all required unlocks */ 159587096Salfred /* Note that unlock can smash the current pointer to a lock */ 159687096Salfred 159787096Salfred /* 159887096Salfred * Normally, LIST_FOREACH is called for, but since 159987096Salfred * the current element *is* the iterator, deleting it 160087096Salfred * would mess up the iteration. Thus, a next element 160187096Salfred * must be used explicitly 160287096Salfred */ 160387096Salfred 160487096Salfred ifl = LIST_FIRST(&nfslocklist_head); 160587096Salfred 160687096Salfred while (ifl != NULL) { 160787096Salfred nfl = LIST_NEXT(ifl, nfslocklist); 160887096Salfred 160987096Salfred if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 161087096Salfred /* Unlock destroys ifl out from underneath */ 161187096Salfred unlock_partialfilelock(ifl); 161287096Salfred /* ifl is NO LONGER VALID AT THIS POINT */ 161387096Salfred } 161487096Salfred ifl = nfl; 161587096Salfred } 161687096Salfred} 161787096Salfred 161887096Salfred/* 161987096Salfred * test_partialfilelock: 162087096Salfred */ 162187096Salfredenum partialfilelock_status 162287096Salfredtest_partialfilelock(const struct file_lock *fl, 162387096Salfred struct file_lock **conflicting_fl) 162487096Salfred{ 162587096Salfred enum partialfilelock_status retval; 162687096Salfred enum nfslock_status teststatus; 162787096Salfred 162887096Salfred debuglog("Entering testpartialfilelock...\n"); 162987096Salfred 163087096Salfred retval = PFL_DENIED; 163187096Salfred 163287096Salfred teststatus = test_nfslock(fl, conflicting_fl); 163387096Salfred debuglog("test_partialfilelock: teststatus %d\n",teststatus); 163487096Salfred 163587096Salfred if (teststatus == NFS_GRANTED || teststatus == NFS_GRANTED_DUPLICATE) { 163687096Salfred /* XXX: Add the underlying filesystem locking code */ 163787096Salfred retval = (teststatus == NFS_GRANTED) ? 163887096Salfred PFL_GRANTED : PFL_GRANTED_DUPLICATE; 163987096Salfred debuglog("Dumping locks...\n"); 164087096Salfred dump_filelock(fl); 164187096Salfred dump_filelock(*conflicting_fl); 164287096Salfred debuglog("Done dumping locks...\n"); 164387096Salfred } else { 164487096Salfred retval = PFL_NFSDENIED; 164587096Salfred debuglog("NFS test denied.\n"); 164687096Salfred dump_filelock(fl); 164787096Salfred debuglog("Conflicting.\n"); 164887096Salfred dump_filelock(*conflicting_fl); 164987096Salfred } 165087096Salfred 165187096Salfred debuglog("Exiting testpartialfilelock...\n"); 165287096Salfred 165387096Salfred return retval; 165487096Salfred} 165587096Salfred 165687096Salfred/* 165787096Salfred * Below here are routines associated with translating the partial file locking 165887096Salfred * codes into useful codes to send back to the NFS RPC messaging system 165987096Salfred */ 166087096Salfred 166187096Salfred/* 166287096Salfred * These routines translate the (relatively) useful return codes back onto 166387096Salfred * the few return codes which the nlm subsystems wishes to trasmit 166487096Salfred */ 166587096Salfred 166674462Salfredenum nlm_stats 166787096Salfreddo_test(struct file_lock *fl, struct file_lock **conflicting_fl) 166874462Salfred{ 166987096Salfred enum partialfilelock_status pfsret; 167087096Salfred enum nlm_stats retval; 167174462Salfred 167287096Salfred debuglog("Entering do_test...\n"); 167387096Salfred 167487096Salfred pfsret = test_partialfilelock(fl,conflicting_fl); 167587096Salfred 167687096Salfred switch (pfsret) { 167787096Salfred case PFL_GRANTED: 167887096Salfred debuglog("PFL test lock granted\n"); 167987096Salfred dump_filelock(fl); 168087096Salfred dump_filelock(*conflicting_fl); 168187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 168287096Salfred break; 168387096Salfred case PFL_GRANTED_DUPLICATE: 168487096Salfred debuglog("PFL test lock granted--duplicate id detected\n"); 168587096Salfred dump_filelock(fl); 168687096Salfred dump_filelock(*conflicting_fl); 168787096Salfred debuglog("Clearing conflicting_fl for call semantics\n"); 168887096Salfred *conflicting_fl = NULL; 168987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 169087096Salfred break; 169187096Salfred case PFL_NFSDENIED: 169287096Salfred case PFL_HWDENIED: 169387096Salfred debuglog("PFL test lock denied\n"); 169487096Salfred dump_filelock(fl); 169587096Salfred dump_filelock(*conflicting_fl); 169687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 169787096Salfred break; 169887096Salfred case PFL_NFSRESERR: 169987096Salfred case PFL_HWRESERR: 170087096Salfred debuglog("PFL test lock resource fail\n"); 170187096Salfred dump_filelock(fl); 170287096Salfred dump_filelock(*conflicting_fl); 170387096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 170487096Salfred break; 170587096Salfred default: 170687096Salfred debuglog("PFL test lock *FAILED*\n"); 170787096Salfred dump_filelock(fl); 170887096Salfred dump_filelock(*conflicting_fl); 170987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 171087096Salfred break; 171187096Salfred } 171287096Salfred 171387096Salfred debuglog("Exiting do_test...\n"); 171487096Salfred 171587096Salfred return retval; 171687096Salfred} 171787096Salfred 171887096Salfred/* 171987096Salfred * do_lock: Try to acquire a lock 172087096Salfred * 172187096Salfred * This routine makes a distinction between NLM versions. I am pretty 172287096Salfred * convinced that this should be abstracted out and bounced up a level 172387096Salfred */ 172487096Salfred 172587096Salfredenum nlm_stats 172687096Salfreddo_lock(struct file_lock *fl) 172787096Salfred{ 172887096Salfred enum partialfilelock_status pfsret; 172987096Salfred enum nlm_stats retval; 173087096Salfred 173187096Salfred debuglog("Entering do_lock...\n"); 173287096Salfred 173387096Salfred pfsret = lock_partialfilelock(fl); 173487096Salfred 173587096Salfred switch (pfsret) { 173687096Salfred case PFL_GRANTED: 173787096Salfred debuglog("PFL lock granted"); 173887096Salfred dump_filelock(fl); 173987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 174087096Salfred break; 174187096Salfred case PFL_GRANTED_DUPLICATE: 174287096Salfred debuglog("PFL lock granted--duplicate id detected"); 174387096Salfred dump_filelock(fl); 174487096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 174587096Salfred break; 174687096Salfred case PFL_NFSDENIED: 174787096Salfred case PFL_HWDENIED: 174887096Salfred debuglog("PFL_NFS lock denied"); 174987096Salfred dump_filelock(fl); 175087096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 175187096Salfred break; 175287096Salfred case PFL_NFSBLOCKED: 175387096Salfred case PFL_HWBLOCKED: 175487096Salfred debuglog("PFL_NFS blocking lock denied. Queued.\n"); 175587096Salfred dump_filelock(fl); 175687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_blocked : nlm_blocked; 175787096Salfred break; 175887096Salfred case PFL_NFSRESERR: 175987096Salfred case PFL_HWRESERR: 176087096Salfred debuglog("PFL lock resource alocation fail\n"); 176187096Salfred dump_filelock(fl); 176287096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 176387096Salfred break; 176487096Salfred default: 176587096Salfred debuglog("PFL lock *FAILED*"); 176687096Salfred dump_filelock(fl); 176787096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 176887096Salfred break; 176987096Salfred } 177087096Salfred 177187096Salfred debuglog("Exiting do_lock...\n"); 177287096Salfred 177387096Salfred return retval; 177487096Salfred} 177587096Salfred 177687096Salfredenum nlm_stats 177787096Salfreddo_unlock(struct file_lock *fl) 177887096Salfred{ 177987096Salfred enum partialfilelock_status pfsret; 178087096Salfred enum nlm_stats retval; 178187096Salfred 178287096Salfred debuglog("Entering do_unlock...\n"); 178387096Salfred pfsret = unlock_partialfilelock(fl); 178487096Salfred 178587096Salfred switch (pfsret) { 178687096Salfred case PFL_GRANTED: 178787096Salfred debuglog("PFL unlock granted"); 178887096Salfred dump_filelock(fl); 178987096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 179087096Salfred break; 179187096Salfred case PFL_NFSDENIED: 179287096Salfred case PFL_HWDENIED: 179387096Salfred debuglog("PFL_NFS unlock denied"); 179487096Salfred dump_filelock(fl); 179587096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 179687096Salfred break; 179787096Salfred case PFL_NFSDENIED_NOLOCK: 179887096Salfred case PFL_HWDENIED_NOLOCK: 179987096Salfred debuglog("PFL_NFS no lock found\n"); 180087096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 180187096Salfred break; 180287096Salfred case PFL_NFSRESERR: 180387096Salfred case PFL_HWRESERR: 180487096Salfred debuglog("PFL unlock resource failure"); 180587096Salfred dump_filelock(fl); 180687096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 180787096Salfred break; 180887096Salfred default: 180987096Salfred debuglog("PFL unlock *FAILED*"); 181087096Salfred dump_filelock(fl); 181187096Salfred retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 181287096Salfred break; 181387096Salfred } 181487096Salfred 181587096Salfred debuglog("Exiting do_unlock...\n"); 181687096Salfred 181787096Salfred return retval; 181887096Salfred} 181987096Salfred 182087096Salfred/* 182187096Salfred * do_clear 182287096Salfred * 182387096Salfred * This routine is non-existent because it doesn't have a return code. 182487096Salfred * It is here for completeness in case someone *does* need to do return 182587096Salfred * codes later. A decent compiler should optimize this away. 182687096Salfred */ 182787096Salfred 182887096Salfredvoid 182987096Salfreddo_clear(const char *hostname) 183087096Salfred{ 183187096Salfred 183287096Salfred clear_partialfilelock(hostname); 183387096Salfred} 183487096Salfred 183587096Salfred/* 183687096Salfred * The following routines are all called from the code which the 183787096Salfred * RPC layer invokes 183887096Salfred */ 183987096Salfred 184087096Salfred/* 184187096Salfred * testlock(): inform the caller if the requested lock would be granted 184287096Salfred * 184387096Salfred * returns NULL if lock would granted 184487096Salfred * returns pointer to a conflicting nlm4_holder if not 184587096Salfred */ 184687096Salfred 184787096Salfredstruct nlm4_holder * 184892911Salfredtestlock(struct nlm4_lock *lock, bool_t exclusive, int flags __unused) 184987096Salfred{ 185087096Salfred struct file_lock test_fl, *conflicting_fl; 185187096Salfred 185287096Salfred bzero(&test_fl, sizeof(test_fl)); 185387096Salfred 185487096Salfred bcopy(lock->fh.n_bytes, &(test_fl.filehandle), sizeof(fhandle_t)); 185587096Salfred copy_nlm4_lock_to_nlm4_holder(lock, exclusive, &test_fl.client); 185687096Salfred 185787096Salfred siglock(); 185887096Salfred do_test(&test_fl, &conflicting_fl); 185987096Salfred 186087096Salfred if (conflicting_fl == NULL) { 186187096Salfred debuglog("No conflicting lock found\n"); 186287096Salfred sigunlock(); 186387096Salfred return NULL; 186487096Salfred } else { 186587096Salfred debuglog("Found conflicting lock\n"); 186687096Salfred dump_filelock(conflicting_fl); 186787096Salfred sigunlock(); 186887096Salfred return (&conflicting_fl->client); 186987096Salfred } 187087096Salfred} 187187096Salfred 187287096Salfred/* 187387096Salfred * getlock: try to aquire the lock. 187487096Salfred * If file is already locked and we can sleep, put the lock in the list with 187587096Salfred * status LKST_WAITING; it'll be processed later. 187687096Salfred * Otherwise try to lock. If we're allowed to block, fork a child which 187787096Salfred * will do the blocking lock. 187887096Salfred */ 187987096Salfred 188087096Salfredenum nlm_stats 188187096Salfredgetlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) 188287096Salfred{ 188387096Salfred struct file_lock *newfl; 188487096Salfred enum nlm_stats retval; 188587096Salfred 188687096Salfred debuglog("Entering getlock...\n"); 188787096Salfred 188887096Salfred if (grace_expired == 0 && lckarg->reclaim == 0) 188987096Salfred return (flags & LOCK_V4) ? 189087096Salfred nlm4_denied_grace_period : nlm_denied_grace_period; 189187096Salfred 189287096Salfred /* allocate new file_lock for this request */ 189387096Salfred newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie); 189487096Salfred if (newfl == NULL) { 189587096Salfred syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); 189687096Salfred /* failed */ 189787096Salfred return (flags & LOCK_V4) ? 189887096Salfred nlm4_denied_nolocks : nlm_denied_nolocks; 189987096Salfred } 190087096Salfred 190187096Salfred if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) { 190287096Salfred debuglog("recieved fhandle size %d, local size %d", 190387096Salfred lckarg->alock.fh.n_len, (int)sizeof(fhandle_t)); 190487096Salfred } 190587096Salfred 190687096Salfred fill_file_lock(newfl, (fhandle_t *)lckarg->alock.fh.n_bytes, 190787096Salfred (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf, 190887199Salfred lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, 190987199Salfred lckarg->alock.l_len, 191087096Salfred lckarg->alock.caller_name, lckarg->state, 0, flags, lckarg->block); 191187096Salfred 191287096Salfred /* 191387096Salfred * newfl is now fully constructed and deallocate_file_lock 191487096Salfred * can now be used to delete it 191587096Salfred */ 191687096Salfred 191787096Salfred siglock(); 191887096Salfred debuglog("Pointer to new lock is %p\n",newfl); 191987096Salfred 192087096Salfred retval = do_lock(newfl); 192187096Salfred 192287096Salfred debuglog("Pointer to new lock is %p\n",newfl); 192387096Salfred sigunlock(); 192487096Salfred 192587096Salfred switch (retval) 192687096Salfred { 192787096Salfred case nlm4_granted: 192887096Salfred /* case nlm_granted: is the same as nlm4_granted */ 192987096Salfred /* do_mon(lckarg->alock.caller_name); */ 193074462Salfred break; 193187096Salfred case nlm4_blocked: 193287096Salfred /* case nlm_blocked: is the same as nlm4_blocked */ 193387096Salfred /* do_mon(lckarg->alock.caller_name); */ 193474462Salfred break; 193574462Salfred default: 193687096Salfred deallocate_file_lock(newfl); 193787096Salfred break; 193874462Salfred } 193987096Salfred 194087096Salfred debuglog("Exiting getlock...\n"); 194187096Salfred 194287096Salfred return retval; 194387096Salfred} 194487096Salfred 194587096Salfred 194687096Salfred/* unlock a filehandle */ 194787096Salfredenum nlm_stats 194892911Salfredunlock(nlm4_lock *lock, const int flags __unused) 194987096Salfred{ 195087096Salfred struct file_lock fl; 195187096Salfred enum nlm_stats err; 195287096Salfred 195387096Salfred siglock(); 195487096Salfred 195587096Salfred debuglog("Entering unlock...\n"); 195687096Salfred 195787096Salfred bzero(&fl,sizeof(struct file_lock)); 195887096Salfred bcopy(lock->fh.n_bytes, &fl.filehandle, sizeof(fhandle_t)); 195987096Salfred 196087096Salfred copy_nlm4_lock_to_nlm4_holder(lock, 0, &fl.client); 196187096Salfred 196287096Salfred err = do_unlock(&fl); 196387096Salfred 196487096Salfred sigunlock(); 196587096Salfred 196687096Salfred debuglog("Exiting unlock...\n"); 196787096Salfred 196887096Salfred return err; 196987096Salfred} 197087096Salfred 197187096Salfred/* 197287096Salfred * XXX: The following monitor/unmonitor routines 197387096Salfred * have not been extensively tested (ie. no regression 197487096Salfred * script exists like for the locking sections 197587096Salfred */ 197687096Salfred 197787096Salfred/* 197887096Salfred * monitor_lock_host: monitor lock hosts locally with a ref count and 197987096Salfred * inform statd 198087096Salfred */ 198187096Salfredvoid 198287096Salfredmonitor_lock_host(const char *hostname) 198387096Salfred{ 198487096Salfred struct host *ihp, *nhp; 198587096Salfred struct mon smon; 198687096Salfred struct sm_stat_res sres; 198787096Salfred int rpcret, statflag; 198887096Salfred 198987096Salfred rpcret = 0; 199087096Salfred statflag = 0; 199187096Salfred 199287096Salfred LIST_FOREACH(ihp, &hostlst_head, hostlst) { 199387096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 199487096Salfred /* Host is already monitored, bump refcount */ 199587096Salfred ++ihp->refcnt; 199687096Salfred /* Host should only be in the monitor list once */ 199787096Salfred return; 199887096Salfred } 199974462Salfred } 200087096Salfred 200187096Salfred /* Host is not yet monitored, add it */ 200287096Salfred nhp = malloc(sizeof(struct host)); 200387096Salfred 200487096Salfred if (nhp == NULL) { 200587096Salfred debuglog("Unable to allocate entry for statd mon\n"); 200687096Salfred return; 200774462Salfred } 200887096Salfred 200987096Salfred /* Allocated new host entry, now fill the fields */ 201087096Salfred strncpy(nhp->name, hostname, SM_MAXSTRLEN); 201187096Salfred nhp->refcnt = 1; 201287096Salfred debuglog("Locally Monitoring host %16s\n",hostname); 201387096Salfred 201487096Salfred debuglog("Attempting to tell statd\n"); 201587096Salfred 201687096Salfred bzero(&smon,sizeof(smon)); 201787096Salfred 201887096Salfred smon.mon_id.mon_name = nhp->name; 201987096Salfred smon.mon_id.my_id.my_name = "localhost\0"; 202087096Salfred 202187096Salfred smon.mon_id.my_id.my_prog = NLM_PROG; 202287096Salfred smon.mon_id.my_id.my_vers = NLM_SM; 202387096Salfred smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 202487096Salfred 202587096Salfred rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon, 202687096Salfred &smon, xdr_sm_stat_res, &sres); 202787096Salfred 202887096Salfred if (rpcret == 0) { 202987096Salfred if (sres.res_stat == stat_fail) { 203087096Salfred debuglog("Statd call failed\n"); 203187096Salfred statflag = 0; 203287096Salfred } else { 203387096Salfred statflag = 1; 203474462Salfred } 203587096Salfred } else { 203687096Salfred debuglog("Rpc call to statd failed with return value: %d\n", 203787096Salfred rpcret); 203887096Salfred statflag = 0; 203974462Salfred } 204087096Salfred 204187096Salfred if (statflag == 1) { 204287096Salfred LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst); 204387096Salfred } else { 204487096Salfred free(nhp); 204587096Salfred } 204687096Salfred 204787096Salfred} 204887096Salfred 204987096Salfred/* 205087096Salfred * unmonitor_lock_host: clear monitor ref counts and inform statd when gone 205187096Salfred */ 205287096Salfredvoid 205387096Salfredunmonitor_lock_host(const char *hostname) 205487096Salfred{ 205587096Salfred struct host *ihp; 205687096Salfred struct mon_id smon_id; 205787096Salfred struct sm_stat smstat; 205887096Salfred int rpcret; 205987096Salfred 206087096Salfred rpcret = 0; 206187096Salfred 206287096Salfred for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL; 206387096Salfred ihp=LIST_NEXT(ihp, hostlst)) { 206487096Salfred if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 206587096Salfred /* Host is monitored, bump refcount */ 206687096Salfred --ihp->refcnt; 206787096Salfred /* Host should only be in the monitor list once */ 206874462Salfred break; 206974462Salfred } 207074462Salfred } 207187096Salfred 207287096Salfred if (ihp == NULL) { 207387096Salfred debuglog("Could not find host %16s in mon list\n", hostname); 207487096Salfred return; 207587096Salfred } 207687096Salfred 207787096Salfred if (ihp->refcnt > 0) 207887096Salfred return; 207987096Salfred 208087096Salfred if (ihp->refcnt < 0) { 208187096Salfred debuglog("Negative refcount!: %d\n", 208287096Salfred ihp->refcnt); 208387096Salfred } 208487096Salfred 208587096Salfred debuglog("Attempting to unmonitor host %16s\n", hostname); 208687096Salfred 208787096Salfred bzero(&smon_id,sizeof(smon_id)); 208887096Salfred 208987096Salfred smon_id.mon_name = (char *)hostname; 209087096Salfred smon_id.my_id.my_name = "localhost"; 209187096Salfred smon_id.my_id.my_prog = NLM_PROG; 209287096Salfred smon_id.my_id.my_vers = NLM_SM; 209387096Salfred smon_id.my_id.my_proc = NLM_SM_NOTIFY; 209487096Salfred 209587096Salfred rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, xdr_mon, 209687096Salfred &smon_id, xdr_sm_stat_res, &smstat); 209787096Salfred 209887096Salfred if (rpcret != 0) { 209987096Salfred debuglog("Rpc call to unmonitor statd failed with " 210087096Salfred " return value: %d\n", rpcret); 210187096Salfred } 210287096Salfred 210387096Salfred LIST_REMOVE(ihp, hostlst); 210487096Salfred free(ihp); 210574462Salfred} 210674462Salfred 210787096Salfred/* 210887096Salfred * notify: Clear all locks from a host if statd complains 210987096Salfred * 211087096Salfred * XXX: This routine has not been thoroughly tested. However, neither 211187096Salfred * had the old one been. It used to compare the statd crash state counter 211287096Salfred * to the current lock state. The upshot of this was that it basically 211387096Salfred * cleared all locks from the specified host 99% of the time (with the 211487096Salfred * other 1% being a bug). Consequently, the assumption is that clearing 211587096Salfred * all locks from a host when notified by statd is acceptable. 211687096Salfred * 211787096Salfred * Please note that this routine skips the usual level of redirection 211887096Salfred * through a do_* type routine. This introduces a possible level of 211987096Salfred * error and might better be written as do_notify and take this one out. 212087096Salfred 212187096Salfred */ 212287096Salfred 212374462Salfredvoid 212487096Salfrednotify(const char *hostname, const int state) 212587096Salfred{ 212687096Salfred debuglog("notify from %s, new state %d", hostname, state); 212787096Salfred 212887096Salfred siglock(); 212987096Salfred do_clear(hostname); 213087096Salfred sigunlock(); 213187096Salfred 213287096Salfred debuglog("Leaving notify\n"); 213387096Salfred} 213487096Salfred 213587096Salfredvoid 213674462Salfredsend_granted(fl, opcode) 213774462Salfred struct file_lock *fl; 213892911Salfred int opcode __unused; 213974462Salfred{ 214074462Salfred CLIENT *cli; 214174462Salfred static char dummy; 214274462Salfred struct timeval timeo; 214374462Salfred int success; 214474462Salfred static struct nlm_res retval; 214574462Salfred static struct nlm4_res retval4; 214674462Salfred 214787096Salfred debuglog("About to send granted on blocked lock\n"); 214887096Salfred sleep(1); 214987096Salfred debuglog("Blowing off return send\n"); 215087096Salfred 215174462Salfred cli = get_client(fl->addr, 215274462Salfred (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); 215374462Salfred if (cli == NULL) { 215474462Salfred syslog(LOG_NOTICE, "failed to get CLIENT for %s", 215574462Salfred fl->client_name); 215674462Salfred /* 215774462Salfred * We fail to notify remote that the lock has been granted. 215874462Salfred * The client will timeout and retry, the lock will be 215974462Salfred * granted at this time. 216074462Salfred */ 216174462Salfred return; 216274462Salfred } 216374462Salfred timeo.tv_sec = 0; 216474462Salfred timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ 216574462Salfred 216674462Salfred if (fl->flags & LOCK_V4) { 216774462Salfred static nlm4_testargs res; 216874462Salfred res.cookie = fl->client_cookie; 216974462Salfred res.exclusive = fl->client.exclusive; 217074462Salfred res.alock.caller_name = fl->client_name; 217174462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 217274462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 217374462Salfred res.alock.oh = fl->client.oh; 217474462Salfred res.alock.svid = fl->client.svid; 217574462Salfred res.alock.l_offset = fl->client.l_offset; 217674462Salfred res.alock.l_len = fl->client.l_len; 217787096Salfred debuglog("sending v4 reply%s", 217887096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 217974462Salfred if (fl->flags & LOCK_ASYNC) { 218074462Salfred success = clnt_call(cli, NLM4_GRANTED_MSG, 218174462Salfred xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo); 218274462Salfred } else { 218374462Salfred success = clnt_call(cli, NLM4_GRANTED, 218474462Salfred xdr_nlm4_testargs, &res, xdr_nlm4_res, 218574462Salfred &retval4, timeo); 218674462Salfred } 218774462Salfred } else { 218874462Salfred static nlm_testargs res; 218974462Salfred 219074462Salfred res.cookie = fl->client_cookie; 219174462Salfred res.exclusive = fl->client.exclusive; 219274462Salfred res.alock.caller_name = fl->client_name; 219374462Salfred res.alock.fh.n_len = sizeof(fhandle_t); 219474462Salfred res.alock.fh.n_bytes = (char*)&fl->filehandle; 219574462Salfred res.alock.oh = fl->client.oh; 219674462Salfred res.alock.svid = fl->client.svid; 219774462Salfred res.alock.l_offset = fl->client.l_offset; 219874462Salfred res.alock.l_len = fl->client.l_len; 219987096Salfred debuglog("sending v1 reply%s", 220087096Salfred (fl->flags & LOCK_ASYNC) ? " (async)":""); 220174462Salfred if (fl->flags & LOCK_ASYNC) { 220274462Salfred success = clnt_call(cli, NLM_GRANTED_MSG, 220374462Salfred xdr_nlm_testargs, &res, xdr_void, &dummy, timeo); 220474462Salfred } else { 220574462Salfred success = clnt_call(cli, NLM_GRANTED, 220674462Salfred xdr_nlm_testargs, &res, xdr_nlm_res, 220774462Salfred &retval, timeo); 220874462Salfred } 220974462Salfred } 221074462Salfred if (debug_level > 2) 221187096Salfred debuglog("clnt_call returns %d(%s) for granted", 221287096Salfred success, clnt_sperrno(success)); 221374462Salfred 221474462Salfred} 221574462Salfred 221687096Salfred/* 221787096Salfred * Routines below here have not been modified in the overhaul 221887096Salfred */ 221974462Salfred 222087096Salfred/* 222187096Salfred * Are these two routines still required since lockd is not spawning off 222287096Salfred * children to service locks anymore? Presumably they were originally 222387096Salfred * put in place to prevent a one child from changing the lock list out 222487096Salfred * from under another one. 222587096Salfred */ 222674462Salfred 222774462Salfredvoid 222887096Salfredsiglock(void) 222974462Salfred{ 223087096Salfred sigset_t block; 223174462Salfred 223287096Salfred sigemptyset(&block); 223387096Salfred sigaddset(&block, SIGCHLD); 223474462Salfred 223587096Salfred if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) { 223687096Salfred syslog(LOG_WARNING, "siglock failed: %s", strerror(errno)); 223787096Salfred } 223874462Salfred} 223974462Salfred 224074462Salfredvoid 224187096Salfredsigunlock(void) 224274462Salfred{ 224387096Salfred sigset_t block; 224474462Salfred 224587096Salfred sigemptyset(&block); 224687096Salfred sigaddset(&block, SIGCHLD); 224787096Salfred 224887096Salfred if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) { 224987096Salfred syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno)); 225087096Salfred } 225174462Salfred} 225274462Salfred 225374462Salfred 2254