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