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