194047d49SGordon Ross /*
294047d49SGordon Ross  * This file and its contents are supplied under the terms of the
394047d49SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
494047d49SGordon Ross  * You may only use this file in accordance with the terms of version
594047d49SGordon Ross  * 1.0 of the CDDL.
694047d49SGordon Ross  *
794047d49SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
894047d49SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
994047d49SGordon Ross  * http://www.illumos.org/license/CDDL.
1094047d49SGordon Ross  */
1194047d49SGordon Ross 
1294047d49SGordon Ross /*
13e8754e84SGordon Ross  * Copyright 2020 Tintri by DDN, Inc.  All rights reserved.
14da90d5b8SJohn Levon  * Copyright 2019 Joyent, Inc.
154d723c3fSGordon Ross  * Copyright 2022 RackTop Systems, Inc.
1694047d49SGordon Ross  */
1794047d49SGordon Ross 
1894047d49SGordon Ross /*
1994047d49SGordon Ross  * Test & debug program for oplocks
2094047d49SGordon Ross  *
2194047d49SGordon Ross  * This implements a simple command reader which accepts
2294047d49SGordon Ross  * commands to simulate oplock events, and prints the
2394047d49SGordon Ross  * state changes and actions that would happen after
2494047d49SGordon Ross  * each event.
2594047d49SGordon Ross  */
2694047d49SGordon Ross 
2794047d49SGordon Ross #include <sys/types.h>
2894047d49SGordon Ross #include <sys/debug.h>
2994047d49SGordon Ross #include <sys/stddef.h>
3094047d49SGordon Ross #include <stdio.h>
3194047d49SGordon Ross #include <stdlib.h>
3294047d49SGordon Ross #include <string.h>
3394047d49SGordon Ross #include <strings.h>
3494047d49SGordon Ross #include <unistd.h>
3594047d49SGordon Ross 
3694047d49SGordon Ross #include <smbsrv/smb_kproto.h>
3794047d49SGordon Ross #include <smbsrv/smb_oplock.h>
3894047d49SGordon Ross 
39*7f6a299eSGordon Ross extern const char *xlate_nt_status(uint32_t);
40*7f6a299eSGordon Ross 
4194047d49SGordon Ross #define	OPLOCK_CACHE_RWH	(READ_CACHING | HANDLE_CACHING | WRITE_CACHING)
4294047d49SGordon Ross #define	OPLOCK_TYPE	(LEVEL_TWO_OPLOCK | LEVEL_ONE_OPLOCK |\
4394047d49SGordon Ross 			BATCH_OPLOCK | OPLOCK_LEVEL_GRANULAR)
4494047d49SGordon Ross 
4594047d49SGordon Ross #define	MAXFID 10
4694047d49SGordon Ross 
4794047d49SGordon Ross smb_node_t root_node, test_node;
4894047d49SGordon Ross smb_ofile_t  ofile_array[MAXFID];
4994047d49SGordon Ross smb_request_t test_sr;
5094047d49SGordon Ross uint32_t last_ind_break_level;
5194047d49SGordon Ross char cmdbuf[100];
5294047d49SGordon Ross 
53*7f6a299eSGordon Ross static void run_ind_break_in_ack(smb_ofile_t *);
5494047d49SGordon Ross 
5594047d49SGordon Ross #define	BIT_DEF(name) { name, #name }
5694047d49SGordon Ross 
5794047d49SGordon Ross struct bit_defs {
5894047d49SGordon Ross 	uint32_t mask;
5994047d49SGordon Ross 	const char *name;
6094047d49SGordon Ross } state_bits[] = {
6194047d49SGordon Ross 	BIT_DEF(NO_OPLOCK),
6294047d49SGordon Ross 	BIT_DEF(BREAK_TO_NO_CACHING),
6394047d49SGordon Ross 	BIT_DEF(BREAK_TO_WRITE_CACHING),
6494047d49SGordon Ross 	BIT_DEF(BREAK_TO_HANDLE_CACHING),
6594047d49SGordon Ross 	BIT_DEF(BREAK_TO_READ_CACHING),
6694047d49SGordon Ross 	BIT_DEF(BREAK_TO_TWO_TO_NONE),
6794047d49SGordon Ross 	BIT_DEF(BREAK_TO_NONE),
6894047d49SGordon Ross 	BIT_DEF(BREAK_TO_TWO),
6994047d49SGordon Ross 	BIT_DEF(BATCH_OPLOCK),
7094047d49SGordon Ross 	BIT_DEF(LEVEL_ONE_OPLOCK),
7194047d49SGordon Ross 	BIT_DEF(LEVEL_TWO_OPLOCK),
7294047d49SGordon Ross 	BIT_DEF(MIXED_R_AND_RH),
7394047d49SGordon Ross 	BIT_DEF(EXCLUSIVE),
7494047d49SGordon Ross 	BIT_DEF(WRITE_CACHING),
7594047d49SGordon Ross 	BIT_DEF(HANDLE_CACHING),
7694047d49SGordon Ross 	BIT_DEF(READ_CACHING),
7794047d49SGordon Ross 	{ 0, NULL }
7894047d49SGordon Ross };
7994047d49SGordon Ross 
8094047d49SGordon Ross /*
8194047d49SGordon Ross  * Helper to print flags fields
8294047d49SGordon Ross  */
8394047d49SGordon Ross static void
print_bits32(char * label,struct bit_defs * bit,uint32_t state)8494047d49SGordon Ross print_bits32(char *label, struct bit_defs *bit, uint32_t state)
8594047d49SGordon Ross {
8694047d49SGordon Ross 	printf("%s0x%x (", label, state);
8794047d49SGordon Ross 	while (bit->mask != 0) {
8894047d49SGordon Ross 		if ((state & bit->mask) != 0)
8994047d49SGordon Ross 			printf(" %s", bit->name);
9094047d49SGordon Ross 		bit++;
9194047d49SGordon Ross 	}
9294047d49SGordon Ross 	printf(" )\n");
9394047d49SGordon Ross }
9494047d49SGordon Ross 
9594047d49SGordon Ross /*
9694047d49SGordon Ross  * Command language:
9794047d49SGordon Ross  *
9894047d49SGordon Ross  */
9994047d49SGordon Ross const char helpstr[] = "Commands:\n"
10094047d49SGordon Ross 	"help\t\tList commands\n"
10194047d49SGordon Ross 	"show\t\tShow OpLock state etc.\n"
10294047d49SGordon Ross 	"open FID\n"
10394047d49SGordon Ross 	"close FID\n"
10494047d49SGordon Ross 	"req FID [OplockLevel]\n"
10594047d49SGordon Ross 	"ack FID [OplockLevel]\n"
10694047d49SGordon Ross 	"brk-parent FID\n"
10794047d49SGordon Ross 	"brk-open [OverWrite]\n"
10894047d49SGordon Ross 	"brk-handle FID\n"
10994047d49SGordon Ross 	"brk-read FID\n"
11094047d49SGordon Ross 	"brk-write FID\n"
11194047d49SGordon Ross 	"brk-setinfo FID [InfoClass]\n"
11294047d49SGordon Ross 	"move FID1 FID2\n"
11394047d49SGordon Ross 	"waiters FID [count]\n";
11494047d49SGordon Ross 
11594047d49SGordon Ross /*
11694047d49SGordon Ross  * Command handlers
11794047d49SGordon Ross  */
11894047d49SGordon Ross 
11994047d49SGordon Ross static void
do_show(void)12094047d49SGordon Ross do_show(void)
12194047d49SGordon Ross {
12294047d49SGordon Ross 	smb_node_t *node = &test_node;
12394047d49SGordon Ross 	smb_oplock_t *ol = &node->n_oplock;
12494047d49SGordon Ross 	uint32_t state = ol->ol_state;
12594047d49SGordon Ross 	smb_ofile_t *f;
12694047d49SGordon Ross 
12794047d49SGordon Ross 	print_bits32(" ol_state=", state_bits, state);
12894047d49SGordon Ross 
12994047d49SGordon Ross 	if (ol->excl_open != NULL)
13094047d49SGordon Ross 		printf(" Excl=Y (FID=%d)", ol->excl_open->f_fid);
13194047d49SGordon Ross 	else
13294047d49SGordon Ross 		printf(" Excl=n");
13394047d49SGordon Ross 	printf(" cnt_II=%d cnt_R=%d cnt_RH=%d cnt_RHBQ=%d\n",
13494047d49SGordon Ross 	    ol->cnt_II, ol->cnt_R, ol->cnt_RH, ol->cnt_RHBQ);
13594047d49SGordon Ross 
13694047d49SGordon Ross 	printf(" ofile_cnt=%d\n", node->n_ofile_list.ll_count);
13794047d49SGordon Ross 	FOREACH_NODE_OFILE(node, f) {
13894047d49SGordon Ross 		smb_oplock_grant_t *og = &f->f_oplock;
139*7f6a299eSGordon Ross 		printf("  fid=%d Lease=%s State=0x%x",
14094047d49SGordon Ross 		    f->f_fid,
14194047d49SGordon Ross 		    f->TargetOplockKey,	/* lease */
142*7f6a299eSGordon Ross 		    og->og_state);
143*7f6a299eSGordon Ross 		if (og->og_breaking)
144*7f6a299eSGordon Ross 			printf(" BreakTo=0x%x", og->og_breakto);
145*7f6a299eSGordon Ross 		printf(" Excl=%s onlist:",
146*7f6a299eSGordon Ross 		    (ol->excl_open == f) ? "Y" : "N");
147*7f6a299eSGordon Ross 		if (og->onlist_II)
148*7f6a299eSGordon Ross 			printf(" II");
149*7f6a299eSGordon Ross 		if (og->onlist_R)
150*7f6a299eSGordon Ross 			printf(" R");
151*7f6a299eSGordon Ross 		if (og->onlist_RH)
152*7f6a299eSGordon Ross 			printf(" RH");
15394047d49SGordon Ross 		if (og->onlist_RHBQ) {
15494047d49SGordon Ross 			printf(" RHBQ(to %s)",
15594047d49SGordon Ross 			    og->BreakingToRead ?
15694047d49SGordon Ross 			    "read" : "none");
15794047d49SGordon Ross 		}
15894047d49SGordon Ross 		printf("\n");
15994047d49SGordon Ross 	}
16094047d49SGordon Ross }
16194047d49SGordon Ross 
16294047d49SGordon Ross static void
do_open(int fid,char * arg2)16394047d49SGordon Ross do_open(int fid, char *arg2)
16494047d49SGordon Ross {
16594047d49SGordon Ross 	smb_node_t *node = &test_node;
16694047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
16794047d49SGordon Ross 
16894047d49SGordon Ross 	/*
16994047d49SGordon Ross 	 * Simulate an open (minimal init)
17094047d49SGordon Ross 	 */
17194047d49SGordon Ross 	if (ofile->f_refcnt) {
17294047d49SGordon Ross 		printf("open fid %d already opened\n");
17394047d49SGordon Ross 		return;
17494047d49SGordon Ross 	}
17594047d49SGordon Ross 
176da90d5b8SJohn Levon 	if (arg2 != NULL) {
177da90d5b8SJohn Levon 		(void) strlcpy((char *)ofile->TargetOplockKey, arg2,
17894047d49SGordon Ross 		    SMB_LEASE_KEY_SZ);
179da90d5b8SJohn Levon 	}
18094047d49SGordon Ross 
18194047d49SGordon Ross 	ofile->f_refcnt++;
18294047d49SGordon Ross 	node->n_open_count++;
18394047d49SGordon Ross 	smb_llist_insert_tail(&node->n_ofile_list, ofile);
18494047d49SGordon Ross 	printf(" open %d OK\n", fid);
18594047d49SGordon Ross }
18694047d49SGordon Ross 
18794047d49SGordon Ross static void
do_close(int fid)18894047d49SGordon Ross do_close(int fid)
18994047d49SGordon Ross {
19094047d49SGordon Ross 	smb_node_t *node = &test_node;
19194047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
19294047d49SGordon Ross 
19394047d49SGordon Ross 	/*
19494047d49SGordon Ross 	 * Simulate an close
19594047d49SGordon Ross 	 */
19694047d49SGordon Ross 	if (ofile->f_refcnt <= 0) {
19794047d49SGordon Ross 		printf(" close fid %d already closed\n");
19894047d49SGordon Ross 		return;
19994047d49SGordon Ross 	}
2004d723c3fSGordon Ross 
2014d723c3fSGordon Ross 	smb_llist_enter(&node->n_ofile_list, RW_READER);
2024d723c3fSGordon Ross 	mutex_enter(&node->n_oplock.ol_mutex);
2034d723c3fSGordon Ross 
20494047d49SGordon Ross 	smb_oplock_break_CLOSE(ofile->f_node, ofile);
20594047d49SGordon Ross 
20694047d49SGordon Ross 	smb_llist_remove(&node->n_ofile_list, ofile);
20794047d49SGordon Ross 	node->n_open_count--;
2084d723c3fSGordon Ross 
2094d723c3fSGordon Ross 	mutex_exit(&node->n_oplock.ol_mutex);
2104d723c3fSGordon Ross 	smb_llist_exit(&node->n_ofile_list);
2114d723c3fSGordon Ross 
21294047d49SGordon Ross 	ofile->f_refcnt--;
21394047d49SGordon Ross 
21494047d49SGordon Ross 	bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ);
21594047d49SGordon Ross 
21694047d49SGordon Ross 	printf(" close OK\n");
21794047d49SGordon Ross }
21894047d49SGordon Ross 
21994047d49SGordon Ross static void
do_req(int fid,char * arg2)22094047d49SGordon Ross do_req(int fid, char *arg2)
22194047d49SGordon Ross {
22294047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
22394047d49SGordon Ross 	uint32_t oplock = BATCH_OPLOCK;
22494047d49SGordon Ross 	uint32_t status;
22594047d49SGordon Ross 
22694047d49SGordon Ross 	if (arg2 != NULL)
22794047d49SGordon Ross 		oplock = strtol(arg2, NULL, 16);
22894047d49SGordon Ross 
22994047d49SGordon Ross 	/*
23094047d49SGordon Ross 	 * Request an oplock
23194047d49SGordon Ross 	 */
23294047d49SGordon Ross 	status = smb_oplock_request(&test_sr, ofile, &oplock);
233*7f6a299eSGordon Ross 	if (status == 0 ||
234*7f6a299eSGordon Ross 	    status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
23594047d49SGordon Ross 		ofile->f_oplock.og_state = oplock;
236*7f6a299eSGordon Ross 		/* When no break pending, breakto=state */
237*7f6a299eSGordon Ross 		ofile->f_oplock.og_breakto = oplock;
238*7f6a299eSGordon Ross 		ofile->f_oplock.og_breaking = B_FALSE;
239*7f6a299eSGordon Ross 	}
24094047d49SGordon Ross 	printf(" req oplock fid=%d ret oplock=0x%x status=0x%x (%s)\n",
24194047d49SGordon Ross 	    fid, oplock, status, xlate_nt_status(status));
24294047d49SGordon Ross }
24394047d49SGordon Ross 
24494047d49SGordon Ross 
24594047d49SGordon Ross static void
do_ack(int fid,char * arg2)24694047d49SGordon Ross do_ack(int fid, char *arg2)
24794047d49SGordon Ross {
24872b35b05SGordon Ross 	smb_node_t *node = &test_node;
24994047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
25094047d49SGordon Ross 	uint32_t oplock;
25194047d49SGordon Ross 	uint32_t status;
25294047d49SGordon Ross 
25394047d49SGordon Ross 	/* Default to level in last smb_oplock_ind_break() */
25494047d49SGordon Ross 	oplock = last_ind_break_level;
25594047d49SGordon Ross 	if (arg2 != NULL)
25694047d49SGordon Ross 		oplock = strtol(arg2, NULL, 16);
25794047d49SGordon Ross 
25872b35b05SGordon Ross 	smb_llist_enter(&node->n_ofile_list, RW_READER);
25972b35b05SGordon Ross 	mutex_enter(&node->n_oplock.ol_mutex);
26072b35b05SGordon Ross 
26194047d49SGordon Ross 	ofile->f_oplock.og_breaking = 0;
26294047d49SGordon Ross 	status = smb_oplock_ack_break(&test_sr, ofile, &oplock);
263*7f6a299eSGordon Ross 	if (status == 0)
26472b35b05SGordon Ross 		ofile->f_oplock.og_state = oplock;
26572b35b05SGordon Ross 
26672b35b05SGordon Ross 	mutex_exit(&node->n_oplock.ol_mutex);
26772b35b05SGordon Ross 	smb_llist_exit(&node->n_ofile_list);
26872b35b05SGordon Ross 
26994047d49SGordon Ross 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
270*7f6a299eSGordon Ross 		/* should not get this status */
27194047d49SGordon Ross 		printf(" ack: break fid=%d, break-in-progress\n", fid);
272*7f6a299eSGordon Ross 		ASSERT(0);
27394047d49SGordon Ross 	}
27494047d49SGordon Ross 
27594047d49SGordon Ross 	printf(" ack: break fid=%d, newstate=0x%x, status=0x%x (%s)\n",
27694047d49SGordon Ross 	    fid, oplock, status, xlate_nt_status(status));
277*7f6a299eSGordon Ross 
278*7f6a299eSGordon Ross 	run_ind_break_in_ack(ofile);
27994047d49SGordon Ross }
28094047d49SGordon Ross 
28194047d49SGordon Ross static void
do_brk_parent(int fid)28294047d49SGordon Ross do_brk_parent(int fid)
28394047d49SGordon Ross {
28494047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
28594047d49SGordon Ross 	uint32_t status;
28694047d49SGordon Ross 
28794047d49SGordon Ross 	status = smb_oplock_break_PARENT(&test_node, ofile);
28894047d49SGordon Ross 	printf(" brk-parent %d ret status=0x%x (%s)\n",
28994047d49SGordon Ross 	    fid, status, xlate_nt_status(status));
29094047d49SGordon Ross }
29194047d49SGordon Ross 
29294047d49SGordon Ross static void
do_brk_open(int fid,char * arg2)29394047d49SGordon Ross do_brk_open(int fid, char *arg2)
29494047d49SGordon Ross {
29594047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
29694047d49SGordon Ross 	uint32_t status;
29794047d49SGordon Ross 	int disp = FILE_OPEN;
29894047d49SGordon Ross 
29994047d49SGordon Ross 	if (arg2 != NULL)
30094047d49SGordon Ross 		disp = strtol(arg2, NULL, 16);
30194047d49SGordon Ross 
30294047d49SGordon Ross 	status = smb_oplock_break_OPEN(&test_node, ofile, 7, disp);
30394047d49SGordon Ross 	printf(" brk-open %d ret status=0x%x (%s)\n",
30494047d49SGordon Ross 	    fid, status, xlate_nt_status(status));
30594047d49SGordon Ross }
30694047d49SGordon Ross 
30794047d49SGordon Ross static void
do_brk_handle(int fid)30894047d49SGordon Ross do_brk_handle(int fid)
30994047d49SGordon Ross {
31094047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
31194047d49SGordon Ross 	uint32_t status;
31294047d49SGordon Ross 
31394047d49SGordon Ross 	status = smb_oplock_break_HANDLE(&test_node, ofile);
31494047d49SGordon Ross 	printf(" brk-handle %d ret status=0x%x (%s)\n",
31594047d49SGordon Ross 	    fid, status, xlate_nt_status(status));
31694047d49SGordon Ross 
31794047d49SGordon Ross }
31894047d49SGordon Ross 
31994047d49SGordon Ross static void
do_brk_read(int fid)32094047d49SGordon Ross do_brk_read(int fid)
32194047d49SGordon Ross {
32294047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
32394047d49SGordon Ross 	uint32_t status;
32494047d49SGordon Ross 
32594047d49SGordon Ross 	status = smb_oplock_break_READ(ofile->f_node, ofile);
32694047d49SGordon Ross 	printf(" brk-read %d ret status=0x%x (%s)\n",
32794047d49SGordon Ross 	    fid, status, xlate_nt_status(status));
32894047d49SGordon Ross }
32994047d49SGordon Ross 
33094047d49SGordon Ross static void
do_brk_write(int fid)33194047d49SGordon Ross do_brk_write(int fid)
33294047d49SGordon Ross {
33394047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
33494047d49SGordon Ross 	uint32_t status;
33594047d49SGordon Ross 
33694047d49SGordon Ross 	status = smb_oplock_break_WRITE(ofile->f_node, ofile);
33794047d49SGordon Ross 	printf(" brk-write %d ret status=0x%x (%s)\n",
33894047d49SGordon Ross 	    fid, status, xlate_nt_status(status));
33994047d49SGordon Ross }
34094047d49SGordon Ross 
34194047d49SGordon Ross static void
do_brk_setinfo(int fid,char * arg2)34294047d49SGordon Ross do_brk_setinfo(int fid, char *arg2)
34394047d49SGordon Ross {
34494047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
34594047d49SGordon Ross 	uint32_t status;
34694047d49SGordon Ross 	int infoclass = FileEndOfFileInformation; /* 20 */
34794047d49SGordon Ross 
34894047d49SGordon Ross 	if (arg2 != NULL)
34994047d49SGordon Ross 		infoclass = strtol(arg2, NULL, 16);
35094047d49SGordon Ross 
35194047d49SGordon Ross 	status = smb_oplock_break_SETINFO(
35294047d49SGordon Ross 	    &test_node, ofile, infoclass);
353*7f6a299eSGordon Ross 	printf(" brk-setinfo %d 0x%x ret status=0x%x (%s)\n",
354*7f6a299eSGordon Ross 	    fid, infoclass, status, xlate_nt_status(status));
35594047d49SGordon Ross 
35694047d49SGordon Ross }
35794047d49SGordon Ross 
35894047d49SGordon Ross /*
35994047d49SGordon Ross  * Move oplock to another FD, as specified,
36094047d49SGordon Ross  * or any other available open
36194047d49SGordon Ross  */
36294047d49SGordon Ross static void
do_move(int fid,char * arg2)36394047d49SGordon Ross do_move(int fid, char *arg2)
36494047d49SGordon Ross {
3654d723c3fSGordon Ross 	smb_node_t *node = &test_node;
36694047d49SGordon Ross 	smb_ofile_t *ofile = &ofile_array[fid];
36794047d49SGordon Ross 	smb_ofile_t *of2;
36894047d49SGordon Ross 	int fid2;
36994047d49SGordon Ross 
37094047d49SGordon Ross 	if (arg2 == NULL) {
37194047d49SGordon Ross 		fprintf(stderr, "move: FID2 required\n");
37294047d49SGordon Ross 		return;
37394047d49SGordon Ross 	}
37494047d49SGordon Ross 	fid2 = atoi(arg2);
37594047d49SGordon Ross 	if (fid2 <= 0 || fid2 >= MAXFID) {
37694047d49SGordon Ross 		fprintf(stderr, "move: bad FID2 %d\n", fid2);
37794047d49SGordon Ross 		return;
37894047d49SGordon Ross 	}
37994047d49SGordon Ross 	of2 = &ofile_array[fid2];
38094047d49SGordon Ross 
3814d723c3fSGordon Ross 	mutex_enter(&node->n_oplock.ol_mutex);
3824d723c3fSGordon Ross 
38394047d49SGordon Ross 	smb_oplock_move(&test_node, ofile, of2);
3844d723c3fSGordon Ross 
3854d723c3fSGordon Ross 	mutex_exit(&node->n_oplock.ol_mutex);
3864d723c3fSGordon Ross 
38794047d49SGordon Ross 	printf(" move %d %d\n", fid, fid2);
38894047d49SGordon Ross }
38994047d49SGordon Ross 
39094047d49SGordon Ross /*
39194047d49SGordon Ross  * Set/clear oplock.waiters, which affects ack-break
39294047d49SGordon Ross  */
39394047d49SGordon Ross static void
do_waiters(int fid,char * arg2)39494047d49SGordon Ross do_waiters(int fid, char *arg2)
39594047d49SGordon Ross {
39694047d49SGordon Ross 	smb_node_t *node = &test_node;
39794047d49SGordon Ross 	smb_oplock_t *ol = &node->n_oplock;
39894047d49SGordon Ross 	int old, new = 0;
39994047d49SGordon Ross 
40094047d49SGordon Ross 	if (arg2 != NULL)
40194047d49SGordon Ross 		new = atoi(arg2);
40294047d49SGordon Ross 
40394047d49SGordon Ross 	old = ol->waiters;
40494047d49SGordon Ross 	ol->waiters = new;
40594047d49SGordon Ross 
40694047d49SGordon Ross 	printf(" waiters %d -> %d\n", old, new);
40794047d49SGordon Ross }
40894047d49SGordon Ross 
40994047d49SGordon Ross int
main(int argc,char * argv[])41094047d49SGordon Ross main(int argc, char *argv[])
41194047d49SGordon Ross {
41294047d49SGordon Ross 	smb_node_t *node = &test_node;
41394047d49SGordon Ross 	char *cmd;
41494047d49SGordon Ross 	char *arg1;
41594047d49SGordon Ross 	char *arg2;
41694047d49SGordon Ross 	char *savep;
41794047d49SGordon Ross 	char *sep = " \t\n";
41894047d49SGordon Ross 	char *prompt = NULL;
41994047d49SGordon Ross 	int fid;
42094047d49SGordon Ross 
42194047d49SGordon Ross 	if (isatty(0))
42294047d49SGordon Ross 		prompt = "> ";
42394047d49SGordon Ross 
4244d723c3fSGordon Ross 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
4254d723c3fSGordon Ross 
42694047d49SGordon Ross 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
42794047d49SGordon Ross 	    offsetof(smb_ofile_t, f_node_lnd));
42894047d49SGordon Ross 
42994047d49SGordon Ross 	for (fid = 0; fid < MAXFID; fid++) {
43094047d49SGordon Ross 		smb_ofile_t *f = &ofile_array[fid];
43194047d49SGordon Ross 
43294047d49SGordon Ross 		f->f_magic = SMB_OFILE_MAGIC;
43394047d49SGordon Ross 		mutex_init(&f->f_mutex, NULL, MUTEX_DEFAULT, NULL);
43494047d49SGordon Ross 		f->f_fid = fid;
43594047d49SGordon Ross 		f->f_ftype = SMB_FTYPE_DISK;
43694047d49SGordon Ross 		f->f_node = &test_node;
43794047d49SGordon Ross 	}
43894047d49SGordon Ross 
43994047d49SGordon Ross 	for (;;) {
44094047d49SGordon Ross 		if (prompt) {
441da90d5b8SJohn Levon 			(void) fputs(prompt, stdout);
44294047d49SGordon Ross 			fflush(stdout);
44394047d49SGordon Ross 		}
44494047d49SGordon Ross 
44594047d49SGordon Ross 		cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
44694047d49SGordon Ross 		if (cmd == NULL)
44794047d49SGordon Ross 			break;
44894047d49SGordon Ross 		if (cmd[0] == '#')
44994047d49SGordon Ross 			continue;
45094047d49SGordon Ross 
45194047d49SGordon Ross 		if (prompt == NULL) {
45294047d49SGordon Ross 			/* Put commands in the output too. */
453da90d5b8SJohn Levon 			(void) fputs(cmdbuf, stdout);
45494047d49SGordon Ross 		}
45594047d49SGordon Ross 		cmd = strtok_r(cmd, sep, &savep);
45694047d49SGordon Ross 		if (cmd == NULL)
45794047d49SGordon Ross 			continue;
45894047d49SGordon Ross 
45994047d49SGordon Ross 		/*
46094047d49SGordon Ross 		 * Commands with no args
46194047d49SGordon Ross 		 */
46294047d49SGordon Ross 		if (0 == strcmp(cmd, "help")) {
463da90d5b8SJohn Levon 			(void) fputs(helpstr, stdout);
46494047d49SGordon Ross 			continue;
46594047d49SGordon Ross 		}
46694047d49SGordon Ross 
46794047d49SGordon Ross 		if (0 == strcmp(cmd, "show")) {
46894047d49SGordon Ross 			do_show();
46994047d49SGordon Ross 			continue;
47094047d49SGordon Ross 		}
47194047d49SGordon Ross 
47294047d49SGordon Ross 		/*
47394047d49SGordon Ross 		 * Commands with one arg (the FID)
47494047d49SGordon Ross 		 */
47594047d49SGordon Ross 		arg1 = strtok_r(NULL, sep, &savep);
47694047d49SGordon Ross 		if (arg1 == NULL) {
47794047d49SGordon Ross 			fprintf(stderr, "%s missing arg1\n", cmd);
47894047d49SGordon Ross 			continue;
47994047d49SGordon Ross 		}
48094047d49SGordon Ross 		fid = atoi(arg1);
48194047d49SGordon Ross 		if (fid <= 0 || fid >= MAXFID) {
48294047d49SGordon Ross 			fprintf(stderr, "%s bad FID %d\n", cmd, fid);
48394047d49SGordon Ross 			continue;
48494047d49SGordon Ross 		}
48594047d49SGordon Ross 
48694047d49SGordon Ross 		if (0 == strcmp(cmd, "close")) {
48794047d49SGordon Ross 			do_close(fid);
48894047d49SGordon Ross 			continue;
48994047d49SGordon Ross 		}
49094047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-parent")) {
49194047d49SGordon Ross 			do_brk_parent(fid);
49294047d49SGordon Ross 			continue;
49394047d49SGordon Ross 		}
49494047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-handle")) {
49594047d49SGordon Ross 			do_brk_handle(fid);
49694047d49SGordon Ross 			continue;
49794047d49SGordon Ross 		}
49894047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-read")) {
49994047d49SGordon Ross 			do_brk_read(fid);
50094047d49SGordon Ross 			continue;
50194047d49SGordon Ross 		}
50294047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-write")) {
50394047d49SGordon Ross 			do_brk_write(fid);
50494047d49SGordon Ross 			continue;
50594047d49SGordon Ross 		}
50694047d49SGordon Ross 
50794047d49SGordon Ross 		/*
50894047d49SGordon Ross 		 * Commands with an (optional) arg2.
50994047d49SGordon Ross 		 */
51094047d49SGordon Ross 		arg2 = strtok_r(NULL, sep, &savep);
51194047d49SGordon Ross 
51294047d49SGordon Ross 		if (0 == strcmp(cmd, "open")) {
51394047d49SGordon Ross 			do_open(fid, arg2);
51494047d49SGordon Ross 			continue;
51594047d49SGordon Ross 		}
51694047d49SGordon Ross 		if (0 == strcmp(cmd, "req")) {
51794047d49SGordon Ross 			do_req(fid, arg2);
51894047d49SGordon Ross 			continue;
51994047d49SGordon Ross 		}
52094047d49SGordon Ross 		if (0 == strcmp(cmd, "ack")) {
52194047d49SGordon Ross 			do_ack(fid, arg2);
52294047d49SGordon Ross 			continue;
52394047d49SGordon Ross 		}
52494047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-open")) {
52594047d49SGordon Ross 			do_brk_open(fid, arg2);
52694047d49SGordon Ross 			continue;
52794047d49SGordon Ross 		}
52894047d49SGordon Ross 		if (0 == strcmp(cmd, "brk-setinfo")) {
52994047d49SGordon Ross 			do_brk_setinfo(fid, arg2);
53094047d49SGordon Ross 			continue;
53194047d49SGordon Ross 		}
53294047d49SGordon Ross 		if (0 == strcmp(cmd, "move")) {
53394047d49SGordon Ross 			do_move(fid, arg2);
53494047d49SGordon Ross 			continue;
53594047d49SGordon Ross 		}
53694047d49SGordon Ross 		if (0 == strcmp(cmd, "waiters")) {
53794047d49SGordon Ross 			do_waiters(fid, arg2);
53894047d49SGordon Ross 			continue;
53994047d49SGordon Ross 		}
54094047d49SGordon Ross 
54194047d49SGordon Ross 		fprintf(stderr, "%s unknown command. Try help\n", cmd);
54294047d49SGordon Ross 	}
54394047d49SGordon Ross 	return (0);
54494047d49SGordon Ross }
54594047d49SGordon Ross 
54694047d49SGordon Ross /*
54794047d49SGordon Ross  * A few functions called by the oplock code
54894047d49SGordon Ross  * Stubbed out, and/or just print a message.
54994047d49SGordon Ross  */
55094047d49SGordon Ross 
55194047d49SGordon Ross boolean_t
smb_node_is_file(smb_node_t * node)55294047d49SGordon Ross smb_node_is_file(smb_node_t *node)
55394047d49SGordon Ross {
55494047d49SGordon Ross 	return (B_TRUE);
55594047d49SGordon Ross }
55694047d49SGordon Ross 
55794047d49SGordon Ross boolean_t
smb_ofile_is_open(smb_ofile_t * ofile)55894047d49SGordon Ross smb_ofile_is_open(smb_ofile_t *ofile)
55994047d49SGordon Ross {
56094047d49SGordon Ross 	return (ofile->f_refcnt != 0);
56194047d49SGordon Ross }
56294047d49SGordon Ross 
56394047d49SGordon Ross int
smb_lock_range_access(smb_request_t * sr,smb_node_t * node,uint64_t start,uint64_t length,boolean_t will_write)56494047d49SGordon Ross smb_lock_range_access(
56594047d49SGordon Ross     smb_request_t	*sr,
56694047d49SGordon Ross     smb_node_t		*node,
56794047d49SGordon Ross     uint64_t		start,
56894047d49SGordon Ross     uint64_t		length,
56994047d49SGordon Ross     boolean_t		will_write)
57094047d49SGordon Ross {
57194047d49SGordon Ross 	return (0);
57294047d49SGordon Ross }
57394047d49SGordon Ross 
57494047d49SGordon Ross /*
57572b35b05SGordon Ross  * Test code replacement for combination of:
57672b35b05SGordon Ross  *	smb_oplock_hdl_update()
577*7f6a299eSGordon Ross  *	smb_oplock_send_break()
578*7f6a299eSGordon Ross  *
579*7f6a299eSGordon Ross  * In a real server, we would send a break to the client,
580*7f6a299eSGordon Ross  * and keep track (at the SMB level) whether this oplock
581*7f6a299eSGordon Ross  * was obtained via a lease or an old-style oplock.
58294047d49SGordon Ross  */
58394047d49SGordon Ross static void
test_oplock_send_break(smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckReq)584*7f6a299eSGordon Ross test_oplock_send_break(smb_ofile_t *ofile,
58594047d49SGordon Ross     uint32_t NewLevel, boolean_t AckReq)
58694047d49SGordon Ross {
58794047d49SGordon Ross 	smb_oplock_grant_t *og = &ofile->f_oplock;
588*7f6a299eSGordon Ross 	uint32_t OldLevel;
58994047d49SGordon Ross 
59094047d49SGordon Ross 	/* Skip building a message. */
59194047d49SGordon Ross 
59294047d49SGordon Ross 	if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0)
59394047d49SGordon Ross 		NewLevel |= OPLOCK_LEVEL_GRANULAR;
59494047d49SGordon Ross 
595*7f6a299eSGordon Ross 	OldLevel = og->og_state;
596*7f6a299eSGordon Ross 	og->og_breakto = NewLevel;
597*7f6a299eSGordon Ross 	og->og_breaking = B_TRUE;
598*7f6a299eSGordon Ross 
599*7f6a299eSGordon Ross 	printf("*smb_oplock_send_break fid=%d "
600*7f6a299eSGordon Ross 	    "NewLevel=0x%x, OldLevel=0x%x, AckReq=%d)\n",
601*7f6a299eSGordon Ross 	    ofile->f_fid, NewLevel, OldLevel, AckReq);
602*7f6a299eSGordon Ross 
603*7f6a299eSGordon Ross 	if (!AckReq) {
60494047d49SGordon Ross 		og->og_state = NewLevel;
605*7f6a299eSGordon Ross 		og->og_breaking = B_FALSE;
60694047d49SGordon Ross 	}
60772b35b05SGordon Ross 
60872b35b05SGordon Ross 	/* Next, smb_oplock_send_break() would send a break. */
60972b35b05SGordon Ross 	last_ind_break_level = NewLevel;
61094047d49SGordon Ross }
61194047d49SGordon Ross 
61294047d49SGordon Ross /*
61394047d49SGordon Ross  * Simplified version of what's in smb_srv_oplock.c
61494047d49SGordon Ross  */
61594047d49SGordon Ross void
smb_oplock_ind_break(smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckReq,uint32_t status)61694047d49SGordon Ross smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
61794047d49SGordon Ross     boolean_t AckReq, uint32_t status)
61894047d49SGordon Ross {
61994047d49SGordon Ross 	smb_oplock_grant_t *og = &ofile->f_oplock;
62094047d49SGordon Ross 
62194047d49SGordon Ross 	printf("*smb_oplock_ind_break fid=%d NewLevel=0x%x,"
62294047d49SGordon Ross 	    " AckReq=%d, ComplStatus=0x%x (%s)\n",
62394047d49SGordon Ross 	    ofile->f_fid, NewLevel, AckReq,
62494047d49SGordon Ross 	    status, xlate_nt_status(status));
62594047d49SGordon Ross 
62694047d49SGordon Ross 	/*
62794047d49SGordon Ross 	 * Note that the CompletionStatus from the FS level
62894047d49SGordon Ross 	 * (smb_cmn_oplock.c) encodes what kind of action we
62994047d49SGordon Ross 	 * need to take at the SMB level.
63094047d49SGordon Ross 	 */
63194047d49SGordon Ross 	switch (status) {
63294047d49SGordon Ross 
63394047d49SGordon Ross 	case NT_STATUS_SUCCESS:
63494047d49SGordon Ross 	case NT_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK:
635*7f6a299eSGordon Ross 		test_oplock_send_break(ofile, NewLevel, AckReq);
63694047d49SGordon Ross 		break;
63794047d49SGordon Ross 
63894047d49SGordon Ross 	case NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE:
63994047d49SGordon Ross 	case NT_STATUS_OPLOCK_HANDLE_CLOSED:
64094047d49SGordon Ross 		og->og_state = OPLOCK_LEVEL_NONE;
641*7f6a299eSGordon Ross 		og->og_breakto = OPLOCK_LEVEL_NONE;
642*7f6a299eSGordon Ross 		og->og_breaking = B_FALSE;
64394047d49SGordon Ross 		break;
64494047d49SGordon Ross 
64594047d49SGordon Ross 	default:
64694047d49SGordon Ross 		ASSERT(0);
64794047d49SGordon Ross 		break;
64894047d49SGordon Ross 	}
64994047d49SGordon Ross }
65094047d49SGordon Ross 
651*7f6a299eSGordon Ross /* Arrange for break_in_ack to run after ack completes. */
652*7f6a299eSGordon Ross static uint32_t break_in_ack_NewLevel;
653*7f6a299eSGordon Ross static boolean_t break_in_ack_AckReq;
654*7f6a299eSGordon Ross static boolean_t break_in_ack_called;
655*7f6a299eSGordon Ross 
65694047d49SGordon Ross void
smb_oplock_ind_break_in_ack(smb_request_t * sr,smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckRequired)65794047d49SGordon Ross smb_oplock_ind_break_in_ack(smb_request_t *sr, smb_ofile_t *ofile,
65894047d49SGordon Ross     uint32_t NewLevel, boolean_t AckRequired)
65994047d49SGordon Ross {
66094047d49SGordon Ross 	ASSERT(sr == &test_sr);
661*7f6a299eSGordon Ross 
662*7f6a299eSGordon Ross 	/* Process these after ack */
663*7f6a299eSGordon Ross 	ASSERT(!break_in_ack_called);
664*7f6a299eSGordon Ross 	break_in_ack_called = B_TRUE;
665*7f6a299eSGordon Ross 	break_in_ack_NewLevel = NewLevel;
666*7f6a299eSGordon Ross 	break_in_ack_AckReq = AckRequired;
667*7f6a299eSGordon Ross }
668*7f6a299eSGordon Ross 
669*7f6a299eSGordon Ross static void
run_ind_break_in_ack(smb_ofile_t * ofile)670*7f6a299eSGordon Ross run_ind_break_in_ack(smb_ofile_t *ofile)
671*7f6a299eSGordon Ross {
672*7f6a299eSGordon Ross 	uint32_t NewLevel;
673*7f6a299eSGordon Ross 	boolean_t AckReq;
674*7f6a299eSGordon Ross 
675*7f6a299eSGordon Ross 	/* Process these after ack */
676*7f6a299eSGordon Ross 	if (!break_in_ack_called)
677*7f6a299eSGordon Ross 		return;
678*7f6a299eSGordon Ross 	break_in_ack_called = B_FALSE;
679*7f6a299eSGordon Ross 	NewLevel = break_in_ack_NewLevel;
680*7f6a299eSGordon Ross 	AckReq = break_in_ack_AckReq;
681*7f6a299eSGordon Ross 
682*7f6a299eSGordon Ross 	printf("*smb_oplock_ind_break_in_ack fid=%d NewLevel=0x%x,"
683*7f6a299eSGordon Ross 	    " AckReq=%d\n",
684*7f6a299eSGordon Ross 	    ofile->f_fid, NewLevel, AckReq);
685*7f6a299eSGordon Ross 
686*7f6a299eSGordon Ross 	test_oplock_send_break(ofile, NewLevel, AckReq);
68794047d49SGordon Ross }
68894047d49SGordon Ross 
68994047d49SGordon Ross uint32_t
smb_oplock_wait_break(smb_request_t * sr,smb_node_t * node,int timeout)69072b35b05SGordon Ross smb_oplock_wait_break(smb_request_t *sr, smb_node_t *node, int timeout)
69194047d49SGordon Ross {
69294047d49SGordon Ross 	printf("*smb_oplock_wait_break (state=0x%x)\n",
69394047d49SGordon Ross 	    node->n_oplock.ol_state);
69494047d49SGordon Ross 	return (0);
69594047d49SGordon Ross }
69694047d49SGordon Ross 
697e8754e84SGordon Ross int
smb_fem_oplock_install(smb_node_t * node)698e8754e84SGordon Ross smb_fem_oplock_install(smb_node_t *node)
699e8754e84SGordon Ross {
700e8754e84SGordon Ross 	return (0);
701e8754e84SGordon Ross }
702e8754e84SGordon Ross 
703e8754e84SGordon Ross void
smb_fem_oplock_uninstall(smb_node_t * node)704e8754e84SGordon Ross smb_fem_oplock_uninstall(smb_node_t *node)
705e8754e84SGordon Ross {
706e8754e84SGordon Ross }
707e8754e84SGordon Ross 
70894047d49SGordon Ross /*
70994047d49SGordon Ross  * There are a couple DTRACE_PROBE* in smb_cmn_oplock.c but we're
71094047d49SGordon Ross  * not linking with the user-level dtrace support, so just
71194047d49SGordon Ross  * stub these out.
71294047d49SGordon Ross  */
71394047d49SGordon Ross void
__dtrace_fksmb___probe1(char * n,unsigned long a)71494047d49SGordon Ross __dtrace_fksmb___probe1(char *n, unsigned long a)
71594047d49SGordon Ross {
71694047d49SGordon Ross }
71794047d49SGordon Ross void
__dtrace_fksmb___probe2(char * n,unsigned long a,unsigned long b)71894047d49SGordon Ross __dtrace_fksmb___probe2(char *n, unsigned long a, unsigned long b)
71994047d49SGordon Ross {
72094047d49SGordon Ross }
721