1 /*- 2 * Copyright (c) 2009 Rick Macklem, University of Guelph 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 /* 32 * These functions implement the client side state handling for NFSv4. 33 * NFSv4 state handling: 34 * - A lockowner is used to determine lock contention, so it 35 * corresponds directly to a Posix pid. (1 to 1 mapping) 36 * - The correct granularity of an OpenOwner is not nearly so 37 * obvious. An OpenOwner does the following: 38 * - provides a serial sequencing of Open/Close/Lock-with-new-lockowner 39 * - is used to check for Open/Share contention (not applicable to 40 * this client, since all Opens are Deny_None) 41 * As such, I considered both extreme. 42 * 1 OpenOwner per ClientID - Simple to manage, but fully serializes 43 * all Open, Close and Lock (with a new lockowner) Ops. 44 * 1 OpenOwner for each Open - This one results in an OpenConfirm for 45 * every Open, for most servers. 46 * So, I chose to use the same mapping as I did for LockOwnwers. 47 * The main concern here is that you can end up with multiple Opens 48 * for the same File Handle, but on different OpenOwners (opens 49 * inherited from parents, grandparents...) and you do not know 50 * which of these the vnodeop close applies to. This is handled by 51 * delaying the Close Op(s) until all of the Opens have been closed. 52 * (It is not yet obvious if this is the correct granularity.) 53 * - How the code handles serialization: 54 * - For the ClientId, it uses an exclusive lock while getting its 55 * SetClientId and during recovery. Otherwise, it uses a shared 56 * lock via a reference count. 57 * - For the rest of the data structures, it uses an SMP mutex 58 * (once the nfs client is SMP safe) and doesn't sleep while 59 * manipulating the linked lists. 60 * - The serialization of Open/Close/Lock/LockU falls out in the 61 * "wash", since OpenOwners and LockOwners are both mapped from 62 * Posix pid. In other words, there is only one Posix pid using 63 * any given owner, so that owner is serialized. (If you change 64 * the granularity of the OpenOwner, then code must be added to 65 * serialize Ops on the OpenOwner.) 66 * - When to get rid of OpenOwners and LockOwners. 67 * - When a process exits, it calls nfscl_cleanup(), which goes 68 * through the client list looking for all Open and Lock Owners. 69 * When one is found, it is marked "defunct" or in the case of 70 * an OpenOwner without any Opens, freed. 71 * The renew thread scans for defunct Owners and gets rid of them, 72 * if it can. The LockOwners will also be deleted when the 73 * associated Open is closed. 74 * - If the LockU or Close Op(s) fail during close in a way 75 * that could be recovered upon retry, they are relinked to the 76 * ClientId's defunct open list and retried by the renew thread 77 * until they succeed or an unmount/recovery occurs. 78 * (Since we are done with them, they do not need to be recovered.) 79 */ 80 81 #ifndef APPLEKEXT 82 #include <fs/nfs/nfsport.h> 83 84 /* 85 * Global variables 86 */ 87 extern struct nfsstats newnfsstats; 88 extern struct nfsreqhead nfsd_reqq; 89 NFSREQSPINLOCK; 90 NFSCLSTATEMUTEX; 91 int nfscl_inited = 0; 92 struct nfsclhead nfsclhead; /* Head of clientid list */ 93 int nfscl_deleghighwater = NFSCLDELEGHIGHWATER; 94 #endif /* !APPLEKEXT */ 95 96 static int nfscl_delegcnt = 0; 97 static int nfscl_getopen(struct nfsclownerhead *, u_int8_t *, int, u_int8_t *, 98 NFSPROC_T *, u_int32_t, struct nfsclowner **, struct nfsclopen **); 99 static void nfscl_clrelease(struct nfsclclient *); 100 static void nfscl_cleanclient(struct nfsclclient *); 101 static void nfscl_expireclient(struct nfsclclient *, struct nfsmount *, 102 struct ucred *, NFSPROC_T *); 103 static int nfscl_expireopen(struct nfsclclient *, struct nfsclopen *, 104 struct nfsmount *, struct ucred *, NFSPROC_T *); 105 static void nfscl_recover(struct nfsclclient *, struct ucred *, NFSPROC_T *); 106 static void nfscl_insertlock(struct nfscllockowner *, struct nfscllock *, 107 struct nfscllock *, int); 108 static int nfscl_updatelock(struct nfscllockowner *, struct nfscllock **, 109 struct nfscllock **, int); 110 static void nfscl_delegreturnall(struct nfsclclient *, NFSPROC_T *); 111 static u_int32_t nfscl_nextcbident(void); 112 static mount_t nfscl_getmnt(u_int32_t); 113 static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *, 114 int); 115 static int nfscl_checkconflict(struct nfscllockownerhead *, struct nfscllock *, 116 u_int8_t *, struct nfscllock **); 117 static void nfscl_freelockowner(struct nfscllockowner *, int); 118 static void nfscl_freealllocks(struct nfscllockownerhead *, int); 119 static int nfscl_localconflict(struct nfsclclient *, u_int8_t *, int, 120 struct nfscllock *, u_int8_t *, struct nfscldeleg *, struct nfscllock **); 121 static void nfscl_newopen(struct nfsclclient *, struct nfscldeleg *, 122 struct nfsclowner **, struct nfsclowner **, struct nfsclopen **, 123 struct nfsclopen **, u_int8_t *, u_int8_t *, int, int *); 124 static int nfscl_moveopen(vnode_t , struct nfsclclient *, 125 struct nfsmount *, struct nfsclopen *, struct nfsclowner *, 126 struct nfscldeleg *, struct ucred *, NFSPROC_T *); 127 static void nfscl_totalrecall(struct nfsclclient *); 128 static int nfscl_relock(vnode_t , struct nfsclclient *, struct nfsmount *, 129 struct nfscllockowner *, struct nfscllock *, struct ucred *, NFSPROC_T *); 130 static int nfscl_tryopen(struct nfsmount *, vnode_t , u_int8_t *, int, 131 u_int8_t *, int, u_int32_t, struct nfsclopen *, u_int8_t *, int, 132 struct nfscldeleg **, int, u_int32_t, struct ucred *, NFSPROC_T *); 133 static int nfscl_trylock(struct nfsmount *, vnode_t , u_int8_t *, 134 int, struct nfscllockowner *, int, int, u_int64_t, u_int64_t, short, 135 struct ucred *, NFSPROC_T *); 136 static int nfsrpc_reopen(struct nfsmount *, u_int8_t *, int, u_int32_t, 137 struct nfsclopen *, struct nfscldeleg **, struct ucred *, NFSPROC_T *); 138 static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *); 139 static int nfscl_errmap(struct nfsrv_descript *); 140 static void nfscl_cleanup_common(struct nfsclclient *, u_int8_t *); 141 static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *, 142 struct nfscldeleg *, vnode_t, struct ucred *, NFSPROC_T *, int); 143 static void nfscl_freeopenowner(struct nfsclowner *, int); 144 static void nfscl_cleandeleg(struct nfscldeleg *); 145 static int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *, 146 struct nfsmount *, NFSPROC_T *); 147 148 static short nfscberr_null[] = { 149 0, 150 0, 151 }; 152 153 static short nfscberr_getattr[] = { 154 NFSERR_RESOURCE, 155 NFSERR_BADHANDLE, 156 NFSERR_BADXDR, 157 NFSERR_RESOURCE, 158 NFSERR_SERVERFAULT, 159 0, 160 }; 161 162 static short nfscberr_recall[] = { 163 NFSERR_RESOURCE, 164 NFSERR_BADHANDLE, 165 NFSERR_BADSTATEID, 166 NFSERR_BADXDR, 167 NFSERR_RESOURCE, 168 NFSERR_SERVERFAULT, 169 0, 170 }; 171 172 static short *nfscl_cberrmap[] = { 173 nfscberr_null, 174 nfscberr_null, 175 nfscberr_null, 176 nfscberr_getattr, 177 nfscberr_recall 178 }; 179 180 #define NETFAMILY(clp) \ 181 (((clp)->nfsc_flags & NFSCLFLAGS_AFINET6) ? AF_INET6 : AF_INET) 182 183 /* 184 * Called for an open operation. 185 * If the nfhp argument is NULL, just get an openowner. 186 */ 187 APPLESTATIC int 188 nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg, 189 struct ucred *cred, NFSPROC_T *p, struct nfsclowner **owpp, 190 struct nfsclopen **opp, int *newonep, int *retp, int lockit) 191 { 192 struct nfsclclient *clp; 193 struct nfsclowner *owp, *nowp; 194 struct nfsclopen *op = NULL, *nop = NULL; 195 struct nfscldeleg *dp; 196 struct nfsclownerhead *ohp; 197 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 198 int ret; 199 200 if (newonep != NULL) 201 *newonep = 0; 202 if (opp != NULL) 203 *opp = NULL; 204 if (owpp != NULL) 205 *owpp = NULL; 206 207 /* 208 * Might need one or both of these, so MALLOC them now, to 209 * avoid a tsleep() in MALLOC later. 210 */ 211 MALLOC(nowp, struct nfsclowner *, sizeof (struct nfsclowner), 212 M_NFSCLOWNER, M_WAITOK); 213 if (nfhp != NULL) 214 MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) + 215 fhlen - 1, M_NFSCLOPEN, M_WAITOK); 216 ret = nfscl_getcl(vp, cred, p, &clp); 217 if (ret != 0) { 218 FREE((caddr_t)nowp, M_NFSCLOWNER); 219 if (nop != NULL) 220 FREE((caddr_t)nop, M_NFSCLOPEN); 221 return (ret); 222 } 223 224 /* 225 * Get the Open iff it already exists. 226 * If none found, add the new one or return error, depending upon 227 * "create". 228 */ 229 nfscl_filllockowner(p, own); 230 NFSLOCKCLSTATE(); 231 dp = NULL; 232 /* First check the delegation list */ 233 if (nfhp != NULL && usedeleg) { 234 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) { 235 if (dp->nfsdl_fhlen == fhlen && 236 !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) { 237 if (!(amode & NFSV4OPEN_ACCESSWRITE) || 238 (dp->nfsdl_flags & NFSCLDL_WRITE)) 239 break; 240 dp = NULL; 241 break; 242 } 243 } 244 } 245 246 if (dp != NULL) 247 ohp = &dp->nfsdl_owner; 248 else 249 ohp = &clp->nfsc_owner; 250 /* Now, search for an openowner */ 251 LIST_FOREACH(owp, ohp, nfsow_list) { 252 if (!NFSBCMP(owp->nfsow_owner, own, NFSV4CL_LOCKNAMELEN)) 253 break; 254 } 255 256 /* 257 * Create a new open, as required. 258 */ 259 nfscl_newopen(clp, dp, &owp, &nowp, &op, &nop, own, nfhp, fhlen, 260 newonep); 261 262 /* 263 * Serialize modifications to the open owner for multiple threads 264 * within the same process using a read/write sleep lock. 265 */ 266 if (lockit) 267 nfscl_lockexcl(&owp->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 268 NFSUNLOCKCLSTATE(); 269 if (nowp != NULL) 270 FREE((caddr_t)nowp, M_NFSCLOWNER); 271 if (nop != NULL) 272 FREE((caddr_t)nop, M_NFSCLOPEN); 273 if (owpp != NULL) 274 *owpp = owp; 275 if (opp != NULL) 276 *opp = op; 277 if (retp != NULL) { 278 if (nfhp != NULL && dp != NULL && nop == NULL) 279 /* new local open on delegation */ 280 *retp = NFSCLOPEN_SETCRED; 281 else 282 *retp = NFSCLOPEN_OK; 283 } 284 285 /* 286 * Now, check the mode on the open and return the appropriate 287 * value. 288 */ 289 if (op != NULL && (amode & ~(op->nfso_mode))) { 290 op->nfso_mode |= amode; 291 if (retp != NULL && dp == NULL) 292 *retp = NFSCLOPEN_DOOPEN; 293 } 294 return (0); 295 } 296 297 /* 298 * Create a new open, as required. 299 */ 300 static void 301 nfscl_newopen(struct nfsclclient *clp, struct nfscldeleg *dp, 302 struct nfsclowner **owpp, struct nfsclowner **nowpp, struct nfsclopen **opp, 303 struct nfsclopen **nopp, u_int8_t *own, u_int8_t *fhp, int fhlen, 304 int *newonep) 305 { 306 struct nfsclowner *owp = *owpp, *nowp; 307 struct nfsclopen *op, *nop; 308 309 if (nowpp != NULL) 310 nowp = *nowpp; 311 else 312 nowp = NULL; 313 if (nopp != NULL) 314 nop = *nopp; 315 else 316 nop = NULL; 317 if (owp == NULL && nowp != NULL) { 318 NFSBCOPY(own, nowp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 319 LIST_INIT(&nowp->nfsow_open); 320 nowp->nfsow_clp = clp; 321 nowp->nfsow_seqid = 0; 322 nowp->nfsow_defunct = 0; 323 nfscl_lockinit(&nowp->nfsow_rwlock); 324 if (dp != NULL) { 325 newnfsstats.cllocalopenowners++; 326 LIST_INSERT_HEAD(&dp->nfsdl_owner, nowp, nfsow_list); 327 } else { 328 newnfsstats.clopenowners++; 329 LIST_INSERT_HEAD(&clp->nfsc_owner, nowp, nfsow_list); 330 } 331 owp = *owpp = nowp; 332 *nowpp = NULL; 333 if (newonep != NULL) 334 *newonep = 1; 335 } 336 337 /* If an fhp has been specified, create an Open as well. */ 338 if (fhp != NULL) { 339 /* and look for the correct open, based upon FH */ 340 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 341 if (op->nfso_fhlen == fhlen && 342 !NFSBCMP(op->nfso_fh, fhp, fhlen)) 343 break; 344 } 345 if (op == NULL && nop != NULL) { 346 nop->nfso_own = owp; 347 nop->nfso_mode = 0; 348 nop->nfso_opencnt = 0; 349 nop->nfso_posixlock = 1; 350 nop->nfso_fhlen = fhlen; 351 NFSBCOPY(fhp, nop->nfso_fh, fhlen); 352 LIST_INIT(&nop->nfso_lock); 353 nop->nfso_stateid.seqid = 0; 354 nop->nfso_stateid.other[0] = 0; 355 nop->nfso_stateid.other[1] = 0; 356 nop->nfso_stateid.other[2] = 0; 357 if (dp != NULL) { 358 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 359 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, 360 nfsdl_list); 361 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 362 newnfsstats.cllocalopens++; 363 } else { 364 newnfsstats.clopens++; 365 } 366 LIST_INSERT_HEAD(&owp->nfsow_open, nop, nfso_list); 367 *opp = nop; 368 *nopp = NULL; 369 if (newonep != NULL) 370 *newonep = 1; 371 } else { 372 *opp = op; 373 } 374 } 375 } 376 377 /* 378 * Called to find/add a delegation to a client. 379 */ 380 APPLESTATIC int 381 nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp, 382 int fhlen, struct ucred *cred, NFSPROC_T *p, struct nfscldeleg **dpp) 383 { 384 struct nfscldeleg *dp = *dpp, *tdp; 385 386 /* 387 * First, if we have received a Read delegation for a file on a 388 * read/write file system, just return it, because they aren't 389 * useful, imho. 390 */ 391 if (mp != NULL && dp != NULL && !NFSMNT_RDONLY(mp) && 392 (dp->nfsdl_flags & NFSCLDL_READ)) { 393 (void) nfscl_trydelegreturn(dp, cred, VFSTONFS(mp), p); 394 FREE((caddr_t)dp, M_NFSCLDELEG); 395 *dpp = NULL; 396 return (0); 397 } 398 399 /* Look for the correct deleg, based upon FH */ 400 NFSLOCKCLSTATE(); 401 tdp = nfscl_finddeleg(clp, nfhp, fhlen); 402 if (tdp == NULL) { 403 if (dp == NULL) { 404 NFSUNLOCKCLSTATE(); 405 return (NFSERR_BADSTATEID); 406 } 407 *dpp = NULL; 408 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list); 409 LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, nfhp, fhlen), dp, 410 nfsdl_hash); 411 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 412 newnfsstats.cldelegates++; 413 nfscl_delegcnt++; 414 } else { 415 /* 416 * Delegation already exists, what do we do if a new one?? 417 */ 418 if (dp != NULL) { 419 printf("Deleg already exists!\n"); 420 FREE((caddr_t)dp, M_NFSCLDELEG); 421 *dpp = NULL; 422 } else { 423 *dpp = tdp; 424 } 425 } 426 NFSUNLOCKCLSTATE(); 427 return (0); 428 } 429 430 /* 431 * Find a delegation for this file handle. Return NULL upon failure. 432 */ 433 static struct nfscldeleg * 434 nfscl_finddeleg(struct nfsclclient *clp, u_int8_t *fhp, int fhlen) 435 { 436 struct nfscldeleg *dp; 437 438 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, fhp, fhlen), nfsdl_hash) { 439 if (dp->nfsdl_fhlen == fhlen && 440 !NFSBCMP(dp->nfsdl_fh, fhp, fhlen)) 441 break; 442 } 443 return (dp); 444 } 445 446 /* 447 * Get a stateid for an I/O operation. First, look for an open and iff 448 * found, return either a lockowner stateid or the open stateid. 449 * If no Open is found, just return error and the special stateid of all zeros. 450 */ 451 APPLESTATIC int 452 nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode, 453 struct ucred *cred, NFSPROC_T *p, nfsv4stateid_t *stateidp, 454 void **lckpp) 455 { 456 struct nfsclclient *clp; 457 struct nfsclowner *owp; 458 struct nfsclopen *op = NULL; 459 struct nfscllockowner *lp; 460 struct nfscldeleg *dp; 461 struct nfsnode *np; 462 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 463 int error, done; 464 465 *lckpp = NULL; 466 /* 467 * Initially, just set the special stateid of all zeros. 468 */ 469 stateidp->seqid = 0; 470 stateidp->other[0] = 0; 471 stateidp->other[1] = 0; 472 stateidp->other[2] = 0; 473 if (vnode_vtype(vp) != VREG) 474 return (EISDIR); 475 np = VTONFS(vp); 476 NFSLOCKCLSTATE(); 477 clp = nfscl_findcl(VFSTONFS(vnode_mount(vp))); 478 if (clp == NULL) { 479 NFSUNLOCKCLSTATE(); 480 return (EACCES); 481 } 482 483 /* 484 * Wait for recovery to complete. 485 */ 486 while ((clp->nfsc_flags & NFSCLFLAGS_RECVRINPROG)) 487 (void) nfsmsleep(&clp->nfsc_flags, NFSCLSTATEMUTEXPTR, 488 PZERO, "nfsrecvr", NULL); 489 490 /* 491 * First, look for a delegation. 492 */ 493 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) { 494 if (dp->nfsdl_fhlen == fhlen && 495 !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) { 496 if (!(mode & NFSV4OPEN_ACCESSWRITE) || 497 (dp->nfsdl_flags & NFSCLDL_WRITE)) { 498 stateidp->seqid = dp->nfsdl_stateid.seqid; 499 stateidp->other[0] = dp->nfsdl_stateid.other[0]; 500 stateidp->other[1] = dp->nfsdl_stateid.other[1]; 501 stateidp->other[2] = dp->nfsdl_stateid.other[2]; 502 if (!(np->n_flag & NDELEGRECALL)) { 503 TAILQ_REMOVE(&clp->nfsc_deleg, dp, 504 nfsdl_list); 505 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, 506 nfsdl_list); 507 dp->nfsdl_timestamp = NFSD_MONOSEC + 508 120; 509 dp->nfsdl_rwlock.nfslock_usecnt++; 510 *lckpp = (void *)&dp->nfsdl_rwlock; 511 } 512 NFSUNLOCKCLSTATE(); 513 return (0); 514 } 515 break; 516 } 517 } 518 519 if (p != NULL) { 520 /* 521 * If p != NULL, we want to search the parentage tree 522 * for a matching OpenOwner and use that. 523 */ 524 nfscl_filllockowner(p, own); 525 error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p, 526 mode, NULL, &op); 527 if (error == 0) { 528 /* now look for a lockowner */ 529 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 530 if (!NFSBCMP(lp->nfsl_owner, own, 531 NFSV4CL_LOCKNAMELEN)) { 532 stateidp->seqid = 533 lp->nfsl_stateid.seqid; 534 stateidp->other[0] = 535 lp->nfsl_stateid.other[0]; 536 stateidp->other[1] = 537 lp->nfsl_stateid.other[1]; 538 stateidp->other[2] = 539 lp->nfsl_stateid.other[2]; 540 NFSUNLOCKCLSTATE(); 541 return (0); 542 } 543 } 544 } 545 } 546 if (op == NULL) { 547 /* If not found, just look for any OpenOwner that will work. */ 548 done = 0; 549 owp = LIST_FIRST(&clp->nfsc_owner); 550 while (!done && owp != NULL) { 551 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 552 if (op->nfso_fhlen == fhlen && 553 !NFSBCMP(op->nfso_fh, nfhp, fhlen) && 554 (mode & op->nfso_mode) == mode) { 555 done = 1; 556 break; 557 } 558 } 559 if (!done) 560 owp = LIST_NEXT(owp, nfsow_list); 561 } 562 if (!done) { 563 NFSUNLOCKCLSTATE(); 564 return (ENOENT); 565 } 566 /* for read aheads or write behinds, use the open cred */ 567 newnfs_copycred(&op->nfso_cred, cred); 568 } 569 570 /* 571 * No lock stateid, so return the open stateid. 572 */ 573 stateidp->seqid = op->nfso_stateid.seqid; 574 stateidp->other[0] = op->nfso_stateid.other[0]; 575 stateidp->other[1] = op->nfso_stateid.other[1]; 576 stateidp->other[2] = op->nfso_stateid.other[2]; 577 NFSUNLOCKCLSTATE(); 578 return (0); 579 } 580 581 /* 582 * Get an existing open. Search up the parentage tree for a match and 583 * return with the first one found. 584 */ 585 static int 586 nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen, 587 u_int8_t *rown, NFSPROC_T *p, u_int32_t mode, struct nfsclowner **owpp, 588 struct nfsclopen **opp) 589 { 590 struct nfsclowner *owp = NULL; 591 struct nfsclopen *op; 592 NFSPROC_T *nproc; 593 u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp; 594 595 nproc = p; 596 op = NULL; 597 while (op == NULL && (nproc != NULL || rown != NULL)) { 598 if (nproc != NULL) { 599 nfscl_filllockowner(nproc, own); 600 ownp = own; 601 } else { 602 ownp = rown; 603 } 604 /* Search the client list */ 605 LIST_FOREACH(owp, ohp, nfsow_list) { 606 if (!NFSBCMP(owp->nfsow_owner, ownp, 607 NFSV4CL_LOCKNAMELEN)) 608 break; 609 } 610 if (owp != NULL) { 611 /* and look for the correct open */ 612 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 613 if (op->nfso_fhlen == fhlen && 614 !NFSBCMP(op->nfso_fh, nfhp, fhlen) 615 && (op->nfso_mode & mode) == mode) { 616 break; 617 } 618 } 619 } 620 if (rown != NULL) 621 break; 622 if (op == NULL) 623 nproc = nfscl_getparent(nproc); 624 } 625 if (op == NULL) { 626 return (EBADF); 627 } 628 if (owpp) 629 *owpp = owp; 630 *opp = op; 631 return (0); 632 } 633 634 /* 635 * Release use of an open owner. Called when open operations are done 636 * with the open owner. 637 */ 638 APPLESTATIC void 639 nfscl_ownerrelease(struct nfsclowner *owp, __unused int error, 640 __unused int candelete, int unlocked) 641 { 642 643 if (owp == NULL) 644 return; 645 NFSLOCKCLSTATE(); 646 if (!unlocked) 647 nfscl_lockunlock(&owp->nfsow_rwlock); 648 nfscl_clrelease(owp->nfsow_clp); 649 NFSUNLOCKCLSTATE(); 650 } 651 652 /* 653 * Release use of an open structure under an open owner. 654 */ 655 APPLESTATIC void 656 nfscl_openrelease(struct nfsclopen *op, int error, int candelete) 657 { 658 struct nfsclclient *clp; 659 struct nfsclowner *owp; 660 661 if (op == NULL) 662 return; 663 NFSLOCKCLSTATE(); 664 owp = op->nfso_own; 665 nfscl_lockunlock(&owp->nfsow_rwlock); 666 clp = owp->nfsow_clp; 667 if (error && candelete && op->nfso_opencnt == 0) 668 nfscl_freeopen(op, 0); 669 nfscl_clrelease(clp); 670 NFSUNLOCKCLSTATE(); 671 } 672 673 /* 674 * Called to get a clientid structure. It will optionally lock the 675 * client data structures to do the SetClientId/SetClientId_confirm, 676 * but will release that lock and return the clientid with a refernce 677 * count on it. 678 * If the "cred" argument is NULL, a new clientid should not be created. 679 * If the "p" argument is NULL, a SetClientID/SetClientIDConfirm cannot 680 * be done. 681 * It always clpp with a reference count on it, unless returning an error. 682 */ 683 APPLESTATIC int 684 nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 685 struct nfsclclient **clpp) 686 { 687 struct nfsclclient *clp; 688 struct nfsclclient *newclp = NULL; 689 struct nfscllockowner *lp, *nlp; 690 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 691 char uuid[HOSTUUIDLEN]; 692 int igotlock = 0, error, trystalecnt, clidinusedelay, i; 693 u_int16_t idlen = 0; 694 695 if (cred != NULL) { 696 getcredhostuuid(cred, uuid, sizeof uuid); 697 idlen = strlen(uuid); 698 if (idlen > 0) 699 idlen += sizeof (u_int64_t); 700 else 701 idlen += sizeof (u_int64_t) + 16; /* 16 random bytes */ 702 MALLOC(newclp, struct nfsclclient *, 703 sizeof (struct nfsclclient) + idlen - 1, M_NFSCLCLIENT, 704 M_WAITOK); 705 } 706 NFSLOCKCLSTATE(); 707 clp = nmp->nm_clp; 708 if (clp == NULL) { 709 if (newclp == NULL) { 710 NFSUNLOCKCLSTATE(); 711 return (EACCES); 712 } 713 clp = newclp; 714 NFSBZERO((caddr_t)clp, sizeof(struct nfsclclient) + idlen - 1); 715 clp->nfsc_idlen = idlen; 716 LIST_INIT(&clp->nfsc_owner); 717 TAILQ_INIT(&clp->nfsc_deleg); 718 for (i = 0; i < NFSCLDELEGHASHSIZE; i++) 719 LIST_INIT(&clp->nfsc_deleghash[i]); 720 LIST_INIT(&clp->nfsc_defunctlockowner); 721 clp->nfsc_flags = NFSCLFLAGS_INITED; 722 clp->nfsc_clientidrev = 1; 723 clp->nfsc_cbident = nfscl_nextcbident(); 724 nfscl_fillclid(nmp->nm_clval, uuid, clp->nfsc_id, 725 clp->nfsc_idlen); 726 LIST_INSERT_HEAD(&nfsclhead, clp, nfsc_list); 727 nmp->nm_clp = clp; 728 clp->nfsc_nmp = nmp; 729 NFSUNLOCKCLSTATE(); 730 nfscl_start_renewthread(clp); 731 } else { 732 NFSUNLOCKCLSTATE(); 733 if (newclp != NULL) 734 FREE((caddr_t)newclp, M_NFSCLCLIENT); 735 } 736 NFSLOCKCLSTATE(); 737 while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock) 738 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 739 NFSCLSTATEMUTEXPTR); 740 if (!igotlock) 741 nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR); 742 NFSUNLOCKCLSTATE(); 743 744 /* 745 * If it needs a clientid, do the setclientid now. 746 */ 747 if ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0) { 748 if (!igotlock) 749 panic("nfscl_clget"); 750 if (p == NULL || cred == NULL) { 751 NFSLOCKCLSTATE(); 752 nfsv4_unlock(&clp->nfsc_lock, 0); 753 NFSUNLOCKCLSTATE(); 754 return (EACCES); 755 } 756 /* get rid of defunct lockowners */ 757 LIST_FOREACH_SAFE(lp, &clp->nfsc_defunctlockowner, nfsl_list, 758 nlp) { 759 nfscl_freelockowner(lp, 0); 760 } 761 /* 762 * If RFC3530 Sec. 14.2.33 is taken literally, 763 * NFSERR_CLIDINUSE will be returned persistently for the 764 * case where a new mount of the same file system is using 765 * a different principal. In practice, NFSERR_CLIDINUSE is 766 * only returned when there is outstanding unexpired state 767 * on the clientid. As such, try for twice the lease 768 * interval, if we know what that is. Otherwise, make a 769 * wild ass guess. 770 * The case of returning NFSERR_STALECLIENTID is far less 771 * likely, but might occur if there is a significant delay 772 * between doing the SetClientID and SetClientIDConfirm Ops, 773 * such that the server throws away the clientid before 774 * receiving the SetClientIDConfirm. 775 */ 776 if (clp->nfsc_renew > 0) 777 clidinusedelay = NFSCL_LEASE(clp->nfsc_renew) * 2; 778 else 779 clidinusedelay = 120; 780 trystalecnt = 3; 781 do { 782 error = nfsrpc_setclient(VFSTONFS(vnode_mount(vp)), 783 clp, cred, p); 784 if (error == NFSERR_STALECLIENTID || 785 error == NFSERR_STALEDONTRECOVER || 786 error == NFSERR_CLIDINUSE) { 787 (void) nfs_catnap(PZERO, error, "nfs_setcl"); 788 } 789 } while (((error == NFSERR_STALECLIENTID || 790 error == NFSERR_STALEDONTRECOVER) && --trystalecnt > 0) || 791 (error == NFSERR_CLIDINUSE && --clidinusedelay > 0)); 792 if (error) { 793 NFSLOCKCLSTATE(); 794 nfsv4_unlock(&clp->nfsc_lock, 0); 795 NFSUNLOCKCLSTATE(); 796 return (error); 797 } 798 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 799 } 800 if (igotlock) { 801 NFSLOCKCLSTATE(); 802 nfsv4_unlock(&clp->nfsc_lock, 1); 803 NFSUNLOCKCLSTATE(); 804 } 805 806 *clpp = clp; 807 return (0); 808 } 809 810 /* 811 * Get a reference to a clientid and return it, if valid. 812 */ 813 APPLESTATIC struct nfsclclient * 814 nfscl_findcl(struct nfsmount *nmp) 815 { 816 struct nfsclclient *clp; 817 818 clp = nmp->nm_clp; 819 if (clp == NULL || !(clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) 820 return (NULL); 821 return (clp); 822 } 823 824 /* 825 * Release the clientid structure. It may be locked or reference counted. 826 */ 827 static void 828 nfscl_clrelease(struct nfsclclient *clp) 829 { 830 831 if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK) 832 nfsv4_unlock(&clp->nfsc_lock, 0); 833 else 834 nfsv4_relref(&clp->nfsc_lock); 835 } 836 837 /* 838 * External call for nfscl_clrelease. 839 */ 840 APPLESTATIC void 841 nfscl_clientrelease(struct nfsclclient *clp) 842 { 843 844 NFSLOCKCLSTATE(); 845 if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK) 846 nfsv4_unlock(&clp->nfsc_lock, 0); 847 else 848 nfsv4_relref(&clp->nfsc_lock); 849 NFSUNLOCKCLSTATE(); 850 } 851 852 /* 853 * Called when wanting to lock a byte region. 854 */ 855 APPLESTATIC int 856 nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len, 857 short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp, 858 int recovery, u_int8_t *rownp, u_int8_t *ropenownp, 859 struct nfscllockowner **lpp, int *newonep, int *donelocallyp) 860 { 861 struct nfscllockowner *lp; 862 struct nfsclopen *op; 863 struct nfsclclient *clp; 864 struct nfscllockowner *nlp; 865 struct nfscllock *nlop, *otherlop; 866 struct nfscldeleg *dp = NULL, *ldp = NULL; 867 struct nfscllockownerhead *lhp = NULL; 868 struct nfsnode *np; 869 u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp; 870 int error = 0, ret, donelocally = 0; 871 u_int32_t mode; 872 873 if (type == F_WRLCK) 874 mode = NFSV4OPEN_ACCESSWRITE; 875 else 876 mode = NFSV4OPEN_ACCESSREAD; 877 np = VTONFS(vp); 878 *lpp = NULL; 879 *newonep = 0; 880 *donelocallyp = 0; 881 882 /* 883 * Might need these, so MALLOC them now, to 884 * avoid a tsleep() in MALLOC later. 885 */ 886 MALLOC(nlp, struct nfscllockowner *, 887 sizeof (struct nfscllockowner), M_NFSCLLOCKOWNER, M_WAITOK); 888 MALLOC(otherlop, struct nfscllock *, 889 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 890 MALLOC(nlop, struct nfscllock *, 891 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 892 nlop->nfslo_type = type; 893 nlop->nfslo_first = off; 894 if (len == NFS64BITSSET) { 895 nlop->nfslo_end = NFS64BITSSET; 896 } else { 897 nlop->nfslo_end = off + len; 898 if (nlop->nfslo_end <= nlop->nfslo_first) 899 error = NFSERR_INVAL; 900 } 901 902 if (!error) { 903 if (recovery) 904 clp = rclp; 905 else 906 error = nfscl_getcl(vp, cred, p, &clp); 907 } 908 if (error) { 909 FREE((caddr_t)nlp, M_NFSCLLOCKOWNER); 910 FREE((caddr_t)otherlop, M_NFSCLLOCK); 911 FREE((caddr_t)nlop, M_NFSCLLOCK); 912 return (error); 913 } 914 915 op = NULL; 916 if (recovery) { 917 ownp = rownp; 918 } else { 919 nfscl_filllockowner(p, own); 920 ownp = own; 921 } 922 if (!recovery) { 923 NFSLOCKCLSTATE(); 924 /* 925 * First, search for a delegation. If one exists for this file, 926 * the lock can be done locally against it, so long as there 927 * isn't a local lock conflict. 928 */ 929 ldp = dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 930 np->n_fhp->nfh_len); 931 /* Just sanity check for correct type of delegation */ 932 if (dp != NULL && ((dp->nfsdl_flags & 933 (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) != 0 || 934 (type == F_WRLCK && 935 (dp->nfsdl_flags & NFSCLDL_WRITE) == 0))) 936 dp = NULL; 937 } 938 if (dp != NULL) { 939 /* Now, find the associated open to get the correct openowner */ 940 ret = nfscl_getopen(&dp->nfsdl_owner, np->n_fhp->nfh_fh, 941 np->n_fhp->nfh_len, NULL, p, mode, NULL, &op); 942 if (ret) 943 ret = nfscl_getopen(&clp->nfsc_owner, 944 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, NULL, p, 945 mode, NULL, &op); 946 if (!ret) { 947 lhp = &dp->nfsdl_lock; 948 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 949 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list); 950 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 951 donelocally = 1; 952 } else { 953 dp = NULL; 954 } 955 } 956 if (!donelocally) { 957 /* 958 * Get the related Open. 959 */ 960 if (recovery) 961 error = nfscl_getopen(&clp->nfsc_owner, 962 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, ropenownp, 963 NULL, mode, NULL, &op); 964 else 965 error = nfscl_getopen(&clp->nfsc_owner, 966 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, NULL, p, 967 mode, NULL, &op); 968 if (!error) 969 lhp = &op->nfso_lock; 970 } 971 if (!error && !recovery) 972 error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, 973 np->n_fhp->nfh_len, nlop, ownp, ldp, NULL); 974 if (error) { 975 if (!recovery) { 976 nfscl_clrelease(clp); 977 NFSUNLOCKCLSTATE(); 978 } 979 FREE((caddr_t)nlp, M_NFSCLLOCKOWNER); 980 FREE((caddr_t)otherlop, M_NFSCLLOCK); 981 FREE((caddr_t)nlop, M_NFSCLLOCK); 982 return (error); 983 } 984 985 /* 986 * Ok, see if a lockowner exists and create one, as required. 987 */ 988 LIST_FOREACH(lp, lhp, nfsl_list) { 989 if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN)) 990 break; 991 } 992 if (lp == NULL) { 993 NFSBCOPY(ownp, nlp->nfsl_owner, NFSV4CL_LOCKNAMELEN); 994 if (recovery) 995 NFSBCOPY(ropenownp, nlp->nfsl_openowner, 996 NFSV4CL_LOCKNAMELEN); 997 else 998 NFSBCOPY(op->nfso_own->nfsow_owner, nlp->nfsl_openowner, 999 NFSV4CL_LOCKNAMELEN); 1000 nlp->nfsl_seqid = 0; 1001 nlp->nfsl_defunct = 0; 1002 nlp->nfsl_inprog = NULL; 1003 nfscl_lockinit(&nlp->nfsl_rwlock); 1004 LIST_INIT(&nlp->nfsl_lock); 1005 if (donelocally) { 1006 nlp->nfsl_open = NULL; 1007 newnfsstats.cllocallockowners++; 1008 } else { 1009 nlp->nfsl_open = op; 1010 newnfsstats.cllockowners++; 1011 } 1012 LIST_INSERT_HEAD(lhp, nlp, nfsl_list); 1013 lp = nlp; 1014 nlp = NULL; 1015 *newonep = 1; 1016 } 1017 1018 /* 1019 * Now, update the byte ranges for locks. 1020 */ 1021 ret = nfscl_updatelock(lp, &nlop, &otherlop, donelocally); 1022 if (!ret) 1023 donelocally = 1; 1024 if (donelocally) { 1025 *donelocallyp = 1; 1026 if (!recovery) 1027 nfscl_clrelease(clp); 1028 } else { 1029 /* 1030 * Serial modifications on the lock owner for multiple threads 1031 * for the same process using a read/write lock. 1032 */ 1033 if (!recovery) 1034 nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR); 1035 } 1036 if (!recovery) 1037 NFSUNLOCKCLSTATE(); 1038 1039 if (nlp) 1040 FREE((caddr_t)nlp, M_NFSCLLOCKOWNER); 1041 if (nlop) 1042 FREE((caddr_t)nlop, M_NFSCLLOCK); 1043 if (otherlop) 1044 FREE((caddr_t)otherlop, M_NFSCLLOCK); 1045 1046 *lpp = lp; 1047 return (0); 1048 } 1049 1050 /* 1051 * Called to unlock a byte range, for LockU. 1052 */ 1053 APPLESTATIC int 1054 nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len, 1055 __unused struct ucred *cred, NFSPROC_T *p, int callcnt, 1056 struct nfsclclient *clp, struct nfscllockowner **lpp, int *dorpcp) 1057 { 1058 struct nfscllockowner *lp; 1059 struct nfsclowner *owp; 1060 struct nfsclopen *op; 1061 struct nfscllock *nlop, *other_lop = NULL; 1062 struct nfscldeleg *dp; 1063 struct nfsnode *np; 1064 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1065 int ret = 0, fnd; 1066 1067 np = VTONFS(vp); 1068 *lpp = NULL; 1069 *dorpcp = 0; 1070 1071 /* 1072 * Might need these, so MALLOC them now, to 1073 * avoid a tsleep() in MALLOC later. 1074 */ 1075 MALLOC(nlop, struct nfscllock *, 1076 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1077 nlop->nfslo_type = F_UNLCK; 1078 nlop->nfslo_first = off; 1079 if (len == NFS64BITSSET) { 1080 nlop->nfslo_end = NFS64BITSSET; 1081 } else { 1082 nlop->nfslo_end = off + len; 1083 if (nlop->nfslo_end <= nlop->nfslo_first) { 1084 FREE((caddr_t)nlop, M_NFSCLLOCK); 1085 return (NFSERR_INVAL); 1086 } 1087 } 1088 if (callcnt == 0) { 1089 MALLOC(other_lop, struct nfscllock *, 1090 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1091 *other_lop = *nlop; 1092 } 1093 nfscl_filllockowner(p, own); 1094 dp = NULL; 1095 NFSLOCKCLSTATE(); 1096 if (callcnt == 0) 1097 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 1098 np->n_fhp->nfh_len); 1099 1100 /* 1101 * First, unlock any local regions on a delegation. 1102 */ 1103 if (dp != NULL) { 1104 /* Look for this lockowner. */ 1105 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 1106 if (!NFSBCMP(lp->nfsl_owner, own, 1107 NFSV4CL_LOCKNAMELEN)) 1108 break; 1109 } 1110 if (lp != NULL) 1111 /* Use other_lop, so nlop is still available */ 1112 (void)nfscl_updatelock(lp, &other_lop, NULL, 1); 1113 } 1114 1115 /* 1116 * Now, find a matching open/lockowner that hasn't already been done, 1117 * as marked by nfsl_inprog. 1118 */ 1119 lp = NULL; 1120 fnd = 0; 1121 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1122 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1123 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1124 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1125 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1126 if (lp->nfsl_inprog == NULL && 1127 !NFSBCMP(lp->nfsl_owner, own, 1128 NFSV4CL_LOCKNAMELEN)) { 1129 fnd = 1; 1130 break; 1131 } 1132 } 1133 if (fnd) 1134 break; 1135 } 1136 } 1137 if (fnd) 1138 break; 1139 } 1140 1141 if (lp != NULL) { 1142 ret = nfscl_updatelock(lp, &nlop, NULL, 0); 1143 if (ret) 1144 *dorpcp = 1; 1145 /* 1146 * Serial modifications on the lock owner for multiple 1147 * threads for the same process using a read/write lock. 1148 */ 1149 lp->nfsl_inprog = p; 1150 nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR); 1151 *lpp = lp; 1152 } 1153 NFSUNLOCKCLSTATE(); 1154 if (nlop) 1155 FREE((caddr_t)nlop, M_NFSCLLOCK); 1156 if (other_lop) 1157 FREE((caddr_t)other_lop, M_NFSCLLOCK); 1158 return (0); 1159 } 1160 1161 /* 1162 * Release all lockowners marked in progess for this process and file. 1163 */ 1164 APPLESTATIC void 1165 nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p) 1166 { 1167 struct nfsclowner *owp; 1168 struct nfsclopen *op; 1169 struct nfscllockowner *lp; 1170 struct nfsnode *np; 1171 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1172 1173 np = VTONFS(vp); 1174 nfscl_filllockowner(p, own); 1175 NFSLOCKCLSTATE(); 1176 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1177 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1178 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1179 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1180 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1181 if (lp->nfsl_inprog == p && 1182 !NFSBCMP(lp->nfsl_owner, own, 1183 NFSV4CL_LOCKNAMELEN)) { 1184 lp->nfsl_inprog = NULL; 1185 nfscl_lockunlock(&lp->nfsl_rwlock); 1186 } 1187 } 1188 } 1189 } 1190 } 1191 nfscl_clrelease(clp); 1192 NFSUNLOCKCLSTATE(); 1193 } 1194 1195 /* 1196 * Called to find out if any bytes within the byte range specified are 1197 * write locked by the calling process. Used to determine if flushing 1198 * is required before a LockU. 1199 * If in doubt, return 1, so the flush will occur. 1200 */ 1201 APPLESTATIC int 1202 nfscl_checkwritelocked(vnode_t vp, struct flock *fl, 1203 struct ucred *cred, NFSPROC_T *p) 1204 { 1205 struct nfsclowner *owp; 1206 struct nfscllockowner *lp; 1207 struct nfsclopen *op; 1208 struct nfsclclient *clp; 1209 struct nfscllock *lop; 1210 struct nfscldeleg *dp; 1211 struct nfsnode *np; 1212 u_int64_t off, end; 1213 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1214 int error = 0; 1215 1216 np = VTONFS(vp); 1217 switch (fl->l_whence) { 1218 case SEEK_SET: 1219 case SEEK_CUR: 1220 /* 1221 * Caller is responsible for adding any necessary offset 1222 * when SEEK_CUR is used. 1223 */ 1224 off = fl->l_start; 1225 break; 1226 case SEEK_END: 1227 off = np->n_size + fl->l_start; 1228 break; 1229 default: 1230 return (1); 1231 }; 1232 if (fl->l_len != 0) { 1233 end = off + fl->l_len; 1234 if (end < off) 1235 return (1); 1236 } else { 1237 end = NFS64BITSSET; 1238 } 1239 1240 error = nfscl_getcl(vp, cred, p, &clp); 1241 if (error) 1242 return (1); 1243 nfscl_filllockowner(p, own); 1244 NFSLOCKCLSTATE(); 1245 1246 /* 1247 * First check the delegation locks. 1248 */ 1249 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 1250 if (dp != NULL) { 1251 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 1252 if (!NFSBCMP(lp->nfsl_owner, own, 1253 NFSV4CL_LOCKNAMELEN)) 1254 break; 1255 } 1256 if (lp != NULL) { 1257 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 1258 if (lop->nfslo_first >= end) 1259 break; 1260 if (lop->nfslo_end <= off) 1261 continue; 1262 if (lop->nfslo_type == F_WRLCK) { 1263 nfscl_clrelease(clp); 1264 NFSUNLOCKCLSTATE(); 1265 return (1); 1266 } 1267 } 1268 } 1269 } 1270 1271 /* 1272 * Now, check state against the server. 1273 */ 1274 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1275 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1276 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1277 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1278 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1279 if (!NFSBCMP(lp->nfsl_owner, own, 1280 NFSV4CL_LOCKNAMELEN)) 1281 break; 1282 } 1283 if (lp != NULL) { 1284 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 1285 if (lop->nfslo_first >= end) 1286 break; 1287 if (lop->nfslo_end <= off) 1288 continue; 1289 if (lop->nfslo_type == F_WRLCK) { 1290 nfscl_clrelease(clp); 1291 NFSUNLOCKCLSTATE(); 1292 return (1); 1293 } 1294 } 1295 } 1296 } 1297 } 1298 } 1299 nfscl_clrelease(clp); 1300 NFSUNLOCKCLSTATE(); 1301 return (0); 1302 } 1303 1304 /* 1305 * Release a byte range lock owner structure. 1306 */ 1307 APPLESTATIC void 1308 nfscl_lockrelease(struct nfscllockowner *lp, int error, int candelete) 1309 { 1310 struct nfsclclient *clp; 1311 1312 if (lp == NULL) 1313 return; 1314 NFSLOCKCLSTATE(); 1315 clp = lp->nfsl_open->nfso_own->nfsow_clp; 1316 if (error != 0 && candelete && 1317 (lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED) == 0) 1318 nfscl_freelockowner(lp, 0); 1319 else 1320 nfscl_lockunlock(&lp->nfsl_rwlock); 1321 nfscl_clrelease(clp); 1322 NFSUNLOCKCLSTATE(); 1323 } 1324 1325 /* 1326 * Free up an open structure and any associated byte range lock structures. 1327 */ 1328 APPLESTATIC void 1329 nfscl_freeopen(struct nfsclopen *op, int local) 1330 { 1331 1332 LIST_REMOVE(op, nfso_list); 1333 nfscl_freealllocks(&op->nfso_lock, local); 1334 FREE((caddr_t)op, M_NFSCLOPEN); 1335 if (local) 1336 newnfsstats.cllocalopens--; 1337 else 1338 newnfsstats.clopens--; 1339 } 1340 1341 /* 1342 * Free up all lock owners and associated locks. 1343 */ 1344 static void 1345 nfscl_freealllocks(struct nfscllockownerhead *lhp, int local) 1346 { 1347 struct nfscllockowner *lp, *nlp; 1348 1349 LIST_FOREACH_SAFE(lp, lhp, nfsl_list, nlp) { 1350 if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED)) 1351 panic("nfscllckw"); 1352 nfscl_freelockowner(lp, local); 1353 } 1354 } 1355 1356 /* 1357 * Called for an Open when NFSERR_EXPIRED is received from the server. 1358 * If there are no byte range locks nor a Share Deny lost, try to do a 1359 * fresh Open. Otherwise, free the open. 1360 */ 1361 static int 1362 nfscl_expireopen(struct nfsclclient *clp, struct nfsclopen *op, 1363 struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 1364 { 1365 struct nfscllockowner *lp; 1366 struct nfscldeleg *dp; 1367 int mustdelete = 0, error; 1368 1369 /* 1370 * Look for any byte range lock(s). 1371 */ 1372 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1373 if (!LIST_EMPTY(&lp->nfsl_lock)) { 1374 mustdelete = 1; 1375 break; 1376 } 1377 } 1378 1379 /* 1380 * If no byte range lock(s) nor a Share deny, try to re-open. 1381 */ 1382 if (!mustdelete && (op->nfso_mode & NFSLCK_DENYBITS) == 0) { 1383 newnfs_copycred(&op->nfso_cred, cred); 1384 dp = NULL; 1385 error = nfsrpc_reopen(nmp, op->nfso_fh, 1386 op->nfso_fhlen, op->nfso_mode, op, &dp, cred, p); 1387 if (error) { 1388 mustdelete = 1; 1389 if (dp != NULL) { 1390 FREE((caddr_t)dp, M_NFSCLDELEG); 1391 dp = NULL; 1392 } 1393 } 1394 if (dp != NULL) 1395 nfscl_deleg(nmp->nm_mountp, clp, op->nfso_fh, 1396 op->nfso_fhlen, cred, p, &dp); 1397 } 1398 1399 /* 1400 * If a byte range lock or Share deny or couldn't re-open, free it. 1401 */ 1402 if (mustdelete) 1403 nfscl_freeopen(op, 0); 1404 return (mustdelete); 1405 } 1406 1407 /* 1408 * Free up an open owner structure. 1409 */ 1410 static void 1411 nfscl_freeopenowner(struct nfsclowner *owp, int local) 1412 { 1413 1414 LIST_REMOVE(owp, nfsow_list); 1415 FREE((caddr_t)owp, M_NFSCLOWNER); 1416 if (local) 1417 newnfsstats.cllocalopenowners--; 1418 else 1419 newnfsstats.clopenowners--; 1420 } 1421 1422 /* 1423 * Free up a byte range lock owner structure. 1424 */ 1425 static void 1426 nfscl_freelockowner(struct nfscllockowner *lp, int local) 1427 { 1428 struct nfscllock *lop, *nlop; 1429 1430 LIST_REMOVE(lp, nfsl_list); 1431 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 1432 nfscl_freelock(lop, local); 1433 } 1434 FREE((caddr_t)lp, M_NFSCLLOCKOWNER); 1435 if (local) 1436 newnfsstats.cllocallockowners--; 1437 else 1438 newnfsstats.cllockowners--; 1439 } 1440 1441 /* 1442 * Free up a byte range lock structure. 1443 */ 1444 APPLESTATIC void 1445 nfscl_freelock(struct nfscllock *lop, int local) 1446 { 1447 1448 LIST_REMOVE(lop, nfslo_list); 1449 FREE((caddr_t)lop, M_NFSCLLOCK); 1450 if (local) 1451 newnfsstats.cllocallocks--; 1452 else 1453 newnfsstats.cllocks--; 1454 } 1455 1456 /* 1457 * Clean out the state related to a delegation. 1458 */ 1459 static void 1460 nfscl_cleandeleg(struct nfscldeleg *dp) 1461 { 1462 struct nfsclowner *owp, *nowp; 1463 struct nfsclopen *op; 1464 1465 LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) { 1466 op = LIST_FIRST(&owp->nfsow_open); 1467 if (op != NULL) { 1468 if (LIST_NEXT(op, nfso_list) != NULL) 1469 panic("nfscleandel"); 1470 nfscl_freeopen(op, 1); 1471 } 1472 nfscl_freeopenowner(owp, 1); 1473 } 1474 nfscl_freealllocks(&dp->nfsdl_lock, 1); 1475 } 1476 1477 /* 1478 * Free a delegation. 1479 */ 1480 static void 1481 nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp) 1482 { 1483 1484 TAILQ_REMOVE(hdp, dp, nfsdl_list); 1485 LIST_REMOVE(dp, nfsdl_hash); 1486 FREE((caddr_t)dp, M_NFSCLDELEG); 1487 newnfsstats.cldelegates--; 1488 nfscl_delegcnt--; 1489 } 1490 1491 /* 1492 * Free up all state related to this client structure. 1493 */ 1494 static void 1495 nfscl_cleanclient(struct nfsclclient *clp) 1496 { 1497 struct nfsclowner *owp, *nowp; 1498 struct nfsclopen *op, *nop; 1499 struct nfscllockowner *lp, *nlp; 1500 1501 1502 /* get rid of defunct lockowners */ 1503 LIST_FOREACH_SAFE(lp, &clp->nfsc_defunctlockowner, nfsl_list, nlp) { 1504 nfscl_freelockowner(lp, 0); 1505 } 1506 1507 /* Now, all the OpenOwners, etc. */ 1508 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1509 LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) { 1510 nfscl_freeopen(op, 0); 1511 } 1512 nfscl_freeopenowner(owp, 0); 1513 } 1514 } 1515 1516 /* 1517 * Called when an NFSERR_EXPIRED is received from the server. 1518 */ 1519 static void 1520 nfscl_expireclient(struct nfsclclient *clp, struct nfsmount *nmp, 1521 struct ucred *cred, NFSPROC_T *p) 1522 { 1523 struct nfsclowner *owp, *nowp, *towp; 1524 struct nfsclopen *op, *nop, *top; 1525 struct nfscldeleg *dp, *ndp; 1526 int ret, printed = 0; 1527 1528 /* 1529 * First, merge locally issued Opens into the list for the server. 1530 */ 1531 dp = TAILQ_FIRST(&clp->nfsc_deleg); 1532 while (dp != NULL) { 1533 ndp = TAILQ_NEXT(dp, nfsdl_list); 1534 owp = LIST_FIRST(&dp->nfsdl_owner); 1535 while (owp != NULL) { 1536 nowp = LIST_NEXT(owp, nfsow_list); 1537 op = LIST_FIRST(&owp->nfsow_open); 1538 if (op != NULL) { 1539 if (LIST_NEXT(op, nfso_list) != NULL) 1540 panic("nfsclexp"); 1541 LIST_FOREACH(towp, &clp->nfsc_owner, nfsow_list) { 1542 if (!NFSBCMP(towp->nfsow_owner, owp->nfsow_owner, 1543 NFSV4CL_LOCKNAMELEN)) 1544 break; 1545 } 1546 if (towp != NULL) { 1547 /* Merge opens in */ 1548 LIST_FOREACH(top, &towp->nfsow_open, nfso_list) { 1549 if (top->nfso_fhlen == op->nfso_fhlen && 1550 !NFSBCMP(top->nfso_fh, op->nfso_fh, 1551 op->nfso_fhlen)) { 1552 top->nfso_mode |= op->nfso_mode; 1553 top->nfso_opencnt += op->nfso_opencnt; 1554 break; 1555 } 1556 } 1557 if (top == NULL) { 1558 /* Just add the open to the owner list */ 1559 LIST_REMOVE(op, nfso_list); 1560 op->nfso_own = towp; 1561 LIST_INSERT_HEAD(&towp->nfsow_open, op, nfso_list); 1562 newnfsstats.cllocalopens--; 1563 newnfsstats.clopens++; 1564 } 1565 } else { 1566 /* Just add the openowner to the client list */ 1567 LIST_REMOVE(owp, nfsow_list); 1568 owp->nfsow_clp = clp; 1569 LIST_INSERT_HEAD(&clp->nfsc_owner, owp, nfsow_list); 1570 newnfsstats.cllocalopenowners--; 1571 newnfsstats.clopenowners++; 1572 newnfsstats.cllocalopens--; 1573 newnfsstats.clopens++; 1574 } 1575 } 1576 owp = nowp; 1577 } 1578 if (!printed && !LIST_EMPTY(&dp->nfsdl_lock)) { 1579 printed = 1; 1580 printf("nfsv4 expired locks lost\n"); 1581 } 1582 nfscl_cleandeleg(dp); 1583 nfscl_freedeleg(&clp->nfsc_deleg, dp); 1584 dp = ndp; 1585 } 1586 if (!TAILQ_EMPTY(&clp->nfsc_deleg)) 1587 panic("nfsclexp"); 1588 1589 /* 1590 * Now, try and reopen against the server. 1591 */ 1592 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1593 owp->nfsow_seqid = 0; 1594 LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) { 1595 ret = nfscl_expireopen(clp, op, nmp, cred, p); 1596 if (ret && !printed) { 1597 printed = 1; 1598 printf("nfsv4 expired locks lost\n"); 1599 } 1600 } 1601 if (LIST_EMPTY(&owp->nfsow_open)) 1602 nfscl_freeopenowner(owp, 0); 1603 } 1604 } 1605 1606 #ifndef __FreeBSD__ 1607 /* 1608 * Called from exit() upon process termination. 1609 */ 1610 APPLESTATIC void 1611 nfscl_cleanup(NFSPROC_T *p) 1612 { 1613 struct nfsclclient *clp; 1614 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1615 1616 if (!nfscl_inited) 1617 return; 1618 nfscl_filllockowner(p, own); 1619 1620 NFSLOCKCLSTATE(); 1621 /* 1622 * Loop through all the clientids, looking for the OpenOwners. 1623 */ 1624 LIST_FOREACH(clp, &nfsclhead, nfsc_list) 1625 nfscl_cleanup_common(clp, own); 1626 NFSUNLOCKCLSTATE(); 1627 } 1628 #endif /* !__FreeBSD__ */ 1629 1630 /* 1631 * Common code used by nfscl_cleanup() and nfscl_cleanupkext(). 1632 * Must be called with CLSTATE lock held. 1633 */ 1634 static void 1635 nfscl_cleanup_common(struct nfsclclient *clp, u_int8_t *own) 1636 { 1637 struct nfsclowner *owp, *nowp; 1638 struct nfsclopen *op; 1639 struct nfscllockowner *lp, *nlp; 1640 struct nfscldeleg *dp; 1641 1642 /* First, get rid of local locks on delegations. */ 1643 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 1644 LIST_FOREACH_SAFE(lp, &dp->nfsdl_lock, nfsl_list, nlp) { 1645 if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) { 1646 if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED)) 1647 panic("nfscllckw"); 1648 nfscl_freelockowner(lp, 1); 1649 } 1650 } 1651 } 1652 owp = LIST_FIRST(&clp->nfsc_owner); 1653 while (owp != NULL) { 1654 nowp = LIST_NEXT(owp, nfsow_list); 1655 if (!NFSBCMP(owp->nfsow_owner, own, 1656 NFSV4CL_LOCKNAMELEN)) { 1657 /* 1658 * If there are children that haven't closed the 1659 * file descriptors yet, the opens will still be 1660 * here. For that case, let the renew thread clear 1661 * out the OpenOwner later. 1662 */ 1663 if (LIST_EMPTY(&owp->nfsow_open)) 1664 nfscl_freeopenowner(owp, 0); 1665 else 1666 owp->nfsow_defunct = 1; 1667 } else { 1668 /* look for lockowners on other opens */ 1669 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1670 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1671 if (!NFSBCMP(lp->nfsl_owner, own, 1672 NFSV4CL_LOCKNAMELEN)) 1673 lp->nfsl_defunct = 1; 1674 } 1675 } 1676 } 1677 owp = nowp; 1678 } 1679 1680 /* and check the defunct list */ 1681 LIST_FOREACH(lp, &clp->nfsc_defunctlockowner, nfsl_list) { 1682 if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) 1683 lp->nfsl_defunct = 1; 1684 } 1685 } 1686 1687 #if defined(APPLEKEXT) || defined(__FreeBSD__) 1688 /* 1689 * Simulate the call nfscl_cleanup() by looking for open owners associated 1690 * with processes that no longer exist, since a call to nfscl_cleanup() 1691 * can't be patched into exit(). 1692 */ 1693 static void 1694 nfscl_cleanupkext(struct nfsclclient *clp) 1695 { 1696 struct nfsclowner *owp, *nowp; 1697 struct nfscllockowner *lp; 1698 1699 NFSPROCLISTLOCK(); 1700 NFSLOCKCLSTATE(); 1701 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1702 if (nfscl_procdoesntexist(owp->nfsow_owner)) 1703 nfscl_cleanup_common(clp, owp->nfsow_owner); 1704 } 1705 1706 /* and check the defunct list */ 1707 LIST_FOREACH(lp, &clp->nfsc_defunctlockowner, nfsl_list) { 1708 if (nfscl_procdoesntexist(lp->nfsl_owner)) 1709 lp->nfsl_defunct = 1; 1710 } 1711 NFSUNLOCKCLSTATE(); 1712 NFSPROCLISTUNLOCK(); 1713 } 1714 #endif /* APPLEKEXT || __FreeBSD__ */ 1715 1716 /* 1717 * Called from nfs umount to free up the clientid. 1718 */ 1719 APPLESTATIC void 1720 nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p) 1721 { 1722 struct nfsclclient *clp; 1723 struct ucred *cred; 1724 int igotlock; 1725 1726 clp = nmp->nm_clp; 1727 if (clp != NULL) { 1728 if ((clp->nfsc_flags & NFSCLFLAGS_INITED) == 0) 1729 panic("nfscl umount"); 1730 1731 /* 1732 * First, handshake with the nfscl renew thread, to terminate 1733 * it. 1734 */ 1735 clp->nfsc_flags |= NFSCLFLAGS_UMOUNT; 1736 while (clp->nfsc_flags & NFSCLFLAGS_HASTHREAD) 1737 (void) tsleep((caddr_t)clp, PWAIT, "nfsclumnt", hz); 1738 1739 NFSLOCKCLSTATE(); 1740 do { 1741 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 1742 NFSCLSTATEMUTEXPTR); 1743 } while (!igotlock); 1744 NFSUNLOCKCLSTATE(); 1745 1746 /* 1747 * Free up all the state. It will expire on the server, but 1748 * maybe we should do a SetClientId/SetClientIdConfirm so 1749 * the server throws it away? 1750 */ 1751 LIST_REMOVE(clp, nfsc_list); 1752 nfscl_delegreturnall(clp, p); 1753 cred = newnfs_getcred(); 1754 (void) nfsrpc_setclient(nmp, clp, cred, p); 1755 nfscl_cleanclient(clp); 1756 nmp->nm_clp = NULL; 1757 NFSFREECRED(cred); 1758 FREE((caddr_t)clp, M_NFSCLCLIENT); 1759 } 1760 1761 } 1762 1763 /* 1764 * This function is called when a server replies with NFSERR_STALECLIENTID 1765 * or NFSERR_STALESTATEID. It traverses the clientid lists, doing Opens 1766 * and Locks with reclaim. If these fail, it deletes the corresponding state. 1767 */ 1768 static void 1769 nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) 1770 { 1771 struct nfsclowner *owp, *nowp; 1772 struct nfsclopen *op, *nop; 1773 struct nfscllockowner *lp, *nlp; 1774 struct nfscllock *lop, *nlop; 1775 struct nfscldeleg *dp, *ndp, *tdp; 1776 struct nfsmount *nmp; 1777 struct ucred *tcred; 1778 struct nfsclopenhead extra_open; 1779 struct nfscldeleghead extra_deleg; 1780 struct nfsreq *rep; 1781 u_int64_t len; 1782 u_int32_t delegtype = NFSV4OPEN_DELEGATEWRITE, mode; 1783 int igotlock = 0, error, trycnt, firstlock, s; 1784 1785 /* 1786 * First, lock the client structure, so everyone else will 1787 * block when trying to use state. 1788 */ 1789 NFSLOCKCLSTATE(); 1790 clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG; 1791 do { 1792 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 1793 NFSCLSTATEMUTEXPTR); 1794 } while (!igotlock); 1795 NFSUNLOCKCLSTATE(); 1796 1797 nmp = clp->nfsc_nmp; 1798 if (nmp == NULL) 1799 panic("nfscl recover"); 1800 trycnt = 5; 1801 do { 1802 error = nfsrpc_setclient(nmp, clp, cred, p); 1803 } while ((error == NFSERR_STALECLIENTID || 1804 error == NFSERR_STALEDONTRECOVER) && --trycnt > 0); 1805 if (error) { 1806 nfscl_cleanclient(clp); 1807 NFSLOCKCLSTATE(); 1808 clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID | 1809 NFSCLFLAGS_RECOVER | NFSCLFLAGS_RECVRINPROG); 1810 wakeup(&clp->nfsc_flags); 1811 nfsv4_unlock(&clp->nfsc_lock, 0); 1812 NFSUNLOCKCLSTATE(); 1813 return; 1814 } 1815 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 1816 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 1817 1818 /* 1819 * Mark requests already queued on the server, so that they don't 1820 * initiate another recovery cycle. Any requests already in the 1821 * queue that handle state information will have the old stale 1822 * clientid/stateid and will get a NFSERR_STALESTATEID or 1823 * NFSERR_STALECLIENTID reply from the server. This will be 1824 * translated to NFSERR_STALEDONTRECOVER when R_DONTRECOVER is set. 1825 */ 1826 s = splsoftclock(); 1827 NFSLOCKREQ(); 1828 TAILQ_FOREACH(rep, &nfsd_reqq, r_chain) { 1829 if (rep->r_nmp == nmp) 1830 rep->r_flags |= R_DONTRECOVER; 1831 } 1832 NFSUNLOCKREQ(); 1833 splx(s); 1834 1835 /* get rid of defunct lockowners */ 1836 LIST_FOREACH_SAFE(lp, &clp->nfsc_defunctlockowner, nfsl_list, nlp) { 1837 nfscl_freelockowner(lp, 0); 1838 } 1839 1840 /* 1841 * Now, mark all delegations "need reclaim". 1842 */ 1843 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) 1844 dp->nfsdl_flags |= NFSCLDL_NEEDRECLAIM; 1845 1846 TAILQ_INIT(&extra_deleg); 1847 LIST_INIT(&extra_open); 1848 /* 1849 * Now traverse the state lists, doing Open and Lock Reclaims. 1850 */ 1851 tcred = newnfs_getcred(); 1852 owp = LIST_FIRST(&clp->nfsc_owner); 1853 while (owp != NULL) { 1854 nowp = LIST_NEXT(owp, nfsow_list); 1855 owp->nfsow_seqid = 0; 1856 op = LIST_FIRST(&owp->nfsow_open); 1857 while (op != NULL) { 1858 nop = LIST_NEXT(op, nfso_list); 1859 if (error != NFSERR_NOGRACE) { 1860 /* Search for a delegation to reclaim with the open */ 1861 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 1862 if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) 1863 continue; 1864 if ((dp->nfsdl_flags & NFSCLDL_WRITE)) { 1865 mode = NFSV4OPEN_ACCESSWRITE; 1866 delegtype = NFSV4OPEN_DELEGATEWRITE; 1867 } else { 1868 mode = NFSV4OPEN_ACCESSREAD; 1869 delegtype = NFSV4OPEN_DELEGATEREAD; 1870 } 1871 if ((op->nfso_mode & mode) == mode && 1872 op->nfso_fhlen == dp->nfsdl_fhlen && 1873 !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, op->nfso_fhlen)) 1874 break; 1875 } 1876 ndp = dp; 1877 if (dp == NULL) 1878 delegtype = NFSV4OPEN_DELEGATENONE; 1879 newnfs_copycred(&op->nfso_cred, tcred); 1880 error = nfscl_tryopen(nmp, NULL, op->nfso_fh, 1881 op->nfso_fhlen, op->nfso_fh, op->nfso_fhlen, 1882 op->nfso_mode, op, NULL, 0, &ndp, 1, delegtype, 1883 tcred, p); 1884 if (!error) { 1885 /* Handle any replied delegation */ 1886 if (ndp != NULL && ((ndp->nfsdl_flags & NFSCLDL_WRITE) 1887 || NFSMNT_RDONLY(nmp->nm_mountp))) { 1888 if ((ndp->nfsdl_flags & NFSCLDL_WRITE)) 1889 mode = NFSV4OPEN_ACCESSWRITE; 1890 else 1891 mode = NFSV4OPEN_ACCESSREAD; 1892 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 1893 if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) 1894 continue; 1895 if ((op->nfso_mode & mode) == mode && 1896 op->nfso_fhlen == dp->nfsdl_fhlen && 1897 !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, 1898 op->nfso_fhlen)) { 1899 dp->nfsdl_stateid = ndp->nfsdl_stateid; 1900 dp->nfsdl_sizelimit = ndp->nfsdl_sizelimit; 1901 dp->nfsdl_ace = ndp->nfsdl_ace; 1902 dp->nfsdl_change = ndp->nfsdl_change; 1903 dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM; 1904 if ((ndp->nfsdl_flags & NFSCLDL_RECALL)) 1905 dp->nfsdl_flags |= NFSCLDL_RECALL; 1906 FREE((caddr_t)ndp, M_NFSCLDELEG); 1907 ndp = NULL; 1908 break; 1909 } 1910 } 1911 } 1912 if (ndp != NULL) 1913 TAILQ_INSERT_HEAD(&extra_deleg, ndp, nfsdl_list); 1914 1915 /* and reclaim all byte range locks */ 1916 lp = LIST_FIRST(&op->nfso_lock); 1917 while (lp != NULL) { 1918 nlp = LIST_NEXT(lp, nfsl_list); 1919 lp->nfsl_seqid = 0; 1920 firstlock = 1; 1921 lop = LIST_FIRST(&lp->nfsl_lock); 1922 while (lop != NULL) { 1923 nlop = LIST_NEXT(lop, nfslo_list); 1924 if (lop->nfslo_end == NFS64BITSSET) 1925 len = NFS64BITSSET; 1926 else 1927 len = lop->nfslo_end - lop->nfslo_first; 1928 if (error != NFSERR_NOGRACE) 1929 error = nfscl_trylock(nmp, NULL, 1930 op->nfso_fh, op->nfso_fhlen, lp, 1931 firstlock, 1, lop->nfslo_first, len, 1932 lop->nfslo_type, tcred, p); 1933 if (error != 0) 1934 nfscl_freelock(lop, 0); 1935 else 1936 firstlock = 0; 1937 lop = nlop; 1938 } 1939 /* If no locks, but a lockowner, just delete it. */ 1940 if (LIST_EMPTY(&lp->nfsl_lock)) 1941 nfscl_freelockowner(lp, 0); 1942 lp = nlp; 1943 } 1944 } else { 1945 nfscl_freeopen(op, 0); 1946 } 1947 } 1948 op = nop; 1949 } 1950 owp = nowp; 1951 } 1952 1953 /* 1954 * Now, try and get any delegations not yet reclaimed by cobbling 1955 * to-gether an appropriate open. 1956 */ 1957 nowp = NULL; 1958 dp = TAILQ_FIRST(&clp->nfsc_deleg); 1959 while (dp != NULL) { 1960 ndp = TAILQ_NEXT(dp, nfsdl_list); 1961 if ((dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) { 1962 if (nowp == NULL) { 1963 MALLOC(nowp, struct nfsclowner *, 1964 sizeof (struct nfsclowner), M_NFSCLOWNER, M_WAITOK); 1965 /* 1966 * Name must be as long an largest possible 1967 * NFSV4CL_LOCKNAMELEN. 12 for now. 1968 */ 1969 NFSBCOPY("RECLAIMDELEG", nowp->nfsow_owner, 1970 NFSV4CL_LOCKNAMELEN); 1971 LIST_INIT(&nowp->nfsow_open); 1972 nowp->nfsow_clp = clp; 1973 nowp->nfsow_seqid = 0; 1974 nowp->nfsow_defunct = 0; 1975 nfscl_lockinit(&nowp->nfsow_rwlock); 1976 } 1977 nop = NULL; 1978 if (error != NFSERR_NOGRACE) { 1979 MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) + 1980 dp->nfsdl_fhlen - 1, M_NFSCLOPEN, M_WAITOK); 1981 nop->nfso_own = nowp; 1982 if ((dp->nfsdl_flags & NFSCLDL_WRITE)) { 1983 nop->nfso_mode = NFSV4OPEN_ACCESSWRITE; 1984 delegtype = NFSV4OPEN_DELEGATEWRITE; 1985 } else { 1986 nop->nfso_mode = NFSV4OPEN_ACCESSREAD; 1987 delegtype = NFSV4OPEN_DELEGATEREAD; 1988 } 1989 nop->nfso_opencnt = 0; 1990 nop->nfso_posixlock = 1; 1991 nop->nfso_fhlen = dp->nfsdl_fhlen; 1992 NFSBCOPY(dp->nfsdl_fh, nop->nfso_fh, dp->nfsdl_fhlen); 1993 LIST_INIT(&nop->nfso_lock); 1994 nop->nfso_stateid.seqid = 0; 1995 nop->nfso_stateid.other[0] = 0; 1996 nop->nfso_stateid.other[1] = 0; 1997 nop->nfso_stateid.other[2] = 0; 1998 newnfs_copycred(&dp->nfsdl_cred, tcred); 1999 newnfs_copyincred(tcred, &nop->nfso_cred); 2000 tdp = NULL; 2001 error = nfscl_tryopen(nmp, NULL, nop->nfso_fh, 2002 nop->nfso_fhlen, nop->nfso_fh, nop->nfso_fhlen, 2003 nop->nfso_mode, nop, NULL, 0, &tdp, 1, 2004 delegtype, tcred, p); 2005 if (tdp != NULL) { 2006 if ((tdp->nfsdl_flags & NFSCLDL_WRITE)) 2007 mode = NFSV4OPEN_ACCESSWRITE; 2008 else 2009 mode = NFSV4OPEN_ACCESSREAD; 2010 if ((nop->nfso_mode & mode) == mode && 2011 nop->nfso_fhlen == tdp->nfsdl_fhlen && 2012 !NFSBCMP(nop->nfso_fh, tdp->nfsdl_fh, 2013 nop->nfso_fhlen)) { 2014 dp->nfsdl_stateid = tdp->nfsdl_stateid; 2015 dp->nfsdl_sizelimit = tdp->nfsdl_sizelimit; 2016 dp->nfsdl_ace = tdp->nfsdl_ace; 2017 dp->nfsdl_change = tdp->nfsdl_change; 2018 dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM; 2019 if ((tdp->nfsdl_flags & NFSCLDL_RECALL)) 2020 dp->nfsdl_flags |= NFSCLDL_RECALL; 2021 FREE((caddr_t)tdp, M_NFSCLDELEG); 2022 } else { 2023 TAILQ_INSERT_HEAD(&extra_deleg, tdp, nfsdl_list); 2024 } 2025 } 2026 } 2027 if (error) { 2028 if (nop != NULL) 2029 FREE((caddr_t)nop, M_NFSCLOPEN); 2030 /* 2031 * Couldn't reclaim it, so throw the state 2032 * away. Ouch!! 2033 */ 2034 nfscl_cleandeleg(dp); 2035 nfscl_freedeleg(&clp->nfsc_deleg, dp); 2036 } else { 2037 LIST_INSERT_HEAD(&extra_open, nop, nfso_list); 2038 } 2039 } 2040 dp = ndp; 2041 } 2042 2043 /* 2044 * Now, get rid of extra Opens and Delegations. 2045 */ 2046 LIST_FOREACH_SAFE(op, &extra_open, nfso_list, nop) { 2047 do { 2048 newnfs_copycred(&op->nfso_cred, tcred); 2049 error = nfscl_tryclose(op, tcred, nmp, p); 2050 if (error == NFSERR_GRACE) 2051 (void) nfs_catnap(PZERO, error, "nfsexcls"); 2052 } while (error == NFSERR_GRACE); 2053 LIST_REMOVE(op, nfso_list); 2054 FREE((caddr_t)op, M_NFSCLOPEN); 2055 } 2056 if (nowp != NULL) 2057 FREE((caddr_t)nowp, M_NFSCLOWNER); 2058 2059 TAILQ_FOREACH_SAFE(dp, &extra_deleg, nfsdl_list, ndp) { 2060 do { 2061 newnfs_copycred(&dp->nfsdl_cred, tcred); 2062 error = nfscl_trydelegreturn(dp, tcred, nmp, p); 2063 if (error == NFSERR_GRACE) 2064 (void) nfs_catnap(PZERO, error, "nfsexdlg"); 2065 } while (error == NFSERR_GRACE); 2066 TAILQ_REMOVE(&extra_deleg, dp, nfsdl_list); 2067 FREE((caddr_t)dp, M_NFSCLDELEG); 2068 } 2069 2070 NFSLOCKCLSTATE(); 2071 clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG; 2072 wakeup(&clp->nfsc_flags); 2073 nfsv4_unlock(&clp->nfsc_lock, 0); 2074 NFSUNLOCKCLSTATE(); 2075 NFSFREECRED(tcred); 2076 } 2077 2078 /* 2079 * This function is called when a server replies with NFSERR_EXPIRED. 2080 * It deletes all state for the client and does a fresh SetClientId/confirm. 2081 * XXX Someday it should post a signal to the process(es) that hold the 2082 * state, so they know that lock state has been lost. 2083 */ 2084 APPLESTATIC int 2085 nfscl_hasexpired(struct nfsclclient *clp, u_int32_t clidrev, NFSPROC_T *p) 2086 { 2087 struct nfscllockowner *lp, *nlp; 2088 struct nfsmount *nmp; 2089 struct ucred *cred; 2090 int igotlock = 0, error, trycnt; 2091 2092 /* 2093 * If the clientid has gone away or a new SetClientid has already 2094 * been done, just return ok. 2095 */ 2096 if (clp == NULL || clidrev != clp->nfsc_clientidrev) 2097 return (0); 2098 2099 /* 2100 * First, lock the client structure, so everyone else will 2101 * block when trying to use state. Also, use NFSCLFLAGS_EXPIREIT so 2102 * that only one thread does the work. 2103 */ 2104 NFSLOCKCLSTATE(); 2105 clp->nfsc_flags |= NFSCLFLAGS_EXPIREIT; 2106 do { 2107 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 2108 NFSCLSTATEMUTEXPTR); 2109 } while (!igotlock && (clp->nfsc_flags & NFSCLFLAGS_EXPIREIT)); 2110 if ((clp->nfsc_flags & NFSCLFLAGS_EXPIREIT) == 0) { 2111 if (igotlock) 2112 nfsv4_unlock(&clp->nfsc_lock, 0); 2113 NFSUNLOCKCLSTATE(); 2114 return (0); 2115 } 2116 clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG; 2117 NFSUNLOCKCLSTATE(); 2118 2119 nmp = clp->nfsc_nmp; 2120 if (nmp == NULL) 2121 panic("nfscl expired"); 2122 cred = newnfs_getcred(); 2123 trycnt = 5; 2124 do { 2125 error = nfsrpc_setclient(nmp, clp, cred, p); 2126 } while ((error == NFSERR_STALECLIENTID || 2127 error == NFSERR_STALEDONTRECOVER) && --trycnt > 0); 2128 if (error) { 2129 /* 2130 * Clear out any state. 2131 */ 2132 nfscl_cleanclient(clp); 2133 NFSLOCKCLSTATE(); 2134 clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID | 2135 NFSCLFLAGS_RECOVER); 2136 } else { 2137 /* get rid of defunct lockowners */ 2138 LIST_FOREACH_SAFE(lp, &clp->nfsc_defunctlockowner, nfsl_list, 2139 nlp) { 2140 nfscl_freelockowner(lp, 0); 2141 } 2142 2143 /* 2144 * Expire the state for the client. 2145 */ 2146 nfscl_expireclient(clp, nmp, cred, p); 2147 NFSLOCKCLSTATE(); 2148 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 2149 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 2150 } 2151 clp->nfsc_flags &= ~(NFSCLFLAGS_EXPIREIT | NFSCLFLAGS_RECVRINPROG); 2152 wakeup(&clp->nfsc_flags); 2153 nfsv4_unlock(&clp->nfsc_lock, 0); 2154 NFSUNLOCKCLSTATE(); 2155 NFSFREECRED(cred); 2156 return (error); 2157 } 2158 2159 /* 2160 * This function inserts a lock in the list after insert_lop. 2161 */ 2162 static void 2163 nfscl_insertlock(struct nfscllockowner *lp, struct nfscllock *new_lop, 2164 struct nfscllock *insert_lop, int local) 2165 { 2166 2167 if ((struct nfscllockowner *)insert_lop == lp) 2168 LIST_INSERT_HEAD(&lp->nfsl_lock, new_lop, nfslo_list); 2169 else 2170 LIST_INSERT_AFTER(insert_lop, new_lop, nfslo_list); 2171 if (local) 2172 newnfsstats.cllocallocks++; 2173 else 2174 newnfsstats.cllocks++; 2175 } 2176 2177 /* 2178 * This function updates the locking for a lock owner and given file. It 2179 * maintains a list of lock ranges ordered on increasing file offset that 2180 * are NFSCLLOCK_READ or NFSCLLOCK_WRITE and non-overlapping (aka POSIX style). 2181 * It always adds new_lop to the list and sometimes uses the one pointed 2182 * at by other_lopp. 2183 * Returns 1 if the locks were modified, 0 otherwise. 2184 */ 2185 static int 2186 nfscl_updatelock(struct nfscllockowner *lp, struct nfscllock **new_lopp, 2187 struct nfscllock **other_lopp, int local) 2188 { 2189 struct nfscllock *new_lop = *new_lopp; 2190 struct nfscllock *lop, *tlop, *ilop; 2191 struct nfscllock *other_lop; 2192 int unlock = 0, modified = 0; 2193 u_int64_t tmp; 2194 2195 /* 2196 * Work down the list until the lock is merged. 2197 */ 2198 if (new_lop->nfslo_type == F_UNLCK) 2199 unlock = 1; 2200 ilop = (struct nfscllock *)lp; 2201 lop = LIST_FIRST(&lp->nfsl_lock); 2202 while (lop != NULL) { 2203 /* 2204 * Only check locks for this file that aren't before the start of 2205 * new lock's range. 2206 */ 2207 if (lop->nfslo_end >= new_lop->nfslo_first) { 2208 if (new_lop->nfslo_end < lop->nfslo_first) { 2209 /* 2210 * If the new lock ends before the start of the 2211 * current lock's range, no merge, just insert 2212 * the new lock. 2213 */ 2214 break; 2215 } 2216 if (new_lop->nfslo_type == lop->nfslo_type || 2217 (new_lop->nfslo_first <= lop->nfslo_first && 2218 new_lop->nfslo_end >= lop->nfslo_end)) { 2219 /* 2220 * This lock can be absorbed by the new lock/unlock. 2221 * This happens when it covers the entire range 2222 * of the old lock or is contiguous 2223 * with the old lock and is of the same type or an 2224 * unlock. 2225 */ 2226 if (new_lop->nfslo_type != lop->nfslo_type || 2227 new_lop->nfslo_first != lop->nfslo_first || 2228 new_lop->nfslo_end != lop->nfslo_end) 2229 modified = 1; 2230 if (lop->nfslo_first < new_lop->nfslo_first) 2231 new_lop->nfslo_first = lop->nfslo_first; 2232 if (lop->nfslo_end > new_lop->nfslo_end) 2233 new_lop->nfslo_end = lop->nfslo_end; 2234 tlop = lop; 2235 lop = LIST_NEXT(lop, nfslo_list); 2236 nfscl_freelock(tlop, local); 2237 continue; 2238 } 2239 2240 /* 2241 * All these cases are for contiguous locks that are not the 2242 * same type, so they can't be merged. 2243 */ 2244 if (new_lop->nfslo_first <= lop->nfslo_first) { 2245 /* 2246 * This case is where the new lock overlaps with the 2247 * first part of the old lock. Move the start of the 2248 * old lock to just past the end of the new lock. The 2249 * new lock will be inserted in front of the old, since 2250 * ilop hasn't been updated. (We are done now.) 2251 */ 2252 if (lop->nfslo_first != new_lop->nfslo_end) { 2253 lop->nfslo_first = new_lop->nfslo_end; 2254 modified = 1; 2255 } 2256 break; 2257 } 2258 if (new_lop->nfslo_end >= lop->nfslo_end) { 2259 /* 2260 * This case is where the new lock overlaps with the 2261 * end of the old lock's range. Move the old lock's 2262 * end to just before the new lock's first and insert 2263 * the new lock after the old lock. 2264 * Might not be done yet, since the new lock could 2265 * overlap further locks with higher ranges. 2266 */ 2267 if (lop->nfslo_end != new_lop->nfslo_first) { 2268 lop->nfslo_end = new_lop->nfslo_first; 2269 modified = 1; 2270 } 2271 ilop = lop; 2272 lop = LIST_NEXT(lop, nfslo_list); 2273 continue; 2274 } 2275 /* 2276 * The final case is where the new lock's range is in the 2277 * middle of the current lock's and splits the current lock 2278 * up. Use *other_lopp to handle the second part of the 2279 * split old lock range. (We are done now.) 2280 * For unlock, we use new_lop as other_lop and tmp, since 2281 * other_lop and new_lop are the same for this case. 2282 * We noted the unlock case above, so we don't need 2283 * new_lop->nfslo_type any longer. 2284 */ 2285 tmp = new_lop->nfslo_first; 2286 if (unlock) { 2287 other_lop = new_lop; 2288 *new_lopp = NULL; 2289 } else { 2290 other_lop = *other_lopp; 2291 *other_lopp = NULL; 2292 } 2293 other_lop->nfslo_first = new_lop->nfslo_end; 2294 other_lop->nfslo_end = lop->nfslo_end; 2295 other_lop->nfslo_type = lop->nfslo_type; 2296 lop->nfslo_end = tmp; 2297 nfscl_insertlock(lp, other_lop, lop, local); 2298 ilop = lop; 2299 modified = 1; 2300 break; 2301 } 2302 ilop = lop; 2303 lop = LIST_NEXT(lop, nfslo_list); 2304 if (lop == NULL) 2305 break; 2306 } 2307 2308 /* 2309 * Insert the new lock in the list at the appropriate place. 2310 */ 2311 if (!unlock) { 2312 nfscl_insertlock(lp, new_lop, ilop, local); 2313 *new_lopp = NULL; 2314 modified = 1; 2315 } 2316 return (modified); 2317 } 2318 2319 /* 2320 * This function must be run as a kernel thread. 2321 * It does Renew Ops and recovery, when required. 2322 */ 2323 APPLESTATIC void 2324 nfscl_renewthread(struct nfsclclient *clp, NFSPROC_T *p) 2325 { 2326 struct nfsclowner *owp, *nowp; 2327 struct nfsclopen *op; 2328 struct nfscllockowner *lp, *nlp, *olp; 2329 struct nfscldeleghead dh; 2330 struct nfscllockownerhead lh; 2331 struct nfscldeleg *dp, *ndp; 2332 struct ucred *cred; 2333 u_int32_t clidrev; 2334 int error, cbpathdown, islept, igotlock, ret, clearok; 2335 uint32_t recover_done_time = 0; 2336 2337 cred = newnfs_getcred(); 2338 NFSLOCKCLSTATE(); 2339 clp->nfsc_flags |= NFSCLFLAGS_HASTHREAD; 2340 NFSUNLOCKCLSTATE(); 2341 for(;;) { 2342 newnfs_setroot(cred); 2343 cbpathdown = 0; 2344 if (clp->nfsc_flags & NFSCLFLAGS_RECOVER) { 2345 /* 2346 * Only allow one recover within 1/2 of the lease 2347 * duration (nfsc_renew). 2348 */ 2349 if (recover_done_time < NFSD_MONOSEC) { 2350 recover_done_time = NFSD_MONOSEC + 2351 clp->nfsc_renew; 2352 nfscl_recover(clp, cred, p); 2353 } else { 2354 NFSLOCKCLSTATE(); 2355 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 2356 NFSUNLOCKCLSTATE(); 2357 } 2358 } 2359 if (clp->nfsc_expire <= NFSD_MONOSEC && 2360 (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) { 2361 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 2362 clidrev = clp->nfsc_clientidrev; 2363 error = nfsrpc_renew(clp, cred, p); 2364 if (error == NFSERR_CBPATHDOWN) 2365 cbpathdown = 1; 2366 else if (error == NFSERR_STALECLIENTID) { 2367 NFSLOCKCLSTATE(); 2368 clp->nfsc_flags |= NFSCLFLAGS_RECOVER; 2369 NFSUNLOCKCLSTATE(); 2370 } else if (error == NFSERR_EXPIRED) 2371 (void) nfscl_hasexpired(clp, clidrev, p); 2372 } 2373 2374 LIST_INIT(&lh); 2375 TAILQ_INIT(&dh); 2376 NFSLOCKCLSTATE(); 2377 if (cbpathdown) 2378 /* It's a Total Recall! */ 2379 nfscl_totalrecall(clp); 2380 2381 /* 2382 * Now, handle defunct owners. 2383 */ 2384 owp = LIST_FIRST(&clp->nfsc_owner); 2385 while (owp != NULL) { 2386 nowp = LIST_NEXT(owp, nfsow_list); 2387 if (LIST_EMPTY(&owp->nfsow_open)) { 2388 if (owp->nfsow_defunct) 2389 nfscl_freeopenowner(owp, 0); 2390 } else { 2391 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2392 lp = LIST_FIRST(&op->nfso_lock); 2393 while (lp != NULL) { 2394 nlp = LIST_NEXT(lp, nfsl_list); 2395 if (lp->nfsl_defunct && 2396 LIST_EMPTY(&lp->nfsl_lock)) { 2397 LIST_FOREACH(olp, &lh, nfsl_list) { 2398 if (!NFSBCMP(olp->nfsl_owner, 2399 lp->nfsl_owner,NFSV4CL_LOCKNAMELEN)) 2400 break; 2401 } 2402 if (olp == NULL) { 2403 LIST_REMOVE(lp, nfsl_list); 2404 LIST_INSERT_HEAD(&lh, lp, nfsl_list); 2405 } else { 2406 nfscl_freelockowner(lp, 0); 2407 } 2408 } 2409 lp = nlp; 2410 } 2411 } 2412 } 2413 owp = nowp; 2414 } 2415 2416 /* also search the defunct list */ 2417 lp = LIST_FIRST(&clp->nfsc_defunctlockowner); 2418 while (lp != NULL) { 2419 nlp = LIST_NEXT(lp, nfsl_list); 2420 if (lp->nfsl_defunct) { 2421 LIST_FOREACH(olp, &lh, nfsl_list) { 2422 if (!NFSBCMP(olp->nfsl_owner, lp->nfsl_owner, 2423 NFSV4CL_LOCKNAMELEN)) 2424 break; 2425 } 2426 if (olp == NULL) { 2427 LIST_REMOVE(lp, nfsl_list); 2428 LIST_INSERT_HEAD(&lh, lp, nfsl_list); 2429 } else { 2430 nfscl_freelockowner(lp, 0); 2431 } 2432 } 2433 lp = nlp; 2434 } 2435 /* and release defunct lock owners */ 2436 LIST_FOREACH_SAFE(lp, &lh, nfsl_list, nlp) { 2437 nfscl_freelockowner(lp, 0); 2438 } 2439 2440 /* 2441 * Do the recall on any delegations. To avoid trouble, always 2442 * come back up here after having slept. 2443 */ 2444 igotlock = 0; 2445 tryagain: 2446 dp = TAILQ_FIRST(&clp->nfsc_deleg); 2447 while (dp != NULL) { 2448 ndp = TAILQ_NEXT(dp, nfsdl_list); 2449 if ((dp->nfsdl_flags & NFSCLDL_RECALL)) { 2450 /* 2451 * Wait for outstanding I/O ops to be done. 2452 */ 2453 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 2454 if (igotlock) { 2455 nfsv4_unlock(&clp->nfsc_lock, 0); 2456 igotlock = 0; 2457 } 2458 dp->nfsdl_rwlock.nfslock_lock |= 2459 NFSV4LOCK_WANTED; 2460 (void) nfsmsleep(&dp->nfsdl_rwlock, 2461 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", 2462 NULL); 2463 goto tryagain; 2464 } 2465 while (!igotlock) { 2466 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 2467 &islept, NFSCLSTATEMUTEXPTR); 2468 if (islept) 2469 goto tryagain; 2470 } 2471 NFSUNLOCKCLSTATE(); 2472 newnfs_copycred(&dp->nfsdl_cred, cred); 2473 ret = nfscl_recalldeleg(clp, clp->nfsc_nmp, dp, 2474 NULL, cred, p, 1); 2475 if (!ret) { 2476 nfscl_cleandeleg(dp); 2477 TAILQ_REMOVE(&clp->nfsc_deleg, dp, 2478 nfsdl_list); 2479 LIST_REMOVE(dp, nfsdl_hash); 2480 TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list); 2481 nfscl_delegcnt--; 2482 newnfsstats.cldelegates--; 2483 } 2484 NFSLOCKCLSTATE(); 2485 } 2486 dp = ndp; 2487 } 2488 2489 /* 2490 * Clear out old delegations, if we are above the high water 2491 * mark. Only clear out ones with no state related to them. 2492 * The tailq list is in LRU order. 2493 */ 2494 dp = TAILQ_LAST(&clp->nfsc_deleg, nfscldeleghead); 2495 while (nfscl_delegcnt > nfscl_deleghighwater && dp != NULL) { 2496 ndp = TAILQ_PREV(dp, nfscldeleghead, nfsdl_list); 2497 if (dp->nfsdl_rwlock.nfslock_usecnt == 0 && 2498 dp->nfsdl_rwlock.nfslock_lock == 0 && 2499 dp->nfsdl_timestamp < NFSD_MONOSEC && 2500 (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_ZAPPED | 2501 NFSCLDL_NEEDRECLAIM | NFSCLDL_DELEGRET)) == 0) { 2502 clearok = 1; 2503 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 2504 op = LIST_FIRST(&owp->nfsow_open); 2505 if (op != NULL) { 2506 clearok = 0; 2507 break; 2508 } 2509 } 2510 if (clearok) { 2511 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 2512 if (!LIST_EMPTY(&lp->nfsl_lock)) { 2513 clearok = 0; 2514 break; 2515 } 2516 } 2517 } 2518 if (clearok) { 2519 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 2520 LIST_REMOVE(dp, nfsdl_hash); 2521 TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list); 2522 nfscl_delegcnt--; 2523 newnfsstats.cldelegates--; 2524 } 2525 } 2526 dp = ndp; 2527 } 2528 if (igotlock) 2529 nfsv4_unlock(&clp->nfsc_lock, 0); 2530 NFSUNLOCKCLSTATE(); 2531 2532 /* 2533 * Delegreturn any delegations cleaned out or recalled. 2534 */ 2535 TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) { 2536 newnfs_copycred(&dp->nfsdl_cred, cred); 2537 (void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); 2538 TAILQ_REMOVE(&dh, dp, nfsdl_list); 2539 FREE((caddr_t)dp, M_NFSCLDELEG); 2540 } 2541 2542 #if defined(APPLEKEXT) || defined(__FreeBSD__) 2543 /* 2544 * Simulate the calls to nfscl_cleanup() when a process 2545 * exits, since the call can't be patched into exit(). 2546 */ 2547 { 2548 struct timespec mytime; 2549 static time_t prevsec = 0; 2550 2551 NFSGETNANOTIME(&mytime); 2552 if (prevsec != mytime.tv_sec) { 2553 prevsec = mytime.tv_sec; 2554 nfscl_cleanupkext(clp); 2555 } 2556 } 2557 #endif /* APPLEKEXT || __FreeBSD__ */ 2558 2559 if ((clp->nfsc_flags & NFSCLFLAGS_RECOVER) == 0) 2560 (void) tsleep((caddr_t)clp, PWAIT, "nfscl", hz); 2561 if (clp->nfsc_flags & NFSCLFLAGS_UMOUNT) { 2562 NFSFREECRED(cred); 2563 clp->nfsc_flags &= ~NFSCLFLAGS_HASTHREAD; 2564 wakeup((caddr_t)clp); 2565 return; 2566 } 2567 } 2568 } 2569 2570 /* 2571 * Initiate state recovery. Called when NFSERR_STALECLIENTID or 2572 * NFSERR_STALESTATEID is received. 2573 */ 2574 APPLESTATIC void 2575 nfscl_initiate_recovery(struct nfsclclient *clp) 2576 { 2577 2578 if (clp == NULL) 2579 return; 2580 NFSLOCKCLSTATE(); 2581 clp->nfsc_flags |= NFSCLFLAGS_RECOVER; 2582 NFSUNLOCKCLSTATE(); 2583 wakeup((caddr_t)clp); 2584 } 2585 2586 /* 2587 * Dump out the state stuff for debugging. 2588 */ 2589 APPLESTATIC void 2590 nfscl_dumpstate(struct nfsmount *nmp, int openowner, int opens, 2591 int lockowner, int locks) 2592 { 2593 struct nfsclclient *clp; 2594 struct nfsclowner *owp; 2595 struct nfsclopen *op; 2596 struct nfscllockowner *lp; 2597 struct nfscllock *lop; 2598 struct nfscldeleg *dp; 2599 2600 clp = nmp->nm_clp; 2601 if (clp == NULL) { 2602 printf("nfscl dumpstate NULL clp\n"); 2603 return; 2604 } 2605 NFSLOCKCLSTATE(); 2606 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 2607 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 2608 if (openowner && !LIST_EMPTY(&owp->nfsow_open)) 2609 printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n", 2610 owp->nfsow_owner[0], owp->nfsow_owner[1], 2611 owp->nfsow_owner[2], owp->nfsow_owner[3], 2612 owp->nfsow_seqid); 2613 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2614 if (opens) 2615 printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n", 2616 op->nfso_stateid.other[0], op->nfso_stateid.other[1], 2617 op->nfso_stateid.other[2], op->nfso_opencnt, 2618 op->nfso_fh[12]); 2619 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 2620 if (lockowner) 2621 printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n", 2622 lp->nfsl_owner[0], lp->nfsl_owner[1], 2623 lp->nfsl_owner[2], lp->nfsl_owner[3], 2624 lp->nfsl_seqid, 2625 lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1], 2626 lp->nfsl_stateid.other[2]); 2627 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 2628 if (locks) 2629 #ifdef __FreeBSD__ 2630 printf("lck typ=%d fst=%ju end=%ju\n", 2631 lop->nfslo_type, (intmax_t)lop->nfslo_first, 2632 (intmax_t)lop->nfslo_end); 2633 #else 2634 printf("lck typ=%d fst=%qd end=%qd\n", 2635 lop->nfslo_type, lop->nfslo_first, 2636 lop->nfslo_end); 2637 #endif 2638 } 2639 } 2640 } 2641 } 2642 } 2643 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2644 if (openowner && !LIST_EMPTY(&owp->nfsow_open)) 2645 printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n", 2646 owp->nfsow_owner[0], owp->nfsow_owner[1], 2647 owp->nfsow_owner[2], owp->nfsow_owner[3], 2648 owp->nfsow_seqid); 2649 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2650 if (opens) 2651 printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n", 2652 op->nfso_stateid.other[0], op->nfso_stateid.other[1], 2653 op->nfso_stateid.other[2], op->nfso_opencnt, 2654 op->nfso_fh[12]); 2655 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 2656 if (lockowner) 2657 printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n", 2658 lp->nfsl_owner[0], lp->nfsl_owner[1], 2659 lp->nfsl_owner[2], lp->nfsl_owner[3], 2660 lp->nfsl_seqid, 2661 lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1], 2662 lp->nfsl_stateid.other[2]); 2663 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 2664 if (locks) 2665 #ifdef __FreeBSD__ 2666 printf("lck typ=%d fst=%ju end=%ju\n", 2667 lop->nfslo_type, (intmax_t)lop->nfslo_first, 2668 (intmax_t)lop->nfslo_end); 2669 #else 2670 printf("lck typ=%d fst=%qd end=%qd\n", 2671 lop->nfslo_type, lop->nfslo_first, 2672 lop->nfslo_end); 2673 #endif 2674 } 2675 } 2676 } 2677 } 2678 NFSUNLOCKCLSTATE(); 2679 } 2680 2681 /* 2682 * Check for duplicate open owners and opens. 2683 * (Only used as a diagnostic aid.) 2684 */ 2685 APPLESTATIC void 2686 nfscl_dupopen(vnode_t vp, int dupopens) 2687 { 2688 struct nfsclclient *clp; 2689 struct nfsclowner *owp, *owp2; 2690 struct nfsclopen *op, *op2; 2691 struct nfsfh *nfhp; 2692 2693 clp = VFSTONFS(vnode_mount(vp))->nm_clp; 2694 if (clp == NULL) { 2695 printf("nfscl dupopen NULL clp\n"); 2696 return; 2697 } 2698 nfhp = VTONFS(vp)->n_fhp; 2699 NFSLOCKCLSTATE(); 2700 2701 /* 2702 * First, search for duplicate owners. 2703 * These should never happen! 2704 */ 2705 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 2706 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2707 if (owp != owp2 && 2708 !NFSBCMP(owp->nfsow_owner, owp2->nfsow_owner, 2709 NFSV4CL_LOCKNAMELEN)) { 2710 NFSUNLOCKCLSTATE(); 2711 printf("DUP OWNER\n"); 2712 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 0); 2713 return; 2714 } 2715 } 2716 } 2717 2718 /* 2719 * Now, search for duplicate stateids. 2720 * These shouldn't happen, either. 2721 */ 2722 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 2723 LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) { 2724 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2725 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2726 if (op != op2 && 2727 (op->nfso_stateid.other[0] != 0 || 2728 op->nfso_stateid.other[1] != 0 || 2729 op->nfso_stateid.other[2] != 0) && 2730 op->nfso_stateid.other[0] == op2->nfso_stateid.other[0] && 2731 op->nfso_stateid.other[1] == op2->nfso_stateid.other[1] && 2732 op->nfso_stateid.other[2] == op2->nfso_stateid.other[2]) { 2733 NFSUNLOCKCLSTATE(); 2734 printf("DUP STATEID\n"); 2735 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 2736 0); 2737 return; 2738 } 2739 } 2740 } 2741 } 2742 } 2743 2744 /* 2745 * Now search for duplicate opens. 2746 * Duplicate opens for the same owner 2747 * should never occur. Other duplicates are 2748 * possible and are checked for if "dupopens" 2749 * is true. 2750 */ 2751 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 2752 LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) { 2753 if (nfhp->nfh_len == op2->nfso_fhlen && 2754 !NFSBCMP(nfhp->nfh_fh, op2->nfso_fh, nfhp->nfh_len)) { 2755 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2756 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2757 if (op != op2 && nfhp->nfh_len == op->nfso_fhlen && 2758 !NFSBCMP(nfhp->nfh_fh, op->nfso_fh, nfhp->nfh_len) && 2759 (!NFSBCMP(op->nfso_own->nfsow_owner, 2760 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN) || 2761 dupopens)) { 2762 if (!NFSBCMP(op->nfso_own->nfsow_owner, 2763 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN)) { 2764 NFSUNLOCKCLSTATE(); 2765 printf("BADDUP OPEN\n"); 2766 } else { 2767 NFSUNLOCKCLSTATE(); 2768 printf("DUP OPEN\n"); 2769 } 2770 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 2771 0, 0); 2772 return; 2773 } 2774 } 2775 } 2776 } 2777 } 2778 } 2779 NFSUNLOCKCLSTATE(); 2780 } 2781 2782 /* 2783 * During close, find an open that needs to be dereferenced and 2784 * dereference it. If there are no more opens for this file, 2785 * log a message to that effect. 2786 * Opens aren't actually Close'd until VOP_INACTIVE() is performed 2787 * on the file's vnode. 2788 * This is the safe way, since it is difficult to identify 2789 * which open the close is for and I/O can be performed after the 2790 * close(2) system call when a file is mmap'd. 2791 * If it returns 0 for success, there will be a referenced 2792 * clp returned via clpp. 2793 */ 2794 APPLESTATIC int 2795 nfscl_getclose(vnode_t vp, struct nfsclclient **clpp) 2796 { 2797 struct nfsclclient *clp; 2798 struct nfsclowner *owp; 2799 struct nfsclopen *op; 2800 struct nfscldeleg *dp; 2801 struct nfsfh *nfhp; 2802 int error, notdecr; 2803 2804 error = nfscl_getcl(vp, NULL, NULL, &clp); 2805 if (error) 2806 return (error); 2807 *clpp = clp; 2808 2809 nfhp = VTONFS(vp)->n_fhp; 2810 notdecr = 1; 2811 NFSLOCKCLSTATE(); 2812 /* 2813 * First, look for one under a delegation that was locally issued 2814 * and just decrement the opencnt for it. Since all my Opens against 2815 * the server are DENY_NONE, I don't see a problem with hanging 2816 * onto them. (It is much easier to use one of the extant Opens 2817 * that I already have on the server when a Delegation is recalled 2818 * than to do fresh Opens.) Someday, I might need to rethink this, but. 2819 */ 2820 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); 2821 if (dp != NULL) { 2822 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 2823 op = LIST_FIRST(&owp->nfsow_open); 2824 if (op != NULL) { 2825 /* 2826 * Since a delegation is for a file, there 2827 * should never be more than one open for 2828 * each openowner. 2829 */ 2830 if (LIST_NEXT(op, nfso_list) != NULL) 2831 panic("nfscdeleg opens"); 2832 if (notdecr && op->nfso_opencnt > 0) { 2833 notdecr = 0; 2834 op->nfso_opencnt--; 2835 break; 2836 } 2837 } 2838 } 2839 } 2840 2841 /* Now process the opens against the server. */ 2842 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2843 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2844 if (op->nfso_fhlen == nfhp->nfh_len && 2845 !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, 2846 nfhp->nfh_len)) { 2847 /* Found an open, decrement cnt if possible */ 2848 if (notdecr && op->nfso_opencnt > 0) { 2849 notdecr = 0; 2850 op->nfso_opencnt--; 2851 } 2852 /* 2853 * There are more opens, so just return. 2854 */ 2855 if (op->nfso_opencnt > 0) { 2856 NFSUNLOCKCLSTATE(); 2857 return (0); 2858 } 2859 } 2860 } 2861 } 2862 NFSUNLOCKCLSTATE(); 2863 if (notdecr) 2864 printf("nfscl: never fnd open\n"); 2865 return (0); 2866 } 2867 2868 APPLESTATIC int 2869 nfscl_doclose(vnode_t vp, struct nfsclclient **clpp, NFSPROC_T *p) 2870 { 2871 struct nfsclclient *clp; 2872 struct nfsclowner *owp, *nowp; 2873 struct nfsclopen *op; 2874 struct nfscldeleg *dp; 2875 struct nfsfh *nfhp; 2876 int error; 2877 2878 error = nfscl_getcl(vp, NULL, NULL, &clp); 2879 if (error) 2880 return (error); 2881 *clpp = clp; 2882 2883 nfhp = VTONFS(vp)->n_fhp; 2884 NFSLOCKCLSTATE(); 2885 /* 2886 * First get rid of the local Open structures, which should be no 2887 * longer in use. 2888 */ 2889 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); 2890 if (dp != NULL) { 2891 LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) { 2892 op = LIST_FIRST(&owp->nfsow_open); 2893 if (op != NULL) { 2894 KASSERT((op->nfso_opencnt == 0), 2895 ("nfscl: bad open cnt on deleg")); 2896 nfscl_freeopen(op, 1); 2897 } 2898 nfscl_freeopenowner(owp, 1); 2899 } 2900 } 2901 2902 /* Now process the opens against the server. */ 2903 lookformore: 2904 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2905 op = LIST_FIRST(&owp->nfsow_open); 2906 while (op != NULL) { 2907 if (op->nfso_fhlen == nfhp->nfh_len && 2908 !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, 2909 nfhp->nfh_len)) { 2910 /* Found an open, close it. */ 2911 KASSERT((op->nfso_opencnt == 0), 2912 ("nfscl: bad open cnt on server")); 2913 NFSUNLOCKCLSTATE(); 2914 nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), op, 2915 p); 2916 NFSLOCKCLSTATE(); 2917 goto lookformore; 2918 } 2919 op = LIST_NEXT(op, nfso_list); 2920 } 2921 } 2922 NFSUNLOCKCLSTATE(); 2923 return (0); 2924 } 2925 2926 /* 2927 * Return all delegations on this client. 2928 * (Must be called with client sleep lock.) 2929 */ 2930 static void 2931 nfscl_delegreturnall(struct nfsclclient *clp, NFSPROC_T *p) 2932 { 2933 struct nfscldeleg *dp, *ndp; 2934 struct ucred *cred; 2935 2936 cred = newnfs_getcred(); 2937 TAILQ_FOREACH_SAFE(dp, &clp->nfsc_deleg, nfsdl_list, ndp) { 2938 nfscl_cleandeleg(dp); 2939 (void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); 2940 nfscl_freedeleg(&clp->nfsc_deleg, dp); 2941 } 2942 NFSFREECRED(cred); 2943 } 2944 2945 /* 2946 * Do a callback RPC. 2947 */ 2948 APPLESTATIC void 2949 nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p) 2950 { 2951 int i, op; 2952 u_int32_t *tl; 2953 struct nfsclclient *clp; 2954 struct nfscldeleg *dp = NULL; 2955 int numops, taglen = -1, error = 0, trunc, ret = 0; 2956 u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp, cbident; 2957 u_char tag[NFSV4_SMALLSTR + 1], *tagstr; 2958 vnode_t vp = NULL; 2959 struct nfsnode *np; 2960 struct vattr va; 2961 struct nfsfh *nfhp; 2962 mount_t mp; 2963 nfsattrbit_t attrbits, rattrbits; 2964 nfsv4stateid_t stateid; 2965 2966 nfsrvd_rephead(nd); 2967 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2968 taglen = fxdr_unsigned(int, *tl); 2969 if (taglen < 0) { 2970 error = EBADRPC; 2971 goto nfsmout; 2972 } 2973 if (taglen <= NFSV4_SMALLSTR) 2974 tagstr = tag; 2975 else 2976 tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK); 2977 error = nfsrv_mtostr(nd, tagstr, taglen); 2978 if (error) { 2979 if (taglen > NFSV4_SMALLSTR) 2980 free(tagstr, M_TEMP); 2981 taglen = -1; 2982 goto nfsmout; 2983 } 2984 (void) nfsm_strtom(nd, tag, taglen); 2985 if (taglen > NFSV4_SMALLSTR) { 2986 free(tagstr, M_TEMP); 2987 } 2988 NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED); 2989 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2990 minorvers = fxdr_unsigned(u_int32_t, *tl++); 2991 if (minorvers != NFSV4_MINORVERSION) 2992 nd->nd_repstat = NFSERR_MINORVERMISMATCH; 2993 cbident = fxdr_unsigned(u_int32_t, *tl++); 2994 if (nd->nd_repstat) 2995 numops = 0; 2996 else 2997 numops = fxdr_unsigned(int, *tl); 2998 /* 2999 * Loop around doing the sub ops. 3000 */ 3001 for (i = 0; i < numops; i++) { 3002 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3003 NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED); 3004 *repp++ = *tl; 3005 op = fxdr_unsigned(int, *tl); 3006 if (op < NFSV4OP_CBGETATTR || op > NFSV4OP_CBRECALL) { 3007 nd->nd_repstat = NFSERR_OPILLEGAL; 3008 *repp = nfscl_errmap(nd); 3009 retops++; 3010 break; 3011 } 3012 nd->nd_procnum = op; 3013 newnfsstats.cbrpccnt[nd->nd_procnum]++; 3014 switch (op) { 3015 case NFSV4OP_CBGETATTR: 3016 clp = NULL; 3017 error = nfsm_getfh(nd, &nfhp); 3018 if (!error) 3019 error = nfsrv_getattrbits(nd, &attrbits, 3020 NULL, NULL); 3021 if (!error) { 3022 mp = nfscl_getmnt(cbident); 3023 if (mp == NULL) 3024 error = NFSERR_SERVERFAULT; 3025 } 3026 if (!error) { 3027 dp = NULL; 3028 NFSLOCKCLSTATE(); 3029 clp = nfscl_findcl(VFSTONFS(mp)); 3030 if (clp != NULL) 3031 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, 3032 nfhp->nfh_len); 3033 NFSUNLOCKCLSTATE(); 3034 if (dp == NULL) 3035 error = NFSERR_SERVERFAULT; 3036 } 3037 if (!error) { 3038 ret = nfscl_ngetreopen(mp, nfhp->nfh_fh, 3039 nfhp->nfh_len, p, &np); 3040 if (!ret) 3041 vp = NFSTOV(np); 3042 } 3043 if (nfhp != NULL) 3044 FREE((caddr_t)nfhp, M_NFSFH); 3045 if (!error) { 3046 NFSZERO_ATTRBIT(&rattrbits); 3047 if (NFSISSET_ATTRBIT(&attrbits, 3048 NFSATTRBIT_SIZE)) { 3049 if (!ret) 3050 va.va_size = np->n_size; 3051 else 3052 va.va_size = dp->nfsdl_size; 3053 NFSSETBIT_ATTRBIT(&rattrbits, 3054 NFSATTRBIT_SIZE); 3055 } 3056 if (NFSISSET_ATTRBIT(&attrbits, 3057 NFSATTRBIT_CHANGE)) { 3058 va.va_filerev = dp->nfsdl_change; 3059 if (ret || (np->n_flag & NDELEGMOD)) 3060 va.va_filerev++; 3061 NFSSETBIT_ATTRBIT(&rattrbits, 3062 NFSATTRBIT_CHANGE); 3063 } 3064 (void) nfsv4_fillattr(nd, NULL, NULL, &va, 3065 NULL, 0, &rattrbits, NULL, NULL, 0, 0); 3066 if (!ret) 3067 vrele(vp); 3068 } 3069 break; 3070 case NFSV4OP_CBRECALL: 3071 clp = NULL; 3072 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3073 NFSX_UNSIGNED); 3074 stateid.seqid = *tl++; 3075 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, 3076 NFSX_STATEIDOTHER); 3077 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3078 trunc = fxdr_unsigned(int, *tl); 3079 error = nfsm_getfh(nd, &nfhp); 3080 if (!error) { 3081 mp = nfscl_getmnt(cbident); 3082 if (mp == NULL) 3083 error = NFSERR_SERVERFAULT; 3084 } 3085 if (!error) { 3086 NFSLOCKCLSTATE(); 3087 clp = nfscl_findcl(VFSTONFS(mp)); 3088 if (clp != NULL) { 3089 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, 3090 nfhp->nfh_len); 3091 if (dp != NULL && (dp->nfsdl_flags & 3092 NFSCLDL_DELEGRET) == 0) { 3093 dp->nfsdl_flags |= 3094 NFSCLDL_RECALL; 3095 wakeup((caddr_t)clp); 3096 } 3097 } else { 3098 error = NFSERR_SERVERFAULT; 3099 } 3100 NFSUNLOCKCLSTATE(); 3101 } 3102 if (nfhp != NULL) 3103 FREE((caddr_t)nfhp, M_NFSFH); 3104 break; 3105 }; 3106 if (error) { 3107 if (error == EBADRPC || error == NFSERR_BADXDR) { 3108 nd->nd_repstat = NFSERR_BADXDR; 3109 } else { 3110 nd->nd_repstat = error; 3111 } 3112 error = 0; 3113 } 3114 retops++; 3115 if (nd->nd_repstat) { 3116 *repp = nfscl_errmap(nd); 3117 break; 3118 } else 3119 *repp = 0; /* NFS4_OK */ 3120 } 3121 nfsmout: 3122 if (error) { 3123 if (error == EBADRPC || error == NFSERR_BADXDR) 3124 nd->nd_repstat = NFSERR_BADXDR; 3125 else 3126 printf("nfsv4 comperr1=%d\n", error); 3127 } 3128 if (taglen == -1) { 3129 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3130 *tl++ = 0; 3131 *tl = 0; 3132 } else { 3133 *retopsp = txdr_unsigned(retops); 3134 } 3135 *nd->nd_errp = nfscl_errmap(nd); 3136 } 3137 3138 /* 3139 * Generate the next cbident value. Basically just increment a static value 3140 * and then check that it isn't already in the list, if it has wrapped around. 3141 */ 3142 static u_int32_t 3143 nfscl_nextcbident(void) 3144 { 3145 struct nfsclclient *clp; 3146 int matched; 3147 static u_int32_t nextcbident = 0; 3148 static int haswrapped = 0; 3149 3150 nextcbident++; 3151 if (nextcbident == 0) 3152 haswrapped = 1; 3153 if (haswrapped) { 3154 /* 3155 * Search the clientid list for one already using this cbident. 3156 */ 3157 do { 3158 matched = 0; 3159 NFSLOCKCLSTATE(); 3160 LIST_FOREACH(clp, &nfsclhead, nfsc_list) { 3161 if (clp->nfsc_cbident == nextcbident) { 3162 matched = 1; 3163 break; 3164 } 3165 } 3166 NFSUNLOCKCLSTATE(); 3167 if (matched == 1) 3168 nextcbident++; 3169 } while (matched); 3170 } 3171 return (nextcbident); 3172 } 3173 3174 /* 3175 * Get the mount point related to a given cbident. 3176 */ 3177 static mount_t 3178 nfscl_getmnt(u_int32_t cbident) 3179 { 3180 struct nfsclclient *clp; 3181 struct nfsmount *nmp; 3182 3183 NFSLOCKCLSTATE(); 3184 LIST_FOREACH(clp, &nfsclhead, nfsc_list) { 3185 if (clp->nfsc_cbident == cbident) 3186 break; 3187 } 3188 if (clp == NULL) { 3189 NFSUNLOCKCLSTATE(); 3190 return (NULL); 3191 } 3192 nmp = clp->nfsc_nmp; 3193 NFSUNLOCKCLSTATE(); 3194 return (nmp->nm_mountp); 3195 } 3196 3197 /* 3198 * Search for a lock conflict locally on the client. A conflict occurs if 3199 * - not same owner and overlapping byte range and at least one of them is 3200 * a write lock or this is an unlock. 3201 */ 3202 static int 3203 nfscl_localconflict(struct nfsclclient *clp, u_int8_t *fhp, int fhlen, 3204 struct nfscllock *nlop, u_int8_t *own, struct nfscldeleg *dp, 3205 struct nfscllock **lopp) 3206 { 3207 struct nfsclowner *owp; 3208 struct nfsclopen *op; 3209 int ret; 3210 3211 if (dp != NULL) { 3212 ret = nfscl_checkconflict(&dp->nfsdl_lock, nlop, own, lopp); 3213 if (ret) 3214 return (ret); 3215 } 3216 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3217 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3218 if (op->nfso_fhlen == fhlen && 3219 !NFSBCMP(op->nfso_fh, fhp, fhlen)) { 3220 ret = nfscl_checkconflict(&op->nfso_lock, nlop, 3221 own, lopp); 3222 if (ret) 3223 return (ret); 3224 } 3225 } 3226 } 3227 return (0); 3228 } 3229 3230 static int 3231 nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop, 3232 u_int8_t *own, struct nfscllock **lopp) 3233 { 3234 struct nfscllockowner *lp; 3235 struct nfscllock *lop; 3236 3237 LIST_FOREACH(lp, lhp, nfsl_list) { 3238 if (NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) { 3239 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 3240 if (lop->nfslo_first >= nlop->nfslo_end) 3241 break; 3242 if (lop->nfslo_end <= nlop->nfslo_first) 3243 continue; 3244 if (lop->nfslo_type == F_WRLCK || 3245 nlop->nfslo_type == F_WRLCK || 3246 nlop->nfslo_type == F_UNLCK) { 3247 if (lopp != NULL) 3248 *lopp = lop; 3249 return (NFSERR_DENIED); 3250 } 3251 } 3252 } 3253 } 3254 return (0); 3255 } 3256 3257 /* 3258 * Check for a local conflicting lock. 3259 */ 3260 APPLESTATIC int 3261 nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off, 3262 u_int64_t len, struct flock *fl, NFSPROC_T *p) 3263 { 3264 struct nfscllock *lop, nlck; 3265 struct nfscldeleg *dp; 3266 struct nfsnode *np; 3267 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 3268 int error; 3269 3270 nlck.nfslo_type = fl->l_type; 3271 nlck.nfslo_first = off; 3272 if (len == NFS64BITSSET) { 3273 nlck.nfslo_end = NFS64BITSSET; 3274 } else { 3275 nlck.nfslo_end = off + len; 3276 if (nlck.nfslo_end <= nlck.nfslo_first) 3277 return (NFSERR_INVAL); 3278 } 3279 np = VTONFS(vp); 3280 nfscl_filllockowner(p, own); 3281 NFSLOCKCLSTATE(); 3282 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 3283 error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 3284 &nlck, own, dp, &lop); 3285 if (error != 0) { 3286 fl->l_whence = SEEK_SET; 3287 fl->l_start = lop->nfslo_first; 3288 if (lop->nfslo_end == NFS64BITSSET) 3289 fl->l_len = 0; 3290 else 3291 fl->l_len = lop->nfslo_end - lop->nfslo_first; 3292 fl->l_pid = (pid_t)0; 3293 fl->l_type = lop->nfslo_type; 3294 error = -1; /* no RPC required */ 3295 } else if (dp != NULL && ((dp->nfsdl_flags & NFSCLDL_WRITE) || 3296 fl->l_type == F_RDLCK)) { 3297 /* 3298 * The delegation ensures that there isn't a conflicting 3299 * lock on the server, so return -1 to indicate an RPC 3300 * isn't required. 3301 */ 3302 fl->l_type = F_UNLCK; 3303 error = -1; 3304 } 3305 NFSUNLOCKCLSTATE(); 3306 return (error); 3307 } 3308 3309 /* 3310 * Handle Recall of a delegation. 3311 * The clp must be exclusive locked when this is called. 3312 */ 3313 static int 3314 nfscl_recalldeleg(struct nfsclclient *clp, struct nfsmount *nmp, 3315 struct nfscldeleg *dp, vnode_t vp, struct ucred *cred, NFSPROC_T *p, 3316 int called_from_renewthread) 3317 { 3318 struct nfsclowner *owp, *lowp, *nowp; 3319 struct nfsclopen *op, *lop; 3320 struct nfscllockowner *lp; 3321 struct nfscllock *lckp; 3322 struct nfsnode *np; 3323 int error = 0, ret, gotvp = 0; 3324 3325 if (vp == NULL) { 3326 /* 3327 * First, get a vnode for the file. This is needed to do RPCs. 3328 */ 3329 ret = nfscl_ngetreopen(nmp->nm_mountp, dp->nfsdl_fh, 3330 dp->nfsdl_fhlen, p, &np); 3331 if (ret) { 3332 /* 3333 * File isn't open, so nothing to move over to the 3334 * server. 3335 */ 3336 return (0); 3337 } 3338 vp = NFSTOV(np); 3339 gotvp = 1; 3340 } else { 3341 np = VTONFS(vp); 3342 } 3343 dp->nfsdl_flags &= ~NFSCLDL_MODTIMESET; 3344 3345 /* 3346 * Ok, if it's a write delegation, flush data to the server, so 3347 * that close/open consistency is retained. 3348 */ 3349 ret = 0; 3350 NFSLOCKNODE(np); 3351 if ((dp->nfsdl_flags & NFSCLDL_WRITE) && (np->n_flag & NMODIFIED)) { 3352 np->n_flag |= NDELEGRECALL; 3353 NFSUNLOCKNODE(np); 3354 ret = ncl_flush(vp, MNT_WAIT, cred, p, 1, 3355 called_from_renewthread); 3356 NFSLOCKNODE(np); 3357 np->n_flag &= ~NDELEGRECALL; 3358 } 3359 NFSINVALATTRCACHE(np); 3360 NFSUNLOCKNODE(np); 3361 if (ret == EIO && called_from_renewthread != 0) { 3362 /* 3363 * If the flush failed with EIO for the renew thread, 3364 * return now, so that the dirty buffer will be flushed 3365 * later. 3366 */ 3367 if (gotvp != 0) 3368 vrele(vp); 3369 return (ret); 3370 } 3371 3372 /* 3373 * Now, for each openowner with opens issued locally, move them 3374 * over to state against the server. 3375 */ 3376 LIST_FOREACH(lowp, &dp->nfsdl_owner, nfsow_list) { 3377 lop = LIST_FIRST(&lowp->nfsow_open); 3378 if (lop != NULL) { 3379 if (LIST_NEXT(lop, nfso_list) != NULL) 3380 panic("nfsdlg mult opens"); 3381 /* 3382 * Look for the same openowner against the server. 3383 */ 3384 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3385 if (!NFSBCMP(lowp->nfsow_owner, 3386 owp->nfsow_owner, NFSV4CL_LOCKNAMELEN)) { 3387 newnfs_copycred(&dp->nfsdl_cred, cred); 3388 ret = nfscl_moveopen(vp, clp, nmp, lop, 3389 owp, dp, cred, p); 3390 if (ret == NFSERR_STALECLIENTID || 3391 ret == NFSERR_STALEDONTRECOVER) { 3392 if (gotvp) 3393 vrele(vp); 3394 return (ret); 3395 } 3396 if (ret) { 3397 nfscl_freeopen(lop, 1); 3398 if (!error) 3399 error = ret; 3400 } 3401 break; 3402 } 3403 } 3404 3405 /* 3406 * If no openowner found, create one and get an open 3407 * for it. 3408 */ 3409 if (owp == NULL) { 3410 MALLOC(nowp, struct nfsclowner *, 3411 sizeof (struct nfsclowner), M_NFSCLOWNER, 3412 M_WAITOK); 3413 nfscl_newopen(clp, NULL, &owp, &nowp, &op, 3414 NULL, lowp->nfsow_owner, dp->nfsdl_fh, 3415 dp->nfsdl_fhlen, NULL); 3416 newnfs_copycred(&dp->nfsdl_cred, cred); 3417 ret = nfscl_moveopen(vp, clp, nmp, lop, 3418 owp, dp, cred, p); 3419 if (ret) { 3420 nfscl_freeopenowner(owp, 0); 3421 if (ret == NFSERR_STALECLIENTID || 3422 ret == NFSERR_STALEDONTRECOVER) { 3423 if (gotvp) 3424 vrele(vp); 3425 return (ret); 3426 } 3427 if (ret) { 3428 nfscl_freeopen(lop, 1); 3429 if (!error) 3430 error = ret; 3431 } 3432 } 3433 } 3434 } 3435 } 3436 3437 /* 3438 * Now, get byte range locks for any locks done locally. 3439 */ 3440 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 3441 LIST_FOREACH(lckp, &lp->nfsl_lock, nfslo_list) { 3442 newnfs_copycred(&dp->nfsdl_cred, cred); 3443 ret = nfscl_relock(vp, clp, nmp, lp, lckp, cred, p); 3444 if (ret == NFSERR_STALESTATEID || 3445 ret == NFSERR_STALEDONTRECOVER || 3446 ret == NFSERR_STALECLIENTID) { 3447 if (gotvp) 3448 vrele(vp); 3449 return (ret); 3450 } 3451 if (ret && !error) 3452 error = ret; 3453 } 3454 } 3455 if (gotvp) 3456 vrele(vp); 3457 return (error); 3458 } 3459 3460 /* 3461 * Move a locally issued open over to an owner on the state list. 3462 * SIDE EFFECT: If it needs to sleep (do an rpc), it unlocks clstate and 3463 * returns with it unlocked. 3464 */ 3465 static int 3466 nfscl_moveopen(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp, 3467 struct nfsclopen *lop, struct nfsclowner *owp, struct nfscldeleg *dp, 3468 struct ucred *cred, NFSPROC_T *p) 3469 { 3470 struct nfsclopen *op, *nop; 3471 struct nfscldeleg *ndp; 3472 struct nfsnode *np; 3473 int error = 0, newone; 3474 3475 /* 3476 * First, look for an appropriate open, If found, just increment the 3477 * opencnt in it. 3478 */ 3479 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3480 if ((op->nfso_mode & lop->nfso_mode) == lop->nfso_mode && 3481 op->nfso_fhlen == lop->nfso_fhlen && 3482 !NFSBCMP(op->nfso_fh, lop->nfso_fh, op->nfso_fhlen)) { 3483 op->nfso_opencnt += lop->nfso_opencnt; 3484 nfscl_freeopen(lop, 1); 3485 return (0); 3486 } 3487 } 3488 3489 /* No appropriate open, so we have to do one against the server. */ 3490 np = VTONFS(vp); 3491 MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) + 3492 lop->nfso_fhlen - 1, M_NFSCLOPEN, M_WAITOK); 3493 newone = 0; 3494 nfscl_newopen(clp, NULL, &owp, NULL, &op, &nop, owp->nfsow_owner, 3495 lop->nfso_fh, lop->nfso_fhlen, &newone); 3496 ndp = dp; 3497 error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen, 3498 lop->nfso_fh, lop->nfso_fhlen, lop->nfso_mode, op, 3499 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &ndp, 0, 0, cred, p); 3500 if (error) { 3501 if (newone) 3502 nfscl_freeopen(op, 0); 3503 } else { 3504 if (newone) 3505 newnfs_copyincred(cred, &op->nfso_cred); 3506 op->nfso_mode |= lop->nfso_mode; 3507 op->nfso_opencnt += lop->nfso_opencnt; 3508 nfscl_freeopen(lop, 1); 3509 } 3510 if (nop != NULL) 3511 FREE((caddr_t)nop, M_NFSCLOPEN); 3512 if (ndp != NULL) { 3513 /* 3514 * What should I do with the returned delegation, since the 3515 * delegation is being recalled? For now, just printf and 3516 * through it away. 3517 */ 3518 printf("Moveopen returned deleg\n"); 3519 FREE((caddr_t)ndp, M_NFSCLDELEG); 3520 } 3521 return (error); 3522 } 3523 3524 /* 3525 * Recall all delegations on this client. 3526 */ 3527 static void 3528 nfscl_totalrecall(struct nfsclclient *clp) 3529 { 3530 struct nfscldeleg *dp; 3531 3532 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 3533 if ((dp->nfsdl_flags & NFSCLDL_DELEGRET) == 0) 3534 dp->nfsdl_flags |= NFSCLDL_RECALL; 3535 } 3536 } 3537 3538 /* 3539 * Relock byte ranges. Called for delegation recall and state expiry. 3540 */ 3541 static int 3542 nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp, 3543 struct nfscllockowner *lp, struct nfscllock *lop, struct ucred *cred, 3544 NFSPROC_T *p) 3545 { 3546 struct nfscllockowner *nlp; 3547 struct nfsfh *nfhp; 3548 u_int64_t off, len; 3549 u_int32_t clidrev = 0; 3550 int error, newone, donelocally; 3551 3552 off = lop->nfslo_first; 3553 len = lop->nfslo_end - lop->nfslo_first; 3554 error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p, 3555 clp, 1, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone, 3556 &donelocally); 3557 if (error || donelocally) 3558 return (error); 3559 if (nmp->nm_clp != NULL) 3560 clidrev = nmp->nm_clp->nfsc_clientidrev; 3561 else 3562 clidrev = 0; 3563 nfhp = VTONFS(vp)->n_fhp; 3564 error = nfscl_trylock(nmp, vp, nfhp->nfh_fh, 3565 nfhp->nfh_len, nlp, newone, 0, off, 3566 len, lop->nfslo_type, cred, p); 3567 if (error) 3568 nfscl_freelockowner(nlp, 0); 3569 return (error); 3570 } 3571 3572 /* 3573 * Called to re-open a file. Basically get a vnode for the file handle 3574 * and then call nfsrpc_openrpc() to do the rest. 3575 */ 3576 static int 3577 nfsrpc_reopen(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, 3578 u_int32_t mode, struct nfsclopen *op, struct nfscldeleg **dpp, 3579 struct ucred *cred, NFSPROC_T *p) 3580 { 3581 struct nfsnode *np; 3582 vnode_t vp; 3583 int error; 3584 3585 error = nfscl_ngetreopen(nmp->nm_mountp, fhp, fhlen, p, &np); 3586 if (error) 3587 return (error); 3588 vp = NFSTOV(np); 3589 if (np->n_v4 != NULL) { 3590 error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, 3591 np->n_v4->n4_fhlen, fhp, fhlen, mode, op, 3592 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, dpp, 0, 0, 3593 cred, p); 3594 } else { 3595 error = EINVAL; 3596 } 3597 vrele(vp); 3598 return (error); 3599 } 3600 3601 /* 3602 * Try an open against the server. Just call nfsrpc_openrpc(), retrying while 3603 * NFSERR_DELAY. Also, try system credentials, if the passed in credentials 3604 * fail. 3605 */ 3606 static int 3607 nfscl_tryopen(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen, 3608 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 3609 u_int8_t *name, int namelen, struct nfscldeleg **ndpp, 3610 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p) 3611 { 3612 int error; 3613 3614 do { 3615 error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, newfhlen, 3616 mode, op, name, namelen, ndpp, reclaim, delegtype, cred, p, 3617 0, 0); 3618 if (error == NFSERR_DELAY) 3619 (void) nfs_catnap(PZERO, error, "nfstryop"); 3620 } while (error == NFSERR_DELAY); 3621 if (error == EAUTH || error == EACCES) { 3622 /* Try again using system credentials */ 3623 newnfs_setroot(cred); 3624 do { 3625 error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, 3626 newfhlen, mode, op, name, namelen, ndpp, reclaim, 3627 delegtype, cred, p, 1, 0); 3628 if (error == NFSERR_DELAY) 3629 (void) nfs_catnap(PZERO, error, "nfstryop"); 3630 } while (error == NFSERR_DELAY); 3631 } 3632 return (error); 3633 } 3634 3635 /* 3636 * Try a byte range lock. Just loop on nfsrpc_lock() while it returns 3637 * NFSERR_DELAY. Also, retry with system credentials, if the provided 3638 * cred don't work. 3639 */ 3640 static int 3641 nfscl_trylock(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, 3642 int fhlen, struct nfscllockowner *nlp, int newone, int reclaim, 3643 u_int64_t off, u_int64_t len, short type, struct ucred *cred, NFSPROC_T *p) 3644 { 3645 struct nfsrv_descript nfsd, *nd = &nfsd; 3646 int error; 3647 3648 do { 3649 error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, newone, 3650 reclaim, off, len, type, cred, p, 0); 3651 if (!error && nd->nd_repstat == NFSERR_DELAY) 3652 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3653 "nfstrylck"); 3654 } while (!error && nd->nd_repstat == NFSERR_DELAY); 3655 if (!error) 3656 error = nd->nd_repstat; 3657 if (error == EAUTH || error == EACCES) { 3658 /* Try again using root credentials */ 3659 newnfs_setroot(cred); 3660 do { 3661 error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, 3662 newone, reclaim, off, len, type, cred, p, 1); 3663 if (!error && nd->nd_repstat == NFSERR_DELAY) 3664 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3665 "nfstrylck"); 3666 } while (!error && nd->nd_repstat == NFSERR_DELAY); 3667 if (!error) 3668 error = nd->nd_repstat; 3669 } 3670 return (error); 3671 } 3672 3673 /* 3674 * Try a delegreturn against the server. Just call nfsrpc_delegreturn(), 3675 * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in 3676 * credentials fail. 3677 */ 3678 static int 3679 nfscl_trydelegreturn(struct nfscldeleg *dp, struct ucred *cred, 3680 struct nfsmount *nmp, NFSPROC_T *p) 3681 { 3682 int error; 3683 3684 do { 3685 error = nfsrpc_delegreturn(dp, cred, nmp, p, 0); 3686 if (error == NFSERR_DELAY) 3687 (void) nfs_catnap(PZERO, error, "nfstrydp"); 3688 } while (error == NFSERR_DELAY); 3689 if (error == EAUTH || error == EACCES) { 3690 /* Try again using system credentials */ 3691 newnfs_setroot(cred); 3692 do { 3693 error = nfsrpc_delegreturn(dp, cred, nmp, p, 1); 3694 if (error == NFSERR_DELAY) 3695 (void) nfs_catnap(PZERO, error, "nfstrydp"); 3696 } while (error == NFSERR_DELAY); 3697 } 3698 return (error); 3699 } 3700 3701 /* 3702 * Try a close against the server. Just call nfsrpc_closerpc(), 3703 * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in 3704 * credentials fail. 3705 */ 3706 APPLESTATIC int 3707 nfscl_tryclose(struct nfsclopen *op, struct ucred *cred, 3708 struct nfsmount *nmp, NFSPROC_T *p) 3709 { 3710 struct nfsrv_descript nfsd, *nd = &nfsd; 3711 int error; 3712 3713 do { 3714 error = nfsrpc_closerpc(nd, nmp, op, cred, p, 0); 3715 if (error == NFSERR_DELAY) 3716 (void) nfs_catnap(PZERO, error, "nfstrycl"); 3717 } while (error == NFSERR_DELAY); 3718 if (error == EAUTH || error == EACCES) { 3719 /* Try again using system credentials */ 3720 newnfs_setroot(cred); 3721 do { 3722 error = nfsrpc_closerpc(nd, nmp, op, cred, p, 1); 3723 if (error == NFSERR_DELAY) 3724 (void) nfs_catnap(PZERO, error, "nfstrycl"); 3725 } while (error == NFSERR_DELAY); 3726 } 3727 return (error); 3728 } 3729 3730 /* 3731 * Decide if a delegation on a file permits close without flushing writes 3732 * to the server. This might be a big performance win in some environments. 3733 * (Not useful until the client does caching on local stable storage.) 3734 */ 3735 APPLESTATIC int 3736 nfscl_mustflush(vnode_t vp) 3737 { 3738 struct nfsclclient *clp; 3739 struct nfscldeleg *dp; 3740 struct nfsnode *np; 3741 struct nfsmount *nmp; 3742 3743 np = VTONFS(vp); 3744 nmp = VFSTONFS(vnode_mount(vp)); 3745 if (!NFSHASNFSV4(nmp)) 3746 return (1); 3747 NFSLOCKCLSTATE(); 3748 clp = nfscl_findcl(nmp); 3749 if (clp == NULL) { 3750 NFSUNLOCKCLSTATE(); 3751 return (1); 3752 } 3753 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 3754 if (dp != NULL && (dp->nfsdl_flags & 3755 (NFSCLDL_WRITE | NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 3756 NFSCLDL_WRITE && 3757 (dp->nfsdl_sizelimit >= np->n_size || 3758 !NFSHASSTRICT3530(nmp))) { 3759 NFSUNLOCKCLSTATE(); 3760 return (0); 3761 } 3762 NFSUNLOCKCLSTATE(); 3763 return (1); 3764 } 3765 3766 /* 3767 * See if a (write) delegation exists for this file. 3768 */ 3769 APPLESTATIC int 3770 nfscl_nodeleg(vnode_t vp, int writedeleg) 3771 { 3772 struct nfsclclient *clp; 3773 struct nfscldeleg *dp; 3774 struct nfsnode *np; 3775 struct nfsmount *nmp; 3776 3777 np = VTONFS(vp); 3778 nmp = VFSTONFS(vnode_mount(vp)); 3779 if (!NFSHASNFSV4(nmp)) 3780 return (1); 3781 NFSLOCKCLSTATE(); 3782 clp = nfscl_findcl(nmp); 3783 if (clp == NULL) { 3784 NFSUNLOCKCLSTATE(); 3785 return (1); 3786 } 3787 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 3788 if (dp != NULL && 3789 (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 0 && 3790 (writedeleg == 0 || (dp->nfsdl_flags & NFSCLDL_WRITE) == 3791 NFSCLDL_WRITE)) { 3792 NFSUNLOCKCLSTATE(); 3793 return (0); 3794 } 3795 NFSUNLOCKCLSTATE(); 3796 return (1); 3797 } 3798 3799 /* 3800 * Look for an associated delegation that should be DelegReturned. 3801 */ 3802 APPLESTATIC int 3803 nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp) 3804 { 3805 struct nfsclclient *clp; 3806 struct nfscldeleg *dp; 3807 struct nfsclowner *owp; 3808 struct nfscllockowner *lp; 3809 struct nfsmount *nmp; 3810 struct ucred *cred; 3811 struct nfsnode *np; 3812 int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept; 3813 3814 nmp = VFSTONFS(vnode_mount(vp)); 3815 np = VTONFS(vp); 3816 NFSLOCKCLSTATE(); 3817 /* 3818 * Loop around waiting for: 3819 * - outstanding I/O operations on delegations to complete 3820 * - for a delegation on vp that has state, lock the client and 3821 * do a recall 3822 * - return delegation with no state 3823 */ 3824 while (1) { 3825 clp = nfscl_findcl(nmp); 3826 if (clp == NULL) { 3827 NFSUNLOCKCLSTATE(); 3828 return (retcnt); 3829 } 3830 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 3831 np->n_fhp->nfh_len); 3832 if (dp != NULL) { 3833 /* 3834 * Wait for outstanding I/O ops to be done. 3835 */ 3836 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 3837 if (igotlock) { 3838 nfsv4_unlock(&clp->nfsc_lock, 0); 3839 igotlock = 0; 3840 } 3841 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 3842 (void) nfsmsleep(&dp->nfsdl_rwlock, 3843 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 3844 continue; 3845 } 3846 needsrecall = 0; 3847 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 3848 if (!LIST_EMPTY(&owp->nfsow_open)) { 3849 needsrecall = 1; 3850 break; 3851 } 3852 } 3853 if (!needsrecall) { 3854 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 3855 if (!LIST_EMPTY(&lp->nfsl_lock)) { 3856 needsrecall = 1; 3857 break; 3858 } 3859 } 3860 } 3861 if (needsrecall && !triedrecall) { 3862 dp->nfsdl_flags |= NFSCLDL_DELEGRET; 3863 islept = 0; 3864 while (!igotlock) { 3865 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 3866 &islept, NFSCLSTATEMUTEXPTR); 3867 if (islept) 3868 break; 3869 } 3870 if (islept) 3871 continue; 3872 NFSUNLOCKCLSTATE(); 3873 cred = newnfs_getcred(); 3874 newnfs_copycred(&dp->nfsdl_cred, cred); 3875 (void) nfscl_recalldeleg(clp, nmp, dp, vp, cred, p, 0); 3876 NFSFREECRED(cred); 3877 triedrecall = 1; 3878 NFSLOCKCLSTATE(); 3879 nfsv4_unlock(&clp->nfsc_lock, 0); 3880 igotlock = 0; 3881 continue; 3882 } 3883 *stp = dp->nfsdl_stateid; 3884 retcnt = 1; 3885 nfscl_cleandeleg(dp); 3886 nfscl_freedeleg(&clp->nfsc_deleg, dp); 3887 } 3888 if (igotlock) 3889 nfsv4_unlock(&clp->nfsc_lock, 0); 3890 NFSUNLOCKCLSTATE(); 3891 return (retcnt); 3892 } 3893 } 3894 3895 /* 3896 * Look for associated delegation(s) that should be DelegReturned. 3897 */ 3898 APPLESTATIC int 3899 nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp, 3900 nfsv4stateid_t *tstp, int *gottdp, NFSPROC_T *p) 3901 { 3902 struct nfsclclient *clp; 3903 struct nfscldeleg *dp; 3904 struct nfsclowner *owp; 3905 struct nfscllockowner *lp; 3906 struct nfsmount *nmp; 3907 struct ucred *cred; 3908 struct nfsnode *np; 3909 int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept; 3910 3911 nmp = VFSTONFS(vnode_mount(fvp)); 3912 *gotfdp = 0; 3913 *gottdp = 0; 3914 NFSLOCKCLSTATE(); 3915 /* 3916 * Loop around waiting for: 3917 * - outstanding I/O operations on delegations to complete 3918 * - for a delegation on fvp that has state, lock the client and 3919 * do a recall 3920 * - return delegation(s) with no state. 3921 */ 3922 while (1) { 3923 clp = nfscl_findcl(nmp); 3924 if (clp == NULL) { 3925 NFSUNLOCKCLSTATE(); 3926 return (retcnt); 3927 } 3928 np = VTONFS(fvp); 3929 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 3930 np->n_fhp->nfh_len); 3931 if (dp != NULL && *gotfdp == 0) { 3932 /* 3933 * Wait for outstanding I/O ops to be done. 3934 */ 3935 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 3936 if (igotlock) { 3937 nfsv4_unlock(&clp->nfsc_lock, 0); 3938 igotlock = 0; 3939 } 3940 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 3941 (void) nfsmsleep(&dp->nfsdl_rwlock, 3942 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 3943 continue; 3944 } 3945 needsrecall = 0; 3946 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 3947 if (!LIST_EMPTY(&owp->nfsow_open)) { 3948 needsrecall = 1; 3949 break; 3950 } 3951 } 3952 if (!needsrecall) { 3953 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 3954 if (!LIST_EMPTY(&lp->nfsl_lock)) { 3955 needsrecall = 1; 3956 break; 3957 } 3958 } 3959 } 3960 if (needsrecall && !triedrecall) { 3961 dp->nfsdl_flags |= NFSCLDL_DELEGRET; 3962 islept = 0; 3963 while (!igotlock) { 3964 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 3965 &islept, NFSCLSTATEMUTEXPTR); 3966 if (islept) 3967 break; 3968 } 3969 if (islept) 3970 continue; 3971 NFSUNLOCKCLSTATE(); 3972 cred = newnfs_getcred(); 3973 newnfs_copycred(&dp->nfsdl_cred, cred); 3974 (void) nfscl_recalldeleg(clp, nmp, dp, fvp, cred, p, 0); 3975 NFSFREECRED(cred); 3976 triedrecall = 1; 3977 NFSLOCKCLSTATE(); 3978 nfsv4_unlock(&clp->nfsc_lock, 0); 3979 igotlock = 0; 3980 continue; 3981 } 3982 *fstp = dp->nfsdl_stateid; 3983 retcnt++; 3984 *gotfdp = 1; 3985 nfscl_cleandeleg(dp); 3986 nfscl_freedeleg(&clp->nfsc_deleg, dp); 3987 } 3988 if (igotlock) { 3989 nfsv4_unlock(&clp->nfsc_lock, 0); 3990 igotlock = 0; 3991 } 3992 if (tvp != NULL) { 3993 np = VTONFS(tvp); 3994 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 3995 np->n_fhp->nfh_len); 3996 if (dp != NULL && *gottdp == 0) { 3997 /* 3998 * Wait for outstanding I/O ops to be done. 3999 */ 4000 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 4001 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 4002 (void) nfsmsleep(&dp->nfsdl_rwlock, 4003 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 4004 continue; 4005 } 4006 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 4007 if (!LIST_EMPTY(&owp->nfsow_open)) { 4008 NFSUNLOCKCLSTATE(); 4009 return (retcnt); 4010 } 4011 } 4012 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 4013 if (!LIST_EMPTY(&lp->nfsl_lock)) { 4014 NFSUNLOCKCLSTATE(); 4015 return (retcnt); 4016 } 4017 } 4018 *tstp = dp->nfsdl_stateid; 4019 retcnt++; 4020 *gottdp = 1; 4021 nfscl_cleandeleg(dp); 4022 nfscl_freedeleg(&clp->nfsc_deleg, dp); 4023 } 4024 } 4025 NFSUNLOCKCLSTATE(); 4026 return (retcnt); 4027 } 4028 } 4029 4030 /* 4031 * Get a reference on the clientid associated with the mount point. 4032 * Return 1 if success, 0 otherwise. 4033 */ 4034 APPLESTATIC int 4035 nfscl_getref(struct nfsmount *nmp) 4036 { 4037 struct nfsclclient *clp; 4038 4039 NFSLOCKCLSTATE(); 4040 clp = nfscl_findcl(nmp); 4041 if (clp == NULL) { 4042 NFSUNLOCKCLSTATE(); 4043 return (0); 4044 } 4045 nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR); 4046 NFSUNLOCKCLSTATE(); 4047 return (1); 4048 } 4049 4050 /* 4051 * Release a reference on a clientid acquired with the above call. 4052 */ 4053 APPLESTATIC void 4054 nfscl_relref(struct nfsmount *nmp) 4055 { 4056 struct nfsclclient *clp; 4057 4058 NFSLOCKCLSTATE(); 4059 clp = nfscl_findcl(nmp); 4060 if (clp == NULL) { 4061 NFSUNLOCKCLSTATE(); 4062 return; 4063 } 4064 nfsv4_relref(&clp->nfsc_lock); 4065 NFSUNLOCKCLSTATE(); 4066 } 4067 4068 /* 4069 * Save the size attribute in the delegation, since the nfsnode 4070 * is going away. 4071 */ 4072 APPLESTATIC void 4073 nfscl_reclaimnode(vnode_t vp) 4074 { 4075 struct nfsclclient *clp; 4076 struct nfscldeleg *dp; 4077 struct nfsnode *np = VTONFS(vp); 4078 struct nfsmount *nmp; 4079 4080 nmp = VFSTONFS(vnode_mount(vp)); 4081 if (!NFSHASNFSV4(nmp)) 4082 return; 4083 NFSLOCKCLSTATE(); 4084 clp = nfscl_findcl(nmp); 4085 if (clp == NULL) { 4086 NFSUNLOCKCLSTATE(); 4087 return; 4088 } 4089 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4090 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) 4091 dp->nfsdl_size = np->n_size; 4092 NFSUNLOCKCLSTATE(); 4093 } 4094 4095 /* 4096 * Get the saved size attribute in the delegation, since it is a 4097 * newly allocated nfsnode. 4098 */ 4099 APPLESTATIC void 4100 nfscl_newnode(vnode_t vp) 4101 { 4102 struct nfsclclient *clp; 4103 struct nfscldeleg *dp; 4104 struct nfsnode *np = VTONFS(vp); 4105 struct nfsmount *nmp; 4106 4107 nmp = VFSTONFS(vnode_mount(vp)); 4108 if (!NFSHASNFSV4(nmp)) 4109 return; 4110 NFSLOCKCLSTATE(); 4111 clp = nfscl_findcl(nmp); 4112 if (clp == NULL) { 4113 NFSUNLOCKCLSTATE(); 4114 return; 4115 } 4116 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4117 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) 4118 np->n_size = dp->nfsdl_size; 4119 NFSUNLOCKCLSTATE(); 4120 } 4121 4122 /* 4123 * If there is a valid write delegation for this file, set the modtime 4124 * to the local clock time. 4125 */ 4126 APPLESTATIC void 4127 nfscl_delegmodtime(vnode_t vp) 4128 { 4129 struct nfsclclient *clp; 4130 struct nfscldeleg *dp; 4131 struct nfsnode *np = VTONFS(vp); 4132 struct nfsmount *nmp; 4133 4134 nmp = VFSTONFS(vnode_mount(vp)); 4135 if (!NFSHASNFSV4(nmp)) 4136 return; 4137 NFSLOCKCLSTATE(); 4138 clp = nfscl_findcl(nmp); 4139 if (clp == NULL) { 4140 NFSUNLOCKCLSTATE(); 4141 return; 4142 } 4143 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4144 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) { 4145 NFSGETNANOTIME(&dp->nfsdl_modtime); 4146 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 4147 } 4148 NFSUNLOCKCLSTATE(); 4149 } 4150 4151 /* 4152 * If there is a valid write delegation for this file with a modtime set, 4153 * put that modtime in mtime. 4154 */ 4155 APPLESTATIC void 4156 nfscl_deleggetmodtime(vnode_t vp, struct timespec *mtime) 4157 { 4158 struct nfsclclient *clp; 4159 struct nfscldeleg *dp; 4160 struct nfsnode *np = VTONFS(vp); 4161 struct nfsmount *nmp; 4162 4163 nmp = VFSTONFS(vnode_mount(vp)); 4164 if (!NFSHASNFSV4(nmp)) 4165 return; 4166 NFSLOCKCLSTATE(); 4167 clp = nfscl_findcl(nmp); 4168 if (clp == NULL) { 4169 NFSUNLOCKCLSTATE(); 4170 return; 4171 } 4172 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4173 if (dp != NULL && 4174 (dp->nfsdl_flags & (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) == 4175 (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) 4176 *mtime = dp->nfsdl_modtime; 4177 NFSUNLOCKCLSTATE(); 4178 } 4179 4180 static int 4181 nfscl_errmap(struct nfsrv_descript *nd) 4182 { 4183 short *defaulterrp, *errp; 4184 4185 if (!nd->nd_repstat) 4186 return (0); 4187 if (nd->nd_procnum == NFSPROC_NOOP) 4188 return (txdr_unsigned(nd->nd_repstat & 0xffff)); 4189 if (nd->nd_repstat == EBADRPC) 4190 return (txdr_unsigned(NFSERR_BADXDR)); 4191 if (nd->nd_repstat == NFSERR_MINORVERMISMATCH || 4192 nd->nd_repstat == NFSERR_OPILLEGAL) 4193 return (txdr_unsigned(nd->nd_repstat)); 4194 errp = defaulterrp = nfscl_cberrmap[nd->nd_procnum]; 4195 while (*++errp) 4196 if (*errp == (short)nd->nd_repstat) 4197 return (txdr_unsigned(nd->nd_repstat)); 4198 return (txdr_unsigned(*defaulterrp)); 4199 } 4200 4201