Print this page
Fix NFS design problems re. multiple zone keys
Make NFS server zone-specific data all have the same lifetime
Fix rfs4_clean_state_exi
Fix exi_cache_reclaim
Fix mistakes in zone keys work
More fixes re. exi_zoneid and exi_tree
(danmcd -> Keep some ASSERT()s around for readability.)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ new/usr/src/uts/common/fs/nfs/nfs3_srv.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 *
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 /*
23 23 * Copyright 2018 Nexenta Systems, Inc.
24 24 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25 25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 26 */
27 27
28 28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 29 /* All Rights Reserved */
30 30
31 31
32 32 #include <sys/param.h>
33 33 #include <sys/types.h>
34 34 #include <sys/systm.h>
35 35 #include <sys/cred.h>
36 36 #include <sys/buf.h>
37 37 #include <sys/vfs.h>
38 38 #include <sys/vnode.h>
39 39 #include <sys/uio.h>
40 40 #include <sys/errno.h>
41 41 #include <sys/sysmacros.h>
42 42 #include <sys/statvfs.h>
43 43 #include <sys/kmem.h>
44 44 #include <sys/dirent.h>
45 45 #include <sys/cmn_err.h>
46 46 #include <sys/debug.h>
47 47 #include <sys/systeminfo.h>
48 48 #include <sys/flock.h>
49 49 #include <sys/nbmlock.h>
50 50 #include <sys/policy.h>
51 51 #include <sys/sdt.h>
52 52
53 53 #include <rpc/types.h>
54 54 #include <rpc/auth.h>
55 55 #include <rpc/svc.h>
56 56 #include <rpc/rpc_rdma.h>
57 57
58 58 #include <nfs/nfs.h>
59 59 #include <nfs/export.h>
60 60 #include <nfs/nfs_cmd.h>
61 61
62 62 #include <sys/strsubr.h>
63 63 #include <sys/tsol/label.h>
64 64 #include <sys/tsol/tndb.h>
65 65
66 66 #include <sys/zone.h>
67 67
68 68 #include <inet/ip.h>
69 69 #include <inet/ip6.h>
70 70
71 71 /*
72 72 * Zone global variables of NFSv3 server
73 73 */
74 74 typedef struct nfs3_srv {
75 75 writeverf3 write3verf;
76 76 } nfs3_srv_t;
77 77
78 78 /*
79 79 * These are the interface routines for the server side of the
80 80 * Network File System. See the NFS version 3 protocol specification
81 81 * for a description of this interface.
82 82 */
83 83
|
↓ open down ↓ |
83 lines elided |
↑ open up ↑ |
84 84 static int sattr3_to_vattr(sattr3 *, struct vattr *);
85 85 static int vattr_to_fattr3(struct vattr *, fattr3 *);
86 86 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
87 87 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
88 88 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
89 89 static int rdma_setup_read_data3(READ3args *, READ3resok *);
90 90
91 91 extern int nfs_loaned_buffers;
92 92
93 93 u_longlong_t nfs3_srv_caller_id;
94 -static zone_key_t rfs3_zone_key;
95 94
95 +static nfs3_srv_t *
96 +nfs3_get_srv(void)
97 +{
98 + nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone);
99 + nfs3_srv_t *srv = ng->nfs3_srv;
100 + ASSERT(srv != NULL);
101 + return (srv);
102 +}
103 +
96 104 /* ARGSUSED */
97 105 void
98 106 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
99 107 struct svc_req *req, cred_t *cr, bool_t ro)
100 108 {
101 109 int error;
102 110 vnode_t *vp;
103 111 struct vattr va;
104 112
105 113 vp = nfs3_fhtovp(&args->object, exi);
106 114
107 115 DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
108 116 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
109 117 GETATTR3args *, args);
110 118
111 119 if (vp == NULL) {
112 120 error = ESTALE;
113 121 goto out;
114 122 }
115 123
116 124 va.va_mask = AT_ALL;
117 125 error = rfs4_delegated_getattr(vp, &va, 0, cr);
118 126
119 127 if (!error) {
120 128 /* Lie about the object type for a referral */
121 129 if (vn_is_nfs_reparse(vp, cr))
122 130 va.va_type = VLNK;
123 131
124 132 /* overflow error if time or size is out of range */
125 133 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
126 134 if (error)
127 135 goto out;
128 136 resp->status = NFS3_OK;
129 137
130 138 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
131 139 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
132 140 GETATTR3res *, resp);
133 141
134 142 VN_RELE(vp);
135 143
136 144 return;
137 145 }
138 146
139 147 out:
140 148 if (curthread->t_flag & T_WOULDBLOCK) {
141 149 curthread->t_flag &= ~T_WOULDBLOCK;
142 150 resp->status = NFS3ERR_JUKEBOX;
143 151 } else
144 152 resp->status = puterrno3(error);
145 153
146 154 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
147 155 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
148 156 GETATTR3res *, resp);
149 157
150 158 if (vp != NULL)
151 159 VN_RELE(vp);
152 160 }
153 161
154 162 void *
155 163 rfs3_getattr_getfh(GETATTR3args *args)
156 164 {
157 165
158 166 return (&args->object);
159 167 }
160 168
161 169 void
162 170 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
163 171 struct svc_req *req, cred_t *cr, bool_t ro)
164 172 {
165 173 int error;
166 174 vnode_t *vp;
167 175 struct vattr *bvap;
168 176 struct vattr bva;
169 177 struct vattr *avap;
170 178 struct vattr ava;
171 179 int flag;
172 180 int in_crit = 0;
173 181 struct flock64 bf;
174 182 caller_context_t ct;
175 183
176 184 bvap = NULL;
177 185 avap = NULL;
178 186
179 187 vp = nfs3_fhtovp(&args->object, exi);
180 188
181 189 DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
182 190 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
183 191 SETATTR3args *, args);
184 192
185 193 if (vp == NULL) {
186 194 error = ESTALE;
187 195 goto out;
188 196 }
189 197
190 198 error = sattr3_to_vattr(&args->new_attributes, &ava);
191 199 if (error)
192 200 goto out;
193 201
194 202 if (is_system_labeled()) {
195 203 bslabel_t *clabel = req->rq_label;
196 204
197 205 ASSERT(clabel != NULL);
198 206 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
199 207 "got client label from request(1)", struct svc_req *, req);
200 208
201 209 if (!blequal(&l_admin_low->tsl_label, clabel)) {
202 210 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
203 211 exi)) {
204 212 resp->status = NFS3ERR_ACCES;
205 213 goto out1;
206 214 }
207 215 }
208 216 }
209 217
210 218 /*
211 219 * We need to specially handle size changes because of
212 220 * possible conflicting NBMAND locks. Get into critical
213 221 * region before VOP_GETATTR, so the size attribute is
214 222 * valid when checking conflicts.
215 223 *
216 224 * Also, check to see if the v4 side of the server has
217 225 * delegated this file. If so, then we return JUKEBOX to
218 226 * allow the client to retrasmit its request.
219 227 */
220 228 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
221 229 if (nbl_need_check(vp)) {
222 230 nbl_start_crit(vp, RW_READER);
223 231 in_crit = 1;
224 232 }
225 233 }
226 234
227 235 bva.va_mask = AT_ALL;
228 236 error = rfs4_delegated_getattr(vp, &bva, 0, cr);
229 237
230 238 /*
231 239 * If we can't get the attributes, then we can't do the
232 240 * right access checking. So, we'll fail the request.
233 241 */
234 242 if (error)
235 243 goto out;
236 244
237 245 bvap = &bva;
238 246
239 247 if (rdonly(ro, vp)) {
240 248 resp->status = NFS3ERR_ROFS;
241 249 goto out1;
242 250 }
243 251
244 252 if (args->guard.check &&
245 253 (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
246 254 args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
247 255 resp->status = NFS3ERR_NOT_SYNC;
248 256 goto out1;
249 257 }
250 258
251 259 if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
252 260 flag = ATTR_UTIME;
253 261 else
254 262 flag = 0;
255 263
256 264 /*
257 265 * If the filesystem is exported with nosuid, then mask off
258 266 * the setuid and setgid bits.
259 267 */
260 268 if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
261 269 (exi->exi_export.ex_flags & EX_NOSUID))
262 270 ava.va_mode &= ~(VSUID | VSGID);
263 271
264 272 ct.cc_sysid = 0;
265 273 ct.cc_pid = 0;
266 274 ct.cc_caller_id = nfs3_srv_caller_id;
267 275 ct.cc_flags = CC_DONTBLOCK;
268 276
269 277 /*
270 278 * We need to specially handle size changes because it is
271 279 * possible for the client to create a file with modes
272 280 * which indicate read-only, but with the file opened for
273 281 * writing. If the client then tries to set the size of
274 282 * the file, then the normal access checking done in
275 283 * VOP_SETATTR would prevent the client from doing so,
276 284 * although it should be legal for it to do so. To get
277 285 * around this, we do the access checking for ourselves
278 286 * and then use VOP_SPACE which doesn't do the access
279 287 * checking which VOP_SETATTR does. VOP_SPACE can only
280 288 * operate on VREG files, let VOP_SETATTR handle the other
281 289 * extremely rare cases.
282 290 * Also the client should not be allowed to change the
283 291 * size of the file if there is a conflicting non-blocking
284 292 * mandatory lock in the region the change.
285 293 */
286 294 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
287 295 if (in_crit) {
288 296 u_offset_t offset;
289 297 ssize_t length;
290 298
291 299 if (ava.va_size < bva.va_size) {
292 300 offset = ava.va_size;
293 301 length = bva.va_size - ava.va_size;
294 302 } else {
295 303 offset = bva.va_size;
296 304 length = ava.va_size - bva.va_size;
297 305 }
298 306 if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
299 307 NULL)) {
300 308 error = EACCES;
301 309 goto out;
302 310 }
303 311 }
304 312
305 313 if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
306 314 ava.va_mask &= ~AT_SIZE;
307 315 bf.l_type = F_WRLCK;
308 316 bf.l_whence = 0;
309 317 bf.l_start = (off64_t)ava.va_size;
310 318 bf.l_len = 0;
311 319 bf.l_sysid = 0;
312 320 bf.l_pid = 0;
313 321 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
314 322 (offset_t)ava.va_size, cr, &ct);
315 323 }
316 324 }
317 325
318 326 if (!error && ava.va_mask)
319 327 error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
320 328
321 329 /* check if a monitor detected a delegation conflict */
322 330 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
323 331 resp->status = NFS3ERR_JUKEBOX;
324 332 goto out1;
325 333 }
326 334
327 335 ava.va_mask = AT_ALL;
328 336 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
329 337
330 338 /*
331 339 * Force modified metadata out to stable storage.
332 340 */
333 341 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
334 342
335 343 if (error)
336 344 goto out;
337 345
338 346 if (in_crit)
339 347 nbl_end_crit(vp);
340 348
341 349 resp->status = NFS3_OK;
342 350 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
343 351
344 352 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
345 353 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
346 354 SETATTR3res *, resp);
347 355
348 356 VN_RELE(vp);
349 357
350 358 return;
351 359
352 360 out:
353 361 if (curthread->t_flag & T_WOULDBLOCK) {
354 362 curthread->t_flag &= ~T_WOULDBLOCK;
355 363 resp->status = NFS3ERR_JUKEBOX;
356 364 } else
357 365 resp->status = puterrno3(error);
358 366 out1:
359 367 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
360 368 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
361 369 SETATTR3res *, resp);
362 370
363 371 if (vp != NULL) {
364 372 if (in_crit)
365 373 nbl_end_crit(vp);
366 374 VN_RELE(vp);
367 375 }
368 376 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
369 377 }
370 378
371 379 void *
372 380 rfs3_setattr_getfh(SETATTR3args *args)
373 381 {
374 382
375 383 return (&args->object);
376 384 }
377 385
378 386 /* ARGSUSED */
379 387 void
380 388 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
381 389 struct svc_req *req, cred_t *cr, bool_t ro)
382 390 {
383 391 int error;
384 392 vnode_t *vp;
385 393 vnode_t *dvp;
386 394 struct vattr *vap;
387 395 struct vattr va;
388 396 struct vattr *dvap;
389 397 struct vattr dva;
390 398 nfs_fh3 *fhp;
391 399 struct sec_ol sec = {0, 0};
392 400 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
393 401 struct sockaddr *ca;
394 402 char *name = NULL;
395 403
396 404 dvap = NULL;
397 405
398 406 if (exi != NULL)
399 407 exi_hold(exi);
400 408
401 409 /*
402 410 * Allow lookups from the root - the default
403 411 * location of the public filehandle.
404 412 */
405 413 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
406 414 dvp = ZONE_ROOTVP();
407 415 VN_HOLD(dvp);
408 416
409 417 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
410 418 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
411 419 LOOKUP3args *, args);
412 420 } else {
413 421 dvp = nfs3_fhtovp(&args->what.dir, exi);
414 422
415 423 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
416 424 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
417 425 LOOKUP3args *, args);
418 426
419 427 if (dvp == NULL) {
420 428 error = ESTALE;
421 429 goto out;
422 430 }
423 431 }
424 432
425 433 dva.va_mask = AT_ALL;
426 434 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
427 435
428 436 if (args->what.name == nfs3nametoolong) {
429 437 resp->status = NFS3ERR_NAMETOOLONG;
430 438 goto out1;
431 439 }
432 440
433 441 if (args->what.name == NULL || *(args->what.name) == '\0') {
434 442 resp->status = NFS3ERR_ACCES;
435 443 goto out1;
436 444 }
437 445
438 446 fhp = &args->what.dir;
439 447 ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
440 448 if (strcmp(args->what.name, "..") == 0 &&
441 449 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
442 450 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
443 451 ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
444 452 /*
445 453 * special case for ".." and 'nohide'exported root
446 454 */
447 455 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
448 456 resp->status = NFS3ERR_ACCES;
449 457 goto out1;
450 458 }
451 459 } else {
452 460 resp->status = NFS3ERR_NOENT;
453 461 goto out1;
454 462 }
455 463 }
456 464
457 465 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
458 466 name = nfscmd_convname(ca, exi, args->what.name,
459 467 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
460 468
461 469 if (name == NULL) {
462 470 resp->status = NFS3ERR_ACCES;
463 471 goto out1;
464 472 }
465 473
466 474 /*
467 475 * If the public filehandle is used then allow
468 476 * a multi-component lookup
469 477 */
470 478 if (PUBLIC_FH3(&args->what.dir)) {
471 479 publicfh_flag = TRUE;
472 480
473 481 exi_rele(exi);
474 482
475 483 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
476 484 &exi, &sec);
477 485
478 486 /*
479 487 * Since WebNFS may bypass MOUNT, we need to ensure this
480 488 * request didn't come from an unlabeled admin_low client.
481 489 */
482 490 if (is_system_labeled() && error == 0) {
483 491 int addr_type;
484 492 void *ipaddr;
485 493 tsol_tpc_t *tp;
486 494
487 495 if (ca->sa_family == AF_INET) {
488 496 addr_type = IPV4_VERSION;
489 497 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
490 498 } else if (ca->sa_family == AF_INET6) {
491 499 addr_type = IPV6_VERSION;
492 500 ipaddr = &((struct sockaddr_in6 *)
493 501 ca)->sin6_addr;
494 502 }
495 503 tp = find_tpc(ipaddr, addr_type, B_FALSE);
496 504 if (tp == NULL || tp->tpc_tp.tp_doi !=
497 505 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
498 506 SUN_CIPSO) {
499 507 VN_RELE(vp);
500 508 error = EACCES;
501 509 }
502 510 if (tp != NULL)
503 511 TPC_RELE(tp);
504 512 }
505 513 } else {
506 514 error = VOP_LOOKUP(dvp, name, &vp,
507 515 NULL, 0, NULL, cr, NULL, NULL, NULL);
508 516 }
509 517
510 518 if (name != args->what.name)
511 519 kmem_free(name, MAXPATHLEN + 1);
512 520
513 521 if (error == 0 && vn_ismntpt(vp)) {
514 522 error = rfs_cross_mnt(&vp, &exi);
515 523 if (error)
516 524 VN_RELE(vp);
517 525 }
518 526
519 527 if (is_system_labeled() && error == 0) {
520 528 bslabel_t *clabel = req->rq_label;
521 529
522 530 ASSERT(clabel != NULL);
523 531 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
524 532 "got client label from request(1)", struct svc_req *, req);
525 533
526 534 if (!blequal(&l_admin_low->tsl_label, clabel)) {
527 535 if (!do_rfs_label_check(clabel, dvp,
528 536 DOMINANCE_CHECK, exi)) {
529 537 VN_RELE(vp);
530 538 error = EACCES;
531 539 }
532 540 }
533 541 }
534 542
535 543 dva.va_mask = AT_ALL;
536 544 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
537 545
538 546 if (error)
539 547 goto out;
540 548
541 549 if (sec.sec_flags & SEC_QUERY) {
542 550 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
543 551 } else {
544 552 error = makefh3(&resp->resok.object, vp, exi);
545 553 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
546 554 auth_weak = TRUE;
547 555 }
548 556
549 557 if (error) {
550 558 VN_RELE(vp);
551 559 goto out;
552 560 }
553 561
554 562 va.va_mask = AT_ALL;
555 563 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
556 564
557 565 exi_rele(exi);
558 566 VN_RELE(vp);
559 567
560 568 resp->status = NFS3_OK;
561 569 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
562 570 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
563 571
564 572 /*
565 573 * If it's public fh, no 0x81, and client's flavor is
566 574 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
567 575 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
568 576 */
569 577 if (auth_weak)
570 578 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
571 579
572 580 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
573 581 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
574 582 LOOKUP3res *, resp);
575 583 VN_RELE(dvp);
576 584
577 585 return;
578 586
579 587 out:
580 588 if (curthread->t_flag & T_WOULDBLOCK) {
581 589 curthread->t_flag &= ~T_WOULDBLOCK;
582 590 resp->status = NFS3ERR_JUKEBOX;
583 591 } else
584 592 resp->status = puterrno3(error);
585 593 out1:
586 594 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
587 595 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
588 596 LOOKUP3res *, resp);
589 597
590 598 if (exi != NULL)
591 599 exi_rele(exi);
592 600
593 601 if (dvp != NULL)
594 602 VN_RELE(dvp);
595 603 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
596 604
597 605 }
598 606
599 607 void *
600 608 rfs3_lookup_getfh(LOOKUP3args *args)
601 609 {
602 610
603 611 return (&args->what.dir);
604 612 }
605 613
606 614 /* ARGSUSED */
607 615 void
608 616 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
609 617 struct svc_req *req, cred_t *cr, bool_t ro)
610 618 {
611 619 int error;
612 620 vnode_t *vp;
613 621 struct vattr *vap;
614 622 struct vattr va;
615 623 int checkwriteperm;
616 624 boolean_t dominant_label = B_FALSE;
617 625 boolean_t equal_label = B_FALSE;
618 626 boolean_t admin_low_client;
619 627
620 628 vap = NULL;
621 629
622 630 vp = nfs3_fhtovp(&args->object, exi);
623 631
624 632 DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
625 633 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
626 634 ACCESS3args *, args);
627 635
628 636 if (vp == NULL) {
629 637 error = ESTALE;
630 638 goto out;
631 639 }
632 640
633 641 /*
634 642 * If the file system is exported read only, it is not appropriate
635 643 * to check write permissions for regular files and directories.
636 644 * Special files are interpreted by the client, so the underlying
637 645 * permissions are sent back to the client for interpretation.
638 646 */
639 647 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
640 648 checkwriteperm = 0;
641 649 else
642 650 checkwriteperm = 1;
643 651
644 652 /*
645 653 * We need the mode so that we can correctly determine access
646 654 * permissions relative to a mandatory lock file. Access to
647 655 * mandatory lock files is denied on the server, so it might
648 656 * as well be reflected to the server during the open.
649 657 */
650 658 va.va_mask = AT_MODE;
651 659 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
652 660 if (error)
653 661 goto out;
654 662
655 663 vap = &va;
656 664
657 665 resp->resok.access = 0;
658 666
659 667 if (is_system_labeled()) {
660 668 bslabel_t *clabel = req->rq_label;
661 669
662 670 ASSERT(clabel != NULL);
663 671 DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
664 672 "got client label from request(1)", struct svc_req *, req);
665 673
666 674 if (!blequal(&l_admin_low->tsl_label, clabel)) {
667 675 if ((equal_label = do_rfs_label_check(clabel, vp,
668 676 EQUALITY_CHECK, exi)) == B_FALSE) {
669 677 dominant_label = do_rfs_label_check(clabel,
670 678 vp, DOMINANCE_CHECK, exi);
671 679 } else
672 680 dominant_label = B_TRUE;
673 681 admin_low_client = B_FALSE;
674 682 } else
675 683 admin_low_client = B_TRUE;
676 684 }
677 685
678 686 if (args->access & ACCESS3_READ) {
679 687 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
680 688 if (error) {
681 689 if (curthread->t_flag & T_WOULDBLOCK)
682 690 goto out;
683 691 } else if (!MANDLOCK(vp, va.va_mode) &&
684 692 (!is_system_labeled() || admin_low_client ||
685 693 dominant_label))
686 694 resp->resok.access |= ACCESS3_READ;
687 695 }
688 696 if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
689 697 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
690 698 if (error) {
691 699 if (curthread->t_flag & T_WOULDBLOCK)
692 700 goto out;
693 701 } else if (!is_system_labeled() || admin_low_client ||
694 702 dominant_label)
695 703 resp->resok.access |= ACCESS3_LOOKUP;
696 704 }
697 705 if (checkwriteperm &&
698 706 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
699 707 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
700 708 if (error) {
701 709 if (curthread->t_flag & T_WOULDBLOCK)
702 710 goto out;
703 711 } else if (!MANDLOCK(vp, va.va_mode) &&
704 712 (!is_system_labeled() || admin_low_client || equal_label)) {
705 713 resp->resok.access |=
706 714 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
707 715 }
708 716 }
709 717 if (checkwriteperm &&
710 718 (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
711 719 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
712 720 if (error) {
713 721 if (curthread->t_flag & T_WOULDBLOCK)
714 722 goto out;
715 723 } else if (!is_system_labeled() || admin_low_client ||
716 724 equal_label)
717 725 resp->resok.access |= ACCESS3_DELETE;
718 726 }
719 727 if (args->access & ACCESS3_EXECUTE) {
720 728 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
721 729 if (error) {
722 730 if (curthread->t_flag & T_WOULDBLOCK)
723 731 goto out;
724 732 } else if (!MANDLOCK(vp, va.va_mode) &&
725 733 (!is_system_labeled() || admin_low_client ||
726 734 dominant_label))
727 735 resp->resok.access |= ACCESS3_EXECUTE;
728 736 }
729 737
730 738 va.va_mask = AT_ALL;
731 739 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
732 740
733 741 resp->status = NFS3_OK;
734 742 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
735 743
736 744 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
737 745 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
738 746 ACCESS3res *, resp);
739 747
740 748 VN_RELE(vp);
741 749
742 750 return;
743 751
744 752 out:
745 753 if (curthread->t_flag & T_WOULDBLOCK) {
746 754 curthread->t_flag &= ~T_WOULDBLOCK;
747 755 resp->status = NFS3ERR_JUKEBOX;
748 756 } else
749 757 resp->status = puterrno3(error);
750 758 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
751 759 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
752 760 ACCESS3res *, resp);
753 761 if (vp != NULL)
754 762 VN_RELE(vp);
755 763 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
756 764 }
757 765
758 766 void *
759 767 rfs3_access_getfh(ACCESS3args *args)
760 768 {
761 769
762 770 return (&args->object);
763 771 }
764 772
765 773 /* ARGSUSED */
766 774 void
767 775 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
768 776 struct svc_req *req, cred_t *cr, bool_t ro)
769 777 {
770 778 int error;
771 779 vnode_t *vp;
772 780 struct vattr *vap;
773 781 struct vattr va;
774 782 struct iovec iov;
775 783 struct uio uio;
776 784 char *data;
777 785 struct sockaddr *ca;
778 786 char *name = NULL;
779 787 int is_referral = 0;
780 788
781 789 vap = NULL;
782 790
783 791 vp = nfs3_fhtovp(&args->symlink, exi);
784 792
785 793 DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
786 794 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
787 795 READLINK3args *, args);
788 796
789 797 if (vp == NULL) {
790 798 error = ESTALE;
791 799 goto out;
792 800 }
793 801
794 802 va.va_mask = AT_ALL;
795 803 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
796 804 if (error)
797 805 goto out;
798 806
799 807 vap = &va;
800 808
801 809 /* We lied about the object type for a referral */
802 810 if (vn_is_nfs_reparse(vp, cr))
803 811 is_referral = 1;
804 812
805 813 if (vp->v_type != VLNK && !is_referral) {
806 814 resp->status = NFS3ERR_INVAL;
807 815 goto out1;
808 816 }
809 817
810 818 if (MANDLOCK(vp, va.va_mode)) {
811 819 resp->status = NFS3ERR_ACCES;
812 820 goto out1;
813 821 }
814 822
815 823 if (is_system_labeled()) {
816 824 bslabel_t *clabel = req->rq_label;
817 825
818 826 ASSERT(clabel != NULL);
819 827 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
820 828 "got client label from request(1)", struct svc_req *, req);
821 829
822 830 if (!blequal(&l_admin_low->tsl_label, clabel)) {
823 831 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
824 832 exi)) {
825 833 resp->status = NFS3ERR_ACCES;
826 834 goto out1;
827 835 }
828 836 }
829 837 }
830 838
831 839 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
832 840
833 841 if (is_referral) {
834 842 char *s;
835 843 size_t strsz;
836 844
837 845 /* Get an artificial symlink based on a referral */
838 846 s = build_symlink(vp, cr, &strsz);
839 847 global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
840 848 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
841 849 vnode_t *, vp, char *, s);
842 850 if (s == NULL)
843 851 error = EINVAL;
844 852 else {
845 853 error = 0;
846 854 (void) strlcpy(data, s, MAXPATHLEN + 1);
847 855 kmem_free(s, strsz);
848 856 }
849 857
850 858 } else {
851 859
852 860 iov.iov_base = data;
853 861 iov.iov_len = MAXPATHLEN;
854 862 uio.uio_iov = &iov;
855 863 uio.uio_iovcnt = 1;
856 864 uio.uio_segflg = UIO_SYSSPACE;
857 865 uio.uio_extflg = UIO_COPY_CACHED;
858 866 uio.uio_loffset = 0;
859 867 uio.uio_resid = MAXPATHLEN;
860 868
861 869 error = VOP_READLINK(vp, &uio, cr, NULL);
862 870
863 871 if (!error)
864 872 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
865 873 }
866 874
867 875 va.va_mask = AT_ALL;
868 876 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
869 877
870 878 /* Lie about object type again just to be consistent */
871 879 if (is_referral && vap != NULL)
872 880 vap->va_type = VLNK;
873 881
874 882 #if 0 /* notyet */
875 883 /*
876 884 * Don't do this. It causes local disk writes when just
877 885 * reading the file and the overhead is deemed larger
878 886 * than the benefit.
879 887 */
880 888 /*
881 889 * Force modified metadata out to stable storage.
882 890 */
883 891 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
884 892 #endif
885 893
886 894 if (error) {
887 895 kmem_free(data, MAXPATHLEN + 1);
888 896 goto out;
889 897 }
890 898
891 899 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
892 900 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
893 901 MAXPATHLEN + 1);
894 902
895 903 if (name == NULL) {
896 904 /*
897 905 * Even though the conversion failed, we return
898 906 * something. We just don't translate it.
899 907 */
900 908 name = data;
901 909 }
902 910
903 911 resp->status = NFS3_OK;
904 912 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
905 913 resp->resok.data = name;
906 914
907 915 DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
908 916 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
909 917 READLINK3res *, resp);
910 918 VN_RELE(vp);
911 919
912 920 if (name != data)
913 921 kmem_free(data, MAXPATHLEN + 1);
914 922
915 923 return;
916 924
917 925 out:
918 926 if (curthread->t_flag & T_WOULDBLOCK) {
919 927 curthread->t_flag &= ~T_WOULDBLOCK;
920 928 resp->status = NFS3ERR_JUKEBOX;
921 929 } else
922 930 resp->status = puterrno3(error);
923 931 out1:
924 932 DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
925 933 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
926 934 READLINK3res *, resp);
927 935 if (vp != NULL)
928 936 VN_RELE(vp);
929 937 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
930 938 }
931 939
932 940 void *
933 941 rfs3_readlink_getfh(READLINK3args *args)
934 942 {
935 943
936 944 return (&args->symlink);
937 945 }
938 946
939 947 void
940 948 rfs3_readlink_free(READLINK3res *resp)
941 949 {
942 950
943 951 if (resp->status == NFS3_OK)
944 952 kmem_free(resp->resok.data, MAXPATHLEN + 1);
945 953 }
946 954
947 955 /*
948 956 * Server routine to handle read
949 957 * May handle RDMA data as well as mblks
950 958 */
951 959 /* ARGSUSED */
952 960 void
953 961 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
954 962 struct svc_req *req, cred_t *cr, bool_t ro)
955 963 {
956 964 int error;
957 965 vnode_t *vp;
958 966 struct vattr *vap;
959 967 struct vattr va;
960 968 struct iovec iov, *iovp = NULL;
961 969 int iovcnt;
962 970 struct uio uio;
963 971 u_offset_t offset;
964 972 mblk_t *mp = NULL;
965 973 int in_crit = 0;
966 974 int need_rwunlock = 0;
967 975 caller_context_t ct;
968 976 int rdma_used = 0;
969 977 int loaned_buffers;
970 978 struct uio *uiop;
971 979
972 980 vap = NULL;
973 981
974 982 vp = nfs3_fhtovp(&args->file, exi);
975 983
976 984 DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
977 985 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
978 986 READ3args *, args);
979 987
980 988
981 989 if (vp == NULL) {
982 990 error = ESTALE;
983 991 goto out;
984 992 }
985 993
986 994 if (args->wlist) {
987 995 if (args->count > clist_len(args->wlist)) {
988 996 error = EINVAL;
989 997 goto out;
990 998 }
991 999 rdma_used = 1;
992 1000 }
993 1001
994 1002 /* use loaned buffers for TCP */
995 1003 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
996 1004
997 1005 if (is_system_labeled()) {
998 1006 bslabel_t *clabel = req->rq_label;
999 1007
1000 1008 ASSERT(clabel != NULL);
1001 1009 DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
1002 1010 "got client label from request(1)", struct svc_req *, req);
1003 1011
1004 1012 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1005 1013 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
1006 1014 exi)) {
1007 1015 resp->status = NFS3ERR_ACCES;
1008 1016 goto out1;
1009 1017 }
1010 1018 }
1011 1019 }
1012 1020
1013 1021 ct.cc_sysid = 0;
1014 1022 ct.cc_pid = 0;
1015 1023 ct.cc_caller_id = nfs3_srv_caller_id;
1016 1024 ct.cc_flags = CC_DONTBLOCK;
1017 1025
1018 1026 /*
1019 1027 * Enter the critical region before calling VOP_RWLOCK
1020 1028 * to avoid a deadlock with write requests.
1021 1029 */
1022 1030 if (nbl_need_check(vp)) {
1023 1031 nbl_start_crit(vp, RW_READER);
1024 1032 in_crit = 1;
1025 1033 if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
1026 1034 NULL)) {
1027 1035 error = EACCES;
1028 1036 goto out;
1029 1037 }
1030 1038 }
1031 1039
1032 1040 error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1033 1041
1034 1042 /* check if a monitor detected a delegation conflict */
1035 1043 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1036 1044 resp->status = NFS3ERR_JUKEBOX;
1037 1045 goto out1;
1038 1046 }
1039 1047
1040 1048 need_rwunlock = 1;
1041 1049
1042 1050 va.va_mask = AT_ALL;
1043 1051 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1044 1052
1045 1053 /*
1046 1054 * If we can't get the attributes, then we can't do the
1047 1055 * right access checking. So, we'll fail the request.
1048 1056 */
1049 1057 if (error)
1050 1058 goto out;
1051 1059
1052 1060 vap = &va;
1053 1061
1054 1062 if (vp->v_type != VREG) {
1055 1063 resp->status = NFS3ERR_INVAL;
1056 1064 goto out1;
1057 1065 }
1058 1066
1059 1067 if (crgetuid(cr) != va.va_uid) {
1060 1068 error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
1061 1069 if (error) {
1062 1070 if (curthread->t_flag & T_WOULDBLOCK)
1063 1071 goto out;
1064 1072 error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
1065 1073 if (error)
1066 1074 goto out;
1067 1075 }
1068 1076 }
1069 1077
1070 1078 if (MANDLOCK(vp, va.va_mode)) {
1071 1079 resp->status = NFS3ERR_ACCES;
1072 1080 goto out1;
1073 1081 }
1074 1082
1075 1083 offset = args->offset;
1076 1084 if (offset >= va.va_size) {
1077 1085 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1078 1086 if (in_crit)
1079 1087 nbl_end_crit(vp);
1080 1088 resp->status = NFS3_OK;
1081 1089 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1082 1090 resp->resok.count = 0;
1083 1091 resp->resok.eof = TRUE;
1084 1092 resp->resok.data.data_len = 0;
1085 1093 resp->resok.data.data_val = NULL;
1086 1094 resp->resok.data.mp = NULL;
1087 1095 /* RDMA */
1088 1096 resp->resok.wlist = args->wlist;
1089 1097 resp->resok.wlist_len = resp->resok.count;
1090 1098 if (resp->resok.wlist)
1091 1099 clist_zero_len(resp->resok.wlist);
1092 1100 goto done;
1093 1101 }
1094 1102
1095 1103 if (args->count == 0) {
1096 1104 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1097 1105 if (in_crit)
1098 1106 nbl_end_crit(vp);
1099 1107 resp->status = NFS3_OK;
1100 1108 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1101 1109 resp->resok.count = 0;
1102 1110 resp->resok.eof = FALSE;
1103 1111 resp->resok.data.data_len = 0;
1104 1112 resp->resok.data.data_val = NULL;
1105 1113 resp->resok.data.mp = NULL;
1106 1114 /* RDMA */
1107 1115 resp->resok.wlist = args->wlist;
1108 1116 resp->resok.wlist_len = resp->resok.count;
1109 1117 if (resp->resok.wlist)
1110 1118 clist_zero_len(resp->resok.wlist);
1111 1119 goto done;
1112 1120 }
1113 1121
1114 1122 /*
1115 1123 * do not allocate memory more the max. allowed
1116 1124 * transfer size
1117 1125 */
1118 1126 if (args->count > rfs3_tsize(req))
1119 1127 args->count = rfs3_tsize(req);
1120 1128
1121 1129 if (loaned_buffers) {
1122 1130 uiop = (uio_t *)rfs_setup_xuio(vp);
1123 1131 ASSERT(uiop != NULL);
1124 1132 uiop->uio_segflg = UIO_SYSSPACE;
1125 1133 uiop->uio_loffset = args->offset;
1126 1134 uiop->uio_resid = args->count;
1127 1135
1128 1136 /* Jump to do the read if successful */
1129 1137 if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
1130 1138 /*
1131 1139 * Need to hold the vnode until after VOP_RETZCBUF()
1132 1140 * is called.
1133 1141 */
1134 1142 VN_HOLD(vp);
1135 1143 goto doio_read;
1136 1144 }
1137 1145
1138 1146 DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
1139 1147 uiop->uio_loffset, int, uiop->uio_resid);
1140 1148
1141 1149 uiop->uio_extflg = 0;
1142 1150 /* failure to setup for zero copy */
1143 1151 rfs_free_xuio((void *)uiop);
1144 1152 loaned_buffers = 0;
1145 1153 }
1146 1154
1147 1155 /*
1148 1156 * If returning data via RDMA Write, then grab the chunk list.
1149 1157 * If we aren't returning READ data w/RDMA_WRITE, then grab
1150 1158 * a mblk.
1151 1159 */
1152 1160 if (rdma_used) {
1153 1161 (void) rdma_get_wchunk(req, &iov, args->wlist);
1154 1162 uio.uio_iov = &iov;
1155 1163 uio.uio_iovcnt = 1;
1156 1164 } else {
1157 1165 /*
1158 1166 * mp will contain the data to be sent out in the read reply.
1159 1167 * For UDP, this will be freed after the reply has been sent
1160 1168 * out by the driver. For TCP, it will be freed after the last
1161 1169 * segment associated with the reply has been ACKed by the
1162 1170 * client.
1163 1171 */
1164 1172 mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
1165 1173 uio.uio_iov = iovp;
1166 1174 uio.uio_iovcnt = iovcnt;
1167 1175 }
1168 1176
1169 1177 uio.uio_segflg = UIO_SYSSPACE;
1170 1178 uio.uio_extflg = UIO_COPY_CACHED;
1171 1179 uio.uio_loffset = args->offset;
1172 1180 uio.uio_resid = args->count;
1173 1181 uiop = &uio;
1174 1182
1175 1183 doio_read:
1176 1184 error = VOP_READ(vp, uiop, 0, cr, &ct);
1177 1185
1178 1186 if (error) {
1179 1187 if (mp)
1180 1188 freemsg(mp);
1181 1189 /* check if a monitor detected a delegation conflict */
1182 1190 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1183 1191 resp->status = NFS3ERR_JUKEBOX;
1184 1192 goto out1;
1185 1193 }
1186 1194 goto out;
1187 1195 }
1188 1196
1189 1197 /* make mblk using zc buffers */
1190 1198 if (loaned_buffers) {
1191 1199 mp = uio_to_mblk(uiop);
1192 1200 ASSERT(mp != NULL);
1193 1201 }
1194 1202
1195 1203 va.va_mask = AT_ALL;
1196 1204 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1197 1205
1198 1206 if (error)
1199 1207 vap = NULL;
1200 1208 else
1201 1209 vap = &va;
1202 1210
1203 1211 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1204 1212
1205 1213 if (in_crit)
1206 1214 nbl_end_crit(vp);
1207 1215
1208 1216 resp->status = NFS3_OK;
1209 1217 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1210 1218 resp->resok.count = args->count - uiop->uio_resid;
1211 1219 if (!error && offset + resp->resok.count == va.va_size)
1212 1220 resp->resok.eof = TRUE;
1213 1221 else
1214 1222 resp->resok.eof = FALSE;
1215 1223 resp->resok.data.data_len = resp->resok.count;
1216 1224
1217 1225 if (mp)
1218 1226 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1219 1227
1220 1228 resp->resok.data.mp = mp;
1221 1229 resp->resok.size = (uint_t)args->count;
1222 1230
1223 1231 if (rdma_used) {
1224 1232 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1225 1233 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1226 1234 resp->status = NFS3ERR_INVAL;
1227 1235 }
1228 1236 } else {
1229 1237 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1230 1238 (resp->resok).wlist = NULL;
1231 1239 }
1232 1240
1233 1241 done:
1234 1242 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1235 1243 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1236 1244 READ3res *, resp);
1237 1245
1238 1246 VN_RELE(vp);
1239 1247
1240 1248 if (iovp != NULL)
1241 1249 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1242 1250
1243 1251 return;
1244 1252
1245 1253 out:
1246 1254 if (curthread->t_flag & T_WOULDBLOCK) {
1247 1255 curthread->t_flag &= ~T_WOULDBLOCK;
1248 1256 resp->status = NFS3ERR_JUKEBOX;
1249 1257 } else
1250 1258 resp->status = puterrno3(error);
1251 1259 out1:
1252 1260 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1253 1261 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1254 1262 READ3res *, resp);
1255 1263
1256 1264 if (vp != NULL) {
1257 1265 if (need_rwunlock)
1258 1266 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1259 1267 if (in_crit)
1260 1268 nbl_end_crit(vp);
1261 1269 VN_RELE(vp);
1262 1270 }
1263 1271 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1264 1272
1265 1273 if (iovp != NULL)
1266 1274 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1267 1275 }
1268 1276
1269 1277 void
1270 1278 rfs3_read_free(READ3res *resp)
1271 1279 {
1272 1280 mblk_t *mp;
1273 1281
1274 1282 if (resp->status == NFS3_OK) {
1275 1283 mp = resp->resok.data.mp;
1276 1284 if (mp != NULL)
1277 1285 freemsg(mp);
1278 1286 }
1279 1287 }
1280 1288
1281 1289 void *
1282 1290 rfs3_read_getfh(READ3args *args)
1283 1291 {
1284 1292
1285 1293 return (&args->file);
1286 1294 }
1287 1295
1288 1296 #define MAX_IOVECS 12
1289 1297
1290 1298 #ifdef DEBUG
1291 1299 static int rfs3_write_hits = 0;
1292 1300 static int rfs3_write_misses = 0;
1293 1301 #endif
1294 1302
1295 1303 void
1296 1304 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1297 1305 struct svc_req *req, cred_t *cr, bool_t ro)
1298 1306 {
1299 1307 nfs3_srv_t *ns;
1300 1308 int error;
1301 1309 vnode_t *vp;
1302 1310 struct vattr *bvap = NULL;
1303 1311 struct vattr bva;
1304 1312 struct vattr *avap = NULL;
1305 1313 struct vattr ava;
1306 1314 u_offset_t rlimit;
1307 1315 struct uio uio;
1308 1316 struct iovec iov[MAX_IOVECS];
1309 1317 mblk_t *m;
1310 1318 struct iovec *iovp;
1311 1319 int iovcnt;
1312 1320 int ioflag;
1313 1321 cred_t *savecred;
1314 1322 int in_crit = 0;
1315 1323 int rwlock_ret = -1;
1316 1324 caller_context_t ct;
1317 1325
1318 1326 vp = nfs3_fhtovp(&args->file, exi);
1319 1327
|
↓ open down ↓ |
1214 lines elided |
↑ open up ↑ |
1320 1328 DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1321 1329 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1322 1330 WRITE3args *, args);
1323 1331
1324 1332 if (vp == NULL) {
1325 1333 error = ESTALE;
1326 1334 goto err;
1327 1335 }
1328 1336
1329 1337 ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
1330 - ns = zone_getspecific(rfs3_zone_key, curzone);
1338 + ns = nfs3_get_srv();
1339 +
1331 1340 if (is_system_labeled()) {
1332 1341 bslabel_t *clabel = req->rq_label;
1333 1342
1334 1343 ASSERT(clabel != NULL);
1335 1344 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1336 1345 "got client label from request(1)", struct svc_req *, req);
1337 1346
1338 1347 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1339 1348 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1340 1349 exi)) {
1341 1350 resp->status = NFS3ERR_ACCES;
1342 1351 goto err1;
1343 1352 }
1344 1353 }
1345 1354 }
1346 1355
1347 1356 ct.cc_sysid = 0;
1348 1357 ct.cc_pid = 0;
1349 1358 ct.cc_caller_id = nfs3_srv_caller_id;
1350 1359 ct.cc_flags = CC_DONTBLOCK;
1351 1360
1352 1361 /*
1353 1362 * We have to enter the critical region before calling VOP_RWLOCK
1354 1363 * to avoid a deadlock with ufs.
1355 1364 */
1356 1365 if (nbl_need_check(vp)) {
1357 1366 nbl_start_crit(vp, RW_READER);
1358 1367 in_crit = 1;
1359 1368 if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1360 1369 NULL)) {
1361 1370 error = EACCES;
1362 1371 goto err;
1363 1372 }
1364 1373 }
1365 1374
1366 1375 rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1367 1376
1368 1377 /* check if a monitor detected a delegation conflict */
1369 1378 if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1370 1379 resp->status = NFS3ERR_JUKEBOX;
1371 1380 rwlock_ret = -1;
1372 1381 goto err1;
1373 1382 }
1374 1383
1375 1384
1376 1385 bva.va_mask = AT_ALL;
1377 1386 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1378 1387
1379 1388 /*
1380 1389 * If we can't get the attributes, then we can't do the
1381 1390 * right access checking. So, we'll fail the request.
1382 1391 */
1383 1392 if (error)
1384 1393 goto err;
1385 1394
1386 1395 bvap = &bva;
1387 1396 avap = bvap;
1388 1397
1389 1398 if (args->count != args->data.data_len) {
1390 1399 resp->status = NFS3ERR_INVAL;
1391 1400 goto err1;
1392 1401 }
1393 1402
1394 1403 if (rdonly(ro, vp)) {
1395 1404 resp->status = NFS3ERR_ROFS;
1396 1405 goto err1;
1397 1406 }
1398 1407
1399 1408 if (vp->v_type != VREG) {
1400 1409 resp->status = NFS3ERR_INVAL;
1401 1410 goto err1;
1402 1411 }
1403 1412
1404 1413 if (crgetuid(cr) != bva.va_uid &&
1405 1414 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1406 1415 goto err;
1407 1416
1408 1417 if (MANDLOCK(vp, bva.va_mode)) {
1409 1418 resp->status = NFS3ERR_ACCES;
1410 1419 goto err1;
1411 1420 }
1412 1421
1413 1422 if (args->count == 0) {
1414 1423 resp->status = NFS3_OK;
1415 1424 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1416 1425 resp->resok.count = 0;
1417 1426 resp->resok.committed = args->stable;
1418 1427 resp->resok.verf = ns->write3verf;
1419 1428 goto out;
1420 1429 }
1421 1430
1422 1431 if (args->mblk != NULL) {
1423 1432 iovcnt = 0;
1424 1433 for (m = args->mblk; m != NULL; m = m->b_cont)
1425 1434 iovcnt++;
1426 1435 if (iovcnt <= MAX_IOVECS) {
1427 1436 #ifdef DEBUG
1428 1437 rfs3_write_hits++;
1429 1438 #endif
1430 1439 iovp = iov;
1431 1440 } else {
1432 1441 #ifdef DEBUG
1433 1442 rfs3_write_misses++;
1434 1443 #endif
1435 1444 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1436 1445 }
1437 1446 mblk_to_iov(args->mblk, iovcnt, iovp);
1438 1447
1439 1448 } else if (args->rlist != NULL) {
1440 1449 iovcnt = 1;
1441 1450 iovp = iov;
1442 1451 iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
1443 1452 iovp->iov_len = args->count;
1444 1453 } else {
1445 1454 iovcnt = 1;
1446 1455 iovp = iov;
1447 1456 iovp->iov_base = args->data.data_val;
1448 1457 iovp->iov_len = args->count;
1449 1458 }
1450 1459
1451 1460 uio.uio_iov = iovp;
1452 1461 uio.uio_iovcnt = iovcnt;
1453 1462
1454 1463 uio.uio_segflg = UIO_SYSSPACE;
1455 1464 uio.uio_extflg = UIO_COPY_DEFAULT;
1456 1465 uio.uio_loffset = args->offset;
1457 1466 uio.uio_resid = args->count;
1458 1467 uio.uio_llimit = curproc->p_fsz_ctl;
1459 1468 rlimit = uio.uio_llimit - args->offset;
1460 1469 if (rlimit < (u_offset_t)uio.uio_resid)
1461 1470 uio.uio_resid = (int)rlimit;
1462 1471
1463 1472 if (args->stable == UNSTABLE)
1464 1473 ioflag = 0;
1465 1474 else if (args->stable == FILE_SYNC)
1466 1475 ioflag = FSYNC;
1467 1476 else if (args->stable == DATA_SYNC)
1468 1477 ioflag = FDSYNC;
1469 1478 else {
1470 1479 if (iovp != iov)
1471 1480 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1472 1481 resp->status = NFS3ERR_INVAL;
1473 1482 goto err1;
1474 1483 }
1475 1484
1476 1485 /*
1477 1486 * We're changing creds because VM may fault and we need
1478 1487 * the cred of the current thread to be used if quota
1479 1488 * checking is enabled.
1480 1489 */
1481 1490 savecred = curthread->t_cred;
1482 1491 curthread->t_cred = cr;
1483 1492 error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1484 1493 curthread->t_cred = savecred;
1485 1494
1486 1495 if (iovp != iov)
1487 1496 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1488 1497
1489 1498 /* check if a monitor detected a delegation conflict */
1490 1499 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1491 1500 resp->status = NFS3ERR_JUKEBOX;
1492 1501 goto err1;
1493 1502 }
1494 1503
1495 1504 ava.va_mask = AT_ALL;
1496 1505 avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1497 1506
1498 1507 if (error)
1499 1508 goto err;
1500 1509
1501 1510 /*
1502 1511 * If we were unable to get the V_WRITELOCK_TRUE, then we
1503 1512 * may not have accurate after attrs, so check if
1504 1513 * we have both attributes, they have a non-zero va_seq, and
1505 1514 * va_seq has changed by exactly one,
1506 1515 * if not, turn off the before attr.
1507 1516 */
1508 1517 if (rwlock_ret != V_WRITELOCK_TRUE) {
1509 1518 if (bvap == NULL || avap == NULL ||
1510 1519 bvap->va_seq == 0 || avap->va_seq == 0 ||
1511 1520 avap->va_seq != (bvap->va_seq + 1)) {
1512 1521 bvap = NULL;
1513 1522 }
1514 1523 }
1515 1524
1516 1525 resp->status = NFS3_OK;
1517 1526 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1518 1527 resp->resok.count = args->count - uio.uio_resid;
1519 1528 resp->resok.committed = args->stable;
1520 1529 resp->resok.verf = ns->write3verf;
1521 1530 goto out;
1522 1531
1523 1532 err:
1524 1533 if (curthread->t_flag & T_WOULDBLOCK) {
1525 1534 curthread->t_flag &= ~T_WOULDBLOCK;
1526 1535 resp->status = NFS3ERR_JUKEBOX;
1527 1536 } else
1528 1537 resp->status = puterrno3(error);
1529 1538 err1:
1530 1539 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1531 1540 out:
1532 1541 DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1533 1542 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1534 1543 WRITE3res *, resp);
1535 1544
1536 1545 if (vp != NULL) {
1537 1546 if (rwlock_ret != -1)
1538 1547 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1539 1548 if (in_crit)
1540 1549 nbl_end_crit(vp);
1541 1550 VN_RELE(vp);
1542 1551 }
1543 1552 }
1544 1553
1545 1554 void *
1546 1555 rfs3_write_getfh(WRITE3args *args)
1547 1556 {
1548 1557
1549 1558 return (&args->file);
1550 1559 }
1551 1560
1552 1561 void
1553 1562 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1554 1563 struct svc_req *req, cred_t *cr, bool_t ro)
1555 1564 {
1556 1565 int error;
1557 1566 int in_crit = 0;
1558 1567 vnode_t *vp;
1559 1568 vnode_t *tvp = NULL;
1560 1569 vnode_t *dvp;
1561 1570 struct vattr *vap;
1562 1571 struct vattr va;
1563 1572 struct vattr *dbvap;
1564 1573 struct vattr dbva;
1565 1574 struct vattr *davap;
1566 1575 struct vattr dava;
1567 1576 enum vcexcl excl;
1568 1577 nfstime3 *mtime;
1569 1578 len_t reqsize;
1570 1579 bool_t trunc;
1571 1580 struct sockaddr *ca;
1572 1581 char *name = NULL;
1573 1582
1574 1583 dbvap = NULL;
1575 1584 davap = NULL;
1576 1585
1577 1586 dvp = nfs3_fhtovp(&args->where.dir, exi);
1578 1587
1579 1588 DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1580 1589 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1581 1590 CREATE3args *, args);
1582 1591
1583 1592 if (dvp == NULL) {
1584 1593 error = ESTALE;
1585 1594 goto out;
1586 1595 }
1587 1596
1588 1597 dbva.va_mask = AT_ALL;
1589 1598 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1590 1599 davap = dbvap;
1591 1600
1592 1601 if (args->where.name == nfs3nametoolong) {
1593 1602 resp->status = NFS3ERR_NAMETOOLONG;
1594 1603 goto out1;
1595 1604 }
1596 1605
1597 1606 if (args->where.name == NULL || *(args->where.name) == '\0') {
1598 1607 resp->status = NFS3ERR_ACCES;
1599 1608 goto out1;
1600 1609 }
1601 1610
1602 1611 if (rdonly(ro, dvp)) {
1603 1612 resp->status = NFS3ERR_ROFS;
1604 1613 goto out1;
1605 1614 }
1606 1615
1607 1616 if (is_system_labeled()) {
1608 1617 bslabel_t *clabel = req->rq_label;
1609 1618
1610 1619 ASSERT(clabel != NULL);
1611 1620 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1612 1621 "got client label from request(1)", struct svc_req *, req);
1613 1622
1614 1623 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1615 1624 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1616 1625 exi)) {
1617 1626 resp->status = NFS3ERR_ACCES;
1618 1627 goto out1;
1619 1628 }
1620 1629 }
1621 1630 }
1622 1631
1623 1632 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1624 1633 name = nfscmd_convname(ca, exi, args->where.name,
1625 1634 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1626 1635
1627 1636 if (name == NULL) {
1628 1637 /* This is really a Solaris EILSEQ */
1629 1638 resp->status = NFS3ERR_INVAL;
1630 1639 goto out1;
1631 1640 }
1632 1641
1633 1642 if (args->how.mode == EXCLUSIVE) {
1634 1643 va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
1635 1644 va.va_type = VREG;
1636 1645 va.va_mode = (mode_t)0;
1637 1646 /*
1638 1647 * Ensure no time overflows and that types match
1639 1648 */
1640 1649 mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1641 1650 va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
1642 1651 va.va_mtime.tv_nsec = mtime->nseconds;
1643 1652 excl = EXCL;
1644 1653 } else {
1645 1654 error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
1646 1655 &va);
1647 1656 if (error)
1648 1657 goto out;
1649 1658 va.va_mask |= AT_TYPE;
1650 1659 va.va_type = VREG;
1651 1660 if (args->how.mode == GUARDED)
1652 1661 excl = EXCL;
1653 1662 else {
1654 1663 excl = NONEXCL;
1655 1664
1656 1665 /*
1657 1666 * During creation of file in non-exclusive mode
1658 1667 * if size of file is being set then make sure
1659 1668 * that if the file already exists that no conflicting
1660 1669 * non-blocking mandatory locks exists in the region
1661 1670 * being modified. If there are conflicting locks fail
1662 1671 * the operation with EACCES.
1663 1672 */
1664 1673 if (va.va_mask & AT_SIZE) {
1665 1674 struct vattr tva;
1666 1675
1667 1676 /*
1668 1677 * Does file already exist?
1669 1678 */
1670 1679 error = VOP_LOOKUP(dvp, name, &tvp,
1671 1680 NULL, 0, NULL, cr, NULL, NULL, NULL);
1672 1681
1673 1682 /*
1674 1683 * Check to see if the file has been delegated
1675 1684 * to a v4 client. If so, then begin recall of
1676 1685 * the delegation and return JUKEBOX to allow
1677 1686 * the client to retrasmit its request.
1678 1687 */
1679 1688
1680 1689 trunc = va.va_size == 0;
1681 1690 if (!error &&
1682 1691 rfs4_check_delegated(FWRITE, tvp, trunc)) {
1683 1692 resp->status = NFS3ERR_JUKEBOX;
1684 1693 goto out1;
1685 1694 }
1686 1695
1687 1696 /*
1688 1697 * Check for NBMAND lock conflicts
1689 1698 */
1690 1699 if (!error && nbl_need_check(tvp)) {
1691 1700 u_offset_t offset;
1692 1701 ssize_t len;
1693 1702
1694 1703 nbl_start_crit(tvp, RW_READER);
1695 1704 in_crit = 1;
1696 1705
1697 1706 tva.va_mask = AT_SIZE;
1698 1707 error = VOP_GETATTR(tvp, &tva, 0, cr,
1699 1708 NULL);
1700 1709 /*
1701 1710 * Can't check for conflicts, so return
1702 1711 * error.
1703 1712 */
1704 1713 if (error)
1705 1714 goto out;
1706 1715
1707 1716 offset = tva.va_size < va.va_size ?
1708 1717 tva.va_size : va.va_size;
1709 1718 len = tva.va_size < va.va_size ?
1710 1719 va.va_size - tva.va_size :
1711 1720 tva.va_size - va.va_size;
1712 1721 if (nbl_conflict(tvp, NBL_WRITE,
1713 1722 offset, len, 0, NULL)) {
1714 1723 error = EACCES;
1715 1724 goto out;
1716 1725 }
1717 1726 } else if (tvp) {
1718 1727 VN_RELE(tvp);
1719 1728 tvp = NULL;
1720 1729 }
1721 1730 }
1722 1731 }
1723 1732 if (va.va_mask & AT_SIZE)
1724 1733 reqsize = va.va_size;
1725 1734 }
1726 1735
1727 1736 /*
1728 1737 * Must specify the mode.
1729 1738 */
1730 1739 if (!(va.va_mask & AT_MODE)) {
1731 1740 resp->status = NFS3ERR_INVAL;
1732 1741 goto out1;
1733 1742 }
1734 1743
1735 1744 /*
1736 1745 * If the filesystem is exported with nosuid, then mask off
1737 1746 * the setuid and setgid bits.
1738 1747 */
1739 1748 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1740 1749 va.va_mode &= ~(VSUID | VSGID);
1741 1750
1742 1751 tryagain:
1743 1752 /*
1744 1753 * The file open mode used is VWRITE. If the client needs
1745 1754 * some other semantic, then it should do the access checking
1746 1755 * itself. It would have been nice to have the file open mode
1747 1756 * passed as part of the arguments.
1748 1757 */
1749 1758 error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1750 1759 &vp, cr, 0, NULL, NULL);
1751 1760
1752 1761 dava.va_mask = AT_ALL;
1753 1762 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1754 1763
1755 1764 if (error) {
1756 1765 /*
1757 1766 * If we got something other than file already exists
1758 1767 * then just return this error. Otherwise, we got
1759 1768 * EEXIST. If we were doing a GUARDED create, then
1760 1769 * just return this error. Otherwise, we need to
1761 1770 * make sure that this wasn't a duplicate of an
1762 1771 * exclusive create request.
1763 1772 *
1764 1773 * The assumption is made that a non-exclusive create
1765 1774 * request will never return EEXIST.
1766 1775 */
1767 1776 if (error != EEXIST || args->how.mode == GUARDED)
1768 1777 goto out;
1769 1778 /*
1770 1779 * Lookup the file so that we can get a vnode for it.
1771 1780 */
1772 1781 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1773 1782 NULL, cr, NULL, NULL, NULL);
1774 1783 if (error) {
1775 1784 /*
1776 1785 * We couldn't find the file that we thought that
1777 1786 * we just created. So, we'll just try creating
1778 1787 * it again.
1779 1788 */
1780 1789 if (error == ENOENT)
1781 1790 goto tryagain;
1782 1791 goto out;
1783 1792 }
1784 1793
1785 1794 /*
1786 1795 * If the file is delegated to a v4 client, go ahead
1787 1796 * and initiate recall, this create is a hint that a
1788 1797 * conflicting v3 open has occurred.
1789 1798 */
1790 1799
1791 1800 if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
1792 1801 VN_RELE(vp);
1793 1802 resp->status = NFS3ERR_JUKEBOX;
1794 1803 goto out1;
1795 1804 }
1796 1805
1797 1806 va.va_mask = AT_ALL;
1798 1807 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1799 1808
1800 1809 mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1801 1810 /* % with INT32_MAX to prevent overflows */
1802 1811 if (args->how.mode == EXCLUSIVE && (vap == NULL ||
1803 1812 vap->va_mtime.tv_sec !=
1804 1813 (mtime->seconds % INT32_MAX) ||
1805 1814 vap->va_mtime.tv_nsec != mtime->nseconds)) {
1806 1815 VN_RELE(vp);
1807 1816 error = EEXIST;
1808 1817 goto out;
1809 1818 }
1810 1819 } else {
1811 1820
1812 1821 if ((args->how.mode == UNCHECKED ||
1813 1822 args->how.mode == GUARDED) &&
1814 1823 args->how.createhow3_u.obj_attributes.size.set_it &&
1815 1824 va.va_size == 0)
1816 1825 trunc = TRUE;
1817 1826 else
1818 1827 trunc = FALSE;
1819 1828
1820 1829 if (rfs4_check_delegated(FWRITE, vp, trunc)) {
1821 1830 VN_RELE(vp);
1822 1831 resp->status = NFS3ERR_JUKEBOX;
1823 1832 goto out1;
1824 1833 }
1825 1834
1826 1835 va.va_mask = AT_ALL;
1827 1836 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1828 1837
1829 1838 /*
1830 1839 * We need to check to make sure that the file got
1831 1840 * created to the indicated size. If not, we do a
1832 1841 * setattr to try to change the size, but we don't
1833 1842 * try too hard. This shouldn't a problem as most
1834 1843 * clients will only specifiy a size of zero which
1835 1844 * local file systems handle. However, even if
1836 1845 * the client does specify a non-zero size, it can
1837 1846 * still recover by checking the size of the file
1838 1847 * after it has created it and then issue a setattr
1839 1848 * request of its own to set the size of the file.
1840 1849 */
1841 1850 if (vap != NULL &&
1842 1851 (args->how.mode == UNCHECKED ||
1843 1852 args->how.mode == GUARDED) &&
1844 1853 args->how.createhow3_u.obj_attributes.size.set_it &&
1845 1854 vap->va_size != reqsize) {
1846 1855 va.va_mask = AT_SIZE;
1847 1856 va.va_size = reqsize;
1848 1857 (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1849 1858 va.va_mask = AT_ALL;
1850 1859 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1851 1860 }
1852 1861 }
1853 1862
1854 1863 if (name != args->where.name)
1855 1864 kmem_free(name, MAXPATHLEN + 1);
1856 1865
1857 1866 error = makefh3(&resp->resok.obj.handle, vp, exi);
1858 1867 if (error)
1859 1868 resp->resok.obj.handle_follows = FALSE;
1860 1869 else
1861 1870 resp->resok.obj.handle_follows = TRUE;
1862 1871
1863 1872 /*
1864 1873 * Force modified data and metadata out to stable storage.
1865 1874 */
1866 1875 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1867 1876 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1868 1877
1869 1878 VN_RELE(vp);
1870 1879 if (tvp != NULL) {
1871 1880 if (in_crit)
1872 1881 nbl_end_crit(tvp);
1873 1882 VN_RELE(tvp);
1874 1883 }
1875 1884
1876 1885 resp->status = NFS3_OK;
1877 1886 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1878 1887 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1879 1888
1880 1889 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1881 1890 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1882 1891 CREATE3res *, resp);
1883 1892
1884 1893 VN_RELE(dvp);
1885 1894 return;
1886 1895
1887 1896 out:
1888 1897 if (curthread->t_flag & T_WOULDBLOCK) {
1889 1898 curthread->t_flag &= ~T_WOULDBLOCK;
1890 1899 resp->status = NFS3ERR_JUKEBOX;
1891 1900 } else
1892 1901 resp->status = puterrno3(error);
1893 1902 out1:
1894 1903 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1895 1904 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1896 1905 CREATE3res *, resp);
1897 1906
1898 1907 if (name != NULL && name != args->where.name)
1899 1908 kmem_free(name, MAXPATHLEN + 1);
1900 1909
1901 1910 if (tvp != NULL) {
1902 1911 if (in_crit)
1903 1912 nbl_end_crit(tvp);
1904 1913 VN_RELE(tvp);
1905 1914 }
1906 1915 if (dvp != NULL)
1907 1916 VN_RELE(dvp);
1908 1917 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1909 1918 }
1910 1919
1911 1920 void *
1912 1921 rfs3_create_getfh(CREATE3args *args)
1913 1922 {
1914 1923
1915 1924 return (&args->where.dir);
1916 1925 }
1917 1926
1918 1927 void
1919 1928 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1920 1929 struct svc_req *req, cred_t *cr, bool_t ro)
1921 1930 {
1922 1931 int error;
1923 1932 vnode_t *vp = NULL;
1924 1933 vnode_t *dvp;
1925 1934 struct vattr *vap;
1926 1935 struct vattr va;
1927 1936 struct vattr *dbvap;
1928 1937 struct vattr dbva;
1929 1938 struct vattr *davap;
1930 1939 struct vattr dava;
1931 1940 struct sockaddr *ca;
1932 1941 char *name = NULL;
1933 1942
1934 1943 dbvap = NULL;
1935 1944 davap = NULL;
1936 1945
1937 1946 dvp = nfs3_fhtovp(&args->where.dir, exi);
1938 1947
1939 1948 DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1940 1949 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1941 1950 MKDIR3args *, args);
1942 1951
1943 1952 if (dvp == NULL) {
1944 1953 error = ESTALE;
1945 1954 goto out;
1946 1955 }
1947 1956
1948 1957 dbva.va_mask = AT_ALL;
1949 1958 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1950 1959 davap = dbvap;
1951 1960
1952 1961 if (args->where.name == nfs3nametoolong) {
1953 1962 resp->status = NFS3ERR_NAMETOOLONG;
1954 1963 goto out1;
1955 1964 }
1956 1965
1957 1966 if (args->where.name == NULL || *(args->where.name) == '\0') {
1958 1967 resp->status = NFS3ERR_ACCES;
1959 1968 goto out1;
1960 1969 }
1961 1970
1962 1971 if (rdonly(ro, dvp)) {
1963 1972 resp->status = NFS3ERR_ROFS;
1964 1973 goto out1;
1965 1974 }
1966 1975
1967 1976 if (is_system_labeled()) {
1968 1977 bslabel_t *clabel = req->rq_label;
1969 1978
1970 1979 ASSERT(clabel != NULL);
1971 1980 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1972 1981 "got client label from request(1)", struct svc_req *, req);
1973 1982
1974 1983 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1975 1984 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1976 1985 exi)) {
1977 1986 resp->status = NFS3ERR_ACCES;
1978 1987 goto out1;
1979 1988 }
1980 1989 }
1981 1990 }
1982 1991
1983 1992 error = sattr3_to_vattr(&args->attributes, &va);
1984 1993 if (error)
1985 1994 goto out;
1986 1995
1987 1996 if (!(va.va_mask & AT_MODE)) {
1988 1997 resp->status = NFS3ERR_INVAL;
1989 1998 goto out1;
1990 1999 }
1991 2000
1992 2001 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1993 2002 name = nfscmd_convname(ca, exi, args->where.name,
1994 2003 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1995 2004
1996 2005 if (name == NULL) {
1997 2006 resp->status = NFS3ERR_INVAL;
1998 2007 goto out1;
1999 2008 }
2000 2009
2001 2010 va.va_mask |= AT_TYPE;
2002 2011 va.va_type = VDIR;
2003 2012
2004 2013 error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
2005 2014
2006 2015 if (name != args->where.name)
2007 2016 kmem_free(name, MAXPATHLEN + 1);
2008 2017
2009 2018 dava.va_mask = AT_ALL;
2010 2019 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2011 2020
2012 2021 /*
2013 2022 * Force modified data and metadata out to stable storage.
2014 2023 */
2015 2024 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2016 2025
2017 2026 if (error)
2018 2027 goto out;
2019 2028
2020 2029 error = makefh3(&resp->resok.obj.handle, vp, exi);
2021 2030 if (error)
2022 2031 resp->resok.obj.handle_follows = FALSE;
2023 2032 else
2024 2033 resp->resok.obj.handle_follows = TRUE;
2025 2034
2026 2035 va.va_mask = AT_ALL;
2027 2036 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2028 2037
2029 2038 /*
2030 2039 * Force modified data and metadata out to stable storage.
2031 2040 */
2032 2041 (void) VOP_FSYNC(vp, 0, cr, NULL);
2033 2042
2034 2043 VN_RELE(vp);
2035 2044
2036 2045 resp->status = NFS3_OK;
2037 2046 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2038 2047 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2039 2048
2040 2049 DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2041 2050 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2042 2051 MKDIR3res *, resp);
2043 2052 VN_RELE(dvp);
2044 2053
2045 2054 return;
2046 2055
2047 2056 out:
2048 2057 if (curthread->t_flag & T_WOULDBLOCK) {
2049 2058 curthread->t_flag &= ~T_WOULDBLOCK;
2050 2059 resp->status = NFS3ERR_JUKEBOX;
2051 2060 } else
2052 2061 resp->status = puterrno3(error);
2053 2062 out1:
2054 2063 DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2055 2064 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2056 2065 MKDIR3res *, resp);
2057 2066 if (dvp != NULL)
2058 2067 VN_RELE(dvp);
2059 2068 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2060 2069 }
2061 2070
2062 2071 void *
2063 2072 rfs3_mkdir_getfh(MKDIR3args *args)
2064 2073 {
2065 2074
2066 2075 return (&args->where.dir);
2067 2076 }
2068 2077
2069 2078 void
2070 2079 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2071 2080 struct svc_req *req, cred_t *cr, bool_t ro)
2072 2081 {
2073 2082 int error;
2074 2083 vnode_t *vp;
2075 2084 vnode_t *dvp;
2076 2085 struct vattr *vap;
2077 2086 struct vattr va;
2078 2087 struct vattr *dbvap;
2079 2088 struct vattr dbva;
2080 2089 struct vattr *davap;
2081 2090 struct vattr dava;
2082 2091 struct sockaddr *ca;
2083 2092 char *name = NULL;
2084 2093 char *symdata = NULL;
2085 2094
2086 2095 dbvap = NULL;
2087 2096 davap = NULL;
2088 2097
2089 2098 dvp = nfs3_fhtovp(&args->where.dir, exi);
2090 2099
2091 2100 DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2092 2101 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2093 2102 SYMLINK3args *, args);
2094 2103
2095 2104 if (dvp == NULL) {
2096 2105 error = ESTALE;
2097 2106 goto err;
2098 2107 }
2099 2108
2100 2109 dbva.va_mask = AT_ALL;
2101 2110 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2102 2111 davap = dbvap;
2103 2112
2104 2113 if (args->where.name == nfs3nametoolong) {
2105 2114 resp->status = NFS3ERR_NAMETOOLONG;
2106 2115 goto err1;
2107 2116 }
2108 2117
2109 2118 if (args->where.name == NULL || *(args->where.name) == '\0') {
2110 2119 resp->status = NFS3ERR_ACCES;
2111 2120 goto err1;
2112 2121 }
2113 2122
2114 2123 if (rdonly(ro, dvp)) {
2115 2124 resp->status = NFS3ERR_ROFS;
2116 2125 goto err1;
2117 2126 }
2118 2127
2119 2128 if (is_system_labeled()) {
2120 2129 bslabel_t *clabel = req->rq_label;
2121 2130
2122 2131 ASSERT(clabel != NULL);
2123 2132 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2124 2133 "got client label from request(1)", struct svc_req *, req);
2125 2134
2126 2135 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2127 2136 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2128 2137 exi)) {
2129 2138 resp->status = NFS3ERR_ACCES;
2130 2139 goto err1;
2131 2140 }
2132 2141 }
2133 2142 }
2134 2143
2135 2144 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2136 2145 if (error)
2137 2146 goto err;
2138 2147
2139 2148 if (!(va.va_mask & AT_MODE)) {
2140 2149 resp->status = NFS3ERR_INVAL;
2141 2150 goto err1;
2142 2151 }
2143 2152
2144 2153 if (args->symlink.symlink_data == nfs3nametoolong) {
2145 2154 resp->status = NFS3ERR_NAMETOOLONG;
2146 2155 goto err1;
2147 2156 }
2148 2157
2149 2158 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2150 2159 name = nfscmd_convname(ca, exi, args->where.name,
2151 2160 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2152 2161
2153 2162 if (name == NULL) {
2154 2163 /* This is really a Solaris EILSEQ */
2155 2164 resp->status = NFS3ERR_INVAL;
2156 2165 goto err1;
2157 2166 }
2158 2167
2159 2168 symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2160 2169 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2161 2170 if (symdata == NULL) {
2162 2171 /* This is really a Solaris EILSEQ */
2163 2172 resp->status = NFS3ERR_INVAL;
2164 2173 goto err1;
2165 2174 }
2166 2175
2167 2176
2168 2177 va.va_mask |= AT_TYPE;
2169 2178 va.va_type = VLNK;
2170 2179
2171 2180 error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2172 2181
2173 2182 dava.va_mask = AT_ALL;
2174 2183 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2175 2184
2176 2185 if (error)
2177 2186 goto err;
2178 2187
2179 2188 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2180 2189 NULL, NULL, NULL);
2181 2190
2182 2191 /*
2183 2192 * Force modified data and metadata out to stable storage.
2184 2193 */
2185 2194 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2186 2195
2187 2196
2188 2197 resp->status = NFS3_OK;
2189 2198 if (error) {
2190 2199 resp->resok.obj.handle_follows = FALSE;
2191 2200 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2192 2201 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2193 2202 goto out;
2194 2203 }
2195 2204
2196 2205 error = makefh3(&resp->resok.obj.handle, vp, exi);
2197 2206 if (error)
2198 2207 resp->resok.obj.handle_follows = FALSE;
2199 2208 else
2200 2209 resp->resok.obj.handle_follows = TRUE;
2201 2210
2202 2211 va.va_mask = AT_ALL;
2203 2212 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2204 2213
2205 2214 /*
2206 2215 * Force modified data and metadata out to stable storage.
2207 2216 */
2208 2217 (void) VOP_FSYNC(vp, 0, cr, NULL);
2209 2218
2210 2219 VN_RELE(vp);
2211 2220
2212 2221 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2213 2222 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2214 2223 goto out;
2215 2224
2216 2225 err:
2217 2226 if (curthread->t_flag & T_WOULDBLOCK) {
2218 2227 curthread->t_flag &= ~T_WOULDBLOCK;
2219 2228 resp->status = NFS3ERR_JUKEBOX;
2220 2229 } else
2221 2230 resp->status = puterrno3(error);
2222 2231 err1:
2223 2232 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2224 2233 out:
2225 2234 if (name != NULL && name != args->where.name)
2226 2235 kmem_free(name, MAXPATHLEN + 1);
2227 2236 if (symdata != NULL && symdata != args->symlink.symlink_data)
2228 2237 kmem_free(symdata, MAXPATHLEN + 1);
2229 2238
2230 2239 DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2231 2240 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2232 2241 SYMLINK3res *, resp);
2233 2242
2234 2243 if (dvp != NULL)
2235 2244 VN_RELE(dvp);
2236 2245 }
2237 2246
2238 2247 void *
2239 2248 rfs3_symlink_getfh(SYMLINK3args *args)
2240 2249 {
2241 2250
2242 2251 return (&args->where.dir);
2243 2252 }
2244 2253
2245 2254 void
2246 2255 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2247 2256 struct svc_req *req, cred_t *cr, bool_t ro)
2248 2257 {
2249 2258 int error;
2250 2259 vnode_t *vp;
2251 2260 vnode_t *realvp;
2252 2261 vnode_t *dvp;
2253 2262 struct vattr *vap;
2254 2263 struct vattr va;
2255 2264 struct vattr *dbvap;
2256 2265 struct vattr dbva;
2257 2266 struct vattr *davap;
2258 2267 struct vattr dava;
2259 2268 int mode;
2260 2269 enum vcexcl excl;
2261 2270 struct sockaddr *ca;
2262 2271 char *name = NULL;
2263 2272
2264 2273 dbvap = NULL;
2265 2274 davap = NULL;
2266 2275
2267 2276 dvp = nfs3_fhtovp(&args->where.dir, exi);
2268 2277
2269 2278 DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2270 2279 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2271 2280 MKNOD3args *, args);
2272 2281
2273 2282 if (dvp == NULL) {
2274 2283 error = ESTALE;
2275 2284 goto out;
2276 2285 }
2277 2286
2278 2287 dbva.va_mask = AT_ALL;
2279 2288 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2280 2289 davap = dbvap;
2281 2290
2282 2291 if (args->where.name == nfs3nametoolong) {
2283 2292 resp->status = NFS3ERR_NAMETOOLONG;
2284 2293 goto out1;
2285 2294 }
2286 2295
2287 2296 if (args->where.name == NULL || *(args->where.name) == '\0') {
2288 2297 resp->status = NFS3ERR_ACCES;
2289 2298 goto out1;
2290 2299 }
2291 2300
2292 2301 if (rdonly(ro, dvp)) {
2293 2302 resp->status = NFS3ERR_ROFS;
2294 2303 goto out1;
2295 2304 }
2296 2305
2297 2306 if (is_system_labeled()) {
2298 2307 bslabel_t *clabel = req->rq_label;
2299 2308
2300 2309 ASSERT(clabel != NULL);
2301 2310 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2302 2311 "got client label from request(1)", struct svc_req *, req);
2303 2312
2304 2313 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2305 2314 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2306 2315 exi)) {
2307 2316 resp->status = NFS3ERR_ACCES;
2308 2317 goto out1;
2309 2318 }
2310 2319 }
2311 2320 }
2312 2321
2313 2322 switch (args->what.type) {
2314 2323 case NF3CHR:
2315 2324 case NF3BLK:
2316 2325 error = sattr3_to_vattr(
2317 2326 &args->what.mknoddata3_u.device.dev_attributes, &va);
2318 2327 if (error)
2319 2328 goto out;
2320 2329 if (secpolicy_sys_devices(cr) != 0) {
2321 2330 resp->status = NFS3ERR_PERM;
2322 2331 goto out1;
2323 2332 }
2324 2333 if (args->what.type == NF3CHR)
2325 2334 va.va_type = VCHR;
2326 2335 else
2327 2336 va.va_type = VBLK;
2328 2337 va.va_rdev = makedevice(
2329 2338 args->what.mknoddata3_u.device.spec.specdata1,
2330 2339 args->what.mknoddata3_u.device.spec.specdata2);
2331 2340 va.va_mask |= AT_TYPE | AT_RDEV;
2332 2341 break;
2333 2342 case NF3SOCK:
2334 2343 error = sattr3_to_vattr(
2335 2344 &args->what.mknoddata3_u.pipe_attributes, &va);
2336 2345 if (error)
2337 2346 goto out;
2338 2347 va.va_type = VSOCK;
2339 2348 va.va_mask |= AT_TYPE;
2340 2349 break;
2341 2350 case NF3FIFO:
2342 2351 error = sattr3_to_vattr(
2343 2352 &args->what.mknoddata3_u.pipe_attributes, &va);
2344 2353 if (error)
2345 2354 goto out;
2346 2355 va.va_type = VFIFO;
2347 2356 va.va_mask |= AT_TYPE;
2348 2357 break;
2349 2358 default:
2350 2359 resp->status = NFS3ERR_BADTYPE;
2351 2360 goto out1;
2352 2361 }
2353 2362
2354 2363 /*
2355 2364 * Must specify the mode.
2356 2365 */
2357 2366 if (!(va.va_mask & AT_MODE)) {
2358 2367 resp->status = NFS3ERR_INVAL;
2359 2368 goto out1;
2360 2369 }
2361 2370
2362 2371 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2363 2372 name = nfscmd_convname(ca, exi, args->where.name,
2364 2373 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2365 2374
2366 2375 if (name == NULL) {
2367 2376 resp->status = NFS3ERR_INVAL;
2368 2377 goto out1;
2369 2378 }
2370 2379
2371 2380 excl = EXCL;
2372 2381
2373 2382 mode = 0;
2374 2383
2375 2384 error = VOP_CREATE(dvp, name, &va, excl, mode,
2376 2385 &vp, cr, 0, NULL, NULL);
2377 2386
2378 2387 if (name != args->where.name)
2379 2388 kmem_free(name, MAXPATHLEN + 1);
2380 2389
2381 2390 dava.va_mask = AT_ALL;
2382 2391 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2383 2392
2384 2393 /*
2385 2394 * Force modified data and metadata out to stable storage.
2386 2395 */
2387 2396 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2388 2397
2389 2398 if (error)
2390 2399 goto out;
2391 2400
2392 2401 resp->status = NFS3_OK;
2393 2402
2394 2403 error = makefh3(&resp->resok.obj.handle, vp, exi);
2395 2404 if (error)
2396 2405 resp->resok.obj.handle_follows = FALSE;
2397 2406 else
2398 2407 resp->resok.obj.handle_follows = TRUE;
2399 2408
2400 2409 va.va_mask = AT_ALL;
2401 2410 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2402 2411
2403 2412 /*
2404 2413 * Force modified metadata out to stable storage.
2405 2414 *
2406 2415 * if a underlying vp exists, pass it to VOP_FSYNC
2407 2416 */
2408 2417 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2409 2418 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2410 2419 else
2411 2420 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2412 2421
2413 2422 VN_RELE(vp);
2414 2423
2415 2424 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2416 2425 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2417 2426 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2418 2427 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2419 2428 MKNOD3res *, resp);
2420 2429 VN_RELE(dvp);
2421 2430 return;
2422 2431
2423 2432 out:
2424 2433 if (curthread->t_flag & T_WOULDBLOCK) {
2425 2434 curthread->t_flag &= ~T_WOULDBLOCK;
2426 2435 resp->status = NFS3ERR_JUKEBOX;
2427 2436 } else
2428 2437 resp->status = puterrno3(error);
2429 2438 out1:
2430 2439 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2431 2440 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2432 2441 MKNOD3res *, resp);
2433 2442 if (dvp != NULL)
2434 2443 VN_RELE(dvp);
2435 2444 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2436 2445 }
2437 2446
2438 2447 void *
2439 2448 rfs3_mknod_getfh(MKNOD3args *args)
2440 2449 {
2441 2450
2442 2451 return (&args->where.dir);
2443 2452 }
2444 2453
2445 2454 void
2446 2455 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2447 2456 struct svc_req *req, cred_t *cr, bool_t ro)
2448 2457 {
2449 2458 int error = 0;
2450 2459 vnode_t *vp;
2451 2460 struct vattr *bvap;
2452 2461 struct vattr bva;
2453 2462 struct vattr *avap;
2454 2463 struct vattr ava;
2455 2464 vnode_t *targvp = NULL;
2456 2465 struct sockaddr *ca;
2457 2466 char *name = NULL;
2458 2467
2459 2468 bvap = NULL;
2460 2469 avap = NULL;
2461 2470
2462 2471 vp = nfs3_fhtovp(&args->object.dir, exi);
2463 2472
2464 2473 DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2465 2474 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2466 2475 REMOVE3args *, args);
2467 2476
2468 2477 if (vp == NULL) {
2469 2478 error = ESTALE;
2470 2479 goto err;
2471 2480 }
2472 2481
2473 2482 bva.va_mask = AT_ALL;
2474 2483 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2475 2484 avap = bvap;
2476 2485
2477 2486 if (vp->v_type != VDIR) {
2478 2487 resp->status = NFS3ERR_NOTDIR;
2479 2488 goto err1;
2480 2489 }
2481 2490
2482 2491 if (args->object.name == nfs3nametoolong) {
2483 2492 resp->status = NFS3ERR_NAMETOOLONG;
2484 2493 goto err1;
2485 2494 }
2486 2495
2487 2496 if (args->object.name == NULL || *(args->object.name) == '\0') {
2488 2497 resp->status = NFS3ERR_ACCES;
2489 2498 goto err1;
2490 2499 }
2491 2500
2492 2501 if (rdonly(ro, vp)) {
2493 2502 resp->status = NFS3ERR_ROFS;
2494 2503 goto err1;
2495 2504 }
2496 2505
2497 2506 if (is_system_labeled()) {
2498 2507 bslabel_t *clabel = req->rq_label;
2499 2508
2500 2509 ASSERT(clabel != NULL);
2501 2510 DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
2502 2511 "got client label from request(1)", struct svc_req *, req);
2503 2512
2504 2513 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2505 2514 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2506 2515 exi)) {
2507 2516 resp->status = NFS3ERR_ACCES;
2508 2517 goto err1;
2509 2518 }
2510 2519 }
2511 2520 }
2512 2521
2513 2522 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2514 2523 name = nfscmd_convname(ca, exi, args->object.name,
2515 2524 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2516 2525
2517 2526 if (name == NULL) {
2518 2527 resp->status = NFS3ERR_INVAL;
2519 2528 goto err1;
2520 2529 }
2521 2530
2522 2531 /*
2523 2532 * Check for a conflict with a non-blocking mandatory share
2524 2533 * reservation and V4 delegations
2525 2534 */
2526 2535 error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2527 2536 NULL, cr, NULL, NULL, NULL);
2528 2537 if (error != 0)
2529 2538 goto err;
2530 2539
2531 2540 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2532 2541 resp->status = NFS3ERR_JUKEBOX;
2533 2542 goto err1;
2534 2543 }
2535 2544
2536 2545 if (!nbl_need_check(targvp)) {
2537 2546 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2538 2547 } else {
2539 2548 nbl_start_crit(targvp, RW_READER);
2540 2549 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2541 2550 error = EACCES;
2542 2551 } else {
2543 2552 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2544 2553 }
2545 2554 nbl_end_crit(targvp);
2546 2555 }
2547 2556 VN_RELE(targvp);
2548 2557 targvp = NULL;
2549 2558
2550 2559 ava.va_mask = AT_ALL;
2551 2560 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2552 2561
2553 2562 /*
2554 2563 * Force modified data and metadata out to stable storage.
2555 2564 */
2556 2565 (void) VOP_FSYNC(vp, 0, cr, NULL);
2557 2566
2558 2567 if (error)
2559 2568 goto err;
2560 2569
2561 2570 resp->status = NFS3_OK;
2562 2571 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2563 2572 goto out;
2564 2573
2565 2574 err:
2566 2575 if (curthread->t_flag & T_WOULDBLOCK) {
2567 2576 curthread->t_flag &= ~T_WOULDBLOCK;
2568 2577 resp->status = NFS3ERR_JUKEBOX;
2569 2578 } else
2570 2579 resp->status = puterrno3(error);
2571 2580 err1:
2572 2581 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2573 2582 out:
2574 2583 DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2575 2584 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2576 2585 REMOVE3res *, resp);
2577 2586
2578 2587 if (name != NULL && name != args->object.name)
2579 2588 kmem_free(name, MAXPATHLEN + 1);
2580 2589
2581 2590 if (vp != NULL)
2582 2591 VN_RELE(vp);
2583 2592 }
2584 2593
2585 2594 void *
2586 2595 rfs3_remove_getfh(REMOVE3args *args)
2587 2596 {
2588 2597
2589 2598 return (&args->object.dir);
2590 2599 }
2591 2600
2592 2601 void
2593 2602 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2594 2603 struct svc_req *req, cred_t *cr, bool_t ro)
2595 2604 {
2596 2605 int error;
2597 2606 vnode_t *vp;
2598 2607 struct vattr *bvap;
2599 2608 struct vattr bva;
2600 2609 struct vattr *avap;
2601 2610 struct vattr ava;
2602 2611 struct sockaddr *ca;
2603 2612 char *name = NULL;
2604 2613
2605 2614 bvap = NULL;
2606 2615 avap = NULL;
2607 2616
2608 2617 vp = nfs3_fhtovp(&args->object.dir, exi);
2609 2618
2610 2619 DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2611 2620 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2612 2621 RMDIR3args *, args);
2613 2622
2614 2623 if (vp == NULL) {
2615 2624 error = ESTALE;
2616 2625 goto err;
2617 2626 }
2618 2627
2619 2628 bva.va_mask = AT_ALL;
2620 2629 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2621 2630 avap = bvap;
2622 2631
2623 2632 if (vp->v_type != VDIR) {
2624 2633 resp->status = NFS3ERR_NOTDIR;
2625 2634 goto err1;
2626 2635 }
2627 2636
2628 2637 if (args->object.name == nfs3nametoolong) {
2629 2638 resp->status = NFS3ERR_NAMETOOLONG;
2630 2639 goto err1;
2631 2640 }
2632 2641
2633 2642 if (args->object.name == NULL || *(args->object.name) == '\0') {
2634 2643 resp->status = NFS3ERR_ACCES;
2635 2644 goto err1;
2636 2645 }
2637 2646
2638 2647 if (rdonly(ro, vp)) {
2639 2648 resp->status = NFS3ERR_ROFS;
2640 2649 goto err1;
2641 2650 }
2642 2651
2643 2652 if (is_system_labeled()) {
2644 2653 bslabel_t *clabel = req->rq_label;
2645 2654
2646 2655 ASSERT(clabel != NULL);
2647 2656 DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
2648 2657 "got client label from request(1)", struct svc_req *, req);
2649 2658
2650 2659 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2651 2660 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2652 2661 exi)) {
2653 2662 resp->status = NFS3ERR_ACCES;
2654 2663 goto err1;
2655 2664 }
2656 2665 }
2657 2666 }
2658 2667
2659 2668 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2660 2669 name = nfscmd_convname(ca, exi, args->object.name,
2661 2670 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2662 2671
2663 2672 if (name == NULL) {
2664 2673 resp->status = NFS3ERR_INVAL;
2665 2674 goto err1;
2666 2675 }
2667 2676
2668 2677 error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2669 2678
2670 2679 if (name != args->object.name)
2671 2680 kmem_free(name, MAXPATHLEN + 1);
2672 2681
2673 2682 ava.va_mask = AT_ALL;
2674 2683 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2675 2684
2676 2685 /*
2677 2686 * Force modified data and metadata out to stable storage.
2678 2687 */
2679 2688 (void) VOP_FSYNC(vp, 0, cr, NULL);
2680 2689
2681 2690 if (error) {
2682 2691 /*
2683 2692 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2684 2693 * if the directory is not empty. A System V NFS server
2685 2694 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2686 2695 * over the wire.
2687 2696 */
2688 2697 if (error == EEXIST)
2689 2698 error = ENOTEMPTY;
2690 2699 goto err;
2691 2700 }
2692 2701
2693 2702 resp->status = NFS3_OK;
2694 2703 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2695 2704 goto out;
2696 2705
2697 2706 err:
2698 2707 if (curthread->t_flag & T_WOULDBLOCK) {
2699 2708 curthread->t_flag &= ~T_WOULDBLOCK;
2700 2709 resp->status = NFS3ERR_JUKEBOX;
2701 2710 } else
2702 2711 resp->status = puterrno3(error);
2703 2712 err1:
2704 2713 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2705 2714 out:
2706 2715 DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2707 2716 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2708 2717 RMDIR3res *, resp);
2709 2718 if (vp != NULL)
2710 2719 VN_RELE(vp);
2711 2720
2712 2721 }
2713 2722
2714 2723 void *
2715 2724 rfs3_rmdir_getfh(RMDIR3args *args)
2716 2725 {
2717 2726
2718 2727 return (&args->object.dir);
2719 2728 }
2720 2729
2721 2730 void
2722 2731 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2723 2732 struct svc_req *req, cred_t *cr, bool_t ro)
2724 2733 {
2725 2734 int error = 0;
2726 2735 vnode_t *fvp;
2727 2736 vnode_t *tvp;
2728 2737 vnode_t *targvp;
2729 2738 struct vattr *fbvap;
2730 2739 struct vattr fbva;
2731 2740 struct vattr *favap;
2732 2741 struct vattr fava;
2733 2742 struct vattr *tbvap;
2734 2743 struct vattr tbva;
2735 2744 struct vattr *tavap;
2736 2745 struct vattr tava;
2737 2746 nfs_fh3 *fh3;
2738 2747 struct exportinfo *to_exi;
2739 2748 vnode_t *srcvp = NULL;
2740 2749 bslabel_t *clabel;
2741 2750 struct sockaddr *ca;
2742 2751 char *name = NULL;
2743 2752 char *toname = NULL;
2744 2753
2745 2754 fbvap = NULL;
2746 2755 favap = NULL;
2747 2756 tbvap = NULL;
2748 2757 tavap = NULL;
2749 2758 tvp = NULL;
2750 2759
2751 2760 fvp = nfs3_fhtovp(&args->from.dir, exi);
2752 2761
2753 2762 DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2754 2763 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2755 2764 RENAME3args *, args);
2756 2765
2757 2766 if (fvp == NULL) {
2758 2767 error = ESTALE;
2759 2768 goto err;
2760 2769 }
2761 2770
2762 2771 if (is_system_labeled()) {
2763 2772 clabel = req->rq_label;
2764 2773 ASSERT(clabel != NULL);
2765 2774 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2766 2775 "got client label from request(1)", struct svc_req *, req);
2767 2776
2768 2777 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2769 2778 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2770 2779 exi)) {
2771 2780 resp->status = NFS3ERR_ACCES;
2772 2781 goto err1;
2773 2782 }
2774 2783 }
2775 2784 }
2776 2785
2777 2786 fbva.va_mask = AT_ALL;
2778 2787 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2779 2788 favap = fbvap;
2780 2789
2781 2790 fh3 = &args->to.dir;
2782 2791 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2783 2792 if (to_exi == NULL) {
2784 2793 resp->status = NFS3ERR_ACCES;
2785 2794 goto err1;
2786 2795 }
2787 2796 exi_rele(to_exi);
2788 2797
2789 2798 if (to_exi != exi) {
2790 2799 resp->status = NFS3ERR_XDEV;
2791 2800 goto err1;
2792 2801 }
2793 2802
2794 2803 tvp = nfs3_fhtovp(&args->to.dir, exi);
2795 2804 if (tvp == NULL) {
2796 2805 error = ESTALE;
2797 2806 goto err;
2798 2807 }
2799 2808
2800 2809 tbva.va_mask = AT_ALL;
2801 2810 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2802 2811 tavap = tbvap;
2803 2812
2804 2813 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2805 2814 resp->status = NFS3ERR_NOTDIR;
2806 2815 goto err1;
2807 2816 }
2808 2817
2809 2818 if (args->from.name == nfs3nametoolong ||
2810 2819 args->to.name == nfs3nametoolong) {
2811 2820 resp->status = NFS3ERR_NAMETOOLONG;
2812 2821 goto err1;
2813 2822 }
2814 2823 if (args->from.name == NULL || *(args->from.name) == '\0' ||
2815 2824 args->to.name == NULL || *(args->to.name) == '\0') {
2816 2825 resp->status = NFS3ERR_ACCES;
2817 2826 goto err1;
2818 2827 }
2819 2828
2820 2829 if (rdonly(ro, tvp)) {
2821 2830 resp->status = NFS3ERR_ROFS;
2822 2831 goto err1;
2823 2832 }
2824 2833
2825 2834 if (is_system_labeled()) {
2826 2835 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2827 2836 if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2828 2837 exi)) {
2829 2838 resp->status = NFS3ERR_ACCES;
2830 2839 goto err1;
2831 2840 }
2832 2841 }
2833 2842 }
2834 2843
2835 2844 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2836 2845 name = nfscmd_convname(ca, exi, args->from.name,
2837 2846 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2838 2847
2839 2848 if (name == NULL) {
2840 2849 resp->status = NFS3ERR_INVAL;
2841 2850 goto err1;
2842 2851 }
2843 2852
2844 2853 toname = nfscmd_convname(ca, exi, args->to.name,
2845 2854 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2846 2855
2847 2856 if (toname == NULL) {
2848 2857 resp->status = NFS3ERR_INVAL;
2849 2858 goto err1;
2850 2859 }
2851 2860
2852 2861 /*
2853 2862 * Check for a conflict with a non-blocking mandatory share
2854 2863 * reservation or V4 delegations.
2855 2864 */
2856 2865 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2857 2866 NULL, cr, NULL, NULL, NULL);
2858 2867 if (error != 0)
2859 2868 goto err;
2860 2869
2861 2870 /*
2862 2871 * If we rename a delegated file we should recall the
2863 2872 * delegation, since future opens should fail or would
2864 2873 * refer to a new file.
2865 2874 */
2866 2875 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2867 2876 resp->status = NFS3ERR_JUKEBOX;
2868 2877 goto err1;
2869 2878 }
2870 2879
2871 2880 /*
2872 2881 * Check for renaming over a delegated file. Check nfs4_deleg_policy
2873 2882 * first to avoid VOP_LOOKUP if possible.
2874 2883 */
2875 2884 if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2876 2885 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2877 2886 NULL, NULL, NULL) == 0) {
2878 2887
2879 2888 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2880 2889 VN_RELE(targvp);
2881 2890 resp->status = NFS3ERR_JUKEBOX;
2882 2891 goto err1;
2883 2892 }
2884 2893 VN_RELE(targvp);
2885 2894 }
2886 2895
2887 2896 if (!nbl_need_check(srcvp)) {
2888 2897 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2889 2898 } else {
2890 2899 nbl_start_crit(srcvp, RW_READER);
2891 2900 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2892 2901 error = EACCES;
2893 2902 else
2894 2903 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2895 2904 nbl_end_crit(srcvp);
2896 2905 }
2897 2906 if (error == 0)
2898 2907 vn_renamepath(tvp, srcvp, args->to.name,
2899 2908 strlen(args->to.name));
2900 2909 VN_RELE(srcvp);
2901 2910 srcvp = NULL;
2902 2911
2903 2912 fava.va_mask = AT_ALL;
2904 2913 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2905 2914 tava.va_mask = AT_ALL;
2906 2915 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2907 2916
2908 2917 /*
2909 2918 * Force modified data and metadata out to stable storage.
2910 2919 */
2911 2920 (void) VOP_FSYNC(fvp, 0, cr, NULL);
2912 2921 (void) VOP_FSYNC(tvp, 0, cr, NULL);
2913 2922
2914 2923 if (error)
2915 2924 goto err;
2916 2925
2917 2926 resp->status = NFS3_OK;
2918 2927 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
2919 2928 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2920 2929 goto out;
2921 2930
2922 2931 err:
2923 2932 if (curthread->t_flag & T_WOULDBLOCK) {
2924 2933 curthread->t_flag &= ~T_WOULDBLOCK;
2925 2934 resp->status = NFS3ERR_JUKEBOX;
2926 2935 } else {
2927 2936 resp->status = puterrno3(error);
2928 2937 }
2929 2938 err1:
2930 2939 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2931 2940 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2932 2941
2933 2942 out:
2934 2943 if (name != NULL && name != args->from.name)
2935 2944 kmem_free(name, MAXPATHLEN + 1);
2936 2945 if (toname != NULL && toname != args->to.name)
2937 2946 kmem_free(toname, MAXPATHLEN + 1);
2938 2947
2939 2948 DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2940 2949 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2941 2950 RENAME3res *, resp);
2942 2951 if (fvp != NULL)
2943 2952 VN_RELE(fvp);
2944 2953 if (tvp != NULL)
2945 2954 VN_RELE(tvp);
2946 2955 }
2947 2956
2948 2957 void *
2949 2958 rfs3_rename_getfh(RENAME3args *args)
2950 2959 {
2951 2960
2952 2961 return (&args->from.dir);
2953 2962 }
2954 2963
2955 2964 void
2956 2965 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2957 2966 struct svc_req *req, cred_t *cr, bool_t ro)
2958 2967 {
2959 2968 int error;
2960 2969 vnode_t *vp;
2961 2970 vnode_t *dvp;
2962 2971 struct vattr *vap;
2963 2972 struct vattr va;
2964 2973 struct vattr *bvap;
2965 2974 struct vattr bva;
2966 2975 struct vattr *avap;
2967 2976 struct vattr ava;
2968 2977 nfs_fh3 *fh3;
2969 2978 struct exportinfo *to_exi;
2970 2979 bslabel_t *clabel;
2971 2980 struct sockaddr *ca;
2972 2981 char *name = NULL;
2973 2982
2974 2983 vap = NULL;
2975 2984 bvap = NULL;
2976 2985 avap = NULL;
2977 2986 dvp = NULL;
2978 2987
2979 2988 vp = nfs3_fhtovp(&args->file, exi);
2980 2989
2981 2990 DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2982 2991 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2983 2992 LINK3args *, args);
2984 2993
2985 2994 if (vp == NULL) {
2986 2995 error = ESTALE;
2987 2996 goto out;
2988 2997 }
2989 2998
2990 2999 va.va_mask = AT_ALL;
2991 3000 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2992 3001
2993 3002 fh3 = &args->link.dir;
2994 3003 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2995 3004 if (to_exi == NULL) {
2996 3005 resp->status = NFS3ERR_ACCES;
2997 3006 goto out1;
2998 3007 }
2999 3008 exi_rele(to_exi);
3000 3009
3001 3010 if (to_exi != exi) {
3002 3011 resp->status = NFS3ERR_XDEV;
3003 3012 goto out1;
3004 3013 }
3005 3014
3006 3015 if (is_system_labeled()) {
3007 3016 clabel = req->rq_label;
3008 3017
3009 3018 ASSERT(clabel != NULL);
3010 3019 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3011 3020 "got client label from request(1)", struct svc_req *, req);
3012 3021
3013 3022 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3014 3023 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3015 3024 exi)) {
3016 3025 resp->status = NFS3ERR_ACCES;
3017 3026 goto out1;
3018 3027 }
3019 3028 }
3020 3029 }
3021 3030
3022 3031 dvp = nfs3_fhtovp(&args->link.dir, exi);
3023 3032 if (dvp == NULL) {
3024 3033 error = ESTALE;
3025 3034 goto out;
3026 3035 }
3027 3036
3028 3037 bva.va_mask = AT_ALL;
3029 3038 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3030 3039
3031 3040 if (dvp->v_type != VDIR) {
3032 3041 resp->status = NFS3ERR_NOTDIR;
3033 3042 goto out1;
3034 3043 }
3035 3044
3036 3045 if (args->link.name == nfs3nametoolong) {
3037 3046 resp->status = NFS3ERR_NAMETOOLONG;
3038 3047 goto out1;
3039 3048 }
3040 3049
3041 3050 if (args->link.name == NULL || *(args->link.name) == '\0') {
3042 3051 resp->status = NFS3ERR_ACCES;
3043 3052 goto out1;
3044 3053 }
3045 3054
3046 3055 if (rdonly(ro, dvp)) {
3047 3056 resp->status = NFS3ERR_ROFS;
3048 3057 goto out1;
3049 3058 }
3050 3059
3051 3060 if (is_system_labeled()) {
3052 3061 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3053 3062 "got client label from request(1)", struct svc_req *, req);
3054 3063
3055 3064 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3056 3065 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3057 3066 exi)) {
3058 3067 resp->status = NFS3ERR_ACCES;
3059 3068 goto out1;
3060 3069 }
3061 3070 }
3062 3071 }
3063 3072
3064 3073 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3065 3074 name = nfscmd_convname(ca, exi, args->link.name,
3066 3075 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3067 3076
3068 3077 if (name == NULL) {
3069 3078 resp->status = NFS3ERR_SERVERFAULT;
3070 3079 goto out1;
3071 3080 }
3072 3081
3073 3082 error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3074 3083
3075 3084 va.va_mask = AT_ALL;
3076 3085 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3077 3086 ava.va_mask = AT_ALL;
3078 3087 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3079 3088
3080 3089 /*
3081 3090 * Force modified data and metadata out to stable storage.
3082 3091 */
3083 3092 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3084 3093 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3085 3094
3086 3095 if (error)
3087 3096 goto out;
3088 3097
3089 3098 VN_RELE(dvp);
3090 3099
3091 3100 resp->status = NFS3_OK;
3092 3101 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3093 3102 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3094 3103
3095 3104 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3096 3105 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3097 3106 LINK3res *, resp);
3098 3107
3099 3108 VN_RELE(vp);
3100 3109
3101 3110 return;
3102 3111
3103 3112 out:
3104 3113 if (curthread->t_flag & T_WOULDBLOCK) {
3105 3114 curthread->t_flag &= ~T_WOULDBLOCK;
3106 3115 resp->status = NFS3ERR_JUKEBOX;
3107 3116 } else
3108 3117 resp->status = puterrno3(error);
3109 3118 out1:
3110 3119 if (name != NULL && name != args->link.name)
3111 3120 kmem_free(name, MAXPATHLEN + 1);
3112 3121
3113 3122 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3114 3123 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3115 3124 LINK3res *, resp);
3116 3125
3117 3126 if (vp != NULL)
3118 3127 VN_RELE(vp);
3119 3128 if (dvp != NULL)
3120 3129 VN_RELE(dvp);
3121 3130 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3122 3131 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3123 3132 }
3124 3133
3125 3134 void *
3126 3135 rfs3_link_getfh(LINK3args *args)
3127 3136 {
3128 3137
3129 3138 return (&args->file);
3130 3139 }
3131 3140
3132 3141 /*
3133 3142 * This macro defines the size of a response which contains attribute
3134 3143 * information and one directory entry (whose length is specified by
3135 3144 * the macro parameter). If the incoming request is larger than this,
3136 3145 * then we are guaranteed to be able to return at one directory entry
3137 3146 * if one exists. Therefore, we do not need to check for
3138 3147 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it
3139 3148 * is not, then we need to check to make sure that this error does not
3140 3149 * need to be returned.
3141 3150 *
3142 3151 * NFS3_READDIR_MIN_COUNT is comprised of following :
3143 3152 *
3144 3153 * status - 1 * BYTES_PER_XDR_UNIT
3145 3154 * attr. flag - 1 * BYTES_PER_XDR_UNIT
3146 3155 * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3147 3156 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3148 3157 * boolean - 1 * BYTES_PER_XDR_UNIT
3149 3158 * file id - 2 * BYTES_PER_XDR_UNIT
3150 3159 * directory name length - 1 * BYTES_PER_XDR_UNIT
3151 3160 * cookie - 2 * BYTES_PER_XDR_UNIT
3152 3161 * end of list - 1 * BYTES_PER_XDR_UNIT
3153 3162 * end of file - 1 * BYTES_PER_XDR_UNIT
3154 3163 * Name length of directory to the nearest byte
3155 3164 */
3156 3165
3157 3166 #define NFS3_READDIR_MIN_COUNT(length) \
3158 3167 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3159 3168 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3160 3169
3161 3170 /* ARGSUSED */
3162 3171 void
3163 3172 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3164 3173 struct svc_req *req, cred_t *cr, bool_t ro)
3165 3174 {
3166 3175 int error;
3167 3176 vnode_t *vp;
3168 3177 struct vattr *vap;
3169 3178 struct vattr va;
3170 3179 struct iovec iov;
3171 3180 struct uio uio;
3172 3181 char *data;
3173 3182 int iseof;
3174 3183 int bufsize;
3175 3184 int namlen;
3176 3185 uint_t count;
3177 3186 struct sockaddr *ca;
3178 3187
3179 3188 vap = NULL;
3180 3189
3181 3190 vp = nfs3_fhtovp(&args->dir, exi);
3182 3191
3183 3192 DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3184 3193 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3185 3194 READDIR3args *, args);
3186 3195
3187 3196 if (vp == NULL) {
3188 3197 error = ESTALE;
3189 3198 goto out;
3190 3199 }
3191 3200
3192 3201 if (is_system_labeled()) {
3193 3202 bslabel_t *clabel = req->rq_label;
3194 3203
3195 3204 ASSERT(clabel != NULL);
3196 3205 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3197 3206 "got client label from request(1)", struct svc_req *, req);
3198 3207
3199 3208 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3200 3209 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3201 3210 exi)) {
3202 3211 resp->status = NFS3ERR_ACCES;
3203 3212 goto out1;
3204 3213 }
3205 3214 }
3206 3215 }
3207 3216
3208 3217 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3209 3218
3210 3219 va.va_mask = AT_ALL;
3211 3220 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3212 3221
3213 3222 if (vp->v_type != VDIR) {
3214 3223 resp->status = NFS3ERR_NOTDIR;
3215 3224 goto out1;
3216 3225 }
3217 3226
3218 3227 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3219 3228 if (error)
3220 3229 goto out;
3221 3230
3222 3231 /*
3223 3232 * Now don't allow arbitrary count to alloc;
3224 3233 * allow the maximum not to exceed rfs3_tsize()
3225 3234 */
3226 3235 if (args->count > rfs3_tsize(req))
3227 3236 args->count = rfs3_tsize(req);
3228 3237
3229 3238 /*
3230 3239 * Make sure that there is room to read at least one entry
3231 3240 * if any are available.
3232 3241 */
3233 3242 if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3234 3243 count = DIRENT64_RECLEN(MAXNAMELEN);
3235 3244 else
3236 3245 count = args->count;
3237 3246
3238 3247 data = kmem_alloc(count, KM_SLEEP);
3239 3248
3240 3249 iov.iov_base = data;
3241 3250 iov.iov_len = count;
3242 3251 uio.uio_iov = &iov;
3243 3252 uio.uio_iovcnt = 1;
3244 3253 uio.uio_segflg = UIO_SYSSPACE;
3245 3254 uio.uio_extflg = UIO_COPY_CACHED;
3246 3255 uio.uio_loffset = (offset_t)args->cookie;
3247 3256 uio.uio_resid = count;
3248 3257
3249 3258 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3250 3259
3251 3260 va.va_mask = AT_ALL;
3252 3261 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3253 3262
3254 3263 if (error) {
3255 3264 kmem_free(data, count);
3256 3265 goto out;
3257 3266 }
3258 3267
3259 3268 /*
3260 3269 * If the count was not large enough to be able to guarantee
3261 3270 * to be able to return at least one entry, then need to
3262 3271 * check to see if NFS3ERR_TOOSMALL should be returned.
3263 3272 */
3264 3273 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3265 3274 /*
3266 3275 * bufsize is used to keep track of the size of the response.
3267 3276 * It is primed with:
3268 3277 * 1 for the status +
3269 3278 * 1 for the dir_attributes.attributes boolean +
3270 3279 * 2 for the cookie verifier
3271 3280 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3272 3281 * to bytes. If there are directory attributes to be
3273 3282 * returned, then:
3274 3283 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3275 3284 * time BYTES_PER_XDR_UNIT is added to account for them.
3276 3285 */
3277 3286 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3278 3287 if (vap != NULL)
3279 3288 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3280 3289 /*
3281 3290 * An entry is composed of:
3282 3291 * 1 for the true/false list indicator +
3283 3292 * 2 for the fileid +
3284 3293 * 1 for the length of the name +
3285 3294 * 2 for the cookie +
3286 3295 * all times BYTES_PER_XDR_UNIT to convert from
3287 3296 * XDR units to bytes, plus the length of the name
3288 3297 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3289 3298 */
3290 3299 if (count != uio.uio_resid) {
3291 3300 namlen = strlen(((struct dirent64 *)data)->d_name);
3292 3301 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3293 3302 roundup(namlen, BYTES_PER_XDR_UNIT);
3294 3303 }
3295 3304 /*
3296 3305 * We need to check to see if the number of bytes left
3297 3306 * to go into the buffer will actually fit into the
3298 3307 * buffer. This is calculated as the size of this
3299 3308 * entry plus:
3300 3309 * 1 for the true/false list indicator +
3301 3310 * 1 for the eof indicator
3302 3311 * times BYTES_PER_XDR_UNIT to convert from from
3303 3312 * XDR units to bytes.
3304 3313 */
3305 3314 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3306 3315 if (bufsize > args->count) {
3307 3316 kmem_free(data, count);
3308 3317 resp->status = NFS3ERR_TOOSMALL;
3309 3318 goto out1;
3310 3319 }
3311 3320 }
3312 3321
3313 3322 /*
3314 3323 * Have a valid readir buffer for the native character
3315 3324 * set. Need to check if a conversion is necessary and
3316 3325 * potentially rewrite the whole buffer. Note that if the
3317 3326 * conversion expands names enough, the structure may not
3318 3327 * fit. In this case, we need to drop entries until if fits
3319 3328 * and patch the counts in order that the next readdir will
3320 3329 * get the correct entries.
3321 3330 */
3322 3331 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3323 3332 data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3324 3333
3325 3334
3326 3335 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3327 3336
3328 3337 #if 0 /* notyet */
3329 3338 /*
3330 3339 * Don't do this. It causes local disk writes when just
3331 3340 * reading the file and the overhead is deemed larger
3332 3341 * than the benefit.
3333 3342 */
3334 3343 /*
3335 3344 * Force modified metadata out to stable storage.
3336 3345 */
3337 3346 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3338 3347 #endif
3339 3348
3340 3349 resp->status = NFS3_OK;
3341 3350 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3342 3351 resp->resok.cookieverf = 0;
3343 3352 resp->resok.reply.entries = (entry3 *)data;
3344 3353 resp->resok.reply.eof = iseof;
3345 3354 resp->resok.size = count - uio.uio_resid;
3346 3355 resp->resok.count = args->count;
3347 3356 resp->resok.freecount = count;
3348 3357
3349 3358 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3350 3359 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3351 3360 READDIR3res *, resp);
3352 3361
3353 3362 VN_RELE(vp);
3354 3363
3355 3364 return;
3356 3365
3357 3366 out:
3358 3367 if (curthread->t_flag & T_WOULDBLOCK) {
3359 3368 curthread->t_flag &= ~T_WOULDBLOCK;
3360 3369 resp->status = NFS3ERR_JUKEBOX;
3361 3370 } else
3362 3371 resp->status = puterrno3(error);
3363 3372 out1:
3364 3373 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3365 3374
3366 3375 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3367 3376 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3368 3377 READDIR3res *, resp);
3369 3378
3370 3379 if (vp != NULL) {
3371 3380 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3372 3381 VN_RELE(vp);
3373 3382 }
3374 3383 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3375 3384 }
3376 3385
3377 3386 void *
3378 3387 rfs3_readdir_getfh(READDIR3args *args)
3379 3388 {
3380 3389
3381 3390 return (&args->dir);
3382 3391 }
3383 3392
3384 3393 void
3385 3394 rfs3_readdir_free(READDIR3res *resp)
3386 3395 {
3387 3396
3388 3397 if (resp->status == NFS3_OK)
3389 3398 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3390 3399 }
3391 3400
3392 3401 #ifdef nextdp
3393 3402 #undef nextdp
3394 3403 #endif
3395 3404 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3396 3405
3397 3406 /*
3398 3407 * This macro computes the size of a response which contains
3399 3408 * one directory entry including the attributes as well as file handle.
3400 3409 * If the incoming request is larger than this, then we are guaranteed to be
3401 3410 * able to return at least one more directory entry if one exists.
3402 3411 *
3403 3412 * NFS3_READDIRPLUS_ENTRY is made up of the following:
3404 3413 *
3405 3414 * boolean - 1 * BYTES_PER_XDR_UNIT
3406 3415 * file id - 2 * BYTES_PER_XDR_UNIT
3407 3416 * directory name length - 1 * BYTES_PER_XDR_UNIT
3408 3417 * cookie - 2 * BYTES_PER_XDR_UNIT
3409 3418 * attribute flag - 1 * BYTES_PER_XDR_UNIT
3410 3419 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3411 3420 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT
3412 3421 * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3413 3422 * Maximum length of a file handle (NFS3_MAXFHSIZE)
3414 3423 * name length of the entry to the nearest bytes
3415 3424 */
3416 3425 #define NFS3_READDIRPLUS_ENTRY(namelen) \
3417 3426 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3418 3427 BYTES_PER_XDR_UNIT + \
3419 3428 NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3420 3429
3421 3430 static int rfs3_readdir_unit = MAXBSIZE;
3422 3431
3423 3432 /* ARGSUSED */
3424 3433 void
3425 3434 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3426 3435 struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3427 3436 {
3428 3437 int error;
3429 3438 vnode_t *vp;
3430 3439 struct vattr *vap;
3431 3440 struct vattr va;
3432 3441 struct iovec iov;
3433 3442 struct uio uio;
3434 3443 char *data;
3435 3444 int iseof;
3436 3445 struct dirent64 *dp;
3437 3446 vnode_t *nvp;
3438 3447 struct vattr *nvap;
3439 3448 struct vattr nva;
3440 3449 entryplus3_info *infop = NULL;
3441 3450 int size = 0;
3442 3451 int nents = 0;
3443 3452 int bufsize = 0;
3444 3453 int entrysize = 0;
3445 3454 int tofit = 0;
3446 3455 int rd_unit = rfs3_readdir_unit;
3447 3456 int prev_len;
3448 3457 int space_left;
3449 3458 int i;
3450 3459 uint_t *namlen = NULL;
3451 3460 char *ndata = NULL;
3452 3461 struct sockaddr *ca;
3453 3462 size_t ret;
3454 3463
3455 3464 vap = NULL;
3456 3465
3457 3466 vp = nfs3_fhtovp(&args->dir, exi);
3458 3467
3459 3468 DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3460 3469 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3461 3470 READDIRPLUS3args *, args);
3462 3471
3463 3472 if (vp == NULL) {
3464 3473 error = ESTALE;
3465 3474 goto out;
3466 3475 }
3467 3476
3468 3477 if (is_system_labeled()) {
3469 3478 bslabel_t *clabel = req->rq_label;
3470 3479
3471 3480 ASSERT(clabel != NULL);
3472 3481 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3473 3482 char *, "got client label from request(1)",
3474 3483 struct svc_req *, req);
3475 3484
3476 3485 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3477 3486 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3478 3487 exi)) {
3479 3488 resp->status = NFS3ERR_ACCES;
3480 3489 goto out1;
3481 3490 }
3482 3491 }
3483 3492 }
3484 3493
3485 3494 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3486 3495
3487 3496 va.va_mask = AT_ALL;
3488 3497 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3489 3498
3490 3499 if (vp->v_type != VDIR) {
3491 3500 error = ENOTDIR;
3492 3501 goto out;
3493 3502 }
3494 3503
3495 3504 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3496 3505 if (error)
3497 3506 goto out;
3498 3507
3499 3508 /*
3500 3509 * Don't allow arbitrary counts for allocation
3501 3510 */
3502 3511 if (args->maxcount > rfs3_tsize(req))
3503 3512 args->maxcount = rfs3_tsize(req);
3504 3513
3505 3514 /*
3506 3515 * Make sure that there is room to read at least one entry
3507 3516 * if any are available
3508 3517 */
3509 3518 args->dircount = MIN(args->dircount, args->maxcount);
3510 3519
3511 3520 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3512 3521 args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3513 3522
3514 3523 /*
3515 3524 * This allocation relies on a minimum directory entry
3516 3525 * being roughly 24 bytes. Therefore, the namlen array
3517 3526 * will have enough space based on the maximum number of
3518 3527 * entries to read.
3519 3528 */
3520 3529 namlen = kmem_alloc(args->dircount, KM_SLEEP);
3521 3530
3522 3531 space_left = args->dircount;
3523 3532 data = kmem_alloc(args->dircount, KM_SLEEP);
3524 3533 dp = (struct dirent64 *)data;
3525 3534 uio.uio_iov = &iov;
3526 3535 uio.uio_iovcnt = 1;
3527 3536 uio.uio_segflg = UIO_SYSSPACE;
3528 3537 uio.uio_extflg = UIO_COPY_CACHED;
3529 3538 uio.uio_loffset = (offset_t)args->cookie;
3530 3539
3531 3540 /*
3532 3541 * bufsize is used to keep track of the size of the response as we
3533 3542 * get post op attributes and filehandles for each entry. This is
3534 3543 * an optimization as the server may have read more entries than will
3535 3544 * fit in the buffer specified by maxcount. We stop calculating
3536 3545 * post op attributes and filehandles once we have exceeded maxcount.
3537 3546 * This will minimize the effect of truncation.
3538 3547 *
3539 3548 * It is primed with:
3540 3549 * 1 for the status +
3541 3550 * 1 for the dir_attributes.attributes boolean +
3542 3551 * 2 for the cookie verifier
3543 3552 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3544 3553 * to bytes. If there are directory attributes to be
3545 3554 * returned, then:
3546 3555 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3547 3556 * time BYTES_PER_XDR_UNIT is added to account for them.
3548 3557 */
3549 3558 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3550 3559 if (vap != NULL)
3551 3560 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3552 3561
3553 3562 getmoredents:
3554 3563 /*
3555 3564 * Here we make a check so that our read unit is not larger than
3556 3565 * the space left in the buffer.
3557 3566 */
3558 3567 rd_unit = MIN(rd_unit, space_left);
3559 3568 iov.iov_base = (char *)dp;
3560 3569 iov.iov_len = rd_unit;
3561 3570 uio.uio_resid = rd_unit;
3562 3571 prev_len = rd_unit;
3563 3572
3564 3573 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3565 3574
3566 3575 if (error) {
3567 3576 kmem_free(data, args->dircount);
3568 3577 goto out;
3569 3578 }
3570 3579
3571 3580 if (uio.uio_resid == prev_len && !iseof) {
3572 3581 if (nents == 0) {
3573 3582 kmem_free(data, args->dircount);
3574 3583 resp->status = NFS3ERR_TOOSMALL;
3575 3584 goto out1;
3576 3585 }
3577 3586
3578 3587 /*
3579 3588 * We could not get any more entries, so get the attributes
3580 3589 * and filehandle for the entries already obtained.
3581 3590 */
3582 3591 goto good;
3583 3592 }
3584 3593
3585 3594 /*
3586 3595 * We estimate the size of the response by assuming the
3587 3596 * entry exists and attributes and filehandle are also valid
3588 3597 */
3589 3598 for (size = prev_len - uio.uio_resid;
3590 3599 size > 0;
3591 3600 size -= dp->d_reclen, dp = nextdp(dp)) {
3592 3601
3593 3602 if (dp->d_ino == 0) {
3594 3603 nents++;
3595 3604 continue;
3596 3605 }
3597 3606
3598 3607 namlen[nents] = strlen(dp->d_name);
3599 3608 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3600 3609
3601 3610 /*
3602 3611 * We need to check to see if the number of bytes left
3603 3612 * to go into the buffer will actually fit into the
3604 3613 * buffer. This is calculated as the size of this
3605 3614 * entry plus:
3606 3615 * 1 for the true/false list indicator +
3607 3616 * 1 for the eof indicator
3608 3617 * times BYTES_PER_XDR_UNIT to convert from XDR units
3609 3618 * to bytes.
3610 3619 *
3611 3620 * Also check the dircount limit against the first entry read
3612 3621 *
3613 3622 */
3614 3623 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3615 3624 if (bufsize + tofit > args->maxcount) {
3616 3625 /*
3617 3626 * We make a check here to see if this was the
3618 3627 * first entry being measured. If so, then maxcount
3619 3628 * was too small to begin with and so we need to
3620 3629 * return with NFS3ERR_TOOSMALL.
3621 3630 */
3622 3631 if (nents == 0) {
3623 3632 kmem_free(data, args->dircount);
3624 3633 resp->status = NFS3ERR_TOOSMALL;
3625 3634 goto out1;
3626 3635 }
3627 3636 iseof = FALSE;
3628 3637 goto good;
3629 3638 }
3630 3639 bufsize += entrysize;
3631 3640 nents++;
3632 3641 }
3633 3642
3634 3643 /*
3635 3644 * If there is enough room to fit at least 1 more entry including
3636 3645 * post op attributes and filehandle in the buffer AND that we haven't
3637 3646 * exceeded dircount then go back and get some more.
3638 3647 */
3639 3648 if (!iseof &&
3640 3649 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3641 3650 space_left -= (prev_len - uio.uio_resid);
3642 3651 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3643 3652 goto getmoredents;
3644 3653
3645 3654 /* else, fall through */
3646 3655 }
3647 3656 good:
3648 3657 va.va_mask = AT_ALL;
3649 3658 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3650 3659
3651 3660 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3652 3661
3653 3662 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3654 3663 resp->resok.infop = infop;
3655 3664
3656 3665 dp = (struct dirent64 *)data;
3657 3666 for (i = 0; i < nents; i++) {
3658 3667
3659 3668 if (dp->d_ino == 0) {
3660 3669 infop[i].attr.attributes = FALSE;
3661 3670 infop[i].fh.handle_follows = FALSE;
3662 3671 dp = nextdp(dp);
3663 3672 continue;
3664 3673 }
3665 3674
3666 3675 infop[i].namelen = namlen[i];
3667 3676
3668 3677 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3669 3678 NULL, NULL, NULL);
3670 3679 if (error) {
3671 3680 infop[i].attr.attributes = FALSE;
3672 3681 infop[i].fh.handle_follows = FALSE;
3673 3682 dp = nextdp(dp);
3674 3683 continue;
3675 3684 }
3676 3685
3677 3686 nva.va_mask = AT_ALL;
3678 3687 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3679 3688
3680 3689 /* Lie about the object type for a referral */
3681 3690 if (vn_is_nfs_reparse(nvp, cr))
3682 3691 nvap->va_type = VLNK;
3683 3692
3684 3693 if (vn_ismntpt(nvp)) {
3685 3694 infop[i].attr.attributes = FALSE;
3686 3695 infop[i].fh.handle_follows = FALSE;
3687 3696 } else {
3688 3697 vattr_to_post_op_attr(nvap, &infop[i].attr);
3689 3698
3690 3699 error = makefh3(&infop[i].fh.handle, nvp, exi);
3691 3700 if (!error)
3692 3701 infop[i].fh.handle_follows = TRUE;
3693 3702 else
3694 3703 infop[i].fh.handle_follows = FALSE;
3695 3704 }
3696 3705
3697 3706 VN_RELE(nvp);
3698 3707 dp = nextdp(dp);
3699 3708 }
3700 3709
3701 3710 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3702 3711 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3703 3712 if (ndata == NULL)
3704 3713 ndata = data;
3705 3714
3706 3715 if (ret > 0) {
3707 3716 /*
3708 3717 * We had to drop one or more entries in order to fit
3709 3718 * during the character conversion. We need to patch
3710 3719 * up the size and eof info.
3711 3720 */
3712 3721 if (iseof)
3713 3722 iseof = FALSE;
3714 3723
3715 3724 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3716 3725 nents, ret);
3717 3726 }
3718 3727
3719 3728
3720 3729 #if 0 /* notyet */
3721 3730 /*
3722 3731 * Don't do this. It causes local disk writes when just
3723 3732 * reading the file and the overhead is deemed larger
3724 3733 * than the benefit.
3725 3734 */
3726 3735 /*
3727 3736 * Force modified metadata out to stable storage.
3728 3737 */
3729 3738 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3730 3739 #endif
3731 3740
3732 3741 kmem_free(namlen, args->dircount);
3733 3742
3734 3743 resp->status = NFS3_OK;
3735 3744 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3736 3745 resp->resok.cookieverf = 0;
3737 3746 resp->resok.reply.entries = (entryplus3 *)ndata;
3738 3747 resp->resok.reply.eof = iseof;
3739 3748 resp->resok.size = nents;
3740 3749 resp->resok.count = args->dircount - ret;
3741 3750 resp->resok.maxcount = args->maxcount;
3742 3751
3743 3752 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3744 3753 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3745 3754 READDIRPLUS3res *, resp);
3746 3755
3747 3756 VN_RELE(vp);
3748 3757
3749 3758 return;
3750 3759
3751 3760 out:
3752 3761 if (curthread->t_flag & T_WOULDBLOCK) {
3753 3762 curthread->t_flag &= ~T_WOULDBLOCK;
3754 3763 resp->status = NFS3ERR_JUKEBOX;
3755 3764 } else {
3756 3765 resp->status = puterrno3(error);
3757 3766 }
3758 3767 out1:
3759 3768 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3760 3769
3761 3770 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3762 3771 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3763 3772 READDIRPLUS3res *, resp);
3764 3773
3765 3774 if (vp != NULL) {
3766 3775 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3767 3776 VN_RELE(vp);
3768 3777 }
3769 3778
3770 3779 if (namlen != NULL)
3771 3780 kmem_free(namlen, args->dircount);
3772 3781
3773 3782 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3774 3783 }
3775 3784
3776 3785 void *
3777 3786 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3778 3787 {
3779 3788
3780 3789 return (&args->dir);
3781 3790 }
3782 3791
3783 3792 void
3784 3793 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3785 3794 {
3786 3795
3787 3796 if (resp->status == NFS3_OK) {
3788 3797 kmem_free(resp->resok.reply.entries, resp->resok.count);
3789 3798 kmem_free(resp->resok.infop,
3790 3799 resp->resok.size * sizeof (struct entryplus3_info));
3791 3800 }
3792 3801 }
3793 3802
3794 3803 /* ARGSUSED */
3795 3804 void
3796 3805 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3797 3806 struct svc_req *req, cred_t *cr, bool_t ro)
3798 3807 {
3799 3808 int error;
3800 3809 vnode_t *vp;
3801 3810 struct vattr *vap;
3802 3811 struct vattr va;
3803 3812 struct statvfs64 sb;
3804 3813
3805 3814 vap = NULL;
3806 3815
3807 3816 vp = nfs3_fhtovp(&args->fsroot, exi);
3808 3817
3809 3818 DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3810 3819 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3811 3820 FSSTAT3args *, args);
3812 3821
3813 3822 if (vp == NULL) {
3814 3823 error = ESTALE;
3815 3824 goto out;
3816 3825 }
3817 3826
3818 3827 if (is_system_labeled()) {
3819 3828 bslabel_t *clabel = req->rq_label;
3820 3829
3821 3830 ASSERT(clabel != NULL);
3822 3831 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3823 3832 "got client label from request(1)", struct svc_req *, req);
3824 3833
3825 3834 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3826 3835 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3827 3836 exi)) {
3828 3837 resp->status = NFS3ERR_ACCES;
3829 3838 goto out1;
3830 3839 }
3831 3840 }
3832 3841 }
3833 3842
3834 3843 error = VFS_STATVFS(vp->v_vfsp, &sb);
3835 3844
3836 3845 va.va_mask = AT_ALL;
3837 3846 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3838 3847
3839 3848 if (error)
3840 3849 goto out;
3841 3850
3842 3851 resp->status = NFS3_OK;
3843 3852 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3844 3853 if (sb.f_blocks != (fsblkcnt64_t)-1)
3845 3854 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3846 3855 else
3847 3856 resp->resok.tbytes = (size3)sb.f_blocks;
3848 3857 if (sb.f_bfree != (fsblkcnt64_t)-1)
3849 3858 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3850 3859 else
3851 3860 resp->resok.fbytes = (size3)sb.f_bfree;
3852 3861 if (sb.f_bavail != (fsblkcnt64_t)-1)
3853 3862 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3854 3863 else
3855 3864 resp->resok.abytes = (size3)sb.f_bavail;
3856 3865 resp->resok.tfiles = (size3)sb.f_files;
3857 3866 resp->resok.ffiles = (size3)sb.f_ffree;
3858 3867 resp->resok.afiles = (size3)sb.f_favail;
3859 3868 resp->resok.invarsec = 0;
3860 3869
3861 3870 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3862 3871 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3863 3872 FSSTAT3res *, resp);
3864 3873 VN_RELE(vp);
3865 3874
3866 3875 return;
3867 3876
3868 3877 out:
3869 3878 if (curthread->t_flag & T_WOULDBLOCK) {
3870 3879 curthread->t_flag &= ~T_WOULDBLOCK;
3871 3880 resp->status = NFS3ERR_JUKEBOX;
3872 3881 } else
3873 3882 resp->status = puterrno3(error);
3874 3883 out1:
3875 3884 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3876 3885 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3877 3886 FSSTAT3res *, resp);
3878 3887
3879 3888 if (vp != NULL)
3880 3889 VN_RELE(vp);
3881 3890 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3882 3891 }
3883 3892
3884 3893 void *
3885 3894 rfs3_fsstat_getfh(FSSTAT3args *args)
3886 3895 {
3887 3896
3888 3897 return (&args->fsroot);
3889 3898 }
3890 3899
3891 3900 /* ARGSUSED */
3892 3901 void
3893 3902 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3894 3903 struct svc_req *req, cred_t *cr, bool_t ro)
3895 3904 {
3896 3905 vnode_t *vp;
3897 3906 struct vattr *vap;
3898 3907 struct vattr va;
3899 3908 uint32_t xfer_size;
3900 3909 ulong_t l = 0;
3901 3910 int error;
3902 3911
3903 3912 vp = nfs3_fhtovp(&args->fsroot, exi);
3904 3913
3905 3914 DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3906 3915 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3907 3916 FSINFO3args *, args);
3908 3917
3909 3918 if (vp == NULL) {
3910 3919 if (curthread->t_flag & T_WOULDBLOCK) {
3911 3920 curthread->t_flag &= ~T_WOULDBLOCK;
3912 3921 resp->status = NFS3ERR_JUKEBOX;
3913 3922 } else
3914 3923 resp->status = NFS3ERR_STALE;
3915 3924 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3916 3925 goto out;
3917 3926 }
3918 3927
3919 3928 if (is_system_labeled()) {
3920 3929 bslabel_t *clabel = req->rq_label;
3921 3930
3922 3931 ASSERT(clabel != NULL);
3923 3932 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3924 3933 "got client label from request(1)", struct svc_req *, req);
3925 3934
3926 3935 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3927 3936 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3928 3937 exi)) {
3929 3938 resp->status = NFS3ERR_STALE;
3930 3939 vattr_to_post_op_attr(NULL,
3931 3940 &resp->resfail.obj_attributes);
3932 3941 goto out;
3933 3942 }
3934 3943 }
3935 3944 }
3936 3945
3937 3946 va.va_mask = AT_ALL;
3938 3947 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3939 3948
3940 3949 resp->status = NFS3_OK;
3941 3950 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3942 3951 xfer_size = rfs3_tsize(req);
3943 3952 resp->resok.rtmax = xfer_size;
3944 3953 resp->resok.rtpref = xfer_size;
3945 3954 resp->resok.rtmult = DEV_BSIZE;
3946 3955 resp->resok.wtmax = xfer_size;
3947 3956 resp->resok.wtpref = xfer_size;
3948 3957 resp->resok.wtmult = DEV_BSIZE;
3949 3958 resp->resok.dtpref = MAXBSIZE;
3950 3959
3951 3960 /*
3952 3961 * Large file spec: want maxfilesize based on limit of
3953 3962 * underlying filesystem. We can guess 2^31-1 if need be.
3954 3963 */
3955 3964 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3956 3965 if (error) {
3957 3966 resp->status = puterrno3(error);
3958 3967 goto out;
3959 3968 }
3960 3969
3961 3970 /*
3962 3971 * If the underlying file system does not support _PC_FILESIZEBITS,
3963 3972 * return a reasonable default. Note that error code on VOP_PATHCONF
3964 3973 * will be 0, even if the underlying file system does not support
3965 3974 * _PC_FILESIZEBITS.
3966 3975 */
3967 3976 if (l == (ulong_t)-1) {
3968 3977 resp->resok.maxfilesize = MAXOFF32_T;
3969 3978 } else {
3970 3979 if (l >= (sizeof (uint64_t) * 8))
3971 3980 resp->resok.maxfilesize = INT64_MAX;
3972 3981 else
3973 3982 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3974 3983 }
3975 3984
3976 3985 resp->resok.time_delta.seconds = 0;
3977 3986 resp->resok.time_delta.nseconds = 1000;
3978 3987 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3979 3988 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3980 3989
3981 3990 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3982 3991 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3983 3992 FSINFO3res *, resp);
3984 3993
3985 3994 VN_RELE(vp);
3986 3995
3987 3996 return;
3988 3997
3989 3998 out:
3990 3999 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3991 4000 cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
3992 4001 FSINFO3res *, resp);
3993 4002 if (vp != NULL)
3994 4003 VN_RELE(vp);
3995 4004 }
3996 4005
3997 4006 void *
3998 4007 rfs3_fsinfo_getfh(FSINFO3args *args)
3999 4008 {
4000 4009 return (&args->fsroot);
4001 4010 }
4002 4011
4003 4012 /* ARGSUSED */
4004 4013 void
4005 4014 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
4006 4015 struct svc_req *req, cred_t *cr, bool_t ro)
4007 4016 {
4008 4017 int error;
4009 4018 vnode_t *vp;
4010 4019 struct vattr *vap;
4011 4020 struct vattr va;
4012 4021 ulong_t val;
4013 4022
4014 4023 vap = NULL;
4015 4024
4016 4025 vp = nfs3_fhtovp(&args->object, exi);
4017 4026
4018 4027 DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4019 4028 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4020 4029 PATHCONF3args *, args);
4021 4030
4022 4031 if (vp == NULL) {
4023 4032 error = ESTALE;
4024 4033 goto out;
4025 4034 }
4026 4035
4027 4036 if (is_system_labeled()) {
4028 4037 bslabel_t *clabel = req->rq_label;
4029 4038
4030 4039 ASSERT(clabel != NULL);
4031 4040 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4032 4041 "got client label from request(1)", struct svc_req *, req);
4033 4042
4034 4043 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4035 4044 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4036 4045 exi)) {
4037 4046 resp->status = NFS3ERR_ACCES;
4038 4047 goto out1;
4039 4048 }
4040 4049 }
4041 4050 }
4042 4051
4043 4052 va.va_mask = AT_ALL;
4044 4053 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4045 4054
4046 4055 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
4047 4056 if (error)
4048 4057 goto out;
4049 4058 resp->resok.info.link_max = (uint32)val;
4050 4059
4051 4060 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
4052 4061 if (error)
4053 4062 goto out;
4054 4063 resp->resok.info.name_max = (uint32)val;
4055 4064
4056 4065 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4057 4066 if (error)
4058 4067 goto out;
4059 4068 if (val == 1)
4060 4069 resp->resok.info.no_trunc = TRUE;
4061 4070 else
4062 4071 resp->resok.info.no_trunc = FALSE;
4063 4072
4064 4073 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4065 4074 if (error)
4066 4075 goto out;
4067 4076 if (val == 1)
4068 4077 resp->resok.info.chown_restricted = TRUE;
4069 4078 else
4070 4079 resp->resok.info.chown_restricted = FALSE;
4071 4080
4072 4081 resp->status = NFS3_OK;
4073 4082 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4074 4083 resp->resok.info.case_insensitive = FALSE;
4075 4084 resp->resok.info.case_preserving = TRUE;
4076 4085 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4077 4086 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4078 4087 PATHCONF3res *, resp);
4079 4088 VN_RELE(vp);
4080 4089 return;
4081 4090
4082 4091 out:
4083 4092 if (curthread->t_flag & T_WOULDBLOCK) {
4084 4093 curthread->t_flag &= ~T_WOULDBLOCK;
4085 4094 resp->status = NFS3ERR_JUKEBOX;
4086 4095 } else
4087 4096 resp->status = puterrno3(error);
4088 4097 out1:
4089 4098 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4090 4099 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4091 4100 PATHCONF3res *, resp);
4092 4101 if (vp != NULL)
4093 4102 VN_RELE(vp);
4094 4103 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4095 4104 }
4096 4105
4097 4106 void *
4098 4107 rfs3_pathconf_getfh(PATHCONF3args *args)
4099 4108 {
4100 4109
4101 4110 return (&args->object);
4102 4111 }
4103 4112
4104 4113 void
4105 4114 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4106 4115 struct svc_req *req, cred_t *cr, bool_t ro)
4107 4116 {
4108 4117 nfs3_srv_t *ns;
4109 4118 int error;
4110 4119 vnode_t *vp;
4111 4120 struct vattr *bvap;
4112 4121 struct vattr bva;
4113 4122 struct vattr *avap;
4114 4123 struct vattr ava;
4115 4124
4116 4125 bvap = NULL;
4117 4126 avap = NULL;
4118 4127
4119 4128 vp = nfs3_fhtovp(&args->file, exi);
4120 4129
|
↓ open down ↓ |
2780 lines elided |
↑ open up ↑ |
4121 4130 DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4122 4131 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4123 4132 COMMIT3args *, args);
4124 4133
4125 4134 if (vp == NULL) {
4126 4135 error = ESTALE;
4127 4136 goto out;
4128 4137 }
4129 4138
4130 4139 ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
4131 - ns = zone_getspecific(rfs3_zone_key, curzone);
4140 + ns = nfs3_get_srv();
4132 4141 bva.va_mask = AT_ALL;
4133 4142 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4134 4143
4135 4144 /*
4136 4145 * If we can't get the attributes, then we can't do the
4137 4146 * right access checking. So, we'll fail the request.
4138 4147 */
4139 4148 if (error)
4140 4149 goto out;
4141 4150
4142 4151 bvap = &bva;
4143 4152
4144 4153 if (rdonly(ro, vp)) {
4145 4154 resp->status = NFS3ERR_ROFS;
4146 4155 goto out1;
4147 4156 }
4148 4157
4149 4158 if (vp->v_type != VREG) {
4150 4159 resp->status = NFS3ERR_INVAL;
4151 4160 goto out1;
4152 4161 }
4153 4162
4154 4163 if (is_system_labeled()) {
4155 4164 bslabel_t *clabel = req->rq_label;
4156 4165
4157 4166 ASSERT(clabel != NULL);
4158 4167 DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4159 4168 "got client label from request(1)", struct svc_req *, req);
4160 4169
4161 4170 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4162 4171 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4163 4172 exi)) {
4164 4173 resp->status = NFS3ERR_ACCES;
4165 4174 goto out1;
4166 4175 }
4167 4176 }
4168 4177 }
4169 4178
4170 4179 if (crgetuid(cr) != bva.va_uid &&
4171 4180 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4172 4181 goto out;
4173 4182
4174 4183 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4175 4184
4176 4185 ava.va_mask = AT_ALL;
4177 4186 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4178 4187
4179 4188 if (error)
4180 4189 goto out;
4181 4190
4182 4191 resp->status = NFS3_OK;
4183 4192 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4184 4193 resp->resok.verf = ns->write3verf;
4185 4194
4186 4195 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4187 4196 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4188 4197 COMMIT3res *, resp);
4189 4198
4190 4199 VN_RELE(vp);
4191 4200
4192 4201 return;
4193 4202
4194 4203 out:
4195 4204 if (curthread->t_flag & T_WOULDBLOCK) {
4196 4205 curthread->t_flag &= ~T_WOULDBLOCK;
4197 4206 resp->status = NFS3ERR_JUKEBOX;
4198 4207 } else
4199 4208 resp->status = puterrno3(error);
4200 4209 out1:
4201 4210 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4202 4211 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4203 4212 COMMIT3res *, resp);
4204 4213
4205 4214 if (vp != NULL)
4206 4215 VN_RELE(vp);
4207 4216 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4208 4217 }
4209 4218
4210 4219 void *
4211 4220 rfs3_commit_getfh(COMMIT3args *args)
4212 4221 {
4213 4222
4214 4223 return (&args->file);
4215 4224 }
4216 4225
4217 4226 static int
4218 4227 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4219 4228 {
4220 4229
4221 4230 vap->va_mask = 0;
4222 4231
4223 4232 if (sap->mode.set_it) {
4224 4233 vap->va_mode = (mode_t)sap->mode.mode;
4225 4234 vap->va_mask |= AT_MODE;
4226 4235 }
4227 4236 if (sap->uid.set_it) {
4228 4237 vap->va_uid = (uid_t)sap->uid.uid;
4229 4238 vap->va_mask |= AT_UID;
4230 4239 }
4231 4240 if (sap->gid.set_it) {
4232 4241 vap->va_gid = (gid_t)sap->gid.gid;
4233 4242 vap->va_mask |= AT_GID;
4234 4243 }
4235 4244 if (sap->size.set_it) {
4236 4245 if (sap->size.size > (size3)((u_longlong_t)-1))
4237 4246 return (EINVAL);
4238 4247 vap->va_size = sap->size.size;
4239 4248 vap->va_mask |= AT_SIZE;
4240 4249 }
4241 4250 if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
4242 4251 #ifndef _LP64
4243 4252 /* check time validity */
4244 4253 if (!NFS3_TIME_OK(sap->atime.atime.seconds))
4245 4254 return (EOVERFLOW);
4246 4255 #endif
4247 4256 /*
4248 4257 * nfs protocol defines times as unsigned so don't extend sign,
4249 4258 * unless sysadmin set nfs_allow_preepoch_time.
4250 4259 */
4251 4260 NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4252 4261 sap->atime.atime.seconds);
4253 4262 vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
4254 4263 vap->va_mask |= AT_ATIME;
4255 4264 } else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
4256 4265 gethrestime(&vap->va_atime);
4257 4266 vap->va_mask |= AT_ATIME;
4258 4267 }
4259 4268 if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
4260 4269 #ifndef _LP64
4261 4270 /* check time validity */
4262 4271 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4263 4272 return (EOVERFLOW);
4264 4273 #endif
4265 4274 /*
4266 4275 * nfs protocol defines times as unsigned so don't extend sign,
4267 4276 * unless sysadmin set nfs_allow_preepoch_time.
4268 4277 */
4269 4278 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4270 4279 sap->mtime.mtime.seconds);
4271 4280 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4272 4281 vap->va_mask |= AT_MTIME;
4273 4282 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4274 4283 gethrestime(&vap->va_mtime);
4275 4284 vap->va_mask |= AT_MTIME;
4276 4285 }
4277 4286
4278 4287 return (0);
4279 4288 }
4280 4289
4281 4290 static const ftype3 vt_to_nf3[] = {
4282 4291 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4283 4292 };
4284 4293
4285 4294 static int
4286 4295 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4287 4296 {
4288 4297
4289 4298 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4290 4299 /* Return error if time or size overflow */
4291 4300 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4292 4301 return (EOVERFLOW);
4293 4302 }
4294 4303 fap->type = vt_to_nf3[vap->va_type];
4295 4304 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4296 4305 fap->nlink = (uint32)vap->va_nlink;
4297 4306 if (vap->va_uid == UID_NOBODY)
4298 4307 fap->uid = (uid3)NFS_UID_NOBODY;
4299 4308 else
4300 4309 fap->uid = (uid3)vap->va_uid;
4301 4310 if (vap->va_gid == GID_NOBODY)
4302 4311 fap->gid = (gid3)NFS_GID_NOBODY;
4303 4312 else
4304 4313 fap->gid = (gid3)vap->va_gid;
4305 4314 fap->size = (size3)vap->va_size;
4306 4315 fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
4307 4316 fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
4308 4317 fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
4309 4318 fap->fsid = (uint64)vap->va_fsid;
4310 4319 fap->fileid = (fileid3)vap->va_nodeid;
4311 4320 fap->atime.seconds = vap->va_atime.tv_sec;
4312 4321 fap->atime.nseconds = vap->va_atime.tv_nsec;
4313 4322 fap->mtime.seconds = vap->va_mtime.tv_sec;
4314 4323 fap->mtime.nseconds = vap->va_mtime.tv_nsec;
4315 4324 fap->ctime.seconds = vap->va_ctime.tv_sec;
4316 4325 fap->ctime.nseconds = vap->va_ctime.tv_nsec;
4317 4326 return (0);
4318 4327 }
4319 4328
4320 4329 static int
4321 4330 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
4322 4331 {
4323 4332
4324 4333 /* Return error if time or size overflow */
4325 4334 if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4326 4335 NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4327 4336 NFS3_SIZE_OK(vap->va_size))) {
4328 4337 return (EOVERFLOW);
4329 4338 }
4330 4339 wccap->size = (size3)vap->va_size;
4331 4340 wccap->mtime.seconds = vap->va_mtime.tv_sec;
4332 4341 wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
4333 4342 wccap->ctime.seconds = vap->va_ctime.tv_sec;
4334 4343 wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
4335 4344 return (0);
4336 4345 }
4337 4346
4338 4347 static void
4339 4348 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
4340 4349 {
4341 4350
4342 4351 /* don't return attrs if time overflow */
4343 4352 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4344 4353 poap->attributes = TRUE;
4345 4354 } else
4346 4355 poap->attributes = FALSE;
4347 4356 }
4348 4357
4349 4358 void
4350 4359 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4351 4360 {
4352 4361
4353 4362 /* don't return attrs if time overflow */
4354 4363 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4355 4364 poap->attributes = TRUE;
4356 4365 } else
4357 4366 poap->attributes = FALSE;
4358 4367 }
4359 4368
4360 4369 static void
4361 4370 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4362 4371 {
4363 4372 vattr_to_pre_op_attr(bvap, &wccp->before);
4364 4373 vattr_to_post_op_attr(avap, &wccp->after);
4365 4374 }
4366 4375
4367 4376 static int
4368 4377 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4369 4378 {
4370 4379 struct clist *wcl;
4371 4380 int wlist_len;
4372 4381 count3 count = rok->count;
4373 4382
|
↓ open down ↓ |
232 lines elided |
↑ open up ↑ |
4374 4383 wcl = args->wlist;
4375 4384 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4376 4385 return (FALSE);
4377 4386
4378 4387 wcl = args->wlist;
4379 4388 rok->wlist_len = wlist_len;
4380 4389 rok->wlist = wcl;
4381 4390 return (TRUE);
4382 4391 }
4383 4392
4384 -/* ARGSUSED */
4385 -static void *
4386 -rfs3_zone_init(zoneid_t zoneid)
4393 +void
4394 +rfs3_srv_zone_init(nfs_globals_t *ng)
4387 4395 {
4388 4396 nfs3_srv_t *ns;
4389 4397 struct rfs3_verf_overlay {
4390 4398 uint_t id; /* a "unique" identifier */
4391 4399 int ts; /* a unique timestamp */
4392 4400 } *verfp;
4393 4401 timestruc_t now;
4394 4402
4395 4403 ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4396 4404
4397 4405 /*
4398 4406 * The following algorithm attempts to find a unique verifier
4399 4407 * to be used as the write verifier returned from the server
4400 4408 * to the client. It is important that this verifier change
4401 4409 * whenever the server reboots. Of secondary importance, it
4402 4410 * is important for the verifier to be unique between two
4403 4411 * different servers.
4404 4412 *
4405 4413 * Thus, an attempt is made to use the system hostid and the
4406 4414 * current time in seconds when the nfssrv kernel module is
4407 4415 * loaded. It is assumed that an NFS server will not be able
4408 4416 * to boot and then to reboot in less than a second. If the
4409 4417 * hostid has not been set, then the current high resolution
4410 4418 * time is used. This will ensure different verifiers each
4411 4419 * time the server reboots and minimize the chances that two
4412 4420 * different servers will have the same verifier.
4413 4421 */
4414 4422
4415 4423 #ifndef lint
4416 4424 /*
4417 4425 * We ASSERT that this constant logic expression is
4418 4426 * always true because in the past, it wasn't.
4419 4427 */
4420 4428 ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
4421 4429 #endif
4422 4430
4423 4431 gethrestime(&now);
4424 4432 verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4425 4433 verfp->ts = (int)now.tv_sec;
4426 4434 verfp->id = zone_get_hostid(NULL);
4427 4435
4428 4436 if (verfp->id == 0)
4429 4437 verfp->id = (uint_t)now.tv_nsec;
4430 4438
4431 - return (ns);
4439 + ng->nfs3_srv = ns;
4432 4440 }
4433 4441
4434 -/* ARGSUSED */
4435 -static void
4436 -rfs3_zone_fini(zoneid_t zoneid, void *data)
4442 +void
4443 +rfs3_srv_zone_fini(nfs_globals_t *ng)
4437 4444 {
4438 - nfs3_srv_t *ns = data;
4445 + nfs3_srv_t *ns = ng->nfs3_srv;
4439 4446
4447 + ng->nfs3_srv = NULL;
4448 +
4440 4449 kmem_free(ns, sizeof (*ns));
4441 4450 }
4442 4451
4443 4452 void
4444 4453 rfs3_srvrinit(void)
4445 4454 {
4446 4455 nfs3_srv_caller_id = fs_new_caller_id();
4447 - zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini);
4448 4456 }
4449 4457
4450 4458 void
4451 4459 rfs3_srvrfini(void)
4452 4460 {
4453 4461 /* Nothing to do */
4454 4462 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX