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