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