1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009 Rick Macklem, University of Guelph 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * These functions implement the client side state handling for NFSv4. 35 * NFSv4 state handling: 36 * - A lockowner is used to determine lock contention, so it 37 * corresponds directly to a Posix pid. (1 to 1 mapping) 38 * - The correct granularity of an OpenOwner is not nearly so 39 * obvious. An OpenOwner does the following: 40 * - provides a serial sequencing of Open/Close/Lock-with-new-lockowner 41 * - is used to check for Open/Share contention (not applicable to 42 * this client, since all Opens are Deny_None) 43 * As such, I considered both extreme. 44 * 1 OpenOwner per ClientID - Simple to manage, but fully serializes 45 * all Open, Close and Lock (with a new lockowner) Ops. 46 * 1 OpenOwner for each Open - This one results in an OpenConfirm for 47 * every Open, for most servers. 48 * So, I chose to use the same mapping as I did for LockOwnwers. 49 * The main concern here is that you can end up with multiple Opens 50 * for the same File Handle, but on different OpenOwners (opens 51 * inherited from parents, grandparents...) and you do not know 52 * which of these the vnodeop close applies to. This is handled by 53 * delaying the Close Op(s) until all of the Opens have been closed. 54 * (It is not yet obvious if this is the correct granularity.) 55 * - How the code handles serialization: 56 * - For the ClientId, it uses an exclusive lock while getting its 57 * SetClientId and during recovery. Otherwise, it uses a shared 58 * lock via a reference count. 59 * - For the rest of the data structures, it uses an SMP mutex 60 * (once the nfs client is SMP safe) and doesn't sleep while 61 * manipulating the linked lists. 62 * - The serialization of Open/Close/Lock/LockU falls out in the 63 * "wash", since OpenOwners and LockOwners are both mapped from 64 * Posix pid. In other words, there is only one Posix pid using 65 * any given owner, so that owner is serialized. (If you change 66 * the granularity of the OpenOwner, then code must be added to 67 * serialize Ops on the OpenOwner.) 68 * - When to get rid of OpenOwners and LockOwners. 69 * - The function nfscl_cleanup_common() is executed after a process exits. 70 * It goes through the client list looking for all Open and Lock Owners. 71 * When one is found, it is marked "defunct" or in the case of 72 * an OpenOwner without any Opens, freed. 73 * The renew thread scans for defunct Owners and gets rid of them, 74 * if it can. The LockOwners will also be deleted when the 75 * associated Open is closed. 76 * - If the LockU or Close Op(s) fail during close in a way 77 * that could be recovered upon retry, they are relinked to the 78 * ClientId's defunct open list and retried by the renew thread 79 * until they succeed or an unmount/recovery occurs. 80 * (Since we are done with them, they do not need to be recovered.) 81 */ 82 83 #ifndef APPLEKEXT 84 #include <fs/nfs/nfsport.h> 85 86 /* 87 * Global variables 88 */ 89 extern struct nfsstatsv1 nfsstatsv1; 90 extern struct nfsreqhead nfsd_reqq; 91 extern u_int32_t newnfs_false, newnfs_true; 92 extern int nfscl_debuglevel; 93 extern int nfscl_enablecallb; 94 extern int nfs_numnfscbd; 95 NFSREQSPINLOCK; 96 NFSCLSTATEMUTEX; 97 int nfscl_inited = 0; 98 struct nfsclhead nfsclhead; /* Head of clientid list */ 99 int nfscl_deleghighwater = NFSCLDELEGHIGHWATER; 100 int nfscl_layouthighwater = NFSCLLAYOUTHIGHWATER; 101 #endif /* !APPLEKEXT */ 102 103 static int nfscl_delegcnt = 0; 104 static int nfscl_layoutcnt = 0; 105 static int nfscl_getopen(struct nfsclownerhead *, u_int8_t *, int, u_int8_t *, 106 u_int8_t *, u_int32_t, struct nfscllockowner **, struct nfsclopen **); 107 static void nfscl_clrelease(struct nfsclclient *); 108 static void nfscl_cleanclient(struct nfsclclient *); 109 static void nfscl_expireclient(struct nfsclclient *, struct nfsmount *, 110 struct ucred *, NFSPROC_T *); 111 static int nfscl_expireopen(struct nfsclclient *, struct nfsclopen *, 112 struct nfsmount *, struct ucred *, NFSPROC_T *); 113 static void nfscl_recover(struct nfsclclient *, bool *, struct ucred *, 114 NFSPROC_T *); 115 static void nfscl_insertlock(struct nfscllockowner *, struct nfscllock *, 116 struct nfscllock *, int); 117 static int nfscl_updatelock(struct nfscllockowner *, struct nfscllock **, 118 struct nfscllock **, int); 119 static void nfscl_delegreturnall(struct nfsclclient *, NFSPROC_T *); 120 static u_int32_t nfscl_nextcbident(void); 121 static mount_t nfscl_getmnt(int, uint8_t *, u_int32_t, struct nfsclclient **); 122 static struct nfsclclient *nfscl_getclnt(u_int32_t); 123 static struct nfsclclient *nfscl_getclntsess(uint8_t *); 124 static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *, 125 int); 126 static void nfscl_retoncloselayout(vnode_t, struct nfsclclient *, uint8_t *, 127 int, struct nfsclrecalllayout **); 128 static void nfscl_reldevinfo_locked(struct nfscldevinfo *); 129 static struct nfscllayout *nfscl_findlayout(struct nfsclclient *, u_int8_t *, 130 int); 131 static struct nfscldevinfo *nfscl_finddevinfo(struct nfsclclient *, uint8_t *); 132 static int nfscl_checkconflict(struct nfscllockownerhead *, struct nfscllock *, 133 u_int8_t *, struct nfscllock **); 134 static void nfscl_freealllocks(struct nfscllockownerhead *, int); 135 static int nfscl_localconflict(struct nfsclclient *, u_int8_t *, int, 136 struct nfscllock *, u_int8_t *, struct nfscldeleg *, struct nfscllock **); 137 static void nfscl_newopen(struct nfsclclient *, struct nfscldeleg *, 138 struct nfsclowner **, struct nfsclowner **, struct nfsclopen **, 139 struct nfsclopen **, u_int8_t *, u_int8_t *, int, struct ucred *, int *); 140 static int nfscl_moveopen(vnode_t , struct nfsclclient *, 141 struct nfsmount *, struct nfsclopen *, struct nfsclowner *, 142 struct nfscldeleg *, struct ucred *, NFSPROC_T *); 143 static void nfscl_totalrecall(struct nfsclclient *); 144 static int nfscl_relock(vnode_t , struct nfsclclient *, struct nfsmount *, 145 struct nfscllockowner *, struct nfscllock *, struct ucred *, NFSPROC_T *); 146 static int nfscl_tryopen(struct nfsmount *, vnode_t , u_int8_t *, int, 147 u_int8_t *, int, u_int32_t, struct nfsclopen *, u_int8_t *, int, 148 struct nfscldeleg **, int, u_int32_t, struct ucred *, NFSPROC_T *); 149 static int nfscl_trylock(struct nfsmount *, vnode_t , u_int8_t *, 150 int, struct nfscllockowner *, int, int, u_int64_t, u_int64_t, short, 151 struct ucred *, NFSPROC_T *); 152 static int nfsrpc_reopen(struct nfsmount *, u_int8_t *, int, u_int32_t, 153 struct nfsclopen *, struct nfscldeleg **, struct ucred *, NFSPROC_T *); 154 static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *); 155 static int nfscl_errmap(struct nfsrv_descript *, u_int32_t); 156 static void nfscl_cleanup_common(struct nfsclclient *, u_int8_t *); 157 static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *, 158 struct nfscldeleg *, vnode_t, struct ucred *, NFSPROC_T *, int); 159 static void nfscl_freeopenowner(struct nfsclowner *, int); 160 static void nfscl_cleandeleg(struct nfscldeleg *); 161 static int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *, 162 struct nfsmount *, NFSPROC_T *); 163 static void nfscl_emptylockowner(struct nfscllockowner *, 164 struct nfscllockownerfhhead *); 165 static void nfscl_mergeflayouts(struct nfsclflayouthead *, 166 struct nfsclflayouthead *); 167 static int nfscl_layoutrecall(int, struct nfscllayout *, uint32_t, uint64_t, 168 uint64_t, uint32_t, uint32_t, uint32_t, char *, struct nfsclrecalllayout *); 169 static int nfscl_seq(uint32_t, uint32_t); 170 static void nfscl_layoutreturn(struct nfsmount *, struct nfscllayout *, 171 struct ucred *, NFSPROC_T *); 172 static void nfscl_dolayoutcommit(struct nfsmount *, struct nfscllayout *, 173 struct ucred *, NFSPROC_T *); 174 175 static short nfscberr_null[] = { 176 0, 177 0, 178 }; 179 180 static short nfscberr_getattr[] = { 181 NFSERR_RESOURCE, 182 NFSERR_BADHANDLE, 183 NFSERR_BADXDR, 184 NFSERR_RESOURCE, 185 NFSERR_SERVERFAULT, 186 0, 187 }; 188 189 static short nfscberr_recall[] = { 190 NFSERR_RESOURCE, 191 NFSERR_BADHANDLE, 192 NFSERR_BADSTATEID, 193 NFSERR_BADXDR, 194 NFSERR_RESOURCE, 195 NFSERR_SERVERFAULT, 196 0, 197 }; 198 199 static short *nfscl_cberrmap[] = { 200 nfscberr_null, 201 nfscberr_null, 202 nfscberr_null, 203 nfscberr_getattr, 204 nfscberr_recall 205 }; 206 207 #define NETFAMILY(clp) \ 208 (((clp)->nfsc_flags & NFSCLFLAGS_AFINET6) ? AF_INET6 : AF_INET) 209 210 /* 211 * Called for an open operation. 212 * If the nfhp argument is NULL, just get an openowner. 213 */ 214 APPLESTATIC int 215 nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg, 216 struct ucred *cred, NFSPROC_T *p, struct nfsclowner **owpp, 217 struct nfsclopen **opp, int *newonep, int *retp, int lockit) 218 { 219 struct nfsclclient *clp; 220 struct nfsclowner *owp, *nowp; 221 struct nfsclopen *op = NULL, *nop = NULL; 222 struct nfscldeleg *dp; 223 struct nfsclownerhead *ohp; 224 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 225 int ret; 226 227 if (newonep != NULL) 228 *newonep = 0; 229 if (opp != NULL) 230 *opp = NULL; 231 if (owpp != NULL) 232 *owpp = NULL; 233 234 /* 235 * Might need one or both of these, so MALLOC them now, to 236 * avoid a tsleep() in MALLOC later. 237 */ 238 nowp = malloc(sizeof (struct nfsclowner), 239 M_NFSCLOWNER, M_WAITOK); 240 if (nfhp != NULL) 241 nop = malloc(sizeof (struct nfsclopen) + 242 fhlen - 1, M_NFSCLOPEN, M_WAITOK); 243 ret = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 244 if (ret != 0) { 245 free(nowp, M_NFSCLOWNER); 246 if (nop != NULL) 247 free(nop, M_NFSCLOPEN); 248 return (ret); 249 } 250 251 /* 252 * Get the Open iff it already exists. 253 * If none found, add the new one or return error, depending upon 254 * "create". 255 */ 256 NFSLOCKCLSTATE(); 257 dp = NULL; 258 /* First check the delegation list */ 259 if (nfhp != NULL && usedeleg) { 260 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) { 261 if (dp->nfsdl_fhlen == fhlen && 262 !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) { 263 if (!(amode & NFSV4OPEN_ACCESSWRITE) || 264 (dp->nfsdl_flags & NFSCLDL_WRITE)) 265 break; 266 dp = NULL; 267 break; 268 } 269 } 270 } 271 272 if (dp != NULL) { 273 nfscl_filllockowner(p->td_proc, own, F_POSIX); 274 ohp = &dp->nfsdl_owner; 275 } else { 276 /* For NFSv4.1 and this option, use a single open_owner. */ 277 if (NFSHASONEOPENOWN(VFSTONFS(vnode_mount(vp)))) 278 nfscl_filllockowner(NULL, own, F_POSIX); 279 else 280 nfscl_filllockowner(p->td_proc, own, F_POSIX); 281 ohp = &clp->nfsc_owner; 282 } 283 /* Now, search for an openowner */ 284 LIST_FOREACH(owp, ohp, nfsow_list) { 285 if (!NFSBCMP(owp->nfsow_owner, own, NFSV4CL_LOCKNAMELEN)) 286 break; 287 } 288 289 /* 290 * Create a new open, as required. 291 */ 292 nfscl_newopen(clp, dp, &owp, &nowp, &op, &nop, own, nfhp, fhlen, 293 cred, newonep); 294 295 /* 296 * Now, check the mode on the open and return the appropriate 297 * value. 298 */ 299 if (retp != NULL) { 300 if (nfhp != NULL && dp != NULL && nop == NULL) 301 /* new local open on delegation */ 302 *retp = NFSCLOPEN_SETCRED; 303 else 304 *retp = NFSCLOPEN_OK; 305 } 306 if (op != NULL && (amode & ~(op->nfso_mode))) { 307 op->nfso_mode |= amode; 308 if (retp != NULL && dp == NULL) 309 *retp = NFSCLOPEN_DOOPEN; 310 } 311 312 /* 313 * Serialize modifications to the open owner for multiple threads 314 * within the same process using a read/write sleep lock. 315 * For NFSv4.1 and a single OpenOwner, allow concurrent open operations 316 * by acquiring a shared lock. The close operations still use an 317 * exclusive lock for this case. 318 */ 319 if (lockit != 0) { 320 if (NFSHASONEOPENOWN(VFSTONFS(vnode_mount(vp)))) { 321 /* 322 * Get a shared lock on the OpenOwner, but first 323 * wait for any pending exclusive lock, so that the 324 * exclusive locker gets priority. 325 */ 326 nfsv4_lock(&owp->nfsow_rwlock, 0, NULL, 327 NFSCLSTATEMUTEXPTR, NULL); 328 nfsv4_getref(&owp->nfsow_rwlock, NULL, 329 NFSCLSTATEMUTEXPTR, NULL); 330 } else 331 nfscl_lockexcl(&owp->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 332 } 333 NFSUNLOCKCLSTATE(); 334 if (nowp != NULL) 335 free(nowp, M_NFSCLOWNER); 336 if (nop != NULL) 337 free(nop, M_NFSCLOPEN); 338 if (owpp != NULL) 339 *owpp = owp; 340 if (opp != NULL) 341 *opp = op; 342 return (0); 343 } 344 345 /* 346 * Create a new open, as required. 347 */ 348 static void 349 nfscl_newopen(struct nfsclclient *clp, struct nfscldeleg *dp, 350 struct nfsclowner **owpp, struct nfsclowner **nowpp, struct nfsclopen **opp, 351 struct nfsclopen **nopp, u_int8_t *own, u_int8_t *fhp, int fhlen, 352 struct ucred *cred, int *newonep) 353 { 354 struct nfsclowner *owp = *owpp, *nowp; 355 struct nfsclopen *op, *nop; 356 357 if (nowpp != NULL) 358 nowp = *nowpp; 359 else 360 nowp = NULL; 361 if (nopp != NULL) 362 nop = *nopp; 363 else 364 nop = NULL; 365 if (owp == NULL && nowp != NULL) { 366 NFSBCOPY(own, nowp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 367 LIST_INIT(&nowp->nfsow_open); 368 nowp->nfsow_clp = clp; 369 nowp->nfsow_seqid = 0; 370 nowp->nfsow_defunct = 0; 371 nfscl_lockinit(&nowp->nfsow_rwlock); 372 if (dp != NULL) { 373 nfsstatsv1.cllocalopenowners++; 374 LIST_INSERT_HEAD(&dp->nfsdl_owner, nowp, nfsow_list); 375 } else { 376 nfsstatsv1.clopenowners++; 377 LIST_INSERT_HEAD(&clp->nfsc_owner, nowp, nfsow_list); 378 } 379 owp = *owpp = nowp; 380 *nowpp = NULL; 381 if (newonep != NULL) 382 *newonep = 1; 383 } 384 385 /* If an fhp has been specified, create an Open as well. */ 386 if (fhp != NULL) { 387 /* and look for the correct open, based upon FH */ 388 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 389 if (op->nfso_fhlen == fhlen && 390 !NFSBCMP(op->nfso_fh, fhp, fhlen)) 391 break; 392 } 393 if (op == NULL && nop != NULL) { 394 nop->nfso_own = owp; 395 nop->nfso_mode = 0; 396 nop->nfso_opencnt = 0; 397 nop->nfso_posixlock = 1; 398 nop->nfso_fhlen = fhlen; 399 NFSBCOPY(fhp, nop->nfso_fh, fhlen); 400 LIST_INIT(&nop->nfso_lock); 401 nop->nfso_stateid.seqid = 0; 402 nop->nfso_stateid.other[0] = 0; 403 nop->nfso_stateid.other[1] = 0; 404 nop->nfso_stateid.other[2] = 0; 405 KASSERT(cred != NULL, ("%s: cred NULL\n", __func__)); 406 newnfs_copyincred(cred, &nop->nfso_cred); 407 if (dp != NULL) { 408 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 409 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, 410 nfsdl_list); 411 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 412 nfsstatsv1.cllocalopens++; 413 } else { 414 nfsstatsv1.clopens++; 415 } 416 LIST_INSERT_HEAD(&owp->nfsow_open, nop, nfso_list); 417 *opp = nop; 418 *nopp = NULL; 419 if (newonep != NULL) 420 *newonep = 1; 421 } else { 422 *opp = op; 423 } 424 } 425 } 426 427 /* 428 * Called to find/add a delegation to a client. 429 */ 430 APPLESTATIC int 431 nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp, 432 int fhlen, struct ucred *cred, NFSPROC_T *p, struct nfscldeleg **dpp) 433 { 434 struct nfscldeleg *dp = *dpp, *tdp; 435 436 /* 437 * First, if we have received a Read delegation for a file on a 438 * read/write file system, just return it, because they aren't 439 * useful, imho. 440 */ 441 if (mp != NULL && dp != NULL && !NFSMNT_RDONLY(mp) && 442 (dp->nfsdl_flags & NFSCLDL_READ)) { 443 (void) nfscl_trydelegreturn(dp, cred, VFSTONFS(mp), p); 444 free(dp, M_NFSCLDELEG); 445 *dpp = NULL; 446 return (0); 447 } 448 449 /* Look for the correct deleg, based upon FH */ 450 NFSLOCKCLSTATE(); 451 tdp = nfscl_finddeleg(clp, nfhp, fhlen); 452 if (tdp == NULL) { 453 if (dp == NULL) { 454 NFSUNLOCKCLSTATE(); 455 return (NFSERR_BADSTATEID); 456 } 457 *dpp = NULL; 458 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list); 459 LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, nfhp, fhlen), dp, 460 nfsdl_hash); 461 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 462 nfsstatsv1.cldelegates++; 463 nfscl_delegcnt++; 464 } else { 465 /* 466 * Delegation already exists, what do we do if a new one?? 467 */ 468 if (dp != NULL) { 469 printf("Deleg already exists!\n"); 470 free(dp, M_NFSCLDELEG); 471 *dpp = NULL; 472 } else { 473 *dpp = tdp; 474 } 475 } 476 NFSUNLOCKCLSTATE(); 477 return (0); 478 } 479 480 /* 481 * Find a delegation for this file handle. Return NULL upon failure. 482 */ 483 static struct nfscldeleg * 484 nfscl_finddeleg(struct nfsclclient *clp, u_int8_t *fhp, int fhlen) 485 { 486 struct nfscldeleg *dp; 487 488 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, fhp, fhlen), nfsdl_hash) { 489 if (dp->nfsdl_fhlen == fhlen && 490 !NFSBCMP(dp->nfsdl_fh, fhp, fhlen)) 491 break; 492 } 493 return (dp); 494 } 495 496 /* 497 * Get a stateid for an I/O operation. First, look for an open and iff 498 * found, return either a lockowner stateid or the open stateid. 499 * If no Open is found, just return error and the special stateid of all zeros. 500 */ 501 APPLESTATIC int 502 nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode, 503 int fords, struct ucred *cred, NFSPROC_T *p, nfsv4stateid_t *stateidp, 504 void **lckpp) 505 { 506 struct nfsclclient *clp; 507 struct nfsclowner *owp; 508 struct nfsclopen *op = NULL, *top; 509 struct nfscllockowner *lp; 510 struct nfscldeleg *dp; 511 struct nfsnode *np; 512 struct nfsmount *nmp; 513 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 514 int error, done; 515 516 *lckpp = NULL; 517 /* 518 * Initially, just set the special stateid of all zeros. 519 * (Don't do this for a DS, since the special stateid can't be used.) 520 */ 521 if (fords == 0) { 522 stateidp->seqid = 0; 523 stateidp->other[0] = 0; 524 stateidp->other[1] = 0; 525 stateidp->other[2] = 0; 526 } 527 if (vnode_vtype(vp) != VREG) 528 return (EISDIR); 529 np = VTONFS(vp); 530 nmp = VFSTONFS(vnode_mount(vp)); 531 NFSLOCKCLSTATE(); 532 clp = nfscl_findcl(nmp); 533 if (clp == NULL) { 534 NFSUNLOCKCLSTATE(); 535 return (EACCES); 536 } 537 538 /* 539 * Wait for recovery to complete. 540 */ 541 while ((clp->nfsc_flags & NFSCLFLAGS_RECVRINPROG)) 542 (void) nfsmsleep(&clp->nfsc_flags, NFSCLSTATEMUTEXPTR, 543 PZERO, "nfsrecvr", NULL); 544 545 /* 546 * First, look for a delegation. 547 */ 548 LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) { 549 if (dp->nfsdl_fhlen == fhlen && 550 !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) { 551 if (!(mode & NFSV4OPEN_ACCESSWRITE) || 552 (dp->nfsdl_flags & NFSCLDL_WRITE)) { 553 stateidp->seqid = dp->nfsdl_stateid.seqid; 554 stateidp->other[0] = dp->nfsdl_stateid.other[0]; 555 stateidp->other[1] = dp->nfsdl_stateid.other[1]; 556 stateidp->other[2] = dp->nfsdl_stateid.other[2]; 557 if (!(np->n_flag & NDELEGRECALL)) { 558 TAILQ_REMOVE(&clp->nfsc_deleg, dp, 559 nfsdl_list); 560 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, 561 nfsdl_list); 562 dp->nfsdl_timestamp = NFSD_MONOSEC + 563 120; 564 dp->nfsdl_rwlock.nfslock_usecnt++; 565 *lckpp = (void *)&dp->nfsdl_rwlock; 566 } 567 NFSUNLOCKCLSTATE(); 568 return (0); 569 } 570 break; 571 } 572 } 573 574 if (p != NULL) { 575 /* 576 * If p != NULL, we want to search the parentage tree 577 * for a matching OpenOwner and use that. 578 */ 579 if (NFSHASONEOPENOWN(VFSTONFS(vnode_mount(vp)))) 580 nfscl_filllockowner(NULL, own, F_POSIX); 581 else 582 nfscl_filllockowner(p->td_proc, own, F_POSIX); 583 lp = NULL; 584 error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, own, own, 585 mode, &lp, &op); 586 if (error == 0 && lp != NULL && fords == 0) { 587 /* Don't return a lock stateid for a DS. */ 588 stateidp->seqid = 589 lp->nfsl_stateid.seqid; 590 stateidp->other[0] = 591 lp->nfsl_stateid.other[0]; 592 stateidp->other[1] = 593 lp->nfsl_stateid.other[1]; 594 stateidp->other[2] = 595 lp->nfsl_stateid.other[2]; 596 NFSUNLOCKCLSTATE(); 597 return (0); 598 } 599 } 600 if (op == NULL) { 601 /* If not found, just look for any OpenOwner that will work. */ 602 top = NULL; 603 done = 0; 604 owp = LIST_FIRST(&clp->nfsc_owner); 605 while (!done && owp != NULL) { 606 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 607 if (op->nfso_fhlen == fhlen && 608 !NFSBCMP(op->nfso_fh, nfhp, fhlen)) { 609 if (top == NULL && (op->nfso_mode & 610 NFSV4OPEN_ACCESSWRITE) != 0 && 611 (mode & NFSV4OPEN_ACCESSREAD) != 0) 612 top = op; 613 if ((mode & op->nfso_mode) == mode) { 614 done = 1; 615 break; 616 } 617 } 618 } 619 if (!done) 620 owp = LIST_NEXT(owp, nfsow_list); 621 } 622 if (!done) { 623 NFSCL_DEBUG(2, "openmode top=%p\n", top); 624 if (top == NULL || NFSHASOPENMODE(nmp)) { 625 NFSUNLOCKCLSTATE(); 626 return (ENOENT); 627 } else 628 op = top; 629 } 630 /* 631 * For read aheads or write behinds, use the open cred. 632 * A read ahead or write behind is indicated by p == NULL. 633 */ 634 if (p == NULL) 635 newnfs_copycred(&op->nfso_cred, cred); 636 } 637 638 /* 639 * No lock stateid, so return the open stateid. 640 */ 641 stateidp->seqid = op->nfso_stateid.seqid; 642 stateidp->other[0] = op->nfso_stateid.other[0]; 643 stateidp->other[1] = op->nfso_stateid.other[1]; 644 stateidp->other[2] = op->nfso_stateid.other[2]; 645 NFSUNLOCKCLSTATE(); 646 return (0); 647 } 648 649 /* 650 * Search for a matching file, mode and, optionally, lockowner. 651 */ 652 static int 653 nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen, 654 u_int8_t *openown, u_int8_t *lockown, u_int32_t mode, 655 struct nfscllockowner **lpp, struct nfsclopen **opp) 656 { 657 struct nfsclowner *owp; 658 struct nfsclopen *op, *rop, *rop2; 659 struct nfscllockowner *lp; 660 int keep_looping; 661 662 if (lpp != NULL) 663 *lpp = NULL; 664 /* 665 * rop will be set to the open to be returned. There are three 666 * variants of this, all for an open of the correct file: 667 * 1 - A match of lockown. 668 * 2 - A match of the openown, when no lockown match exists. 669 * 3 - A match for any open, if no openown or lockown match exists. 670 * Looking for #2 over #3 probably isn't necessary, but since 671 * RFC3530 is vague w.r.t. the relationship between openowners and 672 * lockowners, I think this is the safer way to go. 673 */ 674 rop = NULL; 675 rop2 = NULL; 676 keep_looping = 1; 677 /* Search the client list */ 678 owp = LIST_FIRST(ohp); 679 while (owp != NULL && keep_looping != 0) { 680 /* and look for the correct open */ 681 op = LIST_FIRST(&owp->nfsow_open); 682 while (op != NULL && keep_looping != 0) { 683 if (op->nfso_fhlen == fhlen && 684 !NFSBCMP(op->nfso_fh, nfhp, fhlen) 685 && (op->nfso_mode & mode) == mode) { 686 if (lpp != NULL) { 687 /* Now look for a matching lockowner. */ 688 LIST_FOREACH(lp, &op->nfso_lock, 689 nfsl_list) { 690 if (!NFSBCMP(lp->nfsl_owner, 691 lockown, 692 NFSV4CL_LOCKNAMELEN)) { 693 *lpp = lp; 694 rop = op; 695 keep_looping = 0; 696 break; 697 } 698 } 699 } 700 if (rop == NULL && !NFSBCMP(owp->nfsow_owner, 701 openown, NFSV4CL_LOCKNAMELEN)) { 702 rop = op; 703 if (lpp == NULL) 704 keep_looping = 0; 705 } 706 if (rop2 == NULL) 707 rop2 = op; 708 } 709 op = LIST_NEXT(op, nfso_list); 710 } 711 owp = LIST_NEXT(owp, nfsow_list); 712 } 713 if (rop == NULL) 714 rop = rop2; 715 if (rop == NULL) 716 return (EBADF); 717 *opp = rop; 718 return (0); 719 } 720 721 /* 722 * Release use of an open owner. Called when open operations are done 723 * with the open owner. 724 */ 725 APPLESTATIC void 726 nfscl_ownerrelease(struct nfsmount *nmp, struct nfsclowner *owp, 727 __unused int error, __unused int candelete, int unlocked) 728 { 729 730 if (owp == NULL) 731 return; 732 NFSLOCKCLSTATE(); 733 if (unlocked == 0) { 734 if (NFSHASONEOPENOWN(nmp)) 735 nfsv4_relref(&owp->nfsow_rwlock); 736 else 737 nfscl_lockunlock(&owp->nfsow_rwlock); 738 } 739 nfscl_clrelease(owp->nfsow_clp); 740 NFSUNLOCKCLSTATE(); 741 } 742 743 /* 744 * Release use of an open structure under an open owner. 745 */ 746 APPLESTATIC void 747 nfscl_openrelease(struct nfsmount *nmp, struct nfsclopen *op, int error, 748 int candelete) 749 { 750 struct nfsclclient *clp; 751 struct nfsclowner *owp; 752 753 if (op == NULL) 754 return; 755 NFSLOCKCLSTATE(); 756 owp = op->nfso_own; 757 if (NFSHASONEOPENOWN(nmp)) 758 nfsv4_relref(&owp->nfsow_rwlock); 759 else 760 nfscl_lockunlock(&owp->nfsow_rwlock); 761 clp = owp->nfsow_clp; 762 if (error && candelete && op->nfso_opencnt == 0) 763 nfscl_freeopen(op, 0); 764 nfscl_clrelease(clp); 765 NFSUNLOCKCLSTATE(); 766 } 767 768 /* 769 * Called to get a clientid structure. It will optionally lock the 770 * client data structures to do the SetClientId/SetClientId_confirm, 771 * but will release that lock and return the clientid with a reference 772 * count on it. 773 * If the "cred" argument is NULL, a new clientid should not be created. 774 * If the "p" argument is NULL, a SetClientID/SetClientIDConfirm cannot 775 * be done. 776 * The start_renewthread argument tells nfscl_getcl() to start a renew 777 * thread if this creates a new clp. 778 * It always clpp with a reference count on it, unless returning an error. 779 */ 780 APPLESTATIC int 781 nfscl_getcl(struct mount *mp, struct ucred *cred, NFSPROC_T *p, 782 int start_renewthread, struct nfsclclient **clpp) 783 { 784 struct nfsclclient *clp; 785 struct nfsclclient *newclp = NULL; 786 struct nfsmount *nmp; 787 char uuid[HOSTUUIDLEN]; 788 int igotlock = 0, error, trystalecnt, clidinusedelay, i; 789 u_int16_t idlen = 0; 790 791 nmp = VFSTONFS(mp); 792 if (cred != NULL) { 793 getcredhostuuid(cred, uuid, sizeof uuid); 794 idlen = strlen(uuid); 795 if (idlen > 0) 796 idlen += sizeof (u_int64_t); 797 else 798 idlen += sizeof (u_int64_t) + 16; /* 16 random bytes */ 799 newclp = malloc( 800 sizeof (struct nfsclclient) + idlen - 1, M_NFSCLCLIENT, 801 M_WAITOK | M_ZERO); 802 } 803 NFSLOCKCLSTATE(); 804 /* 805 * If a forced dismount is already in progress, don't 806 * allocate a new clientid and get out now. For the case where 807 * clp != NULL, this is a harmless optimization. 808 */ 809 if (NFSCL_FORCEDISM(mp)) { 810 NFSUNLOCKCLSTATE(); 811 if (newclp != NULL) 812 free(newclp, M_NFSCLCLIENT); 813 return (EBADF); 814 } 815 clp = nmp->nm_clp; 816 if (clp == NULL) { 817 if (newclp == NULL) { 818 NFSUNLOCKCLSTATE(); 819 return (EACCES); 820 } 821 clp = newclp; 822 clp->nfsc_idlen = idlen; 823 LIST_INIT(&clp->nfsc_owner); 824 TAILQ_INIT(&clp->nfsc_deleg); 825 TAILQ_INIT(&clp->nfsc_layout); 826 LIST_INIT(&clp->nfsc_devinfo); 827 for (i = 0; i < NFSCLDELEGHASHSIZE; i++) 828 LIST_INIT(&clp->nfsc_deleghash[i]); 829 for (i = 0; i < NFSCLLAYOUTHASHSIZE; i++) 830 LIST_INIT(&clp->nfsc_layouthash[i]); 831 clp->nfsc_flags = NFSCLFLAGS_INITED; 832 clp->nfsc_clientidrev = 1; 833 clp->nfsc_cbident = nfscl_nextcbident(); 834 nfscl_fillclid(nmp->nm_clval, uuid, clp->nfsc_id, 835 clp->nfsc_idlen); 836 LIST_INSERT_HEAD(&nfsclhead, clp, nfsc_list); 837 nmp->nm_clp = clp; 838 clp->nfsc_nmp = nmp; 839 NFSUNLOCKCLSTATE(); 840 if (start_renewthread != 0) 841 nfscl_start_renewthread(clp); 842 } else { 843 NFSUNLOCKCLSTATE(); 844 if (newclp != NULL) 845 free(newclp, M_NFSCLCLIENT); 846 } 847 NFSLOCKCLSTATE(); 848 while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock && 849 !NFSCL_FORCEDISM(mp)) 850 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 851 NFSCLSTATEMUTEXPTR, mp); 852 if (igotlock == 0) { 853 /* 854 * Call nfsv4_lock() with "iwantlock == 0" so that it will 855 * wait for a pending exclusive lock request. This gives the 856 * exclusive lock request priority over this shared lock 857 * request. 858 * An exclusive lock on nfsc_lock is used mainly for server 859 * crash recoveries. 860 */ 861 nfsv4_lock(&clp->nfsc_lock, 0, NULL, NFSCLSTATEMUTEXPTR, mp); 862 nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, mp); 863 } 864 if (igotlock == 0 && NFSCL_FORCEDISM(mp)) { 865 /* 866 * Both nfsv4_lock() and nfsv4_getref() know to check 867 * for NFSCL_FORCEDISM() and return without sleeping to 868 * wait for the exclusive lock to be released, since it 869 * might be held by nfscl_umount() and we need to get out 870 * now for that case and not wait until nfscl_umount() 871 * releases it. 872 */ 873 NFSUNLOCKCLSTATE(); 874 return (EBADF); 875 } 876 NFSUNLOCKCLSTATE(); 877 878 /* 879 * If it needs a clientid, do the setclientid now. 880 */ 881 if ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0) { 882 if (!igotlock) 883 panic("nfscl_clget"); 884 if (p == NULL || cred == NULL) { 885 NFSLOCKCLSTATE(); 886 nfsv4_unlock(&clp->nfsc_lock, 0); 887 NFSUNLOCKCLSTATE(); 888 return (EACCES); 889 } 890 /* 891 * If RFC3530 Sec. 14.2.33 is taken literally, 892 * NFSERR_CLIDINUSE will be returned persistently for the 893 * case where a new mount of the same file system is using 894 * a different principal. In practice, NFSERR_CLIDINUSE is 895 * only returned when there is outstanding unexpired state 896 * on the clientid. As such, try for twice the lease 897 * interval, if we know what that is. Otherwise, make a 898 * wild ass guess. 899 * The case of returning NFSERR_STALECLIENTID is far less 900 * likely, but might occur if there is a significant delay 901 * between doing the SetClientID and SetClientIDConfirm Ops, 902 * such that the server throws away the clientid before 903 * receiving the SetClientIDConfirm. 904 */ 905 if (clp->nfsc_renew > 0) 906 clidinusedelay = NFSCL_LEASE(clp->nfsc_renew) * 2; 907 else 908 clidinusedelay = 120; 909 trystalecnt = 3; 910 do { 911 error = nfsrpc_setclient(nmp, clp, 0, NULL, cred, p); 912 if (error == NFSERR_STALECLIENTID || 913 error == NFSERR_STALEDONTRECOVER || 914 error == NFSERR_BADSESSION || 915 error == NFSERR_CLIDINUSE) { 916 (void) nfs_catnap(PZERO, error, "nfs_setcl"); 917 } 918 } while (((error == NFSERR_STALECLIENTID || 919 error == NFSERR_BADSESSION || 920 error == NFSERR_STALEDONTRECOVER) && --trystalecnt > 0) || 921 (error == NFSERR_CLIDINUSE && --clidinusedelay > 0)); 922 if (error) { 923 NFSLOCKCLSTATE(); 924 nfsv4_unlock(&clp->nfsc_lock, 0); 925 NFSUNLOCKCLSTATE(); 926 return (error); 927 } 928 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 929 } 930 if (igotlock) { 931 NFSLOCKCLSTATE(); 932 nfsv4_unlock(&clp->nfsc_lock, 1); 933 NFSUNLOCKCLSTATE(); 934 } 935 936 *clpp = clp; 937 return (0); 938 } 939 940 /* 941 * Get a reference to a clientid and return it, if valid. 942 */ 943 APPLESTATIC struct nfsclclient * 944 nfscl_findcl(struct nfsmount *nmp) 945 { 946 struct nfsclclient *clp; 947 948 clp = nmp->nm_clp; 949 if (clp == NULL || !(clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) 950 return (NULL); 951 return (clp); 952 } 953 954 /* 955 * Release the clientid structure. It may be locked or reference counted. 956 */ 957 static void 958 nfscl_clrelease(struct nfsclclient *clp) 959 { 960 961 if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK) 962 nfsv4_unlock(&clp->nfsc_lock, 0); 963 else 964 nfsv4_relref(&clp->nfsc_lock); 965 } 966 967 /* 968 * External call for nfscl_clrelease. 969 */ 970 APPLESTATIC void 971 nfscl_clientrelease(struct nfsclclient *clp) 972 { 973 974 NFSLOCKCLSTATE(); 975 if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK) 976 nfsv4_unlock(&clp->nfsc_lock, 0); 977 else 978 nfsv4_relref(&clp->nfsc_lock); 979 NFSUNLOCKCLSTATE(); 980 } 981 982 /* 983 * Called when wanting to lock a byte region. 984 */ 985 APPLESTATIC int 986 nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len, 987 short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp, 988 int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp, 989 struct nfscllockowner **lpp, int *newonep, int *donelocallyp) 990 { 991 struct nfscllockowner *lp; 992 struct nfsclopen *op; 993 struct nfsclclient *clp; 994 struct nfscllockowner *nlp; 995 struct nfscllock *nlop, *otherlop; 996 struct nfscldeleg *dp = NULL, *ldp = NULL; 997 struct nfscllockownerhead *lhp = NULL; 998 struct nfsnode *np; 999 u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp, openown[NFSV4CL_LOCKNAMELEN]; 1000 u_int8_t *openownp; 1001 int error = 0, ret, donelocally = 0; 1002 u_int32_t mode; 1003 1004 /* For Lock Ops, the open mode doesn't matter, so use 0 to match any. */ 1005 mode = 0; 1006 np = VTONFS(vp); 1007 *lpp = NULL; 1008 lp = NULL; 1009 *newonep = 0; 1010 *donelocallyp = 0; 1011 1012 /* 1013 * Might need these, so MALLOC them now, to 1014 * avoid a tsleep() in MALLOC later. 1015 */ 1016 nlp = malloc( 1017 sizeof (struct nfscllockowner), M_NFSCLLOCKOWNER, M_WAITOK); 1018 otherlop = malloc( 1019 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1020 nlop = malloc( 1021 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1022 nlop->nfslo_type = type; 1023 nlop->nfslo_first = off; 1024 if (len == NFS64BITSSET) { 1025 nlop->nfslo_end = NFS64BITSSET; 1026 } else { 1027 nlop->nfslo_end = off + len; 1028 if (nlop->nfslo_end <= nlop->nfslo_first) 1029 error = NFSERR_INVAL; 1030 } 1031 1032 if (!error) { 1033 if (recovery) 1034 clp = rclp; 1035 else 1036 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 1037 } 1038 if (error) { 1039 free(nlp, M_NFSCLLOCKOWNER); 1040 free(otherlop, M_NFSCLLOCK); 1041 free(nlop, M_NFSCLLOCK); 1042 return (error); 1043 } 1044 1045 op = NULL; 1046 if (recovery) { 1047 ownp = rownp; 1048 openownp = ropenownp; 1049 } else { 1050 nfscl_filllockowner(id, own, flags); 1051 ownp = own; 1052 if (NFSHASONEOPENOWN(VFSTONFS(vnode_mount(vp)))) 1053 nfscl_filllockowner(NULL, openown, F_POSIX); 1054 else 1055 nfscl_filllockowner(p->td_proc, openown, F_POSIX); 1056 openownp = openown; 1057 } 1058 if (!recovery) { 1059 NFSLOCKCLSTATE(); 1060 /* 1061 * First, search for a delegation. If one exists for this file, 1062 * the lock can be done locally against it, so long as there 1063 * isn't a local lock conflict. 1064 */ 1065 ldp = dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 1066 np->n_fhp->nfh_len); 1067 /* Just sanity check for correct type of delegation */ 1068 if (dp != NULL && ((dp->nfsdl_flags & 1069 (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) != 0 || 1070 (type == F_WRLCK && 1071 (dp->nfsdl_flags & NFSCLDL_WRITE) == 0))) 1072 dp = NULL; 1073 } 1074 if (dp != NULL) { 1075 /* Now, find an open and maybe a lockowner. */ 1076 ret = nfscl_getopen(&dp->nfsdl_owner, np->n_fhp->nfh_fh, 1077 np->n_fhp->nfh_len, openownp, ownp, mode, NULL, &op); 1078 if (ret) 1079 ret = nfscl_getopen(&clp->nfsc_owner, 1080 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp, 1081 ownp, mode, NULL, &op); 1082 if (!ret) { 1083 lhp = &dp->nfsdl_lock; 1084 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 1085 TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list); 1086 dp->nfsdl_timestamp = NFSD_MONOSEC + 120; 1087 donelocally = 1; 1088 } else { 1089 dp = NULL; 1090 } 1091 } 1092 if (!donelocally) { 1093 /* 1094 * Get the related Open and maybe lockowner. 1095 */ 1096 error = nfscl_getopen(&clp->nfsc_owner, 1097 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp, 1098 ownp, mode, &lp, &op); 1099 if (!error) 1100 lhp = &op->nfso_lock; 1101 } 1102 if (!error && !recovery) 1103 error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, 1104 np->n_fhp->nfh_len, nlop, ownp, ldp, NULL); 1105 if (error) { 1106 if (!recovery) { 1107 nfscl_clrelease(clp); 1108 NFSUNLOCKCLSTATE(); 1109 } 1110 free(nlp, M_NFSCLLOCKOWNER); 1111 free(otherlop, M_NFSCLLOCK); 1112 free(nlop, M_NFSCLLOCK); 1113 return (error); 1114 } 1115 1116 /* 1117 * Ok, see if a lockowner exists and create one, as required. 1118 */ 1119 if (lp == NULL) 1120 LIST_FOREACH(lp, lhp, nfsl_list) { 1121 if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN)) 1122 break; 1123 } 1124 if (lp == NULL) { 1125 NFSBCOPY(ownp, nlp->nfsl_owner, NFSV4CL_LOCKNAMELEN); 1126 if (recovery) 1127 NFSBCOPY(ropenownp, nlp->nfsl_openowner, 1128 NFSV4CL_LOCKNAMELEN); 1129 else 1130 NFSBCOPY(op->nfso_own->nfsow_owner, nlp->nfsl_openowner, 1131 NFSV4CL_LOCKNAMELEN); 1132 nlp->nfsl_seqid = 0; 1133 nlp->nfsl_lockflags = flags; 1134 nlp->nfsl_inprog = NULL; 1135 nfscl_lockinit(&nlp->nfsl_rwlock); 1136 LIST_INIT(&nlp->nfsl_lock); 1137 if (donelocally) { 1138 nlp->nfsl_open = NULL; 1139 nfsstatsv1.cllocallockowners++; 1140 } else { 1141 nlp->nfsl_open = op; 1142 nfsstatsv1.cllockowners++; 1143 } 1144 LIST_INSERT_HEAD(lhp, nlp, nfsl_list); 1145 lp = nlp; 1146 nlp = NULL; 1147 *newonep = 1; 1148 } 1149 1150 /* 1151 * Now, update the byte ranges for locks. 1152 */ 1153 ret = nfscl_updatelock(lp, &nlop, &otherlop, donelocally); 1154 if (!ret) 1155 donelocally = 1; 1156 if (donelocally) { 1157 *donelocallyp = 1; 1158 if (!recovery) 1159 nfscl_clrelease(clp); 1160 } else { 1161 /* 1162 * Serial modifications on the lock owner for multiple threads 1163 * for the same process using a read/write lock. 1164 */ 1165 if (!recovery) 1166 nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR); 1167 } 1168 if (!recovery) 1169 NFSUNLOCKCLSTATE(); 1170 1171 if (nlp) 1172 free(nlp, M_NFSCLLOCKOWNER); 1173 if (nlop) 1174 free(nlop, M_NFSCLLOCK); 1175 if (otherlop) 1176 free(otherlop, M_NFSCLLOCK); 1177 1178 *lpp = lp; 1179 return (0); 1180 } 1181 1182 /* 1183 * Called to unlock a byte range, for LockU. 1184 */ 1185 APPLESTATIC int 1186 nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len, 1187 __unused struct ucred *cred, NFSPROC_T *p, int callcnt, 1188 struct nfsclclient *clp, void *id, int flags, 1189 struct nfscllockowner **lpp, int *dorpcp) 1190 { 1191 struct nfscllockowner *lp; 1192 struct nfsclowner *owp; 1193 struct nfsclopen *op; 1194 struct nfscllock *nlop, *other_lop = NULL; 1195 struct nfscldeleg *dp; 1196 struct nfsnode *np; 1197 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1198 int ret = 0, fnd; 1199 1200 np = VTONFS(vp); 1201 *lpp = NULL; 1202 *dorpcp = 0; 1203 1204 /* 1205 * Might need these, so MALLOC them now, to 1206 * avoid a tsleep() in MALLOC later. 1207 */ 1208 nlop = malloc( 1209 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1210 nlop->nfslo_type = F_UNLCK; 1211 nlop->nfslo_first = off; 1212 if (len == NFS64BITSSET) { 1213 nlop->nfslo_end = NFS64BITSSET; 1214 } else { 1215 nlop->nfslo_end = off + len; 1216 if (nlop->nfslo_end <= nlop->nfslo_first) { 1217 free(nlop, M_NFSCLLOCK); 1218 return (NFSERR_INVAL); 1219 } 1220 } 1221 if (callcnt == 0) { 1222 other_lop = malloc( 1223 sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK); 1224 *other_lop = *nlop; 1225 } 1226 nfscl_filllockowner(id, own, flags); 1227 dp = NULL; 1228 NFSLOCKCLSTATE(); 1229 if (callcnt == 0) 1230 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 1231 np->n_fhp->nfh_len); 1232 1233 /* 1234 * First, unlock any local regions on a delegation. 1235 */ 1236 if (dp != NULL) { 1237 /* Look for this lockowner. */ 1238 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 1239 if (!NFSBCMP(lp->nfsl_owner, own, 1240 NFSV4CL_LOCKNAMELEN)) 1241 break; 1242 } 1243 if (lp != NULL) 1244 /* Use other_lop, so nlop is still available */ 1245 (void)nfscl_updatelock(lp, &other_lop, NULL, 1); 1246 } 1247 1248 /* 1249 * Now, find a matching open/lockowner that hasn't already been done, 1250 * as marked by nfsl_inprog. 1251 */ 1252 lp = NULL; 1253 fnd = 0; 1254 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1255 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1256 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1257 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1258 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1259 if (lp->nfsl_inprog == NULL && 1260 !NFSBCMP(lp->nfsl_owner, own, 1261 NFSV4CL_LOCKNAMELEN)) { 1262 fnd = 1; 1263 break; 1264 } 1265 } 1266 if (fnd) 1267 break; 1268 } 1269 } 1270 if (fnd) 1271 break; 1272 } 1273 1274 if (lp != NULL) { 1275 ret = nfscl_updatelock(lp, &nlop, NULL, 0); 1276 if (ret) 1277 *dorpcp = 1; 1278 /* 1279 * Serial modifications on the lock owner for multiple 1280 * threads for the same process using a read/write lock. 1281 */ 1282 lp->nfsl_inprog = p; 1283 nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR); 1284 *lpp = lp; 1285 } 1286 NFSUNLOCKCLSTATE(); 1287 if (nlop) 1288 free(nlop, M_NFSCLLOCK); 1289 if (other_lop) 1290 free(other_lop, M_NFSCLLOCK); 1291 return (0); 1292 } 1293 1294 /* 1295 * Release all lockowners marked in progess for this process and file. 1296 */ 1297 APPLESTATIC void 1298 nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p, 1299 void *id, int flags) 1300 { 1301 struct nfsclowner *owp; 1302 struct nfsclopen *op; 1303 struct nfscllockowner *lp; 1304 struct nfsnode *np; 1305 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1306 1307 np = VTONFS(vp); 1308 nfscl_filllockowner(id, own, flags); 1309 NFSLOCKCLSTATE(); 1310 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1311 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1312 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1313 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1314 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1315 if (lp->nfsl_inprog == p && 1316 !NFSBCMP(lp->nfsl_owner, own, 1317 NFSV4CL_LOCKNAMELEN)) { 1318 lp->nfsl_inprog = NULL; 1319 nfscl_lockunlock(&lp->nfsl_rwlock); 1320 } 1321 } 1322 } 1323 } 1324 } 1325 nfscl_clrelease(clp); 1326 NFSUNLOCKCLSTATE(); 1327 } 1328 1329 /* 1330 * Called to find out if any bytes within the byte range specified are 1331 * write locked by the calling process. Used to determine if flushing 1332 * is required before a LockU. 1333 * If in doubt, return 1, so the flush will occur. 1334 */ 1335 APPLESTATIC int 1336 nfscl_checkwritelocked(vnode_t vp, struct flock *fl, 1337 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 1338 { 1339 struct nfsclowner *owp; 1340 struct nfscllockowner *lp; 1341 struct nfsclopen *op; 1342 struct nfsclclient *clp; 1343 struct nfscllock *lop; 1344 struct nfscldeleg *dp; 1345 struct nfsnode *np; 1346 u_int64_t off, end; 1347 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 1348 int error = 0; 1349 1350 np = VTONFS(vp); 1351 switch (fl->l_whence) { 1352 case SEEK_SET: 1353 case SEEK_CUR: 1354 /* 1355 * Caller is responsible for adding any necessary offset 1356 * when SEEK_CUR is used. 1357 */ 1358 off = fl->l_start; 1359 break; 1360 case SEEK_END: 1361 off = np->n_size + fl->l_start; 1362 break; 1363 default: 1364 return (1); 1365 } 1366 if (fl->l_len != 0) { 1367 end = off + fl->l_len; 1368 if (end < off) 1369 return (1); 1370 } else { 1371 end = NFS64BITSSET; 1372 } 1373 1374 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 1375 if (error) 1376 return (1); 1377 nfscl_filllockowner(id, own, flags); 1378 NFSLOCKCLSTATE(); 1379 1380 /* 1381 * First check the delegation locks. 1382 */ 1383 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 1384 if (dp != NULL) { 1385 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 1386 if (!NFSBCMP(lp->nfsl_owner, own, 1387 NFSV4CL_LOCKNAMELEN)) 1388 break; 1389 } 1390 if (lp != NULL) { 1391 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 1392 if (lop->nfslo_first >= end) 1393 break; 1394 if (lop->nfslo_end <= off) 1395 continue; 1396 if (lop->nfslo_type == F_WRLCK) { 1397 nfscl_clrelease(clp); 1398 NFSUNLOCKCLSTATE(); 1399 return (1); 1400 } 1401 } 1402 } 1403 } 1404 1405 /* 1406 * Now, check state against the server. 1407 */ 1408 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 1409 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1410 if (op->nfso_fhlen == np->n_fhp->nfh_len && 1411 !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) { 1412 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1413 if (!NFSBCMP(lp->nfsl_owner, own, 1414 NFSV4CL_LOCKNAMELEN)) 1415 break; 1416 } 1417 if (lp != NULL) { 1418 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 1419 if (lop->nfslo_first >= end) 1420 break; 1421 if (lop->nfslo_end <= off) 1422 continue; 1423 if (lop->nfslo_type == F_WRLCK) { 1424 nfscl_clrelease(clp); 1425 NFSUNLOCKCLSTATE(); 1426 return (1); 1427 } 1428 } 1429 } 1430 } 1431 } 1432 } 1433 nfscl_clrelease(clp); 1434 NFSUNLOCKCLSTATE(); 1435 return (0); 1436 } 1437 1438 /* 1439 * Release a byte range lock owner structure. 1440 */ 1441 APPLESTATIC void 1442 nfscl_lockrelease(struct nfscllockowner *lp, int error, int candelete) 1443 { 1444 struct nfsclclient *clp; 1445 1446 if (lp == NULL) 1447 return; 1448 NFSLOCKCLSTATE(); 1449 clp = lp->nfsl_open->nfso_own->nfsow_clp; 1450 if (error != 0 && candelete && 1451 (lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED) == 0) 1452 nfscl_freelockowner(lp, 0); 1453 else 1454 nfscl_lockunlock(&lp->nfsl_rwlock); 1455 nfscl_clrelease(clp); 1456 NFSUNLOCKCLSTATE(); 1457 } 1458 1459 /* 1460 * Free up an open structure and any associated byte range lock structures. 1461 */ 1462 APPLESTATIC void 1463 nfscl_freeopen(struct nfsclopen *op, int local) 1464 { 1465 1466 LIST_REMOVE(op, nfso_list); 1467 nfscl_freealllocks(&op->nfso_lock, local); 1468 free(op, M_NFSCLOPEN); 1469 if (local) 1470 nfsstatsv1.cllocalopens--; 1471 else 1472 nfsstatsv1.clopens--; 1473 } 1474 1475 /* 1476 * Free up all lock owners and associated locks. 1477 */ 1478 static void 1479 nfscl_freealllocks(struct nfscllockownerhead *lhp, int local) 1480 { 1481 struct nfscllockowner *lp, *nlp; 1482 1483 LIST_FOREACH_SAFE(lp, lhp, nfsl_list, nlp) { 1484 if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED)) 1485 panic("nfscllckw"); 1486 nfscl_freelockowner(lp, local); 1487 } 1488 } 1489 1490 /* 1491 * Called for an Open when NFSERR_EXPIRED is received from the server. 1492 * If there are no byte range locks nor a Share Deny lost, try to do a 1493 * fresh Open. Otherwise, free the open. 1494 */ 1495 static int 1496 nfscl_expireopen(struct nfsclclient *clp, struct nfsclopen *op, 1497 struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 1498 { 1499 struct nfscllockowner *lp; 1500 struct nfscldeleg *dp; 1501 int mustdelete = 0, error; 1502 1503 /* 1504 * Look for any byte range lock(s). 1505 */ 1506 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 1507 if (!LIST_EMPTY(&lp->nfsl_lock)) { 1508 mustdelete = 1; 1509 break; 1510 } 1511 } 1512 1513 /* 1514 * If no byte range lock(s) nor a Share deny, try to re-open. 1515 */ 1516 if (!mustdelete && (op->nfso_mode & NFSLCK_DENYBITS) == 0) { 1517 newnfs_copycred(&op->nfso_cred, cred); 1518 dp = NULL; 1519 error = nfsrpc_reopen(nmp, op->nfso_fh, 1520 op->nfso_fhlen, op->nfso_mode, op, &dp, cred, p); 1521 if (error) { 1522 mustdelete = 1; 1523 if (dp != NULL) { 1524 free(dp, M_NFSCLDELEG); 1525 dp = NULL; 1526 } 1527 } 1528 if (dp != NULL) 1529 nfscl_deleg(nmp->nm_mountp, clp, op->nfso_fh, 1530 op->nfso_fhlen, cred, p, &dp); 1531 } 1532 1533 /* 1534 * If a byte range lock or Share deny or couldn't re-open, free it. 1535 */ 1536 if (mustdelete) 1537 nfscl_freeopen(op, 0); 1538 return (mustdelete); 1539 } 1540 1541 /* 1542 * Free up an open owner structure. 1543 */ 1544 static void 1545 nfscl_freeopenowner(struct nfsclowner *owp, int local) 1546 { 1547 1548 LIST_REMOVE(owp, nfsow_list); 1549 free(owp, M_NFSCLOWNER); 1550 if (local) 1551 nfsstatsv1.cllocalopenowners--; 1552 else 1553 nfsstatsv1.clopenowners--; 1554 } 1555 1556 /* 1557 * Free up a byte range lock owner structure. 1558 */ 1559 APPLESTATIC void 1560 nfscl_freelockowner(struct nfscllockowner *lp, int local) 1561 { 1562 struct nfscllock *lop, *nlop; 1563 1564 LIST_REMOVE(lp, nfsl_list); 1565 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 1566 nfscl_freelock(lop, local); 1567 } 1568 free(lp, M_NFSCLLOCKOWNER); 1569 if (local) 1570 nfsstatsv1.cllocallockowners--; 1571 else 1572 nfsstatsv1.cllockowners--; 1573 } 1574 1575 /* 1576 * Free up a byte range lock structure. 1577 */ 1578 APPLESTATIC void 1579 nfscl_freelock(struct nfscllock *lop, int local) 1580 { 1581 1582 LIST_REMOVE(lop, nfslo_list); 1583 free(lop, M_NFSCLLOCK); 1584 if (local) 1585 nfsstatsv1.cllocallocks--; 1586 else 1587 nfsstatsv1.cllocks--; 1588 } 1589 1590 /* 1591 * Clean out the state related to a delegation. 1592 */ 1593 static void 1594 nfscl_cleandeleg(struct nfscldeleg *dp) 1595 { 1596 struct nfsclowner *owp, *nowp; 1597 struct nfsclopen *op; 1598 1599 LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) { 1600 op = LIST_FIRST(&owp->nfsow_open); 1601 if (op != NULL) { 1602 if (LIST_NEXT(op, nfso_list) != NULL) 1603 panic("nfscleandel"); 1604 nfscl_freeopen(op, 1); 1605 } 1606 nfscl_freeopenowner(owp, 1); 1607 } 1608 nfscl_freealllocks(&dp->nfsdl_lock, 1); 1609 } 1610 1611 /* 1612 * Free a delegation. 1613 */ 1614 static void 1615 nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp) 1616 { 1617 1618 TAILQ_REMOVE(hdp, dp, nfsdl_list); 1619 LIST_REMOVE(dp, nfsdl_hash); 1620 free(dp, M_NFSCLDELEG); 1621 nfsstatsv1.cldelegates--; 1622 nfscl_delegcnt--; 1623 } 1624 1625 /* 1626 * Free up all state related to this client structure. 1627 */ 1628 static void 1629 nfscl_cleanclient(struct nfsclclient *clp) 1630 { 1631 struct nfsclowner *owp, *nowp; 1632 struct nfsclopen *op, *nop; 1633 struct nfscllayout *lyp, *nlyp; 1634 struct nfscldevinfo *dip, *ndip; 1635 1636 TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp) 1637 nfscl_freelayout(lyp); 1638 1639 LIST_FOREACH_SAFE(dip, &clp->nfsc_devinfo, nfsdi_list, ndip) 1640 nfscl_freedevinfo(dip); 1641 1642 /* Now, all the OpenOwners, etc. */ 1643 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1644 LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) { 1645 nfscl_freeopen(op, 0); 1646 } 1647 nfscl_freeopenowner(owp, 0); 1648 } 1649 } 1650 1651 /* 1652 * Called when an NFSERR_EXPIRED is received from the server. 1653 */ 1654 static void 1655 nfscl_expireclient(struct nfsclclient *clp, struct nfsmount *nmp, 1656 struct ucred *cred, NFSPROC_T *p) 1657 { 1658 struct nfsclowner *owp, *nowp, *towp; 1659 struct nfsclopen *op, *nop, *top; 1660 struct nfscldeleg *dp, *ndp; 1661 int ret, printed = 0; 1662 1663 /* 1664 * First, merge locally issued Opens into the list for the server. 1665 */ 1666 dp = TAILQ_FIRST(&clp->nfsc_deleg); 1667 while (dp != NULL) { 1668 ndp = TAILQ_NEXT(dp, nfsdl_list); 1669 owp = LIST_FIRST(&dp->nfsdl_owner); 1670 while (owp != NULL) { 1671 nowp = LIST_NEXT(owp, nfsow_list); 1672 op = LIST_FIRST(&owp->nfsow_open); 1673 if (op != NULL) { 1674 if (LIST_NEXT(op, nfso_list) != NULL) 1675 panic("nfsclexp"); 1676 LIST_FOREACH(towp, &clp->nfsc_owner, nfsow_list) { 1677 if (!NFSBCMP(towp->nfsow_owner, owp->nfsow_owner, 1678 NFSV4CL_LOCKNAMELEN)) 1679 break; 1680 } 1681 if (towp != NULL) { 1682 /* Merge opens in */ 1683 LIST_FOREACH(top, &towp->nfsow_open, nfso_list) { 1684 if (top->nfso_fhlen == op->nfso_fhlen && 1685 !NFSBCMP(top->nfso_fh, op->nfso_fh, 1686 op->nfso_fhlen)) { 1687 top->nfso_mode |= op->nfso_mode; 1688 top->nfso_opencnt += op->nfso_opencnt; 1689 break; 1690 } 1691 } 1692 if (top == NULL) { 1693 /* Just add the open to the owner list */ 1694 LIST_REMOVE(op, nfso_list); 1695 op->nfso_own = towp; 1696 LIST_INSERT_HEAD(&towp->nfsow_open, op, nfso_list); 1697 nfsstatsv1.cllocalopens--; 1698 nfsstatsv1.clopens++; 1699 } 1700 } else { 1701 /* Just add the openowner to the client list */ 1702 LIST_REMOVE(owp, nfsow_list); 1703 owp->nfsow_clp = clp; 1704 LIST_INSERT_HEAD(&clp->nfsc_owner, owp, nfsow_list); 1705 nfsstatsv1.cllocalopenowners--; 1706 nfsstatsv1.clopenowners++; 1707 nfsstatsv1.cllocalopens--; 1708 nfsstatsv1.clopens++; 1709 } 1710 } 1711 owp = nowp; 1712 } 1713 if (!printed && !LIST_EMPTY(&dp->nfsdl_lock)) { 1714 printed = 1; 1715 printf("nfsv4 expired locks lost\n"); 1716 } 1717 nfscl_cleandeleg(dp); 1718 nfscl_freedeleg(&clp->nfsc_deleg, dp); 1719 dp = ndp; 1720 } 1721 if (!TAILQ_EMPTY(&clp->nfsc_deleg)) 1722 panic("nfsclexp"); 1723 1724 /* 1725 * Now, try and reopen against the server. 1726 */ 1727 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1728 owp->nfsow_seqid = 0; 1729 LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) { 1730 ret = nfscl_expireopen(clp, op, nmp, cred, p); 1731 if (ret && !printed) { 1732 printed = 1; 1733 printf("nfsv4 expired locks lost\n"); 1734 } 1735 } 1736 if (LIST_EMPTY(&owp->nfsow_open)) 1737 nfscl_freeopenowner(owp, 0); 1738 } 1739 } 1740 1741 /* 1742 * This function must be called after the process represented by "own" has 1743 * exited. Must be called with CLSTATE lock held. 1744 */ 1745 static void 1746 nfscl_cleanup_common(struct nfsclclient *clp, u_int8_t *own) 1747 { 1748 struct nfsclowner *owp, *nowp; 1749 struct nfscllockowner *lp, *nlp; 1750 struct nfscldeleg *dp; 1751 1752 /* First, get rid of local locks on delegations. */ 1753 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 1754 LIST_FOREACH_SAFE(lp, &dp->nfsdl_lock, nfsl_list, nlp) { 1755 if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) { 1756 if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED)) 1757 panic("nfscllckw"); 1758 nfscl_freelockowner(lp, 1); 1759 } 1760 } 1761 } 1762 owp = LIST_FIRST(&clp->nfsc_owner); 1763 while (owp != NULL) { 1764 nowp = LIST_NEXT(owp, nfsow_list); 1765 if (!NFSBCMP(owp->nfsow_owner, own, 1766 NFSV4CL_LOCKNAMELEN)) { 1767 /* 1768 * If there are children that haven't closed the 1769 * file descriptors yet, the opens will still be 1770 * here. For that case, let the renew thread clear 1771 * out the OpenOwner later. 1772 */ 1773 if (LIST_EMPTY(&owp->nfsow_open)) 1774 nfscl_freeopenowner(owp, 0); 1775 else 1776 owp->nfsow_defunct = 1; 1777 } 1778 owp = nowp; 1779 } 1780 } 1781 1782 /* 1783 * Find open/lock owners for processes that have exited. 1784 */ 1785 static void 1786 nfscl_cleanupkext(struct nfsclclient *clp, struct nfscllockownerfhhead *lhp) 1787 { 1788 struct nfsclowner *owp, *nowp; 1789 struct nfsclopen *op; 1790 struct nfscllockowner *lp, *nlp; 1791 struct nfscldeleg *dp; 1792 1793 /* 1794 * All the pidhash locks must be acquired, since they are sx locks 1795 * and must be acquired before the mutexes. The pid(s) that will 1796 * be used aren't known yet, so all the locks need to be acquired. 1797 * Fortunately, this function is only performed once/sec. 1798 */ 1799 pidhash_slockall(); 1800 NFSLOCKCLSTATE(); 1801 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 1802 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 1803 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) { 1804 if (LIST_EMPTY(&lp->nfsl_lock)) 1805 nfscl_emptylockowner(lp, lhp); 1806 } 1807 } 1808 if (nfscl_procdoesntexist(owp->nfsow_owner)) 1809 nfscl_cleanup_common(clp, owp->nfsow_owner); 1810 } 1811 1812 /* 1813 * For the single open_owner case, these lock owners need to be 1814 * checked to see if they still exist separately. 1815 * This is because nfscl_procdoesntexist() never returns true for 1816 * the single open_owner so that the above doesn't ever call 1817 * nfscl_cleanup_common(). 1818 */ 1819 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 1820 LIST_FOREACH_SAFE(lp, &dp->nfsdl_lock, nfsl_list, nlp) { 1821 if (nfscl_procdoesntexist(lp->nfsl_owner)) 1822 nfscl_cleanup_common(clp, lp->nfsl_owner); 1823 } 1824 } 1825 NFSUNLOCKCLSTATE(); 1826 pidhash_sunlockall(); 1827 } 1828 1829 /* 1830 * Take the empty lock owner and move it to the local lhp list if the 1831 * associated process no longer exists. 1832 */ 1833 static void 1834 nfscl_emptylockowner(struct nfscllockowner *lp, 1835 struct nfscllockownerfhhead *lhp) 1836 { 1837 struct nfscllockownerfh *lfhp, *mylfhp; 1838 struct nfscllockowner *nlp; 1839 int fnd_it; 1840 1841 /* If not a Posix lock owner, just return. */ 1842 if ((lp->nfsl_lockflags & F_POSIX) == 0) 1843 return; 1844 1845 fnd_it = 0; 1846 mylfhp = NULL; 1847 /* 1848 * First, search to see if this lock owner is already in the list. 1849 * If it is, then the associated process no longer exists. 1850 */ 1851 SLIST_FOREACH(lfhp, lhp, nfslfh_list) { 1852 if (lfhp->nfslfh_len == lp->nfsl_open->nfso_fhlen && 1853 !NFSBCMP(lfhp->nfslfh_fh, lp->nfsl_open->nfso_fh, 1854 lfhp->nfslfh_len)) 1855 mylfhp = lfhp; 1856 LIST_FOREACH(nlp, &lfhp->nfslfh_lock, nfsl_list) 1857 if (!NFSBCMP(nlp->nfsl_owner, lp->nfsl_owner, 1858 NFSV4CL_LOCKNAMELEN)) 1859 fnd_it = 1; 1860 } 1861 /* If not found, check if process still exists. */ 1862 if (fnd_it == 0 && nfscl_procdoesntexist(lp->nfsl_owner) == 0) 1863 return; 1864 1865 /* Move the lock owner over to the local list. */ 1866 if (mylfhp == NULL) { 1867 mylfhp = malloc(sizeof(struct nfscllockownerfh), M_TEMP, 1868 M_NOWAIT); 1869 if (mylfhp == NULL) 1870 return; 1871 mylfhp->nfslfh_len = lp->nfsl_open->nfso_fhlen; 1872 NFSBCOPY(lp->nfsl_open->nfso_fh, mylfhp->nfslfh_fh, 1873 mylfhp->nfslfh_len); 1874 LIST_INIT(&mylfhp->nfslfh_lock); 1875 SLIST_INSERT_HEAD(lhp, mylfhp, nfslfh_list); 1876 } 1877 LIST_REMOVE(lp, nfsl_list); 1878 LIST_INSERT_HEAD(&mylfhp->nfslfh_lock, lp, nfsl_list); 1879 } 1880 1881 static int fake_global; /* Used to force visibility of MNTK_UNMOUNTF */ 1882 /* 1883 * Called from nfs umount to free up the clientid. 1884 */ 1885 APPLESTATIC void 1886 nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p) 1887 { 1888 struct nfsclclient *clp; 1889 struct ucred *cred; 1890 int igotlock; 1891 1892 /* 1893 * For the case that matters, this is the thread that set 1894 * MNTK_UNMOUNTF, so it will see it set. The code that follows is 1895 * done to ensure that any thread executing nfscl_getcl() after 1896 * this time, will see MNTK_UNMOUNTF set. nfscl_getcl() uses the 1897 * mutex for NFSLOCKCLSTATE(), so it is "m" for the following 1898 * explanation, courtesy of Alan Cox. 1899 * What follows is a snippet from Alan Cox's email at: 1900 * https://docs.FreeBSD.org/cgi/mid.cgi?BANLkTikR3d65zPHo9==08ZfJ2vmqZucEvw 1901 * 1902 * 1. Set MNTK_UNMOUNTF 1903 * 2. Acquire a standard FreeBSD mutex "m". 1904 * 3. Update some data structures. 1905 * 4. Release mutex "m". 1906 * 1907 * Then, other threads that acquire "m" after step 4 has occurred will 1908 * see MNTK_UNMOUNTF as set. But, other threads that beat thread X to 1909 * step 2 may or may not see MNTK_UNMOUNTF as set. 1910 */ 1911 NFSLOCKCLSTATE(); 1912 if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1913 fake_global++; 1914 NFSUNLOCKCLSTATE(); 1915 NFSLOCKCLSTATE(); 1916 } 1917 1918 clp = nmp->nm_clp; 1919 if (clp != NULL) { 1920 if ((clp->nfsc_flags & NFSCLFLAGS_INITED) == 0) 1921 panic("nfscl umount"); 1922 1923 /* 1924 * First, handshake with the nfscl renew thread, to terminate 1925 * it. 1926 */ 1927 clp->nfsc_flags |= NFSCLFLAGS_UMOUNT; 1928 while (clp->nfsc_flags & NFSCLFLAGS_HASTHREAD) 1929 (void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT, 1930 "nfsclumnt", hz); 1931 1932 /* 1933 * Now, get the exclusive lock on the client state, so 1934 * that no uses of the state are still in progress. 1935 */ 1936 do { 1937 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 1938 NFSCLSTATEMUTEXPTR, NULL); 1939 } while (!igotlock); 1940 NFSUNLOCKCLSTATE(); 1941 1942 /* 1943 * Free up all the state. It will expire on the server, but 1944 * maybe we should do a SetClientId/SetClientIdConfirm so 1945 * the server throws it away? 1946 */ 1947 LIST_REMOVE(clp, nfsc_list); 1948 nfscl_delegreturnall(clp, p); 1949 cred = newnfs_getcred(); 1950 if (NFSHASNFSV4N(nmp)) { 1951 (void)nfsrpc_destroysession(nmp, clp, cred, p); 1952 (void)nfsrpc_destroyclient(nmp, clp, cred, p); 1953 } else 1954 (void)nfsrpc_setclient(nmp, clp, 0, NULL, cred, p); 1955 nfscl_cleanclient(clp); 1956 nmp->nm_clp = NULL; 1957 NFSFREECRED(cred); 1958 free(clp, M_NFSCLCLIENT); 1959 } else 1960 NFSUNLOCKCLSTATE(); 1961 } 1962 1963 /* 1964 * This function is called when a server replies with NFSERR_STALECLIENTID 1965 * NFSERR_STALESTATEID or NFSERR_BADSESSION. It traverses the clientid lists, 1966 * doing Opens and Locks with reclaim. If these fail, it deletes the 1967 * corresponding state. 1968 */ 1969 static void 1970 nfscl_recover(struct nfsclclient *clp, bool *retokp, struct ucred *cred, 1971 NFSPROC_T *p) 1972 { 1973 struct nfsclowner *owp, *nowp; 1974 struct nfsclopen *op, *nop; 1975 struct nfscllockowner *lp, *nlp; 1976 struct nfscllock *lop, *nlop; 1977 struct nfscldeleg *dp, *ndp, *tdp; 1978 struct nfsmount *nmp; 1979 struct ucred *tcred; 1980 struct nfsclopenhead extra_open; 1981 struct nfscldeleghead extra_deleg; 1982 struct nfsreq *rep; 1983 u_int64_t len; 1984 u_int32_t delegtype = NFSV4OPEN_DELEGATEWRITE, mode; 1985 int i, igotlock = 0, error, trycnt, firstlock; 1986 struct nfscllayout *lyp, *nlyp; 1987 1988 /* 1989 * First, lock the client structure, so everyone else will 1990 * block when trying to use state. 1991 */ 1992 NFSLOCKCLSTATE(); 1993 clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG; 1994 do { 1995 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 1996 NFSCLSTATEMUTEXPTR, NULL); 1997 } while (!igotlock); 1998 NFSUNLOCKCLSTATE(); 1999 2000 nmp = clp->nfsc_nmp; 2001 if (nmp == NULL) 2002 panic("nfscl recover"); 2003 2004 /* 2005 * For now, just get rid of all layouts. There may be a need 2006 * to do LayoutCommit Ops with reclaim == true later. 2007 */ 2008 TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp) 2009 nfscl_freelayout(lyp); 2010 TAILQ_INIT(&clp->nfsc_layout); 2011 for (i = 0; i < NFSCLLAYOUTHASHSIZE; i++) 2012 LIST_INIT(&clp->nfsc_layouthash[i]); 2013 2014 trycnt = 5; 2015 tcred = NULL; 2016 do { 2017 error = nfsrpc_setclient(nmp, clp, 1, retokp, cred, p); 2018 } while ((error == NFSERR_STALECLIENTID || 2019 error == NFSERR_BADSESSION || 2020 error == NFSERR_STALEDONTRECOVER) && --trycnt > 0); 2021 if (error) { 2022 NFSLOCKCLSTATE(); 2023 clp->nfsc_flags &= ~(NFSCLFLAGS_RECOVER | 2024 NFSCLFLAGS_RECVRINPROG); 2025 wakeup(&clp->nfsc_flags); 2026 nfsv4_unlock(&clp->nfsc_lock, 0); 2027 NFSUNLOCKCLSTATE(); 2028 return; 2029 } 2030 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 2031 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 2032 2033 /* 2034 * Mark requests already queued on the server, so that they don't 2035 * initiate another recovery cycle. Any requests already in the 2036 * queue that handle state information will have the old stale 2037 * clientid/stateid and will get a NFSERR_STALESTATEID, 2038 * NFSERR_STALECLIENTID or NFSERR_BADSESSION reply from the server. 2039 * This will be translated to NFSERR_STALEDONTRECOVER when 2040 * R_DONTRECOVER is set. 2041 */ 2042 NFSLOCKREQ(); 2043 TAILQ_FOREACH(rep, &nfsd_reqq, r_chain) { 2044 if (rep->r_nmp == nmp) 2045 rep->r_flags |= R_DONTRECOVER; 2046 } 2047 NFSUNLOCKREQ(); 2048 2049 /* 2050 * If nfsrpc_setclient() returns *retokp == true, 2051 * no more recovery is needed. 2052 */ 2053 if (*retokp) 2054 goto out; 2055 2056 /* 2057 * Now, mark all delegations "need reclaim". 2058 */ 2059 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) 2060 dp->nfsdl_flags |= NFSCLDL_NEEDRECLAIM; 2061 2062 TAILQ_INIT(&extra_deleg); 2063 LIST_INIT(&extra_open); 2064 /* 2065 * Now traverse the state lists, doing Open and Lock Reclaims. 2066 */ 2067 tcred = newnfs_getcred(); 2068 owp = LIST_FIRST(&clp->nfsc_owner); 2069 while (owp != NULL) { 2070 nowp = LIST_NEXT(owp, nfsow_list); 2071 owp->nfsow_seqid = 0; 2072 op = LIST_FIRST(&owp->nfsow_open); 2073 while (op != NULL) { 2074 nop = LIST_NEXT(op, nfso_list); 2075 if (error != NFSERR_NOGRACE && error != NFSERR_BADSESSION) { 2076 /* Search for a delegation to reclaim with the open */ 2077 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 2078 if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) 2079 continue; 2080 if ((dp->nfsdl_flags & NFSCLDL_WRITE)) { 2081 mode = NFSV4OPEN_ACCESSWRITE; 2082 delegtype = NFSV4OPEN_DELEGATEWRITE; 2083 } else { 2084 mode = NFSV4OPEN_ACCESSREAD; 2085 delegtype = NFSV4OPEN_DELEGATEREAD; 2086 } 2087 if ((op->nfso_mode & mode) == mode && 2088 op->nfso_fhlen == dp->nfsdl_fhlen && 2089 !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, op->nfso_fhlen)) 2090 break; 2091 } 2092 ndp = dp; 2093 if (dp == NULL) 2094 delegtype = NFSV4OPEN_DELEGATENONE; 2095 newnfs_copycred(&op->nfso_cred, tcred); 2096 error = nfscl_tryopen(nmp, NULL, op->nfso_fh, 2097 op->nfso_fhlen, op->nfso_fh, op->nfso_fhlen, 2098 op->nfso_mode, op, NULL, 0, &ndp, 1, delegtype, 2099 tcred, p); 2100 if (!error) { 2101 /* Handle any replied delegation */ 2102 if (ndp != NULL && ((ndp->nfsdl_flags & NFSCLDL_WRITE) 2103 || NFSMNT_RDONLY(nmp->nm_mountp))) { 2104 if ((ndp->nfsdl_flags & NFSCLDL_WRITE)) 2105 mode = NFSV4OPEN_ACCESSWRITE; 2106 else 2107 mode = NFSV4OPEN_ACCESSREAD; 2108 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 2109 if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) 2110 continue; 2111 if ((op->nfso_mode & mode) == mode && 2112 op->nfso_fhlen == dp->nfsdl_fhlen && 2113 !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, 2114 op->nfso_fhlen)) { 2115 dp->nfsdl_stateid = ndp->nfsdl_stateid; 2116 dp->nfsdl_sizelimit = ndp->nfsdl_sizelimit; 2117 dp->nfsdl_ace = ndp->nfsdl_ace; 2118 dp->nfsdl_change = ndp->nfsdl_change; 2119 dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM; 2120 if ((ndp->nfsdl_flags & NFSCLDL_RECALL)) 2121 dp->nfsdl_flags |= NFSCLDL_RECALL; 2122 free(ndp, M_NFSCLDELEG); 2123 ndp = NULL; 2124 break; 2125 } 2126 } 2127 } 2128 if (ndp != NULL) 2129 TAILQ_INSERT_HEAD(&extra_deleg, ndp, nfsdl_list); 2130 2131 /* and reclaim all byte range locks */ 2132 lp = LIST_FIRST(&op->nfso_lock); 2133 while (lp != NULL) { 2134 nlp = LIST_NEXT(lp, nfsl_list); 2135 lp->nfsl_seqid = 0; 2136 firstlock = 1; 2137 lop = LIST_FIRST(&lp->nfsl_lock); 2138 while (lop != NULL) { 2139 nlop = LIST_NEXT(lop, nfslo_list); 2140 if (lop->nfslo_end == NFS64BITSSET) 2141 len = NFS64BITSSET; 2142 else 2143 len = lop->nfslo_end - lop->nfslo_first; 2144 error = nfscl_trylock(nmp, NULL, 2145 op->nfso_fh, op->nfso_fhlen, lp, 2146 firstlock, 1, lop->nfslo_first, len, 2147 lop->nfslo_type, tcred, p); 2148 if (error != 0) 2149 nfscl_freelock(lop, 0); 2150 else 2151 firstlock = 0; 2152 lop = nlop; 2153 } 2154 /* If no locks, but a lockowner, just delete it. */ 2155 if (LIST_EMPTY(&lp->nfsl_lock)) 2156 nfscl_freelockowner(lp, 0); 2157 lp = nlp; 2158 } 2159 } 2160 } 2161 if (error != 0 && error != NFSERR_BADSESSION) 2162 nfscl_freeopen(op, 0); 2163 op = nop; 2164 } 2165 owp = nowp; 2166 } 2167 2168 /* 2169 * Now, try and get any delegations not yet reclaimed by cobbling 2170 * to-gether an appropriate open. 2171 */ 2172 nowp = NULL; 2173 dp = TAILQ_FIRST(&clp->nfsc_deleg); 2174 while (dp != NULL) { 2175 ndp = TAILQ_NEXT(dp, nfsdl_list); 2176 if ((dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) { 2177 if (nowp == NULL) { 2178 nowp = malloc( 2179 sizeof (struct nfsclowner), M_NFSCLOWNER, M_WAITOK); 2180 /* 2181 * Name must be as long an largest possible 2182 * NFSV4CL_LOCKNAMELEN. 12 for now. 2183 */ 2184 NFSBCOPY("RECLAIMDELEG", nowp->nfsow_owner, 2185 NFSV4CL_LOCKNAMELEN); 2186 LIST_INIT(&nowp->nfsow_open); 2187 nowp->nfsow_clp = clp; 2188 nowp->nfsow_seqid = 0; 2189 nowp->nfsow_defunct = 0; 2190 nfscl_lockinit(&nowp->nfsow_rwlock); 2191 } 2192 nop = NULL; 2193 if (error != NFSERR_NOGRACE && error != NFSERR_BADSESSION) { 2194 nop = malloc(sizeof (struct nfsclopen) + 2195 dp->nfsdl_fhlen - 1, M_NFSCLOPEN, M_WAITOK); 2196 nop->nfso_own = nowp; 2197 if ((dp->nfsdl_flags & NFSCLDL_WRITE)) { 2198 nop->nfso_mode = NFSV4OPEN_ACCESSWRITE; 2199 delegtype = NFSV4OPEN_DELEGATEWRITE; 2200 } else { 2201 nop->nfso_mode = NFSV4OPEN_ACCESSREAD; 2202 delegtype = NFSV4OPEN_DELEGATEREAD; 2203 } 2204 nop->nfso_opencnt = 0; 2205 nop->nfso_posixlock = 1; 2206 nop->nfso_fhlen = dp->nfsdl_fhlen; 2207 NFSBCOPY(dp->nfsdl_fh, nop->nfso_fh, dp->nfsdl_fhlen); 2208 LIST_INIT(&nop->nfso_lock); 2209 nop->nfso_stateid.seqid = 0; 2210 nop->nfso_stateid.other[0] = 0; 2211 nop->nfso_stateid.other[1] = 0; 2212 nop->nfso_stateid.other[2] = 0; 2213 newnfs_copycred(&dp->nfsdl_cred, tcred); 2214 newnfs_copyincred(tcred, &nop->nfso_cred); 2215 tdp = NULL; 2216 error = nfscl_tryopen(nmp, NULL, nop->nfso_fh, 2217 nop->nfso_fhlen, nop->nfso_fh, nop->nfso_fhlen, 2218 nop->nfso_mode, nop, NULL, 0, &tdp, 1, 2219 delegtype, tcred, p); 2220 if (tdp != NULL) { 2221 if ((tdp->nfsdl_flags & NFSCLDL_WRITE)) 2222 mode = NFSV4OPEN_ACCESSWRITE; 2223 else 2224 mode = NFSV4OPEN_ACCESSREAD; 2225 if ((nop->nfso_mode & mode) == mode && 2226 nop->nfso_fhlen == tdp->nfsdl_fhlen && 2227 !NFSBCMP(nop->nfso_fh, tdp->nfsdl_fh, 2228 nop->nfso_fhlen)) { 2229 dp->nfsdl_stateid = tdp->nfsdl_stateid; 2230 dp->nfsdl_sizelimit = tdp->nfsdl_sizelimit; 2231 dp->nfsdl_ace = tdp->nfsdl_ace; 2232 dp->nfsdl_change = tdp->nfsdl_change; 2233 dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM; 2234 if ((tdp->nfsdl_flags & NFSCLDL_RECALL)) 2235 dp->nfsdl_flags |= NFSCLDL_RECALL; 2236 free(tdp, M_NFSCLDELEG); 2237 } else { 2238 TAILQ_INSERT_HEAD(&extra_deleg, tdp, nfsdl_list); 2239 } 2240 } 2241 } 2242 if (error) { 2243 if (nop != NULL) 2244 free(nop, M_NFSCLOPEN); 2245 /* 2246 * Couldn't reclaim it, so throw the state 2247 * away. Ouch!! 2248 */ 2249 nfscl_cleandeleg(dp); 2250 nfscl_freedeleg(&clp->nfsc_deleg, dp); 2251 } else { 2252 LIST_INSERT_HEAD(&extra_open, nop, nfso_list); 2253 } 2254 } 2255 dp = ndp; 2256 } 2257 2258 /* 2259 * Now, get rid of extra Opens and Delegations. 2260 */ 2261 LIST_FOREACH_SAFE(op, &extra_open, nfso_list, nop) { 2262 do { 2263 newnfs_copycred(&op->nfso_cred, tcred); 2264 error = nfscl_tryclose(op, tcred, nmp, p); 2265 if (error == NFSERR_GRACE) 2266 (void) nfs_catnap(PZERO, error, "nfsexcls"); 2267 } while (error == NFSERR_GRACE); 2268 LIST_REMOVE(op, nfso_list); 2269 free(op, M_NFSCLOPEN); 2270 } 2271 if (nowp != NULL) 2272 free(nowp, M_NFSCLOWNER); 2273 2274 TAILQ_FOREACH_SAFE(dp, &extra_deleg, nfsdl_list, ndp) { 2275 do { 2276 newnfs_copycred(&dp->nfsdl_cred, tcred); 2277 error = nfscl_trydelegreturn(dp, tcred, nmp, p); 2278 if (error == NFSERR_GRACE) 2279 (void) nfs_catnap(PZERO, error, "nfsexdlg"); 2280 } while (error == NFSERR_GRACE); 2281 TAILQ_REMOVE(&extra_deleg, dp, nfsdl_list); 2282 free(dp, M_NFSCLDELEG); 2283 } 2284 2285 /* For NFSv4.1 or later, do a RECLAIM_COMPLETE. */ 2286 if (NFSHASNFSV4N(nmp)) 2287 (void)nfsrpc_reclaimcomplete(nmp, cred, p); 2288 2289 out: 2290 NFSLOCKCLSTATE(); 2291 clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG; 2292 wakeup(&clp->nfsc_flags); 2293 nfsv4_unlock(&clp->nfsc_lock, 0); 2294 NFSUNLOCKCLSTATE(); 2295 if (tcred != NULL) 2296 NFSFREECRED(tcred); 2297 } 2298 2299 /* 2300 * This function is called when a server replies with NFSERR_EXPIRED. 2301 * It deletes all state for the client and does a fresh SetClientId/confirm. 2302 * XXX Someday it should post a signal to the process(es) that hold the 2303 * state, so they know that lock state has been lost. 2304 */ 2305 APPLESTATIC int 2306 nfscl_hasexpired(struct nfsclclient *clp, u_int32_t clidrev, NFSPROC_T *p) 2307 { 2308 struct nfsmount *nmp; 2309 struct ucred *cred; 2310 int igotlock = 0, error, trycnt; 2311 2312 /* 2313 * If the clientid has gone away or a new SetClientid has already 2314 * been done, just return ok. 2315 */ 2316 if (clp == NULL || clidrev != clp->nfsc_clientidrev) 2317 return (0); 2318 2319 /* 2320 * First, lock the client structure, so everyone else will 2321 * block when trying to use state. Also, use NFSCLFLAGS_EXPIREIT so 2322 * that only one thread does the work. 2323 */ 2324 NFSLOCKCLSTATE(); 2325 clp->nfsc_flags |= NFSCLFLAGS_EXPIREIT; 2326 do { 2327 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL, 2328 NFSCLSTATEMUTEXPTR, NULL); 2329 } while (!igotlock && (clp->nfsc_flags & NFSCLFLAGS_EXPIREIT)); 2330 if ((clp->nfsc_flags & NFSCLFLAGS_EXPIREIT) == 0) { 2331 if (igotlock) 2332 nfsv4_unlock(&clp->nfsc_lock, 0); 2333 NFSUNLOCKCLSTATE(); 2334 return (0); 2335 } 2336 clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG; 2337 NFSUNLOCKCLSTATE(); 2338 2339 nmp = clp->nfsc_nmp; 2340 if (nmp == NULL) 2341 panic("nfscl expired"); 2342 cred = newnfs_getcred(); 2343 trycnt = 5; 2344 do { 2345 error = nfsrpc_setclient(nmp, clp, 0, NULL, cred, p); 2346 } while ((error == NFSERR_STALECLIENTID || 2347 error == NFSERR_BADSESSION || 2348 error == NFSERR_STALEDONTRECOVER) && --trycnt > 0); 2349 if (error) { 2350 NFSLOCKCLSTATE(); 2351 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 2352 } else { 2353 /* 2354 * Expire the state for the client. 2355 */ 2356 nfscl_expireclient(clp, nmp, cred, p); 2357 NFSLOCKCLSTATE(); 2358 clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID; 2359 clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; 2360 } 2361 clp->nfsc_flags &= ~(NFSCLFLAGS_EXPIREIT | NFSCLFLAGS_RECVRINPROG); 2362 wakeup(&clp->nfsc_flags); 2363 nfsv4_unlock(&clp->nfsc_lock, 0); 2364 NFSUNLOCKCLSTATE(); 2365 NFSFREECRED(cred); 2366 return (error); 2367 } 2368 2369 /* 2370 * This function inserts a lock in the list after insert_lop. 2371 */ 2372 static void 2373 nfscl_insertlock(struct nfscllockowner *lp, struct nfscllock *new_lop, 2374 struct nfscllock *insert_lop, int local) 2375 { 2376 2377 if ((struct nfscllockowner *)insert_lop == lp) 2378 LIST_INSERT_HEAD(&lp->nfsl_lock, new_lop, nfslo_list); 2379 else 2380 LIST_INSERT_AFTER(insert_lop, new_lop, nfslo_list); 2381 if (local) 2382 nfsstatsv1.cllocallocks++; 2383 else 2384 nfsstatsv1.cllocks++; 2385 } 2386 2387 /* 2388 * This function updates the locking for a lock owner and given file. It 2389 * maintains a list of lock ranges ordered on increasing file offset that 2390 * are NFSCLLOCK_READ or NFSCLLOCK_WRITE and non-overlapping (aka POSIX style). 2391 * It always adds new_lop to the list and sometimes uses the one pointed 2392 * at by other_lopp. 2393 * Returns 1 if the locks were modified, 0 otherwise. 2394 */ 2395 static int 2396 nfscl_updatelock(struct nfscllockowner *lp, struct nfscllock **new_lopp, 2397 struct nfscllock **other_lopp, int local) 2398 { 2399 struct nfscllock *new_lop = *new_lopp; 2400 struct nfscllock *lop, *tlop, *ilop; 2401 struct nfscllock *other_lop; 2402 int unlock = 0, modified = 0; 2403 u_int64_t tmp; 2404 2405 /* 2406 * Work down the list until the lock is merged. 2407 */ 2408 if (new_lop->nfslo_type == F_UNLCK) 2409 unlock = 1; 2410 ilop = (struct nfscllock *)lp; 2411 lop = LIST_FIRST(&lp->nfsl_lock); 2412 while (lop != NULL) { 2413 /* 2414 * Only check locks for this file that aren't before the start of 2415 * new lock's range. 2416 */ 2417 if (lop->nfslo_end >= new_lop->nfslo_first) { 2418 if (new_lop->nfslo_end < lop->nfslo_first) { 2419 /* 2420 * If the new lock ends before the start of the 2421 * current lock's range, no merge, just insert 2422 * the new lock. 2423 */ 2424 break; 2425 } 2426 if (new_lop->nfslo_type == lop->nfslo_type || 2427 (new_lop->nfslo_first <= lop->nfslo_first && 2428 new_lop->nfslo_end >= lop->nfslo_end)) { 2429 /* 2430 * This lock can be absorbed by the new lock/unlock. 2431 * This happens when it covers the entire range 2432 * of the old lock or is contiguous 2433 * with the old lock and is of the same type or an 2434 * unlock. 2435 */ 2436 if (new_lop->nfslo_type != lop->nfslo_type || 2437 new_lop->nfslo_first != lop->nfslo_first || 2438 new_lop->nfslo_end != lop->nfslo_end) 2439 modified = 1; 2440 if (lop->nfslo_first < new_lop->nfslo_first) 2441 new_lop->nfslo_first = lop->nfslo_first; 2442 if (lop->nfslo_end > new_lop->nfslo_end) 2443 new_lop->nfslo_end = lop->nfslo_end; 2444 tlop = lop; 2445 lop = LIST_NEXT(lop, nfslo_list); 2446 nfscl_freelock(tlop, local); 2447 continue; 2448 } 2449 2450 /* 2451 * All these cases are for contiguous locks that are not the 2452 * same type, so they can't be merged. 2453 */ 2454 if (new_lop->nfslo_first <= lop->nfslo_first) { 2455 /* 2456 * This case is where the new lock overlaps with the 2457 * first part of the old lock. Move the start of the 2458 * old lock to just past the end of the new lock. The 2459 * new lock will be inserted in front of the old, since 2460 * ilop hasn't been updated. (We are done now.) 2461 */ 2462 if (lop->nfslo_first != new_lop->nfslo_end) { 2463 lop->nfslo_first = new_lop->nfslo_end; 2464 modified = 1; 2465 } 2466 break; 2467 } 2468 if (new_lop->nfslo_end >= lop->nfslo_end) { 2469 /* 2470 * This case is where the new lock overlaps with the 2471 * end of the old lock's range. Move the old lock's 2472 * end to just before the new lock's first and insert 2473 * the new lock after the old lock. 2474 * Might not be done yet, since the new lock could 2475 * overlap further locks with higher ranges. 2476 */ 2477 if (lop->nfslo_end != new_lop->nfslo_first) { 2478 lop->nfslo_end = new_lop->nfslo_first; 2479 modified = 1; 2480 } 2481 ilop = lop; 2482 lop = LIST_NEXT(lop, nfslo_list); 2483 continue; 2484 } 2485 /* 2486 * The final case is where the new lock's range is in the 2487 * middle of the current lock's and splits the current lock 2488 * up. Use *other_lopp to handle the second part of the 2489 * split old lock range. (We are done now.) 2490 * For unlock, we use new_lop as other_lop and tmp, since 2491 * other_lop and new_lop are the same for this case. 2492 * We noted the unlock case above, so we don't need 2493 * new_lop->nfslo_type any longer. 2494 */ 2495 tmp = new_lop->nfslo_first; 2496 if (unlock) { 2497 other_lop = new_lop; 2498 *new_lopp = NULL; 2499 } else { 2500 other_lop = *other_lopp; 2501 *other_lopp = NULL; 2502 } 2503 other_lop->nfslo_first = new_lop->nfslo_end; 2504 other_lop->nfslo_end = lop->nfslo_end; 2505 other_lop->nfslo_type = lop->nfslo_type; 2506 lop->nfslo_end = tmp; 2507 nfscl_insertlock(lp, other_lop, lop, local); 2508 ilop = lop; 2509 modified = 1; 2510 break; 2511 } 2512 ilop = lop; 2513 lop = LIST_NEXT(lop, nfslo_list); 2514 if (lop == NULL) 2515 break; 2516 } 2517 2518 /* 2519 * Insert the new lock in the list at the appropriate place. 2520 */ 2521 if (!unlock) { 2522 nfscl_insertlock(lp, new_lop, ilop, local); 2523 *new_lopp = NULL; 2524 modified = 1; 2525 } 2526 return (modified); 2527 } 2528 2529 /* 2530 * This function must be run as a kernel thread. 2531 * It does Renew Ops and recovery, when required. 2532 */ 2533 APPLESTATIC void 2534 nfscl_renewthread(struct nfsclclient *clp, NFSPROC_T *p) 2535 { 2536 struct nfsclowner *owp, *nowp; 2537 struct nfsclopen *op; 2538 struct nfscllockowner *lp, *nlp; 2539 struct nfscldeleghead dh; 2540 struct nfscldeleg *dp, *ndp; 2541 struct ucred *cred; 2542 u_int32_t clidrev; 2543 int error, cbpathdown, islept, igotlock, ret, clearok; 2544 uint32_t recover_done_time = 0; 2545 time_t mytime; 2546 static time_t prevsec = 0; 2547 struct nfscllockownerfh *lfhp, *nlfhp; 2548 struct nfscllockownerfhhead lfh; 2549 struct nfscllayout *lyp, *nlyp; 2550 struct nfscldevinfo *dip, *ndip; 2551 struct nfscllayouthead rlh; 2552 struct nfsclrecalllayout *recallp; 2553 struct nfsclds *dsp; 2554 bool retok; 2555 2556 cred = newnfs_getcred(); 2557 NFSLOCKCLSTATE(); 2558 clp->nfsc_flags |= NFSCLFLAGS_HASTHREAD; 2559 NFSUNLOCKCLSTATE(); 2560 for(;;) { 2561 newnfs_setroot(cred); 2562 cbpathdown = 0; 2563 if (clp->nfsc_flags & NFSCLFLAGS_RECOVER) { 2564 /* 2565 * Only allow one full recover within 1/2 of the lease 2566 * duration (nfsc_renew). 2567 * retok is value/result. If passed in set to true, 2568 * it indicates only a CreateSession operation should 2569 * be attempted. 2570 * If it is returned true, it indicates that the 2571 * recovery only required a CreateSession. 2572 */ 2573 retok = true; 2574 if (recover_done_time < NFSD_MONOSEC) { 2575 recover_done_time = NFSD_MONOSEC + 2576 clp->nfsc_renew; 2577 retok = false; 2578 } 2579 NFSCL_DEBUG(1, "Doing recovery, only " 2580 "createsession=%d\n", retok); 2581 nfscl_recover(clp, &retok, cred, p); 2582 } 2583 if (clp->nfsc_expire <= NFSD_MONOSEC && 2584 (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) { 2585 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 2586 clidrev = clp->nfsc_clientidrev; 2587 error = nfsrpc_renew(clp, NULL, cred, p); 2588 if (error == NFSERR_CBPATHDOWN) 2589 cbpathdown = 1; 2590 else if (error == NFSERR_STALECLIENTID || 2591 error == NFSERR_BADSESSION) { 2592 NFSLOCKCLSTATE(); 2593 clp->nfsc_flags |= NFSCLFLAGS_RECOVER; 2594 NFSUNLOCKCLSTATE(); 2595 } else if (error == NFSERR_EXPIRED) 2596 (void) nfscl_hasexpired(clp, clidrev, p); 2597 } 2598 2599 checkdsrenew: 2600 if (NFSHASNFSV4N(clp->nfsc_nmp)) { 2601 /* Do renews for any DS sessions. */ 2602 NFSLOCKMNT(clp->nfsc_nmp); 2603 /* Skip first entry, since the MDS is handled above. */ 2604 dsp = TAILQ_FIRST(&clp->nfsc_nmp->nm_sess); 2605 if (dsp != NULL) 2606 dsp = TAILQ_NEXT(dsp, nfsclds_list); 2607 while (dsp != NULL) { 2608 if (dsp->nfsclds_expire <= NFSD_MONOSEC && 2609 dsp->nfsclds_sess.nfsess_defunct == 0) { 2610 dsp->nfsclds_expire = NFSD_MONOSEC + 2611 clp->nfsc_renew; 2612 NFSUNLOCKMNT(clp->nfsc_nmp); 2613 (void)nfsrpc_renew(clp, dsp, cred, p); 2614 goto checkdsrenew; 2615 } 2616 dsp = TAILQ_NEXT(dsp, nfsclds_list); 2617 } 2618 NFSUNLOCKMNT(clp->nfsc_nmp); 2619 } 2620 2621 TAILQ_INIT(&dh); 2622 NFSLOCKCLSTATE(); 2623 if (cbpathdown) 2624 /* It's a Total Recall! */ 2625 nfscl_totalrecall(clp); 2626 2627 /* 2628 * Now, handle defunct owners. 2629 */ 2630 LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) { 2631 if (LIST_EMPTY(&owp->nfsow_open)) { 2632 if (owp->nfsow_defunct != 0) 2633 nfscl_freeopenowner(owp, 0); 2634 } 2635 } 2636 2637 /* 2638 * Do the recall on any delegations. To avoid trouble, always 2639 * come back up here after having slept. 2640 */ 2641 igotlock = 0; 2642 tryagain: 2643 dp = TAILQ_FIRST(&clp->nfsc_deleg); 2644 while (dp != NULL) { 2645 ndp = TAILQ_NEXT(dp, nfsdl_list); 2646 if ((dp->nfsdl_flags & NFSCLDL_RECALL)) { 2647 /* 2648 * Wait for outstanding I/O ops to be done. 2649 */ 2650 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 2651 if (igotlock) { 2652 nfsv4_unlock(&clp->nfsc_lock, 0); 2653 igotlock = 0; 2654 } 2655 dp->nfsdl_rwlock.nfslock_lock |= 2656 NFSV4LOCK_WANTED; 2657 (void) nfsmsleep(&dp->nfsdl_rwlock, 2658 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", 2659 NULL); 2660 goto tryagain; 2661 } 2662 while (!igotlock) { 2663 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 2664 &islept, NFSCLSTATEMUTEXPTR, NULL); 2665 if (islept) 2666 goto tryagain; 2667 } 2668 NFSUNLOCKCLSTATE(); 2669 newnfs_copycred(&dp->nfsdl_cred, cred); 2670 ret = nfscl_recalldeleg(clp, clp->nfsc_nmp, dp, 2671 NULL, cred, p, 1); 2672 if (!ret) { 2673 nfscl_cleandeleg(dp); 2674 TAILQ_REMOVE(&clp->nfsc_deleg, dp, 2675 nfsdl_list); 2676 LIST_REMOVE(dp, nfsdl_hash); 2677 TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list); 2678 nfscl_delegcnt--; 2679 nfsstatsv1.cldelegates--; 2680 } 2681 NFSLOCKCLSTATE(); 2682 } 2683 dp = ndp; 2684 } 2685 2686 /* 2687 * Clear out old delegations, if we are above the high water 2688 * mark. Only clear out ones with no state related to them. 2689 * The tailq list is in LRU order. 2690 */ 2691 dp = TAILQ_LAST(&clp->nfsc_deleg, nfscldeleghead); 2692 while (nfscl_delegcnt > nfscl_deleghighwater && dp != NULL) { 2693 ndp = TAILQ_PREV(dp, nfscldeleghead, nfsdl_list); 2694 if (dp->nfsdl_rwlock.nfslock_usecnt == 0 && 2695 dp->nfsdl_rwlock.nfslock_lock == 0 && 2696 dp->nfsdl_timestamp < NFSD_MONOSEC && 2697 (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_ZAPPED | 2698 NFSCLDL_NEEDRECLAIM | NFSCLDL_DELEGRET)) == 0) { 2699 clearok = 1; 2700 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 2701 op = LIST_FIRST(&owp->nfsow_open); 2702 if (op != NULL) { 2703 clearok = 0; 2704 break; 2705 } 2706 } 2707 if (clearok) { 2708 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 2709 if (!LIST_EMPTY(&lp->nfsl_lock)) { 2710 clearok = 0; 2711 break; 2712 } 2713 } 2714 } 2715 if (clearok) { 2716 TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list); 2717 LIST_REMOVE(dp, nfsdl_hash); 2718 TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list); 2719 nfscl_delegcnt--; 2720 nfsstatsv1.cldelegates--; 2721 } 2722 } 2723 dp = ndp; 2724 } 2725 if (igotlock) 2726 nfsv4_unlock(&clp->nfsc_lock, 0); 2727 2728 /* 2729 * Do the recall on any layouts. To avoid trouble, always 2730 * come back up here after having slept. 2731 */ 2732 TAILQ_INIT(&rlh); 2733 tryagain2: 2734 TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp) { 2735 if ((lyp->nfsly_flags & NFSLY_RECALL) != 0) { 2736 /* 2737 * Wait for outstanding I/O ops to be done. 2738 */ 2739 if (lyp->nfsly_lock.nfslock_usecnt > 0 || 2740 (lyp->nfsly_lock.nfslock_lock & 2741 NFSV4LOCK_LOCK) != 0) { 2742 lyp->nfsly_lock.nfslock_lock |= 2743 NFSV4LOCK_WANTED; 2744 nfsmsleep(&lyp->nfsly_lock.nfslock_lock, 2745 NFSCLSTATEMUTEXPTR, PZERO, "nfslyp", 2746 NULL); 2747 goto tryagain2; 2748 } 2749 /* Move the layout to the recall list. */ 2750 TAILQ_REMOVE(&clp->nfsc_layout, lyp, 2751 nfsly_list); 2752 LIST_REMOVE(lyp, nfsly_hash); 2753 TAILQ_INSERT_HEAD(&rlh, lyp, nfsly_list); 2754 2755 /* Handle any layout commits. */ 2756 if (!NFSHASNOLAYOUTCOMMIT(clp->nfsc_nmp) && 2757 (lyp->nfsly_flags & NFSLY_WRITTEN) != 0) { 2758 lyp->nfsly_flags &= ~NFSLY_WRITTEN; 2759 NFSUNLOCKCLSTATE(); 2760 NFSCL_DEBUG(3, "do layoutcommit\n"); 2761 nfscl_dolayoutcommit(clp->nfsc_nmp, lyp, 2762 cred, p); 2763 NFSLOCKCLSTATE(); 2764 goto tryagain2; 2765 } 2766 } 2767 } 2768 2769 /* Now, look for stale layouts. */ 2770 lyp = TAILQ_LAST(&clp->nfsc_layout, nfscllayouthead); 2771 while (lyp != NULL) { 2772 nlyp = TAILQ_PREV(lyp, nfscllayouthead, nfsly_list); 2773 if (lyp->nfsly_timestamp < NFSD_MONOSEC && 2774 (lyp->nfsly_flags & NFSLY_RECALL) == 0 && 2775 lyp->nfsly_lock.nfslock_usecnt == 0 && 2776 lyp->nfsly_lock.nfslock_lock == 0) { 2777 NFSCL_DEBUG(4, "ret stale lay=%d\n", 2778 nfscl_layoutcnt); 2779 recallp = malloc(sizeof(*recallp), 2780 M_NFSLAYRECALL, M_NOWAIT); 2781 if (recallp == NULL) 2782 break; 2783 (void)nfscl_layoutrecall(NFSLAYOUTRETURN_FILE, 2784 lyp, NFSLAYOUTIOMODE_ANY, 0, UINT64_MAX, 2785 lyp->nfsly_stateid.seqid, 0, 0, NULL, 2786 recallp); 2787 } 2788 lyp = nlyp; 2789 } 2790 2791 /* 2792 * Free up any unreferenced device info structures. 2793 */ 2794 LIST_FOREACH_SAFE(dip, &clp->nfsc_devinfo, nfsdi_list, ndip) { 2795 if (dip->nfsdi_layoutrefs == 0 && 2796 dip->nfsdi_refcnt == 0) { 2797 NFSCL_DEBUG(4, "freeing devinfo\n"); 2798 LIST_REMOVE(dip, nfsdi_list); 2799 nfscl_freedevinfo(dip); 2800 } 2801 } 2802 NFSUNLOCKCLSTATE(); 2803 2804 /* Do layout return(s), as required. */ 2805 TAILQ_FOREACH_SAFE(lyp, &rlh, nfsly_list, nlyp) { 2806 TAILQ_REMOVE(&rlh, lyp, nfsly_list); 2807 NFSCL_DEBUG(4, "ret layout\n"); 2808 nfscl_layoutreturn(clp->nfsc_nmp, lyp, cred, p); 2809 nfscl_freelayout(lyp); 2810 } 2811 2812 /* 2813 * Delegreturn any delegations cleaned out or recalled. 2814 */ 2815 TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) { 2816 newnfs_copycred(&dp->nfsdl_cred, cred); 2817 (void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); 2818 TAILQ_REMOVE(&dh, dp, nfsdl_list); 2819 free(dp, M_NFSCLDELEG); 2820 } 2821 2822 SLIST_INIT(&lfh); 2823 /* 2824 * Call nfscl_cleanupkext() once per second to check for 2825 * open/lock owners where the process has exited. 2826 */ 2827 mytime = NFSD_MONOSEC; 2828 if (prevsec != mytime) { 2829 prevsec = mytime; 2830 nfscl_cleanupkext(clp, &lfh); 2831 } 2832 2833 /* 2834 * Do a ReleaseLockOwner for all lock owners where the 2835 * associated process no longer exists, as found by 2836 * nfscl_cleanupkext(). 2837 */ 2838 newnfs_setroot(cred); 2839 SLIST_FOREACH_SAFE(lfhp, &lfh, nfslfh_list, nlfhp) { 2840 LIST_FOREACH_SAFE(lp, &lfhp->nfslfh_lock, nfsl_list, 2841 nlp) { 2842 (void)nfsrpc_rellockown(clp->nfsc_nmp, lp, 2843 lfhp->nfslfh_fh, lfhp->nfslfh_len, cred, 2844 p); 2845 nfscl_freelockowner(lp, 0); 2846 } 2847 free(lfhp, M_TEMP); 2848 } 2849 SLIST_INIT(&lfh); 2850 2851 NFSLOCKCLSTATE(); 2852 if ((clp->nfsc_flags & NFSCLFLAGS_RECOVER) == 0) 2853 (void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT, "nfscl", 2854 hz); 2855 if (clp->nfsc_flags & NFSCLFLAGS_UMOUNT) { 2856 clp->nfsc_flags &= ~NFSCLFLAGS_HASTHREAD; 2857 NFSUNLOCKCLSTATE(); 2858 NFSFREECRED(cred); 2859 wakeup((caddr_t)clp); 2860 return; 2861 } 2862 NFSUNLOCKCLSTATE(); 2863 } 2864 } 2865 2866 /* 2867 * Initiate state recovery. Called when NFSERR_STALECLIENTID, 2868 * NFSERR_STALESTATEID or NFSERR_BADSESSION is received. 2869 */ 2870 APPLESTATIC void 2871 nfscl_initiate_recovery(struct nfsclclient *clp) 2872 { 2873 2874 if (clp == NULL) 2875 return; 2876 NFSLOCKCLSTATE(); 2877 clp->nfsc_flags |= NFSCLFLAGS_RECOVER; 2878 NFSUNLOCKCLSTATE(); 2879 wakeup((caddr_t)clp); 2880 } 2881 2882 /* 2883 * Dump out the state stuff for debugging. 2884 */ 2885 APPLESTATIC void 2886 nfscl_dumpstate(struct nfsmount *nmp, int openowner, int opens, 2887 int lockowner, int locks) 2888 { 2889 struct nfsclclient *clp; 2890 struct nfsclowner *owp; 2891 struct nfsclopen *op; 2892 struct nfscllockowner *lp; 2893 struct nfscllock *lop; 2894 struct nfscldeleg *dp; 2895 2896 clp = nmp->nm_clp; 2897 if (clp == NULL) { 2898 printf("nfscl dumpstate NULL clp\n"); 2899 return; 2900 } 2901 NFSLOCKCLSTATE(); 2902 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 2903 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 2904 if (openowner && !LIST_EMPTY(&owp->nfsow_open)) 2905 printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n", 2906 owp->nfsow_owner[0], owp->nfsow_owner[1], 2907 owp->nfsow_owner[2], owp->nfsow_owner[3], 2908 owp->nfsow_seqid); 2909 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2910 if (opens) 2911 printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n", 2912 op->nfso_stateid.other[0], op->nfso_stateid.other[1], 2913 op->nfso_stateid.other[2], op->nfso_opencnt, 2914 op->nfso_fh[12]); 2915 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 2916 if (lockowner) 2917 printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n", 2918 lp->nfsl_owner[0], lp->nfsl_owner[1], 2919 lp->nfsl_owner[2], lp->nfsl_owner[3], 2920 lp->nfsl_seqid, 2921 lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1], 2922 lp->nfsl_stateid.other[2]); 2923 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 2924 if (locks) 2925 #ifdef __FreeBSD__ 2926 printf("lck typ=%d fst=%ju end=%ju\n", 2927 lop->nfslo_type, (intmax_t)lop->nfslo_first, 2928 (intmax_t)lop->nfslo_end); 2929 #else 2930 printf("lck typ=%d fst=%qd end=%qd\n", 2931 lop->nfslo_type, lop->nfslo_first, 2932 lop->nfslo_end); 2933 #endif 2934 } 2935 } 2936 } 2937 } 2938 } 2939 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 2940 if (openowner && !LIST_EMPTY(&owp->nfsow_open)) 2941 printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n", 2942 owp->nfsow_owner[0], owp->nfsow_owner[1], 2943 owp->nfsow_owner[2], owp->nfsow_owner[3], 2944 owp->nfsow_seqid); 2945 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 2946 if (opens) 2947 printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n", 2948 op->nfso_stateid.other[0], op->nfso_stateid.other[1], 2949 op->nfso_stateid.other[2], op->nfso_opencnt, 2950 op->nfso_fh[12]); 2951 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 2952 if (lockowner) 2953 printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n", 2954 lp->nfsl_owner[0], lp->nfsl_owner[1], 2955 lp->nfsl_owner[2], lp->nfsl_owner[3], 2956 lp->nfsl_seqid, 2957 lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1], 2958 lp->nfsl_stateid.other[2]); 2959 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 2960 if (locks) 2961 #ifdef __FreeBSD__ 2962 printf("lck typ=%d fst=%ju end=%ju\n", 2963 lop->nfslo_type, (intmax_t)lop->nfslo_first, 2964 (intmax_t)lop->nfslo_end); 2965 #else 2966 printf("lck typ=%d fst=%qd end=%qd\n", 2967 lop->nfslo_type, lop->nfslo_first, 2968 lop->nfslo_end); 2969 #endif 2970 } 2971 } 2972 } 2973 } 2974 NFSUNLOCKCLSTATE(); 2975 } 2976 2977 /* 2978 * Check for duplicate open owners and opens. 2979 * (Only used as a diagnostic aid.) 2980 */ 2981 APPLESTATIC void 2982 nfscl_dupopen(vnode_t vp, int dupopens) 2983 { 2984 struct nfsclclient *clp; 2985 struct nfsclowner *owp, *owp2; 2986 struct nfsclopen *op, *op2; 2987 struct nfsfh *nfhp; 2988 2989 clp = VFSTONFS(vnode_mount(vp))->nm_clp; 2990 if (clp == NULL) { 2991 printf("nfscl dupopen NULL clp\n"); 2992 return; 2993 } 2994 nfhp = VTONFS(vp)->n_fhp; 2995 NFSLOCKCLSTATE(); 2996 2997 /* 2998 * First, search for duplicate owners. 2999 * These should never happen! 3000 */ 3001 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 3002 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3003 if (owp != owp2 && 3004 !NFSBCMP(owp->nfsow_owner, owp2->nfsow_owner, 3005 NFSV4CL_LOCKNAMELEN)) { 3006 NFSUNLOCKCLSTATE(); 3007 printf("DUP OWNER\n"); 3008 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 0); 3009 return; 3010 } 3011 } 3012 } 3013 3014 /* 3015 * Now, search for duplicate stateids. 3016 * These shouldn't happen, either. 3017 */ 3018 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 3019 LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) { 3020 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3021 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3022 if (op != op2 && 3023 (op->nfso_stateid.other[0] != 0 || 3024 op->nfso_stateid.other[1] != 0 || 3025 op->nfso_stateid.other[2] != 0) && 3026 op->nfso_stateid.other[0] == op2->nfso_stateid.other[0] && 3027 op->nfso_stateid.other[1] == op2->nfso_stateid.other[1] && 3028 op->nfso_stateid.other[2] == op2->nfso_stateid.other[2]) { 3029 NFSUNLOCKCLSTATE(); 3030 printf("DUP STATEID\n"); 3031 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 3032 0); 3033 return; 3034 } 3035 } 3036 } 3037 } 3038 } 3039 3040 /* 3041 * Now search for duplicate opens. 3042 * Duplicate opens for the same owner 3043 * should never occur. Other duplicates are 3044 * possible and are checked for if "dupopens" 3045 * is true. 3046 */ 3047 LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) { 3048 LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) { 3049 if (nfhp->nfh_len == op2->nfso_fhlen && 3050 !NFSBCMP(nfhp->nfh_fh, op2->nfso_fh, nfhp->nfh_len)) { 3051 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3052 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3053 if (op != op2 && nfhp->nfh_len == op->nfso_fhlen && 3054 !NFSBCMP(nfhp->nfh_fh, op->nfso_fh, nfhp->nfh_len) && 3055 (!NFSBCMP(op->nfso_own->nfsow_owner, 3056 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN) || 3057 dupopens)) { 3058 if (!NFSBCMP(op->nfso_own->nfsow_owner, 3059 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN)) { 3060 NFSUNLOCKCLSTATE(); 3061 printf("BADDUP OPEN\n"); 3062 } else { 3063 NFSUNLOCKCLSTATE(); 3064 printf("DUP OPEN\n"); 3065 } 3066 nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 3067 0, 0); 3068 return; 3069 } 3070 } 3071 } 3072 } 3073 } 3074 } 3075 NFSUNLOCKCLSTATE(); 3076 } 3077 3078 /* 3079 * During close, find an open that needs to be dereferenced and 3080 * dereference it. If there are no more opens for this file, 3081 * log a message to that effect. 3082 * Opens aren't actually Close'd until VOP_INACTIVE() is performed 3083 * on the file's vnode. 3084 * This is the safe way, since it is difficult to identify 3085 * which open the close is for and I/O can be performed after the 3086 * close(2) system call when a file is mmap'd. 3087 * If it returns 0 for success, there will be a referenced 3088 * clp returned via clpp. 3089 */ 3090 APPLESTATIC int 3091 nfscl_getclose(vnode_t vp, struct nfsclclient **clpp) 3092 { 3093 struct nfsclclient *clp; 3094 struct nfsclowner *owp; 3095 struct nfsclopen *op; 3096 struct nfscldeleg *dp; 3097 struct nfsfh *nfhp; 3098 int error, notdecr; 3099 3100 error = nfscl_getcl(vnode_mount(vp), NULL, NULL, 1, &clp); 3101 if (error) 3102 return (error); 3103 *clpp = clp; 3104 3105 nfhp = VTONFS(vp)->n_fhp; 3106 notdecr = 1; 3107 NFSLOCKCLSTATE(); 3108 /* 3109 * First, look for one under a delegation that was locally issued 3110 * and just decrement the opencnt for it. Since all my Opens against 3111 * the server are DENY_NONE, I don't see a problem with hanging 3112 * onto them. (It is much easier to use one of the extant Opens 3113 * that I already have on the server when a Delegation is recalled 3114 * than to do fresh Opens.) Someday, I might need to rethink this, but. 3115 */ 3116 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); 3117 if (dp != NULL) { 3118 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 3119 op = LIST_FIRST(&owp->nfsow_open); 3120 if (op != NULL) { 3121 /* 3122 * Since a delegation is for a file, there 3123 * should never be more than one open for 3124 * each openowner. 3125 */ 3126 if (LIST_NEXT(op, nfso_list) != NULL) 3127 panic("nfscdeleg opens"); 3128 if (notdecr && op->nfso_opencnt > 0) { 3129 notdecr = 0; 3130 op->nfso_opencnt--; 3131 break; 3132 } 3133 } 3134 } 3135 } 3136 3137 /* Now process the opens against the server. */ 3138 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3139 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3140 if (op->nfso_fhlen == nfhp->nfh_len && 3141 !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, 3142 nfhp->nfh_len)) { 3143 /* Found an open, decrement cnt if possible */ 3144 if (notdecr && op->nfso_opencnt > 0) { 3145 notdecr = 0; 3146 op->nfso_opencnt--; 3147 } 3148 /* 3149 * There are more opens, so just return. 3150 */ 3151 if (op->nfso_opencnt > 0) { 3152 NFSUNLOCKCLSTATE(); 3153 return (0); 3154 } 3155 } 3156 } 3157 } 3158 NFSUNLOCKCLSTATE(); 3159 if (notdecr) 3160 printf("nfscl: never fnd open\n"); 3161 return (0); 3162 } 3163 3164 APPLESTATIC int 3165 nfscl_doclose(vnode_t vp, struct nfsclclient **clpp, NFSPROC_T *p) 3166 { 3167 struct nfsclclient *clp; 3168 struct nfsclowner *owp, *nowp; 3169 struct nfsclopen *op; 3170 struct nfscldeleg *dp; 3171 struct nfsfh *nfhp; 3172 struct nfsclrecalllayout *recallp; 3173 int error; 3174 3175 error = nfscl_getcl(vnode_mount(vp), NULL, NULL, 1, &clp); 3176 if (error) 3177 return (error); 3178 *clpp = clp; 3179 3180 nfhp = VTONFS(vp)->n_fhp; 3181 recallp = malloc(sizeof(*recallp), M_NFSLAYRECALL, M_WAITOK); 3182 NFSLOCKCLSTATE(); 3183 /* 3184 * First get rid of the local Open structures, which should be no 3185 * longer in use. 3186 */ 3187 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len); 3188 if (dp != NULL) { 3189 LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) { 3190 op = LIST_FIRST(&owp->nfsow_open); 3191 if (op != NULL) { 3192 KASSERT((op->nfso_opencnt == 0), 3193 ("nfscl: bad open cnt on deleg")); 3194 nfscl_freeopen(op, 1); 3195 } 3196 nfscl_freeopenowner(owp, 1); 3197 } 3198 } 3199 3200 /* Return any layouts marked return on close. */ 3201 nfscl_retoncloselayout(vp, clp, nfhp->nfh_fh, nfhp->nfh_len, &recallp); 3202 3203 /* Now process the opens against the server. */ 3204 lookformore: 3205 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3206 op = LIST_FIRST(&owp->nfsow_open); 3207 while (op != NULL) { 3208 if (op->nfso_fhlen == nfhp->nfh_len && 3209 !NFSBCMP(op->nfso_fh, nfhp->nfh_fh, 3210 nfhp->nfh_len)) { 3211 /* Found an open, close it. */ 3212 #ifdef DIAGNOSTIC 3213 KASSERT((op->nfso_opencnt == 0), 3214 ("nfscl: bad open cnt on server (%d)", 3215 op->nfso_opencnt)); 3216 #endif 3217 NFSUNLOCKCLSTATE(); 3218 nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), op, 3219 p); 3220 NFSLOCKCLSTATE(); 3221 goto lookformore; 3222 } 3223 op = LIST_NEXT(op, nfso_list); 3224 } 3225 } 3226 NFSUNLOCKCLSTATE(); 3227 /* 3228 * recallp has been set NULL by nfscl_retoncloselayout() if it was 3229 * used by the function, but calling free() with a NULL pointer is ok. 3230 */ 3231 free(recallp, M_NFSLAYRECALL); 3232 return (0); 3233 } 3234 3235 /* 3236 * Return all delegations on this client. 3237 * (Must be called with client sleep lock.) 3238 */ 3239 static void 3240 nfscl_delegreturnall(struct nfsclclient *clp, NFSPROC_T *p) 3241 { 3242 struct nfscldeleg *dp, *ndp; 3243 struct ucred *cred; 3244 3245 cred = newnfs_getcred(); 3246 TAILQ_FOREACH_SAFE(dp, &clp->nfsc_deleg, nfsdl_list, ndp) { 3247 nfscl_cleandeleg(dp); 3248 (void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); 3249 nfscl_freedeleg(&clp->nfsc_deleg, dp); 3250 } 3251 NFSFREECRED(cred); 3252 } 3253 3254 /* 3255 * Do a callback RPC. 3256 */ 3257 APPLESTATIC void 3258 nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p) 3259 { 3260 int clist, gotseq_ok, i, j, k, op, rcalls; 3261 u_int32_t *tl; 3262 struct nfsclclient *clp; 3263 struct nfscldeleg *dp = NULL; 3264 int numops, taglen = -1, error = 0, trunc __unused; 3265 u_int32_t minorvers = 0, retops = 0, *retopsp = NULL, *repp, cbident; 3266 u_char tag[NFSV4_SMALLSTR + 1], *tagstr; 3267 vnode_t vp = NULL; 3268 struct nfsnode *np; 3269 struct vattr va; 3270 struct nfsfh *nfhp; 3271 mount_t mp; 3272 nfsattrbit_t attrbits, rattrbits; 3273 nfsv4stateid_t stateid; 3274 uint32_t seqid, slotid = 0, highslot, cachethis __unused; 3275 uint8_t sessionid[NFSX_V4SESSIONID]; 3276 struct mbuf *rep; 3277 struct nfscllayout *lyp; 3278 uint64_t filesid[2], len, off; 3279 int changed, gotone, laytype, recalltype; 3280 uint32_t iomode; 3281 struct nfsclrecalllayout *recallp = NULL; 3282 struct nfsclsession *tsep; 3283 3284 gotseq_ok = 0; 3285 nfsrvd_rephead(nd); 3286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3287 taglen = fxdr_unsigned(int, *tl); 3288 if (taglen < 0) { 3289 error = EBADRPC; 3290 goto nfsmout; 3291 } 3292 if (taglen <= NFSV4_SMALLSTR) 3293 tagstr = tag; 3294 else 3295 tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK); 3296 error = nfsrv_mtostr(nd, tagstr, taglen); 3297 if (error) { 3298 if (taglen > NFSV4_SMALLSTR) 3299 free(tagstr, M_TEMP); 3300 taglen = -1; 3301 goto nfsmout; 3302 } 3303 (void) nfsm_strtom(nd, tag, taglen); 3304 if (taglen > NFSV4_SMALLSTR) { 3305 free(tagstr, M_TEMP); 3306 } 3307 NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED); 3308 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3309 minorvers = fxdr_unsigned(u_int32_t, *tl++); 3310 if (minorvers != NFSV4_MINORVERSION && 3311 minorvers != NFSV41_MINORVERSION && 3312 minorvers != NFSV42_MINORVERSION) 3313 nd->nd_repstat = NFSERR_MINORVERMISMATCH; 3314 cbident = fxdr_unsigned(u_int32_t, *tl++); 3315 if (nd->nd_repstat) 3316 numops = 0; 3317 else 3318 numops = fxdr_unsigned(int, *tl); 3319 /* 3320 * Loop around doing the sub ops. 3321 */ 3322 for (i = 0; i < numops; i++) { 3323 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3324 NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED); 3325 *repp++ = *tl; 3326 op = fxdr_unsigned(int, *tl); 3327 if (op < NFSV4OP_CBGETATTR || 3328 (op > NFSV4OP_CBRECALL && minorvers == NFSV4_MINORVERSION) || 3329 (op > NFSV4OP_CBNOTIFYDEVID && 3330 minorvers == NFSV41_MINORVERSION) || 3331 (op > NFSV4OP_CBOFFLOAD && 3332 minorvers == NFSV42_MINORVERSION)) { 3333 nd->nd_repstat = NFSERR_OPILLEGAL; 3334 *repp = nfscl_errmap(nd, minorvers); 3335 retops++; 3336 break; 3337 } 3338 nd->nd_procnum = op; 3339 if (op < NFSV42_CBNOPS) 3340 nfsstatsv1.cbrpccnt[nd->nd_procnum]++; 3341 switch (op) { 3342 case NFSV4OP_CBGETATTR: 3343 NFSCL_DEBUG(4, "cbgetattr\n"); 3344 mp = NULL; 3345 vp = NULL; 3346 error = nfsm_getfh(nd, &nfhp); 3347 if (!error) 3348 error = nfsrv_getattrbits(nd, &attrbits, 3349 NULL, NULL); 3350 if (error == 0 && i == 0 && 3351 minorvers != NFSV4_MINORVERSION) 3352 error = NFSERR_OPNOTINSESS; 3353 if (!error) { 3354 mp = nfscl_getmnt(minorvers, sessionid, cbident, 3355 &clp); 3356 if (mp == NULL) 3357 error = NFSERR_SERVERFAULT; 3358 } 3359 if (!error) { 3360 error = nfscl_ngetreopen(mp, nfhp->nfh_fh, 3361 nfhp->nfh_len, p, &np); 3362 if (!error) 3363 vp = NFSTOV(np); 3364 } 3365 if (!error) { 3366 NFSZERO_ATTRBIT(&rattrbits); 3367 NFSLOCKCLSTATE(); 3368 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, 3369 nfhp->nfh_len); 3370 if (dp != NULL) { 3371 if (NFSISSET_ATTRBIT(&attrbits, 3372 NFSATTRBIT_SIZE)) { 3373 if (vp != NULL) 3374 va.va_size = np->n_size; 3375 else 3376 va.va_size = 3377 dp->nfsdl_size; 3378 NFSSETBIT_ATTRBIT(&rattrbits, 3379 NFSATTRBIT_SIZE); 3380 } 3381 if (NFSISSET_ATTRBIT(&attrbits, 3382 NFSATTRBIT_CHANGE)) { 3383 va.va_filerev = 3384 dp->nfsdl_change; 3385 if (vp == NULL || 3386 (np->n_flag & NDELEGMOD)) 3387 va.va_filerev++; 3388 NFSSETBIT_ATTRBIT(&rattrbits, 3389 NFSATTRBIT_CHANGE); 3390 } 3391 } else 3392 error = NFSERR_SERVERFAULT; 3393 NFSUNLOCKCLSTATE(); 3394 } 3395 if (vp != NULL) 3396 vrele(vp); 3397 if (mp != NULL) 3398 vfs_unbusy(mp); 3399 if (nfhp != NULL) 3400 free(nfhp, M_NFSFH); 3401 if (!error) 3402 (void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va, 3403 NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0, 3404 (uint64_t)0, NULL); 3405 break; 3406 case NFSV4OP_CBRECALL: 3407 NFSCL_DEBUG(4, "cbrecall\n"); 3408 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3409 NFSX_UNSIGNED); 3410 stateid.seqid = *tl++; 3411 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, 3412 NFSX_STATEIDOTHER); 3413 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3414 trunc = fxdr_unsigned(int, *tl); 3415 error = nfsm_getfh(nd, &nfhp); 3416 if (error == 0 && i == 0 && 3417 minorvers != NFSV4_MINORVERSION) 3418 error = NFSERR_OPNOTINSESS; 3419 if (!error) { 3420 NFSLOCKCLSTATE(); 3421 if (minorvers == NFSV4_MINORVERSION) 3422 clp = nfscl_getclnt(cbident); 3423 else 3424 clp = nfscl_getclntsess(sessionid); 3425 if (clp != NULL) { 3426 dp = nfscl_finddeleg(clp, nfhp->nfh_fh, 3427 nfhp->nfh_len); 3428 if (dp != NULL && (dp->nfsdl_flags & 3429 NFSCLDL_DELEGRET) == 0) { 3430 dp->nfsdl_flags |= 3431 NFSCLDL_RECALL; 3432 wakeup((caddr_t)clp); 3433 } 3434 } else { 3435 error = NFSERR_SERVERFAULT; 3436 } 3437 NFSUNLOCKCLSTATE(); 3438 } 3439 if (nfhp != NULL) 3440 free(nfhp, M_NFSFH); 3441 break; 3442 case NFSV4OP_CBLAYOUTRECALL: 3443 NFSCL_DEBUG(4, "cblayrec\n"); 3444 nfhp = NULL; 3445 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3446 laytype = fxdr_unsigned(int, *tl++); 3447 iomode = fxdr_unsigned(uint32_t, *tl++); 3448 if (newnfs_true == *tl++) 3449 changed = 1; 3450 else 3451 changed = 0; 3452 recalltype = fxdr_unsigned(int, *tl); 3453 NFSCL_DEBUG(4, "layt=%d iom=%d ch=%d rectyp=%d\n", 3454 laytype, iomode, changed, recalltype); 3455 recallp = malloc(sizeof(*recallp), M_NFSLAYRECALL, 3456 M_WAITOK); 3457 if (laytype != NFSLAYOUT_NFSV4_1_FILES && 3458 laytype != NFSLAYOUT_FLEXFILE) 3459 error = NFSERR_NOMATCHLAYOUT; 3460 else if (recalltype == NFSLAYOUTRETURN_FILE) { 3461 error = nfsm_getfh(nd, &nfhp); 3462 NFSCL_DEBUG(4, "retfile getfh=%d\n", error); 3463 if (error != 0) 3464 goto nfsmout; 3465 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER + 3466 NFSX_STATEID); 3467 off = fxdr_hyper(tl); tl += 2; 3468 len = fxdr_hyper(tl); tl += 2; 3469 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 3470 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 3471 if (minorvers == NFSV4_MINORVERSION) 3472 error = NFSERR_NOTSUPP; 3473 else if (i == 0) 3474 error = NFSERR_OPNOTINSESS; 3475 NFSCL_DEBUG(4, "off=%ju len=%ju sq=%u err=%d\n", 3476 (uintmax_t)off, (uintmax_t)len, 3477 stateid.seqid, error); 3478 if (error == 0) { 3479 NFSLOCKCLSTATE(); 3480 clp = nfscl_getclntsess(sessionid); 3481 NFSCL_DEBUG(4, "cbly clp=%p\n", clp); 3482 if (clp != NULL) { 3483 lyp = nfscl_findlayout(clp, 3484 nfhp->nfh_fh, 3485 nfhp->nfh_len); 3486 NFSCL_DEBUG(4, "cblyp=%p\n", 3487 lyp); 3488 if (lyp != NULL && 3489 (lyp->nfsly_flags & 3490 (NFSLY_FILES | 3491 NFSLY_FLEXFILE)) != 0 && 3492 !NFSBCMP(stateid.other, 3493 lyp->nfsly_stateid.other, 3494 NFSX_STATEIDOTHER)) { 3495 error = 3496 nfscl_layoutrecall( 3497 recalltype, 3498 lyp, iomode, off, 3499 len, stateid.seqid, 3500 0, 0, NULL, 3501 recallp); 3502 recallp = NULL; 3503 wakeup(clp); 3504 NFSCL_DEBUG(4, 3505 "aft layrcal=%d\n", 3506 error); 3507 } else 3508 error = 3509 NFSERR_NOMATCHLAYOUT; 3510 } else 3511 error = NFSERR_NOMATCHLAYOUT; 3512 NFSUNLOCKCLSTATE(); 3513 } 3514 free(nfhp, M_NFSFH); 3515 } else if (recalltype == NFSLAYOUTRETURN_FSID) { 3516 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER); 3517 filesid[0] = fxdr_hyper(tl); tl += 2; 3518 filesid[1] = fxdr_hyper(tl); tl += 2; 3519 gotone = 0; 3520 NFSLOCKCLSTATE(); 3521 clp = nfscl_getclntsess(sessionid); 3522 if (clp != NULL) { 3523 TAILQ_FOREACH(lyp, &clp->nfsc_layout, 3524 nfsly_list) { 3525 if (lyp->nfsly_filesid[0] == 3526 filesid[0] && 3527 lyp->nfsly_filesid[1] == 3528 filesid[1]) { 3529 error = 3530 nfscl_layoutrecall( 3531 recalltype, 3532 lyp, iomode, 0, 3533 UINT64_MAX, 3534 lyp->nfsly_stateid.seqid, 3535 0, 0, NULL, 3536 recallp); 3537 recallp = NULL; 3538 gotone = 1; 3539 } 3540 } 3541 if (gotone != 0) 3542 wakeup(clp); 3543 else 3544 error = NFSERR_NOMATCHLAYOUT; 3545 } else 3546 error = NFSERR_NOMATCHLAYOUT; 3547 NFSUNLOCKCLSTATE(); 3548 } else if (recalltype == NFSLAYOUTRETURN_ALL) { 3549 gotone = 0; 3550 NFSLOCKCLSTATE(); 3551 clp = nfscl_getclntsess(sessionid); 3552 if (clp != NULL) { 3553 TAILQ_FOREACH(lyp, &clp->nfsc_layout, 3554 nfsly_list) { 3555 error = nfscl_layoutrecall( 3556 recalltype, lyp, iomode, 0, 3557 UINT64_MAX, 3558 lyp->nfsly_stateid.seqid, 3559 0, 0, NULL, recallp); 3560 recallp = NULL; 3561 gotone = 1; 3562 } 3563 if (gotone != 0) 3564 wakeup(clp); 3565 else 3566 error = NFSERR_NOMATCHLAYOUT; 3567 } else 3568 error = NFSERR_NOMATCHLAYOUT; 3569 NFSUNLOCKCLSTATE(); 3570 } else 3571 error = NFSERR_NOMATCHLAYOUT; 3572 if (recallp != NULL) { 3573 free(recallp, M_NFSLAYRECALL); 3574 recallp = NULL; 3575 } 3576 break; 3577 case NFSV4OP_CBSEQUENCE: 3578 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 3579 5 * NFSX_UNSIGNED); 3580 bcopy(tl, sessionid, NFSX_V4SESSIONID); 3581 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3582 seqid = fxdr_unsigned(uint32_t, *tl++); 3583 slotid = fxdr_unsigned(uint32_t, *tl++); 3584 highslot = fxdr_unsigned(uint32_t, *tl++); 3585 cachethis = *tl++; 3586 /* Throw away the referring call stuff. */ 3587 clist = fxdr_unsigned(int, *tl); 3588 for (j = 0; j < clist; j++) { 3589 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 3590 NFSX_UNSIGNED); 3591 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3592 rcalls = fxdr_unsigned(int, *tl); 3593 for (k = 0; k < rcalls; k++) { 3594 NFSM_DISSECT(tl, uint32_t *, 3595 2 * NFSX_UNSIGNED); 3596 } 3597 } 3598 NFSLOCKCLSTATE(); 3599 if (i == 0) { 3600 clp = nfscl_getclntsess(sessionid); 3601 if (clp == NULL) 3602 error = NFSERR_SERVERFAULT; 3603 } else 3604 error = NFSERR_SEQUENCEPOS; 3605 if (error == 0) { 3606 tsep = nfsmnt_mdssession(clp->nfsc_nmp); 3607 error = nfsv4_seqsession(seqid, slotid, 3608 highslot, tsep->nfsess_cbslots, &rep, 3609 tsep->nfsess_backslots); 3610 } 3611 NFSUNLOCKCLSTATE(); 3612 if (error == 0 || error == NFSERR_REPLYFROMCACHE) { 3613 gotseq_ok = 1; 3614 if (rep != NULL) { 3615 /* 3616 * Handle a reply for a retried 3617 * callback. The reply will be 3618 * re-inserted in the session cache 3619 * by the nfsv4_seqsess_cacherep() call 3620 * after out: 3621 */ 3622 KASSERT(error == NFSERR_REPLYFROMCACHE, 3623 ("cbsequence: non-NULL rep")); 3624 NFSCL_DEBUG(4, "Got cbretry\n"); 3625 m_freem(nd->nd_mreq); 3626 nd->nd_mreq = rep; 3627 rep = NULL; 3628 goto out; 3629 } 3630 NFSM_BUILD(tl, uint32_t *, 3631 NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 3632 bcopy(sessionid, tl, NFSX_V4SESSIONID); 3633 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3634 *tl++ = txdr_unsigned(seqid); 3635 *tl++ = txdr_unsigned(slotid); 3636 *tl++ = txdr_unsigned(NFSV4_CBSLOTS - 1); 3637 *tl = txdr_unsigned(NFSV4_CBSLOTS - 1); 3638 } 3639 break; 3640 default: 3641 if (i == 0 && minorvers != NFSV4_MINORVERSION) 3642 error = NFSERR_OPNOTINSESS; 3643 else { 3644 NFSCL_DEBUG(1, "unsupp callback %d\n", op); 3645 error = NFSERR_NOTSUPP; 3646 } 3647 break; 3648 } 3649 if (error) { 3650 if (error == EBADRPC || error == NFSERR_BADXDR) { 3651 nd->nd_repstat = NFSERR_BADXDR; 3652 } else { 3653 nd->nd_repstat = error; 3654 } 3655 error = 0; 3656 } 3657 retops++; 3658 if (nd->nd_repstat) { 3659 *repp = nfscl_errmap(nd, minorvers); 3660 break; 3661 } else 3662 *repp = 0; /* NFS4_OK */ 3663 } 3664 nfsmout: 3665 if (recallp != NULL) 3666 free(recallp, M_NFSLAYRECALL); 3667 if (error) { 3668 if (error == EBADRPC || error == NFSERR_BADXDR) 3669 nd->nd_repstat = NFSERR_BADXDR; 3670 else 3671 printf("nfsv4 comperr1=%d\n", error); 3672 } 3673 if (taglen == -1) { 3674 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3675 *tl++ = 0; 3676 *tl = 0; 3677 } else { 3678 *retopsp = txdr_unsigned(retops); 3679 } 3680 *nd->nd_errp = nfscl_errmap(nd, minorvers); 3681 out: 3682 if (gotseq_ok != 0) { 3683 rep = m_copym(nd->nd_mreq, 0, M_COPYALL, M_WAITOK); 3684 NFSLOCKCLSTATE(); 3685 clp = nfscl_getclntsess(sessionid); 3686 if (clp != NULL) { 3687 tsep = nfsmnt_mdssession(clp->nfsc_nmp); 3688 nfsv4_seqsess_cacherep(slotid, tsep->nfsess_cbslots, 3689 NFSERR_OK, &rep); 3690 NFSUNLOCKCLSTATE(); 3691 } else { 3692 NFSUNLOCKCLSTATE(); 3693 m_freem(rep); 3694 } 3695 } 3696 } 3697 3698 /* 3699 * Generate the next cbident value. Basically just increment a static value 3700 * and then check that it isn't already in the list, if it has wrapped around. 3701 */ 3702 static u_int32_t 3703 nfscl_nextcbident(void) 3704 { 3705 struct nfsclclient *clp; 3706 int matched; 3707 static u_int32_t nextcbident = 0; 3708 static int haswrapped = 0; 3709 3710 nextcbident++; 3711 if (nextcbident == 0) 3712 haswrapped = 1; 3713 if (haswrapped) { 3714 /* 3715 * Search the clientid list for one already using this cbident. 3716 */ 3717 do { 3718 matched = 0; 3719 NFSLOCKCLSTATE(); 3720 LIST_FOREACH(clp, &nfsclhead, nfsc_list) { 3721 if (clp->nfsc_cbident == nextcbident) { 3722 matched = 1; 3723 break; 3724 } 3725 } 3726 NFSUNLOCKCLSTATE(); 3727 if (matched == 1) 3728 nextcbident++; 3729 } while (matched); 3730 } 3731 return (nextcbident); 3732 } 3733 3734 /* 3735 * Get the mount point related to a given cbident or session and busy it. 3736 */ 3737 static mount_t 3738 nfscl_getmnt(int minorvers, uint8_t *sessionid, u_int32_t cbident, 3739 struct nfsclclient **clpp) 3740 { 3741 struct nfsclclient *clp; 3742 mount_t mp; 3743 int error; 3744 struct nfsclsession *tsep; 3745 3746 *clpp = NULL; 3747 NFSLOCKCLSTATE(); 3748 LIST_FOREACH(clp, &nfsclhead, nfsc_list) { 3749 tsep = nfsmnt_mdssession(clp->nfsc_nmp); 3750 if (minorvers == NFSV4_MINORVERSION) { 3751 if (clp->nfsc_cbident == cbident) 3752 break; 3753 } else if (!NFSBCMP(tsep->nfsess_sessionid, sessionid, 3754 NFSX_V4SESSIONID)) 3755 break; 3756 } 3757 if (clp == NULL) { 3758 NFSUNLOCKCLSTATE(); 3759 return (NULL); 3760 } 3761 mp = clp->nfsc_nmp->nm_mountp; 3762 vfs_ref(mp); 3763 NFSUNLOCKCLSTATE(); 3764 error = vfs_busy(mp, 0); 3765 vfs_rel(mp); 3766 if (error != 0) 3767 return (NULL); 3768 *clpp = clp; 3769 return (mp); 3770 } 3771 3772 /* 3773 * Get the clientid pointer related to a given cbident. 3774 */ 3775 static struct nfsclclient * 3776 nfscl_getclnt(u_int32_t cbident) 3777 { 3778 struct nfsclclient *clp; 3779 3780 LIST_FOREACH(clp, &nfsclhead, nfsc_list) 3781 if (clp->nfsc_cbident == cbident) 3782 break; 3783 return (clp); 3784 } 3785 3786 /* 3787 * Get the clientid pointer related to a given sessionid. 3788 */ 3789 static struct nfsclclient * 3790 nfscl_getclntsess(uint8_t *sessionid) 3791 { 3792 struct nfsclclient *clp; 3793 struct nfsclsession *tsep; 3794 3795 LIST_FOREACH(clp, &nfsclhead, nfsc_list) { 3796 tsep = nfsmnt_mdssession(clp->nfsc_nmp); 3797 if (!NFSBCMP(tsep->nfsess_sessionid, sessionid, 3798 NFSX_V4SESSIONID)) 3799 break; 3800 } 3801 return (clp); 3802 } 3803 3804 /* 3805 * Search for a lock conflict locally on the client. A conflict occurs if 3806 * - not same owner and overlapping byte range and at least one of them is 3807 * a write lock or this is an unlock. 3808 */ 3809 static int 3810 nfscl_localconflict(struct nfsclclient *clp, u_int8_t *fhp, int fhlen, 3811 struct nfscllock *nlop, u_int8_t *own, struct nfscldeleg *dp, 3812 struct nfscllock **lopp) 3813 { 3814 struct nfsclowner *owp; 3815 struct nfsclopen *op; 3816 int ret; 3817 3818 if (dp != NULL) { 3819 ret = nfscl_checkconflict(&dp->nfsdl_lock, nlop, own, lopp); 3820 if (ret) 3821 return (ret); 3822 } 3823 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3824 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 3825 if (op->nfso_fhlen == fhlen && 3826 !NFSBCMP(op->nfso_fh, fhp, fhlen)) { 3827 ret = nfscl_checkconflict(&op->nfso_lock, nlop, 3828 own, lopp); 3829 if (ret) 3830 return (ret); 3831 } 3832 } 3833 } 3834 return (0); 3835 } 3836 3837 static int 3838 nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop, 3839 u_int8_t *own, struct nfscllock **lopp) 3840 { 3841 struct nfscllockowner *lp; 3842 struct nfscllock *lop; 3843 3844 LIST_FOREACH(lp, lhp, nfsl_list) { 3845 if (NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) { 3846 LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) { 3847 if (lop->nfslo_first >= nlop->nfslo_end) 3848 break; 3849 if (lop->nfslo_end <= nlop->nfslo_first) 3850 continue; 3851 if (lop->nfslo_type == F_WRLCK || 3852 nlop->nfslo_type == F_WRLCK || 3853 nlop->nfslo_type == F_UNLCK) { 3854 if (lopp != NULL) 3855 *lopp = lop; 3856 return (NFSERR_DENIED); 3857 } 3858 } 3859 } 3860 } 3861 return (0); 3862 } 3863 3864 /* 3865 * Check for a local conflicting lock. 3866 */ 3867 APPLESTATIC int 3868 nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off, 3869 u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags) 3870 { 3871 struct nfscllock *lop, nlck; 3872 struct nfscldeleg *dp; 3873 struct nfsnode *np; 3874 u_int8_t own[NFSV4CL_LOCKNAMELEN]; 3875 int error; 3876 3877 nlck.nfslo_type = fl->l_type; 3878 nlck.nfslo_first = off; 3879 if (len == NFS64BITSSET) { 3880 nlck.nfslo_end = NFS64BITSSET; 3881 } else { 3882 nlck.nfslo_end = off + len; 3883 if (nlck.nfslo_end <= nlck.nfslo_first) 3884 return (NFSERR_INVAL); 3885 } 3886 np = VTONFS(vp); 3887 nfscl_filllockowner(id, own, flags); 3888 NFSLOCKCLSTATE(); 3889 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 3890 error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 3891 &nlck, own, dp, &lop); 3892 if (error != 0) { 3893 fl->l_whence = SEEK_SET; 3894 fl->l_start = lop->nfslo_first; 3895 if (lop->nfslo_end == NFS64BITSSET) 3896 fl->l_len = 0; 3897 else 3898 fl->l_len = lop->nfslo_end - lop->nfslo_first; 3899 fl->l_pid = (pid_t)0; 3900 fl->l_type = lop->nfslo_type; 3901 error = -1; /* no RPC required */ 3902 } else if (dp != NULL && ((dp->nfsdl_flags & NFSCLDL_WRITE) || 3903 fl->l_type == F_RDLCK)) { 3904 /* 3905 * The delegation ensures that there isn't a conflicting 3906 * lock on the server, so return -1 to indicate an RPC 3907 * isn't required. 3908 */ 3909 fl->l_type = F_UNLCK; 3910 error = -1; 3911 } 3912 NFSUNLOCKCLSTATE(); 3913 return (error); 3914 } 3915 3916 /* 3917 * Handle Recall of a delegation. 3918 * The clp must be exclusive locked when this is called. 3919 */ 3920 static int 3921 nfscl_recalldeleg(struct nfsclclient *clp, struct nfsmount *nmp, 3922 struct nfscldeleg *dp, vnode_t vp, struct ucred *cred, NFSPROC_T *p, 3923 int called_from_renewthread) 3924 { 3925 struct nfsclowner *owp, *lowp, *nowp; 3926 struct nfsclopen *op, *lop; 3927 struct nfscllockowner *lp; 3928 struct nfscllock *lckp; 3929 struct nfsnode *np; 3930 int error = 0, ret, gotvp = 0; 3931 3932 if (vp == NULL) { 3933 /* 3934 * First, get a vnode for the file. This is needed to do RPCs. 3935 */ 3936 ret = nfscl_ngetreopen(nmp->nm_mountp, dp->nfsdl_fh, 3937 dp->nfsdl_fhlen, p, &np); 3938 if (ret) { 3939 /* 3940 * File isn't open, so nothing to move over to the 3941 * server. 3942 */ 3943 return (0); 3944 } 3945 vp = NFSTOV(np); 3946 gotvp = 1; 3947 } else { 3948 np = VTONFS(vp); 3949 } 3950 dp->nfsdl_flags &= ~NFSCLDL_MODTIMESET; 3951 3952 /* 3953 * Ok, if it's a write delegation, flush data to the server, so 3954 * that close/open consistency is retained. 3955 */ 3956 ret = 0; 3957 NFSLOCKNODE(np); 3958 if ((dp->nfsdl_flags & NFSCLDL_WRITE) && (np->n_flag & NMODIFIED)) { 3959 np->n_flag |= NDELEGRECALL; 3960 NFSUNLOCKNODE(np); 3961 ret = ncl_flush(vp, MNT_WAIT, p, 1, called_from_renewthread); 3962 NFSLOCKNODE(np); 3963 np->n_flag &= ~NDELEGRECALL; 3964 } 3965 NFSINVALATTRCACHE(np); 3966 NFSUNLOCKNODE(np); 3967 if (ret == EIO && called_from_renewthread != 0) { 3968 /* 3969 * If the flush failed with EIO for the renew thread, 3970 * return now, so that the dirty buffer will be flushed 3971 * later. 3972 */ 3973 if (gotvp != 0) 3974 vrele(vp); 3975 return (ret); 3976 } 3977 3978 /* 3979 * Now, for each openowner with opens issued locally, move them 3980 * over to state against the server. 3981 */ 3982 LIST_FOREACH(lowp, &dp->nfsdl_owner, nfsow_list) { 3983 lop = LIST_FIRST(&lowp->nfsow_open); 3984 if (lop != NULL) { 3985 if (LIST_NEXT(lop, nfso_list) != NULL) 3986 panic("nfsdlg mult opens"); 3987 /* 3988 * Look for the same openowner against the server. 3989 */ 3990 LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) { 3991 if (!NFSBCMP(lowp->nfsow_owner, 3992 owp->nfsow_owner, NFSV4CL_LOCKNAMELEN)) { 3993 newnfs_copycred(&dp->nfsdl_cred, cred); 3994 ret = nfscl_moveopen(vp, clp, nmp, lop, 3995 owp, dp, cred, p); 3996 if (ret == NFSERR_STALECLIENTID || 3997 ret == NFSERR_STALEDONTRECOVER || 3998 ret == NFSERR_BADSESSION) { 3999 if (gotvp) 4000 vrele(vp); 4001 return (ret); 4002 } 4003 if (ret) { 4004 nfscl_freeopen(lop, 1); 4005 if (!error) 4006 error = ret; 4007 } 4008 break; 4009 } 4010 } 4011 4012 /* 4013 * If no openowner found, create one and get an open 4014 * for it. 4015 */ 4016 if (owp == NULL) { 4017 nowp = malloc( 4018 sizeof (struct nfsclowner), M_NFSCLOWNER, 4019 M_WAITOK); 4020 nfscl_newopen(clp, NULL, &owp, &nowp, &op, 4021 NULL, lowp->nfsow_owner, dp->nfsdl_fh, 4022 dp->nfsdl_fhlen, NULL, NULL); 4023 newnfs_copycred(&dp->nfsdl_cred, cred); 4024 ret = nfscl_moveopen(vp, clp, nmp, lop, 4025 owp, dp, cred, p); 4026 if (ret) { 4027 nfscl_freeopenowner(owp, 0); 4028 if (ret == NFSERR_STALECLIENTID || 4029 ret == NFSERR_STALEDONTRECOVER || 4030 ret == NFSERR_BADSESSION) { 4031 if (gotvp) 4032 vrele(vp); 4033 return (ret); 4034 } 4035 if (ret) { 4036 nfscl_freeopen(lop, 1); 4037 if (!error) 4038 error = ret; 4039 } 4040 } 4041 } 4042 } 4043 } 4044 4045 /* 4046 * Now, get byte range locks for any locks done locally. 4047 */ 4048 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 4049 LIST_FOREACH(lckp, &lp->nfsl_lock, nfslo_list) { 4050 newnfs_copycred(&dp->nfsdl_cred, cred); 4051 ret = nfscl_relock(vp, clp, nmp, lp, lckp, cred, p); 4052 if (ret == NFSERR_STALESTATEID || 4053 ret == NFSERR_STALEDONTRECOVER || 4054 ret == NFSERR_STALECLIENTID || 4055 ret == NFSERR_BADSESSION) { 4056 if (gotvp) 4057 vrele(vp); 4058 return (ret); 4059 } 4060 if (ret && !error) 4061 error = ret; 4062 } 4063 } 4064 if (gotvp) 4065 vrele(vp); 4066 return (error); 4067 } 4068 4069 /* 4070 * Move a locally issued open over to an owner on the state list. 4071 * SIDE EFFECT: If it needs to sleep (do an rpc), it unlocks clstate and 4072 * returns with it unlocked. 4073 */ 4074 static int 4075 nfscl_moveopen(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp, 4076 struct nfsclopen *lop, struct nfsclowner *owp, struct nfscldeleg *dp, 4077 struct ucred *cred, NFSPROC_T *p) 4078 { 4079 struct nfsclopen *op, *nop; 4080 struct nfscldeleg *ndp; 4081 struct nfsnode *np; 4082 int error = 0, newone; 4083 4084 /* 4085 * First, look for an appropriate open, If found, just increment the 4086 * opencnt in it. 4087 */ 4088 LIST_FOREACH(op, &owp->nfsow_open, nfso_list) { 4089 if ((op->nfso_mode & lop->nfso_mode) == lop->nfso_mode && 4090 op->nfso_fhlen == lop->nfso_fhlen && 4091 !NFSBCMP(op->nfso_fh, lop->nfso_fh, op->nfso_fhlen)) { 4092 op->nfso_opencnt += lop->nfso_opencnt; 4093 nfscl_freeopen(lop, 1); 4094 return (0); 4095 } 4096 } 4097 4098 /* No appropriate open, so we have to do one against the server. */ 4099 np = VTONFS(vp); 4100 nop = malloc(sizeof (struct nfsclopen) + 4101 lop->nfso_fhlen - 1, M_NFSCLOPEN, M_WAITOK); 4102 newone = 0; 4103 nfscl_newopen(clp, NULL, &owp, NULL, &op, &nop, owp->nfsow_owner, 4104 lop->nfso_fh, lop->nfso_fhlen, cred, &newone); 4105 ndp = dp; 4106 error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen, 4107 lop->nfso_fh, lop->nfso_fhlen, lop->nfso_mode, op, 4108 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &ndp, 0, 0, cred, p); 4109 if (error) { 4110 if (newone) 4111 nfscl_freeopen(op, 0); 4112 } else { 4113 op->nfso_mode |= lop->nfso_mode; 4114 op->nfso_opencnt += lop->nfso_opencnt; 4115 nfscl_freeopen(lop, 1); 4116 } 4117 if (nop != NULL) 4118 free(nop, M_NFSCLOPEN); 4119 if (ndp != NULL) { 4120 /* 4121 * What should I do with the returned delegation, since the 4122 * delegation is being recalled? For now, just printf and 4123 * through it away. 4124 */ 4125 printf("Moveopen returned deleg\n"); 4126 free(ndp, M_NFSCLDELEG); 4127 } 4128 return (error); 4129 } 4130 4131 /* 4132 * Recall all delegations on this client. 4133 */ 4134 static void 4135 nfscl_totalrecall(struct nfsclclient *clp) 4136 { 4137 struct nfscldeleg *dp; 4138 4139 TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) { 4140 if ((dp->nfsdl_flags & NFSCLDL_DELEGRET) == 0) 4141 dp->nfsdl_flags |= NFSCLDL_RECALL; 4142 } 4143 } 4144 4145 /* 4146 * Relock byte ranges. Called for delegation recall and state expiry. 4147 */ 4148 static int 4149 nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp, 4150 struct nfscllockowner *lp, struct nfscllock *lop, struct ucred *cred, 4151 NFSPROC_T *p) 4152 { 4153 struct nfscllockowner *nlp; 4154 struct nfsfh *nfhp; 4155 u_int64_t off, len; 4156 int error, newone, donelocally; 4157 4158 off = lop->nfslo_first; 4159 len = lop->nfslo_end - lop->nfslo_first; 4160 error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p, 4161 clp, 1, NULL, lp->nfsl_lockflags, lp->nfsl_owner, 4162 lp->nfsl_openowner, &nlp, &newone, &donelocally); 4163 if (error || donelocally) 4164 return (error); 4165 nfhp = VTONFS(vp)->n_fhp; 4166 error = nfscl_trylock(nmp, vp, nfhp->nfh_fh, 4167 nfhp->nfh_len, nlp, newone, 0, off, 4168 len, lop->nfslo_type, cred, p); 4169 if (error) 4170 nfscl_freelockowner(nlp, 0); 4171 return (error); 4172 } 4173 4174 /* 4175 * Called to re-open a file. Basically get a vnode for the file handle 4176 * and then call nfsrpc_openrpc() to do the rest. 4177 */ 4178 static int 4179 nfsrpc_reopen(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, 4180 u_int32_t mode, struct nfsclopen *op, struct nfscldeleg **dpp, 4181 struct ucred *cred, NFSPROC_T *p) 4182 { 4183 struct nfsnode *np; 4184 vnode_t vp; 4185 int error; 4186 4187 error = nfscl_ngetreopen(nmp->nm_mountp, fhp, fhlen, p, &np); 4188 if (error) 4189 return (error); 4190 vp = NFSTOV(np); 4191 if (np->n_v4 != NULL) { 4192 error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, 4193 np->n_v4->n4_fhlen, fhp, fhlen, mode, op, 4194 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, dpp, 0, 0, 4195 cred, p); 4196 } else { 4197 error = EINVAL; 4198 } 4199 vrele(vp); 4200 return (error); 4201 } 4202 4203 /* 4204 * Try an open against the server. Just call nfsrpc_openrpc(), retrying while 4205 * NFSERR_DELAY. Also, try system credentials, if the passed in credentials 4206 * fail. 4207 */ 4208 static int 4209 nfscl_tryopen(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen, 4210 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 4211 u_int8_t *name, int namelen, struct nfscldeleg **ndpp, 4212 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p) 4213 { 4214 int error; 4215 4216 do { 4217 error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, newfhlen, 4218 mode, op, name, namelen, ndpp, reclaim, delegtype, cred, p, 4219 0, 0); 4220 if (error == NFSERR_DELAY) 4221 (void) nfs_catnap(PZERO, error, "nfstryop"); 4222 } while (error == NFSERR_DELAY); 4223 if (error == EAUTH || error == EACCES) { 4224 /* Try again using system credentials */ 4225 newnfs_setroot(cred); 4226 do { 4227 error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, 4228 newfhlen, mode, op, name, namelen, ndpp, reclaim, 4229 delegtype, cred, p, 1, 0); 4230 if (error == NFSERR_DELAY) 4231 (void) nfs_catnap(PZERO, error, "nfstryop"); 4232 } while (error == NFSERR_DELAY); 4233 } 4234 return (error); 4235 } 4236 4237 /* 4238 * Try a byte range lock. Just loop on nfsrpc_lock() while it returns 4239 * NFSERR_DELAY. Also, retry with system credentials, if the provided 4240 * cred don't work. 4241 */ 4242 static int 4243 nfscl_trylock(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, 4244 int fhlen, struct nfscllockowner *nlp, int newone, int reclaim, 4245 u_int64_t off, u_int64_t len, short type, struct ucred *cred, NFSPROC_T *p) 4246 { 4247 struct nfsrv_descript nfsd, *nd = &nfsd; 4248 int error; 4249 4250 do { 4251 error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, newone, 4252 reclaim, off, len, type, cred, p, 0); 4253 if (!error && nd->nd_repstat == NFSERR_DELAY) 4254 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 4255 "nfstrylck"); 4256 } while (!error && nd->nd_repstat == NFSERR_DELAY); 4257 if (!error) 4258 error = nd->nd_repstat; 4259 if (error == EAUTH || error == EACCES) { 4260 /* Try again using root credentials */ 4261 newnfs_setroot(cred); 4262 do { 4263 error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, 4264 newone, reclaim, off, len, type, cred, p, 1); 4265 if (!error && nd->nd_repstat == NFSERR_DELAY) 4266 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 4267 "nfstrylck"); 4268 } while (!error && nd->nd_repstat == NFSERR_DELAY); 4269 if (!error) 4270 error = nd->nd_repstat; 4271 } 4272 return (error); 4273 } 4274 4275 /* 4276 * Try a delegreturn against the server. Just call nfsrpc_delegreturn(), 4277 * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in 4278 * credentials fail. 4279 */ 4280 static int 4281 nfscl_trydelegreturn(struct nfscldeleg *dp, struct ucred *cred, 4282 struct nfsmount *nmp, NFSPROC_T *p) 4283 { 4284 int error; 4285 4286 do { 4287 error = nfsrpc_delegreturn(dp, cred, nmp, p, 0); 4288 if (error == NFSERR_DELAY) 4289 (void) nfs_catnap(PZERO, error, "nfstrydp"); 4290 } while (error == NFSERR_DELAY); 4291 if (error == EAUTH || error == EACCES) { 4292 /* Try again using system credentials */ 4293 newnfs_setroot(cred); 4294 do { 4295 error = nfsrpc_delegreturn(dp, cred, nmp, p, 1); 4296 if (error == NFSERR_DELAY) 4297 (void) nfs_catnap(PZERO, error, "nfstrydp"); 4298 } while (error == NFSERR_DELAY); 4299 } 4300 return (error); 4301 } 4302 4303 /* 4304 * Try a close against the server. Just call nfsrpc_closerpc(), 4305 * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in 4306 * credentials fail. 4307 */ 4308 APPLESTATIC int 4309 nfscl_tryclose(struct nfsclopen *op, struct ucred *cred, 4310 struct nfsmount *nmp, NFSPROC_T *p) 4311 { 4312 struct nfsrv_descript nfsd, *nd = &nfsd; 4313 int error; 4314 4315 do { 4316 error = nfsrpc_closerpc(nd, nmp, op, cred, p, 0); 4317 if (error == NFSERR_DELAY) 4318 (void) nfs_catnap(PZERO, error, "nfstrycl"); 4319 } while (error == NFSERR_DELAY); 4320 if (error == EAUTH || error == EACCES) { 4321 /* Try again using system credentials */ 4322 newnfs_setroot(cred); 4323 do { 4324 error = nfsrpc_closerpc(nd, nmp, op, cred, p, 1); 4325 if (error == NFSERR_DELAY) 4326 (void) nfs_catnap(PZERO, error, "nfstrycl"); 4327 } while (error == NFSERR_DELAY); 4328 } 4329 return (error); 4330 } 4331 4332 /* 4333 * Decide if a delegation on a file permits close without flushing writes 4334 * to the server. This might be a big performance win in some environments. 4335 * (Not useful until the client does caching on local stable storage.) 4336 */ 4337 APPLESTATIC int 4338 nfscl_mustflush(vnode_t vp) 4339 { 4340 struct nfsclclient *clp; 4341 struct nfscldeleg *dp; 4342 struct nfsnode *np; 4343 struct nfsmount *nmp; 4344 4345 np = VTONFS(vp); 4346 nmp = VFSTONFS(vnode_mount(vp)); 4347 if (!NFSHASNFSV4(nmp)) 4348 return (1); 4349 NFSLOCKCLSTATE(); 4350 clp = nfscl_findcl(nmp); 4351 if (clp == NULL) { 4352 NFSUNLOCKCLSTATE(); 4353 return (1); 4354 } 4355 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4356 if (dp != NULL && (dp->nfsdl_flags & 4357 (NFSCLDL_WRITE | NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 4358 NFSCLDL_WRITE && 4359 (dp->nfsdl_sizelimit >= np->n_size || 4360 !NFSHASSTRICT3530(nmp))) { 4361 NFSUNLOCKCLSTATE(); 4362 return (0); 4363 } 4364 NFSUNLOCKCLSTATE(); 4365 return (1); 4366 } 4367 4368 /* 4369 * See if a (write) delegation exists for this file. 4370 */ 4371 APPLESTATIC int 4372 nfscl_nodeleg(vnode_t vp, int writedeleg) 4373 { 4374 struct nfsclclient *clp; 4375 struct nfscldeleg *dp; 4376 struct nfsnode *np; 4377 struct nfsmount *nmp; 4378 4379 np = VTONFS(vp); 4380 nmp = VFSTONFS(vnode_mount(vp)); 4381 if (!NFSHASNFSV4(nmp)) 4382 return (1); 4383 NFSLOCKCLSTATE(); 4384 clp = nfscl_findcl(nmp); 4385 if (clp == NULL) { 4386 NFSUNLOCKCLSTATE(); 4387 return (1); 4388 } 4389 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4390 if (dp != NULL && 4391 (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 0 && 4392 (writedeleg == 0 || (dp->nfsdl_flags & NFSCLDL_WRITE) == 4393 NFSCLDL_WRITE)) { 4394 NFSUNLOCKCLSTATE(); 4395 return (0); 4396 } 4397 NFSUNLOCKCLSTATE(); 4398 return (1); 4399 } 4400 4401 /* 4402 * Look for an associated delegation that should be DelegReturned. 4403 */ 4404 APPLESTATIC int 4405 nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp) 4406 { 4407 struct nfsclclient *clp; 4408 struct nfscldeleg *dp; 4409 struct nfsclowner *owp; 4410 struct nfscllockowner *lp; 4411 struct nfsmount *nmp; 4412 struct ucred *cred; 4413 struct nfsnode *np; 4414 int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept; 4415 4416 nmp = VFSTONFS(vnode_mount(vp)); 4417 np = VTONFS(vp); 4418 NFSLOCKCLSTATE(); 4419 /* 4420 * Loop around waiting for: 4421 * - outstanding I/O operations on delegations to complete 4422 * - for a delegation on vp that has state, lock the client and 4423 * do a recall 4424 * - return delegation with no state 4425 */ 4426 while (1) { 4427 clp = nfscl_findcl(nmp); 4428 if (clp == NULL) { 4429 NFSUNLOCKCLSTATE(); 4430 return (retcnt); 4431 } 4432 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 4433 np->n_fhp->nfh_len); 4434 if (dp != NULL) { 4435 /* 4436 * Wait for outstanding I/O ops to be done. 4437 */ 4438 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 4439 if (igotlock) { 4440 nfsv4_unlock(&clp->nfsc_lock, 0); 4441 igotlock = 0; 4442 } 4443 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 4444 (void) nfsmsleep(&dp->nfsdl_rwlock, 4445 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 4446 continue; 4447 } 4448 needsrecall = 0; 4449 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 4450 if (!LIST_EMPTY(&owp->nfsow_open)) { 4451 needsrecall = 1; 4452 break; 4453 } 4454 } 4455 if (!needsrecall) { 4456 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 4457 if (!LIST_EMPTY(&lp->nfsl_lock)) { 4458 needsrecall = 1; 4459 break; 4460 } 4461 } 4462 } 4463 if (needsrecall && !triedrecall) { 4464 dp->nfsdl_flags |= NFSCLDL_DELEGRET; 4465 islept = 0; 4466 while (!igotlock) { 4467 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 4468 &islept, NFSCLSTATEMUTEXPTR, NULL); 4469 if (islept) 4470 break; 4471 } 4472 if (islept) 4473 continue; 4474 NFSUNLOCKCLSTATE(); 4475 cred = newnfs_getcred(); 4476 newnfs_copycred(&dp->nfsdl_cred, cred); 4477 (void) nfscl_recalldeleg(clp, nmp, dp, vp, cred, p, 0); 4478 NFSFREECRED(cred); 4479 triedrecall = 1; 4480 NFSLOCKCLSTATE(); 4481 nfsv4_unlock(&clp->nfsc_lock, 0); 4482 igotlock = 0; 4483 continue; 4484 } 4485 *stp = dp->nfsdl_stateid; 4486 retcnt = 1; 4487 nfscl_cleandeleg(dp); 4488 nfscl_freedeleg(&clp->nfsc_deleg, dp); 4489 } 4490 if (igotlock) 4491 nfsv4_unlock(&clp->nfsc_lock, 0); 4492 NFSUNLOCKCLSTATE(); 4493 return (retcnt); 4494 } 4495 } 4496 4497 /* 4498 * Look for associated delegation(s) that should be DelegReturned. 4499 */ 4500 APPLESTATIC int 4501 nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp, 4502 nfsv4stateid_t *tstp, int *gottdp, NFSPROC_T *p) 4503 { 4504 struct nfsclclient *clp; 4505 struct nfscldeleg *dp; 4506 struct nfsclowner *owp; 4507 struct nfscllockowner *lp; 4508 struct nfsmount *nmp; 4509 struct ucred *cred; 4510 struct nfsnode *np; 4511 int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept; 4512 4513 nmp = VFSTONFS(vnode_mount(fvp)); 4514 *gotfdp = 0; 4515 *gottdp = 0; 4516 NFSLOCKCLSTATE(); 4517 /* 4518 * Loop around waiting for: 4519 * - outstanding I/O operations on delegations to complete 4520 * - for a delegation on fvp that has state, lock the client and 4521 * do a recall 4522 * - return delegation(s) with no state. 4523 */ 4524 while (1) { 4525 clp = nfscl_findcl(nmp); 4526 if (clp == NULL) { 4527 NFSUNLOCKCLSTATE(); 4528 return (retcnt); 4529 } 4530 np = VTONFS(fvp); 4531 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 4532 np->n_fhp->nfh_len); 4533 if (dp != NULL && *gotfdp == 0) { 4534 /* 4535 * Wait for outstanding I/O ops to be done. 4536 */ 4537 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 4538 if (igotlock) { 4539 nfsv4_unlock(&clp->nfsc_lock, 0); 4540 igotlock = 0; 4541 } 4542 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 4543 (void) nfsmsleep(&dp->nfsdl_rwlock, 4544 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 4545 continue; 4546 } 4547 needsrecall = 0; 4548 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 4549 if (!LIST_EMPTY(&owp->nfsow_open)) { 4550 needsrecall = 1; 4551 break; 4552 } 4553 } 4554 if (!needsrecall) { 4555 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 4556 if (!LIST_EMPTY(&lp->nfsl_lock)) { 4557 needsrecall = 1; 4558 break; 4559 } 4560 } 4561 } 4562 if (needsrecall && !triedrecall) { 4563 dp->nfsdl_flags |= NFSCLDL_DELEGRET; 4564 islept = 0; 4565 while (!igotlock) { 4566 igotlock = nfsv4_lock(&clp->nfsc_lock, 1, 4567 &islept, NFSCLSTATEMUTEXPTR, NULL); 4568 if (islept) 4569 break; 4570 } 4571 if (islept) 4572 continue; 4573 NFSUNLOCKCLSTATE(); 4574 cred = newnfs_getcred(); 4575 newnfs_copycred(&dp->nfsdl_cred, cred); 4576 (void) nfscl_recalldeleg(clp, nmp, dp, fvp, cred, p, 0); 4577 NFSFREECRED(cred); 4578 triedrecall = 1; 4579 NFSLOCKCLSTATE(); 4580 nfsv4_unlock(&clp->nfsc_lock, 0); 4581 igotlock = 0; 4582 continue; 4583 } 4584 *fstp = dp->nfsdl_stateid; 4585 retcnt++; 4586 *gotfdp = 1; 4587 nfscl_cleandeleg(dp); 4588 nfscl_freedeleg(&clp->nfsc_deleg, dp); 4589 } 4590 if (igotlock) { 4591 nfsv4_unlock(&clp->nfsc_lock, 0); 4592 igotlock = 0; 4593 } 4594 if (tvp != NULL) { 4595 np = VTONFS(tvp); 4596 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, 4597 np->n_fhp->nfh_len); 4598 if (dp != NULL && *gottdp == 0) { 4599 /* 4600 * Wait for outstanding I/O ops to be done. 4601 */ 4602 if (dp->nfsdl_rwlock.nfslock_usecnt > 0) { 4603 dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED; 4604 (void) nfsmsleep(&dp->nfsdl_rwlock, 4605 NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL); 4606 continue; 4607 } 4608 LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) { 4609 if (!LIST_EMPTY(&owp->nfsow_open)) { 4610 NFSUNLOCKCLSTATE(); 4611 return (retcnt); 4612 } 4613 } 4614 LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) { 4615 if (!LIST_EMPTY(&lp->nfsl_lock)) { 4616 NFSUNLOCKCLSTATE(); 4617 return (retcnt); 4618 } 4619 } 4620 *tstp = dp->nfsdl_stateid; 4621 retcnt++; 4622 *gottdp = 1; 4623 nfscl_cleandeleg(dp); 4624 nfscl_freedeleg(&clp->nfsc_deleg, dp); 4625 } 4626 } 4627 NFSUNLOCKCLSTATE(); 4628 return (retcnt); 4629 } 4630 } 4631 4632 /* 4633 * Get a reference on the clientid associated with the mount point. 4634 * Return 1 if success, 0 otherwise. 4635 */ 4636 APPLESTATIC int 4637 nfscl_getref(struct nfsmount *nmp) 4638 { 4639 struct nfsclclient *clp; 4640 4641 NFSLOCKCLSTATE(); 4642 clp = nfscl_findcl(nmp); 4643 if (clp == NULL) { 4644 NFSUNLOCKCLSTATE(); 4645 return (0); 4646 } 4647 nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, NULL); 4648 NFSUNLOCKCLSTATE(); 4649 return (1); 4650 } 4651 4652 /* 4653 * Release a reference on a clientid acquired with the above call. 4654 */ 4655 APPLESTATIC void 4656 nfscl_relref(struct nfsmount *nmp) 4657 { 4658 struct nfsclclient *clp; 4659 4660 NFSLOCKCLSTATE(); 4661 clp = nfscl_findcl(nmp); 4662 if (clp == NULL) { 4663 NFSUNLOCKCLSTATE(); 4664 return; 4665 } 4666 nfsv4_relref(&clp->nfsc_lock); 4667 NFSUNLOCKCLSTATE(); 4668 } 4669 4670 /* 4671 * Save the size attribute in the delegation, since the nfsnode 4672 * is going away. 4673 */ 4674 APPLESTATIC void 4675 nfscl_reclaimnode(vnode_t vp) 4676 { 4677 struct nfsclclient *clp; 4678 struct nfscldeleg *dp; 4679 struct nfsnode *np = VTONFS(vp); 4680 struct nfsmount *nmp; 4681 4682 nmp = VFSTONFS(vnode_mount(vp)); 4683 if (!NFSHASNFSV4(nmp)) 4684 return; 4685 NFSLOCKCLSTATE(); 4686 clp = nfscl_findcl(nmp); 4687 if (clp == NULL) { 4688 NFSUNLOCKCLSTATE(); 4689 return; 4690 } 4691 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4692 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) 4693 dp->nfsdl_size = np->n_size; 4694 NFSUNLOCKCLSTATE(); 4695 } 4696 4697 /* 4698 * Get the saved size attribute in the delegation, since it is a 4699 * newly allocated nfsnode. 4700 */ 4701 APPLESTATIC void 4702 nfscl_newnode(vnode_t vp) 4703 { 4704 struct nfsclclient *clp; 4705 struct nfscldeleg *dp; 4706 struct nfsnode *np = VTONFS(vp); 4707 struct nfsmount *nmp; 4708 4709 nmp = VFSTONFS(vnode_mount(vp)); 4710 if (!NFSHASNFSV4(nmp)) 4711 return; 4712 NFSLOCKCLSTATE(); 4713 clp = nfscl_findcl(nmp); 4714 if (clp == NULL) { 4715 NFSUNLOCKCLSTATE(); 4716 return; 4717 } 4718 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4719 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) 4720 np->n_size = dp->nfsdl_size; 4721 NFSUNLOCKCLSTATE(); 4722 } 4723 4724 /* 4725 * If there is a valid write delegation for this file, set the modtime 4726 * to the local clock time. 4727 */ 4728 APPLESTATIC void 4729 nfscl_delegmodtime(vnode_t vp) 4730 { 4731 struct nfsclclient *clp; 4732 struct nfscldeleg *dp; 4733 struct nfsnode *np = VTONFS(vp); 4734 struct nfsmount *nmp; 4735 4736 nmp = VFSTONFS(vnode_mount(vp)); 4737 if (!NFSHASNFSV4(nmp)) 4738 return; 4739 NFSLOCKCLSTATE(); 4740 clp = nfscl_findcl(nmp); 4741 if (clp == NULL) { 4742 NFSUNLOCKCLSTATE(); 4743 return; 4744 } 4745 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4746 if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) { 4747 nanotime(&dp->nfsdl_modtime); 4748 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 4749 } 4750 NFSUNLOCKCLSTATE(); 4751 } 4752 4753 /* 4754 * If there is a valid write delegation for this file with a modtime set, 4755 * put that modtime in mtime. 4756 */ 4757 APPLESTATIC void 4758 nfscl_deleggetmodtime(vnode_t vp, struct timespec *mtime) 4759 { 4760 struct nfsclclient *clp; 4761 struct nfscldeleg *dp; 4762 struct nfsnode *np = VTONFS(vp); 4763 struct nfsmount *nmp; 4764 4765 nmp = VFSTONFS(vnode_mount(vp)); 4766 if (!NFSHASNFSV4(nmp)) 4767 return; 4768 NFSLOCKCLSTATE(); 4769 clp = nfscl_findcl(nmp); 4770 if (clp == NULL) { 4771 NFSUNLOCKCLSTATE(); 4772 return; 4773 } 4774 dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 4775 if (dp != NULL && 4776 (dp->nfsdl_flags & (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) == 4777 (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) 4778 *mtime = dp->nfsdl_modtime; 4779 NFSUNLOCKCLSTATE(); 4780 } 4781 4782 static int 4783 nfscl_errmap(struct nfsrv_descript *nd, u_int32_t minorvers) 4784 { 4785 short *defaulterrp, *errp; 4786 4787 if (!nd->nd_repstat) 4788 return (0); 4789 if (nd->nd_procnum == NFSPROC_NOOP) 4790 return (txdr_unsigned(nd->nd_repstat & 0xffff)); 4791 if (nd->nd_repstat == EBADRPC) 4792 return (txdr_unsigned(NFSERR_BADXDR)); 4793 if (nd->nd_repstat == NFSERR_MINORVERMISMATCH || 4794 nd->nd_repstat == NFSERR_OPILLEGAL) 4795 return (txdr_unsigned(nd->nd_repstat)); 4796 if (nd->nd_repstat >= NFSERR_BADIOMODE && nd->nd_repstat < 20000 && 4797 minorvers > NFSV4_MINORVERSION) { 4798 /* NFSv4.n error. */ 4799 return (txdr_unsigned(nd->nd_repstat)); 4800 } 4801 if (nd->nd_procnum < NFSV4OP_CBNOPS) 4802 errp = defaulterrp = nfscl_cberrmap[nd->nd_procnum]; 4803 else 4804 return (txdr_unsigned(nd->nd_repstat)); 4805 while (*++errp) 4806 if (*errp == (short)nd->nd_repstat) 4807 return (txdr_unsigned(nd->nd_repstat)); 4808 return (txdr_unsigned(*defaulterrp)); 4809 } 4810 4811 /* 4812 * Called to find/add a layout to a client. 4813 * This function returns the layout with a refcnt (shared lock) upon 4814 * success (returns 0) or with no lock/refcnt on the layout when an 4815 * error is returned. 4816 * If a layout is passed in via lypp, it is locked (exclusively locked). 4817 */ 4818 APPLESTATIC int 4819 nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen, 4820 nfsv4stateid_t *stateidp, int layouttype, int retonclose, 4821 struct nfsclflayouthead *fhlp, struct nfscllayout **lypp, 4822 struct ucred *cred, NFSPROC_T *p) 4823 { 4824 struct nfsclclient *clp; 4825 struct nfscllayout *lyp, *tlyp; 4826 struct nfsclflayout *flp; 4827 struct nfsnode *np = VTONFS(vp); 4828 mount_t mp; 4829 int layout_passed_in; 4830 4831 mp = nmp->nm_mountp; 4832 layout_passed_in = 1; 4833 tlyp = NULL; 4834 lyp = *lypp; 4835 if (lyp == NULL) { 4836 layout_passed_in = 0; 4837 tlyp = malloc(sizeof(*tlyp) + fhlen - 1, M_NFSLAYOUT, 4838 M_WAITOK | M_ZERO); 4839 } 4840 4841 NFSLOCKCLSTATE(); 4842 clp = nmp->nm_clp; 4843 if (clp == NULL) { 4844 if (layout_passed_in != 0) 4845 nfsv4_unlock(&lyp->nfsly_lock, 0); 4846 NFSUNLOCKCLSTATE(); 4847 if (tlyp != NULL) 4848 free(tlyp, M_NFSLAYOUT); 4849 return (EPERM); 4850 } 4851 if (lyp == NULL) { 4852 /* 4853 * Although no lyp was passed in, another thread might have 4854 * allocated one. If one is found, just increment it's ref 4855 * count and return it. 4856 */ 4857 lyp = nfscl_findlayout(clp, fhp, fhlen); 4858 if (lyp == NULL) { 4859 lyp = tlyp; 4860 tlyp = NULL; 4861 lyp->nfsly_stateid.seqid = stateidp->seqid; 4862 lyp->nfsly_stateid.other[0] = stateidp->other[0]; 4863 lyp->nfsly_stateid.other[1] = stateidp->other[1]; 4864 lyp->nfsly_stateid.other[2] = stateidp->other[2]; 4865 lyp->nfsly_lastbyte = 0; 4866 LIST_INIT(&lyp->nfsly_flayread); 4867 LIST_INIT(&lyp->nfsly_flayrw); 4868 LIST_INIT(&lyp->nfsly_recall); 4869 lyp->nfsly_filesid[0] = np->n_vattr.na_filesid[0]; 4870 lyp->nfsly_filesid[1] = np->n_vattr.na_filesid[1]; 4871 lyp->nfsly_clp = clp; 4872 if (layouttype == NFSLAYOUT_FLEXFILE) 4873 lyp->nfsly_flags = NFSLY_FLEXFILE; 4874 else 4875 lyp->nfsly_flags = NFSLY_FILES; 4876 if (retonclose != 0) 4877 lyp->nfsly_flags |= NFSLY_RETONCLOSE; 4878 lyp->nfsly_fhlen = fhlen; 4879 NFSBCOPY(fhp, lyp->nfsly_fh, fhlen); 4880 TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); 4881 LIST_INSERT_HEAD(NFSCLLAYOUTHASH(clp, fhp, fhlen), lyp, 4882 nfsly_hash); 4883 lyp->nfsly_timestamp = NFSD_MONOSEC + 120; 4884 nfscl_layoutcnt++; 4885 } else { 4886 if (retonclose != 0) 4887 lyp->nfsly_flags |= NFSLY_RETONCLOSE; 4888 TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list); 4889 TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); 4890 lyp->nfsly_timestamp = NFSD_MONOSEC + 120; 4891 } 4892 nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp); 4893 if (NFSCL_FORCEDISM(mp)) { 4894 NFSUNLOCKCLSTATE(); 4895 if (tlyp != NULL) 4896 free(tlyp, M_NFSLAYOUT); 4897 return (EPERM); 4898 } 4899 *lypp = lyp; 4900 } else 4901 lyp->nfsly_stateid.seqid = stateidp->seqid; 4902 4903 /* Merge the new list of File Layouts into the list. */ 4904 flp = LIST_FIRST(fhlp); 4905 if (flp != NULL) { 4906 if (flp->nfsfl_iomode == NFSLAYOUTIOMODE_READ) 4907 nfscl_mergeflayouts(&lyp->nfsly_flayread, fhlp); 4908 else 4909 nfscl_mergeflayouts(&lyp->nfsly_flayrw, fhlp); 4910 } 4911 if (layout_passed_in != 0) 4912 nfsv4_unlock(&lyp->nfsly_lock, 1); 4913 NFSUNLOCKCLSTATE(); 4914 if (tlyp != NULL) 4915 free(tlyp, M_NFSLAYOUT); 4916 return (0); 4917 } 4918 4919 /* 4920 * Search for a layout by MDS file handle. 4921 * If one is found, it is returned with a refcnt (shared lock) iff 4922 * retflpp returned non-NULL and locked (exclusive locked) iff retflpp is 4923 * returned NULL. 4924 */ 4925 struct nfscllayout * 4926 nfscl_getlayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen, 4927 uint64_t off, struct nfsclflayout **retflpp, int *recalledp) 4928 { 4929 struct nfscllayout *lyp; 4930 mount_t mp; 4931 int error, igotlock; 4932 4933 mp = clp->nfsc_nmp->nm_mountp; 4934 *recalledp = 0; 4935 *retflpp = NULL; 4936 NFSLOCKCLSTATE(); 4937 lyp = nfscl_findlayout(clp, fhp, fhlen); 4938 if (lyp != NULL) { 4939 if ((lyp->nfsly_flags & NFSLY_RECALL) == 0) { 4940 TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list); 4941 TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); 4942 lyp->nfsly_timestamp = NFSD_MONOSEC + 120; 4943 error = nfscl_findlayoutforio(lyp, off, 4944 NFSV4OPEN_ACCESSREAD, retflpp); 4945 if (error == 0) 4946 nfsv4_getref(&lyp->nfsly_lock, NULL, 4947 NFSCLSTATEMUTEXPTR, mp); 4948 else { 4949 do { 4950 igotlock = nfsv4_lock(&lyp->nfsly_lock, 4951 1, NULL, NFSCLSTATEMUTEXPTR, mp); 4952 } while (igotlock == 0 && !NFSCL_FORCEDISM(mp)); 4953 *retflpp = NULL; 4954 } 4955 if (NFSCL_FORCEDISM(mp)) { 4956 lyp = NULL; 4957 *recalledp = 1; 4958 } 4959 } else { 4960 lyp = NULL; 4961 *recalledp = 1; 4962 } 4963 } 4964 NFSUNLOCKCLSTATE(); 4965 return (lyp); 4966 } 4967 4968 /* 4969 * Search for a layout by MDS file handle. If one is found, mark in to be 4970 * recalled, if it already marked "return on close". 4971 */ 4972 static void 4973 nfscl_retoncloselayout(vnode_t vp, struct nfsclclient *clp, uint8_t *fhp, 4974 int fhlen, struct nfsclrecalllayout **recallpp) 4975 { 4976 struct nfscllayout *lyp; 4977 uint32_t iomode; 4978 4979 if (vp->v_type != VREG || !NFSHASPNFS(VFSTONFS(vnode_mount(vp))) || 4980 nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 4981 (VTONFS(vp)->n_flag & NNOLAYOUT) != 0) 4982 return; 4983 lyp = nfscl_findlayout(clp, fhp, fhlen); 4984 if (lyp != NULL && (lyp->nfsly_flags & (NFSLY_RETONCLOSE | 4985 NFSLY_RECALL)) == NFSLY_RETONCLOSE) { 4986 iomode = 0; 4987 if (!LIST_EMPTY(&lyp->nfsly_flayread)) 4988 iomode |= NFSLAYOUTIOMODE_READ; 4989 if (!LIST_EMPTY(&lyp->nfsly_flayrw)) 4990 iomode |= NFSLAYOUTIOMODE_RW; 4991 (void)nfscl_layoutrecall(NFSLAYOUTRETURN_FILE, lyp, iomode, 4992 0, UINT64_MAX, lyp->nfsly_stateid.seqid, 0, 0, NULL, 4993 *recallpp); 4994 NFSCL_DEBUG(4, "retoncls recall iomode=%d\n", iomode); 4995 *recallpp = NULL; 4996 } 4997 } 4998 4999 /* 5000 * Mark the layout to be recalled and with an error. 5001 * Also, disable the dsp from further use. 5002 */ 5003 void 5004 nfscl_dserr(uint32_t op, uint32_t stat, struct nfscldevinfo *dp, 5005 struct nfscllayout *lyp, struct nfsclds *dsp) 5006 { 5007 struct nfsclrecalllayout *recallp; 5008 uint32_t iomode; 5009 5010 printf("DS being disabled, error=%d\n", stat); 5011 /* Set up the return of the layout. */ 5012 recallp = malloc(sizeof(*recallp), M_NFSLAYRECALL, M_WAITOK); 5013 iomode = 0; 5014 NFSLOCKCLSTATE(); 5015 if ((lyp->nfsly_flags & NFSLY_RECALL) == 0) { 5016 if (!LIST_EMPTY(&lyp->nfsly_flayread)) 5017 iomode |= NFSLAYOUTIOMODE_READ; 5018 if (!LIST_EMPTY(&lyp->nfsly_flayrw)) 5019 iomode |= NFSLAYOUTIOMODE_RW; 5020 (void)nfscl_layoutrecall(NFSLAYOUTRETURN_FILE, lyp, iomode, 5021 0, UINT64_MAX, lyp->nfsly_stateid.seqid, stat, op, 5022 dp->nfsdi_deviceid, recallp); 5023 NFSUNLOCKCLSTATE(); 5024 NFSCL_DEBUG(4, "nfscl_dserr recall iomode=%d\n", iomode); 5025 } else { 5026 NFSUNLOCKCLSTATE(); 5027 free(recallp, M_NFSLAYRECALL); 5028 } 5029 5030 /* And shut the TCP connection down. */ 5031 nfscl_cancelreqs(dsp); 5032 } 5033 5034 /* 5035 * Cancel all RPCs for this "dsp" by closing the connection. 5036 * Also, mark the session as defunct. 5037 * If NFSCLDS_SAMECONN is set, the connection is shared with other DSs and 5038 * cannot be shut down. 5039 */ 5040 APPLESTATIC void 5041 nfscl_cancelreqs(struct nfsclds *dsp) 5042 { 5043 struct __rpc_client *cl; 5044 static int non_event; 5045 5046 NFSLOCKDS(dsp); 5047 if ((dsp->nfsclds_flags & (NFSCLDS_CLOSED | NFSCLDS_SAMECONN)) == 0 && 5048 dsp->nfsclds_sockp != NULL && 5049 dsp->nfsclds_sockp->nr_client != NULL) { 5050 dsp->nfsclds_flags |= NFSCLDS_CLOSED; 5051 cl = dsp->nfsclds_sockp->nr_client; 5052 dsp->nfsclds_sess.nfsess_defunct = 1; 5053 NFSUNLOCKDS(dsp); 5054 CLNT_CLOSE(cl); 5055 /* 5056 * This 1sec sleep is done to reduce the number of reconnect 5057 * attempts made on the DS while it has failed. 5058 */ 5059 tsleep(&non_event, PVFS, "ndscls", hz); 5060 return; 5061 } 5062 NFSUNLOCKDS(dsp); 5063 } 5064 5065 /* 5066 * Dereference a layout. 5067 */ 5068 void 5069 nfscl_rellayout(struct nfscllayout *lyp, int exclocked) 5070 { 5071 5072 NFSLOCKCLSTATE(); 5073 if (exclocked != 0) 5074 nfsv4_unlock(&lyp->nfsly_lock, 0); 5075 else 5076 nfsv4_relref(&lyp->nfsly_lock); 5077 NFSUNLOCKCLSTATE(); 5078 } 5079 5080 /* 5081 * Search for a devinfo by deviceid. If one is found, return it after 5082 * acquiring a reference count on it. 5083 */ 5084 struct nfscldevinfo * 5085 nfscl_getdevinfo(struct nfsclclient *clp, uint8_t *deviceid, 5086 struct nfscldevinfo *dip) 5087 { 5088 5089 NFSLOCKCLSTATE(); 5090 if (dip == NULL) 5091 dip = nfscl_finddevinfo(clp, deviceid); 5092 if (dip != NULL) 5093 dip->nfsdi_refcnt++; 5094 NFSUNLOCKCLSTATE(); 5095 return (dip); 5096 } 5097 5098 /* 5099 * Dereference a devinfo structure. 5100 */ 5101 static void 5102 nfscl_reldevinfo_locked(struct nfscldevinfo *dip) 5103 { 5104 5105 dip->nfsdi_refcnt--; 5106 if (dip->nfsdi_refcnt == 0) 5107 wakeup(&dip->nfsdi_refcnt); 5108 } 5109 5110 /* 5111 * Dereference a devinfo structure. 5112 */ 5113 void 5114 nfscl_reldevinfo(struct nfscldevinfo *dip) 5115 { 5116 5117 NFSLOCKCLSTATE(); 5118 nfscl_reldevinfo_locked(dip); 5119 NFSUNLOCKCLSTATE(); 5120 } 5121 5122 /* 5123 * Find a layout for this file handle. Return NULL upon failure. 5124 */ 5125 static struct nfscllayout * 5126 nfscl_findlayout(struct nfsclclient *clp, u_int8_t *fhp, int fhlen) 5127 { 5128 struct nfscllayout *lyp; 5129 5130 LIST_FOREACH(lyp, NFSCLLAYOUTHASH(clp, fhp, fhlen), nfsly_hash) 5131 if (lyp->nfsly_fhlen == fhlen && 5132 !NFSBCMP(lyp->nfsly_fh, fhp, fhlen)) 5133 break; 5134 return (lyp); 5135 } 5136 5137 /* 5138 * Find a devinfo for this deviceid. Return NULL upon failure. 5139 */ 5140 static struct nfscldevinfo * 5141 nfscl_finddevinfo(struct nfsclclient *clp, uint8_t *deviceid) 5142 { 5143 struct nfscldevinfo *dip; 5144 5145 LIST_FOREACH(dip, &clp->nfsc_devinfo, nfsdi_list) 5146 if (NFSBCMP(dip->nfsdi_deviceid, deviceid, NFSX_V4DEVICEID) 5147 == 0) 5148 break; 5149 return (dip); 5150 } 5151 5152 /* 5153 * Merge the new file layout list into the main one, maintaining it in 5154 * increasing offset order. 5155 */ 5156 static void 5157 nfscl_mergeflayouts(struct nfsclflayouthead *fhlp, 5158 struct nfsclflayouthead *newfhlp) 5159 { 5160 struct nfsclflayout *flp, *nflp, *prevflp, *tflp; 5161 5162 flp = LIST_FIRST(fhlp); 5163 prevflp = NULL; 5164 LIST_FOREACH_SAFE(nflp, newfhlp, nfsfl_list, tflp) { 5165 while (flp != NULL && flp->nfsfl_off < nflp->nfsfl_off) { 5166 prevflp = flp; 5167 flp = LIST_NEXT(flp, nfsfl_list); 5168 } 5169 if (prevflp == NULL) 5170 LIST_INSERT_HEAD(fhlp, nflp, nfsfl_list); 5171 else 5172 LIST_INSERT_AFTER(prevflp, nflp, nfsfl_list); 5173 prevflp = nflp; 5174 } 5175 } 5176 5177 /* 5178 * Add this nfscldevinfo to the client, if it doesn't already exist. 5179 * This function consumes the structure pointed at by dip, if not NULL. 5180 */ 5181 APPLESTATIC int 5182 nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip, int ind, 5183 struct nfsclflayout *flp) 5184 { 5185 struct nfsclclient *clp; 5186 struct nfscldevinfo *tdip; 5187 uint8_t *dev; 5188 5189 NFSLOCKCLSTATE(); 5190 clp = nmp->nm_clp; 5191 if (clp == NULL) { 5192 NFSUNLOCKCLSTATE(); 5193 if (dip != NULL) 5194 free(dip, M_NFSDEVINFO); 5195 return (ENODEV); 5196 } 5197 if ((flp->nfsfl_flags & NFSFL_FILE) != 0) 5198 dev = flp->nfsfl_dev; 5199 else 5200 dev = flp->nfsfl_ffm[ind].dev; 5201 tdip = nfscl_finddevinfo(clp, dev); 5202 if (tdip != NULL) { 5203 tdip->nfsdi_layoutrefs++; 5204 if ((flp->nfsfl_flags & NFSFL_FILE) != 0) 5205 flp->nfsfl_devp = tdip; 5206 else 5207 flp->nfsfl_ffm[ind].devp = tdip; 5208 nfscl_reldevinfo_locked(tdip); 5209 NFSUNLOCKCLSTATE(); 5210 if (dip != NULL) 5211 free(dip, M_NFSDEVINFO); 5212 return (0); 5213 } 5214 if (dip != NULL) { 5215 LIST_INSERT_HEAD(&clp->nfsc_devinfo, dip, nfsdi_list); 5216 dip->nfsdi_layoutrefs = 1; 5217 if ((flp->nfsfl_flags & NFSFL_FILE) != 0) 5218 flp->nfsfl_devp = dip; 5219 else 5220 flp->nfsfl_ffm[ind].devp = dip; 5221 } 5222 NFSUNLOCKCLSTATE(); 5223 if (dip == NULL) 5224 return (ENODEV); 5225 return (0); 5226 } 5227 5228 /* 5229 * Free up a layout structure and associated file layout structure(s). 5230 */ 5231 APPLESTATIC void 5232 nfscl_freelayout(struct nfscllayout *layp) 5233 { 5234 struct nfsclflayout *flp, *nflp; 5235 struct nfsclrecalllayout *rp, *nrp; 5236 5237 LIST_FOREACH_SAFE(flp, &layp->nfsly_flayread, nfsfl_list, nflp) { 5238 LIST_REMOVE(flp, nfsfl_list); 5239 nfscl_freeflayout(flp); 5240 } 5241 LIST_FOREACH_SAFE(flp, &layp->nfsly_flayrw, nfsfl_list, nflp) { 5242 LIST_REMOVE(flp, nfsfl_list); 5243 nfscl_freeflayout(flp); 5244 } 5245 LIST_FOREACH_SAFE(rp, &layp->nfsly_recall, nfsrecly_list, nrp) { 5246 LIST_REMOVE(rp, nfsrecly_list); 5247 free(rp, M_NFSLAYRECALL); 5248 } 5249 nfscl_layoutcnt--; 5250 free(layp, M_NFSLAYOUT); 5251 } 5252 5253 /* 5254 * Free up a file layout structure. 5255 */ 5256 APPLESTATIC void 5257 nfscl_freeflayout(struct nfsclflayout *flp) 5258 { 5259 int i, j; 5260 5261 if ((flp->nfsfl_flags & NFSFL_FILE) != 0) { 5262 for (i = 0; i < flp->nfsfl_fhcnt; i++) 5263 free(flp->nfsfl_fh[i], M_NFSFH); 5264 if (flp->nfsfl_devp != NULL) 5265 flp->nfsfl_devp->nfsdi_layoutrefs--; 5266 } 5267 if ((flp->nfsfl_flags & NFSFL_FLEXFILE) != 0) 5268 for (i = 0; i < flp->nfsfl_mirrorcnt; i++) { 5269 for (j = 0; j < flp->nfsfl_ffm[i].fhcnt; j++) 5270 free(flp->nfsfl_ffm[i].fh[j], M_NFSFH); 5271 if (flp->nfsfl_ffm[i].devp != NULL) 5272 flp->nfsfl_ffm[i].devp->nfsdi_layoutrefs--; 5273 } 5274 free(flp, M_NFSFLAYOUT); 5275 } 5276 5277 /* 5278 * Free up a file layout devinfo structure. 5279 */ 5280 APPLESTATIC void 5281 nfscl_freedevinfo(struct nfscldevinfo *dip) 5282 { 5283 5284 free(dip, M_NFSDEVINFO); 5285 } 5286 5287 /* 5288 * Mark any layouts that match as recalled. 5289 */ 5290 static int 5291 nfscl_layoutrecall(int recalltype, struct nfscllayout *lyp, uint32_t iomode, 5292 uint64_t off, uint64_t len, uint32_t stateseqid, uint32_t stat, uint32_t op, 5293 char *devid, struct nfsclrecalllayout *recallp) 5294 { 5295 struct nfsclrecalllayout *rp, *orp; 5296 5297 recallp->nfsrecly_recalltype = recalltype; 5298 recallp->nfsrecly_iomode = iomode; 5299 recallp->nfsrecly_stateseqid = stateseqid; 5300 recallp->nfsrecly_off = off; 5301 recallp->nfsrecly_len = len; 5302 recallp->nfsrecly_stat = stat; 5303 recallp->nfsrecly_op = op; 5304 if (devid != NULL) 5305 NFSBCOPY(devid, recallp->nfsrecly_devid, NFSX_V4DEVICEID); 5306 /* 5307 * Order the list as file returns first, followed by fsid and any 5308 * returns, both in increasing stateseqid order. 5309 * Note that the seqids wrap around, so 1 is after 0xffffffff. 5310 * (I'm not sure this is correct because I find RFC5661 confusing 5311 * on this, but hopefully it will work ok.) 5312 */ 5313 orp = NULL; 5314 LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) { 5315 orp = rp; 5316 if ((recalltype == NFSLAYOUTRETURN_FILE && 5317 (rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE || 5318 nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) || 5319 (recalltype != NFSLAYOUTRETURN_FILE && 5320 rp->nfsrecly_recalltype != NFSLAYOUTRETURN_FILE && 5321 nfscl_seq(stateseqid, rp->nfsrecly_stateseqid) != 0)) { 5322 LIST_INSERT_BEFORE(rp, recallp, nfsrecly_list); 5323 break; 5324 } 5325 5326 /* 5327 * Put any error return on all the file returns that will 5328 * preceed this one. 5329 */ 5330 if (rp->nfsrecly_recalltype == NFSLAYOUTRETURN_FILE && 5331 stat != 0 && rp->nfsrecly_stat == 0) { 5332 rp->nfsrecly_stat = stat; 5333 rp->nfsrecly_op = op; 5334 if (devid != NULL) 5335 NFSBCOPY(devid, rp->nfsrecly_devid, 5336 NFSX_V4DEVICEID); 5337 } 5338 } 5339 if (rp == NULL) { 5340 if (orp == NULL) 5341 LIST_INSERT_HEAD(&lyp->nfsly_recall, recallp, 5342 nfsrecly_list); 5343 else 5344 LIST_INSERT_AFTER(orp, recallp, nfsrecly_list); 5345 } 5346 lyp->nfsly_flags |= NFSLY_RECALL; 5347 wakeup(lyp->nfsly_clp); 5348 return (0); 5349 } 5350 5351 /* 5352 * Compare the two seqids for ordering. The trick is that the seqids can 5353 * wrap around from 0xffffffff->0, so check for the cases where one 5354 * has wrapped around. 5355 * Return 1 if seqid1 comes before seqid2, 0 otherwise. 5356 */ 5357 static int 5358 nfscl_seq(uint32_t seqid1, uint32_t seqid2) 5359 { 5360 5361 if (seqid2 > seqid1 && (seqid2 - seqid1) >= 0x7fffffff) 5362 /* seqid2 has wrapped around. */ 5363 return (0); 5364 if (seqid1 > seqid2 && (seqid1 - seqid2) >= 0x7fffffff) 5365 /* seqid1 has wrapped around. */ 5366 return (1); 5367 if (seqid1 <= seqid2) 5368 return (1); 5369 return (0); 5370 } 5371 5372 /* 5373 * Do a layout return for each of the recalls. 5374 */ 5375 static void 5376 nfscl_layoutreturn(struct nfsmount *nmp, struct nfscllayout *lyp, 5377 struct ucred *cred, NFSPROC_T *p) 5378 { 5379 struct nfsclrecalllayout *rp; 5380 nfsv4stateid_t stateid; 5381 int layouttype; 5382 5383 NFSBCOPY(lyp->nfsly_stateid.other, stateid.other, NFSX_STATEIDOTHER); 5384 stateid.seqid = lyp->nfsly_stateid.seqid; 5385 if ((lyp->nfsly_flags & NFSLY_FILES) != 0) 5386 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5387 else 5388 layouttype = NFSLAYOUT_FLEXFILE; 5389 LIST_FOREACH(rp, &lyp->nfsly_recall, nfsrecly_list) { 5390 (void)nfsrpc_layoutreturn(nmp, lyp->nfsly_fh, 5391 lyp->nfsly_fhlen, 0, layouttype, 5392 rp->nfsrecly_iomode, rp->nfsrecly_recalltype, 5393 rp->nfsrecly_off, rp->nfsrecly_len, 5394 &stateid, cred, p, rp->nfsrecly_stat, rp->nfsrecly_op, 5395 rp->nfsrecly_devid); 5396 } 5397 } 5398 5399 /* 5400 * Do the layout commit for a file layout. 5401 */ 5402 static void 5403 nfscl_dolayoutcommit(struct nfsmount *nmp, struct nfscllayout *lyp, 5404 struct ucred *cred, NFSPROC_T *p) 5405 { 5406 struct nfsclflayout *flp; 5407 uint64_t len; 5408 int error, layouttype; 5409 5410 if ((lyp->nfsly_flags & NFSLY_FILES) != 0) 5411 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5412 else 5413 layouttype = NFSLAYOUT_FLEXFILE; 5414 LIST_FOREACH(flp, &lyp->nfsly_flayrw, nfsfl_list) { 5415 if (layouttype == NFSLAYOUT_FLEXFILE && 5416 (flp->nfsfl_fflags & NFSFLEXFLAG_NO_LAYOUTCOMMIT) != 0) { 5417 NFSCL_DEBUG(4, "Flex file: no layoutcommit\n"); 5418 /* If not supported, don't bother doing it. */ 5419 NFSLOCKMNT(nmp); 5420 nmp->nm_state |= NFSSTA_NOLAYOUTCOMMIT; 5421 NFSUNLOCKMNT(nmp); 5422 break; 5423 } else if (flp->nfsfl_off <= lyp->nfsly_lastbyte) { 5424 len = flp->nfsfl_end - flp->nfsfl_off; 5425 error = nfsrpc_layoutcommit(nmp, lyp->nfsly_fh, 5426 lyp->nfsly_fhlen, 0, flp->nfsfl_off, len, 5427 lyp->nfsly_lastbyte, &lyp->nfsly_stateid, 5428 layouttype, cred, p, NULL); 5429 NFSCL_DEBUG(4, "layoutcommit err=%d\n", error); 5430 if (error == NFSERR_NOTSUPP) { 5431 /* If not supported, don't bother doing it. */ 5432 NFSLOCKMNT(nmp); 5433 nmp->nm_state |= NFSSTA_NOLAYOUTCOMMIT; 5434 NFSUNLOCKMNT(nmp); 5435 break; 5436 } 5437 } 5438 } 5439 } 5440 5441 /* 5442 * Commit all layouts for a file (vnode). 5443 */ 5444 int 5445 nfscl_layoutcommit(vnode_t vp, NFSPROC_T *p) 5446 { 5447 struct nfsclclient *clp; 5448 struct nfscllayout *lyp; 5449 struct nfsnode *np = VTONFS(vp); 5450 mount_t mp; 5451 struct nfsmount *nmp; 5452 5453 mp = vnode_mount(vp); 5454 nmp = VFSTONFS(mp); 5455 if (NFSHASNOLAYOUTCOMMIT(nmp)) 5456 return (0); 5457 NFSLOCKCLSTATE(); 5458 clp = nmp->nm_clp; 5459 if (clp == NULL) { 5460 NFSUNLOCKCLSTATE(); 5461 return (EPERM); 5462 } 5463 lyp = nfscl_findlayout(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); 5464 if (lyp == NULL) { 5465 NFSUNLOCKCLSTATE(); 5466 return (EPERM); 5467 } 5468 nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp); 5469 if (NFSCL_FORCEDISM(mp)) { 5470 NFSUNLOCKCLSTATE(); 5471 return (EPERM); 5472 } 5473 tryagain: 5474 if ((lyp->nfsly_flags & NFSLY_WRITTEN) != 0) { 5475 lyp->nfsly_flags &= ~NFSLY_WRITTEN; 5476 NFSUNLOCKCLSTATE(); 5477 NFSCL_DEBUG(4, "do layoutcommit2\n"); 5478 nfscl_dolayoutcommit(clp->nfsc_nmp, lyp, NFSPROCCRED(p), p); 5479 NFSLOCKCLSTATE(); 5480 goto tryagain; 5481 } 5482 nfsv4_relref(&lyp->nfsly_lock); 5483 NFSUNLOCKCLSTATE(); 5484 return (0); 5485 } 5486 5487