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