Print this page
11227 smb code needs smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/smbsrv/testoplock/tol_main.c
+++ new/usr/src/cmd/smbsrv/testoplock/tol_main.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 + * Copyright 2019 Joyent, Inc.
14 15 */
15 16
16 17 /*
17 18 * Test & debug program for oplocks
18 19 *
19 20 * This implements a simple command reader which accepts
20 21 * commands to simulate oplock events, and prints the
21 22 * state changes and actions that would happen after
22 23 * each event.
23 24 */
24 25
25 26 #include <sys/types.h>
26 27 #include <sys/debug.h>
27 28 #include <sys/stddef.h>
28 29 #include <stdio.h>
29 30 #include <stdlib.h>
30 31 #include <string.h>
31 32 #include <strings.h>
32 33 #include <unistd.h>
33 34
34 35 #include <smbsrv/smb_kproto.h>
35 36 #include <smbsrv/smb_oplock.h>
36 37
37 38 #define OPLOCK_CACHE_RWH (READ_CACHING | HANDLE_CACHING | WRITE_CACHING)
38 39 #define OPLOCK_TYPE (LEVEL_TWO_OPLOCK | LEVEL_ONE_OPLOCK |\
39 40 BATCH_OPLOCK | OPLOCK_LEVEL_GRANULAR)
40 41
41 42 #define MAXFID 10
42 43
43 44 smb_node_t root_node, test_node;
44 45 smb_ofile_t ofile_array[MAXFID];
45 46 smb_request_t test_sr;
46 47 uint32_t last_ind_break_level;
47 48 char cmdbuf[100];
48 49
49 50 extern const char *xlate_nt_status(uint32_t);
50 51
51 52 #define BIT_DEF(name) { name, #name }
52 53
53 54 struct bit_defs {
54 55 uint32_t mask;
55 56 const char *name;
56 57 } state_bits[] = {
57 58 BIT_DEF(NO_OPLOCK),
58 59 BIT_DEF(BREAK_TO_NO_CACHING),
59 60 BIT_DEF(BREAK_TO_WRITE_CACHING),
60 61 BIT_DEF(BREAK_TO_HANDLE_CACHING),
61 62 BIT_DEF(BREAK_TO_READ_CACHING),
62 63 BIT_DEF(BREAK_TO_TWO_TO_NONE),
63 64 BIT_DEF(BREAK_TO_NONE),
64 65 BIT_DEF(BREAK_TO_TWO),
65 66 BIT_DEF(BATCH_OPLOCK),
66 67 BIT_DEF(LEVEL_ONE_OPLOCK),
67 68 BIT_DEF(LEVEL_TWO_OPLOCK),
68 69 BIT_DEF(MIXED_R_AND_RH),
69 70 BIT_DEF(EXCLUSIVE),
70 71 BIT_DEF(WRITE_CACHING),
71 72 BIT_DEF(HANDLE_CACHING),
72 73 BIT_DEF(READ_CACHING),
73 74 { 0, NULL }
74 75 };
75 76
76 77 /*
77 78 * Helper to print flags fields
78 79 */
79 80 static void
80 81 print_bits32(char *label, struct bit_defs *bit, uint32_t state)
81 82 {
82 83 printf("%s0x%x (", label, state);
83 84 while (bit->mask != 0) {
84 85 if ((state & bit->mask) != 0)
85 86 printf(" %s", bit->name);
86 87 bit++;
87 88 }
88 89 printf(" )\n");
89 90 }
90 91
91 92 /*
92 93 * Command language:
93 94 *
94 95 */
95 96 const char helpstr[] = "Commands:\n"
96 97 "help\t\tList commands\n"
97 98 "show\t\tShow OpLock state etc.\n"
98 99 "open FID\n"
99 100 "close FID\n"
100 101 "req FID [OplockLevel]\n"
101 102 "ack FID [OplockLevel]\n"
102 103 "brk-parent FID\n"
103 104 "brk-open [OverWrite]\n"
104 105 "brk-handle FID\n"
105 106 "brk-read FID\n"
106 107 "brk-write FID\n"
107 108 "brk-setinfo FID [InfoClass]\n"
108 109 "move FID1 FID2\n"
109 110 "waiters FID [count]\n";
110 111
111 112 /*
112 113 * Command handlers
113 114 */
114 115
115 116 static void
116 117 do_show(void)
117 118 {
118 119 smb_node_t *node = &test_node;
119 120 smb_oplock_t *ol = &node->n_oplock;
120 121 uint32_t state = ol->ol_state;
121 122 smb_ofile_t *f;
122 123
123 124 print_bits32(" ol_state=", state_bits, state);
124 125
125 126 if (ol->excl_open != NULL)
126 127 printf(" Excl=Y (FID=%d)", ol->excl_open->f_fid);
127 128 else
128 129 printf(" Excl=n");
129 130 printf(" cnt_II=%d cnt_R=%d cnt_RH=%d cnt_RHBQ=%d\n",
130 131 ol->cnt_II, ol->cnt_R, ol->cnt_RH, ol->cnt_RHBQ);
131 132
132 133 printf(" ofile_cnt=%d\n", node->n_ofile_list.ll_count);
133 134 FOREACH_NODE_OFILE(node, f) {
134 135 smb_oplock_grant_t *og = &f->f_oplock;
135 136 printf(" fid=%d Lease=%s OgState=0x%x Brk=0x%x",
136 137 f->f_fid,
137 138 f->TargetOplockKey, /* lease */
138 139 f->f_oplock.og_state,
139 140 f->f_oplock.og_breaking);
140 141 printf(" Excl=%s onlist: %s %s %s",
141 142 (ol->excl_open == f) ? "Y" : "N",
142 143 og->onlist_II ? "II" : "",
143 144 og->onlist_R ? "R" : "",
144 145 og->onlist_RH ? "RH" : "");
145 146 if (og->onlist_RHBQ) {
146 147 printf(" RHBQ(to %s)",
147 148 og->BreakingToRead ?
148 149 "read" : "none");
149 150 }
150 151 printf("\n");
151 152 }
152 153 }
153 154
154 155 static void
155 156 do_open(int fid, char *arg2)
156 157 {
157 158 smb_node_t *node = &test_node;
↓ open down ↓ |
134 lines elided |
↑ open up ↑ |
158 159 smb_ofile_t *ofile = &ofile_array[fid];
159 160
160 161 /*
161 162 * Simulate an open (minimal init)
162 163 */
163 164 if (ofile->f_refcnt) {
164 165 printf("open fid %d already opened\n");
165 166 return;
166 167 }
167 168
168 - if (arg2 != NULL)
169 - strlcpy((char *)ofile->TargetOplockKey, arg2,
169 + if (arg2 != NULL) {
170 + (void) strlcpy((char *)ofile->TargetOplockKey, arg2,
170 171 SMB_LEASE_KEY_SZ);
172 + }
171 173
172 174 ofile->f_refcnt++;
173 175 node->n_open_count++;
174 176 smb_llist_insert_tail(&node->n_ofile_list, ofile);
175 177 printf(" open %d OK\n", fid);
176 178 }
177 179
178 180 static void
179 181 do_close(int fid)
180 182 {
181 183 smb_node_t *node = &test_node;
182 184 smb_ofile_t *ofile = &ofile_array[fid];
183 185
184 186 /*
185 187 * Simulate an close
186 188 */
187 189 if (ofile->f_refcnt <= 0) {
188 190 printf(" close fid %d already closed\n");
189 191 return;
190 192 }
191 193 smb_oplock_break_CLOSE(ofile->f_node, ofile);
192 194
193 195 smb_llist_remove(&node->n_ofile_list, ofile);
194 196 node->n_open_count--;
195 197 ofile->f_refcnt--;
196 198
197 199 bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ);
198 200
199 201 printf(" close OK\n");
200 202 }
201 203
202 204 static void
203 205 do_req(int fid, char *arg2)
204 206 {
205 207 smb_ofile_t *ofile = &ofile_array[fid];
206 208 uint32_t oplock = BATCH_OPLOCK;
207 209 uint32_t status;
208 210
209 211 if (arg2 != NULL)
210 212 oplock = strtol(arg2, NULL, 16);
211 213
212 214 /*
213 215 * Request an oplock
214 216 */
215 217 status = smb_oplock_request(&test_sr, ofile, &oplock);
216 218 if (status == 0)
217 219 ofile->f_oplock.og_state = oplock;
218 220 printf(" req oplock fid=%d ret oplock=0x%x status=0x%x (%s)\n",
219 221 fid, oplock, status, xlate_nt_status(status));
220 222 }
221 223
222 224
223 225 static void
224 226 do_ack(int fid, char *arg2)
225 227 {
226 228 smb_ofile_t *ofile = &ofile_array[fid];
227 229 uint32_t oplock;
228 230 uint32_t status;
229 231
230 232 /* Default to level in last smb_oplock_ind_break() */
231 233 oplock = last_ind_break_level;
232 234 if (arg2 != NULL)
233 235 oplock = strtol(arg2, NULL, 16);
234 236
235 237 ofile->f_oplock.og_breaking = 0;
236 238 status = smb_oplock_ack_break(&test_sr, ofile, &oplock);
237 239 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
238 240 printf(" ack: break fid=%d, break-in-progress\n", fid);
239 241 ofile->f_oplock.og_state = oplock;
240 242 }
241 243 if (status == 0)
242 244 ofile->f_oplock.og_state = oplock;
243 245
244 246 printf(" ack: break fid=%d, newstate=0x%x, status=0x%x (%s)\n",
245 247 fid, oplock, status, xlate_nt_status(status));
246 248 }
247 249
248 250 static void
249 251 do_brk_parent(int fid)
250 252 {
251 253 smb_ofile_t *ofile = &ofile_array[fid];
252 254 uint32_t status;
253 255
254 256 status = smb_oplock_break_PARENT(&test_node, ofile);
255 257 printf(" brk-parent %d ret status=0x%x (%s)\n",
256 258 fid, status, xlate_nt_status(status));
257 259 }
258 260
259 261 static void
260 262 do_brk_open(int fid, char *arg2)
261 263 {
262 264 smb_ofile_t *ofile = &ofile_array[fid];
263 265 uint32_t status;
264 266 int disp = FILE_OPEN;
265 267
266 268 if (arg2 != NULL)
267 269 disp = strtol(arg2, NULL, 16);
268 270
269 271 status = smb_oplock_break_OPEN(&test_node, ofile, 7, disp);
270 272 printf(" brk-open %d ret status=0x%x (%s)\n",
271 273 fid, status, xlate_nt_status(status));
272 274 }
273 275
274 276 static void
275 277 do_brk_handle(int fid)
276 278 {
277 279 smb_ofile_t *ofile = &ofile_array[fid];
278 280 uint32_t status;
279 281
280 282 status = smb_oplock_break_HANDLE(&test_node, ofile);
281 283 printf(" brk-handle %d ret status=0x%x (%s)\n",
282 284 fid, status, xlate_nt_status(status));
283 285
284 286 }
285 287
286 288 static void
287 289 do_brk_read(int fid)
288 290 {
289 291 smb_ofile_t *ofile = &ofile_array[fid];
290 292 uint32_t status;
291 293
292 294 status = smb_oplock_break_READ(ofile->f_node, ofile);
293 295 printf(" brk-read %d ret status=0x%x (%s)\n",
294 296 fid, status, xlate_nt_status(status));
295 297 }
296 298
297 299 static void
298 300 do_brk_write(int fid)
299 301 {
300 302 smb_ofile_t *ofile = &ofile_array[fid];
301 303 uint32_t status;
302 304
303 305 status = smb_oplock_break_WRITE(ofile->f_node, ofile);
304 306 printf(" brk-write %d ret status=0x%x (%s)\n",
305 307 fid, status, xlate_nt_status(status));
306 308 }
307 309
308 310 static void
309 311 do_brk_setinfo(int fid, char *arg2)
310 312 {
311 313 smb_ofile_t *ofile = &ofile_array[fid];
312 314 uint32_t status;
313 315 int infoclass = FileEndOfFileInformation; /* 20 */
314 316
315 317 if (arg2 != NULL)
316 318 infoclass = strtol(arg2, NULL, 16);
317 319
318 320 status = smb_oplock_break_SETINFO(
319 321 &test_node, ofile, infoclass);
320 322 printf(" brk-setinfo %d ret status=0x%x (%s)\n",
321 323 fid, status, xlate_nt_status(status));
322 324
323 325 }
324 326
325 327 /*
326 328 * Move oplock to another FD, as specified,
327 329 * or any other available open
328 330 */
329 331 static void
330 332 do_move(int fid, char *arg2)
331 333 {
332 334 smb_ofile_t *ofile = &ofile_array[fid];
333 335 smb_ofile_t *of2;
334 336 int fid2;
335 337
336 338 if (arg2 == NULL) {
337 339 fprintf(stderr, "move: FID2 required\n");
338 340 return;
339 341 }
340 342 fid2 = atoi(arg2);
341 343 if (fid2 <= 0 || fid2 >= MAXFID) {
342 344 fprintf(stderr, "move: bad FID2 %d\n", fid2);
343 345 return;
344 346 }
345 347 of2 = &ofile_array[fid2];
346 348
347 349 smb_oplock_move(&test_node, ofile, of2);
348 350 printf(" move %d %d\n", fid, fid2);
349 351 }
350 352
351 353 /*
352 354 * Set/clear oplock.waiters, which affects ack-break
353 355 */
354 356 static void
355 357 do_waiters(int fid, char *arg2)
356 358 {
357 359 smb_node_t *node = &test_node;
358 360 smb_oplock_t *ol = &node->n_oplock;
359 361 int old, new = 0;
360 362
361 363 if (arg2 != NULL)
362 364 new = atoi(arg2);
363 365
364 366 old = ol->waiters;
365 367 ol->waiters = new;
366 368
367 369 printf(" waiters %d -> %d\n", old, new);
368 370 }
369 371
370 372 int
371 373 main(int argc, char *argv[])
372 374 {
373 375 smb_node_t *node = &test_node;
374 376 char *cmd;
375 377 char *arg1;
376 378 char *arg2;
377 379 char *savep;
378 380 char *sep = " \t\n";
379 381 char *prompt = NULL;
380 382 int fid;
381 383
382 384 if (isatty(0))
383 385 prompt = "> ";
384 386
385 387 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
386 388 offsetof(smb_ofile_t, f_node_lnd));
387 389
388 390 for (fid = 0; fid < MAXFID; fid++) {
389 391 smb_ofile_t *f = &ofile_array[fid];
↓ open down ↓ |
209 lines elided |
↑ open up ↑ |
390 392
391 393 f->f_magic = SMB_OFILE_MAGIC;
392 394 mutex_init(&f->f_mutex, NULL, MUTEX_DEFAULT, NULL);
393 395 f->f_fid = fid;
394 396 f->f_ftype = SMB_FTYPE_DISK;
395 397 f->f_node = &test_node;
396 398 }
397 399
398 400 for (;;) {
399 401 if (prompt) {
400 - fputs(prompt, stdout);
402 + (void) fputs(prompt, stdout);
401 403 fflush(stdout);
402 404 }
403 405
404 406 cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
405 407 if (cmd == NULL)
406 408 break;
407 409 if (cmd[0] == '#')
408 410 continue;
409 411
410 412 if (prompt == NULL) {
411 413 /* Put commands in the output too. */
412 - fputs(cmdbuf, stdout);
414 + (void) fputs(cmdbuf, stdout);
413 415 }
414 416 cmd = strtok_r(cmd, sep, &savep);
415 417 if (cmd == NULL)
416 418 continue;
417 419
418 420 /*
419 421 * Commands with no args
420 422 */
421 423 if (0 == strcmp(cmd, "help")) {
422 - fputs(helpstr, stdout);
424 + (void) fputs(helpstr, stdout);
423 425 continue;
424 426 }
425 427
426 428 if (0 == strcmp(cmd, "show")) {
427 429 do_show();
428 430 continue;
429 431 }
430 432
431 433 /*
432 434 * Commands with one arg (the FID)
433 435 */
434 436 arg1 = strtok_r(NULL, sep, &savep);
435 437 if (arg1 == NULL) {
436 438 fprintf(stderr, "%s missing arg1\n", cmd);
437 439 continue;
438 440 }
439 441 fid = atoi(arg1);
440 442 if (fid <= 0 || fid >= MAXFID) {
441 443 fprintf(stderr, "%s bad FID %d\n", cmd, fid);
442 444 continue;
443 445 }
444 446
445 447 if (0 == strcmp(cmd, "close")) {
446 448 do_close(fid);
447 449 continue;
448 450 }
449 451 if (0 == strcmp(cmd, "brk-parent")) {
450 452 do_brk_parent(fid);
451 453 continue;
452 454 }
453 455 if (0 == strcmp(cmd, "brk-handle")) {
454 456 do_brk_handle(fid);
455 457 continue;
456 458 }
457 459 if (0 == strcmp(cmd, "brk-read")) {
458 460 do_brk_read(fid);
459 461 continue;
460 462 }
461 463 if (0 == strcmp(cmd, "brk-write")) {
462 464 do_brk_write(fid);
463 465 continue;
464 466 }
465 467
466 468 /*
467 469 * Commands with an (optional) arg2.
468 470 */
469 471 arg2 = strtok_r(NULL, sep, &savep);
470 472
471 473 if (0 == strcmp(cmd, "open")) {
472 474 do_open(fid, arg2);
473 475 continue;
474 476 }
475 477 if (0 == strcmp(cmd, "req")) {
476 478 do_req(fid, arg2);
477 479 continue;
478 480 }
479 481 if (0 == strcmp(cmd, "ack")) {
480 482 do_ack(fid, arg2);
481 483 continue;
482 484 }
483 485 if (0 == strcmp(cmd, "brk-open")) {
484 486 do_brk_open(fid, arg2);
485 487 continue;
486 488 }
487 489 if (0 == strcmp(cmd, "brk-setinfo")) {
488 490 do_brk_setinfo(fid, arg2);
489 491 continue;
490 492 }
491 493 if (0 == strcmp(cmd, "move")) {
492 494 do_move(fid, arg2);
493 495 continue;
494 496 }
495 497 if (0 == strcmp(cmd, "waiters")) {
496 498 do_waiters(fid, arg2);
497 499 continue;
498 500 }
499 501
500 502 fprintf(stderr, "%s unknown command. Try help\n", cmd);
501 503 }
502 504 return (0);
503 505 }
504 506
505 507 /*
506 508 * A few functions called by the oplock code
507 509 * Stubbed out, and/or just print a message.
508 510 */
509 511
510 512 boolean_t
511 513 smb_node_is_file(smb_node_t *node)
512 514 {
513 515 return (B_TRUE);
514 516 }
515 517
516 518 boolean_t
517 519 smb_ofile_is_open(smb_ofile_t *ofile)
518 520 {
519 521 return (ofile->f_refcnt != 0);
520 522 }
521 523
522 524 int
523 525 smb_lock_range_access(
524 526 smb_request_t *sr,
525 527 smb_node_t *node,
526 528 uint64_t start,
527 529 uint64_t length,
528 530 boolean_t will_write)
529 531 {
530 532 return (0);
531 533 }
532 534
533 535 /*
534 536 * Test code replacement for: smb_oplock_send_brk()
535 537 */
536 538 static void
537 539 test_oplock_send_brk(smb_ofile_t *ofile,
538 540 uint32_t NewLevel, boolean_t AckReq)
539 541 {
540 542 smb_oplock_grant_t *og = &ofile->f_oplock;
541 543
542 544 /* Skip building a message. */
543 545
544 546 if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0)
545 547 NewLevel |= OPLOCK_LEVEL_GRANULAR;
546 548
547 549 /*
548 550 * In a real server, we would send a break to the client,
549 551 * and keep track (at the SMB level) whether this oplock
550 552 * was obtained via a lease or an old-style oplock.
551 553 */
552 554 if (AckReq) {
553 555 uint32_t BreakTo;
554 556
555 557 if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0) {
556 558
557 559 BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT;
558 560 if (BreakTo == 0)
559 561 BreakTo = BREAK_TO_NO_CACHING;
560 562 } else {
561 563 if ((NewLevel & LEVEL_TWO_OPLOCK) != 0)
562 564 BreakTo = BREAK_TO_TWO;
563 565 else
564 566 BreakTo = BREAK_TO_NONE;
565 567 }
566 568 og->og_breaking = BreakTo;
567 569 last_ind_break_level = NewLevel;
568 570 /* Set og_state in do_ack */
569 571 } else {
570 572 og->og_state = NewLevel;
571 573 /* Clear og_breaking in do_ack */
572 574 }
573 575 }
574 576
575 577 /*
576 578 * Simplified version of what's in smb_srv_oplock.c
577 579 */
578 580 void
579 581 smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
580 582 boolean_t AckReq, uint32_t status)
581 583 {
582 584 smb_oplock_grant_t *og = &ofile->f_oplock;
583 585
584 586 printf("*smb_oplock_ind_break fid=%d NewLevel=0x%x,"
585 587 " AckReq=%d, ComplStatus=0x%x (%s)\n",
586 588 ofile->f_fid, NewLevel, AckReq,
587 589 status, xlate_nt_status(status));
588 590
589 591 /*
590 592 * Note that the CompletionStatus from the FS level
591 593 * (smb_cmn_oplock.c) encodes what kind of action we
592 594 * need to take at the SMB level.
593 595 */
594 596 switch (status) {
595 597
596 598 case NT_STATUS_SUCCESS:
597 599 case NT_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK:
598 600 test_oplock_send_brk(ofile, NewLevel, AckReq);
599 601 break;
600 602
601 603 case NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE:
602 604 case NT_STATUS_OPLOCK_HANDLE_CLOSED:
603 605 og->og_state = OPLOCK_LEVEL_NONE;
604 606 break;
605 607
606 608 default:
607 609 /* Checked by caller. */
608 610 ASSERT(0);
609 611 break;
610 612 }
611 613 }
612 614
613 615 void
614 616 smb_oplock_ind_break_in_ack(smb_request_t *sr, smb_ofile_t *ofile,
615 617 uint32_t NewLevel, boolean_t AckRequired)
616 618 {
617 619 ASSERT(sr == &test_sr);
618 620 smb_oplock_ind_break(ofile, NewLevel, AckRequired, STATUS_CANT_GRANT);
619 621 }
620 622
621 623 uint32_t
622 624 smb_oplock_wait_break(smb_node_t *node, int timeout)
623 625 {
624 626 printf("*smb_oplock_wait_break (state=0x%x)\n",
625 627 node->n_oplock.ol_state);
626 628 return (0);
627 629 }
628 630
629 631 /*
630 632 * There are a couple DTRACE_PROBE* in smb_cmn_oplock.c but we're
631 633 * not linking with the user-level dtrace support, so just
632 634 * stub these out.
633 635 */
634 636 void
635 637 __dtrace_fksmb___probe1(char *n, unsigned long a)
636 638 {
637 639 }
638 640 void
639 641 __dtrace_fksmb___probe2(char *n, unsigned long a, unsigned long b)
640 642 {
641 643 }
↓ open down ↓ |
209 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX