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