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