1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1610 thurlow * Common Development and Distribution License (the "License"). 6 1610 thurlow * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8662 Jordan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 0 stevel /* All Rights Reserved */ 28 0 stevel 29 0 stevel #include <sys/param.h> 30 0 stevel #include <sys/types.h> 31 0 stevel #include <sys/systm.h> 32 0 stevel #include <sys/cred.h> 33 0 stevel #include <sys/buf.h> 34 0 stevel #include <sys/vfs.h> 35 0 stevel #include <sys/vnode.h> 36 0 stevel #include <sys/uio.h> 37 0 stevel #include <sys/errno.h> 38 0 stevel #include <sys/sysmacros.h> 39 0 stevel #include <sys/statvfs.h> 40 0 stevel #include <sys/kmem.h> 41 0 stevel #include <sys/dirent.h> 42 0 stevel #include <sys/cmn_err.h> 43 0 stevel #include <sys/debug.h> 44 0 stevel #include <sys/systeminfo.h> 45 0 stevel #include <sys/flock.h> 46 0 stevel #include <sys/nbmlock.h> 47 0 stevel #include <sys/policy.h> 48 4971 jarrett #include <sys/sdt.h> 49 0 stevel 50 0 stevel #include <rpc/types.h> 51 0 stevel #include <rpc/auth.h> 52 0 stevel #include <rpc/svc.h> 53 7387 Robert #include <rpc/rpc_rdma.h> 54 0 stevel 55 0 stevel #include <nfs/nfs.h> 56 0 stevel #include <nfs/export.h> 57 7961 Natalie #include <nfs/nfs_cmd.h> 58 0 stevel 59 0 stevel #include <sys/strsubr.h> 60 4971 jarrett 61 4971 jarrett #include <sys/tsol/label.h> 62 4971 jarrett #include <sys/tsol/tndb.h> 63 4971 jarrett 64 8662 Jordan #include <sys/zone.h> 65 8662 Jordan 66 4971 jarrett #include <inet/ip.h> 67 4971 jarrett #include <inet/ip6.h> 68 0 stevel 69 0 stevel /* 70 0 stevel * These are the interface routines for the server side of the 71 0 stevel * Network File System. See the NFS version 3 protocol specification 72 0 stevel * for a description of this interface. 73 0 stevel */ 74 0 stevel 75 0 stevel #ifdef DEBUG 76 0 stevel int rfs3_do_pre_op_attr = 1; 77 0 stevel int rfs3_do_post_op_attr = 1; 78 0 stevel int rfs3_do_post_op_fh3 = 1; 79 0 stevel #endif 80 0 stevel 81 0 stevel static writeverf3 write3verf; 82 0 stevel 83 0 stevel static int sattr3_to_vattr(sattr3 *, struct vattr *); 84 0 stevel static int vattr_to_fattr3(struct vattr *, fattr3 *); 85 0 stevel static int vattr_to_wcc_attr(struct vattr *, wcc_attr *); 86 0 stevel static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *); 87 0 stevel static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *); 88 7387 Robert static int rdma_setup_read_data3(READ3args *, READ3resok *); 89 0 stevel 90 5599 jwahlig u_longlong_t nfs3_srv_caller_id; 91 5599 jwahlig 92 0 stevel /* ARGSUSED */ 93 0 stevel void 94 0 stevel rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi, 95 0 stevel struct svc_req *req, cred_t *cr) 96 0 stevel { 97 0 stevel int error; 98 0 stevel vnode_t *vp; 99 0 stevel struct vattr va; 100 0 stevel 101 0 stevel vp = nfs3_fhtovp(&args->object, exi); 102 5982 ahl 103 5982 ahl DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req, 104 5982 ahl cred_t *, cr, vnode_t *, vp, GETATTR3args *, args); 105 5982 ahl 106 0 stevel if (vp == NULL) { 107 0 stevel error = ESTALE; 108 0 stevel goto out; 109 0 stevel } 110 0 stevel 111 0 stevel va.va_mask = AT_ALL; 112 0 stevel error = rfs4_delegated_getattr(vp, &va, 0, cr); 113 0 stevel 114 0 stevel if (!error) { 115 0 stevel /* overflow error if time or size is out of range */ 116 0 stevel error = vattr_to_fattr3(&va, &resp->resok.obj_attributes); 117 0 stevel if (error) 118 0 stevel goto out; 119 0 stevel resp->status = NFS3_OK; 120 5982 ahl 121 5982 ahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, 122 5982 ahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); 123 5982 ahl 124 5982 ahl VN_RELE(vp); 125 5982 ahl 126 0 stevel return; 127 0 stevel } 128 0 stevel 129 0 stevel out: 130 0 stevel if (curthread->t_flag & T_WOULDBLOCK) { 131 0 stevel curthread->t_flag &= ~T_WOULDBLOCK; 132 0 stevel resp->status = NFS3ERR_JUKEBOX; 133 0 stevel } else 134 0 stevel resp->status = puterrno3(error); 135 5982 ahl 136 5982 ahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, 137 5982 ahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); 138 5982 ahl 139 5982 ahl if (vp != NULL) 140 5982 ahl VN_RELE(vp); 141 0 stevel } 142 0 stevel 143 1610 thurlow void * 144 0 stevel rfs3_getattr_getfh(GETATTR3args *args) 145 0 stevel { 146 0 stevel 147 1610 thurlow return (&args->object); 148 0 stevel } 149 0 stevel 150 0 stevel void 151 0 stevel rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi, 152 0 stevel struct svc_req *req, cred_t *cr) 153 0 stevel { 154 0 stevel int error; 155 0 stevel vnode_t *vp; 156 0 stevel struct vattr *bvap; 157 0 stevel struct vattr bva; 158 0 stevel struct vattr *avap; 159 0 stevel struct vattr ava; 160 0 stevel int flag; 161 0 stevel int in_crit = 0; 162 0 stevel struct flock64 bf; 163 5599 jwahlig caller_context_t ct; 164 0 stevel 165 0 stevel bvap = NULL; 166 0 stevel avap = NULL; 167 0 stevel 168 0 stevel vp = nfs3_fhtovp(&args->object, exi); 169 5982 ahl 170 5982 ahl DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req, 171 5982 ahl cred_t *, cr, vnode_t *, vp, SETATTR3args *, args); 172 5982 ahl 173 0 stevel if (vp == NULL) { 174 0 stevel error = ESTALE; 175 0 stevel goto out; 176 0 stevel } 177 0 stevel 178 0 stevel error = sattr3_to_vattr(&args->new_attributes, &ava); 179 0 stevel if (error) 180 0 stevel goto out; 181 4971 jarrett 182 4971 jarrett if (is_system_labeled()) { 183 4971 jarrett bslabel_t *clabel = req->rq_label; 184 4971 jarrett 185 4971 jarrett ASSERT(clabel != NULL); 186 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *, 187 4971 jarrett "got client label from request(1)", struct svc_req *, req); 188 4971 jarrett 189 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 190 9871 Jarrett if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 191 9871 Jarrett exi)) { 192 4971 jarrett resp->status = NFS3ERR_ACCES; 193 4971 jarrett goto out1; 194 4971 jarrett } 195 4971 jarrett } 196 4971 jarrett } 197 0 stevel 198 0 stevel /* 199 0 stevel * We need to specially handle size changes because of 200 0 stevel * possible conflicting NBMAND locks. Get into critical 201 0 stevel * region before VOP_GETATTR, so the size attribute is 202 0 stevel * valid when checking conflicts. 203 0 stevel * 204 0 stevel * Also, check to see if the v4 side of the server has 205 0 stevel * delegated this file. If so, then we return JUKEBOX to 206 0 stevel * allow the client to retrasmit its request. 207 0 stevel */ 208 0 stevel if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 209 0 stevel if (nbl_need_check(vp)) { 210 0 stevel nbl_start_crit(vp, RW_READER); 211 0 stevel in_crit = 1; 212 0 stevel } 213 0 stevel } 214 0 stevel 215 0 stevel bva.va_mask = AT_ALL; 216 0 stevel error = rfs4_delegated_getattr(vp, &bva, 0, cr); 217 0 stevel 218 0 stevel /* 219 0 stevel * If we can't get the attributes, then we can't do the 220 0 stevel * right access checking. So, we'll fail the request. 221 0 stevel */ 222 0 stevel if (error) 223 0 stevel goto out; 224 0 stevel 225 0 stevel #ifdef DEBUG 226 0 stevel if (rfs3_do_pre_op_attr) 227 0 stevel bvap = &bva; 228 0 stevel #else 229 0 stevel bvap = &bva; 230 0 stevel #endif 231 0 stevel 232 0 stevel if (rdonly(exi, req) || vn_is_readonly(vp)) { 233 0 stevel resp->status = NFS3ERR_ROFS; 234 0 stevel goto out1; 235 0 stevel } 236 0 stevel 237 0 stevel if (args->guard.check && 238 0 stevel (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec || 239 0 stevel args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) { 240 0 stevel resp->status = NFS3ERR_NOT_SYNC; 241 0 stevel goto out1; 242 0 stevel } 243 0 stevel 244 0 stevel if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME) 245 0 stevel flag = ATTR_UTIME; 246 0 stevel else 247 0 stevel flag = 0; 248 0 stevel 249 0 stevel /* 250 0 stevel * If the filesystem is exported with nosuid, then mask off 251 0 stevel * the setuid and setgid bits. 252 0 stevel */ 253 0 stevel if ((ava.va_mask & AT_MODE) && vp->v_type == VREG && 254 0 stevel (exi->exi_export.ex_flags & EX_NOSUID)) 255 0 stevel ava.va_mode &= ~(VSUID | VSGID); 256 5599 jwahlig 257 5599 jwahlig ct.cc_sysid = 0; 258 5599 jwahlig ct.cc_pid = 0; 259 5599 jwahlig ct.cc_caller_id = nfs3_srv_caller_id; 260 5599 jwahlig ct.cc_flags = CC_DONTBLOCK; 261 0 stevel 262 0 stevel /* 263 0 stevel * We need to specially handle size changes because it is 264 0 stevel * possible for the client to create a file with modes 265 0 stevel * which indicate read-only, but with the file opened for 266 0 stevel * writing. If the client then tries to set the size of 267 0 stevel * the file, then the normal access checking done in 268 0 stevel * VOP_SETATTR would prevent the client from doing so, 269 0 stevel * although it should be legal for it to do so. To get 270 0 stevel * around this, we do the access checking for ourselves 271 0 stevel * and then use VOP_SPACE which doesn't do the access 272 0 stevel * checking which VOP_SETATTR does. VOP_SPACE can only 273 0 stevel * operate on VREG files, let VOP_SETATTR handle the other 274 0 stevel * extremely rare cases. 275 0 stevel * Also the client should not be allowed to change the 276 0 stevel * size of the file if there is a conflicting non-blocking 277 0 stevel * mandatory lock in the region the change. 278 0 stevel */ 279 0 stevel if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 280 0 stevel if (in_crit) { 281 0 stevel u_offset_t offset; 282 0 stevel ssize_t length; 283 0 stevel 284 0 stevel if (ava.va_size < bva.va_size) { 285 0 stevel offset = ava.va_size; 286 0 stevel length = bva.va_size - ava.va_size; 287 0 stevel } else { 288 0 stevel offset = bva.va_size; 289 0 stevel length = ava.va_size - bva.va_size; 290 0 stevel } 291 5331 amw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0, 292 5331 amw NULL)) { 293 0 stevel error = EACCES; 294 0 stevel goto out; 295 0 stevel } 296 0 stevel } 297 0 stevel 298 0 stevel if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) { 299 0 stevel ava.va_mask &= ~AT_SIZE; 300 0 stevel bf.l_type = F_WRLCK; 301 0 stevel bf.l_whence = 0; 302 0 stevel bf.l_start = (off64_t)ava.va_size; 303 0 stevel bf.l_len = 0; 304 0 stevel bf.l_sysid = 0; 305 0 stevel bf.l_pid = 0; 306 0 stevel error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE, 307 5599 jwahlig (offset_t)ava.va_size, cr, &ct); 308 0 stevel } 309 0 stevel } 310 0 stevel 311 0 stevel if (!error && ava.va_mask) 312 5599 jwahlig error = VOP_SETATTR(vp, &ava, flag, cr, &ct); 313 5599 jwahlig 314 5599 jwahlig /* check if a monitor detected a delegation conflict */ 315 5599 jwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 316 5599 jwahlig resp->status = NFS3ERR_JUKEBOX; 317 5599 jwahlig goto out1; 318 5599 jwahlig } 319 0 stevel 320 0 stevel #ifdef DEBUG 321 0 stevel if (rfs3_do_post_op_attr) { 322 0 stevel ava.va_mask = AT_ALL; 323 0 stevel avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava; 324 0 stevel } else 325 0 stevel avap = NULL; 326 0 stevel #else 327 0 stevel ava.va_mask = AT_ALL; 328 0 stevel avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava; 329 0 stevel #endif 330 0 stevel 331 0 stevel /* 332 0 stevel * Force modified metadata out to stable storage. 333 0 stevel */ 334 5599 jwahlig (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct); 335 0 stevel 336 0 stevel if (error) 337 0 stevel goto out; 338 0 stevel 339 0 stevel if (in_crit) 340 0 stevel nbl_end_crit(vp); 341 0 stevel 342 0 stevel resp->status = NFS3_OK; 343 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc); 344 5982 ahl 345 5982 ahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, 346 5982 ahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); 347 5982 ahl 348 5982 ahl VN_RELE(vp); 349 5982 ahl 350 5982 ahl return; 351 5982 ahl 352 5982 ahl out: 353 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 354 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 355 5982 ahl resp->status = NFS3ERR_JUKEBOX; 356 5982 ahl } else 357 5982 ahl resp->status = puterrno3(error); 358 5982 ahl out1: 359 5982 ahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, 360 5982 ahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); 361 5982 ahl 362 0 stevel if (vp != NULL) { 363 0 stevel if (in_crit) 364 0 stevel nbl_end_crit(vp); 365 0 stevel VN_RELE(vp); 366 0 stevel } 367 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc); 368 0 stevel } 369 0 stevel 370 1610 thurlow void * 371 0 stevel rfs3_setattr_getfh(SETATTR3args *args) 372 0 stevel { 373 0 stevel 374 1610 thurlow return (&args->object); 375 0 stevel } 376 0 stevel 377 0 stevel /* ARGSUSED */ 378 0 stevel void 379 0 stevel rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi, 380 0 stevel struct svc_req *req, cred_t *cr) 381 0 stevel { 382 0 stevel int error; 383 0 stevel vnode_t *vp; 384 0 stevel vnode_t *dvp; 385 0 stevel struct vattr *vap; 386 0 stevel struct vattr va; 387 0 stevel struct vattr *dvap; 388 0 stevel struct vattr dva; 389 0 stevel nfs_fh3 *fhp; 390 0 stevel struct sec_ol sec = {0, 0}; 391 0 stevel bool_t publicfh_flag = FALSE, auth_weak = FALSE; 392 7961 Natalie struct sockaddr *ca; 393 7961 Natalie char *name = NULL; 394 0 stevel 395 0 stevel dvap = NULL; 396 0 stevel 397 0 stevel /* 398 0 stevel * Allow lookups from the root - the default 399 0 stevel * location of the public filehandle. 400 0 stevel */ 401 0 stevel if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { 402 0 stevel dvp = rootdir; 403 0 stevel VN_HOLD(dvp); 404 5982 ahl 405 5982 ahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, 406 5982 ahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); 407 0 stevel } else { 408 1610 thurlow dvp = nfs3_fhtovp(&args->what.dir, exi); 409 5982 ahl 410 5982 ahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, 411 5982 ahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); 412 5982 ahl 413 0 stevel if (dvp == NULL) { 414 0 stevel error = ESTALE; 415 0 stevel goto out; 416 0 stevel } 417 0 stevel } 418 0 stevel 419 0 stevel #ifdef DEBUG 420 0 stevel if (rfs3_do_pre_op_attr) { 421 0 stevel dva.va_mask = AT_ALL; 422 5331 amw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 423 0 stevel } 424 0 stevel #else 425 0 stevel dva.va_mask = AT_ALL; 426 5331 amw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 427 0 stevel #endif 428 0 stevel 429 0 stevel if (args->what.name == nfs3nametoolong) { 430 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 431 0 stevel goto out1; 432 0 stevel } 433 0 stevel 434 0 stevel if (args->what.name == NULL || *(args->what.name) == '\0') { 435 0 stevel resp->status = NFS3ERR_ACCES; 436 0 stevel goto out1; 437 0 stevel } 438 0 stevel 439 1610 thurlow fhp = &args->what.dir; 440 0 stevel if (strcmp(args->what.name, "..") == 0 && 441 1610 thurlow EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) { 442 0 stevel resp->status = NFS3ERR_NOENT; 443 0 stevel goto out1; 444 0 stevel } 445 0 stevel 446 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 447 7961 Natalie name = nfscmd_convname(ca, exi, args->what.name, 448 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 449 7961 Natalie 450 7961 Natalie if (name == NULL) { 451 7961 Natalie resp->status = NFS3ERR_ACCES; 452 7961 Natalie goto out1; 453 7961 Natalie } 454 7961 Natalie 455 0 stevel /* 456 0 stevel * If the public filehandle is used then allow 457 0 stevel * a multi-component lookup 458 0 stevel */ 459 1610 thurlow if (PUBLIC_FH3(&args->what.dir)) { 460 0 stevel publicfh_flag = TRUE; 461 7961 Natalie error = rfs_publicfh_mclookup(name, dvp, cr, &vp, 462 5599 jwahlig &exi, &sec); 463 0 stevel if (error && exi != NULL) 464 4971 jarrett exi_rele(exi); /* See comment below Re: publicfh_flag */ 465 4971 jarrett /* 466 4971 jarrett * Since WebNFS may bypass MOUNT, we need to ensure this 467 4971 jarrett * request didn't come from an unlabeled admin_low client. 468 4971 jarrett */ 469 4971 jarrett if (is_system_labeled() && error == 0) { 470 4971 jarrett int addr_type; 471 4971 jarrett void *ipaddr; 472 4971 jarrett tsol_tpc_t *tp; 473 4971 jarrett 474 4971 jarrett if (ca->sa_family == AF_INET) { 475 4971 jarrett addr_type = IPV4_VERSION; 476 4971 jarrett ipaddr = &((struct sockaddr_in *)ca)->sin_addr; 477 4971 jarrett } else if (ca->sa_family == AF_INET6) { 478 4971 jarrett addr_type = IPV6_VERSION; 479 4971 jarrett ipaddr = &((struct sockaddr_in6 *) 480 4971 jarrett ca)->sin6_addr; 481 4971 jarrett } 482 4971 jarrett tp = find_tpc(ipaddr, addr_type, B_FALSE); 483 4971 jarrett if (tp == NULL || tp->tpc_tp.tp_doi != 484 4971 jarrett l_admin_low->tsl_doi || tp->tpc_tp.host_type != 485 4971 jarrett SUN_CIPSO) { 486 4971 jarrett if (exi != NULL) 487 4971 jarrett exi_rele(exi); 488 4971 jarrett VN_RELE(vp); 489 4971 jarrett resp->status = NFS3ERR_ACCES; 490 4971 jarrett error = 1; 491 4971 jarrett } 492 4971 jarrett if (tp != NULL) 493 4971 jarrett TPC_RELE(tp); 494 4971 jarrett } 495 0 stevel } else { 496 7961 Natalie error = VOP_LOOKUP(dvp, name, &vp, 497 5599 jwahlig NULL, 0, NULL, cr, NULL, NULL, NULL); 498 4971 jarrett } 499 7961 Natalie 500 7961 Natalie if (name != args->what.name) 501 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 502 4971 jarrett 503 4971 jarrett if (is_system_labeled() && error == 0) { 504 4971 jarrett bslabel_t *clabel = req->rq_label; 505 4971 jarrett 506 4971 jarrett ASSERT(clabel != NULL); 507 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *, 508 4971 jarrett "got client label from request(1)", struct svc_req *, req); 509 4971 jarrett 510 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 511 4971 jarrett if (!do_rfs_label_check(clabel, dvp, 512 9871 Jarrett DOMINANCE_CHECK, exi)) { 513 4971 jarrett if (publicfh_flag && exi != NULL) 514 4971 jarrett exi_rele(exi); 515 4971 jarrett VN_RELE(vp); 516 4971 jarrett resp->status = NFS3ERR_ACCES; 517 4971 jarrett error = 1; 518 4971 jarrett } 519 4971 jarrett } 520 0 stevel } 521 0 stevel 522 0 stevel #ifdef DEBUG 523 0 stevel if (rfs3_do_post_op_attr) { 524 0 stevel dva.va_mask = AT_ALL; 525 5331 amw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 526 0 stevel } else 527 0 stevel dvap = NULL; 528 0 stevel #else 529 0 stevel dva.va_mask = AT_ALL; 530 5331 amw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 531 0 stevel #endif 532 0 stevel 533 0 stevel if (error) 534 0 stevel goto out; 535 0 stevel 536 0 stevel if (sec.sec_flags & SEC_QUERY) { 537 0 stevel error = makefh3_ol(&resp->resok.object, exi, sec.sec_index); 538 0 stevel } else { 539 0 stevel error = makefh3(&resp->resok.object, vp, exi); 540 0 stevel if (!error && publicfh_flag && !chk_clnt_sec(exi, req)) 541 0 stevel auth_weak = TRUE; 542 0 stevel } 543 0 stevel 544 0 stevel if (error) { 545 0 stevel VN_RELE(vp); 546 0 stevel goto out; 547 0 stevel } 548 0 stevel 549 0 stevel /* 550 0 stevel * If publicfh_flag is true then we have called rfs_publicfh_mclookup 551 0 stevel * and have obtained a new exportinfo in exi which needs to be 552 0 stevel * released. Note the the original exportinfo pointed to by exi 553 0 stevel * will be released by the caller, common_dispatch. 554 0 stevel */ 555 0 stevel if (publicfh_flag) 556 0 stevel exi_rele(exi); 557 0 stevel 558 0 stevel #ifdef DEBUG 559 0 stevel if (rfs3_do_post_op_attr) { 560 0 stevel va.va_mask = AT_ALL; 561 0 stevel vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 562 0 stevel } else 563 0 stevel vap = NULL; 564 0 stevel #else 565 0 stevel va.va_mask = AT_ALL; 566 0 stevel vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 567 0 stevel #endif 568 0 stevel 569 0 stevel VN_RELE(vp); 570 0 stevel 571 0 stevel resp->status = NFS3_OK; 572 0 stevel vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 573 0 stevel vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes); 574 0 stevel 575 0 stevel /* 576 0 stevel * If it's public fh, no 0x81, and client's flavor is 577 0 stevel * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now. 578 0 stevel * Then set RPC status to AUTH_TOOWEAK in common_dispatch. 579 0 stevel */ 580 0 stevel if (auth_weak) 581 0 stevel resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR; 582 0 stevel 583 5982 ahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, 584 5982 ahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); 585 5982 ahl VN_RELE(dvp); 586 5982 ahl 587 5982 ahl return; 588 5982 ahl 589 5982 ahl out: 590 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 591 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 592 5982 ahl resp->status = NFS3ERR_JUKEBOX; 593 5982 ahl } else 594 5982 ahl resp->status = puterrno3(error); 595 5982 ahl out1: 596 5982 ahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, 597 5982 ahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); 598 5982 ahl 599 0 stevel if (dvp != NULL) 600 0 stevel VN_RELE(dvp); 601 0 stevel vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes); 602 0 stevel 603 0 stevel } 604 0 stevel 605 1610 thurlow void * 606 0 stevel rfs3_lookup_getfh(LOOKUP3args *args) 607 0 stevel { 608 0 stevel 609 1610 thurlow return (&args->what.dir); 610 0 stevel } 611 0 stevel 612 0 stevel /* ARGSUSED */ 613 0 stevel void 614 0 stevel rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi, 615 0 stevel struct svc_req *req, cred_t *cr) 616 0 stevel { 617 0 stevel int error; 618 0 stevel vnode_t *vp; 619 0 stevel struct vattr *vap; 620 0 stevel struct vattr va; 621 0 stevel int checkwriteperm; 622 4971 jarrett boolean_t dominant_label = B_FALSE; 623 4971 jarrett boolean_t equal_label = B_FALSE; 624 4971 jarrett boolean_t admin_low_client; 625 0 stevel 626 0 stevel vap = NULL; 627 0 stevel 628 0 stevel vp = nfs3_fhtovp(&args->object, exi); 629 5982 ahl 630 5982 ahl DTRACE_NFSV3_4(op__access__start, struct svc_req *, req, 631 5982 ahl cred_t *, cr, vnode_t *, vp, ACCESS3args *, args); 632 5982 ahl 633 0 stevel if (vp == NULL) { 634 0 stevel error = ESTALE; 635 0 stevel goto out; 636 0 stevel } 637 0 stevel 638 0 stevel /* 639 0 stevel * If the file system is exported read only, it is not appropriate 640 0 stevel * to check write permissions for regular files and directories. 641 0 stevel * Special files are interpreted by the client, so the underlying 642 0 stevel * permissions are sent back to the client for interpretation. 643 0 stevel */ 644 0 stevel if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR)) 645 0 stevel checkwriteperm = 0; 646 0 stevel else 647 0 stevel checkwriteperm = 1; 648 0 stevel 649 0 stevel /* 650 0 stevel * We need the mode so that we can correctly determine access 651 0 stevel * permissions relative to a mandatory lock file. Access to 652 0 stevel * mandatory lock files is denied on the server, so it might 653 0 stevel * as well be reflected to the server during the open. 654 0 stevel */ 655 0 stevel va.va_mask = AT_MODE; 656 5331 amw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 657 0 stevel if (error) 658 0 stevel goto out; 659 0 stevel 660 0 stevel #ifdef DEBUG 661 0 stevel if (rfs3_do_post_op_attr) 662 0 stevel vap = &va; 663 0 stevel #else 664 0 stevel vap = &va; 665 0 stevel #endif 666 0 stevel 667 0 stevel resp->resok.access = 0; 668 0 stevel 669 4971 jarrett if (is_system_labeled()) { 670 4971 jarrett bslabel_t *clabel = req->rq_label; 671 4971 jarrett 672 4971 jarrett ASSERT(clabel != NULL); 673 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *, 674 4971 jarrett "got client label from request(1)", struct svc_req *, req); 675 4971 jarrett 676 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 677 4971 jarrett if ((equal_label = do_rfs_label_check(clabel, vp, 678 9871 Jarrett EQUALITY_CHECK, exi)) == B_FALSE) { 679 4971 jarrett dominant_label = do_rfs_label_check(clabel, 680 9871 Jarrett vp, DOMINANCE_CHECK, exi); 681 4971 jarrett } else 682 4971 jarrett dominant_label = B_TRUE; 683 4971 jarrett admin_low_client = B_FALSE; 684 4971 jarrett } else 685 4971 jarrett admin_low_client = B_TRUE; 686 4971 jarrett } 687 4971 jarrett 688 0 stevel if (args->access & ACCESS3_READ) { 689 5331 amw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 690 0 stevel if (error) { 691 0 stevel if (curthread->t_flag & T_WOULDBLOCK) 692 0 stevel goto out; 693 4971 jarrett } else if (!MANDLOCK(vp, va.va_mode) && 694 4971 jarrett (!is_system_labeled() || admin_low_client || 695 4971 jarrett dominant_label)) 696 0 stevel resp->resok.access |= ACCESS3_READ; 697 0 stevel } 698 0 stevel if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) { 699 5331 amw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 700 0 stevel if (error) { 701 0 stevel if (curthread->t_flag & T_WOULDBLOCK) 702 0 stevel goto out; 703 4971 jarrett } else if (!is_system_labeled() || admin_low_client || 704 4971 jarrett dominant_label) 705 0 stevel resp->resok.access |= ACCESS3_LOOKUP; 706 0 stevel } 707 0 stevel if (checkwriteperm && 708 0 stevel (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) { 709 5331 amw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 710 0 stevel if (error) { 711 0 stevel if (curthread->t_flag & T_WOULDBLOCK) 712 0 stevel goto out; 713 4971 jarrett } else if (!MANDLOCK(vp, va.va_mode) && 714 4971 jarrett (!is_system_labeled() || admin_low_client || equal_label)) { 715 0 stevel resp->resok.access |= 716 0 stevel (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND)); 717 0 stevel } 718 0 stevel } 719 0 stevel if (checkwriteperm && 720 0 stevel (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) { 721 5331 amw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 722 0 stevel if (error) { 723 0 stevel if (curthread->t_flag & T_WOULDBLOCK) 724 0 stevel goto out; 725 4971 jarrett } else if (!is_system_labeled() || admin_low_client || 726 4971 jarrett equal_label) 727 0 stevel resp->resok.access |= ACCESS3_DELETE; 728 0 stevel } 729 0 stevel if (args->access & ACCESS3_EXECUTE) { 730 5331 amw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 731 0 stevel if (error) { 732 0 stevel if (curthread->t_flag & T_WOULDBLOCK) 733 0 stevel goto out; 734 4971 jarrett } else if (!MANDLOCK(vp, va.va_mode) && 735 4971 jarrett (!is_system_labeled() || admin_low_client || 736 4971 jarrett dominant_label)) 737 0 stevel resp->resok.access |= ACCESS3_EXECUTE; 738 0 stevel } 739 0 stevel 740 0 stevel #ifdef DEBUG 741 0 stevel if (rfs3_do_post_op_attr) { 742 0 stevel va.va_mask = AT_ALL; 743 0 stevel vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 744 0 stevel } else 745 0 stevel vap = NULL; 746 0 stevel #else 747 0 stevel va.va_mask = AT_ALL; 748 0 stevel vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 749 0 stevel #endif 750 0 stevel 751 5982 ahl resp->status = NFS3_OK; 752 5982 ahl vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 753 5982 ahl 754 5982 ahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, 755 5982 ahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); 756 5982 ahl 757 5982 ahl VN_RELE(vp); 758 5982 ahl 759 5982 ahl return; 760 5982 ahl 761 5982 ahl out: 762 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 763 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 764 5982 ahl resp->status = NFS3ERR_JUKEBOX; 765 5982 ahl } else 766 5982 ahl resp->status = puterrno3(error); 767 5982 ahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, 768 5982 ahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); 769 0 stevel if (vp != NULL) 770 0 stevel VN_RELE(vp); 771 0 stevel vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 772 0 stevel } 773 0 stevel 774 1610 thurlow void * 775 0 stevel rfs3_access_getfh(ACCESS3args *args) 776 0 stevel { 777 0 stevel 778 1610 thurlow return (&args->object); 779 0 stevel } 780 0 stevel 781 0 stevel /* ARGSUSED */ 782 0 stevel void 783 0 stevel rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi, 784 0 stevel struct svc_req *req, cred_t *cr) 785 0 stevel { 786 0 stevel int error; 787 0 stevel vnode_t *vp; 788 0 stevel struct vattr *vap; 789 0 stevel struct vattr va; 790 0 stevel struct iovec iov; 791 0 stevel struct uio uio; 792 0 stevel char *data; 793 7961 Natalie struct sockaddr *ca; 794 7961 Natalie char *name = NULL; 795 0 stevel 796 0 stevel vap = NULL; 797 0 stevel 798 0 stevel vp = nfs3_fhtovp(&args->symlink, exi); 799 5982 ahl 800 5982 ahl DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req, 801 5982 ahl cred_t *, cr, vnode_t *, vp, READLINK3args *, args); 802 5982 ahl 803 0 stevel if (vp == NULL) { 804 0 stevel error = ESTALE; 805 0 stevel goto out; 806 0 stevel } 807 0 stevel 808 0 stevel va.va_mask = AT_ALL; 809 5331 amw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 810 0 stevel if (error) 811 0 stevel goto out; 812 0 stevel 813 0 stevel #ifdef DEBUG 814 0 stevel if (rfs3_do_post_op_attr) 815 0 stevel vap = &va; 816 0 stevel #else 817 0 stevel vap = &va; 818 0 stevel #endif 819 0 stevel 820 0 stevel if (vp->v_type != VLNK) { 821 0 stevel resp->status = NFS3ERR_INVAL; 822 0 stevel goto out1; 823 0 stevel } 824 0 stevel 825 0 stevel if (MANDLOCK(vp, va.va_mode)) { 826 0 stevel resp->status = NFS3ERR_ACCES; 827 0 stevel goto out1; 828 4971 jarrett } 829 4971 jarrett 830 4971 jarrett if (is_system_labeled()) { 831 4971 jarrett bslabel_t *clabel = req->rq_label; 832 4971 jarrett 833 4971 jarrett ASSERT(clabel != NULL); 834 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *, 835 4971 jarrett "got client label from request(1)", struct svc_req *, req); 836 4971 jarrett 837 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 838 9871 Jarrett if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 839 9871 Jarrett exi)) { 840 4971 jarrett resp->status = NFS3ERR_ACCES; 841 4971 jarrett goto out1; 842 4971 jarrett } 843 4971 jarrett } 844 0 stevel } 845 0 stevel 846 0 stevel data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP); 847 0 stevel 848 0 stevel iov.iov_base = data; 849 0 stevel iov.iov_len = MAXPATHLEN; 850 0 stevel uio.uio_iov = &iov; 851 0 stevel uio.uio_iovcnt = 1; 852 0 stevel uio.uio_segflg = UIO_SYSSPACE; 853 0 stevel uio.uio_extflg = UIO_COPY_CACHED; 854 0 stevel uio.uio_loffset = 0; 855 0 stevel uio.uio_resid = MAXPATHLEN; 856 0 stevel 857 5331 amw error = VOP_READLINK(vp, &uio, cr, NULL); 858 5331 amw 859 5331 amw #ifdef DEBUG 860 5331 amw if (rfs3_do_post_op_attr) { 861 5331 amw va.va_mask = AT_ALL; 862 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 863 5331 amw } else 864 5331 amw vap = NULL; 865 5331 amw #else 866 5331 amw va.va_mask = AT_ALL; 867 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 868 0 stevel #endif 869 0 stevel 870 0 stevel #if 0 /* notyet */ 871 0 stevel /* 872 0 stevel * Don't do this. It causes local disk writes when just 873 0 stevel * reading the file and the overhead is deemed larger 874 0 stevel * than the benefit. 875 0 stevel */ 876 0 stevel /* 877 0 stevel * Force modified metadata out to stable storage. 878 0 stevel */ 879 5331 amw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 880 0 stevel #endif 881 0 stevel 882 0 stevel if (error) { 883 0 stevel kmem_free(data, MAXPATHLEN + 1); 884 0 stevel goto out; 885 0 stevel } 886 0 stevel 887 7961 Natalie *(data + MAXPATHLEN - uio.uio_resid) = '\0'; 888 7961 Natalie 889 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 890 7961 Natalie name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND, 891 7961 Natalie MAXPATHLEN + 1); 892 7961 Natalie 893 7961 Natalie if (name == NULL) { 894 7961 Natalie /* 895 7961 Natalie * Even though the conversion failed, we return 896 7961 Natalie * something. We just don't translate it. 897 7961 Natalie */ 898 7961 Natalie name = data; 899 7961 Natalie } 900 7961 Natalie 901 0 stevel resp->status = NFS3_OK; 902 0 stevel vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes); 903 7961 Natalie resp->resok.data = name; 904 5982 ahl 905 5982 ahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, 906 5982 ahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); 907 5982 ahl VN_RELE(vp); 908 7961 Natalie 909 7961 Natalie if (name != data) 910 7961 Natalie kmem_free(data, MAXPATHLEN + 1); 911 5982 ahl 912 5982 ahl return; 913 5982 ahl 914 5982 ahl out: 915 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 916 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 917 5982 ahl resp->status = NFS3ERR_JUKEBOX; 918 5982 ahl } else 919 5982 ahl resp->status = puterrno3(error); 920 5982 ahl out1: 921 5982 ahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, 922 5982 ahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); 923 0 stevel if (vp != NULL) 924 0 stevel VN_RELE(vp); 925 0 stevel vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes); 926 0 stevel } 927 0 stevel 928 1610 thurlow void * 929 0 stevel rfs3_readlink_getfh(READLINK3args *args) 930 0 stevel { 931 0 stevel 932 1610 thurlow return (&args->symlink); 933 0 stevel } 934 0 stevel 935 0 stevel void 936 0 stevel rfs3_readlink_free(READLINK3res *resp) 937 0 stevel { 938 0 stevel 939 0 stevel if (resp->status == NFS3_OK) 940 0 stevel kmem_free(resp->resok.data, MAXPATHLEN + 1); 941 0 stevel } 942 0 stevel 943 7387 Robert /* 944 7387 Robert * Server routine to handle read 945 7387 Robert * May handle RDMA data as well as mblks 946 7387 Robert */ 947 0 stevel /* ARGSUSED */ 948 0 stevel void 949 0 stevel rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi, 950 0 stevel struct svc_req *req, cred_t *cr) 951 0 stevel { 952 0 stevel int error; 953 0 stevel vnode_t *vp; 954 0 stevel struct vattr *vap; 955 0 stevel struct vattr va; 956 0 stevel struct iovec iov; 957 0 stevel struct uio uio; 958 0 stevel u_offset_t offset; 959 0 stevel mblk_t *mp; 960 0 stevel int alloc_err = 0; 961 0 stevel int in_crit = 0; 962 0 stevel int need_rwunlock = 0; 963 5599 jwahlig caller_context_t ct; 964 0 stevel 965 0 stevel vap = NULL; 966 0 stevel 967 0 stevel vp = nfs3_fhtovp(&args->file, exi); 968 5982 ahl 969 5982 ahl DTRACE_NFSV3_4(op__read__start, struct svc_req *, req, 970 5982 ahl cred_t *, cr, vnode_t *, vp, READ3args *, args); 971 5982 ahl 972 0 stevel if (vp == NULL) { 973 0 stevel error = ESTALE; 974 0 stevel goto out; 975 4971 jarrett } 976 4971 jarrett 977 4971 jarrett if (is_system_labeled()) { 978 4971 jarrett bslabel_t *clabel = req->rq_label; 979 4971 jarrett 980 4971 jarrett ASSERT(clabel != NULL); 981 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *, 982 4971 jarrett "got client label from request(1)", struct svc_req *, req); 983 4971 jarrett 984 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 985 9871 Jarrett if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 986 9871 Jarrett exi)) { 987 4971 jarrett resp->status = NFS3ERR_ACCES; 988 4971 jarrett goto out1; 989 4971 jarrett } 990 4971 jarrett } 991 0 stevel } 992 0 stevel 993 5599 jwahlig ct.cc_sysid = 0; 994 5599 jwahlig ct.cc_pid = 0; 995 5599 jwahlig ct.cc_caller_id = nfs3_srv_caller_id; 996 5599 jwahlig ct.cc_flags = CC_DONTBLOCK; 997 0 stevel 998 0 stevel /* 999 0 stevel * Enter the critical region before calling VOP_RWLOCK 1000 0 stevel * to avoid a deadlock with write requests. 1001 0 stevel */ 1002 0 stevel if (nbl_need_check(vp)) { 1003 0 stevel nbl_start_crit(vp, RW_READER); 1004 0 stevel in_crit = 1; 1005 5331 amw if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0, 1006 5331 amw NULL)) { 1007 0 stevel error = EACCES; 1008 0 stevel goto out; 1009 0 stevel } 1010 0 stevel } 1011 0 stevel 1012 5599 jwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct); 1013 5599 jwahlig 1014 5599 jwahlig /* check if a monitor detected a delegation conflict */ 1015 5599 jwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1016 5599 jwahlig resp->status = NFS3ERR_JUKEBOX; 1017 5599 jwahlig goto out1; 1018 5599 jwahlig } 1019 5599 jwahlig 1020 0 stevel need_rwunlock = 1; 1021 0 stevel 1022 0 stevel va.va_mask = AT_ALL; 1023 5599 jwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 1024 0 stevel 1025 0 stevel /* 1026 0 stevel * If we can't get the attributes, then we can't do the 1027 0 stevel * right access checking. So, we'll fail the request. 1028 0 stevel */ 1029 0 stevel if (error) 1030 0 stevel goto out; 1031 0 stevel 1032 0 stevel #ifdef DEBUG 1033 0 stevel if (rfs3_do_post_op_attr) 1034 0 stevel vap = &va; 1035 0 stevel #else 1036 0 stevel vap = &va; 1037 0 stevel #endif 1038 0 stevel 1039 0 stevel if (vp->v_type != VREG) { 1040 0 stevel resp->status = NFS3ERR_INVAL; 1041 0 stevel goto out1; 1042 0 stevel } 1043 0 stevel 1044 0 stevel if (crgetuid(cr) != va.va_uid) { 1045 5599 jwahlig error = VOP_ACCESS(vp, VREAD, 0, cr, &ct); 1046 5599 jwahlig if (error) { 1047 5599 jwahlig if (curthread->t_flag & T_WOULDBLOCK) 1048 5599 jwahlig goto out; 1049 5599 jwahlig error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct); 1050 0 stevel if (error) 1051 0 stevel goto out; 1052 0 stevel } 1053 0 stevel } 1054 0 stevel 1055 0 stevel if (MANDLOCK(vp, va.va_mode)) { 1056 0 stevel resp->status = NFS3ERR_ACCES; 1057 0 stevel goto out1; 1058 0 stevel } 1059 0 stevel 1060 0 stevel offset = args->offset; 1061 0 stevel if (offset >= va.va_size) { 1062 5599 jwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1063 0 stevel if (in_crit) 1064 0 stevel nbl_end_crit(vp); 1065 0 stevel resp->status = NFS3_OK; 1066 0 stevel vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1067 0 stevel resp->resok.count = 0; 1068 0 stevel resp->resok.eof = TRUE; 1069 0 stevel resp->resok.data.data_len = 0; 1070 0 stevel resp->resok.data.data_val = NULL; 1071 0 stevel resp->resok.data.mp = NULL; 1072 7387 Robert /* RDMA */ 1073 7387 Robert resp->resok.wlist = args->wlist; 1074 7387 Robert resp->resok.wlist_len = resp->resok.count; 1075 9348 Siddheshwar if (resp->resok.wlist) 1076 9348 Siddheshwar clist_zero_len(resp->resok.wlist); 1077 5982 ahl goto done; 1078 0 stevel } 1079 0 stevel 1080 0 stevel if (args->count == 0) { 1081 5599 jwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1082 0 stevel if (in_crit) 1083 0 stevel nbl_end_crit(vp); 1084 0 stevel resp->status = NFS3_OK; 1085 0 stevel vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1086 0 stevel resp->resok.count = 0; 1087 0 stevel resp->resok.eof = FALSE; 1088 0 stevel resp->resok.data.data_len = 0; 1089 0 stevel resp->resok.data.data_val = NULL; 1090 0 stevel resp->resok.data.mp = NULL; 1091 7387 Robert /* RDMA */ 1092 7387 Robert resp->resok.wlist = args->wlist; 1093 7387 Robert resp->resok.wlist_len = resp->resok.count; 1094 9348 Siddheshwar if (resp->resok.wlist) 1095 9348 Siddheshwar clist_zero_len(resp->resok.wlist); 1096 5982 ahl goto done; 1097 0 stevel } 1098 0 stevel 1099 0 stevel /* 1100 0 stevel * do not allocate memory more the max. allowed 1101 0 stevel * transfer size 1102 0 stevel */ 1103 0 stevel if (args->count > rfs3_tsize(req)) 1104 0 stevel args->count = rfs3_tsize(req); 1105 0 stevel 1106 0 stevel /* 1107 7387 Robert * If returning data via RDMA Write, then grab the chunk list. 1108 7387 Robert * If we aren't returning READ data w/RDMA_WRITE, then grab 1109 7387 Robert * a mblk. 1110 7387 Robert */ 1111 7387 Robert if (args->wlist) { 1112 7387 Robert mp = NULL; 1113 7387 Robert (void) rdma_get_wchunk(req, &iov, args->wlist); 1114 7387 Robert } else { 1115 7387 Robert /* 1116 7387 Robert * mp will contain the data to be sent out in the read reply. 1117 7387 Robert * This will be freed after the reply has been sent out (by the 1118 7387 Robert * driver). 1119 7387 Robert * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so 1120 7387 Robert * that the call to xdrmblk_putmblk() never fails. 1121 7387 Robert */ 1122 7387 Robert mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG, 1123 7387 Robert &alloc_err); 1124 7387 Robert ASSERT(mp != NULL); 1125 7387 Robert ASSERT(alloc_err == 0); 1126 7387 Robert 1127 7387 Robert iov.iov_base = (caddr_t)mp->b_datap->db_base; 1128 7387 Robert iov.iov_len = args->count; 1129 7387 Robert } 1130 7387 Robert 1131 0 stevel uio.uio_iov = &iov; 1132 0 stevel uio.uio_iovcnt = 1; 1133 0 stevel uio.uio_segflg = UIO_SYSSPACE; 1134 0 stevel uio.uio_extflg = UIO_COPY_CACHED; 1135 0 stevel uio.uio_loffset = args->offset; 1136 0 stevel uio.uio_resid = args->count; 1137 0 stevel 1138 5599 jwahlig error = VOP_READ(vp, &uio, 0, cr, &ct); 1139 0 stevel 1140 0 stevel if (error) { 1141 0 stevel freeb(mp); 1142 5599 jwahlig /* check if a monitor detected a delegation conflict */ 1143 5599 jwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1144 5599 jwahlig resp->status = NFS3ERR_JUKEBOX; 1145 5599 jwahlig goto out1; 1146 5599 jwahlig } 1147 5599 jwahlig goto out; 1148 5599 jwahlig } 1149 5599 jwahlig 1150 5599 jwahlig va.va_mask = AT_ALL; 1151 5599 jwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 1152 0 stevel 1153 0 stevel #ifdef DEBUG 1154 0 stevel if (rfs3_do_post_op_attr) { 1155 0 stevel if (error) 1156 0 stevel vap = NULL; 1157 0 stevel else 1158 0 stevel vap = &va; 1159 0 stevel } else 1160 0 stevel vap = NULL; 1161 0 stevel #else 1162 0 stevel if (error) 1163 0 stevel vap = NULL; 1164 0 stevel else 1165 0 stevel vap = &va; 1166 0 stevel #endif 1167 0 stevel 1168 5599 jwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1169 0 stevel 1170 0 stevel if (in_crit) 1171 0 stevel nbl_end_crit(vp); 1172 0 stevel 1173 0 stevel resp->status = NFS3_OK; 1174 0 stevel vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1175 0 stevel resp->resok.count = args->count - uio.uio_resid; 1176 0 stevel if (!error && offset + resp->resok.count == va.va_size) 1177 0 stevel resp->resok.eof = TRUE; 1178 0 stevel else 1179 0 stevel resp->resok.eof = FALSE; 1180 0 stevel resp->resok.data.data_len = resp->resok.count; 1181 0 stevel resp->resok.data.mp = mp; 1182 0 stevel resp->resok.size = (uint_t)args->count; 1183 7387 Robert 1184 7387 Robert if (args->wlist) { 1185 7387 Robert resp->resok.data.data_val = (caddr_t)iov.iov_base; 1186 7387 Robert if (!rdma_setup_read_data3(args, &(resp->resok))) { 1187 7387 Robert resp->status = NFS3ERR_INVAL; 1188 7387 Robert } 1189 7387 Robert } else { 1190 7387 Robert resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base; 1191 7387 Robert (resp->resok).wlist = NULL; 1192 7387 Robert } 1193 5982 ahl 1194 5982 ahl done: 1195 5982 ahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1196 5982 ahl cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1197 5982 ahl 1198 5982 ahl VN_RELE(vp); 1199 5982 ahl 1200 5982 ahl return; 1201 5982 ahl 1202 5982 ahl out: 1203 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 1204 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 1205 5982 ahl resp->status = NFS3ERR_JUKEBOX; 1206 5982 ahl } else 1207 5982 ahl resp->status = puterrno3(error); 1208 5982 ahl out1: 1209 5982 ahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1210 5982 ahl cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1211 5982 ahl 1212 0 stevel if (vp != NULL) { 1213 0 stevel if (need_rwunlock) 1214 5599 jwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1215 0 stevel if (in_crit) 1216 0 stevel nbl_end_crit(vp); 1217 0 stevel VN_RELE(vp); 1218 0 stevel } 1219 0 stevel vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 1220 0 stevel } 1221 0 stevel 1222 0 stevel void 1223 0 stevel rfs3_read_free(READ3res *resp) 1224 0 stevel { 1225 0 stevel mblk_t *mp; 1226 0 stevel 1227 0 stevel if (resp->status == NFS3_OK) { 1228 0 stevel mp = resp->resok.data.mp; 1229 0 stevel if (mp != NULL) 1230 0 stevel freeb(mp); 1231 0 stevel } 1232 0 stevel } 1233 0 stevel 1234 1610 thurlow void * 1235 0 stevel rfs3_read_getfh(READ3args *args) 1236 0 stevel { 1237 0 stevel 1238 1610 thurlow return (&args->file); 1239 0 stevel } 1240 0 stevel 1241 0 stevel #define MAX_IOVECS 12 1242 0 stevel 1243 0 stevel #ifdef DEBUG 1244 0 stevel static int rfs3_write_hits = 0; 1245 0 stevel static int rfs3_write_misses = 0; 1246 0 stevel #endif 1247 0 stevel 1248 0 stevel void 1249 0 stevel rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi, 1250 0 stevel struct svc_req *req, cred_t *cr) 1251 0 stevel { 1252 0 stevel int error; 1253 0 stevel vnode_t *vp; 1254 0 stevel struct vattr *bvap = NULL; 1255 0 stevel struct vattr bva; 1256 0 stevel struct vattr *avap = NULL; 1257 0 stevel struct vattr ava; 1258 0 stevel u_offset_t rlimit; 1259 0 stevel struct uio uio; 1260 0 stevel struct iovec iov[MAX_IOVECS]; 1261 0 stevel mblk_t *m; 1262 0 stevel struct iovec *iovp; 1263 0 stevel int iovcnt; 1264 0 stevel int ioflag; 1265 0 stevel cred_t *savecred; 1266 0 stevel int in_crit = 0; 1267 0 stevel int rwlock_ret = -1; 1268 5599 jwahlig caller_context_t ct; 1269 0 stevel 1270 0 stevel vp = nfs3_fhtovp(&args->file, exi); 1271 5982 ahl 1272 5982 ahl DTRACE_NFSV3_4(op__write__start, struct svc_req *, req, 1273 5982 ahl cred_t *, cr, vnode_t *, vp, WRITE3args *, args); 1274 5982 ahl 1275 5982 ahl if (vp == NULL) { 1276 5982 ahl error = ESTALE; 1277 5982 ahl goto err; 1278 0 stevel } 1279 0 stevel 1280 4971 jarrett if (is_system_labeled()) { 1281 4971 jarrett bslabel_t *clabel = req->rq_label; 1282 4971 jarrett 1283 4971 jarrett ASSERT(clabel != NULL); 1284 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *, 1285 4971 jarrett "got client label from request(1)", struct svc_req *, req); 1286 4971 jarrett 1287 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1288 9871 Jarrett if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 1289 9871 Jarrett exi)) { 1290 4971 jarrett resp->status = NFS3ERR_ACCES; 1291 5982 ahl goto err1; 1292 4971 jarrett } 1293 4971 jarrett } 1294 4971 jarrett } 1295 4971 jarrett 1296 5599 jwahlig ct.cc_sysid = 0; 1297 5599 jwahlig ct.cc_pid = 0; 1298 5599 jwahlig ct.cc_caller_id = nfs3_srv_caller_id; 1299 5599 jwahlig ct.cc_flags = CC_DONTBLOCK; 1300 0 stevel 1301 0 stevel /* 1302 0 stevel * We have to enter the critical region before calling VOP_RWLOCK 1303 0 stevel * to avoid a deadlock with ufs. 1304 0 stevel */ 1305 0 stevel if (nbl_need_check(vp)) { 1306 0 stevel nbl_start_crit(vp, RW_READER); 1307 0 stevel in_crit = 1; 1308 5331 amw if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0, 1309 5331 amw NULL)) { 1310 0 stevel error = EACCES; 1311 5982 ahl goto err; 1312 0 stevel } 1313 0 stevel } 1314 0 stevel 1315 5599 jwahlig rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct); 1316 5599 jwahlig 1317 5599 jwahlig /* check if a monitor detected a delegation conflict */ 1318 5599 jwahlig if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1319 5599 jwahlig resp->status = NFS3ERR_JUKEBOX; 1320 5599 jwahlig rwlock_ret = -1; 1321 5982 ahl goto err1; 1322 5599 jwahlig } 1323 5599 jwahlig 1324 5599 jwahlig 1325 5599 jwahlig bva.va_mask = AT_ALL; 1326 5599 jwahlig error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 1327 0 stevel 1328 0 stevel /* 1329 0 stevel * If we can't get the attributes, then we can't do the 1330 0 stevel * right access checking. So, we'll fail the request. 1331 0 stevel */ 1332 0 stevel if (error) 1333 5982 ahl goto err; 1334 0 stevel 1335 0 stevel bvap = &bva; 1336 0 stevel #ifdef DEBUG 1337 0 stevel if (!rfs3_do_pre_op_attr) 1338 0 stevel bvap = NULL; 1339 0 stevel #endif 1340 0 stevel avap = bvap; 1341 0 stevel 1342 0 stevel if (args->count != args->data.data_len) { 1343 0 stevel resp->status = NFS3ERR_INVAL; 1344 5982 ahl goto err1; 1345 5982 ahl } 1346 5982 ahl 1347 5982 ahl if (rdonly(exi, req)) { 1348 5982 ahl resp->status = NFS3ERR_ROFS; 1349 5982 ahl goto err1; 1350 0 stevel } 1351 0 stevel 1352 0 stevel if (vp->v_type != VREG) { 1353 0 stevel resp->status = NFS3ERR_INVAL; 1354 5982 ahl goto err1; 1355 0 stevel } 1356 0 stevel 1357 0 stevel if (crgetuid(cr) != bva.va_uid && 1358 5599 jwahlig (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) 1359 5982 ahl goto err; 1360 0 stevel 1361 0 stevel if (MANDLOCK(vp, bva.va_mode)) { 1362 0 stevel resp->status = NFS3ERR_ACCES; 1363 5982 ahl goto err1; 1364 0 stevel } 1365 0 stevel 1366 0 stevel if (args->count == 0) { 1367 0 stevel resp->status = NFS3_OK; 1368 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1369 0 stevel resp->resok.count = 0; 1370 0 stevel resp->resok.committed = args->stable; 1371 0 stevel resp->resok.verf = write3verf; 1372 5982 ahl goto out; 1373 0 stevel } 1374 0 stevel 1375 0 stevel if (args->mblk != NULL) { 1376 0 stevel iovcnt = 0; 1377 0 stevel for (m = args->mblk; m != NULL; m = m->b_cont) 1378 0 stevel iovcnt++; 1379 0 stevel if (iovcnt <= MAX_IOVECS) { 1380 0 stevel #ifdef DEBUG 1381 0 stevel rfs3_write_hits++; 1382 0 stevel #endif 1383 0 stevel iovp = iov; 1384 0 stevel } else { 1385 0 stevel #ifdef DEBUG 1386 0 stevel rfs3_write_misses++; 1387 0 stevel #endif 1388 0 stevel iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 1389 0 stevel } 1390 0 stevel mblk_to_iov(args->mblk, iovcnt, iovp); 1391 7387 Robert 1392 7387 Robert } else if (args->rlist != NULL) { 1393 7387 Robert iovcnt = 1; 1394 7387 Robert iovp = iov; 1395 7387 Robert iovp->iov_base = (char *)((args->rlist)->u.c_daddr3); 1396 7387 Robert iovp->iov_len = args->count; 1397 0 stevel } else { 1398 0 stevel iovcnt = 1; 1399 0 stevel iovp = iov; 1400 0 stevel iovp->iov_base = args->data.data_val; 1401 0 stevel iovp->iov_len = args->count; 1402 0 stevel } 1403 0 stevel 1404 0 stevel uio.uio_iov = iovp; 1405 0 stevel uio.uio_iovcnt = iovcnt; 1406 0 stevel 1407 0 stevel uio.uio_segflg = UIO_SYSSPACE; 1408 0 stevel uio.uio_extflg = UIO_COPY_DEFAULT; 1409 0 stevel uio.uio_loffset = args->offset; 1410 0 stevel uio.uio_resid = args->count; 1411 0 stevel uio.uio_llimit = curproc->p_fsz_ctl; 1412 0 stevel rlimit = uio.uio_llimit - args->offset; 1413 0 stevel if (rlimit < (u_offset_t)uio.uio_resid) 1414 0 stevel uio.uio_resid = (int)rlimit; 1415 0 stevel 1416 0 stevel if (args->stable == UNSTABLE) 1417 0 stevel ioflag = 0; 1418 0 stevel else if (args->stable == FILE_SYNC) 1419 0 stevel ioflag = FSYNC; 1420 0 stevel else if (args->stable == DATA_SYNC) 1421 0 stevel ioflag = FDSYNC; 1422 0 stevel else { 1423 0 stevel if (iovp != iov) 1424 0 stevel kmem_free(iovp, sizeof (*iovp) * iovcnt); 1425 0 stevel resp->status = NFS3ERR_INVAL; 1426 5982 ahl goto err1; 1427 0 stevel } 1428 0 stevel 1429 0 stevel /* 1430 0 stevel * We're changing creds because VM may fault and we need 1431 0 stevel * the cred of the current thread to be used if quota 1432 0 stevel * checking is enabled. 1433 0 stevel */ 1434 0 stevel savecred = curthread->t_cred; 1435 0 stevel curthread->t_cred = cr; 1436 5599 jwahlig error = VOP_WRITE(vp, &uio, ioflag, cr, &ct); 1437 0 stevel curthread->t_cred = savecred; 1438 0 stevel 1439 0 stevel if (iovp != iov) 1440 0 stevel kmem_free(iovp, sizeof (*iovp) * iovcnt); 1441 0 stevel 1442 5599 jwahlig /* check if a monitor detected a delegation conflict */ 1443 5599 jwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1444 5599 jwahlig resp->status = NFS3ERR_JUKEBOX; 1445 5982 ahl goto err1; 1446 5599 jwahlig } 1447 5599 jwahlig 1448 5599 jwahlig ava.va_mask = AT_ALL; 1449 5599 jwahlig avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava; 1450 0 stevel 1451 0 stevel #ifdef DEBUG 1452 0 stevel if (!rfs3_do_post_op_attr) 1453 0 stevel avap = NULL; 1454 0 stevel #endif 1455 0 stevel 1456 0 stevel if (error) 1457 5982 ahl goto err; 1458 0 stevel 1459 0 stevel /* 1460 0 stevel * If we were unable to get the V_WRITELOCK_TRUE, then we 1461 0 stevel * may not have accurate after attrs, so check if 1462 0 stevel * we have both attributes, they have a non-zero va_seq, and 1463 0 stevel * va_seq has changed by exactly one, 1464 0 stevel * if not, turn off the before attr. 1465 0 stevel */ 1466 0 stevel if (rwlock_ret != V_WRITELOCK_TRUE) { 1467 0 stevel if (bvap == NULL || avap == NULL || 1468 5599 jwahlig bvap->va_seq == 0 || avap->va_seq == 0 || 1469 5599 jwahlig avap->va_seq != (bvap->va_seq + 1)) { 1470 0 stevel bvap = NULL; 1471 0 stevel } 1472 0 stevel } 1473 0 stevel 1474 0 stevel resp->status = NFS3_OK; 1475 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1476 0 stevel resp->resok.count = args->count - uio.uio_resid; 1477 0 stevel resp->resok.committed = args->stable; 1478 0 stevel resp->resok.verf = write3verf; 1479 5982 ahl goto out; 1480 5982 ahl 1481 5982 ahl err: 1482 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 1483 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 1484 5982 ahl resp->status = NFS3ERR_JUKEBOX; 1485 5982 ahl } else 1486 5982 ahl resp->status = puterrno3(error); 1487 5982 ahl err1: 1488 5982 ahl vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 1489 5982 ahl out: 1490 5982 ahl DTRACE_NFSV3_4(op__write__done, struct svc_req *, req, 1491 5982 ahl cred_t *, cr, vnode_t *, vp, WRITE3res *, resp); 1492 5982 ahl 1493 0 stevel if (vp != NULL) { 1494 0 stevel if (rwlock_ret != -1) 1495 5599 jwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); 1496 0 stevel if (in_crit) 1497 0 stevel nbl_end_crit(vp); 1498 0 stevel VN_RELE(vp); 1499 0 stevel } 1500 0 stevel } 1501 0 stevel 1502 1610 thurlow void * 1503 0 stevel rfs3_write_getfh(WRITE3args *args) 1504 0 stevel { 1505 0 stevel 1506 1610 thurlow return (&args->file); 1507 0 stevel } 1508 0 stevel 1509 0 stevel void 1510 0 stevel rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi, 1511 0 stevel struct svc_req *req, cred_t *cr) 1512 0 stevel { 1513 0 stevel int error; 1514 0 stevel int in_crit = 0; 1515 0 stevel vnode_t *vp; 1516 0 stevel vnode_t *tvp = NULL; 1517 0 stevel vnode_t *dvp; 1518 0 stevel struct vattr *vap; 1519 0 stevel struct vattr va; 1520 0 stevel struct vattr *dbvap; 1521 0 stevel struct vattr dbva; 1522 0 stevel struct vattr *davap; 1523 0 stevel struct vattr dava; 1524 0 stevel enum vcexcl excl; 1525 0 stevel nfstime3 *mtime; 1526 0 stevel len_t reqsize; 1527 0 stevel bool_t trunc; 1528 7961 Natalie struct sockaddr *ca; 1529 7961 Natalie char *name = NULL; 1530 0 stevel 1531 0 stevel dbvap = NULL; 1532 0 stevel davap = NULL; 1533 0 stevel 1534 1610 thurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 1535 5982 ahl 1536 5982 ahl DTRACE_NFSV3_4(op__create__start, struct svc_req *, req, 1537 5982 ahl cred_t *, cr, vnode_t *, dvp, CREATE3args *, args); 1538 5982 ahl 1539 0 stevel if (dvp == NULL) { 1540 0 stevel error = ESTALE; 1541 0 stevel goto out; 1542 0 stevel } 1543 0 stevel 1544 0 stevel #ifdef DEBUG 1545 0 stevel if (rfs3_do_pre_op_attr) { 1546 0 stevel dbva.va_mask = AT_ALL; 1547 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1548 0 stevel } else 1549 0 stevel dbvap = NULL; 1550 0 stevel #else 1551 0 stevel dbva.va_mask = AT_ALL; 1552 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1553 0 stevel #endif 1554 0 stevel davap = dbvap; 1555 0 stevel 1556 0 stevel if (args->where.name == nfs3nametoolong) { 1557 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 1558 0 stevel goto out1; 1559 0 stevel } 1560 0 stevel 1561 0 stevel if (args->where.name == NULL || *(args->where.name) == '\0') { 1562 0 stevel resp->status = NFS3ERR_ACCES; 1563 0 stevel goto out1; 1564 0 stevel } 1565 0 stevel 1566 0 stevel if (rdonly(exi, req)) { 1567 0 stevel resp->status = NFS3ERR_ROFS; 1568 0 stevel goto out1; 1569 4971 jarrett } 1570 4971 jarrett 1571 4971 jarrett if (is_system_labeled()) { 1572 4971 jarrett bslabel_t *clabel = req->rq_label; 1573 4971 jarrett 1574 4971 jarrett ASSERT(clabel != NULL); 1575 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *, 1576 4971 jarrett "got client label from request(1)", struct svc_req *, req); 1577 4971 jarrett 1578 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1579 9871 Jarrett if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 1580 9871 Jarrett exi)) { 1581 4971 jarrett resp->status = NFS3ERR_ACCES; 1582 4971 jarrett goto out1; 1583 4971 jarrett } 1584 4971 jarrett } 1585 7961 Natalie } 1586 7961 Natalie 1587 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1588 7961 Natalie name = nfscmd_convname(ca, exi, args->where.name, 1589 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1590 7961 Natalie 1591 7961 Natalie if (name == NULL) { 1592 7961 Natalie /* This is really a Solaris EILSEQ */ 1593 7961 Natalie resp->status = NFS3ERR_INVAL; 1594 7961 Natalie goto out1; 1595 0 stevel } 1596 0 stevel 1597 0 stevel if (args->how.mode == EXCLUSIVE) { 1598 0 stevel va.va_mask = AT_TYPE | AT_MODE | AT_MTIME; 1599 0 stevel va.va_type = VREG; 1600 0 stevel va.va_mode = (mode_t)0; 1601 0 stevel /* 1602 0 stevel * Ensure no time overflows and that types match 1603 0 stevel */ 1604 0 stevel mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1605 0 stevel va.va_mtime.tv_sec = mtime->seconds % INT32_MAX; 1606 0 stevel va.va_mtime.tv_nsec = mtime->nseconds; 1607 0 stevel excl = EXCL; 1608 0 stevel } else { 1609 0 stevel error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes, 1610 0 stevel &va); 1611 0 stevel if (error) 1612 0 stevel goto out; 1613 0 stevel va.va_mask |= AT_TYPE; 1614 0 stevel va.va_type = VREG; 1615 0 stevel if (args->how.mode == GUARDED) 1616 0 stevel excl = EXCL; 1617 0 stevel else { 1618 0 stevel excl = NONEXCL; 1619 0 stevel 1620 0 stevel /* 1621 0 stevel * During creation of file in non-exclusive mode 1622 0 stevel * if size of file is being set then make sure 1623 0 stevel * that if the file already exists that no conflicting 1624 0 stevel * non-blocking mandatory locks exists in the region 1625 0 stevel * being modified. If there are conflicting locks fail 1626 0 stevel * the operation with EACCES. 1627 0 stevel */ 1628 0 stevel if (va.va_mask & AT_SIZE) { 1629 0 stevel struct vattr tva; 1630 0 stevel 1631 0 stevel /* 1632 0 stevel * Does file already exist? 1633 0 stevel */ 1634 7961 Natalie error = VOP_LOOKUP(dvp, name, &tvp, 1635 5599 jwahlig NULL, 0, NULL, cr, NULL, NULL, NULL); 1636 0 stevel 1637 0 stevel /* 1638 0 stevel * Check to see if the file has been delegated 1639 0 stevel * to a v4 client. If so, then begin recall of 1640 0 stevel * the delegation and return JUKEBOX to allow 1641 0 stevel * the client to retrasmit its request. 1642 0 stevel */ 1643 0 stevel 1644 0 stevel trunc = va.va_size == 0; 1645 0 stevel if (!error && 1646 0 stevel rfs4_check_delegated(FWRITE, tvp, trunc)) { 1647 0 stevel resp->status = NFS3ERR_JUKEBOX; 1648 0 stevel goto out1; 1649 0 stevel } 1650 0 stevel 1651 0 stevel /* 1652 0 stevel * Check for NBMAND lock conflicts 1653 0 stevel */ 1654 0 stevel if (!error && nbl_need_check(tvp)) { 1655 0 stevel u_offset_t offset; 1656 0 stevel ssize_t len; 1657 0 stevel 1658 0 stevel nbl_start_crit(tvp, RW_READER); 1659 0 stevel in_crit = 1; 1660 0 stevel 1661 0 stevel tva.va_mask = AT_SIZE; 1662 5331 amw error = VOP_GETATTR(tvp, &tva, 0, cr, 1663 5599 jwahlig NULL); 1664 0 stevel /* 1665 0 stevel * Can't check for conflicts, so return 1666 0 stevel * error. 1667 0 stevel */ 1668 0 stevel if (error) 1669 0 stevel goto out; 1670 0 stevel 1671 0 stevel offset = tva.va_size < va.va_size ? 1672 5599 jwahlig tva.va_size : va.va_size; 1673 0 stevel len = tva.va_size < va.va_size ? 1674 5599 jwahlig va.va_size - tva.va_size : 1675 5599 jwahlig tva.va_size - va.va_size; 1676 0 stevel if (nbl_conflict(tvp, NBL_WRITE, 1677 5599 jwahlig offset, len, 0, NULL)) { 1678 0 stevel error = EACCES; 1679 0 stevel goto out; 1680 0 stevel } 1681 0 stevel } else if (tvp) { 1682 0 stevel VN_RELE(tvp); 1683 0 stevel tvp = NULL; 1684 0 stevel } 1685 0 stevel } 1686 0 stevel } 1687 0 stevel if (va.va_mask & AT_SIZE) 1688 0 stevel reqsize = va.va_size; 1689 0 stevel } 1690 0 stevel 1691 0 stevel /* 1692 0 stevel * Must specify the mode. 1693 0 stevel */ 1694 0 stevel if (!(va.va_mask & AT_MODE)) { 1695 0 stevel resp->status = NFS3ERR_INVAL; 1696 0 stevel goto out1; 1697 0 stevel } 1698 0 stevel 1699 0 stevel /* 1700 0 stevel * If the filesystem is exported with nosuid, then mask off 1701 0 stevel * the setuid and setgid bits. 1702 0 stevel */ 1703 0 stevel if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID)) 1704 0 stevel va.va_mode &= ~(VSUID | VSGID); 1705 0 stevel 1706 0 stevel tryagain: 1707 0 stevel /* 1708 0 stevel * The file open mode used is VWRITE. If the client needs 1709 0 stevel * some other semantic, then it should do the access checking 1710 0 stevel * itself. It would have been nice to have the file open mode 1711 0 stevel * passed as part of the arguments. 1712 0 stevel */ 1713 7961 Natalie error = VOP_CREATE(dvp, name, &va, excl, VWRITE, 1714 5331 amw &vp, cr, 0, NULL, NULL); 1715 0 stevel 1716 0 stevel #ifdef DEBUG 1717 0 stevel if (rfs3_do_post_op_attr) { 1718 0 stevel dava.va_mask = AT_ALL; 1719 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1720 0 stevel } else 1721 0 stevel davap = NULL; 1722 0 stevel #else 1723 0 stevel dava.va_mask = AT_ALL; 1724 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1725 0 stevel #endif 1726 0 stevel 1727 0 stevel if (error) { 1728 0 stevel /* 1729 0 stevel * If we got something other than file already exists 1730 0 stevel * then just return this error. Otherwise, we got 1731 0 stevel * EEXIST. If we were doing a GUARDED create, then 1732 0 stevel * just return this error. Otherwise, we need to 1733 0 stevel * make sure that this wasn't a duplicate of an 1734 0 stevel * exclusive create request. 1735 0 stevel * 1736 0 stevel * The assumption is made that a non-exclusive create 1737 0 stevel * request will never return EEXIST. 1738 0 stevel */ 1739 0 stevel if (error != EEXIST || args->how.mode == GUARDED) 1740 0 stevel goto out; 1741 0 stevel /* 1742 0 stevel * Lookup the file so that we can get a vnode for it. 1743 0 stevel */ 1744 7961 Natalie error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, 1745 5331 amw NULL, cr, NULL, NULL, NULL); 1746 0 stevel if (error) { 1747 0 stevel /* 1748 0 stevel * We couldn't find the file that we thought that 1749 0 stevel * we just created. So, we'll just try creating 1750 0 stevel * it again. 1751 0 stevel */ 1752 0 stevel if (error == ENOENT) 1753 0 stevel goto tryagain; 1754 0 stevel goto out; 1755 0 stevel } 1756 0 stevel 1757 0 stevel /* 1758 0 stevel * If the file is delegated to a v4 client, go ahead 1759 0 stevel * and initiate recall, this create is a hint that a 1760 0 stevel * conflicting v3 open has occurred. 1761 0 stevel */ 1762 0 stevel 1763 0 stevel if (rfs4_check_delegated(FWRITE, vp, FALSE)) { 1764 0 stevel VN_RELE(vp); 1765 0 stevel resp->status = NFS3ERR_JUKEBOX; 1766 0 stevel goto out1; 1767 0 stevel } 1768 0 stevel 1769 0 stevel va.va_mask = AT_ALL; 1770 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1771 0 stevel 1772 0 stevel mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1773 0 stevel /* % with INT32_MAX to prevent overflows */ 1774 0 stevel if (args->how.mode == EXCLUSIVE && (vap == NULL || 1775 0 stevel vap->va_mtime.tv_sec != 1776 0 stevel (mtime->seconds % INT32_MAX) || 1777 0 stevel vap->va_mtime.tv_nsec != mtime->nseconds)) { 1778 0 stevel VN_RELE(vp); 1779 0 stevel error = EEXIST; 1780 0 stevel goto out; 1781 0 stevel } 1782 0 stevel } else { 1783 0 stevel 1784 0 stevel if ((args->how.mode == UNCHECKED || 1785 0 stevel args->how.mode == GUARDED) && 1786 0 stevel args->how.createhow3_u.obj_attributes.size.set_it && 1787 0 stevel va.va_size == 0) 1788 0 stevel trunc = TRUE; 1789 0 stevel else 1790 0 stevel trunc = FALSE; 1791 0 stevel 1792 0 stevel if (rfs4_check_delegated(FWRITE, vp, trunc)) { 1793 0 stevel VN_RELE(vp); 1794 0 stevel resp->status = NFS3ERR_JUKEBOX; 1795 0 stevel goto out1; 1796 0 stevel } 1797 0 stevel 1798 0 stevel va.va_mask = AT_ALL; 1799 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1800 0 stevel 1801 0 stevel /* 1802 0 stevel * We need to check to make sure that the file got 1803 0 stevel * created to the indicated size. If not, we do a 1804 0 stevel * setattr to try to change the size, but we don't 1805 0 stevel * try too hard. This shouldn't a problem as most 1806 0 stevel * clients will only specifiy a size of zero which 1807 0 stevel * local file systems handle. However, even if 1808 0 stevel * the client does specify a non-zero size, it can 1809 0 stevel * still recover by checking the size of the file 1810 0 stevel * after it has created it and then issue a setattr 1811 0 stevel * request of its own to set the size of the file. 1812 0 stevel */ 1813 0 stevel if (vap != NULL && 1814 0 stevel (args->how.mode == UNCHECKED || 1815 0 stevel args->how.mode == GUARDED) && 1816 0 stevel args->how.createhow3_u.obj_attributes.size.set_it && 1817 0 stevel vap->va_size != reqsize) { 1818 0 stevel va.va_mask = AT_SIZE; 1819 0 stevel va.va_size = reqsize; 1820 0 stevel (void) VOP_SETATTR(vp, &va, 0, cr, NULL); 1821 0 stevel va.va_mask = AT_ALL; 1822 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1823 0 stevel } 1824 0 stevel } 1825 0 stevel 1826 7961 Natalie if (name != args->where.name) 1827 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1828 7961 Natalie 1829 0 stevel #ifdef DEBUG 1830 0 stevel if (!rfs3_do_post_op_attr) 1831 0 stevel vap = NULL; 1832 0 stevel #endif 1833 0 stevel 1834 0 stevel #ifdef DEBUG 1835 0 stevel if (!rfs3_do_post_op_fh3) 1836 0 stevel resp->resok.obj.handle_follows = FALSE; 1837 0 stevel else { 1838 0 stevel #endif 1839 0 stevel error = makefh3(&resp->resok.obj.handle, vp, exi); 1840 0 stevel if (error) 1841 0 stevel resp->resok.obj.handle_follows = FALSE; 1842 0 stevel else 1843 0 stevel resp->resok.obj.handle_follows = TRUE; 1844 0 stevel #ifdef DEBUG 1845 0 stevel } 1846 0 stevel #endif 1847 0 stevel 1848 0 stevel /* 1849 0 stevel * Force modified data and metadata out to stable storage. 1850 0 stevel */ 1851 5331 amw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 1852 5331 amw (void) VOP_FSYNC(dvp, 0, cr, NULL); 1853 0 stevel 1854 0 stevel VN_RELE(vp); 1855 0 stevel if (tvp != NULL) { 1856 0 stevel if (in_crit) 1857 0 stevel nbl_end_crit(tvp); 1858 0 stevel VN_RELE(tvp); 1859 0 stevel } 1860 0 stevel 1861 0 stevel resp->status = NFS3_OK; 1862 0 stevel vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 1863 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1864 5982 ahl 1865 5982 ahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1866 5982 ahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1867 5982 ahl 1868 5982 ahl VN_RELE(dvp); 1869 5982 ahl return; 1870 5982 ahl 1871 5982 ahl out: 1872 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 1873 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 1874 5982 ahl resp->status = NFS3ERR_JUKEBOX; 1875 5982 ahl } else 1876 5982 ahl resp->status = puterrno3(error); 1877 5982 ahl out1: 1878 5982 ahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1879 5982 ahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1880 7961 Natalie 1881 7961 Natalie if (name != NULL && name != args->where.name) 1882 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1883 5982 ahl 1884 0 stevel if (tvp != NULL) { 1885 0 stevel if (in_crit) 1886 0 stevel nbl_end_crit(tvp); 1887 0 stevel VN_RELE(tvp); 1888 0 stevel } 1889 0 stevel if (dvp != NULL) 1890 0 stevel VN_RELE(dvp); 1891 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 1892 0 stevel } 1893 0 stevel 1894 1610 thurlow void * 1895 0 stevel rfs3_create_getfh(CREATE3args *args) 1896 0 stevel { 1897 0 stevel 1898 1610 thurlow return (&args->where.dir); 1899 0 stevel } 1900 0 stevel 1901 0 stevel void 1902 0 stevel rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi, 1903 0 stevel struct svc_req *req, cred_t *cr) 1904 0 stevel { 1905 0 stevel int error; 1906 0 stevel vnode_t *vp = NULL; 1907 0 stevel vnode_t *dvp; 1908 0 stevel struct vattr *vap; 1909 0 stevel struct vattr va; 1910 0 stevel struct vattr *dbvap; 1911 0 stevel struct vattr dbva; 1912 0 stevel struct vattr *davap; 1913 0 stevel struct vattr dava; 1914 7961 Natalie struct sockaddr *ca; 1915 7961 Natalie char *name = NULL; 1916 0 stevel 1917 0 stevel dbvap = NULL; 1918 0 stevel davap = NULL; 1919 0 stevel 1920 1610 thurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 1921 5982 ahl 1922 5982 ahl DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req, 1923 5982 ahl cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args); 1924 5982 ahl 1925 0 stevel if (dvp == NULL) { 1926 0 stevel error = ESTALE; 1927 0 stevel goto out; 1928 0 stevel } 1929 0 stevel 1930 0 stevel #ifdef DEBUG 1931 0 stevel if (rfs3_do_pre_op_attr) { 1932 0 stevel dbva.va_mask = AT_ALL; 1933 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1934 0 stevel } else 1935 0 stevel dbvap = NULL; 1936 0 stevel #else 1937 0 stevel dbva.va_mask = AT_ALL; 1938 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1939 0 stevel #endif 1940 0 stevel davap = dbvap; 1941 0 stevel 1942 0 stevel if (args->where.name == nfs3nametoolong) { 1943 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 1944 0 stevel goto out1; 1945 0 stevel } 1946 0 stevel 1947 0 stevel if (args->where.name == NULL || *(args->where.name) == '\0') { 1948 0 stevel resp->status = NFS3ERR_ACCES; 1949 0 stevel goto out1; 1950 0 stevel } 1951 0 stevel 1952 0 stevel if (rdonly(exi, req)) { 1953 0 stevel resp->status = NFS3ERR_ROFS; 1954 0 stevel goto out1; 1955 0 stevel } 1956 0 stevel 1957 4971 jarrett if (is_system_labeled()) { 1958 4971 jarrett bslabel_t *clabel = req->rq_label; 1959 4971 jarrett 1960 4971 jarrett ASSERT(clabel != NULL); 1961 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *, 1962 4971 jarrett "got client label from request(1)", struct svc_req *, req); 1963 4971 jarrett 1964 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1965 9871 Jarrett if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 1966 9871 Jarrett exi)) { 1967 4971 jarrett resp->status = NFS3ERR_ACCES; 1968 4971 jarrett goto out1; 1969 4971 jarrett } 1970 4971 jarrett } 1971 4971 jarrett } 1972 4971 jarrett 1973 0 stevel error = sattr3_to_vattr(&args->attributes, &va); 1974 0 stevel if (error) 1975 0 stevel goto out; 1976 0 stevel 1977 0 stevel if (!(va.va_mask & AT_MODE)) { 1978 0 stevel resp->status = NFS3ERR_INVAL; 1979 0 stevel goto out1; 1980 0 stevel } 1981 0 stevel 1982 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1983 7961 Natalie name = nfscmd_convname(ca, exi, args->where.name, 1984 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1985 7961 Natalie 1986 7961 Natalie if (name == NULL) { 1987 7961 Natalie resp->status = NFS3ERR_INVAL; 1988 7961 Natalie goto out1; 1989 7961 Natalie } 1990 7961 Natalie 1991 0 stevel va.va_mask |= AT_TYPE; 1992 0 stevel va.va_type = VDIR; 1993 0 stevel 1994 7961 Natalie error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL); 1995 7961 Natalie 1996 7961 Natalie if (name != args->where.name) 1997 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1998 0 stevel 1999 0 stevel #ifdef DEBUG 2000 0 stevel if (rfs3_do_post_op_attr) { 2001 0 stevel dava.va_mask = AT_ALL; 2002 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2003 0 stevel } else 2004 0 stevel davap = NULL; 2005 0 stevel #else 2006 0 stevel dava.va_mask = AT_ALL; 2007 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2008 5331 amw #endif 2009 5331 amw 2010 5331 amw /* 2011 5331 amw * Force modified data and metadata out to stable storage. 2012 5331 amw */ 2013 5331 amw (void) VOP_FSYNC(dvp, 0, cr, NULL); 2014 0 stevel 2015 0 stevel if (error) 2016 0 stevel goto out; 2017 0 stevel 2018 0 stevel #ifdef DEBUG 2019 0 stevel if (!rfs3_do_post_op_fh3) 2020 0 stevel resp->resok.obj.handle_follows = FALSE; 2021 0 stevel else { 2022 0 stevel #endif 2023 0 stevel error = makefh3(&resp->resok.obj.handle, vp, exi); 2024 0 stevel if (error) 2025 0 stevel resp->resok.obj.handle_follows = FALSE; 2026 0 stevel else 2027 0 stevel resp->resok.obj.handle_follows = TRUE; 2028 0 stevel #ifdef DEBUG 2029 0 stevel } 2030 0 stevel #endif 2031 0 stevel 2032 0 stevel #ifdef DEBUG 2033 0 stevel if (rfs3_do_post_op_attr) { 2034 0 stevel va.va_mask = AT_ALL; 2035 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2036 5331 amw } else 2037 5331 amw vap = NULL; 2038 5331 amw #else 2039 5331 amw va.va_mask = AT_ALL; 2040 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2041 5331 amw #endif 2042 5331 amw 2043 5331 amw /* 2044 5331 amw * Force modified data and metadata out to stable storage. 2045 5331 amw */ 2046 5331 amw (void) VOP_FSYNC(vp, 0, cr, NULL); 2047 0 stevel 2048 0 stevel VN_RELE(vp); 2049 0 stevel 2050 0 stevel resp->status = NFS3_OK; 2051 0 stevel vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2052 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2053 5982 ahl 2054 5982 ahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 2055 5982 ahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 2056 5982 ahl VN_RELE(dvp); 2057 5982 ahl 2058 5982 ahl return; 2059 5982 ahl 2060 5982 ahl out: 2061 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 2062 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 2063 5982 ahl resp->status = NFS3ERR_JUKEBOX; 2064 5982 ahl } else 2065 5982 ahl resp->status = puterrno3(error); 2066 5982 ahl out1: 2067 5982 ahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 2068 5982 ahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 2069 0 stevel if (dvp != NULL) 2070 0 stevel VN_RELE(dvp); 2071 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2072 0 stevel } 2073 0 stevel 2074 1610 thurlow void * 2075 0 stevel rfs3_mkdir_getfh(MKDIR3args *args) 2076 0 stevel { 2077 0 stevel 2078 1610 thurlow return (&args->where.dir); 2079 0 stevel } 2080 0 stevel 2081 0 stevel void 2082 0 stevel rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi, 2083 0 stevel struct svc_req *req, cred_t *cr) 2084 0 stevel { 2085 0 stevel int error; 2086 0 stevel vnode_t *vp; 2087 0 stevel vnode_t *dvp; 2088 0 stevel struct vattr *vap; 2089 0 stevel struct vattr va; 2090 0 stevel struct vattr *dbvap; 2091 0 stevel struct vattr dbva; 2092 0 stevel struct vattr *davap; 2093 0 stevel struct vattr dava; 2094 7961 Natalie struct sockaddr *ca; 2095 7961 Natalie char *name = NULL; 2096 7961 Natalie char *symdata = NULL; 2097 0 stevel 2098 0 stevel dbvap = NULL; 2099 0 stevel davap = NULL; 2100 0 stevel 2101 1610 thurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 2102 5982 ahl 2103 5982 ahl DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req, 2104 5982 ahl cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args); 2105 5982 ahl 2106 5982 ahl if (dvp == NULL) { 2107 5982 ahl error = ESTALE; 2108 5982 ahl goto err; 2109 0 stevel } 2110 0 stevel 2111 0 stevel #ifdef DEBUG 2112 0 stevel if (rfs3_do_pre_op_attr) { 2113 0 stevel dbva.va_mask = AT_ALL; 2114 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2115 0 stevel } else 2116 0 stevel dbvap = NULL; 2117 0 stevel #else 2118 0 stevel dbva.va_mask = AT_ALL; 2119 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2120 0 stevel #endif 2121 0 stevel davap = dbvap; 2122 0 stevel 2123 0 stevel if (args->where.name == nfs3nametoolong) { 2124 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 2125 5982 ahl goto err1; 2126 0 stevel } 2127 0 stevel 2128 0 stevel if (args->where.name == NULL || *(args->where.name) == '\0') { 2129 0 stevel resp->status = NFS3ERR_ACCES; 2130 5982 ahl goto err1; 2131 5982 ahl } 2132 5982 ahl 2133 5982 ahl if (rdonly(exi, req)) { 2134 5982 ahl resp->status = NFS3ERR_ROFS; 2135 5982 ahl goto err1; 2136 4971 jarrett } 2137 4971 jarrett 2138 4971 jarrett if (is_system_labeled()) { 2139 4971 jarrett bslabel_t *clabel = req->rq_label; 2140 4971 jarrett 2141 4971 jarrett ASSERT(clabel != NULL); 2142 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *, 2143 4971 jarrett "got client label from request(1)", struct svc_req *, req); 2144 4971 jarrett 2145 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2146 9871 Jarrett if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 2147 9871 Jarrett exi)) { 2148 4971 jarrett resp->status = NFS3ERR_ACCES; 2149 5982 ahl goto err1; 2150 4971 jarrett } 2151 4971 jarrett } 2152 0 stevel } 2153 0 stevel 2154 0 stevel error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va); 2155 0 stevel if (error) 2156 5982 ahl goto err; 2157 0 stevel 2158 0 stevel if (!(va.va_mask & AT_MODE)) { 2159 0 stevel resp->status = NFS3ERR_INVAL; 2160 5982 ahl goto err1; 2161 0 stevel } 2162 0 stevel 2163 0 stevel if (args->symlink.symlink_data == nfs3nametoolong) { 2164 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 2165 5982 ahl goto err1; 2166 0 stevel } 2167 0 stevel 2168 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2169 7961 Natalie name = nfscmd_convname(ca, exi, args->where.name, 2170 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2171 7961 Natalie 2172 7961 Natalie if (name == NULL) { 2173 7961 Natalie /* This is really a Solaris EILSEQ */ 2174 7961 Natalie resp->status = NFS3ERR_INVAL; 2175 7961 Natalie goto err1; 2176 7961 Natalie } 2177 7961 Natalie 2178 7961 Natalie symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data, 2179 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2180 7961 Natalie if (symdata == NULL) { 2181 7961 Natalie /* This is really a Solaris EILSEQ */ 2182 7961 Natalie resp->status = NFS3ERR_INVAL; 2183 7961 Natalie goto err1; 2184 7961 Natalie } 2185 7961 Natalie 2186 7961 Natalie 2187 0 stevel va.va_mask |= AT_TYPE; 2188 0 stevel va.va_type = VLNK; 2189 0 stevel 2190 7961 Natalie error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0); 2191 0 stevel 2192 0 stevel #ifdef DEBUG 2193 0 stevel if (rfs3_do_post_op_attr) { 2194 0 stevel dava.va_mask = AT_ALL; 2195 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2196 0 stevel } else 2197 0 stevel davap = NULL; 2198 0 stevel #else 2199 0 stevel dava.va_mask = AT_ALL; 2200 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2201 5331 amw #endif 2202 5331 amw 2203 5331 amw if (error) 2204 5982 ahl goto err; 2205 5331 amw 2206 7961 Natalie error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr, 2207 5599 jwahlig NULL, NULL, NULL); 2208 5331 amw 2209 5331 amw /* 2210 5331 amw * Force modified data and metadata out to stable storage. 2211 5331 amw */ 2212 5331 amw (void) VOP_FSYNC(dvp, 0, cr, NULL); 2213 0 stevel 2214 0 stevel 2215 0 stevel resp->status = NFS3_OK; 2216 0 stevel if (error) { 2217 0 stevel resp->resok.obj.handle_follows = FALSE; 2218 0 stevel vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes); 2219 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2220 5982 ahl goto out; 2221 0 stevel } 2222 0 stevel 2223 0 stevel #ifdef DEBUG 2224 0 stevel if (!rfs3_do_post_op_fh3) 2225 0 stevel resp->resok.obj.handle_follows = FALSE; 2226 0 stevel else { 2227 0 stevel #endif 2228 0 stevel error = makefh3(&resp->resok.obj.handle, vp, exi); 2229 0 stevel if (error) 2230 0 stevel resp->resok.obj.handle_follows = FALSE; 2231 0 stevel else 2232 0 stevel resp->resok.obj.handle_follows = TRUE; 2233 0 stevel #ifdef DEBUG 2234 0 stevel } 2235 0 stevel #endif 2236 0 stevel 2237 0 stevel #ifdef DEBUG 2238 0 stevel if (rfs3_do_post_op_attr) { 2239 0 stevel va.va_mask = AT_ALL; 2240 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2241 5331 amw } else 2242 5331 amw vap = NULL; 2243 5331 amw #else 2244 5331 amw va.va_mask = AT_ALL; 2245 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2246 5331 amw #endif 2247 5331 amw 2248 5331 amw /* 2249 5331 amw * Force modified data and metadata out to stable storage. 2250 5331 amw */ 2251 5331 amw (void) VOP_FSYNC(vp, 0, cr, NULL); 2252 0 stevel 2253 0 stevel VN_RELE(vp); 2254 0 stevel 2255 0 stevel vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2256 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2257 5982 ahl goto out; 2258 5982 ahl 2259 5982 ahl err: 2260 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 2261 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 2262 5982 ahl resp->status = NFS3ERR_JUKEBOX; 2263 5982 ahl } else 2264 5982 ahl resp->status = puterrno3(error); 2265 5982 ahl err1: 2266 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2267 5982 ahl out: 2268 7961 Natalie if (name != NULL && name != args->where.name) 2269 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2270 7961 Natalie if (symdata != NULL && symdata != args->symlink.symlink_data) 2271 7961 Natalie kmem_free(symdata, MAXPATHLEN + 1); 2272 7961 Natalie 2273 5982 ahl DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req, 2274 5982 ahl cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp); 2275 5982 ahl 2276 5982 ahl if (dvp != NULL) 2277 5982 ahl VN_RELE(dvp); 2278 0 stevel } 2279 0 stevel 2280 1610 thurlow void * 2281 0 stevel rfs3_symlink_getfh(SYMLINK3args *args) 2282 0 stevel { 2283 0 stevel 2284 1610 thurlow return (&args->where.dir); 2285 0 stevel } 2286 0 stevel 2287 0 stevel void 2288 0 stevel rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi, 2289 0 stevel struct svc_req *req, cred_t *cr) 2290 0 stevel { 2291 0 stevel int error; 2292 0 stevel vnode_t *vp; 2293 6402 gt29601 vnode_t *realvp; 2294 0 stevel vnode_t *dvp; 2295 0 stevel struct vattr *vap; 2296 0 stevel struct vattr va; 2297 0 stevel struct vattr *dbvap; 2298 0 stevel struct vattr dbva; 2299 0 stevel struct vattr *davap; 2300 0 stevel struct vattr dava; 2301 0 stevel int mode; 2302 0 stevel enum vcexcl excl; 2303 7961 Natalie struct sockaddr *ca; 2304 7961 Natalie char *name = NULL; 2305 0 stevel 2306 0 stevel dbvap = NULL; 2307 0 stevel davap = NULL; 2308 0 stevel 2309 1610 thurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 2310 5982 ahl 2311 5982 ahl DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req, 2312 5982 ahl cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args); 2313 5982 ahl 2314 0 stevel if (dvp == NULL) { 2315 0 stevel error = ESTALE; 2316 0 stevel goto out; 2317 0 stevel } 2318 0 stevel 2319 0 stevel #ifdef DEBUG 2320 0 stevel if (rfs3_do_pre_op_attr) { 2321 0 stevel dbva.va_mask = AT_ALL; 2322 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2323 0 stevel } else 2324 0 stevel dbvap = NULL; 2325 0 stevel #else 2326 0 stevel dbva.va_mask = AT_ALL; 2327 5331 amw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2328 0 stevel #endif 2329 0 stevel davap = dbvap; 2330 0 stevel 2331 0 stevel if (args->where.name == nfs3nametoolong) { 2332 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 2333 0 stevel goto out1; 2334 0 stevel } 2335 0 stevel 2336 0 stevel if (args->where.name == NULL || *(args->where.name) == '\0') { 2337 0 stevel resp->status = NFS3ERR_ACCES; 2338 0 stevel goto out1; 2339 0 stevel } 2340 0 stevel 2341 0 stevel if (rdonly(exi, req)) { 2342 0 stevel resp->status = NFS3ERR_ROFS; 2343 0 stevel goto out1; 2344 4971 jarrett } 2345 4971 jarrett 2346 4971 jarrett if (is_system_labeled()) { 2347 4971 jarrett bslabel_t *clabel = req->rq_label; 2348 4971 jarrett 2349 4971 jarrett ASSERT(clabel != NULL); 2350 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *, 2351 4971 jarrett "got client label from request(1)", struct svc_req *, req); 2352 4971 jarrett 2353 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2354 9871 Jarrett if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 2355 9871 Jarrett exi)) { 2356 4971 jarrett resp->status = NFS3ERR_ACCES; 2357 4971 jarrett goto out1; 2358 4971 jarrett } 2359 4971 jarrett } 2360 0 stevel } 2361 0 stevel 2362 0 stevel switch (args->what.type) { 2363 0 stevel case NF3CHR: 2364 0 stevel case NF3BLK: 2365 0 stevel error = sattr3_to_vattr( 2366 0 stevel &args->what.mknoddata3_u.device.dev_attributes, &va); 2367 0 stevel if (error) 2368 0 stevel goto out; 2369 0 stevel if (secpolicy_sys_devices(cr) != 0) { 2370 0 stevel resp->status = NFS3ERR_PERM; 2371 0 stevel goto out1; 2372 0 stevel } 2373 0 stevel if (args->what.type == NF3CHR) 2374 0 stevel va.va_type = VCHR; 2375 0 stevel else 2376 0 stevel va.va_type = VBLK; 2377 0 stevel va.va_rdev = makedevice( 2378 0 stevel args->what.mknoddata3_u.device.spec.specdata1, 2379 0 stevel args->what.mknoddata3_u.device.spec.specdata2); 2380 0 stevel va.va_mask |= AT_TYPE | AT_RDEV; 2381 0 stevel break; 2382 0 stevel case NF3SOCK: 2383 0 stevel error = sattr3_to_vattr( 2384 0 stevel &args->what.mknoddata3_u.pipe_attributes, &va); 2385 0 stevel if (error) 2386 0 stevel goto out; 2387 0 stevel va.va_type = VSOCK; 2388 0 stevel va.va_mask |= AT_TYPE; 2389 0 stevel break; 2390 0 stevel case NF3FIFO: 2391 0 stevel error = sattr3_to_vattr( 2392 0 stevel &args->what.mknoddata3_u.pipe_attributes, &va); 2393 0 stevel if (error) 2394 0 stevel goto out; 2395 0 stevel va.va_type = VFIFO; 2396 0 stevel va.va_mask |= AT_TYPE; 2397 0 stevel break; 2398 0 stevel default: 2399 0 stevel resp->status = NFS3ERR_BADTYPE; 2400 0 stevel goto out1; 2401 0 stevel } 2402 0 stevel 2403 0 stevel /* 2404 0 stevel * Must specify the mode. 2405 0 stevel */ 2406 0 stevel if (!(va.va_mask & AT_MODE)) { 2407 0 stevel resp->status = NFS3ERR_INVAL; 2408 0 stevel goto out1; 2409 0 stevel } 2410 0 stevel 2411 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2412 7961 Natalie name = nfscmd_convname(ca, exi, args->where.name, 2413 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2414 7961 Natalie 2415 7961 Natalie if (name == NULL) { 2416 7961 Natalie resp->status = NFS3ERR_INVAL; 2417 7961 Natalie goto out1; 2418 7961 Natalie } 2419 7961 Natalie 2420 0 stevel excl = EXCL; 2421 0 stevel 2422 0 stevel mode = 0; 2423 0 stevel 2424 7961 Natalie error = VOP_CREATE(dvp, name, &va, excl, mode, 2425 5331 amw &vp, cr, 0, NULL, NULL); 2426 7961 Natalie 2427 7961 Natalie if (name != args->where.name) 2428 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2429 0 stevel 2430 0 stevel #ifdef DEBUG 2431 0 stevel if (rfs3_do_post_op_attr) { 2432 0 stevel dava.va_mask = AT_ALL; 2433 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2434 0 stevel } else 2435 0 stevel davap = NULL; 2436 0 stevel #else 2437 0 stevel dava.va_mask = AT_ALL; 2438 5331 amw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2439 5331 amw #endif 2440 5331 amw 2441 5331 amw /* 2442 5331 amw * Force modified data and metadata out to stable storage. 2443 5331 amw */ 2444 5331 amw (void) VOP_FSYNC(dvp, 0, cr, NULL); 2445 0 stevel 2446 0 stevel if (error) 2447 0 stevel goto out; 2448 0 stevel 2449 0 stevel resp->status = NFS3_OK; 2450 0 stevel 2451 0 stevel #ifdef DEBUG 2452 0 stevel if (!rfs3_do_post_op_fh3) 2453 0 stevel resp->resok.obj.handle_follows = FALSE; 2454 0 stevel else { 2455 0 stevel #endif 2456 0 stevel error = makefh3(&resp->resok.obj.handle, vp, exi); 2457 0 stevel if (error) 2458 0 stevel resp->resok.obj.handle_follows = FALSE; 2459 0 stevel else 2460 0 stevel resp->resok.obj.handle_follows = TRUE; 2461 0 stevel #ifdef DEBUG 2462 0 stevel } 2463 0 stevel #endif 2464 0 stevel 2465 0 stevel #ifdef DEBUG 2466 0 stevel if (rfs3_do_post_op_attr) { 2467 0 stevel va.va_mask = AT_ALL; 2468 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2469 5331 amw } else 2470 5331 amw vap = NULL; 2471 5331 amw #else 2472 5331 amw va.va_mask = AT_ALL; 2473 5331 amw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2474 5331 amw #endif 2475 5331 amw 2476 5331 amw /* 2477 5331 amw * Force modified metadata out to stable storage. 2478 6402 gt29601 * 2479 6402 gt29601 * if a underlying vp exists, pass it to VOP_FSYNC 2480 6402 gt29601 */ 2481 6402 gt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0) 2482 6402 gt29601 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL); 2483 6402 gt29601 else 2484 6402 gt29601 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 2485 0 stevel 2486 0 stevel VN_RELE(vp); 2487 0 stevel 2488 0 stevel vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2489 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2490 5982 ahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2491 5982 ahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 2492 5982 ahl VN_RELE(dvp); 2493 5982 ahl return; 2494 5982 ahl 2495 5982 ahl out: 2496 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 2497 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 2498 5982 ahl resp->status = NFS3ERR_JUKEBOX; 2499 5982 ahl } else 2500 5982 ahl resp->status = puterrno3(error); 2501 5982 ahl out1: 2502 5982 ahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2503 5982 ahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 2504 0 stevel if (dvp != NULL) 2505 0 stevel VN_RELE(dvp); 2506 0 stevel vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2507 0 stevel } 2508 0 stevel 2509 1610 thurlow void * 2510 0 stevel rfs3_mknod_getfh(MKNOD3args *args) 2511 0 stevel { 2512 0 stevel 2513 1610 thurlow return (&args->where.dir); 2514 0 stevel } 2515 0 stevel 2516 0 stevel void 2517 0 stevel rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi, 2518 0 stevel struct svc_req *req, cred_t *cr) 2519 0 stevel { 2520 0 stevel int error = 0; 2521 0 stevel vnode_t *vp; 2522 0 stevel struct vattr *bvap; 2523 0 stevel struct vattr bva; 2524 0 stevel struct vattr *avap; 2525 0 stevel struct vattr ava; 2526 0 stevel vnode_t *targvp = NULL; 2527 7961 Natalie struct sockaddr *ca; 2528 7961 Natalie char *name = NULL; 2529 0 stevel 2530 0 stevel bvap = NULL; 2531 0 stevel avap = NULL; 2532 0 stevel 2533 1610 thurlow vp = nfs3_fhtovp(&args->object.dir, exi); 2534 5982 ahl 2535 5982 ahl DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req, 2536 5982 ahl cred_t *, cr, vnode_t *, vp, REMOVE3args *, args); 2537 5982 ahl 2538 5982 ahl if (vp == NULL) { 2539 5982 ahl error = ESTALE; 2540 5982 ahl goto err; 2541 0 stevel } 2542 0 stevel 2543 0 stevel #ifdef DEBUG 2544 0 stevel if (rfs3_do_pre_op_attr) { 2545 0 stevel bva.va_mask = AT_ALL; 2546 5331 amw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2547 5331 amw } else 2548 5331 amw bvap = NULL; 2549 5331 amw #else 2550 5331 amw bva.va_mask = AT_ALL; 2551 5331 amw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2552 0 stevel #endif 2553 0 stevel avap = bvap; 2554 0 stevel 2555 0 stevel if (vp->v_type != VDIR) { 2556 0 stevel resp->status = NFS3ERR_NOTDIR; 2557 5982 ahl goto err1; 2558 0 stevel } 2559 0 stevel 2560 0 stevel if (args->object.name == nfs3nametoolong) { 2561 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 2562 5982 ahl goto err1; 2563 0 stevel } 2564 0 stevel 2565 0 stevel if (args->object.name == NULL || *(args->object.name) == '\0') { 2566 0 stevel resp->status = NFS3ERR_ACCES; 2567 5982 ahl goto err1; 2568 5982 ahl } 2569 5982 ahl 2570 5982 ahl if (rdonly(exi, req)) { 2571 5982 ahl resp->status = NFS3ERR_ROFS; 2572 5982 ahl goto err1; 2573 0 stevel } 2574 0 stevel 2575 4971 jarrett if (is_system_labeled()) { 2576 4971 jarrett bslabel_t *clabel = req->rq_label; 2577 4971 jarrett 2578 4971 jarrett ASSERT(clabel != NULL); 2579 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *, 2580 4971 jarrett "got client label from request(1)", struct svc_req *, req); 2581 4971 jarrett 2582 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2583 9871 Jarrett if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 2584 9871 Jarrett exi)) { 2585 4971 jarrett resp->status = NFS3ERR_ACCES; 2586 5982 ahl goto err1; 2587 4971 jarrett } 2588 4971 jarrett } 2589 4971 jarrett } 2590 4971 jarrett 2591 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2592 7961 Natalie name = nfscmd_convname(ca, exi, args->object.name, 2593 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2594 7961 Natalie 2595 7961 Natalie if (name == NULL) { 2596 7961 Natalie resp->status = NFS3ERR_INVAL; 2597 7961 Natalie goto err1; 2598 7961 Natalie } 2599 7961 Natalie 2600 0 stevel /* 2601 0 stevel * Check for a conflict with a non-blocking mandatory share 2602 0 stevel * reservation and V4 delegations 2603 0 stevel */ 2604 7961 Natalie error = VOP_LOOKUP(vp, name, &targvp, NULL, 0, 2605 5599 jwahlig NULL, cr, NULL, NULL, NULL); 2606 0 stevel if (error != 0) 2607 5982 ahl goto err; 2608 0 stevel 2609 0 stevel if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 2610 0 stevel resp->status = NFS3ERR_JUKEBOX; 2611 5982 ahl goto err1; 2612 0 stevel } 2613 0 stevel 2614 0 stevel if (!nbl_need_check(targvp)) { 2615 7961 Natalie error = VOP_REMOVE(vp, name, cr, NULL, 0); 2616 0 stevel } else { 2617 0 stevel nbl_start_crit(targvp, RW_READER); 2618 5331 amw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) { 2619 0 stevel error = EACCES; 2620 0 stevel } else { 2621 7961 Natalie error = VOP_REMOVE(vp, name, cr, NULL, 0); 2622 0 stevel } 2623 0 stevel nbl_end_crit(targvp); 2624 0 stevel } 2625 0 stevel VN_RELE(targvp); 2626 0 stevel targvp = NULL; 2627 0 stevel 2628 0 stevel #ifdef DEBUG 2629 0 stevel if (rfs3_do_post_op_attr) { 2630 0 stevel ava.va_mask = AT_ALL; 2631 5331 amw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2632 5331 amw } else 2633 5331 amw avap = NULL; 2634 5331 amw #else 2635 5331 amw ava.va_mask = AT_ALL; 2636 5331 amw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2637 5331 amw #endif 2638 5331 amw 2639 5331 amw /* 2640 5331 amw * Force modified data and metadata out to stable storage. 2641 5331 amw */ 2642 5331 amw (void) VOP_FSYNC(vp, 0, cr, NULL); 2643 0 stevel 2644 0 stevel if (error) 2645 5982 ahl goto err; 2646 0 stevel 2647 0 stevel resp->status = NFS3_OK; 2648 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2649 5982 ahl goto out; 2650 5982 ahl 2651 5982 ahl err: 2652 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 2653 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 2654 5982 ahl resp->status = NFS3ERR_JUKEBOX; 2655 5982 ahl } else 2656 5982 ahl resp->status = puterrno3(error); 2657 5982 ahl err1: 2658 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2659 5982 ahl out: 2660 5982 ahl DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req, 2661 5982 ahl cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp); 2662 7961 Natalie 2663 7961 Natalie if (name != NULL && name != args->object.name) 2664 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2665 7961 Natalie 2666 5982 ahl if (vp != NULL) 2667 5982 ahl VN_RELE(vp); 2668 0 stevel } 2669 0 stevel 2670 1610 thurlow void * 2671 0 stevel rfs3_remove_getfh(REMOVE3args *args) 2672 0 stevel { 2673 0 stevel 2674 1610 thurlow return (&args->object.dir); 2675 0 stevel } 2676 0 stevel 2677 0 stevel void 2678 0 stevel rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi, 2679 0 stevel struct svc_req *req, cred_t *cr) 2680 0 stevel { 2681 0 stevel int error; 2682 0 stevel vnode_t *vp; 2683 0 stevel struct vattr *bvap; 2684 0 stevel struct vattr bva; 2685 0 stevel struct vattr *avap; 2686 0 stevel struct vattr ava; 2687 7961 Natalie struct sockaddr *ca; 2688 7961 Natalie char *name = NULL; 2689 0 stevel 2690 0 stevel bvap = NULL; 2691 0 stevel avap = NULL; 2692 0 stevel 2693 1610 thurlow vp = nfs3_fhtovp(&args->object.dir, exi); 2694 5982 ahl 2695 5982 ahl DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req, 2696 5982 ahl cred_t *, cr, vnode_t *, vp, RMDIR3args *, args); 2697 5982 ahl 2698 5982 ahl if (vp == NULL) { 2699 5982 ahl error = ESTALE; 2700 5982 ahl goto err; 2701 0 stevel } 2702 0 stevel 2703 0 stevel #ifdef DEBUG 2704 0 stevel if (rfs3_do_pre_op_attr) { 2705 0 stevel bva.va_mask = AT_ALL; 2706 5331 amw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2707 5331 amw } else 2708 5331 amw bvap = NULL; 2709 5331 amw #else 2710 5331 amw bva.va_mask = AT_ALL; 2711 5331 amw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2712 0 stevel #endif 2713 0 stevel avap = bvap; 2714 0 stevel 2715 0 stevel if (vp->v_type != VDIR) { 2716 0 stevel resp->status = NFS3ERR_NOTDIR; 2717 5982 ahl goto err1; 2718 0 stevel } 2719 0 stevel 2720 0 stevel if (args->object.name == nfs3nametoolong) { 2721 0 stevel resp->status = NFS3ERR_NAMETOOLONG; 2722 5982 ahl goto err1; 2723 0 stevel } 2724 0 stevel 2725 0 stevel if (args->object.name == NULL || *(args->object.name) == '\0') { 2726 0 stevel resp->status = NFS3ERR_ACCES; 2727 5982 ahl goto err1; 2728 5982 ahl } 2729 5982 ahl 2730 5982 ahl if (rdonly(exi, req)) { 2731 5982 ahl resp->status = NFS3ERR_ROFS; 2732 5982 ahl goto err1; 2733 4971 jarrett } 2734 4971 jarrett 2735 4971 jarrett if (is_system_labeled()) { 2736 4971 jarrett bslabel_t *clabel = req->rq_label; 2737 4971 jarrett 2738 4971 jarrett ASSERT(clabel != NULL); 2739 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *, 2740 4971 jarrett "got client label from request(1)", struct svc_req *, req); 2741 4971 jarrett 2742 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2743 9871 Jarrett if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 2744 9871 Jarrett exi)) { 2745 4971 jarrett resp->status = NFS3ERR_ACCES; 2746 5982 ahl goto err1; 2747 4971 jarrett } 2748 4971 jarrett } 2749 0 stevel } 2750 0 stevel 2751 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2752 7961 Natalie name = nfscmd_convname(ca, exi, args->object.name, 2753 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2754 7961 Natalie 2755 7961 Natalie if (name == NULL) { 2756 7961 Natalie resp->status = NFS3ERR_INVAL; 2757 7961 Natalie goto err1; 2758 7961 Natalie } 2759 7961 Natalie 2760 7961 Natalie error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0); 2761 7961 Natalie 2762 7961 Natalie if (name != args->object.name) 2763 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2764 5331 amw 2765 5331 amw #ifdef DEBUG 2766 5331 amw if (rfs3_do_post_op_attr) { 2767 5331 amw ava.va_mask = AT_ALL; 2768 5331 amw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2769 5331 amw } else 2770 5331 amw avap = NULL; 2771 5331 amw #else 2772 5331 amw ava.va_mask = AT_ALL; 2773 5331 amw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2774 5331 amw #endif 2775 5331 amw 2776 5331 amw /* 2777 5331 amw * Force modified data and metadata out to stable storage. 2778 5331 amw */ 2779 5331 amw (void) VOP_FSYNC(vp, 0, cr, NULL); 2780 0 stevel 2781 0 stevel if (error) { 2782 0 stevel /* 2783 0 stevel * System V defines rmdir to return EEXIST, not ENOTEMPTY, 2784 0 stevel * if the directory is not empty. A System V NFS server 2785 0 stevel * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit 2786 0 stevel * over the wire. 2787 0 stevel */ 2788 0 stevel if (error == EEXIST) 2789 0 stevel error = ENOTEMPTY; 2790 5982 ahl goto err; 2791 5982 ahl } 2792 0 stevel 2793 0 stevel resp->status = NFS3_OK; 2794 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2795 5982 ahl goto out; 2796 5982 ahl 2797 5982 ahl err: 2798 5982 ahl if (curthread->t_flag & T_WOULDBLOCK) { 2799 5982 ahl curthread->t_flag &= ~T_WOULDBLOCK; 2800 5982 ahl resp->status = NFS3ERR_JUKEBOX; 2801 5982 ahl } else 2802 5982 ahl resp->status = puterrno3(error); 2803 5982 ahl err1: 2804 0 stevel vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2805 5982 ahl out: 2806 5982 ahl DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req, 2807 5982 ahl cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp); 2808 5982 ahl if (vp != NULL) 2809 5982 ahl VN_RELE(vp); 2810 5982 ahl 2811 0 stevel } 2812 0 stevel 2813 1610 thurlow void * 2814 0 stevel rfs3_rmdir_getfh(RMDIR3args *args) 2815 0 stevel { 2816 0 stevel 2817 1610 thurlow return (&args->object.dir); 2818 0 stevel } 2819 0 stevel 2820 0 stevel void 2821 0 stevel rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi, 2822 0 stevel struct svc_req *req, cred_t *cr) 2823 0 stevel { 2824 0 stevel int error = 0; 2825 0 stevel vnode_t *fvp; 2826 0 stevel vnode_t *tvp; 2827 0 stevel vnode_t *targvp; 2828 0 stevel struct vattr *fbvap; 2829 0 stevel struct vattr fbva; 2830 0 stevel struct vattr *favap; 2831 0 stevel struct vattr fava; 2832 0 stevel struct vattr *tbvap; 2833 0 stevel struct vattr tbva; 2834 0 stevel struct vattr *tavap; 2835 0 stevel struct vattr tava; 2836 1610 thurlow nfs_fh3 *fh3; 2837 0 stevel struct exportinfo *to_exi; 2838 0 stevel vnode_t *srcvp = NULL; 2839 4971 jarrett bslabel_t *clabel; 2840 7961 Natalie struct sockaddr *ca; 2841 7961 Natalie char *name = NULL; 2842 7961 Natalie char *toname = NULL; 2843 0 stevel 2844 0 stevel fbvap = NULL; 2845 0 stevel favap = NULL; 2846 0 stevel tbvap = NULL; 2847 0 stevel tavap = NULL; 2848 0 stevel tvp = NULL; 2849 0 stevel 2850 1610 thurlow fvp = nfs3_fhtovp(&args->from.dir, exi); 2851 5982 ahl 2852 5982 ahl DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req, 2853 5982 ahl cred_t *, cr, vnode_t *, fvp, RENAME3args *, args); 2854 5982 ahl 2855 0 stevel if (fvp == NULL) { 2856 0 stevel error = ESTALE; 2857 5982 ahl goto err; 2858 0 stevel } 2859 0 stevel 2860 4971 jarrett if (is_system_labeled()) { 2861 4971 jarrett clabel = req->rq_label; 2862 4971 jarrett ASSERT(clabel != NULL); 2863 4971 jarrett DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *, 2864 4971 jarrett "got client label from request(1)", struct svc_req *, req); 2865 4971 jarrett 2866 4971 jarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2867 9871 Jarrett if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK, 2868 9871 Jarrett exi)) { 2869 4971 jarrett resp->status = NFS3ERR_ACCES; 2870 5982 ahl goto err1; 2871 4971 jarrett } 2872 4971 jarrett } 2873 4971 jarrett } 2874 4971 jarrett 2875 0 stevel #ifdef DEBUG 2876 0 stevel if (rfs3_do_pre_op_attr) { 2877 0 stevel fbva.va_mask = AT_ALL; 2878 5331 amw fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva; 2879 0 stevel } else 2880 0 stevel fbvap = NULL; 2881 0 stevel #else 2882 0 stevel fbva.va_mask = AT_ALL; 2883 5331 amw fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva; 2884 0 stevel #endif 2885 0 stevel favap = fbvap; 2886 0 stevel 2887 1610 thurlow fh3 = &args->to.dir; 2888 1610 thurlow to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); 2889 0 stevel if (to_exi == NULL) { 2890 0 stevel resp->status = NFS3ERR_ACCES; 2891 5982 ahl goto err1; 2892 0 stevel } 2893 0 stevel exi_rele(to_exi); 2894 0 stevel 2895 0 stevel if (to_exi != exi) { 2896 0 stevel resp->status = NFS3ERR_XDEV; 2897 5982 ahl goto err1; 2898 0 stevel } 2899 0 stevel 2900 1610 thurlow tvp = nfs3_fhtovp(&args->to.dir, exi); 2901 0 stevel if (tvp == NULL) { 2902 0 stevel error = ESTALE; 2903 5982 ahl goto err; 2904 0 stevel } 2905 0 stevel 2906 0 stevel #ifdef DEBUG 2907 0 stevel if (rfs3_do_pre_op_attr) { 2908 0 stevel tbva.va_mask = AT_ALL; 2909 5331