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