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