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