194047d4Gordon Ross/*
294047d4Gordon Ross * This file and its contents are supplied under the terms of the
394047d4Gordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
494047d4Gordon Ross * You may only use this file in accordance with the terms of version
594047d4Gordon Ross * 1.0 of the CDDL.
694047d4Gordon Ross *
794047d4Gordon Ross * A full copy of the text of the CDDL should have accompanied this
894047d4Gordon Ross * source.  A copy of the CDDL is also available via the Internet at
994047d4Gordon Ross * http://www.illumos.org/license/CDDL.
1094047d4Gordon Ross */
1194047d4Gordon Ross
1294047d4Gordon Ross/*
1394047d4Gordon Ross * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
14da90d5bJohn Levon * Copyright 2019 Joyent, Inc.
1594047d4Gordon Ross */
1694047d4Gordon Ross
1794047d4Gordon Ross/*
1894047d4Gordon Ross * Test & debug program for oplocks
1994047d4Gordon Ross *
2094047d4Gordon Ross * This implements a simple command reader which accepts
2194047d4Gordon Ross * commands to simulate oplock events, and prints the
2294047d4Gordon Ross * state changes and actions that would happen after
2394047d4Gordon Ross * each event.
2494047d4Gordon Ross */
2594047d4Gordon Ross
2694047d4Gordon Ross#include <sys/types.h>
2794047d4Gordon Ross#include <sys/debug.h>
2894047d4Gordon Ross#include <sys/stddef.h>
2994047d4Gordon Ross#include <stdio.h>
3094047d4Gordon Ross#include <stdlib.h>
3194047d4Gordon Ross#include <string.h>
3294047d4Gordon Ross#include <strings.h>
3394047d4Gordon Ross#include <unistd.h>
3494047d4Gordon Ross
3594047d4Gordon Ross#include <smbsrv/smb_kproto.h>
3694047d4Gordon Ross#include <smbsrv/smb_oplock.h>
3794047d4Gordon Ross
3894047d4Gordon Ross#define	OPLOCK_CACHE_RWH	(READ_CACHING | HANDLE_CACHING | WRITE_CACHING)
3994047d4Gordon Ross#define	OPLOCK_TYPE	(LEVEL_TWO_OPLOCK | LEVEL_ONE_OPLOCK |\
4094047d4Gordon Ross			BATCH_OPLOCK | OPLOCK_LEVEL_GRANULAR)
4194047d4Gordon Ross
4294047d4Gordon Ross#define	MAXFID 10
4394047d4Gordon Ross
4494047d4Gordon Rosssmb_node_t root_node, test_node;
4594047d4Gordon Rosssmb_ofile_t  ofile_array[MAXFID];
4694047d4Gordon Rosssmb_request_t test_sr;
4794047d4Gordon Rossuint32_t last_ind_break_level;
4894047d4Gordon Rosschar cmdbuf[100];
4994047d4Gordon Ross
5094047d4Gordon Rossextern const char *xlate_nt_status(uint32_t);
5194047d4Gordon Ross
5294047d4Gordon Ross#define	BIT_DEF(name) { name, #name }
5394047d4Gordon Ross
5494047d4Gordon Rossstruct bit_defs {
5594047d4Gordon Ross	uint32_t mask;
5694047d4Gordon Ross	const char *name;
5794047d4Gordon Ross} state_bits[] = {
5894047d4Gordon Ross	BIT_DEF(NO_OPLOCK),
5994047d4Gordon Ross	BIT_DEF(BREAK_TO_NO_CACHING),
6094047d4Gordon Ross	BIT_DEF(BREAK_TO_WRITE_CACHING),
6194047d4Gordon Ross	BIT_DEF(BREAK_TO_HANDLE_CACHING),
6294047d4Gordon Ross	BIT_DEF(BREAK_TO_READ_CACHING),
6394047d4Gordon Ross	BIT_DEF(BREAK_TO_TWO_TO_NONE),
6494047d4Gordon Ross	BIT_DEF(BREAK_TO_NONE),
6594047d4Gordon Ross	BIT_DEF(BREAK_TO_TWO),
6694047d4Gordon Ross	BIT_DEF(BATCH_OPLOCK),
6794047d4Gordon Ross	BIT_DEF(LEVEL_ONE_OPLOCK),
6894047d4Gordon Ross	BIT_DEF(LEVEL_TWO_OPLOCK),
6994047d4Gordon Ross	BIT_DEF(MIXED_R_AND_RH),
7094047d4Gordon Ross	BIT_DEF(EXCLUSIVE),
7194047d4Gordon Ross	BIT_DEF(WRITE_CACHING),
7294047d4Gordon Ross	BIT_DEF(HANDLE_CACHING),
7394047d4Gordon Ross	BIT_DEF(READ_CACHING),
7494047d4Gordon Ross	{ 0, NULL }
7594047d4Gordon Ross};
7694047d4Gordon Ross
7794047d4Gordon Ross/*
7894047d4Gordon Ross * Helper to print flags fields
7994047d4Gordon Ross */
8094047d4Gordon Rossstatic void
8194047d4Gordon Rossprint_bits32(char *label, struct bit_defs *bit, uint32_t state)
8294047d4Gordon Ross{
8394047d4Gordon Ross	printf("%s0x%x (", label, state);
8494047d4Gordon Ross	while (bit->mask != 0) {
8594047d4Gordon Ross		if ((state & bit->mask) != 0)
8694047d4Gordon Ross			printf(" %s", bit->name);
8794047d4Gordon Ross		bit++;
8894047d4Gordon Ross	}
8994047d4Gordon Ross	printf(" )\n");
9094047d4Gordon Ross}
9194047d4Gordon Ross
9294047d4Gordon Ross/*
9394047d4Gordon Ross * Command language:
9494047d4Gordon Ross *
9594047d4Gordon Ross */
9694047d4Gordon Rossconst char helpstr[] = "Commands:\n"
9794047d4Gordon Ross	"help\t\tList commands\n"
9894047d4Gordon Ross	"show\t\tShow OpLock state etc.\n"
9994047d4Gordon Ross	"open FID\n"
10094047d4Gordon Ross	"close FID\n"
10194047d4Gordon Ross	"req FID [OplockLevel]\n"
10294047d4Gordon Ross	"ack FID [OplockLevel]\n"
10394047d4Gordon Ross	"brk-parent FID\n"
10494047d4Gordon Ross	"brk-open [OverWrite]\n"
10594047d4Gordon Ross	"brk-handle FID\n"
10694047d4Gordon Ross	"brk-read FID\n"
10794047d4Gordon Ross	"brk-write FID\n"
10894047d4Gordon Ross	"brk-setinfo FID [InfoClass]\n"
10994047d4Gordon Ross	"move FID1 FID2\n"
11094047d4Gordon Ross	"waiters FID [count]\n";
11194047d4Gordon Ross
11294047d4Gordon Ross/*
11394047d4Gordon Ross * Command handlers
11494047d4Gordon Ross */
11594047d4Gordon Ross
11694047d4Gordon Rossstatic void
11794047d4Gordon Rossdo_show(void)
11894047d4Gordon Ross{
11994047d4Gordon Ross	smb_node_t *node = &test_node;
12094047d4Gordon Ross	smb_oplock_t *ol = &node->n_oplock;
12194047d4Gordon Ross	uint32_t state = ol->ol_state;
12294047d4Gordon Ross	smb_ofile_t *f;
12394047d4Gordon Ross
12494047d4Gordon Ross	print_bits32(" ol_state=", state_bits, state);
12594047d4Gordon Ross
12694047d4Gordon Ross	if (ol->excl_open != NULL)
12794047d4Gordon Ross		printf(" Excl=Y (FID=%d)", ol->excl_open->f_fid);
12894047d4Gordon Ross	else
12994047d4Gordon Ross		printf(" Excl=n");
13094047d4Gordon Ross	printf(" cnt_II=%d cnt_R=%d cnt_RH=%d cnt_RHBQ=%d\n",
13194047d4Gordon Ross	    ol->cnt_II, ol->cnt_R, ol->cnt_RH, ol->cnt_RHBQ);
13294047d4Gordon Ross
13394047d4Gordon Ross	printf(" ofile_cnt=%d\n", node->n_ofile_list.ll_count);
13494047d4Gordon Ross	FOREACH_NODE_OFILE(node, f) {
13594047d4Gordon Ross		smb_oplock_grant_t *og = &f->f_oplock;
13694047d4Gordon Ross		printf("  fid=%d Lease=%s OgState=0x%x Brk=0x%x",
13794047d4Gordon Ross		    f->f_fid,
13894047d4Gordon Ross		    f->TargetOplockKey,	/* lease */
13994047d4Gordon Ross		    f->f_oplock.og_state,
14094047d4Gordon Ross		    f->f_oplock.og_breaking);
14194047d4Gordon Ross		printf(" Excl=%s onlist: %s %s %s",
14294047d4Gordon Ross		    (ol->excl_open == f) ? "Y" : "N",
14394047d4Gordon Ross		    og->onlist_II ? "II" : "",
14494047d4Gordon Ross		    og->onlist_R  ? "R" : "",
14594047d4Gordon Ross		    og->onlist_RH ? "RH" : "");
14694047d4Gordon Ross		if (og->onlist_RHBQ) {
14794047d4Gordon Ross			printf(" RHBQ(to %s)",
14894047d4Gordon Ross			    og->BreakingToRead ?
14994047d4Gordon Ross			    "read" : "none");
15094047d4Gordon Ross		}
15194047d4Gordon Ross		printf("\n");
15294047d4Gordon Ross	}
15394047d4Gordon Ross}
15494047d4Gordon Ross
15594047d4Gordon Rossstatic void
15694047d4Gordon Rossdo_open(int fid, char *arg2)
15794047d4Gordon Ross{
15894047d4Gordon Ross	smb_node_t *node = &test_node;
15994047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
16094047d4Gordon Ross
16194047d4Gordon Ross	/*
16294047d4Gordon Ross	 * Simulate an open (minimal init)
16394047d4Gordon Ross	 */
16494047d4Gordon Ross	if (ofile->f_refcnt) {
16594047d4Gordon Ross		printf("open fid %d already opened\n");
16694047d4Gordon Ross		return;
16794047d4Gordon Ross	}
16894047d4Gordon Ross
169da90d5bJohn Levon	if (arg2 != NULL) {
170da90d5bJohn Levon		(void) strlcpy((char *)ofile->TargetOplockKey, arg2,
17194047d4Gordon Ross		    SMB_LEASE_KEY_SZ);
172da90d5bJohn Levon	}
17394047d4Gordon Ross
17494047d4Gordon Ross	ofile->f_refcnt++;
17594047d4Gordon Ross	node->n_open_count++;
17694047d4Gordon Ross	smb_llist_insert_tail(&node->n_ofile_list, ofile);
17794047d4Gordon Ross	printf(" open %d OK\n", fid);
17894047d4Gordon Ross}
17994047d4Gordon Ross
18094047d4Gordon Rossstatic void
18194047d4Gordon Rossdo_close(int fid)
18294047d4Gordon Ross{
18394047d4Gordon Ross	smb_node_t *node = &test_node;
18494047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
18594047d4Gordon Ross
18694047d4Gordon Ross	/*
18794047d4Gordon Ross	 * Simulate an close
18894047d4Gordon Ross	 */
18994047d4Gordon Ross	if (ofile->f_refcnt <= 0) {
19094047d4Gordon Ross		printf(" close fid %d already closed\n");
19194047d4Gordon Ross		return;
19294047d4Gordon Ross	}
19394047d4Gordon Ross	smb_oplock_break_CLOSE(ofile->f_node, ofile);
19494047d4Gordon Ross
19594047d4Gordon Ross	smb_llist_remove(&node->n_ofile_list, ofile);
19694047d4Gordon Ross	node->n_open_count--;
19794047d4Gordon Ross	ofile->f_refcnt--;
19894047d4Gordon Ross
19994047d4Gordon Ross	bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ);
20094047d4Gordon Ross
20194047d4Gordon Ross	printf(" close OK\n");
20294047d4Gordon Ross}
20394047d4Gordon Ross
20494047d4Gordon Rossstatic void
20594047d4Gordon Rossdo_req(int fid, char *arg2)
20694047d4Gordon Ross{
20794047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
20894047d4Gordon Ross	uint32_t oplock = BATCH_OPLOCK;
20994047d4Gordon Ross	uint32_t status;
21094047d4Gordon Ross
21194047d4Gordon Ross	if (arg2 != NULL)
21294047d4Gordon Ross		oplock = strtol(arg2, NULL, 16);
21394047d4Gordon Ross
21494047d4Gordon Ross	/*
21594047d4Gordon Ross	 * Request an oplock
21694047d4Gordon Ross	 */
21794047d4Gordon Ross	status = smb_oplock_request(&test_sr, ofile, &oplock);
21894047d4Gordon Ross	if (status == 0)
21994047d4Gordon Ross		ofile->f_oplock.og_state = oplock;
22094047d4Gordon Ross	printf(" req oplock fid=%d ret oplock=0x%x status=0x%x (%s)\n",
22194047d4Gordon Ross	    fid, oplock, status, xlate_nt_status(status));
22294047d4Gordon Ross}
22394047d4Gordon Ross
22494047d4Gordon Ross
22594047d4Gordon Rossstatic void
22694047d4Gordon Rossdo_ack(int fid, char *arg2)
22794047d4Gordon Ross{
22894047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
22994047d4Gordon Ross	uint32_t oplock;
23094047d4Gordon Ross	uint32_t status;
23194047d4Gordon Ross
23294047d4Gordon Ross	/* Default to level in last smb_oplock_ind_break() */
23394047d4Gordon Ross	oplock = last_ind_break_level;
23494047d4Gordon Ross	if (arg2 != NULL)
23594047d4Gordon Ross		oplock = strtol(arg2, NULL, 16);
23694047d4Gordon Ross
23794047d4Gordon Ross	ofile->f_oplock.og_breaking = 0;
23894047d4Gordon Ross	status = smb_oplock_ack_break(&test_sr, ofile, &oplock);
23994047d4Gordon Ross	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
24094047d4Gordon Ross		printf(" ack: break fid=%d, break-in-progress\n", fid);
24194047d4Gordon Ross		ofile->f_oplock.og_state = oplock;
24294047d4Gordon Ross	}
24394047d4Gordon Ross	if (status == 0)
24494047d4Gordon Ross		ofile->f_oplock.og_state = oplock;
24594047d4Gordon Ross
24694047d4Gordon Ross	printf(" ack: break fid=%d, newstate=0x%x, status=0x%x (%s)\n",
24794047d4Gordon Ross	    fid, oplock, status, xlate_nt_status(status));
24894047d4Gordon Ross}
24994047d4Gordon Ross
25094047d4Gordon Rossstatic void
25194047d4Gordon Rossdo_brk_parent(int fid)
25294047d4Gordon Ross{
25394047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
25494047d4Gordon Ross	uint32_t status;
25594047d4Gordon Ross
25694047d4Gordon Ross	status = smb_oplock_break_PARENT(&test_node, ofile);
25794047d4Gordon Ross	printf(" brk-parent %d ret status=0x%x (%s)\n",
25894047d4Gordon Ross	    fid, status, xlate_nt_status(status));
25994047d4Gordon Ross}
26094047d4Gordon Ross
26194047d4Gordon Rossstatic void
26294047d4Gordon Rossdo_brk_open(int fid, char *arg2)
26394047d4Gordon Ross{
26494047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
26594047d4Gordon Ross	uint32_t status;
26694047d4Gordon Ross	int disp = FILE_OPEN;
26794047d4Gordon Ross
26894047d4Gordon Ross	if (arg2 != NULL)
26994047d4Gordon Ross		disp = strtol(arg2, NULL, 16);
27094047d4Gordon Ross
27194047d4Gordon Ross	status = smb_oplock_break_OPEN(&test_node, ofile, 7, disp);
27294047d4Gordon Ross	printf(" brk-open %d ret status=0x%x (%s)\n",
27394047d4Gordon Ross	    fid, status, xlate_nt_status(status));
27494047d4Gordon Ross}
27594047d4Gordon Ross
27694047d4Gordon Rossstatic void
27794047d4Gordon Rossdo_brk_handle(int fid)
27894047d4Gordon Ross{
27994047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
28094047d4Gordon Ross	uint32_t status;
28194047d4Gordon Ross
28294047d4Gordon Ross	status = smb_oplock_break_HANDLE(&test_node, ofile);
28394047d4Gordon Ross	printf(" brk-handle %d ret status=0x%x (%s)\n",
28494047d4Gordon Ross	    fid, status, xlate_nt_status(status));
28594047d4Gordon Ross
28694047d4Gordon Ross}
28794047d4Gordon Ross
28894047d4Gordon Rossstatic void
28994047d4Gordon Rossdo_brk_read(int fid)
29094047d4Gordon Ross{
29194047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
29294047d4Gordon Ross	uint32_t status;
29394047d4Gordon Ross
29494047d4Gordon Ross	status = smb_oplock_break_READ(ofile->f_node, ofile);
29594047d4Gordon Ross	printf(" brk-read %d ret status=0x%x (%s)\n",
29694047d4Gordon Ross	    fid, status, xlate_nt_status(status));
29794047d4Gordon Ross}
29894047d4Gordon Ross
29994047d4Gordon Rossstatic void
30094047d4Gordon Rossdo_brk_write(int fid)
30194047d4Gordon Ross{
30294047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
30394047d4Gordon Ross	uint32_t status;
30494047d4Gordon Ross
30594047d4Gordon Ross	status = smb_oplock_break_WRITE(ofile->f_node, ofile);
30694047d4Gordon Ross	printf(" brk-write %d ret status=0x%x (%s)\n",
30794047d4Gordon Ross	    fid, status, xlate_nt_status(status));
30894047d4Gordon Ross}
30994047d4Gordon Ross
31094047d4Gordon Rossstatic void
31194047d4Gordon Rossdo_brk_setinfo(int fid, char *arg2)
31294047d4Gordon Ross{
31394047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
31494047d4Gordon Ross	uint32_t status;
31594047d4Gordon Ross	int infoclass = FileEndOfFileInformation; /* 20 */
31694047d4Gordon Ross
31794047d4Gordon Ross	if (arg2 != NULL)
31894047d4Gordon Ross		infoclass = strtol(arg2, NULL, 16);
31994047d4Gordon Ross
32094047d4Gordon Ross	status = smb_oplock_break_SETINFO(
32194047d4Gordon Ross	    &test_node, ofile, infoclass);
32294047d4Gordon Ross	printf(" brk-setinfo %d ret status=0x%x (%s)\n",
32394047d4Gordon Ross	    fid, status, xlate_nt_status(status));
32494047d4Gordon Ross
32594047d4Gordon Ross}
32694047d4Gordon Ross
32794047d4Gordon Ross/*
32894047d4Gordon Ross * Move oplock to another FD, as specified,
32994047d4Gordon Ross * or any other available open
33094047d4Gordon Ross */
33194047d4Gordon Rossstatic void
33294047d4Gordon Rossdo_move(int fid, char *arg2)
33394047d4Gordon Ross{
33494047d4Gordon Ross	smb_ofile_t *ofile = &ofile_array[fid];
33594047d4Gordon Ross	smb_ofile_t *of2;
33694047d4Gordon Ross	int fid2;
33794047d4Gordon Ross
33894047d4Gordon Ross	if (arg2 == NULL) {
33994047d4Gordon Ross		fprintf(stderr, "move: FID2 required\n");
34094047d4Gordon Ross		return;
34194047d4Gordon Ross	}
34294047d4Gordon Ross	fid2 = atoi(arg2);
34394047d4Gordon Ross	if (fid2 <= 0 || fid2 >= MAXFID) {
34494047d4Gordon Ross		fprintf(stderr, "move: bad FID2 %d\n", fid2);
34594047d4Gordon Ross		return;
34694047d4Gordon Ross	}
34794047d4Gordon Ross	of2 = &ofile_array[fid2];
34894047d4Gordon Ross
34994047d4Gordon Ross	smb_oplock_move(&test_node, ofile, of2);
35094047d4Gordon Ross	printf(" move %d %d\n", fid, fid2);
35194047d4Gordon Ross}
35294047d4Gordon Ross
35394047d4Gordon Ross/*
35494047d4Gordon Ross * Set/clear oplock.waiters, which affects ack-break
35594047d4Gordon Ross */
35694047d4Gordon Rossstatic void
35794047d4Gordon Rossdo_waiters(int fid, char *arg2)
35894047d4Gordon Ross{
35994047d4Gordon Ross	smb_node_t *node = &test_node;
36094047d4Gordon Ross	smb_oplock_t *ol = &node->n_oplock;
36194047d4Gordon Ross	int old, new = 0;
36294047d4Gordon Ross
36394047d4Gordon Ross	if (arg2 != NULL)
36494047d4Gordon Ross		new = atoi(arg2);
36594047d4Gordon Ross
36694047d4Gordon Ross	old = ol->waiters;
36794047d4Gordon Ross	ol->waiters = new;
36894047d4Gordon Ross
36994047d4Gordon Ross	printf(" waiters %d -> %d\n", old, new);
37094047d4Gordon Ross}
37194047d4Gordon Ross
37294047d4Gordon Rossint
37394047d4Gordon Rossmain(int argc, char *argv[])
37494047d4Gordon Ross{
37594047d4Gordon Ross	smb_node_t *node = &test_node;
37694047d4Gordon Ross	char *cmd;
37794047d4Gordon Ross	char *arg1;
37894047d4Gordon Ross	char *arg2;
37994047d4Gordon Ross	char *savep;
38094047d4Gordon Ross	char *sep = " \t\n";
38194047d4Gordon Ross	char *prompt = NULL;
38294047d4Gordon Ross	int fid;
38394047d4Gordon Ross
38494047d4Gordon Ross	if (isatty(0))
38594047d4Gordon Ross		prompt = "> ";
38694047d4Gordon Ross
38794047d4Gordon Ross	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
38894047d4Gordon Ross	    offsetof(smb_ofile_t, f_node_lnd));
38994047d4Gordon Ross
39094047d4Gordon Ross	for (fid = 0; fid < MAXFID; fid++) {
39194047d4Gordon Ross		smb_ofile_t *f = &ofile_array[fid];
39294047d4Gordon Ross
39394047d4Gordon Ross		f->f_magic = SMB_OFILE_MAGIC;
39494047d4Gordon Ross		mutex_init(&f->f_mutex, NULL, MUTEX_DEFAULT, NULL);
39594047d4Gordon Ross		f->f_fid = fid;
39694047d4Gordon Ross		f->f_ftype = SMB_FTYPE_DISK;
39794047d4Gordon Ross		f->f_node = &test_node;
39894047d4Gordon Ross	}
39994047d4Gordon Ross
40094047d4Gordon Ross	for (;;) {
40194047d4Gordon Ross		if (prompt) {
402da90d5bJohn Levon			(void) fputs(prompt, stdout);
40394047d4Gordon Ross			fflush(stdout);
40494047d4Gordon Ross		}
40594047d4Gordon Ross
40694047d4Gordon Ross		cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
40794047d4Gordon Ross		if (cmd == NULL)
40894047d4Gordon Ross			break;
40994047d4Gordon Ross		if (cmd[0] == '#')
41094047d4Gordon Ross			continue;
41194047d4Gordon Ross
41294047d4Gordon Ross		if (prompt == NULL) {
41394047d4Gordon Ross			/* Put commands in the output too. */
414da90d5bJohn Levon			(void) fputs(cmdbuf, stdout);
41594047d4Gordon Ross		}
41694047d4Gordon Ross		cmd = strtok_r(cmd, sep, &savep);
41794047d4Gordon Ross		if (cmd == NULL)
41894047d4Gordon Ross			continue;
41994047d4Gordon Ross
42094047d4Gordon Ross		/*
42194047d4Gordon Ross		 * Commands with no args
42294047d4Gordon Ross		 */
42394047d4Gordon Ross		if (0 == strcmp(cmd, "help")) {
424da90d5bJohn Levon			(void) fputs(helpstr, stdout);
42594047d4Gordon Ross			continue;
42694047d4Gordon Ross		}
42794047d4Gordon Ross
42894047d4Gordon Ross		if (0 == strcmp(cmd, "show")) {
42994047d4Gordon Ross			do_show();
43094047d4Gordon Ross			continue;
43194047d4Gordon Ross		}
43294047d4Gordon Ross
43394047d4Gordon Ross		/*
43494047d4Gordon Ross		 * Commands with one arg (the FID)
43594047d4Gordon Ross		 */
43694047d4Gordon Ross		arg1 = strtok_r(NULL, sep, &savep);
43794047d4Gordon Ross		if (arg1 == NULL) {
43894047d4Gordon Ross			fprintf(stderr, "%s missing arg1\n", cmd);
43994047d4Gordon Ross			continue;
44094047d4Gordon Ross		}
44194047d4Gordon Ross		fid = atoi(arg1);
44294047d4Gordon Ross		if (fid <= 0 || fid >= MAXFID) {
44394047d4Gordon Ross			fprintf(stderr, "%s bad FID %d\n", cmd, fid);
44494047d4Gordon Ross			continue;
44594047d4Gordon Ross		}
44694047d4Gordon Ross
44794047d4Gordon Ross		if (0 == strcmp(cmd, "close")) {
44894047d4Gordon Ross			do_close(fid);
44994047d4Gordon Ross			continue;
45094047d4Gordon Ross		}
45194047d4Gordon Ross		if (0 == strcmp(cmd, "brk-parent")) {
45294047d4Gordon Ross			do_brk_parent(fid);
45394047d4Gordon Ross			continue;
45494047d4Gordon Ross		}
45594047d4Gordon Ross		if (0 == strcmp(cmd, "brk-handle")) {
45694047d4Gordon Ross			do_brk_handle(fid);
45794047d4Gordon Ross			continue;
45894047d4Gordon Ross		}
45994047d4Gordon Ross		if (0 == strcmp(cmd, "brk-read")) {
46094047d4Gordon Ross			do_brk_read(fid);
46194047d4Gordon Ross			continue;
46294047d4Gordon Ross		}
46394047d4Gordon Ross		if (0 == strcmp(cmd, "brk-write")) {
46494047d4Gordon Ross			do_brk_write(fid);
46594047d4Gordon Ross			continue;
46694047d4Gordon Ross		}
46794047d4Gordon Ross
46894047d4Gordon Ross		/*
46994047d4Gordon Ross		 * Commands with an (optional) arg2.
47094047d4Gordon Ross		 */
47194047d4Gordon Ross		arg2 = strtok_r(NULL, sep, &savep);
47294047d4Gordon Ross
47394047d4Gordon Ross		if (0 == strcmp(cmd, "open")) {
47494047d4Gordon Ross			do_open(fid, arg2);
47594047d4Gordon Ross			continue;
47694047d4Gordon Ross		}
47794047d4Gordon Ross		if (0 == strcmp(cmd, "req")) {
47894047d4Gordon Ross			do_req(fid, arg2);
47994047d4Gordon Ross			continue;
48094047d4Gordon Ross		}
48194047d4Gordon Ross		if (0 == strcmp(cmd, "ack")) {
48294047d4Gordon Ross			do_ack(fid, arg2);
48394047d4Gordon Ross			continue;
48494047d4Gordon Ross		}
48594047d4Gordon Ross		if (0 == strcmp(cmd, "brk-open")) {
48694047d4Gordon Ross			do_brk_open(fid, arg2);
48794047d4Gordon Ross			continue;
48894047d4Gordon Ross		}
48994047d4Gordon Ross		if (0 == strcmp(cmd, "brk-setinfo")) {
49094047d4Gordon Ross			do_brk_setinfo(fid, arg2);
49194047d4Gordon Ross			continue;
49294047d4Gordon Ross		}
49394047d4Gordon Ross		if (0 == strcmp(cmd, "move")) {
49494047d4Gordon Ross			do_move(fid, arg2);
49594047d4Gordon Ross			continue;
49694047d4Gordon Ross		}
49794047d4Gordon Ross		if (0 == strcmp(cmd, "waiters")) {
49894047d4Gordon Ross			do_waiters(fid, arg2);
49994047d4Gordon Ross			continue;
50094047d4Gordon Ross		}
50194047d4Gordon Ross
50294047d4Gordon Ross		fprintf(stderr, "%s unknown command. Try help\n", cmd);
50394047d4Gordon Ross	}
50494047d4Gordon Ross	return (0);
50594047d4Gordon Ross}
50694047d4Gordon Ross
50794047d4Gordon Ross/*
50894047d4Gordon Ross * A few functions called by the oplock code
50994047d4Gordon Ross * Stubbed out, and/or just print a message.
51094047d4Gordon Ross */
51194047d4Gordon Ross
51294047d4Gordon Rossboolean_t
51394047d4Gordon Rosssmb_node_is_file(smb_node_t *node)
51494047d4Gordon Ross{
51594047d4Gordon Ross	return (B_TRUE);
51694047d4Gordon Ross}
51794047d4Gordon Ross
51894047d4Gordon Rossboolean_t
51994047d4Gordon Rosssmb_ofile_is_open(smb_ofile_t *ofile)
52094047d4Gordon Ross{
52194047d4Gordon Ross	return (ofile->f_refcnt != 0);
52294047d4Gordon Ross}
52394047d4Gordon Ross
52494047d4Gordon Rossint
52594047d4Gordon Rosssmb_lock_range_access(
52694047d4Gordon Ross    smb_request_t	*sr,
52794047d4Gordon Ross    smb_node_t		*node,
52894047d4Gordon Ross    uint64_t		start,
52994047d4Gordon Ross    uint64_t		length,
53094047d4Gordon Ross    boolean_t		will_write)
53194047d4Gordon Ross{
53294047d4Gordon Ross	return (0);
53394047d4Gordon Ross}
53494047d4Gordon Ross
53594047d4Gordon Ross/*
53694047d4Gordon Ross * Test code replacement for: smb_oplock_send_brk()
53794047d4Gordon Ross */
53894047d4Gordon Rossstatic void
53994047d4Gordon Rosstest_oplock_send_brk(smb_ofile_t *ofile,
54094047d4Gordon Ross    uint32_t NewLevel, boolean_t AckReq)
54194047d4Gordon Ross{
54294047d4Gordon Ross	smb_oplock_grant_t *og = &ofile->f_oplock;
54394047d4Gordon Ross
54494047d4Gordon Ross	/* Skip building a message. */
54594047d4Gordon Ross
54694047d4Gordon Ross	if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0)
54794047d4Gordon Ross		NewLevel |= OPLOCK_LEVEL_GRANULAR;
54894047d4Gordon Ross
54994047d4Gordon Ross	/*
55094047d4Gordon Ross	 * In a real server, we would send a break to the client,
55194047d4Gordon Ross	 * and keep track (at the SMB level) whether this oplock
55294047d4Gordon Ross	 * was obtained via a lease or an old-style oplock.
55394047d4Gordon Ross	 */
55494047d4Gordon Ross	if (AckReq) {
55594047d4Gordon Ross		uint32_t BreakTo;
55694047d4Gordon Ross
55794047d4Gordon Ross		if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0) {
55894047d4Gordon Ross
55994047d4Gordon Ross			BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT;
56094047d4Gordon Ross			if (BreakTo == 0)
56194047d4Gordon Ross				BreakTo = BREAK_TO_NO_CACHING;
56294047d4Gordon Ross		} else {
56394047d4Gordon Ross			if ((NewLevel & LEVEL_TWO_OPLOCK) != 0)
56494047d4Gordon Ross				BreakTo = BREAK_TO_TWO;
56594047d4Gordon Ross			else
56694047d4Gordon Ross				BreakTo = BREAK_TO_NONE;
56794047d4Gordon Ross		}
56894047d4Gordon Ross		og->og_breaking = BreakTo;
56994047d4Gordon Ross		last_ind_break_level = NewLevel;
57094047d4Gordon Ross		/* Set og_state in  do_ack */
57194047d4Gordon Ross	} else {
57294047d4Gordon Ross		og->og_state = NewLevel;
57394047d4Gordon Ross		/* Clear og_breaking in do_ack */
57494047d4Gordon Ross	}
57594047d4Gordon Ross}
57694047d4Gordon Ross
57794047d4Gordon Ross/*
57894047d4Gordon Ross * Simplified version of what's in smb_srv_oplock.c
57994047d4Gordon Ross */
58094047d4Gordon Rossvoid
58194047d4Gordon Rosssmb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
58294047d4Gordon Ross    boolean_t AckReq, uint32_t status)
58394047d4Gordon Ross{
58494047d4Gordon Ross	smb_oplock_grant_t *og = &ofile->f_oplock;
58594047d4Gordon Ross
58694047d4Gordon Ross	printf("*smb_oplock_ind_break fid=%d NewLevel=0x%x,"
58794047d4Gordon Ross	    " AckReq=%d, ComplStatus=0x%x (%s)\n",
58894047d4Gordon Ross	    ofile->f_fid, NewLevel, AckReq,
58994047d4Gordon Ross	    status, xlate_nt_status(status));
59094047d4Gordon Ross
59194047d4Gordon Ross	/*
59294047d4Gordon Ross	 * Note that the CompletionStatus from the FS level
59394047d4Gordon Ross	 * (smb_cmn_oplock.c) encodes what kind of action we
59494047d4Gordon Ross	 * need to take at the SMB level.
59594047d4Gordon Ross	 */
59694047d4Gordon Ross	switch (status) {
59794047d4Gordon Ross
59894047d4Gordon Ross	case NT_STATUS_SUCCESS:
59994047d4Gordon Ross	case NT_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK:
60094047d4Gordon Ross		test_oplock_send_brk(ofile, NewLevel, AckReq);
60194047d4Gordon Ross		break;
60294047d4Gordon Ross
60394047d4Gordon Ross	case NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE:
60494047d4Gordon Ross	case NT_STATUS_OPLOCK_HANDLE_CLOSED:
60594047d4Gordon Ross		og->og_state = OPLOCK_LEVEL_NONE;
60694047d4Gordon Ross		break;
60794047d4Gordon Ross
60894047d4Gordon Ross	default:
60994047d4Gordon Ross		/* Checked by caller. */
61094047d4Gordon Ross		ASSERT(0);
61194047d4Gordon Ross		break;
61294047d4Gordon Ross	}
61394047d4Gordon Ross}
61494047d4Gordon Ross
61594047d4Gordon Rossvoid
61694047d4Gordon Rosssmb_oplock_ind_break_in_ack(smb_request_t *sr, smb_ofile_t *ofile,
61794047d4Gordon Ross    uint32_t NewLevel, boolean_t AckRequired)
61894047d4Gordon Ross{
61994047d4Gordon Ross	ASSERT(sr == &test_sr);
62094047d4Gordon Ross	smb_oplock_ind_break(ofile, NewLevel, AckRequired, STATUS_CANT_GRANT);
62194047d4Gordon Ross}
62294047d4Gordon Ross
62394047d4Gordon Rossuint32_t
62494047d4Gordon Rosssmb_oplock_wait_break(smb_node_t *node, int timeout)
62594047d4Gordon Ross{
62694047d4Gordon Ross	printf("*smb_oplock_wait_break (state=0x%x)\n",
62794047d4Gordon Ross	    node->n_oplock.ol_state);
62894047d4Gordon Ross	return (0);
62994047d4Gordon Ross}
63094047d4Gordon Ross
63194047d4Gordon Ross/*
63294047d4Gordon Ross * There are a couple DTRACE_PROBE* in smb_cmn_oplock.c but we're
63394047d4Gordon Ross * not linking with the user-level dtrace support, so just
63494047d4Gordon Ross * stub these out.
63594047d4Gordon Ross */
63694047d4Gordon Rossvoid
63794047d4Gordon Ross__dtrace_fksmb___probe1(char *n, unsigned long a)
63894047d4Gordon Ross{
63994047d4Gordon Ross}
64094047d4Gordon Rossvoid
64194047d4Gordon Ross__dtrace_fksmb___probe2(char *n, unsigned long a, unsigned long b)
64294047d4Gordon Ross{
64394047d4Gordon Ross}
644