Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3620 need upstream cleanups for smbsrv
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
SMB-58 smbsrv should be immune to its own FEM hooks
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_fem.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_fem.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 24 * Copyright 2015 Joyent, Inc.
25 25 */
26 26
27 27 #include <smbsrv/smb_kproto.h>
28 28 #include <smbsrv/smb_fsops.h>
29 29 #include <sys/sdt.h>
30 30 #include <sys/fcntl.h>
31 31 #include <sys/vfs.h>
32 32 #include <sys/vfs_opreg.h>
33 33 #include <sys/vnode.h>
34 34 #include <sys/fem.h>
35 35
36 36 extern caller_context_t smb_ct;
37 37
38 38 static boolean_t smb_fem_initialized = B_FALSE;
39 39 static fem_t *smb_fcn_ops = NULL;
40 40 static fem_t *smb_oplock_ops = NULL;
41 41
42 42 /*
43 43 * Declarations for FCN (file change notification) FEM monitors
44 44 */
45 45
46 46 static int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
47 47 vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
48 48 static int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
49 49 caller_context_t *, int);
50 50 static int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
51 51 cred_t *, caller_context_t *, int);
52 52 static int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
53 53 cred_t *, caller_context_t *, int, vsecattr_t *);
54 54 static int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
55 55 caller_context_t *, int);
56 56 static int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
57 57 caller_context_t *, int);
58 58 static int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
59 59 char *, cred_t *, caller_context_t *, int);
60 60
61 61 static const fs_operation_def_t smb_fcn_tmpl[] = {
62 62 VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
63 63 VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
64 64 VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
65 65 VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
66 66 VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
67 67 VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
68 68 VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
69 69 NULL, NULL
70 70 };
71 71
72 72 /*
73 73 * Declarations for oplock FEM monitors
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
74 74 */
75 75
76 76 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
77 77 struct caller_context *);
78 78 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
79 79 struct caller_context *);
80 80 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
81 81 struct caller_context *);
82 82 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
83 83 caller_context_t *);
84 -static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
85 84 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
86 85 offset_t, cred_t *, caller_context_t *);
87 86 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
88 87 caller_context_t *);
89 88
90 89 static const fs_operation_def_t smb_oplock_tmpl[] = {
91 90 VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open },
92 91 VOPNAME_READ, { .femop_read = smb_fem_oplock_read },
93 92 VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write },
94 93 VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
95 - VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
96 94 VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space },
97 95 VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
98 96 NULL, NULL
99 97 };
100 98
101 -static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
99 +static int smb_fem_oplock_wait(smb_node_t *, caller_context_t *);
102 100
103 101 /*
104 102 * smb_fem_init
105 103 *
106 104 * This function is not multi-thread safe. The caller must make sure only one
107 105 * thread makes the call.
108 106 */
109 107 int
110 108 smb_fem_init(void)
111 109 {
112 110 int rc = 0;
113 111
114 112 if (smb_fem_initialized)
115 113 return (0);
116 114
117 115 rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
118 116 if (rc)
119 117 return (rc);
120 118
121 119 rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,
122 120 &smb_oplock_ops);
123 121
124 122 if (rc) {
125 123 fem_free(smb_fcn_ops);
126 124 smb_fcn_ops = NULL;
127 125 return (rc);
128 126 }
129 127
130 128 smb_fem_initialized = B_TRUE;
131 129
132 130 return (0);
133 131 }
134 132
135 133 /*
136 134 * smb_fem_fini
137 135 *
138 136 * This function is not multi-thread safe. The caller must make sure only one
139 137 * thread makes the call.
140 138 */
141 139 void
142 140 smb_fem_fini(void)
143 141 {
144 142 if (!smb_fem_initialized)
145 143 return;
146 144
147 145 if (smb_fcn_ops != NULL) {
|
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
148 146 fem_free(smb_fcn_ops);
149 147 smb_fcn_ops = NULL;
150 148 }
151 149 if (smb_oplock_ops != NULL) {
152 150 fem_free(smb_oplock_ops);
153 151 smb_oplock_ops = NULL;
154 152 }
155 153 smb_fem_initialized = B_FALSE;
156 154 }
157 155
156 +/*
157 + * Install our fem hooks for change notify.
158 + * Not using hold/rele function here because we
159 + * remove the fem hooks before node destroy.
160 + */
158 161 int
159 162 smb_fem_fcn_install(smb_node_t *node)
160 163 {
161 164 int rc;
162 165
163 166 if (smb_fcn_ops == NULL)
164 167 return (ENOSYS);
165 168 rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
166 - (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
169 + NULL, NULL);
167 170 return (rc);
168 171 }
169 172
170 173 void
171 174 smb_fem_fcn_uninstall(smb_node_t *node)
172 175 {
173 176 if (smb_fcn_ops == NULL)
174 177 return;
175 178 VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
176 179 }
177 180
178 181 int
179 182 smb_fem_oplock_install(smb_node_t *node)
180 183 {
181 184 int rc;
182 185
183 186 if (smb_oplock_ops == NULL)
184 187 return (ENOSYS);
185 188 rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
186 189 (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
187 190 return (rc);
188 191 }
189 192
190 193 void
191 194 smb_fem_oplock_uninstall(smb_node_t *node)
192 195 {
193 196 if (smb_oplock_ops == NULL)
194 197 return;
195 198 VERIFY0(fem_uninstall(node->vp, smb_oplock_ops, (void *)node));
196 199 }
197 200
198 201 /*
199 202 * FEM FCN monitors
200 203 *
201 204 * The FCN monitors intercept the respective VOP_* call regardless
202 205 * of whether the call originates from CIFS, NFS, or a local process.
203 206 */
204 207
205 208 /*
206 209 * smb_fem_fcn_create()
207 210 *
208 211 * This monitor will catch only changes to VREG files and not to extended
209 212 * attribute files. This is fine because, for CIFS files, stream creates
210 213 * should not trigger any file change notification on the VDIR directory
211 214 * being monitored. Creates of any other kind of extended attribute in
212 215 * the directory will also not trigger any file change notification on the
213 216 * VDIR directory being monitored.
214 217 */
215 218
216 219 static int
217 220 smb_fem_fcn_create(
218 221 femarg_t *arg,
219 222 char *name,
220 223 vattr_t *vap,
221 224 vcexcl_t excl,
222 225 int mode,
223 226 vnode_t **vpp,
224 227 cred_t *cr,
225 228 int flag,
226 229 caller_context_t *ct,
227 230 vsecattr_t *vsecp)
228 231 {
229 232 smb_node_t *dnode;
230 233 int error;
231 234
232 235 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
233 236
234 237 ASSERT(dnode);
235 238
236 239 error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
237 240 ct, vsecp);
238 241
239 242 if (error == 0 && ct != &smb_ct)
240 243 smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
241 244
242 245 return (error);
243 246 }
244 247
245 248 /*
246 249 * smb_fem_fcn_remove()
247 250 *
248 251 * This monitor will catch only changes to VREG files and to not extended
249 252 * attribute files. This is fine because, for CIFS files, stream deletes
250 253 * should not trigger any file change notification on the VDIR directory
251 254 * being monitored. Deletes of any other kind of extended attribute in
252 255 * the directory will also not trigger any file change notification on the
253 256 * VDIR directory being monitored.
254 257 */
255 258
256 259 static int
257 260 smb_fem_fcn_remove(
258 261 femarg_t *arg,
259 262 char *name,
260 263 cred_t *cr,
261 264 caller_context_t *ct,
262 265 int flags)
263 266 {
264 267 smb_node_t *dnode;
265 268 int error;
266 269
267 270 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
268 271
269 272 ASSERT(dnode);
270 273
271 274 error = vnext_remove(arg, name, cr, ct, flags);
272 275
273 276 if (error == 0 && ct != &smb_ct)
274 277 smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name);
275 278
276 279 return (error);
277 280 }
278 281
279 282 static int
280 283 smb_fem_fcn_rename(
281 284 femarg_t *arg,
282 285 char *snm,
283 286 vnode_t *tdvp,
284 287 char *tnm,
285 288 cred_t *cr,
286 289 caller_context_t *ct,
287 290 int flags)
288 291 {
289 292 smb_node_t *dnode;
290 293 int error;
291 294
292 295 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
293 296
294 297 ASSERT(dnode);
295 298
296 299 error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
297 300
298 301 if (error == 0 && ct != &smb_ct) {
299 302 /*
300 303 * Note that renames in the same directory are normally
301 304 * delivered in {old,new} pairs, and clients expect them
302 305 * in that order, if both events are delivered.
303 306 */
304 307 smb_node_notify_change(dnode,
305 308 FILE_ACTION_RENAMED_OLD_NAME, snm);
306 309 smb_node_notify_change(dnode,
307 310 FILE_ACTION_RENAMED_NEW_NAME, tnm);
308 311 }
309 312
310 313 return (error);
311 314 }
312 315
313 316 static int
314 317 smb_fem_fcn_mkdir(
315 318 femarg_t *arg,
316 319 char *name,
317 320 vattr_t *vap,
318 321 vnode_t **vpp,
319 322 cred_t *cr,
320 323 caller_context_t *ct,
321 324 int flags,
322 325 vsecattr_t *vsecp)
323 326 {
324 327 smb_node_t *dnode;
325 328 int error;
326 329
327 330 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
328 331
329 332 ASSERT(dnode);
330 333
331 334 error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
332 335
333 336 if (error == 0 && ct != &smb_ct)
334 337 smb_node_notify_change(dnode, FILE_ACTION_ADDED, name);
335 338
336 339 return (error);
337 340 }
338 341
339 342 static int
340 343 smb_fem_fcn_rmdir(
341 344 femarg_t *arg,
342 345 char *name,
343 346 vnode_t *cdir,
344 347 cred_t *cr,
345 348 caller_context_t *ct,
346 349 int flags)
347 350 {
348 351 smb_node_t *dnode;
349 352 int error;
350 353
351 354 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
352 355
353 356 ASSERT(dnode);
354 357
355 358 error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
356 359
357 360 if (error == 0 && ct != &smb_ct)
358 361 smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name);
359 362
360 363 return (error);
361 364 }
362 365
363 366 static int
364 367 smb_fem_fcn_link(
365 368 femarg_t *arg,
366 369 vnode_t *svp,
367 370 char *tnm,
368 371 cred_t *cr,
369 372 caller_context_t *ct,
370 373 int flags)
371 374 {
372 375 smb_node_t *dnode;
373 376 int error;
374 377
375 378 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
376 379
377 380 ASSERT(dnode);
378 381
379 382 error = vnext_link(arg, svp, tnm, cr, ct, flags);
380 383
381 384 if (error == 0 && ct != &smb_ct)
382 385 smb_node_notify_change(dnode, FILE_ACTION_ADDED, tnm);
383 386
384 387 return (error);
385 388 }
386 389
387 390 static int
388 391 smb_fem_fcn_symlink(
389 392 femarg_t *arg,
390 393 char *linkname,
391 394 vattr_t *vap,
392 395 char *target,
393 396 cred_t *cr,
394 397 caller_context_t *ct,
395 398 int flags)
396 399 {
397 400 smb_node_t *dnode;
398 401 int error;
399 402
400 403 dnode = (smb_node_t *)arg->fa_fnode->fn_available;
401 404
402 405 ASSERT(dnode);
403 406
404 407 error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
405 408
406 409 if (error == 0 && ct != &smb_ct)
407 410 smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname);
408 411
409 412 return (error);
410 413 }
411 414
412 415 /*
413 416 * FEM oplock monitors
414 417 *
415 418 * The monitors below are not intended to intercept CIFS calls.
|
↓ open down ↓ |
239 lines elided |
↑ open up ↑ |
416 419 * CIFS higher-level routines will break oplocks as needed prior
417 420 * to getting to the VFS layer.
418 421 */
419 422 static int
420 423 smb_fem_oplock_open(
421 424 femarg_t *arg,
422 425 int mode,
423 426 cred_t *cr,
424 427 caller_context_t *ct)
425 428 {
426 - uint32_t flags;
429 + smb_node_t *node;
430 + uint32_t status;
427 431 int rc = 0;
428 432
429 433 if (ct != &smb_ct) {
430 - if (mode & (FWRITE|FTRUNC))
431 - flags = SMB_OPLOCK_BREAK_TO_NONE;
432 - else
433 - flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
434 - rc = smb_fem_oplock_break(arg, ct, flags);
434 + uint32_t req_acc = FILE_READ_DATA;
435 + uint32_t cr_disp = FILE_OPEN_IF;
436 +
437 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
438 + SMB_NODE_VALID(node);
439 +
440 + /*
441 + * Get req_acc, cr_disp just accurate enough so
442 + * the oplock break call does the right thing.
443 + */
444 + if (mode & FWRITE) {
445 + req_acc = FILE_READ_DATA | FILE_WRITE_DATA;
446 + cr_disp = (mode & FTRUNC) ?
447 + FILE_OVERWRITE_IF : FILE_OPEN_IF;
448 + } else {
449 + req_acc = FILE_READ_DATA;
450 + cr_disp = FILE_OPEN_IF;
451 + }
452 +
453 + status = smb_oplock_break_OPEN(node, NULL,
454 + req_acc, cr_disp);
455 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
456 + rc = smb_fem_oplock_wait(node, ct);
457 + else if (status != 0)
458 + rc = EIO;
435 459 }
436 460 if (rc == 0)
437 461 rc = vnext_open(arg, mode, cr, ct);
438 462
439 463 return (rc);
440 464 }
441 465
442 466 /*
443 467 * Should normally be hit only via NFSv2/v3. All other accesses
444 468 * (CIFS/NFS/local) should call VOP_OPEN first.
445 469 */
446 470
447 471 static int
448 472 smb_fem_oplock_read(
449 473 femarg_t *arg,
450 474 uio_t *uiop,
451 475 int ioflag,
452 476 cred_t *cr,
453 477 caller_context_t *ct)
454 478 {
479 + smb_node_t *node;
480 + uint32_t status;
455 481 int rc = 0;
456 482
457 483 if (ct != &smb_ct) {
458 - rc = smb_fem_oplock_break(arg, ct,
459 - SMB_OPLOCK_BREAK_TO_LEVEL_II);
484 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
485 + SMB_NODE_VALID(node);
486 +
487 + status = smb_oplock_break_READ(node, NULL);
488 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
489 + rc = smb_fem_oplock_wait(node, ct);
490 + else if (status != 0)
491 + rc = EIO;
460 492 }
461 493 if (rc == 0)
462 494 rc = vnext_read(arg, uiop, ioflag, cr, ct);
463 495
464 496 return (rc);
465 497 }
466 498
467 499 /*
468 500 * Should normally be hit only via NFSv2/v3. All other accesses
469 501 * (CIFS/NFS/local) should call VOP_OPEN first.
470 502 */
471 503
472 504 static int
473 505 smb_fem_oplock_write(
474 506 femarg_t *arg,
475 507 uio_t *uiop,
476 508 int ioflag,
477 509 cred_t *cr,
478 510 caller_context_t *ct)
479 511 {
512 + smb_node_t *node;
513 + uint32_t status;
480 514 int rc = 0;
481 515
482 - if (ct != &smb_ct)
483 - rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
516 + if (ct != &smb_ct) {
517 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
518 + SMB_NODE_VALID(node);
519 +
520 + status = smb_oplock_break_WRITE(node, NULL);
521 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
522 + rc = smb_fem_oplock_wait(node, ct);
523 + else if (status != 0)
524 + rc = EIO;
525 + }
484 526 if (rc == 0)
485 527 rc = vnext_write(arg, uiop, ioflag, cr, ct);
486 528
487 529 return (rc);
488 530 }
489 531
490 532 static int
491 533 smb_fem_oplock_setattr(
492 534 femarg_t *arg,
493 535 vattr_t *vap,
494 536 int flags,
495 537 cred_t *cr,
496 538 caller_context_t *ct)
497 539 {
540 + smb_node_t *node;
541 + uint32_t status;
498 542 int rc = 0;
499 543
500 - if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0)
501 - rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
502 - if (rc == 0)
503 - rc = vnext_setattr(arg, vap, flags, cr, ct);
504 - return (rc);
505 -}
544 + if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) {
545 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
546 + SMB_NODE_VALID(node);
506 547
507 -static int
508 -smb_fem_oplock_rwlock(
509 - femarg_t *arg,
510 - int write_lock,
511 - caller_context_t *ct)
512 -{
513 - uint32_t flags;
514 - int rc = 0;
515 -
516 - if (ct != &smb_ct) {
517 - if (write_lock)
518 - flags = SMB_OPLOCK_BREAK_TO_NONE;
519 - else
520 - flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
521 - rc = smb_fem_oplock_break(arg, ct, flags);
548 + status = smb_oplock_break_SETINFO(node, NULL,
549 + FileEndOfFileInformation);
550 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
551 + rc = smb_fem_oplock_wait(node, ct);
552 + else if (status != 0)
553 + rc = EIO;
522 554 }
523 555 if (rc == 0)
524 - rc = vnext_rwlock(arg, write_lock, ct);
525 -
556 + rc = vnext_setattr(arg, vap, flags, cr, ct);
526 557 return (rc);
527 558 }
528 559
529 560 static int
530 561 smb_fem_oplock_space(
531 562 femarg_t *arg,
532 563 int cmd,
533 564 flock64_t *bfp,
534 565 int flag,
535 566 offset_t offset,
536 567 cred_t *cr,
537 568 caller_context_t *ct)
538 569 {
570 + smb_node_t *node;
571 + uint32_t status;
539 572 int rc = 0;
540 573
541 - if (ct != &smb_ct)
542 - rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
574 + if (ct != &smb_ct) {
575 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
576 + SMB_NODE_VALID(node);
577 +
578 + status = smb_oplock_break_SETINFO(node, NULL,
579 + FileAllocationInformation);
580 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
581 + rc = smb_fem_oplock_wait(node, ct);
582 + else if (status != 0)
583 + rc = EIO;
584 + }
543 585 if (rc == 0)
544 586 rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
545 587 return (rc);
546 588 }
547 589
548 590 /*
549 591 * smb_fem_oplock_vnevent()
550 592 *
551 593 * To intercept NFS and local renames and removes in order to break any
552 594 * existing oplock prior to the operation.
553 595 *
554 596 * Note: Currently, this monitor is traversed only when an FS is mounted
555 597 * non-nbmand. (When the FS is mounted nbmand, share reservation checking
556 598 * will detect a share violation and return an error prior to the VOP layer
557 599 * being reached.) Thus, for nbmand NFS and local renames and removes,
558 600 * an existing oplock is never broken prior to share checking (contrary to
559 601 * how it is with intra-CIFS remove and rename requests).
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
560 602 */
561 603
562 604 static int
563 605 smb_fem_oplock_vnevent(
564 606 femarg_t *arg,
565 607 vnevent_t vnevent,
566 608 vnode_t *dvp,
567 609 char *name,
568 610 caller_context_t *ct)
569 611 {
570 - uint32_t flags;
612 + smb_node_t *node;
613 + uint32_t status;
571 614 int rc = 0;
572 615
573 616 if (ct != &smb_ct) {
617 + node = (smb_node_t *)(arg->fa_fnode->fn_available);
618 + SMB_NODE_VALID(node);
619 +
574 620 switch (vnevent) {
575 621 case VE_REMOVE:
576 622 case VE_PRE_RENAME_DEST:
577 623 case VE_RENAME_DEST:
578 - flags = SMB_OPLOCK_BREAK_TO_NONE |
579 - SMB_OPLOCK_BREAK_BATCH;
580 - rc = smb_fem_oplock_break(arg, ct, flags);
624 + status = smb_oplock_break_HANDLE(node, NULL);
581 625 break;
582 626 case VE_PRE_RENAME_SRC:
583 627 case VE_RENAME_SRC:
584 - flags = SMB_OPLOCK_BREAK_TO_LEVEL_II |
585 - SMB_OPLOCK_BREAK_BATCH;
586 - rc = smb_fem_oplock_break(arg, ct, flags);
628 + status = smb_oplock_break_SETINFO(node, NULL,
629 + FileRenameInformation);
587 630 break;
588 631 default:
589 - rc = 0;
632 + status = 0;
590 633 break;
591 634 }
635 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
636 + rc = smb_fem_oplock_wait(node, ct);
637 + else if (status != 0)
638 + rc = EIO;
592 639 }
593 640 if (rc == 0)
594 641 rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
595 642
596 643 return (rc);
597 644 }
598 645
646 +int smb_fem_oplock_timeout = 5000; /* mSec. */
647 +
599 648 static int
600 -smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
649 +smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct)
601 650 {
602 - smb_node_t *node;
603 - int rc;
651 + int rc = 0;
604 652
605 - node = (smb_node_t *)((arg)->fa_fnode->fn_available);
606 - SMB_NODE_VALID(node);
607 -
608 653 ASSERT(ct != &smb_ct);
609 654
610 655 if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
611 - flags |= SMB_OPLOCK_BREAK_NOWAIT;
612 - rc = smb_oplock_break(NULL, node, flags);
613 - if (rc == EAGAIN)
614 - ct->cc_flags |= CC_WOULDBLOCK;
656 + ct->cc_flags |= CC_WOULDBLOCK;
657 + rc = EAGAIN;
615 658 } else {
616 - rc = smb_oplock_break(NULL, node, flags);
659 + (void) smb_oplock_wait_break(node,
660 + smb_fem_oplock_timeout);
661 + rc = 0;
617 662 }
618 663
619 664 return (rc);
620 665 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX