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