1f67e4a8alfred/* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */ 2f67e4a8alfred 39da7bddpfg/*- 49da7bddpfg * SPDX-License-Identifier: BSD-4-Clause 59da7bddpfg * 60190d29alfred * Copyright (c) 2001 Andrew P. Lentvorski, Jr. 7f67e4a8alfred * Copyright (c) 2000 Manuel Bouyer. 8f67e4a8alfred * 9f67e4a8alfred * Redistribution and use in source and binary forms, with or without 10f67e4a8alfred * modification, are permitted provided that the following conditions 11f67e4a8alfred * are met: 12f67e4a8alfred * 1. Redistributions of source code must retain the above copyright 13f67e4a8alfred * notice, this list of conditions and the following disclaimer. 14f67e4a8alfred * 2. Redistributions in binary form must reproduce the above copyright 15f67e4a8alfred * notice, this list of conditions and the following disclaimer in the 16f67e4a8alfred * documentation and/or other materials provided with the distribution. 17f67e4a8alfred * 3. All advertising materials mentioning features or use of this software 18f67e4a8alfred * must display the following acknowledgement: 19f67e4a8alfred * This product includes software developed by the University of 20f67e4a8alfred * California, Berkeley and its contributors. 21f67e4a8alfred * 4. Neither the name of the University nor the names of its contributors 22f67e4a8alfred * may be used to endorse or promote products derived from this software 23f67e4a8alfred * without specific prior written permission. 24f67e4a8alfred * 25f67e4a8alfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26f67e4a8alfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27f67e4a8alfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28f67e4a8alfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29f67e4a8alfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30f67e4a8alfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31f67e4a8alfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32f67e4a8alfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33f67e4a8alfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34f67e4a8alfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35f67e4a8alfred * SUCH DAMAGE. 36f67e4a8alfred * 37f67e4a8alfred */ 38f67e4a8alfred 3980a7e91charnier#include <sys/cdefs.h> 4080a7e91charnier__FBSDID("$FreeBSD$"); 4180a7e91charnier 420190d29alfred#define LOCKD_DEBUG 430190d29alfred 44f67e4a8alfred#include <stdio.h> 450190d29alfred#ifdef LOCKD_DEBUG 460190d29alfred#include <stdarg.h> 470190d29alfred#endif 48f67e4a8alfred#include <stdlib.h> 49f67e4a8alfred#include <unistd.h> 50f67e4a8alfred#include <fcntl.h> 51f67e4a8alfred#include <syslog.h> 52f67e4a8alfred#include <errno.h> 53f67e4a8alfred#include <string.h> 54f67e4a8alfred#include <signal.h> 55f67e4a8alfred#include <rpc/rpc.h> 56f67e4a8alfred#include <sys/types.h> 57f67e4a8alfred#include <sys/stat.h> 58f67e4a8alfred#include <sys/socket.h> 59f67e4a8alfred#include <sys/param.h> 60f67e4a8alfred#include <sys/mount.h> 61f67e4a8alfred#include <sys/wait.h> 62f67e4a8alfred#include <rpcsvc/sm_inter.h> 63f67e4a8alfred#include <rpcsvc/nlm_prot.h> 64f67e4a8alfred#include "lockd_lock.h" 65f67e4a8alfred#include "lockd.h" 66f67e4a8alfred 670190d29alfred#define MAXOBJECTSIZE 64 680190d29alfred#define MAXBUFFERSIZE 1024 690190d29alfred 700190d29alfred/* 718dd54dcalfred * A set of utilities for managing file locking 728dd54dcalfred * 738dd54dcalfred * XXX: All locks are in a linked list, a better structure should be used 74415a3a9uqs * to improve search/access efficiency. 758dd54dcalfred */ 76f67e4a8alfred 77f67e4a8alfred/* struct describing a lock */ 78f67e4a8alfredstruct file_lock { 790190d29alfred LIST_ENTRY(file_lock) nfslocklist; 80f67e4a8alfred fhandle_t filehandle; /* NFS filehandle */ 81f67e4a8alfred struct sockaddr *addr; 82f67e4a8alfred struct nlm4_holder client; /* lock holder */ 833896856mjacob /* XXX: client_cookie used *only* in send_granted */ 84f67e4a8alfred netobj client_cookie; /* cookie sent by the client */ 85f67e4a8alfred int nsm_status; /* status from the remote lock manager */ 86f67e4a8alfred int status; /* lock status, see below */ 87f67e4a8alfred int flags; /* lock flags, see lockd_lock.h */ 880190d29alfred int blocking; /* blocking lock or not */ 890dd4779mr char client_name[SM_MAXSTRLEN]; /* client_name is really variable 900dd4779mr length and must be last! */ 91f67e4a8alfred}; 92f67e4a8alfred 930190d29alfredLIST_HEAD(nfslocklist_head, file_lock); 940190d29alfredstruct nfslocklist_head nfslocklist_head = LIST_HEAD_INITIALIZER(nfslocklist_head); 950190d29alfred 960190d29alfredLIST_HEAD(blockedlocklist_head, file_lock); 970190d29alfredstruct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blockedlocklist_head); 980190d29alfred 99f67e4a8alfred/* lock status */ 100f67e4a8alfred#define LKST_LOCKED 1 /* lock is locked */ 1018dd54dcalfred/* XXX: Is this flag file specific or lock specific? */ 102f67e4a8alfred#define LKST_WAITING 2 /* file is already locked by another host */ 103415a3a9uqs#define LKST_PROCESSING 3 /* child is trying to acquire the lock */ 104f67e4a8alfred#define LKST_DYING 4 /* must dies when we get news from the child */ 105f67e4a8alfred 1060190d29alfred/* struct describing a monitored host */ 1070190d29alfredstruct host { 1080190d29alfred LIST_ENTRY(host) hostlst; 1090190d29alfred int refcnt; 1100dd4779mr char name[SM_MAXSTRLEN]; /* name is really variable length and 1110dd4779mr must be last! */ 1120190d29alfred}; 1130190d29alfred/* list of hosts we monitor */ 1140190d29alfredLIST_HEAD(hostlst_head, host); 1150190d29alfredstruct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); 1160190d29alfred 1170190d29alfred/* 1180190d29alfred * File monitoring handlers 1190190d29alfred * XXX: These might be able to be removed when kevent support 1200190d29alfred * is placed into the hardware lock/unlock routines. (ie. 1210190d29alfred * let the kernel do all the file monitoring) 1220190d29alfred */ 1230190d29alfred 1240190d29alfred/* Struct describing a monitored file */ 1250190d29alfredstruct monfile { 1260190d29alfred LIST_ENTRY(monfile) monfilelist; 1270190d29alfred fhandle_t filehandle; /* Local access filehandle */ 1280190d29alfred int fd; /* file descriptor: remains open until unlock! */ 1290190d29alfred int refcount; 1300190d29alfred int exclusive; 1310190d29alfred}; 1320190d29alfred 1330190d29alfred/* List of files we monitor */ 1340190d29alfredLIST_HEAD(monfilelist_head, monfile); 1350190d29alfredstruct monfilelist_head monfilelist_head = LIST_HEAD_INITIALIZER(monfilelist_head); 1360190d29alfred 1370190d29alfredstatic int debugdelay = 0; 1380190d29alfred 1390190d29alfredenum nfslock_status { NFS_GRANTED = 0, NFS_GRANTED_DUPLICATE, 1400190d29alfred NFS_DENIED, NFS_DENIED_NOLOCK, 1410190d29alfred NFS_RESERR }; 1420190d29alfred 1430190d29alfredenum hwlock_status { HW_GRANTED = 0, HW_GRANTED_DUPLICATE, 1443896856mjacob HW_DENIED, HW_DENIED_NOLOCK, 1450190d29alfred HW_STALEFH, HW_READONLY, HW_RESERR }; 1460190d29alfred 1470190d29alfredenum partialfilelock_status { PFL_GRANTED=0, PFL_GRANTED_DUPLICATE, PFL_DENIED, 1483896856mjacob PFL_NFSDENIED, PFL_NFSBLOCKED, PFL_NFSDENIED_NOLOCK, PFL_NFSRESERR, 1490190d29alfred PFL_HWDENIED, PFL_HWBLOCKED, PFL_HWDENIED_NOLOCK, PFL_HWRESERR}; 1500190d29alfred 1510190d29alfredenum LFLAGS {LEDGE_LEFT, LEDGE_LBOUNDARY, LEDGE_INSIDE, LEDGE_RBOUNDARY, LEDGE_RIGHT}; 1520190d29alfredenum RFLAGS {REDGE_LEFT, REDGE_LBOUNDARY, REDGE_INSIDE, REDGE_RBOUNDARY, REDGE_RIGHT}; 1530190d29alfred/* XXX: WARNING! I HAVE OVERLOADED THIS STATUS ENUM! SPLIT IT APART INTO TWO */ 1540190d29alfredenum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SPL_RESERR=8}; 1550190d29alfred 1560190d29alfredenum partialfilelock_status lock_partialfilelock(struct file_lock *fl); 1570190d29alfred 1580190d29alfredvoid send_granted(struct file_lock *fl, int opcode); 1590190d29alfredvoid siglock(void); 1600190d29alfredvoid sigunlock(void); 1610190d29alfredvoid monitor_lock_host(const char *hostname); 162edafc1apetervoid unmonitor_lock_host(char *hostname); 1630190d29alfred 1640190d29alfredvoid copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, 1650190d29alfred const bool_t exclusive, struct nlm4_holder *dest); 16631de5a1alfredstruct file_lock * allocate_file_lock(const netobj *lockowner, 1670dd4779mr const netobj *matchcookie, 1680dd4779mr const struct sockaddr *addr, 1690dd4779mr const char *caller_name); 1700190d29alfredvoid deallocate_file_lock(struct file_lock *fl); 17131de5a1alfredvoid fill_file_lock(struct file_lock *fl, const fhandle_t *fh, 1720dd4779mr const bool_t exclusive, const int32_t svid, 1730dd4779mr const u_int64_t offset, const u_int64_t len, 17431de5a1alfred const int state, const int status, const int flags, const int blocking); 1750190d29alfredint regions_overlap(const u_int64_t start1, const u_int64_t len1, 1761b3274astefanf const u_int64_t start2, const u_int64_t len2); 1770190d29alfredenum split_status region_compare(const u_int64_t starte, const u_int64_t lene, 1780190d29alfred const u_int64_t startu, const u_int64_t lenu, 1790190d29alfred u_int64_t *start1, u_int64_t *len1, u_int64_t *start2, u_int64_t *len2); 1800190d29alfredint same_netobj(const netobj *n0, const netobj *n1); 1810190d29alfredint same_filelock_identity(const struct file_lock *fl0, 1820190d29alfred const struct file_lock *fl2); 1830190d29alfred 1840190d29alfredstatic void debuglog(char const *fmt, ...); 1850190d29alfredvoid dump_static_object(const unsigned char* object, const int sizeof_object, 1860190d29alfred unsigned char* hbuff, const int sizeof_hbuff, 1870190d29alfred unsigned char* cbuff, const int sizeof_cbuff); 1880190d29alfredvoid dump_netobj(const struct netobj *nobj); 1890190d29alfredvoid dump_filelock(const struct file_lock *fl); 1900190d29alfredstruct file_lock * get_lock_matching_unlock(const struct file_lock *fl); 1910190d29alfredenum nfslock_status test_nfslock(const struct file_lock *fl, 1920190d29alfred struct file_lock **conflicting_fl); 1930190d29alfredenum nfslock_status lock_nfslock(struct file_lock *fl); 1940190d29alfredenum nfslock_status delete_nfslock(struct file_lock *fl); 1950190d29alfredenum nfslock_status unlock_nfslock(const struct file_lock *fl, 1960190d29alfred struct file_lock **released_lock, struct file_lock **left_lock, 1970190d29alfred struct file_lock **right_lock); 1980190d29alfredenum hwlock_status lock_hwlock(struct file_lock *fl); 1990190d29alfredenum split_status split_nfslock(const struct file_lock *exist_lock, 2000190d29alfred const struct file_lock *unlock_lock, struct file_lock **left_lock, 2010190d29alfred struct file_lock **right_lock); 20204f9658uqsint duplicate_block(struct file_lock *fl); 2030190d29alfredvoid add_blockingfilelock(struct file_lock *fl); 2040190d29alfredenum hwlock_status unlock_hwlock(const struct file_lock *fl); 2050190d29alfredenum hwlock_status test_hwlock(const struct file_lock *fl, 2063896856mjacob struct file_lock **conflicting_fl); 2070190d29alfredvoid remove_blockingfilelock(struct file_lock *fl); 2080190d29alfredvoid clear_blockingfilelock(const char *hostname); 2090190d29alfredvoid retry_blockingfilelocklist(void); 2100190d29alfredenum partialfilelock_status unlock_partialfilelock( 2110190d29alfred const struct file_lock *fl); 2120190d29alfredvoid clear_partialfilelock(const char *hostname); 2130190d29alfredenum partialfilelock_status test_partialfilelock( 2140190d29alfred const struct file_lock *fl, struct file_lock **conflicting_fl); 2150190d29alfredenum nlm_stats do_test(struct file_lock *fl, 2160190d29alfred struct file_lock **conflicting_fl); 2170190d29alfredenum nlm_stats do_unlock(struct file_lock *fl); 2180190d29alfredenum nlm_stats do_lock(struct file_lock *fl); 2190190d29alfredvoid do_clear(const char *hostname); 22080a7e91charniersize_t strnlen(const char *, size_t); 2210190d29alfred 2220190d29alfredvoid 2230190d29alfreddebuglog(char const *fmt, ...) 2240190d29alfred{ 2250190d29alfred va_list ap; 2260190d29alfred 2270190d29alfred if (debug_level < 1) { 2280190d29alfred return; 2290190d29alfred } 2300190d29alfred 2310190d29alfred sleep(debugdelay); 2320190d29alfred 2330190d29alfred va_start(ap, fmt); 2340190d29alfred vsyslog(LOG_DEBUG, fmt, ap); 2350190d29alfred va_end(ap); 2360190d29alfred} 2370190d29alfred 2380190d29alfredvoid 2390190d29alfreddump_static_object(object, size_object, hbuff, size_hbuff, cbuff, size_cbuff) 2400190d29alfred const unsigned char *object; 2410190d29alfred const int size_object; 2420190d29alfred unsigned char *hbuff; 2430190d29alfred const int size_hbuff; 2440190d29alfred unsigned char *cbuff; 2450190d29alfred const int size_cbuff; 2463896856mjacob{ 2470190d29alfred int i, objectsize; 2480190d29alfred 2490190d29alfred if (debug_level < 2) { 2500190d29alfred return; 2510190d29alfred } 2520190d29alfred 2530190d29alfred objectsize = size_object; 2540190d29alfred 2550190d29alfred if (objectsize == 0) { 2560190d29alfred debuglog("object is size 0\n"); 2570190d29alfred } else { 2580190d29alfred if (objectsize > MAXOBJECTSIZE) { 2590190d29alfred debuglog("Object of size %d being clamped" 2600190d29alfred "to size %d\n", objectsize, MAXOBJECTSIZE); 2610190d29alfred objectsize = MAXOBJECTSIZE; 2620190d29alfred } 2633896856mjacob 2640190d29alfred if (hbuff != NULL) { 2650190d29alfred if (size_hbuff < objectsize*2+1) { 2660190d29alfred debuglog("Hbuff not large enough." 2670190d29alfred " Increase size\n"); 2680190d29alfred } else { 2690190d29alfred for(i=0;i<objectsize;i++) { 2700190d29alfred sprintf(hbuff+i*2,"%02x",*(object+i)); 2710190d29alfred } 2720190d29alfred *(hbuff+i*2) = '\0'; 2730190d29alfred } 2740190d29alfred } 2753896856mjacob 2760190d29alfred if (cbuff != NULL) { 2770190d29alfred if (size_cbuff < objectsize+1) { 2780190d29alfred debuglog("Cbuff not large enough." 2790190d29alfred " Increase Size\n"); 2800190d29alfred } 2813896856mjacob 2820190d29alfred for(i=0;i<objectsize;i++) { 2830190d29alfred if (*(object+i) >= 32 && *(object+i) <= 127) { 2840190d29alfred *(cbuff+i) = *(object+i); 2850190d29alfred } else { 2860190d29alfred *(cbuff+i) = '.'; 2870190d29alfred } 2880190d29alfred } 2890190d29alfred *(cbuff+i) = '\0'; 2900190d29alfred } 2910190d29alfred } 2920190d29alfred} 2930190d29alfred 2940190d29alfredvoid 2950190d29alfreddump_netobj(const struct netobj *nobj) 2960190d29alfred{ 2970190d29alfred char hbuff[MAXBUFFERSIZE*2]; 2980190d29alfred char cbuff[MAXBUFFERSIZE]; 2990190d29alfred 3000190d29alfred if (debug_level < 2) { 3010190d29alfred return; 3020190d29alfred } 3030190d29alfred 3040190d29alfred if (nobj == NULL) { 3050190d29alfred debuglog("Null netobj pointer\n"); 3060190d29alfred } 3070190d29alfred else if (nobj->n_len == 0) { 3080190d29alfred debuglog("Size zero netobj\n"); 3090190d29alfred } else { 3100190d29alfred dump_static_object(nobj->n_bytes, nobj->n_len, 3110190d29alfred hbuff, sizeof(hbuff), cbuff, sizeof(cbuff)); 3120190d29alfred debuglog("netobj: len: %d data: %s ::: %s\n", 3130190d29alfred nobj->n_len, hbuff, cbuff); 3140190d29alfred } 3150190d29alfred} 3160190d29alfred 3174548450alfred/* #define DUMP_FILELOCK_VERBOSE */ 3180190d29alfredvoid 3190190d29alfreddump_filelock(const struct file_lock *fl) 3200190d29alfred{ 3214548450alfred#ifdef DUMP_FILELOCK_VERBOSE 3220190d29alfred char hbuff[MAXBUFFERSIZE*2]; 3230190d29alfred char cbuff[MAXBUFFERSIZE]; 3244548450alfred#endif 3250190d29alfred 3260190d29alfred if (debug_level < 2) { 3270190d29alfred return; 3280190d29alfred } 3290190d29alfred 3300190d29alfred if (fl != NULL) { 3310190d29alfred debuglog("Dumping file lock structure @ %p\n", fl); 3320190d29alfred 3334548450alfred#ifdef DUMP_FILELOCK_VERBOSE 3340190d29alfred dump_static_object((unsigned char *)&fl->filehandle, 3350190d29alfred sizeof(fl->filehandle), hbuff, sizeof(hbuff), 3360190d29alfred cbuff, sizeof(cbuff)); 3370190d29alfred debuglog("Filehandle: %8s ::: %8s\n", hbuff, cbuff); 3384548450alfred#endif 3393896856mjacob 3400190d29alfred debuglog("Dumping nlm4_holder:\n" 3410190d29alfred "exc: %x svid: %x offset:len %llx:%llx\n", 3420190d29alfred fl->client.exclusive, fl->client.svid, 3430190d29alfred fl->client.l_offset, fl->client.l_len); 3440190d29alfred 3454548450alfred#ifdef DUMP_FILELOCK_VERBOSE 3460190d29alfred debuglog("Dumping client identity:\n"); 3470190d29alfred dump_netobj(&fl->client.oh); 3483896856mjacob 3490190d29alfred debuglog("Dumping client cookie:\n"); 3500190d29alfred dump_netobj(&fl->client_cookie); 3513896856mjacob 352e143d44kuriyama debuglog("nsm: %d status: %d flags: %d svid: %x" 353e143d44kuriyama " client_name: %s\n", fl->nsm_status, fl->status, 354e143d44kuriyama fl->flags, fl->client.svid, fl->client_name); 3554548450alfred#endif 3560190d29alfred } else { 3570190d29alfred debuglog("NULL file lock structure\n"); 3580190d29alfred } 3590190d29alfred} 3600190d29alfred 3610190d29alfredvoid 3620190d29alfredcopy_nlm4_lock_to_nlm4_holder(src, exclusive, dest) 3630190d29alfred const struct nlm4_lock *src; 3640190d29alfred const bool_t exclusive; 3650190d29alfred struct nlm4_holder *dest; 3660190d29alfred{ 3670190d29alfred 3680190d29alfred dest->exclusive = exclusive; 3690190d29alfred dest->oh.n_len = src->oh.n_len; 3700190d29alfred dest->oh.n_bytes = src->oh.n_bytes; 3710190d29alfred dest->svid = src->svid; 3720190d29alfred dest->l_offset = src->l_offset; 3730190d29alfred dest->l_len = src->l_len; 3740190d29alfred} 3750190d29alfred 3760190d29alfred 3770dd4779mrsize_t 3780dd4779mrstrnlen(const char *s, size_t len) 3790dd4779mr{ 3800dd4779mr size_t n; 3810dd4779mr 3820dd4779mr for (n = 0; s[n] != 0 && n < len; n++) 3830dd4779mr ; 3840dd4779mr return n; 3850dd4779mr} 3860dd4779mr 3870190d29alfred/* 3880190d29alfred * allocate_file_lock: Create a lock with the given parameters 3890190d29alfred */ 3900190d29alfred 3910190d29alfredstruct file_lock * 3920dd4779mrallocate_file_lock(const netobj *lockowner, const netobj *matchcookie, 3930dd4779mr const struct sockaddr *addr, const char *caller_name) 3940190d29alfred{ 3950190d29alfred struct file_lock *newfl; 3960dd4779mr size_t n; 3970190d29alfred 3980dd4779mr /* Beware of rubbish input! */ 3990dd4779mr n = strnlen(caller_name, SM_MAXSTRLEN); 4000dd4779mr if (n == SM_MAXSTRLEN) { 4010dd4779mr return NULL; 4020dd4779mr } 4030dd4779mr 4040dd4779mr newfl = malloc(sizeof(*newfl) - sizeof(newfl->client_name) + n + 1); 4050190d29alfred if (newfl == NULL) { 4060190d29alfred return NULL; 4070190d29alfred } 4080dd4779mr bzero(newfl, sizeof(*newfl) - sizeof(newfl->client_name)); 4090dd4779mr memcpy(newfl->client_name, caller_name, n); 4100dd4779mr newfl->client_name[n] = 0; 4110190d29alfred 4120190d29alfred newfl->client.oh.n_bytes = malloc(lockowner->n_len); 4130190d29alfred if (newfl->client.oh.n_bytes == NULL) { 4140190d29alfred free(newfl); 4150190d29alfred return NULL; 4160190d29alfred } 4170190d29alfred newfl->client.oh.n_len = lockowner->n_len; 4180190d29alfred bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len); 4190190d29alfred 4200190d29alfred newfl->client_cookie.n_bytes = malloc(matchcookie->n_len); 4210190d29alfred if (newfl->client_cookie.n_bytes == NULL) { 4220190d29alfred free(newfl->client.oh.n_bytes); 4230190d29alfred free(newfl); 4240190d29alfred return NULL; 4250190d29alfred } 4260190d29alfred newfl->client_cookie.n_len = matchcookie->n_len; 4270190d29alfred bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len); 4280190d29alfred 4290dd4779mr newfl->addr = malloc(addr->sa_len); 4300dd4779mr if (newfl->addr == NULL) { 4310dd4779mr free(newfl->client_cookie.n_bytes); 4320dd4779mr free(newfl->client.oh.n_bytes); 4330dd4779mr free(newfl); 4340dd4779mr return NULL; 4350dd4779mr } 4360dd4779mr memcpy(newfl->addr, addr, addr->sa_len); 4370dd4779mr 4380190d29alfred return newfl; 4390190d29alfred} 4400190d29alfred 4410190d29alfred/* 4420190d29alfred * file_file_lock: Force creation of a valid file lock 4430190d29alfred */ 4440190d29alfredvoid 44531de5a1alfredfill_file_lock(struct file_lock *fl, const fhandle_t *fh, 4460dd4779mr const bool_t exclusive, const int32_t svid, 4470dd4779mr const u_int64_t offset, const u_int64_t len, 44831de5a1alfred const int state, const int status, const int flags, const int blocking) 4490190d29alfred{ 4500190d29alfred bcopy(fh, &fl->filehandle, sizeof(fhandle_t)); 4510190d29alfred 4520190d29alfred fl->client.exclusive = exclusive; 4530190d29alfred fl->client.svid = svid; 4540190d29alfred fl->client.l_offset = offset; 4550190d29alfred fl->client.l_len = len; 4560190d29alfred 4570190d29alfred fl->nsm_status = state; 4580190d29alfred fl->status = status; 4590190d29alfred fl->flags = flags; 4600190d29alfred fl->blocking = blocking; 4610190d29alfred} 4620190d29alfred 4630190d29alfred/* 4640190d29alfred * deallocate_file_lock: Free all storage associated with a file lock 4650190d29alfred */ 4660190d29alfredvoid 4670190d29alfreddeallocate_file_lock(struct file_lock *fl) 4680190d29alfred{ 4690dd4779mr free(fl->addr); 4700190d29alfred free(fl->client.oh.n_bytes); 4710190d29alfred free(fl->client_cookie.n_bytes); 4720190d29alfred free(fl); 4730190d29alfred} 4740190d29alfred 4750190d29alfred/* 4760190d29alfred * regions_overlap(): This function examines the two provided regions for 4770190d29alfred * overlap. 4780190d29alfred */ 4790190d29alfredint 4800190d29alfredregions_overlap(start1, len1, start2, len2) 4810190d29alfred const u_int64_t start1, len1, start2, len2; 4820190d29alfred{ 4830190d29alfred u_int64_t d1,d2,d3,d4; 4840190d29alfred enum split_status result; 4850190d29alfred 4860190d29alfred debuglog("Entering region overlap with vals: %llu:%llu--%llu:%llu\n", 4870190d29alfred start1, len1, start2, len2); 4880190d29alfred 4890190d29alfred result = region_compare(start1, len1, start2, len2, 4900190d29alfred &d1, &d2, &d3, &d4); 4910190d29alfred 4920190d29alfred debuglog("Exiting region overlap with val: %d\n",result); 4930190d29alfred 4940190d29alfred if (result == SPL_DISJOINT) { 4950190d29alfred return 0; 4960190d29alfred } else { 4970190d29alfred return 1; 4980190d29alfred } 4990190d29alfred} 5000190d29alfred 5010190d29alfred/* 5020190d29alfred * region_compare(): Examine lock regions and split appropriately 5030190d29alfred * 5040190d29alfred * XXX: Fix 64 bit overflow problems 5053896856mjacob * XXX: Check to make sure I got *ALL* the cases. 5060190d29alfred * XXX: This DESPERATELY needs a regression test. 5070190d29alfred */ 5080190d29alfredenum split_status 5090190d29alfredregion_compare(starte, lene, startu, lenu, 5100190d29alfred start1, len1, start2, len2) 5110190d29alfred const u_int64_t starte, lene, startu, lenu; 5120190d29alfred u_int64_t *start1, *len1, *start2, *len2; 5130190d29alfred{ 5140190d29alfred /* 5150190d29alfred * Please pay attention to the sequential exclusions 5160190d29alfred * of the if statements!!! 5170190d29alfred */ 5180190d29alfred enum LFLAGS lflags; 5190190d29alfred enum RFLAGS rflags; 5200190d29alfred enum split_status retval; 5210190d29alfred 5220190d29alfred retval = SPL_DISJOINT; 5230190d29alfred 5240190d29alfred if (lene == 0 && lenu == 0) { 5250190d29alfred /* Examine left edge of locker */ 52680a7e91charnier lflags = LEDGE_INSIDE; 5270190d29alfred if (startu < starte) { 5280190d29alfred lflags = LEDGE_LEFT; 5290190d29alfred } else if (startu == starte) { 5300190d29alfred lflags = LEDGE_LBOUNDARY; 5310190d29alfred } 5320190d29alfred 5330190d29alfred rflags = REDGE_RBOUNDARY; /* Both are infiinite */ 5340190d29alfred 5350190d29alfred if (lflags == LEDGE_INSIDE) { 5360190d29alfred *start1 = starte; 5370190d29alfred *len1 = startu - starte; 5380190d29alfred } 5390190d29alfred 5400190d29alfred if (lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) { 5410190d29alfred retval = SPL_CONTAINED; 5420190d29alfred } else { 5430190d29alfred retval = SPL_LOCK1; 5440190d29alfred } 5450190d29alfred } else if (lene == 0 && lenu != 0) { 5460190d29alfred /* Established lock is infinite */ 5470190d29alfred /* Examine left edge of unlocker */ 54880a7e91charnier lflags = LEDGE_INSIDE; 5490190d29alfred if (startu < starte) { 5500190d29alfred lflags = LEDGE_LEFT; 5510190d29alfred } else if (startu == starte) { 5520190d29alfred lflags = LEDGE_LBOUNDARY; 5530190d29alfred } 5540190d29alfred 5550190d29alfred /* Examine right edge of unlocker */ 5560190d29alfred if (startu + lenu < starte) { 5570190d29alfred /* Right edge of unlocker left of established lock */ 5580190d29alfred rflags = REDGE_LEFT; 5590190d29alfred return SPL_DISJOINT; 5600190d29alfred } else if (startu + lenu == starte) { 5610190d29alfred /* Right edge of unlocker on start of established lock */ 5620190d29alfred rflags = REDGE_LBOUNDARY; 5630190d29alfred return SPL_DISJOINT; 5640190d29alfred } else { /* Infinifty is right of finity */ 5650190d29alfred /* Right edge of unlocker inside established lock */ 5660190d29alfred rflags = REDGE_INSIDE; 5670190d29alfred } 5680190d29alfred 5690190d29alfred if (lflags == LEDGE_INSIDE) { 5700190d29alfred *start1 = starte; 5710190d29alfred *len1 = startu - starte; 5720190d29alfred retval |= SPL_LOCK1; 5730190d29alfred } 5740190d29alfred 5750190d29alfred if (rflags == REDGE_INSIDE) { 5760190d29alfred /* Create right lock */ 5770190d29alfred *start2 = startu+lenu; 5780190d29alfred *len2 = 0; 5790190d29alfred retval |= SPL_LOCK2; 5800190d29alfred } 5810190d29alfred } else if (lene != 0 && lenu == 0) { 5820190d29alfred /* Unlocker is infinite */ 5830190d29alfred /* Examine left edge of unlocker */ 58480a7e91charnier lflags = LEDGE_RIGHT; 5850190d29alfred if (startu < starte) { 5860190d29alfred lflags = LEDGE_LEFT; 5870190d29alfred retval = SPL_CONTAINED; 5880190d29alfred return retval; 5890190d29alfred } else if (startu == starte) { 5900190d29alfred lflags = LEDGE_LBOUNDARY; 5910190d29alfred retval = SPL_CONTAINED; 5920190d29alfred return retval; 5930190d29alfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 5940190d29alfred lflags = LEDGE_INSIDE; 5950190d29alfred } else if (startu == starte + lene - 1) { 5960190d29alfred lflags = LEDGE_RBOUNDARY; 5970190d29alfred } else { /* startu > starte + lene -1 */ 5980190d29alfred lflags = LEDGE_RIGHT; 5990190d29alfred return SPL_DISJOINT; 6000190d29alfred } 6010190d29alfred 6020190d29alfred rflags = REDGE_RIGHT; /* Infinity is right of finity */ 6030190d29alfred 6040190d29alfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 6050190d29alfred *start1 = starte; 6060190d29alfred *len1 = startu - starte; 6070190d29alfred retval |= SPL_LOCK1; 6080190d29alfred return retval; 6090190d29alfred } 6100190d29alfred } else { 6110190d29alfred /* Both locks are finite */ 6120190d29alfred 6130190d29alfred /* Examine left edge of unlocker */ 61480a7e91charnier lflags = LEDGE_RIGHT; 6150190d29alfred if (startu < starte) { 6160190d29alfred lflags = LEDGE_LEFT; 6170190d29alfred } else if (startu == starte) { 6180190d29alfred lflags = LEDGE_LBOUNDARY; 6190190d29alfred } else if ((startu > starte) && (startu < starte + lene - 1)) { 6200190d29alfred lflags = LEDGE_INSIDE; 6210190d29alfred } else if (startu == starte + lene - 1) { 6220190d29alfred lflags = LEDGE_RBOUNDARY; 6230190d29alfred } else { /* startu > starte + lene -1 */ 6240190d29alfred lflags = LEDGE_RIGHT; 6250190d29alfred return SPL_DISJOINT; 6260190d29alfred } 6270190d29alfred 6280190d29alfred /* Examine right edge of unlocker */ 6290190d29alfred if (startu + lenu < starte) { 6300190d29alfred /* Right edge of unlocker left of established lock */ 6310190d29alfred rflags = REDGE_LEFT; 6320190d29alfred return SPL_DISJOINT; 6330190d29alfred } else if (startu + lenu == starte) { 6340190d29alfred /* Right edge of unlocker on start of established lock */ 6350190d29alfred rflags = REDGE_LBOUNDARY; 6360190d29alfred return SPL_DISJOINT; 6370190d29alfred } else if (startu + lenu < starte + lene) { 6380190d29alfred /* Right edge of unlocker inside established lock */ 6390190d29alfred rflags = REDGE_INSIDE; 6400190d29alfred } else if (startu + lenu == starte + lene) { 6410190d29alfred /* Right edge of unlocker on right edge of established lock */ 6420190d29alfred rflags = REDGE_RBOUNDARY; 6430190d29alfred } else { /* startu + lenu > starte + lene */ 6440190d29alfred /* Right edge of unlocker is right of established lock */ 6450190d29alfred rflags = REDGE_RIGHT; 6460190d29alfred } 6470190d29alfred 6480190d29alfred if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 6490190d29alfred /* Create left lock */ 6500190d29alfred *start1 = starte; 6510190d29alfred *len1 = (startu - starte); 6520190d29alfred retval |= SPL_LOCK1; 6530190d29alfred } 6540190d29alfred 6550190d29alfred if (rflags == REDGE_INSIDE) { 6560190d29alfred /* Create right lock */ 6570190d29alfred *start2 = startu+lenu; 6580190d29alfred *len2 = starte+lene-(startu+lenu); 6590190d29alfred retval |= SPL_LOCK2; 6600190d29alfred } 6610190d29alfred 6620190d29alfred if ((lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) && 6630190d29alfred (rflags == REDGE_RBOUNDARY || rflags == REDGE_RIGHT)) { 6640190d29alfred retval = SPL_CONTAINED; 6650190d29alfred } 6660190d29alfred } 6670190d29alfred return retval; 6680190d29alfred} 6690190d29alfred 6700190d29alfred/* 6710190d29alfred * same_netobj: Compares the apprpriate bits of a netobj for identity 6720190d29alfred */ 6730190d29alfredint 6740190d29alfredsame_netobj(const netobj *n0, const netobj *n1) 6750190d29alfred{ 6760190d29alfred int retval; 6770190d29alfred 6780190d29alfred retval = 0; 6790190d29alfred 6800190d29alfred debuglog("Entering netobj identity check\n"); 6810190d29alfred 6820190d29alfred if (n0->n_len == n1->n_len) { 6830190d29alfred debuglog("Preliminary length check passed\n"); 6840190d29alfred retval = !bcmp(n0->n_bytes, n1->n_bytes, n0->n_len); 6850190d29alfred debuglog("netobj %smatch\n", retval ? "" : "mis"); 6860190d29alfred } 6873896856mjacob 6880190d29alfred return (retval); 6890190d29alfred} 6900190d29alfred 6910190d29alfred/* 6920190d29alfred * same_filelock_identity: Compares the appropriate bits of a file_lock 6930190d29alfred */ 6940190d29alfredint 6950190d29alfredsame_filelock_identity(fl0, fl1) 6960190d29alfred const struct file_lock *fl0, *fl1; 6970190d29alfred{ 6980190d29alfred int retval; 6990190d29alfred 7000190d29alfred retval = 0; 7010190d29alfred 7020190d29alfred debuglog("Checking filelock identity\n"); 7030190d29alfred 7040190d29alfred /* 7050190d29alfred * Check process ids and host information. 7060190d29alfred */ 7070190d29alfred retval = (fl0->client.svid == fl1->client.svid && 7080190d29alfred same_netobj(&(fl0->client.oh), &(fl1->client.oh))); 7090190d29alfred 7100190d29alfred debuglog("Exiting checking filelock identity: retval: %d\n",retval); 7110190d29alfred 7120190d29alfred return (retval); 7130190d29alfred} 7140190d29alfred 7150190d29alfred/* 7160190d29alfred * Below here are routines associated with manipulating the NFS 7170190d29alfred * lock list. 7180190d29alfred */ 7190190d29alfred 7200190d29alfred/* 7210190d29alfred * get_lock_matching_unlock: Return a lock which matches the given unlock lock 7220190d29alfred * or NULL otehrwise 7230190d29alfred * XXX: It is a shame that this duplicates so much code from test_nfslock. 7240190d29alfred */ 7250190d29alfredstruct file_lock * 7260190d29alfredget_lock_matching_unlock(const struct file_lock *fl) 7270190d29alfred{ 7280190d29alfred struct file_lock *ifl; /* Iterator */ 7290190d29alfred 730e143d44kuriyama debuglog("Entering get_lock_matching_unlock\n"); 7310190d29alfred debuglog("********Dump of fl*****************\n"); 7320190d29alfred dump_filelock(fl); 7330190d29alfred 7340190d29alfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 7350190d29alfred debuglog("Pointer to file lock: %p\n",ifl); 7360190d29alfred 7370190d29alfred debuglog("****Dump of ifl****\n"); 7380190d29alfred dump_filelock(ifl); 7390190d29alfred debuglog("*******************\n"); 7400190d29alfred 7410190d29alfred /* 7420190d29alfred * XXX: It is conceivable that someone could use the NLM RPC 7430190d29alfred * system to directly access filehandles. This may be a 7440190d29alfred * security hazard as the filehandle code may bypass normal 7450190d29alfred * file access controls 7460190d29alfred */ 7470190d29alfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 7480190d29alfred continue; 7490190d29alfred 750e143d44kuriyama debuglog("get_lock_matching_unlock: Filehandles match, " 7510190d29alfred "checking regions\n"); 7520190d29alfred 7530190d29alfred /* Filehandles match, check for region overlap */ 7540190d29alfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 7550190d29alfred ifl->client.l_offset, ifl->client.l_len)) 7560190d29alfred continue; 7573896856mjacob 758e143d44kuriyama debuglog("get_lock_matching_unlock: Region overlap" 7590190d29alfred " found %llu : %llu -- %llu : %llu\n", 7600190d29alfred fl->client.l_offset,fl->client.l_len, 7610190d29alfred ifl->client.l_offset,ifl->client.l_len); 7620190d29alfred 7630190d29alfred /* Regions overlap, check the identity */ 7640190d29alfred if (!same_filelock_identity(fl,ifl)) 7650190d29alfred continue; 7660190d29alfred 767e143d44kuriyama debuglog("get_lock_matching_unlock: Duplicate lock id. Granting\n"); 7680190d29alfred return (ifl); 7690190d29alfred } 7700190d29alfred 771e143d44kuriyama debuglog("Exiting bet_lock_matching_unlock\n"); 7720190d29alfred 7730190d29alfred return (NULL); 7740190d29alfred} 7750190d29alfred 7760190d29alfred/* 7770190d29alfred * test_nfslock: check for NFS lock in lock list 7780190d29alfred * 7790190d29alfred * This routine makes the following assumptions: 7800190d29alfred * 1) Nothing will adjust the lock list during a lookup 7810190d29alfred * 7820190d29alfred * This routine has an intersting quirk which bit me hard. 7830190d29alfred * The conflicting_fl is the pointer to the conflicting lock. 7840190d29alfred * However, to modify the "*pointer* to the conflicting lock" rather 7850190d29alfred * that the "conflicting lock itself" one must pass in a "pointer to 7860190d29alfred * the pointer of the conflicting lock". Gross. 7870190d29alfred */ 7880190d29alfred 7890190d29alfredenum nfslock_status 7900190d29alfredtest_nfslock(const struct file_lock *fl, struct file_lock **conflicting_fl) 7910190d29alfred{ 7920190d29alfred struct file_lock *ifl; /* Iterator */ 7930190d29alfred enum nfslock_status retval; 7940190d29alfred 7950190d29alfred debuglog("Entering test_nfslock\n"); 7960190d29alfred 7970190d29alfred retval = NFS_GRANTED; 7980190d29alfred (*conflicting_fl) = NULL; 7990190d29alfred 8000190d29alfred debuglog("Entering lock search loop\n"); 8010190d29alfred 8020190d29alfred debuglog("***********************************\n"); 8030190d29alfred debuglog("Dumping match filelock\n"); 8040190d29alfred debuglog("***********************************\n"); 8050190d29alfred dump_filelock(fl); 8060190d29alfred debuglog("***********************************\n"); 8070190d29alfred 8080190d29alfred LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 8090190d29alfred if (retval == NFS_DENIED) 8100190d29alfred break; 8110190d29alfred 8120190d29alfred debuglog("Top of lock loop\n"); 8130190d29alfred debuglog("Pointer to file lock: %p\n",ifl); 8143896856mjacob 8150190d29alfred debuglog("***********************************\n"); 8160190d29alfred debuglog("Dumping test filelock\n"); 8170190d29alfred debuglog("***********************************\n"); 8180190d29alfred dump_filelock(ifl); 8190190d29alfred debuglog("***********************************\n"); 8200190d29alfred 8210190d29alfred /* 8220190d29alfred * XXX: It is conceivable that someone could use the NLM RPC 8230190d29alfred * system to directly access filehandles. This may be a 8240190d29alfred * security hazard as the filehandle code may bypass normal 8250190d29alfred * file access controls 8260190d29alfred */ 8270190d29alfred if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 8280190d29alfred continue; 8290190d29alfred 8300190d29alfred debuglog("test_nfslock: filehandle match found\n"); 8310190d29alfred 8320190d29alfred /* Filehandles match, check for region overlap */ 8330190d29alfred if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 8340190d29alfred ifl->client.l_offset, ifl->client.l_len)) 8350190d29alfred continue; 8360190d29alfred 8370190d29alfred debuglog("test_nfslock: Region overlap found" 8380190d29alfred " %llu : %llu -- %llu : %llu\n", 8390190d29alfred fl->client.l_offset,fl->client.l_len, 8400190d29alfred ifl->client.l_offset,ifl->client.l_len); 8410190d29alfred 8420190d29alfred /* Regions overlap, check the exclusivity */ 8430190d29alfred if (!(fl->client.exclusive || ifl->client.exclusive)) 8440190d29alfred continue; 8453896856mjacob 8460190d29alfred debuglog("test_nfslock: Exclusivity failure: %d %d\n", 8470190d29alfred fl->client.exclusive, 8480190d29alfred ifl->client.exclusive); 8490190d29alfred 8500190d29alfred if (same_filelock_identity(fl,ifl)) { 8510190d29alfred debuglog("test_nfslock: Duplicate id. Granting\n"); 8520190d29alfred (*conflicting_fl) = ifl; 8530190d29alfred retval = NFS_GRANTED_DUPLICATE; 8540190d29alfred } else { 8550190d29alfred /* locking attempt fails */ 8560190d29alfred debuglog("test_nfslock: Lock attempt failed\n"); 8570190d29alfred debuglog("Desired lock\n"); 8580190d29alfred dump_filelock(fl); 8590190d29alfred debuglog("Conflicting lock\n"); 8600190d29alfred dump_filelock(ifl); 8610190d29alfred (*conflicting_fl) = ifl; 8620190d29alfred retval = NFS_DENIED; 8630190d29alfred } 8640190d29alfred } 8653896856mjacob 8660190d29alfred debuglog("Dumping file locks\n"); 8670190d29alfred debuglog("Exiting test_nfslock\n"); 8683896856mjacob 8690190d29alfred return (retval); 8700190d29alfred} 8710190d29alfred 8720190d29alfred/* 8730190d29alfred * lock_nfslock: attempt to create a lock in the NFS lock list 8740190d29alfred * 8750190d29alfred * This routine tests whether the lock will be granted and then adds 8760190d29alfred * the entry to the lock list if so. 8773896856mjacob * 8780190d29alfred * Argument fl gets modified as its list housekeeping entries get modified 8790190d29alfred * upon insertion into the NFS lock list 8800190d29alfred * 8810190d29alfred * This routine makes several assumptions: 8820190d29alfred * 1) It is perfectly happy to grant a duplicate lock from the same pid. 8830190d29alfred * While this seems to be intuitively wrong, it is required for proper 8840190d29alfred * Posix semantics during unlock. It is absolutely imperative to not 8850190d29alfred * unlock the main lock before the two child locks are established. Thus, 88656640efeadler * one has to be able to create duplicate locks over an existing lock 8870190d29alfred * 2) It currently accepts duplicate locks from the same id,pid 8880190d29alfred */ 8890190d29alfred 8900190d29alfredenum nfslock_status 8910190d29alfredlock_nfslock(struct file_lock *fl) 8920190d29alfred{ 8930190d29alfred enum nfslock_status retval; 8940190d29alfred struct file_lock *dummy_fl; 8950190d29alfred 8960190d29alfred dummy_fl = NULL; 8970190d29alfred 8980190d29alfred debuglog("Entering lock_nfslock...\n"); 8990190d29alfred 9000190d29alfred retval = test_nfslock(fl,&dummy_fl); 9010190d29alfred 9020190d29alfred if (retval == NFS_GRANTED || retval == NFS_GRANTED_DUPLICATE) { 9030190d29alfred debuglog("Inserting lock...\n"); 9040190d29alfred dump_filelock(fl); 9050190d29alfred LIST_INSERT_HEAD(&nfslocklist_head, fl, nfslocklist); 9060190d29alfred } 9070190d29alfred 9080190d29alfred debuglog("Exiting lock_nfslock...\n"); 9090190d29alfred 9100190d29alfred return (retval); 9110190d29alfred} 9120190d29alfred 9130190d29alfred/* 9140190d29alfred * delete_nfslock: delete an NFS lock list entry 9150190d29alfred * 9160190d29alfred * This routine is used to delete a lock out of the NFS lock list 9170190d29alfred * without regard to status, underlying locks, regions or anything else 9180190d29alfred * 9190190d29alfred * Note that this routine *does not deallocate memory* of the lock. 9200190d29alfred * It just disconnects it from the list. The lock can then be used 9210190d29alfred * by other routines without fear of trashing the list. 9220190d29alfred */ 9230190d29alfred 9240190d29alfredenum nfslock_status 9250190d29alfreddelete_nfslock(struct file_lock *fl) 9260190d29alfred{ 9270190d29alfred 9280190d29alfred LIST_REMOVE(fl, nfslocklist); 9290190d29alfred 9300190d29alfred return (NFS_GRANTED); 9310190d29alfred} 9320190d29alfred 9330190d29alfredenum split_status 9340190d29alfredsplit_nfslock(exist_lock, unlock_lock, left_lock, right_lock) 9350190d29alfred const struct file_lock *exist_lock, *unlock_lock; 9360190d29alfred struct file_lock **left_lock, **right_lock; 9370190d29alfred{ 9380190d29alfred u_int64_t start1, len1, start2, len2; 9390190d29alfred enum split_status spstatus; 9400190d29alfred 9410190d29alfred spstatus = region_compare(exist_lock->client.l_offset, exist_lock->client.l_len, 9420190d29alfred unlock_lock->client.l_offset, unlock_lock->client.l_len, 9430190d29alfred &start1, &len1, &start2, &len2); 9440190d29alfred 9450190d29alfred if ((spstatus & SPL_LOCK1) != 0) { 9460dd4779mr *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 9470190d29alfred if (*left_lock == NULL) { 9480190d29alfred debuglog("Unable to allocate resource for split 1\n"); 9490190d29alfred return SPL_RESERR; 9500190d29alfred } 9510190d29alfred 95231de5a1alfred fill_file_lock(*left_lock, &exist_lock->filehandle, 9530190d29alfred exist_lock->client.exclusive, exist_lock->client.svid, 9540190d29alfred start1, len1, 9550dd4779mr exist_lock->nsm_status, 9560190d29alfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 9570190d29alfred } 9580190d29alfred 9590190d29alfred if ((spstatus & SPL_LOCK2) != 0) { 9600dd4779mr *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 9610190d29alfred if (*right_lock == NULL) { 9620190d29alfred debuglog("Unable to allocate resource for split 1\n"); 9630190d29alfred if (*left_lock != NULL) { 9640190d29alfred deallocate_file_lock(*left_lock); 9650190d29alfred } 9660190d29alfred return SPL_RESERR; 9670190d29alfred } 9680190d29alfred 96931de5a1alfred fill_file_lock(*right_lock, &exist_lock->filehandle, 9700190d29alfred exist_lock->client.exclusive, exist_lock->client.svid, 9710190d29alfred start2, len2, 9720dd4779mr exist_lock->nsm_status, 9730190d29alfred exist_lock->status, exist_lock->flags, exist_lock->blocking); 9740190d29alfred } 9750190d29alfred 9760190d29alfred return spstatus; 9770190d29alfred} 9780190d29alfred 9790190d29alfredenum nfslock_status 9800190d29alfredunlock_nfslock(fl, released_lock, left_lock, right_lock) 9810190d29alfred const struct file_lock *fl; 9820190d29alfred struct file_lock **released_lock; 9830190d29alfred struct file_lock **left_lock; 9840190d29alfred struct file_lock **right_lock; 9850190d29alfred{ 9860190d29alfred struct file_lock *mfl; /* Matching file lock */ 9870190d29alfred enum nfslock_status retval; 9880190d29alfred enum split_status spstatus; 9890190d29alfred 9900190d29alfred debuglog("Entering unlock_nfslock\n"); 9910190d29alfred 9920190d29alfred *released_lock = NULL; 9930190d29alfred *left_lock = NULL; 9940190d29alfred *right_lock = NULL; 9950190d29alfred 9960190d29alfred retval = NFS_DENIED_NOLOCK; 9970190d29alfred 9980dd4779mr debuglog("Attempting to match lock...\n"); 9990190d29alfred mfl = get_lock_matching_unlock(fl); 10000190d29alfred 10010190d29alfred if (mfl != NULL) { 10020190d29alfred debuglog("Unlock matched. Querying for split\n"); 10030190d29alfred 10040190d29alfred spstatus = split_nfslock(mfl, fl, left_lock, right_lock); 10050190d29alfred 10060190d29alfred debuglog("Split returned %d %p %p %p %p\n",spstatus,mfl,fl,*left_lock,*right_lock); 10070190d29alfred debuglog("********Split dumps********"); 10080190d29alfred dump_filelock(mfl); 10090190d29alfred dump_filelock(fl); 10100190d29alfred dump_filelock(*left_lock); 10110190d29alfred dump_filelock(*right_lock); 10120190d29alfred debuglog("********End Split dumps********"); 10130190d29alfred 10140190d29alfred if (spstatus == SPL_RESERR) { 10150190d29alfred if (*left_lock != NULL) { 10160190d29alfred deallocate_file_lock(*left_lock); 10170190d29alfred *left_lock = NULL; 10180190d29alfred } 10190190d29alfred 10200190d29alfred if (*right_lock != NULL) { 10210190d29alfred deallocate_file_lock(*right_lock); 10220190d29alfred *right_lock = NULL; 10230190d29alfred } 10240190d29alfred 10250190d29alfred return NFS_RESERR; 10260190d29alfred } 10270190d29alfred 10280190d29alfred /* Insert new locks from split if required */ 10290190d29alfred if (*left_lock != NULL) { 10300190d29alfred debuglog("Split left activated\n"); 10310190d29alfred LIST_INSERT_HEAD(&nfslocklist_head, *left_lock, nfslocklist); 10320190d29alfred } 10330190d29alfred 10340190d29alfred if (*right_lock != NULL) { 10350190d29alfred debuglog("Split right activated\n"); 1036