1/* $NetBSD: nfs_nfsdstate.c,v 1.5 2023/05/28 08:21:24 andvar Exp $ */ 2/*- 3 * Copyright (c) 2009 Rick Macklem, University of Guelph 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29#include <sys/cdefs.h> 30/* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdstate.c 307694 2016-10-20 23:53:16Z rmacklem "); */ 31__RCSID("$NetBSD: nfs_nfsdstate.c,v 1.5 2023/05/28 08:21:24 andvar Exp $"); 32 33#ifndef APPLEKEXT 34#include <fs/nfs/common/nfsport.h> 35 36struct nfsrv_stablefirst nfsrv_stablefirst; 37int nfsrv_issuedelegs = 0; 38int nfsrv_dolocallocks = 0; 39struct nfsv4lock nfsv4rootfs_lock; 40 41extern int newnfs_numnfsd; 42extern struct nfsstatsv1 nfsstatsv1; 43extern int nfsrv_lease; 44extern struct timeval nfsboottime; 45extern u_int32_t newnfs_true, newnfs_false; 46NFSV4ROOTLOCKMUTEX; 47NFSSTATESPINLOCK; 48 49SYSCTL_DECL(_vfs_nfsd); 50int nfsrv_statehashsize = NFSSTATEHASHSIZE; 51SYSCTL_INT(_vfs_nfsd, OID_AUTO, statehashsize, CTLFLAG_RDTUN, 52 &nfsrv_statehashsize, 0, 53 "Size of state hash table set via loader.conf"); 54 55int nfsrv_clienthashsize = NFSCLIENTHASHSIZE; 56SYSCTL_INT(_vfs_nfsd, OID_AUTO, clienthashsize, CTLFLAG_RDTUN, 57 &nfsrv_clienthashsize, 0, 58 "Size of client hash table set via loader.conf"); 59 60int nfsrv_lockhashsize = NFSLOCKHASHSIZE; 61SYSCTL_INT(_vfs_nfsd, OID_AUTO, fhhashsize, CTLFLAG_RDTUN, 62 &nfsrv_lockhashsize, 0, 63 "Size of file handle hash table set via loader.conf"); 64 65int nfsrv_sessionhashsize = NFSSESSIONHASHSIZE; 66SYSCTL_INT(_vfs_nfsd, OID_AUTO, sessionhashsize, CTLFLAG_RDTUN, 67 &nfsrv_sessionhashsize, 0, 68 "Size of session hash table set via loader.conf"); 69 70static int nfsrv_v4statelimit = NFSRV_V4STATELIMIT; 71SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN, 72 &nfsrv_v4statelimit, 0, 73 "High water limit for NFSv4 opens+locks+delegations"); 74 75static int nfsrv_writedelegifpos = 0; 76SYSCTL_INT(_vfs_nfsd, OID_AUTO, writedelegifpos, CTLFLAG_RW, 77 &nfsrv_writedelegifpos, 0, 78 "Issue a write delegation for read opens if possible"); 79 80/* 81 * Hash lists for nfs V4. 82 */ 83struct nfsclienthashhead *nfsclienthash; 84struct nfslockhashhead *nfslockhash; 85struct nfssessionhash *nfssessionhash; 86#endif /* !APPLEKEXT */ 87 88static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; 89static time_t nfsrvboottime; 90static int nfsrv_returnoldstateid = 0, nfsrv_clients = 0; 91static int nfsrv_clienthighwater = NFSRV_CLIENTHIGHWATER; 92static int nfsrv_nogsscallback = 0; 93 94/* local functions */ 95static void nfsrv_dumpaclient(struct nfsclient *clp, 96 struct nfsd_dumpclients *dumpp); 97static void nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, 98 NFSPROC_T *p); 99static int nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, 100 NFSPROC_T *p); 101static void nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 102 NFSPROC_T *p); 103static void nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, 104 int cansleep, NFSPROC_T *p); 105static void nfsrv_freenfslock(struct nfslock *lop); 106static void nfsrv_freenfslockfile(struct nfslockfile *lfp); 107static void nfsrv_freedeleg(struct nfsstate *); 108static int nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, 109 u_int32_t flags, struct nfsstate **stpp); 110static void nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 111 struct nfsstate **stpp); 112static int nfsrv_getlockfh(vnode_t vp, u_short flags, 113 struct nfslockfile *new_lfp, fhandle_t *nfhp, NFSPROC_T *p); 114static int nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 115 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit); 116static void nfsrv_insertlock(struct nfslock *new_lop, 117 struct nfslock *insert_lop, struct nfsstate *stp, struct nfslockfile *lfp); 118static void nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 119 struct nfslock **other_lopp, struct nfslockfile *lfp); 120static int nfsrv_getipnumber(u_char *cp); 121static int nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 122 nfsv4stateid_t *stateidp, int specialid); 123static int nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp, 124 u_int32_t flags); 125static int nfsrv_docallback(struct nfsclient *clp, int procnum, 126 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, 127 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p); 128static int nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp, 129 uint32_t callback, int op, const char *optag, struct nfsdsession **sepp); 130static u_int32_t nfsrv_nextclientindex(void); 131static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp); 132static void nfsrv_markstable(struct nfsclient *clp); 133static int nfsrv_checkstable(struct nfsclient *clp); 134static int nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, struct 135 vnode *vp, NFSPROC_T *p); 136static int nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, 137 NFSPROC_T *p, vnode_t vp); 138static int nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 139 struct nfsclient *clp, int *haslockp, NFSPROC_T *p); 140static int nfsrv_notsamecredname(struct nfsrv_descript *nd, 141 struct nfsclient *clp); 142static time_t nfsrv_leaseexpiry(void); 143static void nfsrv_delaydelegtimeout(struct nfsstate *stp); 144static int nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 145 struct nfsstate *stp, struct nfsrvcache *op); 146static int nfsrv_nootherstate(struct nfsstate *stp); 147static int nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 148 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p); 149static void nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, 150 uint64_t init_first, uint64_t init_end, NFSPROC_T *p); 151static int nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, 152 int oldflags, uint64_t first, uint64_t end, struct nfslockconflict *cfp, 153 NFSPROC_T *p); 154static void nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, 155 NFSPROC_T *p); 156static void nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, 157 uint64_t first, uint64_t end); 158static void nfsrv_locklf(struct nfslockfile *lfp); 159static void nfsrv_unlocklf(struct nfslockfile *lfp); 160static struct nfsdsession *nfsrv_findsession(uint8_t *sessionid); 161static int nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid); 162static int nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp, 163 int dont_replycache, struct nfsdsession **sepp); 164static int nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp); 165 166/* 167 * Scan the client list for a match and either return the current one, 168 * create a new entry or return an error. 169 * If returning a non-error, the clp structure must either be linked into 170 * the client list or free'd. 171 */ 172APPLESTATIC int 173nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, 174 nfsquad_t *clientidp, nfsquad_t *confirmp, NFSPROC_T *p) 175{ 176 struct nfsclient *clp = NULL, *new_clp = *new_clpp; 177 int i, error = 0; 178 struct nfsstate *stp, *tstp; 179 struct sockaddr_in *sad, *rad; 180 int zapit = 0, gotit, hasstate = 0, igotlock; 181 static u_int64_t confirm_index = 0; 182 183 /* 184 * Check for state resource limit exceeded. 185 */ 186 if (nfsrv_openpluslock > nfsrv_v4statelimit) { 187 error = NFSERR_RESOURCE; 188 goto out; 189 } 190 191 if (nfsrv_issuedelegs == 0 || 192 ((nd->nd_flag & ND_GSS) != 0 && nfsrv_nogsscallback != 0)) 193 /* 194 * Don't do callbacks when delegations are disabled or 195 * for AUTH_GSS unless enabled via nfsrv_nogsscallback. 196 * If establishing a callback connection is attempted 197 * when a firewall is blocking the callback path, the 198 * server may wait too long for the connect attempt to 199 * succeed during the Open. Some clients, such as Linux, 200 * may timeout and give up on the Open before the server 201 * replies. Also, since AUTH_GSS callbacks are not 202 * yet interoperability tested, they might cause the 203 * server to crap out, if they get past the Init call to 204 * the client. 205 */ 206 new_clp->lc_program = 0; 207 208 /* Lock out other nfsd threads */ 209 NFSLOCKV4ROOTMUTEX(); 210 nfsv4_relref(&nfsv4rootfs_lock); 211 do { 212 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 213 NFSV4ROOTLOCKMUTEXPTR, NULL); 214 } while (!igotlock); 215 NFSUNLOCKV4ROOTMUTEX(); 216 217 /* 218 * Search for a match in the client list. 219 */ 220 gotit = i = 0; 221 while (i < nfsrv_clienthashsize && !gotit) { 222 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 223 if (new_clp->lc_idlen == clp->lc_idlen && 224 !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { 225 gotit = 1; 226 break; 227 } 228 } 229 if (gotit == 0) 230 i++; 231 } 232 if (!gotit || 233 (clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) { 234 if ((nd->nd_flag & ND_NFSV41) != 0 && confirmp->lval[1] != 0) { 235 /* 236 * For NFSv4.1, if confirmp->lval[1] is non-zero, the 237 * client is trying to update a confirmed clientid. 238 */ 239 NFSLOCKV4ROOTMUTEX(); 240 nfsv4_unlock(&nfsv4rootfs_lock, 1); 241 NFSUNLOCKV4ROOTMUTEX(); 242 confirmp->lval[1] = 0; 243 error = NFSERR_NOENT; 244 goto out; 245 } 246 /* 247 * Get rid of the old one. 248 */ 249 if (i != nfsrv_clienthashsize) { 250 LIST_REMOVE(clp, lc_hash); 251 nfsrv_cleanclient(clp, p); 252 nfsrv_freedeleglist(&clp->lc_deleg); 253 nfsrv_freedeleglist(&clp->lc_olddeleg); 254 zapit = 1; 255 } 256 /* 257 * Add it after assigning a client id to it. 258 */ 259 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 260 if ((nd->nd_flag & ND_NFSV41) != 0) 261 new_clp->lc_confirm.lval[0] = confirmp->lval[0] = 262 ++confirm_index; 263 else 264 confirmp->qval = new_clp->lc_confirm.qval = 265 ++confirm_index; 266 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 267 (u_int32_t)nfsrvboottime; 268 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 269 nfsrv_nextclientindex(); 270 new_clp->lc_stateindex = 0; 271 new_clp->lc_statemaxindex = 0; 272 new_clp->lc_cbref = 0; 273 new_clp->lc_expiry = nfsrv_leaseexpiry(); 274 LIST_INIT(&new_clp->lc_open); 275 LIST_INIT(&new_clp->lc_deleg); 276 LIST_INIT(&new_clp->lc_olddeleg); 277 LIST_INIT(&new_clp->lc_session); 278 for (i = 0; i < nfsrv_statehashsize; i++) 279 LIST_INIT(&new_clp->lc_stateid[i]); 280 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 281 lc_hash); 282 nfsstatsv1.srvclients++; 283 nfsrv_openpluslock++; 284 nfsrv_clients++; 285 NFSLOCKV4ROOTMUTEX(); 286 nfsv4_unlock(&nfsv4rootfs_lock, 1); 287 NFSUNLOCKV4ROOTMUTEX(); 288 if (zapit) 289 nfsrv_zapclient(clp, p); 290 *new_clpp = NULL; 291 goto out; 292 } 293 294 /* 295 * Now, handle the cases where the id is already issued. 296 */ 297 if (nfsrv_notsamecredname(nd, clp)) { 298 /* 299 * Check to see if there is expired state that should go away. 300 */ 301 if (clp->lc_expiry < NFSD_MONOSEC && 302 (!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) { 303 nfsrv_cleanclient(clp, p); 304 nfsrv_freedeleglist(&clp->lc_deleg); 305 } 306 307 /* 308 * If there is outstanding state, then reply NFSERR_CLIDINUSE per 309 * RFC3530 Sec. 8.1.2 last para. 310 */ 311 if (!LIST_EMPTY(&clp->lc_deleg)) { 312 hasstate = 1; 313 } else if (LIST_EMPTY(&clp->lc_open)) { 314 hasstate = 0; 315 } else { 316 hasstate = 0; 317 /* Look for an Open on the OpenOwner */ 318 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 319 if (!LIST_EMPTY(&stp->ls_open)) { 320 hasstate = 1; 321 break; 322 } 323 } 324 } 325 if (hasstate) { 326 /* 327 * If the uid doesn't match, return NFSERR_CLIDINUSE after 328 * filling out the correct ipaddr and portnum. 329 */ 330 sad = NFSSOCKADDR(new_clp->lc_req.nr_nam, struct sockaddr_in *); 331 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 332 sad->sin_addr.s_addr = rad->sin_addr.s_addr; 333 sad->sin_port = rad->sin_port; 334 NFSLOCKV4ROOTMUTEX(); 335 nfsv4_unlock(&nfsv4rootfs_lock, 1); 336 NFSUNLOCKV4ROOTMUTEX(); 337 error = NFSERR_CLIDINUSE; 338 goto out; 339 } 340 } 341 342 if (NFSBCMP(new_clp->lc_verf, clp->lc_verf, NFSX_VERF)) { 343 /* 344 * If the verifier has changed, the client has rebooted 345 * and a new client id is issued. The old state info 346 * can be thrown away once the SETCLIENTID_CONFIRM occurs. 347 */ 348 LIST_REMOVE(clp, lc_hash); 349 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 350 if ((nd->nd_flag & ND_NFSV41) != 0) 351 new_clp->lc_confirm.lval[0] = confirmp->lval[0] = 352 ++confirm_index; 353 else 354 confirmp->qval = new_clp->lc_confirm.qval = 355 ++confirm_index; 356 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 357 nfsrvboottime; 358 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 359 nfsrv_nextclientindex(); 360 new_clp->lc_stateindex = 0; 361 new_clp->lc_statemaxindex = 0; 362 new_clp->lc_cbref = 0; 363 new_clp->lc_expiry = nfsrv_leaseexpiry(); 364 365 /* 366 * Save the state until confirmed. 367 */ 368 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 369 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 370 tstp->ls_clp = new_clp; 371 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 372 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 373 tstp->ls_clp = new_clp; 374 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, 375 ls_list); 376 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 377 tstp->ls_clp = new_clp; 378 for (i = 0; i < nfsrv_statehashsize; i++) { 379 LIST_NEWHEAD(&new_clp->lc_stateid[i], 380 &clp->lc_stateid[i], ls_hash); 381 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) 382 tstp->ls_clp = new_clp; 383 } 384 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 385 lc_hash); 386 nfsstatsv1.srvclients++; 387 nfsrv_openpluslock++; 388 nfsrv_clients++; 389 NFSLOCKV4ROOTMUTEX(); 390 nfsv4_unlock(&nfsv4rootfs_lock, 1); 391 NFSUNLOCKV4ROOTMUTEX(); 392 393 /* 394 * Must wait until any outstanding callback on the old clp 395 * completes. 396 */ 397 NFSLOCKSTATE(); 398 while (clp->lc_cbref) { 399 clp->lc_flags |= LCL_WAKEUPWANTED; 400 (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1, 401 "nfsd clp", 10 * hz); 402 } 403 NFSUNLOCKSTATE(); 404 nfsrv_zapclient(clp, p); 405 *new_clpp = NULL; 406 goto out; 407 } 408 409 /* For NFSv4.1, mark that we found a confirmed clientid. */ 410 if ((nd->nd_flag & ND_NFSV41) != 0) { 411 clientidp->lval[0] = clp->lc_clientid.lval[0]; 412 clientidp->lval[1] = clp->lc_clientid.lval[1]; 413 confirmp->lval[0] = 0; /* Ignored by client */ 414 confirmp->lval[1] = 1; 415 } else { 416 /* 417 * id and verifier match, so update the net address info 418 * and get rid of any existing callback authentication 419 * handle, so a new one will be acquired. 420 */ 421 LIST_REMOVE(clp, lc_hash); 422 new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN); 423 new_clp->lc_expiry = nfsrv_leaseexpiry(); 424 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 425 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 426 clp->lc_clientid.lval[0]; 427 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 428 clp->lc_clientid.lval[1]; 429 new_clp->lc_delegtime = clp->lc_delegtime; 430 new_clp->lc_stateindex = clp->lc_stateindex; 431 new_clp->lc_statemaxindex = clp->lc_statemaxindex; 432 new_clp->lc_cbref = 0; 433 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 434 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 435 tstp->ls_clp = new_clp; 436 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 437 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 438 tstp->ls_clp = new_clp; 439 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); 440 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 441 tstp->ls_clp = new_clp; 442 for (i = 0; i < nfsrv_statehashsize; i++) { 443 LIST_NEWHEAD(&new_clp->lc_stateid[i], 444 &clp->lc_stateid[i], ls_hash); 445 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) 446 tstp->ls_clp = new_clp; 447 } 448 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 449 lc_hash); 450 nfsstatsv1.srvclients++; 451 nfsrv_openpluslock++; 452 nfsrv_clients++; 453 } 454 NFSLOCKV4ROOTMUTEX(); 455 nfsv4_unlock(&nfsv4rootfs_lock, 1); 456 NFSUNLOCKV4ROOTMUTEX(); 457 458 if ((nd->nd_flag & ND_NFSV41) == 0) { 459 /* 460 * Must wait until any outstanding callback on the old clp 461 * completes. 462 */ 463 NFSLOCKSTATE(); 464 while (clp->lc_cbref) { 465 clp->lc_flags |= LCL_WAKEUPWANTED; 466 (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1, 467 "nfsdclp", 10 * hz); 468 } 469 NFSUNLOCKSTATE(); 470 nfsrv_zapclient(clp, p); 471 *new_clpp = NULL; 472 } 473 474out: 475 NFSEXITCODE2(error, nd); 476 return (error); 477} 478 479/* 480 * Check to see if the client id exists and optionally confirm it. 481 */ 482APPLESTATIC int 483nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, 484 struct nfsdsession *nsep, nfsquad_t confirm, uint32_t cbprogram, 485 struct nfsrv_descript *nd, NFSPROC_T *p) 486{ 487 struct nfsclient *clp; 488 struct nfsstate *stp; 489 int i; 490 struct nfsclienthashhead *hp; 491 int error = 0, igotlock, doneok; 492 struct nfssessionhash *shp; 493 struct nfsdsession *sep; 494 uint64_t sessid[2]; 495 static uint64_t next_sess = 0; 496 497 if (clpp) 498 *clpp = NULL; 499 if ((nd == NULL || (nd->nd_flag & ND_NFSV41) == 0 || 500 opflags != CLOPS_RENEW) && nfsrvboottime != clientid.lval[0]) { 501 error = NFSERR_STALECLIENTID; 502 goto out; 503 } 504 505 /* 506 * If called with opflags == CLOPS_RENEW, the State Lock is 507 * already held. Otherwise, we need to get either that or, 508 * for the case of Confirm, lock out the nfsd threads. 509 */ 510 if (opflags & CLOPS_CONFIRM) { 511 NFSLOCKV4ROOTMUTEX(); 512 nfsv4_relref(&nfsv4rootfs_lock); 513 do { 514 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 515 NFSV4ROOTLOCKMUTEXPTR, NULL); 516 } while (!igotlock); 517 /* 518 * Create a new sessionid here, since we need to do it where 519 * there is a mutex held to serialize update of next_sess. 520 */ 521 if ((nd->nd_flag & ND_NFSV41) != 0) { 522 sessid[0] = ++next_sess; 523 sessid[1] = clientid.qval; 524 } 525 NFSUNLOCKV4ROOTMUTEX(); 526 } else if (opflags != CLOPS_RENEW) { 527 NFSLOCKSTATE(); 528 } 529 530 /* For NFSv4.1, the clp is acquired from the associated session. */ 531 if (nd != NULL && (nd->nd_flag & ND_NFSV41) != 0 && 532 opflags == CLOPS_RENEW) { 533 clp = NULL; 534 if ((nd->nd_flag & ND_HASSEQUENCE) != 0) { 535 shp = NFSSESSIONHASH(nd->nd_sessionid); 536 NFSLOCKSESSION(shp); 537 sep = nfsrv_findsession(nd->nd_sessionid); 538 if (sep != NULL) 539 clp = sep->sess_clp; 540 NFSUNLOCKSESSION(shp); 541 } 542 } else { 543 hp = NFSCLIENTHASH(clientid); 544 LIST_FOREACH(clp, hp, lc_hash) { 545 if (clp->lc_clientid.lval[1] == clientid.lval[1]) 546 break; 547 } 548 } 549 if (clp == NULL) { 550 if (opflags & CLOPS_CONFIRM) 551 error = NFSERR_STALECLIENTID; 552 else 553 error = NFSERR_EXPIRED; 554 } else if (clp->lc_flags & LCL_ADMINREVOKED) { 555 /* 556 * If marked admin revoked, just return the error. 557 */ 558 error = NFSERR_ADMINREVOKED; 559 } 560 if (error) { 561 if (opflags & CLOPS_CONFIRM) { 562 NFSLOCKV4ROOTMUTEX(); 563 nfsv4_unlock(&nfsv4rootfs_lock, 1); 564 NFSUNLOCKV4ROOTMUTEX(); 565 } else if (opflags != CLOPS_RENEW) { 566 NFSUNLOCKSTATE(); 567 } 568 goto out; 569 } 570 571 /* 572 * Perform any operations specified by the opflags. 573 */ 574 if (opflags & CLOPS_CONFIRM) { 575 if (((nd->nd_flag & ND_NFSV41) != 0 && 576 clp->lc_confirm.lval[0] != confirm.lval[0]) || 577 ((nd->nd_flag & ND_NFSV41) == 0 && 578 clp->lc_confirm.qval != confirm.qval)) 579 error = NFSERR_STALECLIENTID; 580 else if (nfsrv_notsamecredname(nd, clp)) 581 error = NFSERR_CLIDINUSE; 582 583 if (!error) { 584 if ((clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_DONTCLEAN)) == 585 LCL_NEEDSCONFIRM) { 586 /* 587 * Hang onto the delegations (as old delegations) 588 * for an Open with CLAIM_DELEGATE_PREV unless in 589 * grace, but get rid of the rest of the state. 590 */ 591 nfsrv_cleanclient(clp, p); 592 nfsrv_freedeleglist(&clp->lc_olddeleg); 593 if (nfsrv_checkgrace(nd, clp, 0)) { 594 /* In grace, so just delete delegations */ 595 nfsrv_freedeleglist(&clp->lc_deleg); 596 } else { 597 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) 598 stp->ls_flags |= NFSLCK_OLDDELEG; 599 clp->lc_delegtime = NFSD_MONOSEC + 600 nfsrv_lease + NFSRV_LEASEDELTA; 601 LIST_NEWHEAD(&clp->lc_olddeleg, &clp->lc_deleg, 602 ls_list); 603 } 604 if ((nd->nd_flag & ND_NFSV41) != 0) 605 clp->lc_program = cbprogram; 606 } 607 clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN); 608 if (clp->lc_program) 609 clp->lc_flags |= LCL_NEEDSCBNULL; 610 /* For NFSv4.1, link the session onto the client. */ 611 if (nsep != NULL) { 612 /* Hold a reference on the xprt for a backchannel. */ 613 if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) 614 != 0 && clp->lc_req.nr_client == NULL) { 615 clp->lc_req.nr_client = (struct __rpc_client *) 616 clnt_bck_create(nd->nd_xprt->xp_socket, 617 cbprogram, NFSV4_CBVERS); 618 if (clp->lc_req.nr_client != NULL) { 619 SVC_ACQUIRE(nd->nd_xprt); 620 nd->nd_xprt->xp_p2 = 621 clp->lc_req.nr_client->cl_private; 622 /* Disable idle timeout. */ 623 nd->nd_xprt->xp_idletimeout = 0; 624 nsep->sess_cbsess.nfsess_xprt = nd->nd_xprt; 625 } else 626 nsep->sess_crflags &= ~NFSV4CRSESS_CONNBACKCHAN; 627 } 628 NFSBCOPY(sessid, nsep->sess_sessionid, 629 NFSX_V4SESSIONID); 630 NFSBCOPY(sessid, nsep->sess_cbsess.nfsess_sessionid, 631 NFSX_V4SESSIONID); 632 shp = NFSSESSIONHASH(nsep->sess_sessionid); 633 NFSLOCKSTATE(); 634 NFSLOCKSESSION(shp); 635 LIST_INSERT_HEAD(&shp->list, nsep, sess_hash); 636 LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list); 637 nsep->sess_clp = clp; 638 NFSUNLOCKSESSION(shp); 639 NFSUNLOCKSTATE(); 640 } 641 } 642 } else if (clp->lc_flags & LCL_NEEDSCONFIRM) { 643 error = NFSERR_EXPIRED; 644 } 645 646 /* 647 * If called by the Renew Op, we must check the principal. 648 */ 649 if (!error && (opflags & CLOPS_RENEWOP)) { 650 if (nfsrv_notsamecredname(nd, clp)) { 651 doneok = 0; 652 for (i = 0; i < nfsrv_statehashsize && doneok == 0; i++) { 653 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 654 if ((stp->ls_flags & NFSLCK_OPEN) && 655 stp->ls_uid == nd->nd_cred->cr_uid) { 656 doneok = 1; 657 break; 658 } 659 } 660 } 661 if (!doneok) 662 error = NFSERR_ACCES; 663 } 664 if (!error && (clp->lc_flags & LCL_CBDOWN)) 665 error = NFSERR_CBPATHDOWN; 666 } 667 if ((!error || error == NFSERR_CBPATHDOWN) && 668 (opflags & CLOPS_RENEW)) { 669 clp->lc_expiry = nfsrv_leaseexpiry(); 670 } 671 if (opflags & CLOPS_CONFIRM) { 672 NFSLOCKV4ROOTMUTEX(); 673 nfsv4_unlock(&nfsv4rootfs_lock, 1); 674 NFSUNLOCKV4ROOTMUTEX(); 675 } else if (opflags != CLOPS_RENEW) { 676 NFSUNLOCKSTATE(); 677 } 678 if (clpp) 679 *clpp = clp; 680 681out: 682 NFSEXITCODE2(error, nd); 683 return (error); 684} 685 686/* 687 * Perform the NFSv4.1 destroy clientid. 688 */ 689int 690nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p) 691{ 692 struct nfsclient *clp; 693 struct nfsclienthashhead *hp; 694 int error = 0, i, igotlock; 695 696 if (nfsrvboottime != clientid.lval[0]) { 697 error = NFSERR_STALECLIENTID; 698 goto out; 699 } 700 701 /* Lock out other nfsd threads */ 702 NFSLOCKV4ROOTMUTEX(); 703 nfsv4_relref(&nfsv4rootfs_lock); 704 do { 705 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 706 NFSV4ROOTLOCKMUTEXPTR, NULL); 707 } while (igotlock == 0); 708 NFSUNLOCKV4ROOTMUTEX(); 709 710 hp = NFSCLIENTHASH(clientid); 711 LIST_FOREACH(clp, hp, lc_hash) { 712 if (clp->lc_clientid.lval[1] == clientid.lval[1]) 713 break; 714 } 715 if (clp == NULL) { 716 NFSLOCKV4ROOTMUTEX(); 717 nfsv4_unlock(&nfsv4rootfs_lock, 1); 718 NFSUNLOCKV4ROOTMUTEX(); 719 /* Just return ok, since it is gone. */ 720 goto out; 721 } 722 723 /* Scan for state on the clientid. */ 724 for (i = 0; i < nfsrv_statehashsize; i++) 725 if (!LIST_EMPTY(&clp->lc_stateid[i])) { 726 NFSLOCKV4ROOTMUTEX(); 727 nfsv4_unlock(&nfsv4rootfs_lock, 1); 728 NFSUNLOCKV4ROOTMUTEX(); 729 error = NFSERR_CLIENTIDBUSY; 730 goto out; 731 } 732 if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) { 733 NFSLOCKV4ROOTMUTEX(); 734 nfsv4_unlock(&nfsv4rootfs_lock, 1); 735 NFSUNLOCKV4ROOTMUTEX(); 736 error = NFSERR_CLIENTIDBUSY; 737 goto out; 738 } 739 740 /* Destroy the clientid and return ok. */ 741 nfsrv_cleanclient(clp, p); 742 nfsrv_freedeleglist(&clp->lc_deleg); 743 nfsrv_freedeleglist(&clp->lc_olddeleg); 744 LIST_REMOVE(clp, lc_hash); 745 NFSLOCKV4ROOTMUTEX(); 746 nfsv4_unlock(&nfsv4rootfs_lock, 1); 747 NFSUNLOCKV4ROOTMUTEX(); 748 nfsrv_zapclient(clp, p); 749out: 750 NFSEXITCODE2(error, nd); 751 return (error); 752} 753 754/* 755 * Called from the new nfssvc syscall to admin revoke a clientid. 756 * Returns 0 for success, error otherwise. 757 */ 758APPLESTATIC int 759nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p) 760{ 761 struct nfsclient *clp = NULL; 762 int i, error = 0; 763 int gotit, igotlock; 764 765 /* 766 * First, lock out the nfsd so that state won't change while the 767 * revocation record is being written to the stable storage restart 768 * file. 769 */ 770 NFSLOCKV4ROOTMUTEX(); 771 do { 772 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 773 NFSV4ROOTLOCKMUTEXPTR, NULL); 774 } while (!igotlock); 775 NFSUNLOCKV4ROOTMUTEX(); 776 777 /* 778 * Search for a match in the client list. 779 */ 780 gotit = i = 0; 781 while (i < nfsrv_clienthashsize && !gotit) { 782 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 783 if (revokep->nclid_idlen == clp->lc_idlen && 784 !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { 785 gotit = 1; 786 break; 787 } 788 } 789 i++; 790 } 791 if (!gotit) { 792 NFSLOCKV4ROOTMUTEX(); 793 nfsv4_unlock(&nfsv4rootfs_lock, 0); 794 NFSUNLOCKV4ROOTMUTEX(); 795 error = EPERM; 796 goto out; 797 } 798 799 /* 800 * Now, write out the revocation record 801 */ 802 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 803 nfsrv_backupstable(); 804 805 /* 806 * and clear out the state, marking the clientid revoked. 807 */ 808 clp->lc_flags &= ~LCL_CALLBACKSON; 809 clp->lc_flags |= LCL_ADMINREVOKED; 810 nfsrv_cleanclient(clp, p); 811 nfsrv_freedeleglist(&clp->lc_deleg); 812 nfsrv_freedeleglist(&clp->lc_olddeleg); 813 NFSLOCKV4ROOTMUTEX(); 814 nfsv4_unlock(&nfsv4rootfs_lock, 0); 815 NFSUNLOCKV4ROOTMUTEX(); 816 817out: 818 NFSEXITCODE(error); 819 return (error); 820} 821 822/* 823 * Dump out stats for all clients. Called from nfssvc(2), that is used 824 * nfsstatsv1. 825 */ 826APPLESTATIC void 827nfsrv_dumpclients(struct nfsd_dumpclients *dumpp, int maxcnt) 828{ 829 struct nfsclient *clp; 830 int i = 0, cnt = 0; 831 832 /* 833 * First, get a reference on the nfsv4rootfs_lock so that an 834 * exclusive lock cannot be acquired while dumping the clients. 835 */ 836 NFSLOCKV4ROOTMUTEX(); 837 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 838 NFSUNLOCKV4ROOTMUTEX(); 839 NFSLOCKSTATE(); 840 /* 841 * Rattle through the client lists until done. 842 */ 843 while (i < nfsrv_clienthashsize && cnt < maxcnt) { 844 clp = LIST_FIRST(&nfsclienthash[i]); 845 while (clp != NULL && cnt < maxcnt) { 846 nfsrv_dumpaclient(clp, &dumpp[cnt]); 847 cnt++; 848 clp = LIST_NEXT(clp, lc_hash); 849 } 850 i++; 851 } 852 if (cnt < maxcnt) 853 dumpp[cnt].ndcl_clid.nclid_idlen = 0; 854 NFSUNLOCKSTATE(); 855 NFSLOCKV4ROOTMUTEX(); 856 nfsv4_relref(&nfsv4rootfs_lock); 857 NFSUNLOCKV4ROOTMUTEX(); 858} 859 860/* 861 * Dump stats for a client. Must be called with the NFSSTATELOCK and spl'd. 862 */ 863static void 864nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_dumpclients *dumpp) 865{ 866 struct nfsstate *stp, *openstp, *lckownstp; 867 struct nfslock *lop; 868 struct sockaddr *sad; 869 struct sockaddr_in *rad; 870 struct sockaddr_in6 *rad6; 871 872 dumpp->ndcl_nopenowners = dumpp->ndcl_nlockowners = 0; 873 dumpp->ndcl_nopens = dumpp->ndcl_nlocks = 0; 874 dumpp->ndcl_ndelegs = dumpp->ndcl_nolddelegs = 0; 875 dumpp->ndcl_flags = clp->lc_flags; 876 dumpp->ndcl_clid.nclid_idlen = clp->lc_idlen; 877 NFSBCOPY(clp->lc_id, dumpp->ndcl_clid.nclid_id, clp->lc_idlen); 878 sad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr *); 879 dumpp->ndcl_addrfam = sad->sa_family; 880 if (sad->sa_family == AF_INET) { 881 rad = (struct sockaddr_in *)sad; 882 dumpp->ndcl_cbaddr.sin_addr = rad->sin_addr; 883 } else { 884 rad6 = (struct sockaddr_in6 *)sad; 885 dumpp->ndcl_cbaddr.sin6_addr = rad6->sin6_addr; 886 } 887 888 /* 889 * Now, scan the state lists and total up the opens and locks. 890 */ 891 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 892 dumpp->ndcl_nopenowners++; 893 LIST_FOREACH(openstp, &stp->ls_open, ls_list) { 894 dumpp->ndcl_nopens++; 895 LIST_FOREACH(lckownstp, &openstp->ls_open, ls_list) { 896 dumpp->ndcl_nlockowners++; 897 LIST_FOREACH(lop, &lckownstp->ls_lock, lo_lckowner) { 898 dumpp->ndcl_nlocks++; 899 } 900 } 901 } 902 } 903 904 /* 905 * and the delegation lists. 906 */ 907 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) { 908 dumpp->ndcl_ndelegs++; 909 } 910 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 911 dumpp->ndcl_nolddelegs++; 912 } 913} 914 915/* 916 * Dump out lock stats for a file. 917 */ 918APPLESTATIC void 919nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldumpp, int maxcnt, 920 NFSPROC_T *p) 921{ 922 struct nfsstate *stp; 923 struct nfslock *lop; 924 int cnt = 0; 925 struct nfslockfile *lfp; 926 struct sockaddr *sad; 927 struct sockaddr_in *rad; 928 struct sockaddr_in6 *rad6; 929 int ret; 930 fhandle_t nfh; 931 932 ret = nfsrv_getlockfh(vp, 0, NULL, &nfh, p); 933 /* 934 * First, get a reference on the nfsv4rootfs_lock so that an 935 * exclusive lock on it cannot be acquired while dumping the locks. 936 */ 937 NFSLOCKV4ROOTMUTEX(); 938 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 939 NFSUNLOCKV4ROOTMUTEX(); 940 NFSLOCKSTATE(); 941 if (!ret) 942 ret = nfsrv_getlockfile(0, NULL, &lfp, &nfh, 0); 943 if (ret) { 944 ldumpp[0].ndlck_clid.nclid_idlen = 0; 945 NFSUNLOCKSTATE(); 946 NFSLOCKV4ROOTMUTEX(); 947 nfsv4_relref(&nfsv4rootfs_lock); 948 NFSUNLOCKV4ROOTMUTEX(); 949 return; 950 } 951 952 /* 953 * For each open share on file, dump it out. 954 */ 955 stp = LIST_FIRST(&lfp->lf_open); 956 while (stp != NULL && cnt < maxcnt) { 957 ldumpp[cnt].ndlck_flags = stp->ls_flags; 958 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 959 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 960 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 961 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 962 ldumpp[cnt].ndlck_owner.nclid_idlen = 963 stp->ls_openowner->ls_ownerlen; 964 NFSBCOPY(stp->ls_openowner->ls_owner, 965 ldumpp[cnt].ndlck_owner.nclid_id, 966 stp->ls_openowner->ls_ownerlen); 967 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 968 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 969 stp->ls_clp->lc_idlen); 970 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 971 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 972 if (sad->sa_family == AF_INET) { 973 rad = (struct sockaddr_in *)sad; 974 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 975 } else { 976 rad6 = (struct sockaddr_in6 *)sad; 977 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 978 } 979 stp = LIST_NEXT(stp, ls_file); 980 cnt++; 981 } 982 983 /* 984 * and all locks. 985 */ 986 lop = LIST_FIRST(&lfp->lf_lock); 987 while (lop != NULL && cnt < maxcnt) { 988 stp = lop->lo_stp; 989 ldumpp[cnt].ndlck_flags = lop->lo_flags; 990 ldumpp[cnt].ndlck_first = lop->lo_first; 991 ldumpp[cnt].ndlck_end = lop->lo_end; 992 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 993 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 994 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 995 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 996 ldumpp[cnt].ndlck_owner.nclid_idlen = stp->ls_ownerlen; 997 NFSBCOPY(stp->ls_owner, ldumpp[cnt].ndlck_owner.nclid_id, 998 stp->ls_ownerlen); 999 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 1000 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 1001 stp->ls_clp->lc_idlen); 1002 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 1003 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 1004 if (sad->sa_family == AF_INET) { 1005 rad = (struct sockaddr_in *)sad; 1006 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 1007 } else { 1008 rad6 = (struct sockaddr_in6 *)sad; 1009 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 1010 } 1011 lop = LIST_NEXT(lop, lo_lckfile); 1012 cnt++; 1013 } 1014 1015 /* 1016 * and the delegations. 1017 */ 1018 stp = LIST_FIRST(&lfp->lf_deleg); 1019 while (stp != NULL && cnt < maxcnt) { 1020 ldumpp[cnt].ndlck_flags = stp->ls_flags; 1021 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 1022 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 1023 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 1024 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 1025 ldumpp[cnt].ndlck_owner.nclid_idlen = 0; 1026 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 1027 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 1028 stp->ls_clp->lc_idlen); 1029 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 1030 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 1031 if (sad->sa_family == AF_INET) { 1032 rad = (struct sockaddr_in *)sad; 1033 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 1034 } else { 1035 rad6 = (struct sockaddr_in6 *)sad; 1036 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 1037 } 1038 stp = LIST_NEXT(stp, ls_file); 1039 cnt++; 1040 } 1041 1042 /* 1043 * If list isn't full, mark end of list by setting the client name 1044 * to zero length. 1045 */ 1046 if (cnt < maxcnt) 1047 ldumpp[cnt].ndlck_clid.nclid_idlen = 0; 1048 NFSUNLOCKSTATE(); 1049 NFSLOCKV4ROOTMUTEX(); 1050 nfsv4_relref(&nfsv4rootfs_lock); 1051 NFSUNLOCKV4ROOTMUTEX(); 1052} 1053 1054/* 1055 * Server timer routine. It can scan any linked list, so long 1056 * as it holds the spin/mutex lock and there is no exclusive lock on 1057 * nfsv4rootfs_lock. 1058 * (For OpenBSD, a kthread is ok. For FreeBSD, I think it is ok 1059 * to do this from a callout, since the spin locks work. For 1060 * Darwin, I'm not sure what will work correctly yet.) 1061 * Should be called once per second. 1062 */ 1063APPLESTATIC void 1064nfsrv_servertimer(void) 1065{ 1066 struct nfsclient *clp, *nclp; 1067 struct nfsstate *stp, *nstp; 1068 int got_ref, i; 1069 1070 /* 1071 * Make sure nfsboottime is set. This is used by V3 as well 1072 * as V4. Note that nfsboottime is not nfsrvboottime, which is 1073 * only used by the V4 server for leases. 1074 */ 1075 if (nfsboottime.tv_sec == 0) 1076 NFSSETBOOTTIME(nfsboottime); 1077 1078 /* 1079 * If server hasn't started yet, just return. 1080 */ 1081 NFSLOCKSTATE(); 1082 if (nfsrv_stablefirst.nsf_eograce == 0) { 1083 NFSUNLOCKSTATE(); 1084 return; 1085 } 1086 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) { 1087 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) && 1088 NFSD_MONOSEC > nfsrv_stablefirst.nsf_eograce) 1089 nfsrv_stablefirst.nsf_flags |= 1090 (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 1091 NFSUNLOCKSTATE(); 1092 return; 1093 } 1094 1095 /* 1096 * Try and get a reference count on the nfsv4rootfs_lock so that 1097 * no nfsd thread can acquire an exclusive lock on it before this 1098 * call is done. If it is already exclusively locked, just return. 1099 */ 1100 NFSLOCKV4ROOTMUTEX(); 1101 got_ref = nfsv4_getref_nonblock(&nfsv4rootfs_lock); 1102 NFSUNLOCKV4ROOTMUTEX(); 1103 if (got_ref == 0) { 1104 NFSUNLOCKSTATE(); 1105 return; 1106 } 1107 1108 /* 1109 * For each client... 1110 */ 1111 for (i = 0; i < nfsrv_clienthashsize; i++) { 1112 clp = LIST_FIRST(&nfsclienthash[i]); 1113 while (clp != NULL) { 1114 nclp = LIST_NEXT(clp, lc_hash); 1115 if (!(clp->lc_flags & LCL_EXPIREIT)) { 1116 if (((clp->lc_expiry + NFSRV_STALELEASE) < NFSD_MONOSEC 1117 && ((LIST_EMPTY(&clp->lc_deleg) 1118 && LIST_EMPTY(&clp->lc_open)) || 1119 nfsrv_clients > nfsrv_clienthighwater)) || 1120 (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || 1121 (clp->lc_expiry < NFSD_MONOSEC && 1122 (nfsrv_openpluslock * 10 / 9) > nfsrv_v4statelimit)) { 1123 /* 1124 * Lease has expired several nfsrv_lease times ago: 1125 * PLUS 1126 * - no state is associated with it 1127 * OR 1128 * - above high water mark for number of clients 1129 * (nfsrv_clienthighwater should be large enough 1130 * that this only occurs when clients fail to 1131 * use the same nfs_client_id4.id. Maybe somewhat 1132 * higher that the maximum number of clients that 1133 * will mount this server?) 1134 * OR 1135 * Lease has expired a very long time ago 1136 * OR 1137 * Lease has expired PLUS the number of opens + locks 1138 * has exceeded 90% of capacity 1139 * 1140 * --> Mark for expiry. The actual expiry will be done 1141 * by an nfsd sometime soon. 1142 */ 1143 clp->lc_flags |= LCL_EXPIREIT; 1144 nfsrv_stablefirst.nsf_flags |= 1145 (NFSNSF_NEEDLOCK | NFSNSF_EXPIREDCLIENT); 1146 } else { 1147 /* 1148 * If there are no opens, increment no open tick cnt 1149 * If time exceeds NFSNOOPEN, mark it to be thrown away 1150 * otherwise, if there is an open, reset no open time 1151 * Hopefully, this will avoid excessive re-creation 1152 * of open owners and subsequent open confirms. 1153 */ 1154 stp = LIST_FIRST(&clp->lc_open); 1155 while (stp != NULL) { 1156 nstp = LIST_NEXT(stp, ls_list); 1157 if (LIST_EMPTY(&stp->ls_open)) { 1158 stp->ls_noopens++; 1159 if (stp->ls_noopens > NFSNOOPEN || 1160 (nfsrv_openpluslock * 2) > 1161 nfsrv_v4statelimit) 1162 nfsrv_stablefirst.nsf_flags |= 1163 NFSNSF_NOOPENS; 1164 } else { 1165 stp->ls_noopens = 0; 1166 } 1167 stp = nstp; 1168 } 1169 } 1170 } 1171 clp = nclp; 1172 } 1173 } 1174 NFSUNLOCKSTATE(); 1175 NFSLOCKV4ROOTMUTEX(); 1176 nfsv4_relref(&nfsv4rootfs_lock); 1177 NFSUNLOCKV4ROOTMUTEX(); 1178} 1179 1180/* 1181 * The following set of functions free up the various data structures. 1182 */ 1183/* 1184 * Clear out all open/lock state related to this nfsclient. 1185 * Caller must hold an exclusive lock on nfsv4rootfs_lock, so that 1186 * there are no other active nfsd threads. 1187 */ 1188APPLESTATIC void 1189nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p) 1190{ 1191 struct nfsstate *stp, *nstp; 1192 struct nfsdsession *sep, *nsep; 1193 1194 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) 1195 nfsrv_freeopenowner(stp, 1, p); 1196 if ((clp->lc_flags & LCL_ADMINREVOKED) == 0) 1197 LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep) 1198 (void)nfsrv_freesession(sep, NULL); 1199} 1200 1201/* 1202 * Free a client that has been cleaned. It should also already have been 1203 * removed from the lists. 1204 * (Just to be safe w.r.t. newnfs_disconnect(), call this function when 1205 * softclock interrupts are enabled.) 1206 */ 1207APPLESTATIC void 1208nfsrv_zapclient(struct nfsclient *clp, NFSPROC_T *p) 1209{ 1210 1211#ifdef notyet 1212 if ((clp->lc_flags & (LCL_GSS | LCL_CALLBACKSON)) == 1213 (LCL_GSS | LCL_CALLBACKSON) && 1214 (clp->lc_hand.nfsh_flag & NFSG_COMPLETE) && 1215 clp->lc_handlelen > 0) { 1216 clp->lc_hand.nfsh_flag &= ~NFSG_COMPLETE; 1217 clp->lc_hand.nfsh_flag |= NFSG_DESTROYED; 1218 (void) nfsrv_docallback(clp, NFSV4PROC_CBNULL, 1219 NULL, 0, NULL, NULL, NULL, p); 1220 } 1221#endif 1222 newnfs_disconnect(&clp->lc_req); 1223 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 1224 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 1225 free(clp->lc_stateid, M_NFSDCLIENT); 1226 free(clp, M_NFSDCLIENT); 1227 NFSLOCKSTATE(); 1228 nfsstatsv1.srvclients--; 1229 nfsrv_openpluslock--; 1230 nfsrv_clients--; 1231 NFSUNLOCKSTATE(); 1232} 1233 1234/* 1235 * Free a list of delegation state structures. 1236 * (This function will also free all nfslockfile structures that no 1237 * longer have associated state.) 1238 */ 1239APPLESTATIC void 1240nfsrv_freedeleglist(struct nfsstatehead *sthp) 1241{ 1242 struct nfsstate *stp, *nstp; 1243 1244 LIST_FOREACH_SAFE(stp, sthp, ls_list, nstp) { 1245 nfsrv_freedeleg(stp); 1246 } 1247 LIST_INIT(sthp); 1248} 1249 1250/* 1251 * Free up a delegation. 1252 */ 1253static void 1254nfsrv_freedeleg(struct nfsstate *stp) 1255{ 1256 struct nfslockfile *lfp; 1257 1258 LIST_REMOVE(stp, ls_hash); 1259 LIST_REMOVE(stp, ls_list); 1260 LIST_REMOVE(stp, ls_file); 1261 lfp = stp->ls_lfp; 1262 if (LIST_EMPTY(&lfp->lf_open) && 1263 LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) && 1264 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1265 lfp->lf_usecount == 0 && 1266 nfsv4_testlock(&lfp->lf_locallock_lck) == 0) 1267 nfsrv_freenfslockfile(lfp); 1268 FREE((caddr_t)stp, M_NFSDSTATE); 1269 nfsstatsv1.srvdelegates--; 1270 nfsrv_openpluslock--; 1271 nfsrv_delegatecnt--; 1272} 1273 1274/* 1275 * This function frees an open owner and all associated opens. 1276 */ 1277static void 1278nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, NFSPROC_T *p) 1279{ 1280 struct nfsstate *nstp, *tstp; 1281 1282 LIST_REMOVE(stp, ls_list); 1283 /* 1284 * Now, free all associated opens. 1285 */ 1286 nstp = LIST_FIRST(&stp->ls_open); 1287 while (nstp != NULL) { 1288 tstp = nstp; 1289 nstp = LIST_NEXT(nstp, ls_list); 1290 (void) nfsrv_freeopen(tstp, NULL, cansleep, p); 1291 } 1292 if (stp->ls_op) 1293 nfsrvd_derefcache(stp->ls_op); 1294 FREE((caddr_t)stp, M_NFSDSTATE); 1295 nfsstatsv1.srvopenowners--; 1296 nfsrv_openpluslock--; 1297} 1298 1299/* 1300 * This function frees an open (nfsstate open structure) with all associated 1301 * lock_owners and locks. It also frees the nfslockfile structure iff there 1302 * are no other opens on the file. 1303 * Returns 1 if it free'd the nfslockfile, 0 otherwise. 1304 */ 1305static int 1306nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) 1307{ 1308 struct nfsstate *nstp, *tstp; 1309 struct nfslockfile *lfp; 1310 int ret; 1311 1312 LIST_REMOVE(stp, ls_hash); 1313 LIST_REMOVE(stp, ls_list); 1314 LIST_REMOVE(stp, ls_file); 1315 1316 lfp = stp->ls_lfp; 1317 /* 1318 * Now, free all lockowners associated with this open. 1319 */ 1320 LIST_FOREACH_SAFE(tstp, &stp->ls_open, ls_list, nstp) 1321 nfsrv_freelockowner(tstp, vp, cansleep, p); 1322 1323 /* 1324 * The nfslockfile is freed here if there are no locks 1325 * associated with the open. 1326 * If there are locks associated with the open, the 1327 * nfslockfile structure can be freed via nfsrv_freelockowner(). 1328 * Acquire the state mutex to avoid races with calls to 1329 * nfsrv_getlockfile(). 1330 */ 1331 if (cansleep != 0) 1332 NFSLOCKSTATE(); 1333 if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && 1334 LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && 1335 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1336 lfp->lf_usecount == 0 && 1337 (cansleep != 0 || nfsv4_testlock(&lfp->lf_locallock_lck) == 0)) { 1338 nfsrv_freenfslockfile(lfp); 1339 ret = 1; 1340 } else 1341 ret = 0; 1342 if (cansleep != 0) 1343 NFSUNLOCKSTATE(); 1344 FREE((caddr_t)stp, M_NFSDSTATE); 1345 nfsstatsv1.srvopens--; 1346 nfsrv_openpluslock--; 1347 return (ret); 1348} 1349 1350/* 1351 * Frees a lockowner and all associated locks. 1352 */ 1353static void 1354nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 1355 NFSPROC_T *p) 1356{ 1357 1358 LIST_REMOVE(stp, ls_hash); 1359 LIST_REMOVE(stp, ls_list); 1360 nfsrv_freeallnfslocks(stp, vp, cansleep, p); 1361 if (stp->ls_op) 1362 nfsrvd_derefcache(stp->ls_op); 1363 FREE((caddr_t)stp, M_NFSDSTATE); 1364 nfsstatsv1.srvlockowners--; 1365 nfsrv_openpluslock--; 1366} 1367 1368/* 1369 * Free all the nfs locks on a lockowner. 1370 */ 1371static void 1372nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, 1373 NFSPROC_T *p) 1374{ 1375 struct nfslock *lop, *nlop; 1376 struct nfsrollback *rlp, *nrlp; 1377 struct nfslockfile *lfp = NULL; 1378 int gottvp = 0; 1379 vnode_t tvp = NULL; 1380 uint64_t first, end; 1381 1382 if (vp != NULL) 1383 ASSERT_VOP_UNLOCKED(vp, "nfsrv_freeallnfslocks: vnode locked"); 1384 lop = LIST_FIRST(&stp->ls_lock); 1385 while (lop != NULL) { 1386 nlop = LIST_NEXT(lop, lo_lckowner); 1387 /* 1388 * Since all locks should be for the same file, lfp should 1389 * not change. 1390 */ 1391 if (lfp == NULL) 1392 lfp = lop->lo_lfp; 1393 else if (lfp != lop->lo_lfp) 1394 panic("allnfslocks"); 1395 /* 1396 * If vp is NULL and cansleep != 0, a vnode must be acquired 1397 * from the file handle. This only occurs when called from 1398 * nfsrv_cleanclient(). 1399 */ 1400 if (gottvp == 0) { 1401 if (nfsrv_dolocallocks == 0) 1402 tvp = NULL; 1403 else if (vp == NULL && cansleep != 0) { 1404 tvp = nfsvno_getvp(&lfp->lf_fh); 1405 NFSVOPUNLOCK(tvp, 0); 1406 } else 1407 tvp = vp; 1408 gottvp = 1; 1409 } 1410 1411 if (tvp != NULL) { 1412 if (cansleep == 0) 1413 panic("allnfs2"); 1414 first = lop->lo_first; 1415 end = lop->lo_end; 1416 nfsrv_freenfslock(lop); 1417 nfsrv_localunlock(tvp, lfp, first, end, p); 1418 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, 1419 nrlp) 1420 free(rlp, M_NFSDROLLBACK); 1421 LIST_INIT(&lfp->lf_rollback); 1422 } else 1423 nfsrv_freenfslock(lop); 1424 lop = nlop; 1425 } 1426 if (vp == NULL && tvp != NULL) 1427 vrele(tvp); 1428} 1429 1430/* 1431 * Free an nfslock structure. 1432 */ 1433static void 1434nfsrv_freenfslock(struct nfslock *lop) 1435{ 1436 1437 if (lop->lo_lckfile.le_prev != NULL) { 1438 LIST_REMOVE(lop, lo_lckfile); 1439 nfsstatsv1.srvlocks--; 1440 nfsrv_openpluslock--; 1441 } 1442 LIST_REMOVE(lop, lo_lckowner); 1443 FREE((caddr_t)lop, M_NFSDLOCK); 1444} 1445 1446/* 1447 * This function frees an nfslockfile structure. 1448 */ 1449static void 1450nfsrv_freenfslockfile(struct nfslockfile *lfp) 1451{ 1452 1453 LIST_REMOVE(lfp, lf_hash); 1454 FREE((caddr_t)lfp, M_NFSDLOCKFILE); 1455} 1456 1457/* 1458 * This function looks up an nfsstate structure via stateid. 1459 */ 1460static int 1461nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, __unused u_int32_t flags, 1462 struct nfsstate **stpp) 1463{ 1464 struct nfsstate *stp; 1465 struct nfsstatehead *hp; 1466 int error = 0; 1467 1468 *stpp = NULL; 1469 hp = NFSSTATEHASH(clp, *stateidp); 1470 LIST_FOREACH(stp, hp, ls_hash) { 1471 if (!NFSBCMP(stp->ls_stateid.other, stateidp->other, 1472 NFSX_STATEIDOTHER)) 1473 break; 1474 } 1475 1476 /* 1477 * If no state id in list, return NFSERR_BADSTATEID. 1478 */ 1479 if (stp == NULL) { 1480 error = NFSERR_BADSTATEID; 1481 goto out; 1482 } 1483 *stpp = stp; 1484 1485out: 1486 NFSEXITCODE(error); 1487 return (error); 1488} 1489 1490/* 1491 * This function gets an nfsstate structure via owner string. 1492 */ 1493static void 1494nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 1495 struct nfsstate **stpp) 1496{ 1497 struct nfsstate *stp; 1498 1499 *stpp = NULL; 1500 LIST_FOREACH(stp, hp, ls_list) { 1501 if (new_stp->ls_ownerlen == stp->ls_ownerlen && 1502 !NFSBCMP(new_stp->ls_owner,stp->ls_owner,stp->ls_ownerlen)) { 1503 *stpp = stp; 1504 return; 1505 } 1506 } 1507} 1508 1509/* 1510 * Lock control function called to update lock status. 1511 * Returns 0 upon success, -1 if there is no lock and the flags indicate 1512 * that one isn't to be created and an NFSERR_xxx for other errors. 1513 * The structures new_stp and new_lop are passed in as pointers that should 1514 * be set to NULL if the structure is used and shouldn't be free'd. 1515 * For the NFSLCK_TEST and NFSLCK_CHECK cases, the structures are 1516 * never used and can safely be allocated on the stack. For all other 1517 * cases, *new_stpp and *new_lopp should be malloc'd before the call, 1518 * in case they are used. 1519 */ 1520APPLESTATIC int 1521nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp, 1522 struct nfslock **new_lopp, struct nfslockconflict *cfp, 1523 nfsquad_t clientid, nfsv4stateid_t *stateidp, 1524 __unused struct nfsexstuff *exp, 1525 struct nfsrv_descript *nd, NFSPROC_T *p) 1526{ 1527 struct nfslock *lop; 1528 struct nfsstate *new_stp = *new_stpp; 1529 struct nfslock *new_lop = *new_lopp; 1530 struct nfsstate *tstp, *mystp, *nstp; 1531 int specialid = 0; 1532 struct nfslockfile *lfp; 1533 struct nfslock *other_lop = NULL; 1534 struct nfsstate *stp, *lckstp = NULL; 1535 struct nfsclient *clp = NULL; 1536 u_int32_t bits; 1537 int error = 0, haslock = 0, ret, reterr; 1538 int getlckret, delegation = 0, filestruct_locked, vnode_unlocked = 0; 1539 fhandle_t nfh; 1540 uint64_t first, end; 1541 uint32_t lock_flags; 1542 1543 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1544 /* 1545 * Note the special cases of "all 1s" or "all 0s" stateids and 1546 * let reads with all 1s go ahead. 1547 */ 1548 if (new_stp->ls_stateid.seqid == 0x0 && 1549 new_stp->ls_stateid.other[0] == 0x0 && 1550 new_stp->ls_stateid.other[1] == 0x0 && 1551 new_stp->ls_stateid.other[2] == 0x0) 1552 specialid = 1; 1553 else if (new_stp->ls_stateid.seqid == 0xffffffff && 1554 new_stp->ls_stateid.other[0] == 0xffffffff && 1555 new_stp->ls_stateid.other[1] == 0xffffffff && 1556 new_stp->ls_stateid.other[2] == 0xffffffff) 1557 specialid = 2; 1558 } 1559 1560 /* 1561 * Check for restart conditions (client and server). 1562 */ 1563 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 1564 &new_stp->ls_stateid, specialid); 1565 if (error) 1566 goto out; 1567 1568 /* 1569 * Check for state resource limit exceeded. 1570 */ 1571 if ((new_stp->ls_flags & NFSLCK_LOCK) && 1572 nfsrv_openpluslock > nfsrv_v4statelimit) { 1573 error = NFSERR_RESOURCE; 1574 goto out; 1575 } 1576 1577 /* 1578 * For the lock case, get another nfslock structure, 1579 * just in case we need it. 1580 * Malloc now, before we start sifting through the linked lists, 1581 * in case we have to wait for memory. 1582 */ 1583tryagain: 1584 if (new_stp->ls_flags & NFSLCK_LOCK) 1585 MALLOC(other_lop, struct nfslock *, sizeof (struct nfslock), 1586 M_NFSDLOCK, M_WAITOK); 1587 filestruct_locked = 0; 1588 reterr = 0; 1589 lfp = NULL; 1590 1591 /* 1592 * Get the lockfile structure for CFH now, so we can do a sanity 1593 * check against the stateid, before incrementing the seqid#, since 1594 * we want to return NFSERR_BADSTATEID on failure and the seqid# 1595 * shouldn't be incremented for this case. 1596 * If nfsrv_getlockfile() returns -1, it means "not found", which 1597 * will be handled later. 1598 * If we are doing Lock/LockU and local locking is enabled, sleep 1599 * lock the nfslockfile structure. 1600 */ 1601 getlckret = nfsrv_getlockfh(vp, new_stp->ls_flags, NULL, &nfh, p); 1602 NFSLOCKSTATE(); 1603 if (getlckret == 0) { 1604 if ((new_stp->ls_flags & (NFSLCK_LOCK | NFSLCK_UNLOCK)) != 0 && 1605 nfsrv_dolocallocks != 0 && nd->nd_repstat == 0) { 1606 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1607 &lfp, &nfh, 1); 1608 if (getlckret == 0) 1609 filestruct_locked = 1; 1610 } else 1611 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1612 &lfp, &nfh, 0); 1613 } 1614 if (getlckret != 0 && getlckret != -1) 1615 reterr = getlckret; 1616 1617 if (filestruct_locked != 0) { 1618 LIST_INIT(&lfp->lf_rollback); 1619 if ((new_stp->ls_flags & NFSLCK_LOCK)) { 1620 /* 1621 * For local locking, do the advisory locking now, so 1622 * that any conflict can be detected. A failure later 1623 * can be rolled back locally. If an error is returned, 1624 * struct nfslockfile has been unlocked and any local 1625 * locking rolled back. 1626 */ 1627 NFSUNLOCKSTATE(); 1628 if (vnode_unlocked == 0) { 1629 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl1"); 1630 vnode_unlocked = 1; 1631 NFSVOPUNLOCK(vp, 0); 1632 } 1633 reterr = nfsrv_locallock(vp, lfp, 1634 (new_lop->lo_flags & (NFSLCK_READ | NFSLCK_WRITE)), 1635 new_lop->lo_first, new_lop->lo_end, cfp, p); 1636 NFSLOCKSTATE(); 1637 } 1638 } 1639 1640 if (specialid == 0) { 1641 if (new_stp->ls_flags & NFSLCK_TEST) { 1642 /* 1643 * RFC 3530 does not list LockT as an op that renews a 1644 * lease, but the consensus seems to be that it is ok 1645 * for a server to do so. 1646 */ 1647 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 1648 (nfsquad_t)((u_quad_t)0), 0, nd, p); 1649 1650 /* 1651 * Since NFSERR_EXPIRED, NFSERR_ADMINREVOKED are not valid 1652 * error returns for LockT, just go ahead and test for a lock, 1653 * since there are no locks for this client, but other locks 1654 * can conflict. (ie. same client will always be false) 1655 */ 1656 if (error == NFSERR_EXPIRED || error == NFSERR_ADMINREVOKED) 1657 error = 0; 1658 lckstp = new_stp; 1659 } else { 1660 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 1661 (nfsquad_t)((u_quad_t)0), 0, nd, p); 1662 if (error == 0) 1663 /* 1664 * Look up the stateid 1665 */ 1666 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 1667 new_stp->ls_flags, &stp); 1668 /* 1669 * do some sanity checks for an unconfirmed open or a 1670 * stateid that refers to the wrong file, for an open stateid 1671 */ 1672 if (error == 0 && (stp->ls_flags & NFSLCK_OPEN) && 1673 ((stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM) || 1674 (getlckret == 0 && stp->ls_lfp != lfp))){ 1675 /* 1676 * NFSLCK_SETATTR should return OK rather than NFSERR_BADSTATEID 1677 * The only exception is using SETATTR with SIZE. 1678 * */ 1679 if ((new_stp->ls_flags & 1680 (NFSLCK_SETATTR | NFSLCK_CHECK)) != NFSLCK_SETATTR) 1681 error = NFSERR_BADSTATEID; 1682 } 1683 1684 if (error == 0 && 1685 (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) && 1686 getlckret == 0 && stp->ls_lfp != lfp) 1687 error = NFSERR_BADSTATEID; 1688 1689 /* 1690 * If the lockowner stateid doesn't refer to the same file, 1691 * I believe that is considered ok, since some clients will 1692 * only create a single lockowner and use that for all locks 1693 * on all files. 1694 * For now, log it as a diagnostic, instead of considering it 1695 * a BadStateid. 1696 */ 1697 if (error == 0 && (stp->ls_flags & 1698 (NFSLCK_OPEN | NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) == 0 && 1699 getlckret == 0 && stp->ls_lfp != lfp) { 1700#ifdef DIAGNOSTIC 1701 printf("Got a lock statid for different file open\n"); 1702#endif 1703 /* 1704 error = NFSERR_BADSTATEID; 1705 */ 1706 } 1707 1708 if (error == 0) { 1709 if (new_stp->ls_flags & NFSLCK_OPENTOLOCK) { 1710 /* 1711 * If haslock set, we've already checked the seqid. 1712 */ 1713 if (!haslock) { 1714 if (stp->ls_flags & NFSLCK_OPEN) 1715 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1716 stp->ls_openowner, new_stp->ls_op); 1717 else 1718 error = NFSERR_BADSTATEID; 1719 } 1720 if (!error) 1721 nfsrv_getowner(&stp->ls_open, new_stp, &lckstp); 1722 if (lckstp) 1723 /* 1724 * I believe this should be an error, but it 1725 * isn't obvious what NFSERR_xxx would be 1726 * appropriate, so I'll use NFSERR_INVAL for now. 1727 */ 1728 error = NFSERR_INVAL; 1729 else 1730 lckstp = new_stp; 1731 } else if (new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK)) { 1732 /* 1733 * If haslock set, ditto above. 1734 */ 1735 if (!haslock) { 1736 if (stp->ls_flags & NFSLCK_OPEN) 1737 error = NFSERR_BADSTATEID; 1738 else 1739 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1740 stp, new_stp->ls_op); 1741 } 1742 lckstp = stp; 1743 } else { 1744 lckstp = stp; 1745 } 1746 } 1747 /* 1748 * If the seqid part of the stateid isn't the same, return 1749 * NFSERR_OLDSTATEID for cases other than I/O Ops. 1750 * For I/O Ops, only return NFSERR_OLDSTATEID if 1751 * nfsrv_returnoldstateid is set. (The consensus on the email 1752 * list was that most clients would prefer to not receive 1753 * NFSERR_OLDSTATEID for I/O Ops, but the RFC suggests that that 1754 * is what will happen, so I use the nfsrv_returnoldstateid to 1755 * allow for either server configuration.) 1756 */ 1757 if (!error && stp->ls_stateid.seqid!=new_stp->ls_stateid.seqid && 1758 (((nd->nd_flag & ND_NFSV41) == 0 && 1759 (!(new_stp->ls_flags & NFSLCK_CHECK) || 1760 nfsrv_returnoldstateid)) || 1761 ((nd->nd_flag & ND_NFSV41) != 0 && 1762 new_stp->ls_stateid.seqid != 0))) 1763 error = NFSERR_OLDSTATEID; 1764 } 1765 } 1766 1767 /* 1768 * Now we can check for grace. 1769 */ 1770 if (!error) 1771 error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags); 1772 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 1773 nfsrv_checkstable(clp)) 1774 error = NFSERR_NOGRACE; 1775 /* 1776 * If we successfully Reclaimed state, note that. 1777 */ 1778 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error) 1779 nfsrv_markstable(clp); 1780 1781 /* 1782 * At this point, either error == NFSERR_BADSTATEID or the 1783 * seqid# has been updated, so we can return any error. 1784 * If error == 0, there may be an error in: 1785 * nd_repstat - Set by the calling function. 1786 * reterr - Set above, if getting the nfslockfile structure 1787 * or acquiring the local lock failed. 1788 * (If both of these are set, nd_repstat should probably be 1789 * returned, since that error was detected before this 1790 * function call.) 1791 */ 1792 if (error != 0 || nd->nd_repstat != 0 || reterr != 0) { 1793 if (error == 0) { 1794 if (nd->nd_repstat != 0) 1795 error = nd->nd_repstat; 1796 else 1797 error = reterr; 1798 } 1799 if (filestruct_locked != 0) { 1800 /* Roll back local locks. */ 1801 NFSUNLOCKSTATE(); 1802 if (vnode_unlocked == 0) { 1803 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl2"); 1804 vnode_unlocked = 1; 1805 NFSVOPUNLOCK(vp, 0); 1806 } 1807 nfsrv_locallock_rollback(vp, lfp, p); 1808 NFSLOCKSTATE(); 1809 nfsrv_unlocklf(lfp); 1810 } 1811 NFSUNLOCKSTATE(); 1812 goto out; 1813 } 1814 1815 /* 1816 * Check the nfsrv_getlockfile return. 1817 * Returned -1 if no structure found. 1818 */ 1819 if (getlckret == -1) { 1820 error = NFSERR_EXPIRED; 1821 /* 1822 * Called from lockt, so no lock is OK. 1823 */ 1824 if (new_stp->ls_flags & NFSLCK_TEST) { 1825 error = 0; 1826 } else if (new_stp->ls_flags & 1827 (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1828 /* 1829 * Called to check for a lock, OK if the stateid is all 1830 * 1s or all 0s, but there should be an nfsstate 1831 * otherwise. 1832 * (ie. If there is no open, I'll assume no share 1833 * deny bits.) 1834 */ 1835 if (specialid) 1836 error = 0; 1837 else 1838 error = NFSERR_BADSTATEID; 1839 } 1840 NFSUNLOCKSTATE(); 1841 goto out; 1842 } 1843 1844 /* 1845 * For NFSLCK_CHECK and NFSLCK_LOCK, test for a share conflict. 1846 * For NFSLCK_CHECK, allow a read if write access is granted, 1847 * but check for a deny. For NFSLCK_LOCK, require correct access, 1848 * which implies a conflicting deny can't exist. 1849 */ 1850 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_LOCK)) { 1851 /* 1852 * Four kinds of state id: 1853 * - specialid (all 0s or all 1s), only for NFSLCK_CHECK 1854 * - stateid for an open 1855 * - stateid for a delegation 1856 * - stateid for a lock owner 1857 */ 1858 if (!specialid) { 1859 if (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 1860 delegation = 1; 1861 mystp = stp; 1862 nfsrv_delaydelegtimeout(stp); 1863 } else if (stp->ls_flags & NFSLCK_OPEN) { 1864 mystp = stp; 1865 } else { 1866 mystp = stp->ls_openstp; 1867 } 1868 /* 1869 * If locking or checking, require correct access 1870 * bit set. 1871 */ 1872 if (((new_stp->ls_flags & NFSLCK_LOCK) && 1873 !((new_lop->lo_flags >> NFSLCK_LOCKSHIFT) & 1874 mystp->ls_flags & NFSLCK_ACCESSBITS)) || 1875 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_READACCESS)) == 1876 (NFSLCK_CHECK | NFSLCK_READACCESS) && 1877 !(mystp->ls_flags & NFSLCK_READACCESS)) || 1878 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_WRITEACCESS)) == 1879 (NFSLCK_CHECK | NFSLCK_WRITEACCESS) && 1880 !(mystp->ls_flags & NFSLCK_WRITEACCESS))) { 1881 if (filestruct_locked != 0) { 1882 /* Roll back local locks. */ 1883 NFSUNLOCKSTATE(); 1884 if (vnode_unlocked == 0) { 1885 ASSERT_VOP_ELOCKED(vp, 1886 "nfsrv_lockctrl3"); 1887 vnode_unlocked = 1; 1888 NFSVOPUNLOCK(vp, 0); 1889 } 1890 nfsrv_locallock_rollback(vp, lfp, p); 1891 NFSLOCKSTATE(); 1892 nfsrv_unlocklf(lfp); 1893 } 1894 NFSUNLOCKSTATE(); 1895 error = NFSERR_OPENMODE; 1896 goto out; 1897 } 1898 } else 1899 mystp = NULL; 1900 if ((new_stp->ls_flags & NFSLCK_CHECK) && !delegation) { 1901 /* 1902 * Check for a conflicting deny bit. 1903 */ 1904 LIST_FOREACH(tstp, &lfp->lf_open, ls_file) { 1905 if (tstp != mystp) { 1906 bits = tstp->ls_flags; 1907 bits >>= NFSLCK_SHIFT; 1908 if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) { 1909 KASSERT(vnode_unlocked == 0, 1910 ("nfsrv_lockctrl: vnode unlocked1")); 1911 ret = nfsrv_clientconflict(tstp->ls_clp, &haslock, 1912 vp, p); 1913 if (ret == 1) { 1914 /* 1915 * nfsrv_clientconflict unlocks state 1916 * when it returns non-zero. 1917 */ 1918 lckstp = NULL; 1919 goto tryagain; 1920 } 1921 if (ret == 0) 1922 NFSUNLOCKSTATE(); 1923 if (ret == 2) 1924 error = NFSERR_PERM; 1925 else 1926 error = NFSERR_OPENMODE; 1927 goto out; 1928 } 1929 } 1930 } 1931 1932 /* We're outta here */ 1933 NFSUNLOCKSTATE(); 1934 goto out; 1935 } 1936 } 1937 1938 /* 1939 * For setattr, just get rid of all the Delegations for other clients. 1940 */ 1941 if (new_stp->ls_flags & NFSLCK_SETATTR) { 1942 KASSERT(vnode_unlocked == 0, 1943 ("nfsrv_lockctrl: vnode unlocked2")); 1944 ret = nfsrv_cleandeleg(vp, lfp, clp, &haslock, p); 1945 if (ret) { 1946 /* 1947 * nfsrv_cleandeleg() unlocks state when it 1948 * returns non-zero. 1949 */ 1950 if (ret == -1) { 1951 lckstp = NULL; 1952 goto tryagain; 1953 } 1954 error = ret; 1955 goto out; 1956 } 1957 if (!(new_stp->ls_flags & NFSLCK_CHECK) || 1958 (LIST_EMPTY(&lfp->lf_open) && LIST_EMPTY(&lfp->lf_lock) && 1959 LIST_EMPTY(&lfp->lf_deleg))) { 1960 NFSUNLOCKSTATE(); 1961 goto out; 1962 } 1963 } 1964 1965 /* 1966 * Check for a conflicting delegation. If one is found, call 1967 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 1968 * been set yet, it will get the lock. Otherwise, it will recall 1969 * the delegation. Then, we try try again... 1970 * I currently believe the conflict algorithm to be: 1971 * For Lock Ops (Lock/LockT/LockU) 1972 * - there is a conflict iff a different client has a write delegation 1973 * For Reading (Read Op) 1974 * - there is a conflict iff a different client has a write delegation 1975 * (the specialids are always a different client) 1976 * For Writing (Write/Setattr of size) 1977 * - there is a conflict if a different client has any delegation 1978 * - there is a conflict if the same client has a read delegation 1979 * (I don't understand why this isn't allowed, but that seems to be 1980 * the current consensus?) 1981 */ 1982 tstp = LIST_FIRST(&lfp->lf_deleg); 1983 while (tstp != NULL) { 1984 nstp = LIST_NEXT(tstp, ls_file); 1985 if ((((new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK|NFSLCK_TEST))|| 1986 ((new_stp->ls_flags & NFSLCK_CHECK) && 1987 (new_lop->lo_flags & NFSLCK_READ))) && 1988 clp != tstp->ls_clp && 1989 (tstp->ls_flags & NFSLCK_DELEGWRITE)) || 1990 ((new_stp->ls_flags & NFSLCK_CHECK) && 1991 (new_lop->lo_flags & NFSLCK_WRITE) && 1992 (clp != tstp->ls_clp || 1993 (tstp->ls_flags & NFSLCK_DELEGREAD)))) { 1994 ret = 0; 1995 if (filestruct_locked != 0) { 1996 /* Roll back local locks. */ 1997 NFSUNLOCKSTATE(); 1998 if (vnode_unlocked == 0) { 1999 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl4"); 2000 NFSVOPUNLOCK(vp, 0); 2001 } 2002 nfsrv_locallock_rollback(vp, lfp, p); 2003 NFSLOCKSTATE(); 2004 nfsrv_unlocklf(lfp); 2005 NFSUNLOCKSTATE(); 2006 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2007 vnode_unlocked = 0; 2008 if ((vp->v_iflag & VI_DOOMED) != 0) 2009 ret = NFSERR_SERVERFAULT; 2010 NFSLOCKSTATE(); 2011 } 2012 if (ret == 0) 2013 ret = nfsrv_delegconflict(tstp, &haslock, p, vp); 2014 if (ret) { 2015 /* 2016 * nfsrv_delegconflict unlocks state when it 2017 * returns non-zero, which it always does. 2018 */ 2019 if (other_lop) { 2020 FREE((caddr_t)other_lop, M_NFSDLOCK); 2021 other_lop = NULL; 2022 } 2023 if (ret == -1) { 2024 lckstp = NULL; 2025 goto tryagain; 2026 } 2027 error = ret; 2028 goto out; 2029 } 2030 /* Never gets here. */ 2031 } 2032 tstp = nstp; 2033 } 2034 2035 /* 2036 * Handle the unlock case by calling nfsrv_updatelock(). 2037 * (Should I have done some access checking above for unlock? For now, 2038 * just let it happen.) 2039 */ 2040 if (new_stp->ls_flags & NFSLCK_UNLOCK) { 2041 first = new_lop->lo_first; 2042 end = new_lop->lo_end; 2043 nfsrv_updatelock(stp, new_lopp, &other_lop, lfp); 2044 stateidp->seqid = ++(stp->ls_stateid.seqid); 2045 if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0) 2046 stateidp->seqid = stp->ls_stateid.seqid = 1; 2047 stateidp->other[0] = stp->ls_stateid.other[0]; 2048 stateidp->other[1] = stp->ls_stateid.other[1]; 2049 stateidp->other[2] = stp->ls_stateid.other[2]; 2050 if (filestruct_locked != 0) { 2051 NFSUNLOCKSTATE(); 2052 if (vnode_unlocked == 0) { 2053 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl5"); 2054 vnode_unlocked = 1; 2055 NFSVOPUNLOCK(vp, 0); 2056 } 2057 /* Update the local locks. */ 2058 nfsrv_localunlock(vp, lfp, first, end, p); 2059 NFSLOCKSTATE(); 2060 nfsrv_unlocklf(lfp); 2061 } 2062 NFSUNLOCKSTATE(); 2063 goto out; 2064 } 2065 2066 /* 2067 * Search for a conflicting lock. A lock conflicts if: 2068 * - the lock range overlaps and 2069 * - at least one lock is a write lock and 2070 * - it is not owned by the same lock owner 2071 */ 2072 if (!delegation) { 2073 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 2074 if (new_lop->lo_end > lop->lo_first && 2075 new_lop->lo_first < lop->lo_end && 2076 (new_lop->lo_flags == NFSLCK_WRITE || 2077 lop->lo_flags == NFSLCK_WRITE) && 2078 lckstp != lop->lo_stp && 2079 (clp != lop->lo_stp->ls_clp || 2080 lckstp->ls_ownerlen != lop->lo_stp->ls_ownerlen || 2081 NFSBCMP(lckstp->ls_owner, lop->lo_stp->ls_owner, 2082 lckstp->ls_ownerlen))) { 2083 if (other_lop) { 2084 FREE((caddr_t)other_lop, M_NFSDLOCK); 2085 other_lop = NULL; 2086 } 2087 if (vnode_unlocked != 0) 2088 ret = nfsrv_clientconflict(lop->lo_stp->ls_clp, &haslock, 2089 NULL, p); 2090 else 2091 ret = nfsrv_clientconflict(lop->lo_stp->ls_clp, &haslock, 2092 vp, p); 2093 if (ret == 1) { 2094 if (filestruct_locked != 0) { 2095 if (vnode_unlocked == 0) { 2096 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl6"); 2097 NFSVOPUNLOCK(vp, 0); 2098 } 2099 /* Roll back local locks. */ 2100 nfsrv_locallock_rollback(vp, lfp, p); 2101 NFSLOCKSTATE(); 2102 nfsrv_unlocklf(lfp); 2103 NFSUNLOCKSTATE(); 2104 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2105 vnode_unlocked = 0; 2106 if ((vp->v_iflag & VI_DOOMED) != 0) { 2107 error = NFSERR_SERVERFAULT; 2108 goto out; 2109 } 2110 } 2111 /* 2112 * nfsrv_clientconflict() unlocks state when it 2113 * returns non-zero. 2114 */ 2115 lckstp = NULL; 2116 goto tryagain; 2117 } 2118 /* 2119 * Found a conflicting lock, so record the conflict and 2120 * return the error. 2121 */ 2122 if (cfp != NULL && ret == 0) { 2123 cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0]; 2124 cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1]; 2125 cfp->cl_first = lop->lo_first; 2126 cfp->cl_end = lop->lo_end; 2127 cfp->cl_flags = lop->lo_flags; 2128 cfp->cl_ownerlen = lop->lo_stp->ls_ownerlen; 2129 NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner, 2130 cfp->cl_ownerlen); 2131 } 2132 if (ret == 2) 2133 error = NFSERR_PERM; 2134 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2135 error = NFSERR_RECLAIMCONFLICT; 2136 else if (new_stp->ls_flags & NFSLCK_CHECK) 2137 error = NFSERR_LOCKED; 2138 else 2139 error = NFSERR_DENIED; 2140 if (filestruct_locked != 0 && ret == 0) { 2141 /* Roll back local locks. */ 2142 NFSUNLOCKSTATE(); 2143 if (vnode_unlocked == 0) { 2144 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl7"); 2145 vnode_unlocked = 1; 2146 NFSVOPUNLOCK(vp, 0); 2147 } 2148 nfsrv_locallock_rollback(vp, lfp, p); 2149 NFSLOCKSTATE(); 2150 nfsrv_unlocklf(lfp); 2151 } 2152 if (ret == 0) 2153 NFSUNLOCKSTATE(); 2154 goto out; 2155 } 2156 } 2157 } 2158 2159 /* 2160 * We only get here if there was no lock that conflicted. 2161 */ 2162 if (new_stp->ls_flags & (NFSLCK_TEST | NFSLCK_CHECK)) { 2163 NFSUNLOCKSTATE(); 2164 goto out; 2165 } 2166 2167 /* 2168 * We only get here when we are creating or modifying a lock. 2169 * There are two variants: 2170 * - exist_lock_owner where lock_owner exists 2171 * - open_to_lock_owner with new lock_owner 2172 */ 2173 first = new_lop->lo_first; 2174 end = new_lop->lo_end; 2175 lock_flags = new_lop->lo_flags; 2176 if (!(new_stp->ls_flags & NFSLCK_OPENTOLOCK)) { 2177 nfsrv_updatelock(lckstp, new_lopp, &other_lop, lfp); 2178 stateidp->seqid = ++(lckstp->ls_stateid.seqid); 2179 if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0) 2180 stateidp->seqid = lckstp->ls_stateid.seqid = 1; 2181 stateidp->other[0] = lckstp->ls_stateid.other[0]; 2182 stateidp->other[1] = lckstp->ls_stateid.other[1]; 2183 stateidp->other[2] = lckstp->ls_stateid.other[2]; 2184 } else { 2185 /* 2186 * The new open_to_lock_owner case. 2187 * Link the new nfsstate into the lists. 2188 */ 2189 new_stp->ls_seq = new_stp->ls_opentolockseq; 2190 nfsrvd_refcache(new_stp->ls_op); 2191 stateidp->seqid = new_stp->ls_stateid.seqid = 1; 2192 stateidp->other[0] = new_stp->ls_stateid.other[0] = 2193 clp->lc_clientid.lval[0]; 2194 stateidp->other[1] = new_stp->ls_stateid.other[1] = 2195 clp->lc_clientid.lval[1]; 2196 stateidp->other[2] = new_stp->ls_stateid.other[2] = 2197 nfsrv_nextstateindex(clp); 2198 new_stp->ls_clp = clp; 2199 LIST_INIT(&new_stp->ls_lock); 2200 new_stp->ls_openstp = stp; 2201 new_stp->ls_lfp = lfp; 2202 nfsrv_insertlock(new_lop, (struct nfslock *)new_stp, new_stp, 2203 lfp); 2204 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_stp->ls_stateid), 2205 new_stp, ls_hash); 2206 LIST_INSERT_HEAD(&stp->ls_open, new_stp, ls_list); 2207 *new_lopp = NULL; 2208 *new_stpp = NULL; 2209 nfsstatsv1.srvlockowners++; 2210 nfsrv_openpluslock++; 2211 } 2212 if (filestruct_locked != 0) { 2213 NFSUNLOCKSTATE(); 2214 nfsrv_locallock_commit(lfp, lock_flags, first, end); 2215 NFSLOCKSTATE(); 2216 nfsrv_unlocklf(lfp); 2217 } 2218 NFSUNLOCKSTATE(); 2219 2220out: 2221 if (haslock) { 2222 NFSLOCKV4ROOTMUTEX(); 2223 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2224 NFSUNLOCKV4ROOTMUTEX(); 2225 } 2226 if (vnode_unlocked != 0) { 2227 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2228 if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0) 2229 error = NFSERR_SERVERFAULT; 2230 } 2231 if (other_lop) 2232 FREE((caddr_t)other_lop, M_NFSDLOCK); 2233 NFSEXITCODE2(error, nd); 2234 return (error); 2235} 2236 2237/* 2238 * Check for state errors for Open. 2239 * repstat is passed back out as an error if more critical errors 2240 * are not detected. 2241 */ 2242APPLESTATIC int 2243nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp, 2244 struct nfsstate *new_stp, vnode_t vp, struct nfsrv_descript *nd, 2245 NFSPROC_T *p, int repstat) 2246{ 2247 struct nfsstate *stp, *nstp; 2248 struct nfsclient *clp; 2249 struct nfsstate *ownerstp; 2250 struct nfslockfile *lfp, *new_lfp; 2251 int error = 0, haslock = 0, ret, readonly = 0, getfhret = 0; 2252 2253 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 2254 readonly = 1; 2255 /* 2256 * Check for restart conditions (client and server). 2257 */ 2258 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2259 &new_stp->ls_stateid, 0); 2260 if (error) 2261 goto out; 2262 2263 /* 2264 * Check for state resource limit exceeded. 2265 * Technically this should be SMP protected, but the worst 2266 * case error is "out by one or two" on the count when it 2267 * returns NFSERR_RESOURCE and the limit is just a rather 2268 * arbitrary high water mark, so no harm is done. 2269 */ 2270 if (nfsrv_openpluslock > nfsrv_v4statelimit) { 2271 error = NFSERR_RESOURCE; 2272 goto out; 2273 } 2274 2275tryagain: 2276 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 2277 M_NFSDLOCKFILE, M_WAITOK); 2278 if (vp) 2279 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, new_lfp, 2280 NULL, p); 2281 NFSLOCKSTATE(); 2282 /* 2283 * Get the nfsclient structure. 2284 */ 2285 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 2286 (nfsquad_t)((u_quad_t)0), 0, nd, p); 2287 2288 /* 2289 * Look up the open owner. See if it needs confirmation and 2290 * check the seq#, as required. 2291 */ 2292 if (!error) 2293 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 2294 2295 if (!error && ownerstp) { 2296 error = nfsrv_checkseqid(nd, new_stp->ls_seq, ownerstp, 2297 new_stp->ls_op); 2298 /* 2299 * If the OpenOwner hasn't been confirmed, assume the 2300 * old one was a replay and this one is ok. 2301 * See: RFC3530 Sec. 14.2.18. 2302 */ 2303 if (error == NFSERR_BADSEQID && 2304 (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM)) 2305 error = 0; 2306 } 2307 2308 /* 2309 * Check for grace. 2310 */ 2311 if (!error) 2312 error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags); 2313 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 2314 nfsrv_checkstable(clp)) 2315 error = NFSERR_NOGRACE; 2316 2317 /* 2318 * If none of the above errors occurred, let repstat be 2319 * returned. 2320 */ 2321 if (repstat && !error) 2322 error = repstat; 2323 if (error) { 2324 NFSUNLOCKSTATE(); 2325 if (haslock) { 2326 NFSLOCKV4ROOTMUTEX(); 2327 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2328 NFSUNLOCKV4ROOTMUTEX(); 2329 } 2330 free((caddr_t)new_lfp, M_NFSDLOCKFILE); 2331 goto out; 2332 } 2333 2334 /* 2335 * If vp == NULL, the file doesn't exist yet, so return ok. 2336 * (This always happens on the first pass, so haslock must be 0.) 2337 */ 2338 if (vp == NULL) { 2339 NFSUNLOCKSTATE(); 2340 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2341 goto out; 2342 } 2343 2344 /* 2345 * Get the structure for the underlying file. 2346 */ 2347 if (getfhret) 2348 error = getfhret; 2349 else 2350 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2351 NULL, 0); 2352 if (new_lfp) 2353 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2354 if (error) { 2355 NFSUNLOCKSTATE(); 2356 if (haslock) { 2357 NFSLOCKV4ROOTMUTEX(); 2358 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2359 NFSUNLOCKV4ROOTMUTEX(); 2360 } 2361 goto out; 2362 } 2363 2364 /* 2365 * Search for a conflicting open/share. 2366 */ 2367 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2368 /* 2369 * For Delegate_Cur, search for the matching Delegation, 2370 * which indicates no conflict. 2371 * An old delegation should have been recovered by the 2372 * client doing a Claim_DELEGATE_Prev, so I won't let 2373 * it match and return NFSERR_EXPIRED. Should I let it 2374 * match? 2375 */ 2376 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2377 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2378 (((nd->nd_flag & ND_NFSV41) != 0 && 2379 stateidp->seqid == 0) || 2380 stateidp->seqid == stp->ls_stateid.seqid) && 2381 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2382 NFSX_STATEIDOTHER)) 2383 break; 2384 } 2385 if (stp == NULL || 2386 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2387 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2388 NFSUNLOCKSTATE(); 2389 if (haslock) { 2390 NFSLOCKV4ROOTMUTEX(); 2391 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2392 NFSUNLOCKV4ROOTMUTEX(); 2393 } 2394 error = NFSERR_EXPIRED; 2395 goto out; 2396 } 2397 } 2398 2399 /* 2400 * Check for access/deny bit conflicts. I check for the same 2401 * owner as well, in case the client didn't bother. 2402 */ 2403 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 2404 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR) && 2405 (((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2406 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2407 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2408 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){ 2409 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2410 if (ret == 1) { 2411 /* 2412 * nfsrv_clientconflict() unlocks 2413 * state when it returns non-zero. 2414 */ 2415 goto tryagain; 2416 } 2417 if (ret == 2) 2418 error = NFSERR_PERM; 2419 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2420 error = NFSERR_RECLAIMCONFLICT; 2421 else 2422 error = NFSERR_SHAREDENIED; 2423 if (ret == 0) 2424 NFSUNLOCKSTATE(); 2425 if (haslock) { 2426 NFSLOCKV4ROOTMUTEX(); 2427 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2428 NFSUNLOCKV4ROOTMUTEX(); 2429 } 2430 goto out; 2431 } 2432 } 2433 2434 /* 2435 * Check for a conflicting delegation. If one is found, call 2436 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2437 * been set yet, it will get the lock. Otherwise, it will recall 2438 * the delegation. Then, we try try again... 2439 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2440 * isn't a conflict.) 2441 * I currently believe the conflict algorithm to be: 2442 * For Open with Read Access and Deny None 2443 * - there is a conflict iff a different client has a write delegation 2444 * For Open with other Write Access or any Deny except None 2445 * - there is a conflict if a different client has any delegation 2446 * - there is a conflict if the same client has a read delegation 2447 * (The current consensus is that this last case should be 2448 * considered a conflict since the client with a read delegation 2449 * could have done an Open with ReadAccess and WriteDeny 2450 * locally and then not have checked for the WriteDeny.) 2451 * Don't check for a Reclaim, since that will be dealt with 2452 * by nfsrv_openctrl(). 2453 */ 2454 if (!(new_stp->ls_flags & 2455 (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR | NFSLCK_RECLAIM))) { 2456 stp = LIST_FIRST(&lfp->lf_deleg); 2457 while (stp != NULL) { 2458 nstp = LIST_NEXT(stp, ls_file); 2459 if ((readonly && stp->ls_clp != clp && 2460 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2461 (!readonly && (stp->ls_clp != clp || 2462 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 2463 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2464 if (ret) { 2465 /* 2466 * nfsrv_delegconflict() unlocks state 2467 * when it returns non-zero. 2468 */ 2469 if (ret == -1) 2470 goto tryagain; 2471 error = ret; 2472 goto out; 2473 } 2474 } 2475 stp = nstp; 2476 } 2477 } 2478 NFSUNLOCKSTATE(); 2479 if (haslock) { 2480 NFSLOCKV4ROOTMUTEX(); 2481 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2482 NFSUNLOCKV4ROOTMUTEX(); 2483 } 2484 2485out: 2486 NFSEXITCODE2(error, nd); 2487 return (error); 2488} 2489 2490/* 2491 * Open control function to create/update open state for an open. 2492 */ 2493APPLESTATIC int 2494nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp, 2495 struct nfsstate **new_stpp, nfsquad_t clientid, nfsv4stateid_t *stateidp, 2496 nfsv4stateid_t *delegstateidp, u_int32_t *rflagsp, struct nfsexstuff *exp, 2497 NFSPROC_T *p, u_quad_t filerev) 2498{ 2499 struct nfsstate *new_stp = *new_stpp; 2500 struct nfsstate *stp, *nstp; 2501 struct nfsstate *openstp = NULL, *new_open, *ownerstp, *new_deleg; 2502 struct nfslockfile *lfp, *new_lfp; 2503 struct nfsclient *clp; 2504 int error = 0, haslock = 0, ret, delegate = 1, writedeleg = 1; 2505 int readonly = 0, cbret = 1, getfhret = 0; 2506 2507 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 2508 readonly = 1; 2509 /* 2510 * Check for restart conditions (client and server). 2511 * (Paranoia, should have been detected by nfsrv_opencheck().) 2512 * If an error does show up, return NFSERR_EXPIRED, since the 2513 * the seqid# has already been incremented. 2514 */ 2515 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2516 &new_stp->ls_stateid, 0); 2517 if (error) { 2518 printf("Nfsd: openctrl unexpected restart err=%d\n", 2519 error); 2520 error = NFSERR_EXPIRED; 2521 goto out; 2522 } 2523 2524tryagain: 2525 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 2526 M_NFSDLOCKFILE, M_WAITOK); 2527 MALLOC(new_open, struct nfsstate *, sizeof (struct nfsstate), 2528 M_NFSDSTATE, M_WAITOK); 2529 MALLOC(new_deleg, struct nfsstate *, sizeof (struct nfsstate), 2530 M_NFSDSTATE, M_WAITOK); 2531 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, new_lfp, 2532 NULL, p); 2533 NFSLOCKSTATE(); 2534 /* 2535 * Get the client structure. Since the linked lists could be changed 2536 * by other nfsd processes if this process does a tsleep(), one of 2537 * two things must be done. 2538 * 1 - don't tsleep() 2539 * or 2540 * 2 - get the nfsv4_lock() { indicated by haslock == 1 } 2541 * before using the lists, since this lock stops the other 2542 * nfsd. This should only be used for rare cases, since it 2543 * essentially single threads the nfsd. 2544 * At this time, it is only done for cases where the stable 2545 * storage file must be written prior to completion of state 2546 * expiration. 2547 */ 2548 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 2549 (nfsquad_t)((u_quad_t)0), 0, nd, p); 2550 if (!error && (clp->lc_flags & LCL_NEEDSCBNULL) && 2551 clp->lc_program) { 2552 /* 2553 * This happens on the first open for a client 2554 * that supports callbacks. 2555 */ 2556 NFSUNLOCKSTATE(); 2557 /* 2558 * Although nfsrv_docallback() will sleep, clp won't 2559 * go away, since they are only removed when the 2560 * nfsv4_lock() has blocked the nfsd threads. The 2561 * fields in clp can change, but having multiple 2562 * threads do this Null callback RPC should be 2563 * harmless. 2564 */ 2565 cbret = nfsrv_docallback(clp, NFSV4PROC_CBNULL, 2566 NULL, 0, NULL, NULL, NULL, p); 2567 NFSLOCKSTATE(); 2568 clp->lc_flags &= ~LCL_NEEDSCBNULL; 2569 if (!cbret) 2570 clp->lc_flags |= LCL_CALLBACKSON; 2571 } 2572 2573 /* 2574 * Look up the open owner. See if it needs confirmation and 2575 * check the seq#, as required. 2576 */ 2577 if (!error) 2578 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 2579 2580 if (error) { 2581 NFSUNLOCKSTATE(); 2582 printf("Nfsd: openctrl unexpected state err=%d\n", 2583 error); 2584 free((caddr_t)new_lfp, M_NFSDLOCKFILE); 2585 free((caddr_t)new_open, M_NFSDSTATE); 2586 free((caddr_t)new_deleg, M_NFSDSTATE); 2587 if (haslock) { 2588 NFSLOCKV4ROOTMUTEX(); 2589 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2590 NFSUNLOCKV4ROOTMUTEX(); 2591 } 2592 error = NFSERR_EXPIRED; 2593 goto out; 2594 } 2595 2596 if (new_stp->ls_flags & NFSLCK_RECLAIM) 2597 nfsrv_markstable(clp); 2598 2599 /* 2600 * Get the structure for the underlying file. 2601 */ 2602 if (getfhret) 2603 error = getfhret; 2604 else 2605 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2606 NULL, 0); 2607 if (new_lfp) 2608 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2609 if (error) { 2610 NFSUNLOCKSTATE(); 2611 printf("Nfsd openctrl unexpected getlockfile err=%d\n", 2612 error); 2613 free((caddr_t)new_open, M_NFSDSTATE); 2614 free((caddr_t)new_deleg, M_NFSDSTATE); 2615 if (haslock) { 2616 NFSLOCKV4ROOTMUTEX(); 2617 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2618 NFSUNLOCKV4ROOTMUTEX(); 2619 } 2620 goto out; 2621 } 2622 2623 /* 2624 * Search for a conflicting open/share. 2625 */ 2626 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2627 /* 2628 * For Delegate_Cur, search for the matching Delegation, 2629 * which indicates no conflict. 2630 * An old delegation should have been recovered by the 2631 * client doing a Claim_DELEGATE_Prev, so I won't let 2632 * it match and return NFSERR_EXPIRED. Should I let it 2633 * match? 2634 */ 2635 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2636 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2637 (((nd->nd_flag & ND_NFSV41) != 0 && 2638 stateidp->seqid == 0) || 2639 stateidp->seqid == stp->ls_stateid.seqid) && 2640 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2641 NFSX_STATEIDOTHER)) 2642 break; 2643 } 2644 if (stp == NULL || 2645 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2646 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2647 NFSUNLOCKSTATE(); 2648 printf("Nfsd openctrl unexpected expiry\n"); 2649 free((caddr_t)new_open, M_NFSDSTATE); 2650 free((caddr_t)new_deleg, M_NFSDSTATE); 2651 if (haslock) { 2652 NFSLOCKV4ROOTMUTEX(); 2653 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2654 NFSUNLOCKV4ROOTMUTEX(); 2655 } 2656 error = NFSERR_EXPIRED; 2657 goto out; 2658 } 2659 2660 /* 2661 * Don't issue a Delegation, since one already exists and 2662 * delay delegation timeout, as required. 2663 */ 2664 delegate = 0; 2665 nfsrv_delaydelegtimeout(stp); 2666 } 2667 2668 /* 2669 * Check for access/deny bit conflicts. I also check for the 2670 * same owner, since the client might not have bothered to check. 2671 * Also, note an open for the same file and owner, if found, 2672 * which is all we do here for Delegate_Cur, since conflict 2673 * checking is already done. 2674 */ 2675 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 2676 if (ownerstp && stp->ls_openowner == ownerstp) 2677 openstp = stp; 2678 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR)) { 2679 /* 2680 * If another client has the file open, the only 2681 * delegation that can be issued is a Read delegation 2682 * and only if it is a Read open with Deny none. 2683 */ 2684 if (clp != stp->ls_clp) { 2685 if ((stp->ls_flags & NFSLCK_SHAREBITS) == 2686 NFSLCK_READACCESS) 2687 writedeleg = 0; 2688 else 2689 delegate = 0; 2690 } 2691 if(((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2692 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2693 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2694 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){ 2695 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2696 if (ret == 1) { 2697 /* 2698 * nfsrv_clientconflict() unlocks state 2699 * when it returns non-zero. 2700 */ 2701 free((caddr_t)new_open, M_NFSDSTATE); 2702 free((caddr_t)new_deleg, M_NFSDSTATE); 2703 openstp = NULL; 2704 goto tryagain; 2705 } 2706 if (ret == 2) 2707 error = NFSERR_PERM; 2708 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2709 error = NFSERR_RECLAIMCONFLICT; 2710 else 2711 error = NFSERR_SHAREDENIED; 2712 if (ret == 0) 2713 NFSUNLOCKSTATE(); 2714 if (haslock) { 2715 NFSLOCKV4ROOTMUTEX(); 2716 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2717 NFSUNLOCKV4ROOTMUTEX(); 2718 } 2719 free((caddr_t)new_open, M_NFSDSTATE); 2720 free((caddr_t)new_deleg, M_NFSDSTATE); 2721 printf("nfsd openctrl unexpected client cnfl\n"); 2722 goto out; 2723 } 2724 } 2725 } 2726 2727 /* 2728 * Check for a conflicting delegation. If one is found, call 2729 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2730 * been set yet, it will get the lock. Otherwise, it will recall 2731 * the delegation. Then, we try try again... 2732 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2733 * isn't a conflict.) 2734 * I currently believe the conflict algorithm to be: 2735 * For Open with Read Access and Deny None 2736 * - there is a conflict iff a different client has a write delegation 2737 * For Open with other Write Access or any Deny except None 2738 * - there is a conflict if a different client has any delegation 2739 * - there is a conflict if the same client has a read delegation 2740 * (The current consensus is that this last case should be 2741 * considered a conflict since the client with a read delegation 2742 * could have done an Open with ReadAccess and WriteDeny 2743 * locally and then not have checked for the WriteDeny.) 2744 */ 2745 if (!(new_stp->ls_flags & (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR))) { 2746 stp = LIST_FIRST(&lfp->lf_deleg); 2747 while (stp != NULL) { 2748 nstp = LIST_NEXT(stp, ls_file); 2749 if (stp->ls_clp != clp && (stp->ls_flags & NFSLCK_DELEGREAD)) 2750 writedeleg = 0; 2751 else 2752 delegate = 0; 2753 if ((readonly && stp->ls_clp != clp && 2754 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2755 (!readonly && (stp->ls_clp != clp || 2756 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 2757 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 2758 delegate = 2; 2759 } else { 2760 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2761 if (ret) { 2762 /* 2763 * nfsrv_delegconflict() unlocks state 2764 * when it returns non-zero. 2765 */ 2766 printf("Nfsd openctrl unexpected deleg cnfl\n"); 2767 free((caddr_t)new_open, M_NFSDSTATE); 2768 free((caddr_t)new_deleg, M_NFSDSTATE); 2769 if (ret == -1) { 2770 openstp = NULL; 2771 goto tryagain; 2772 } 2773 error = ret; 2774 goto out; 2775 } 2776 } 2777 } 2778 stp = nstp; 2779 } 2780 } 2781 2782 /* 2783 * We only get here if there was no open that conflicted. 2784 * If an open for the owner exists, or in the access/deny bits. 2785 * Otherwise it is a new open. If the open_owner hasn't been 2786 * confirmed, replace the open with the new one needing confirmation, 2787 * otherwise add the open. 2788 */ 2789 if (new_stp->ls_flags & NFSLCK_DELEGPREV) { 2790 /* 2791 * Handle NFSLCK_DELEGPREV by searching the old delegations for 2792 * a match. If found, just move the old delegation to the current 2793 * delegation list and issue open. If not found, return 2794 * NFSERR_EXPIRED. 2795 */ 2796 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 2797 if (stp->ls_lfp == lfp) { 2798 /* Found it */ 2799 if (stp->ls_clp != clp) 2800 panic("olddeleg clp"); 2801 LIST_REMOVE(stp, ls_list); 2802 LIST_REMOVE(stp, ls_hash); 2803 stp->ls_flags &= ~NFSLCK_OLDDELEG; 2804 stp->ls_stateid.seqid = delegstateidp->seqid = 1; 2805 stp->ls_stateid.other[0] = delegstateidp->other[0] = 2806 clp->lc_clientid.lval[0]; 2807 stp->ls_stateid.other[1] = delegstateidp->other[1] = 2808 clp->lc_clientid.lval[1]; 2809 stp->ls_stateid.other[2] = delegstateidp->other[2] = 2810 nfsrv_nextstateindex(clp); 2811 stp->ls_compref = nd->nd_compref; 2812 LIST_INSERT_HEAD(&clp->lc_deleg, stp, ls_list); 2813 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2814 stp->ls_stateid), stp, ls_hash); 2815 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2816 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2817 else 2818 *rflagsp |= NFSV4OPEN_READDELEGATE; 2819 clp->lc_delegtime = NFSD_MONOSEC + 2820 nfsrv_lease + NFSRV_LEASEDELTA; 2821 2822 /* 2823 * Now, do the associated open. 2824 */ 2825 new_open->ls_stateid.seqid = 1; 2826 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2827 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2828 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2829 new_open->ls_flags = (new_stp->ls_flags&NFSLCK_DENYBITS)| 2830 NFSLCK_OPEN; 2831 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2832 new_open->ls_flags |= (NFSLCK_READACCESS | 2833 NFSLCK_WRITEACCESS); 2834 else 2835 new_open->ls_flags |= NFSLCK_READACCESS; 2836 new_open->ls_uid = new_stp->ls_uid; 2837 new_open->ls_lfp = lfp; 2838 new_open->ls_clp = clp; 2839 LIST_INIT(&new_open->ls_open); 2840 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2841 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2842 new_open, ls_hash); 2843 /* 2844 * and handle the open owner 2845 */ 2846 if (ownerstp) { 2847 new_open->ls_openowner = ownerstp; 2848 LIST_INSERT_HEAD(&ownerstp->ls_open,new_open,ls_list); 2849 } else { 2850 new_open->ls_openowner = new_stp; 2851 new_stp->ls_flags = 0; 2852 nfsrvd_refcache(new_stp->ls_op); 2853 new_stp->ls_noopens = 0; 2854 LIST_INIT(&new_stp->ls_open); 2855 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2856 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2857 *new_stpp = NULL; 2858 nfsstatsv1.srvopenowners++; 2859 nfsrv_openpluslock++; 2860 } 2861 openstp = new_open; 2862 new_open = NULL; 2863 nfsstatsv1.srvopens++; 2864 nfsrv_openpluslock++; 2865 break; 2866 } 2867 } 2868 if (stp == NULL) 2869 error = NFSERR_EXPIRED; 2870 } else if (new_stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 2871 /* 2872 * Scan to see that no delegation for this client and file 2873 * doesn't already exist. 2874 * There also shouldn't yet be an Open for this file and 2875 * openowner. 2876 */ 2877 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2878 if (stp->ls_clp == clp) 2879 break; 2880 } 2881 if (stp == NULL && openstp == NULL) { 2882 /* 2883 * This is the Claim_Previous case with a delegation 2884 * type != Delegate_None. 2885 */ 2886 /* 2887 * First, add the delegation. (Although we must issue the 2888 * delegation, we can also ask for an immediate return.) 2889 */ 2890 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; 2891 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] = 2892 clp->lc_clientid.lval[0]; 2893 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] = 2894 clp->lc_clientid.lval[1]; 2895 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] = 2896 nfsrv_nextstateindex(clp); 2897 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) { 2898 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2899 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2900 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2901 } else { 2902 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 2903 NFSLCK_READACCESS); 2904 *rflagsp |= NFSV4OPEN_READDELEGATE; 2905 } 2906 new_deleg->ls_uid = new_stp->ls_uid; 2907 new_deleg->ls_lfp = lfp; 2908 new_deleg->ls_clp = clp; 2909 new_deleg->ls_filerev = filerev; 2910 new_deleg->ls_compref = nd->nd_compref; 2911 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2912 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2913 new_deleg->ls_stateid), new_deleg, ls_hash); 2914 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2915 new_deleg = NULL; 2916 if (delegate == 2 || nfsrv_issuedelegs == 0 || 2917 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != 2918 LCL_CALLBACKSON || 2919 NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) || 2920 !NFSVNO_DELEGOK(vp)) 2921 *rflagsp |= NFSV4OPEN_RECALL; 2922 nfsstatsv1.srvdelegates++; 2923 nfsrv_openpluslock++; 2924 nfsrv_delegatecnt++; 2925 2926 /* 2927 * Now, do the associated open. 2928 */ 2929 new_open->ls_stateid.seqid = 1; 2930 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2931 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2932 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2933 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_DENYBITS) | 2934 NFSLCK_OPEN; 2935 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) 2936 new_open->ls_flags |= (NFSLCK_READACCESS | 2937 NFSLCK_WRITEACCESS); 2938 else 2939 new_open->ls_flags |= NFSLCK_READACCESS; 2940 new_open->ls_uid = new_stp->ls_uid; 2941 new_open->ls_lfp = lfp; 2942 new_open->ls_clp = clp; 2943 LIST_INIT(&new_open->ls_open); 2944 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2945 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2946 new_open, ls_hash); 2947 /* 2948 * and handle the open owner 2949 */ 2950 if (ownerstp) { 2951 new_open->ls_openowner = ownerstp; 2952 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 2953 } else { 2954 new_open->ls_openowner = new_stp; 2955 new_stp->ls_flags = 0; 2956 nfsrvd_refcache(new_stp->ls_op); 2957 new_stp->ls_noopens = 0; 2958 LIST_INIT(&new_stp->ls_open); 2959 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2960 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2961 *new_stpp = NULL; 2962 nfsstatsv1.srvopenowners++; 2963 nfsrv_openpluslock++; 2964 } 2965 openstp = new_open; 2966 new_open = NULL; 2967 nfsstatsv1.srvopens++; 2968 nfsrv_openpluslock++; 2969 } else { 2970 error = NFSERR_RECLAIMCONFLICT; 2971 } 2972 } else if (ownerstp) { 2973 if (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM) { 2974 /* Replace the open */ 2975 if (ownerstp->ls_op) 2976 nfsrvd_derefcache(ownerstp->ls_op); 2977 ownerstp->ls_op = new_stp->ls_op; 2978 nfsrvd_refcache(ownerstp->ls_op); 2979 ownerstp->ls_seq = new_stp->ls_seq; 2980 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 2981 stp = LIST_FIRST(&ownerstp->ls_open); 2982 stp->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 2983 NFSLCK_OPEN; 2984 stp->ls_stateid.seqid = 1; 2985 stp->ls_uid = new_stp->ls_uid; 2986 if (lfp != stp->ls_lfp) { 2987 LIST_REMOVE(stp, ls_file); 2988 LIST_INSERT_HEAD(&lfp->lf_open, stp, ls_file); 2989 stp->ls_lfp = lfp; 2990 } 2991 openstp = stp; 2992 } else if (openstp) { 2993 openstp->ls_flags |= (new_stp->ls_flags & NFSLCK_SHAREBITS); 2994 openstp->ls_stateid.seqid++; 2995 if ((nd->nd_flag & ND_NFSV41) != 0 && 2996 openstp->ls_stateid.seqid == 0) 2997 openstp->ls_stateid.seqid = 1; 2998 2999 /* 3000 * This is where we can choose to issue a delegation. 3001 */ 3002 if (delegate == 0 || writedeleg == 0 || 3003 NFSVNO_EXRDONLY(exp) || (readonly != 0 && 3004 nfsrv_writedelegifpos == 0) || 3005 !NFSVNO_DELEGOK(vp) || 3006 (new_stp->ls_flags & NFSLCK_WANTRDELEG) != 0 || 3007 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != 3008 LCL_CALLBACKSON) 3009 *rflagsp |= NFSV4OPEN_WDCONTENTION; 3010 else if (nfsrv_issuedelegs == 0 || 3011 NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt)) 3012 *rflagsp |= NFSV4OPEN_WDRESOURCE; 3013 else if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0) 3014 *rflagsp |= NFSV4OPEN_WDNOTWANTED; 3015 else { 3016 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; 3017 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 3018 = clp->lc_clientid.lval[0]; 3019 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 3020 = clp->lc_clientid.lval[1]; 3021 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 3022 = nfsrv_nextstateindex(clp); 3023 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 3024 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 3025 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 3026 new_deleg->ls_uid = new_stp->ls_uid; 3027 new_deleg->ls_lfp = lfp; 3028 new_deleg->ls_clp = clp; 3029 new_deleg->ls_filerev = filerev; 3030 new_deleg->ls_compref = nd->nd_compref; 3031 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 3032 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 3033 new_deleg->ls_stateid), new_deleg, ls_hash); 3034 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 3035 new_deleg = NULL; 3036 nfsstatsv1.srvdelegates++; 3037 nfsrv_openpluslock++; 3038 nfsrv_delegatecnt++; 3039 } 3040 } else { 3041 new_open->ls_stateid.seqid = 1; 3042 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 3043 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 3044 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 3045 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS)| 3046 NFSLCK_OPEN; 3047 new_open->ls_uid = new_stp->ls_uid; 3048 new_open->ls_openowner = ownerstp; 3049 new_open->ls_lfp = lfp; 3050 new_open->ls_clp = clp; 3051 LIST_INIT(&new_open->ls_open); 3052 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 3053 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 3054 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 3055 new_open, ls_hash); 3056 openstp = new_open; 3057 new_open = NULL; 3058 nfsstatsv1.srvopens++; 3059 nfsrv_openpluslock++; 3060 3061 /* 3062 * This is where we can choose to issue a delegation. 3063 */ 3064 if (delegate == 0 || (writedeleg == 0 && readonly == 0) || 3065 !NFSVNO_DELEGOK(vp) || 3066 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != 3067 LCL_CALLBACKSON) 3068 *rflagsp |= NFSV4OPEN_WDCONTENTION; 3069 else if (nfsrv_issuedelegs == 0 || 3070 NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt)) 3071 *rflagsp |= NFSV4OPEN_WDRESOURCE; 3072 else if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0) 3073 *rflagsp |= NFSV4OPEN_WDNOTWANTED; 3074 else { 3075 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; 3076 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 3077 = clp->lc_clientid.lval[0]; 3078 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 3079 = clp->lc_clientid.lval[1]; 3080 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 3081 = nfsrv_nextstateindex(clp); 3082 if (writedeleg && !NFSVNO_EXRDONLY(exp) && 3083 (nfsrv_writedelegifpos || !readonly) && 3084 (new_stp->ls_flags & NFSLCK_WANTRDELEG) == 0) { 3085 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 3086 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 3087 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 3088 } else { 3089 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 3090 NFSLCK_READACCESS); 3091 *rflagsp |= NFSV4OPEN_READDELEGATE; 3092 } 3093 new_deleg->ls_uid = new_stp->ls_uid; 3094 new_deleg->ls_lfp = lfp; 3095 new_deleg->ls_clp = clp; 3096 new_deleg->ls_filerev = filerev; 3097 new_deleg->ls_compref = nd->nd_compref; 3098 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 3099 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 3100 new_deleg->ls_stateid), new_deleg, ls_hash); 3101 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 3102 new_deleg = NULL; 3103 nfsstatsv1.srvdelegates++; 3104 nfsrv_openpluslock++; 3105 nfsrv_delegatecnt++; 3106 } 3107 } 3108 } else { 3109 /* 3110 * New owner case. Start the open_owner sequence with a 3111 * Needs confirmation (unless a reclaim) and hang the 3112 * new open off it. 3113 */ 3114 new_open->ls_stateid.seqid = 1; 3115 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 3116 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 3117 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 3118 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 3119 NFSLCK_OPEN; 3120 new_open->ls_uid = new_stp->ls_uid; 3121 LIST_INIT(&new_open->ls_open); 3122 new_open->ls_openowner = new_stp; 3123 new_open->ls_lfp = lfp; 3124 new_open->ls_clp = clp; 3125 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 3126 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 3127 new_stp->ls_flags = 0; 3128 } else if ((nd->nd_flag & ND_NFSV41) != 0) { 3129 /* NFSv4.1 never needs confirmation. */ 3130 new_stp->ls_flags = 0; 3131 3132 /* 3133 * This is where we can choose to issue a delegation. 3134 */ 3135 if (delegate && nfsrv_issuedelegs && 3136 (writedeleg || readonly) && 3137 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == 3138 LCL_CALLBACKSON && 3139 !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && 3140 NFSVNO_DELEGOK(vp) && 3141 ((nd->nd_flag & ND_NFSV41) == 0 || 3142 (new_stp->ls_flags & NFSLCK_WANTNODELEG) == 0)) { 3143 new_deleg->ls_stateid.seqid = 3144 delegstateidp->seqid = 1; 3145 new_deleg->ls_stateid.other[0] = 3146 delegstateidp->other[0] 3147 = clp->lc_clientid.lval[0]; 3148 new_deleg->ls_stateid.other[1] = 3149 delegstateidp->other[1] 3150 = clp->lc_clientid.lval[1]; 3151 new_deleg->ls_stateid.other[2] = 3152 delegstateidp->other[2] 3153 = nfsrv_nextstateindex(clp); 3154 if (writedeleg && !NFSVNO_EXRDONLY(exp) && 3155 (nfsrv_writedelegifpos || !readonly) && 3156 ((nd->nd_flag & ND_NFSV41) == 0 || 3157 (new_stp->ls_flags & NFSLCK_WANTRDELEG) == 3158 0)) { 3159 new_deleg->ls_flags = 3160 (NFSLCK_DELEGWRITE | 3161 NFSLCK_READACCESS | 3162 NFSLCK_WRITEACCESS); 3163 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 3164 } else { 3165 new_deleg->ls_flags = 3166 (NFSLCK_DELEGREAD | 3167 NFSLCK_READACCESS); 3168 *rflagsp |= NFSV4OPEN_READDELEGATE; 3169 } 3170 new_deleg->ls_uid = new_stp->ls_uid; 3171 new_deleg->ls_lfp = lfp; 3172 new_deleg->ls_clp = clp; 3173 new_deleg->ls_filerev = filerev; 3174 new_deleg->ls_compref = nd->nd_compref; 3175 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, 3176 ls_file); 3177 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 3178 new_deleg->ls_stateid), new_deleg, ls_hash); 3179 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, 3180 ls_list); 3181 new_deleg = NULL; 3182 nfsstatsv1.srvdelegates++; 3183 nfsrv_openpluslock++; 3184 nfsrv_delegatecnt++; 3185 } 3186 } else { 3187 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 3188 new_stp->ls_flags = NFSLCK_NEEDSCONFIRM; 3189 } 3190 nfsrvd_refcache(new_stp->ls_op); 3191 new_stp->ls_noopens = 0; 3192 LIST_INIT(&new_stp->ls_open); 3193 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 3194 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 3195 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 3196 new_open, ls_hash); 3197 openstp = new_open; 3198 new_open = NULL; 3199 *new_stpp = NULL; 3200 nfsstatsv1.srvopens++; 3201 nfsrv_openpluslock++; 3202 nfsstatsv1.srvopenowners++; 3203 nfsrv_openpluslock++; 3204 } 3205 if (!error) { 3206 stateidp->seqid = openstp->ls_stateid.seqid; 3207 stateidp->other[0] = openstp->ls_stateid.other[0]; 3208 stateidp->other[1] = openstp->ls_stateid.other[1]; 3209 stateidp->other[2] = openstp->ls_stateid.other[2]; 3210 } 3211 NFSUNLOCKSTATE(); 3212 if (haslock) { 3213 NFSLOCKV4ROOTMUTEX(); 3214 nfsv4_unlock(&nfsv4rootfs_lock, 1); 3215 NFSUNLOCKV4ROOTMUTEX(); 3216 } 3217 if (new_open) 3218 FREE((caddr_t)new_open, M_NFSDSTATE); 3219 if (new_deleg) 3220 FREE((caddr_t)new_deleg, M_NFSDSTATE); 3221 3222out: 3223 NFSEXITCODE2(error, nd); 3224 return (error); 3225} 3226 3227/* 3228 * Open update. Does the confirm, downgrade and close. 3229 */ 3230APPLESTATIC int 3231nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid, 3232 nfsv4stateid_t *stateidp, struct nfsrv_descript *nd, NFSPROC_T *p) 3233{ 3234 struct nfsstate *stp, *ownerstp; 3235 struct nfsclient *clp; 3236 struct nfslockfile *lfp; 3237 u_int32_t bits; 3238 int error = 0, gotstate = 0, len = 0; 3239 u_char client[NFSV4_OPAQUELIMIT]; 3240 3241 /* 3242 * Check for restart conditions (client and server). 3243 */ 3244 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 3245 &new_stp->ls_stateid, 0); 3246 if (error) 3247 goto out; 3248 3249 NFSLOCKSTATE(); 3250 /* 3251 * Get the open structure via clientid and stateid. 3252 */ 3253 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 3254 (nfsquad_t)((u_quad_t)0), 0, nd, p); 3255 if (!error) 3256 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 3257 new_stp->ls_flags, &stp); 3258 3259 /* 3260 * Sanity check the open. 3261 */ 3262 if (!error && (!(stp->ls_flags & NFSLCK_OPEN) || 3263 (!(new_stp->ls_flags & NFSLCK_CONFIRM) && 3264 (stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) || 3265 ((new_stp->ls_flags & NFSLCK_CONFIRM) && 3266 (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM))))) 3267 error = NFSERR_BADSTATEID; 3268 3269 if (!error) 3270 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 3271 stp->ls_openowner, new_stp->ls_op); 3272 if (!error && stp->ls_stateid.seqid != new_stp->ls_stateid.seqid && 3273 (((nd->nd_flag & ND_NFSV41) == 0 && 3274 !(new_stp->ls_flags & NFSLCK_CONFIRM)) || 3275 ((nd->nd_flag & ND_NFSV41) != 0 && 3276 new_stp->ls_stateid.seqid != 0))) 3277 error = NFSERR_OLDSTATEID; 3278 if (!error && vnode_vtype(vp) != VREG) { 3279 if (vnode_vtype(vp) == VDIR) 3280 error = NFSERR_ISDIR; 3281 else 3282 error = NFSERR_INVAL; 3283 } 3284 3285 if (error) { 3286 /* 3287 * If a client tries to confirm an Open with a bad 3288 * seqid# and there are no byte range locks or other Opens 3289 * on the openowner, just throw it away, so the next use of the 3290 * openowner will start a fresh seq#. 3291 */ 3292 if (error == NFSERR_BADSEQID && 3293 (new_stp->ls_flags & NFSLCK_CONFIRM) && 3294 nfsrv_nootherstate(stp)) 3295 nfsrv_freeopenowner(stp->ls_openowner, 0, p); 3296 NFSUNLOCKSTATE(); 3297 goto out; 3298 } 3299 3300 /* 3301 * Set the return stateid. 3302 */ 3303 stateidp->seqid = stp->ls_stateid.seqid + 1; 3304 if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0) 3305 stateidp->seqid = 1; 3306 stateidp->other[0] = stp->ls_stateid.other[0]; 3307 stateidp->other[1] = stp->ls_stateid.other[1]; 3308 stateidp->other[2] = stp->ls_stateid.other[2]; 3309 /* 3310 * Now, handle the three cases. 3311 */ 3312 if (new_stp->ls_flags & NFSLCK_CONFIRM) { 3313 /* 3314 * If the open doesn't need confirmation, it seems to me that 3315 * there is a client error, but I'll just log it and keep going? 3316 */ 3317 if (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) 3318 printf("Nfsv4d: stray open confirm\n"); 3319 stp->ls_openowner->ls_flags = 0; 3320 stp->ls_stateid.seqid++; 3321 if ((nd->nd_flag & ND_NFSV41) != 0 && 3322 stp->ls_stateid.seqid == 0) 3323 stp->ls_stateid.seqid = 1; 3324 if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) { 3325 clp->lc_flags |= LCL_STAMPEDSTABLE; 3326 len = clp->lc_idlen; 3327 NFSBCOPY(clp->lc_id, client, len); 3328 gotstate = 1; 3329 } 3330 NFSUNLOCKSTATE(); 3331 } else if (new_stp->ls_flags & NFSLCK_CLOSE) { 3332 ownerstp = stp->ls_openowner; 3333 lfp = stp->ls_lfp; 3334 if (nfsrv_dolocallocks != 0 && !LIST_EMPTY(&stp->ls_open)) { 3335 /* Get the lf lock */ 3336 nfsrv_locklf(lfp); 3337 NFSUNLOCKSTATE(); 3338 ASSERT_VOP_ELOCKED(vp, "nfsrv_openupdate"); 3339 NFSVOPUNLOCK(vp, 0); 3340 if (nfsrv_freeopen(stp, vp, 1, p) == 0) { 3341 NFSLOCKSTATE(); 3342 nfsrv_unlocklf(lfp); 3343 NFSUNLOCKSTATE(); 3344 } 3345 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3346 } else { 3347 (void) nfsrv_freeopen(stp, NULL, 0, p); 3348 NFSUNLOCKSTATE(); 3349 } 3350 } else { 3351 /* 3352 * Update the share bits, making sure that the new set are a 3353 * subset of the old ones. 3354 */ 3355 bits = (new_stp->ls_flags & NFSLCK_SHAREBITS); 3356 if (~(stp->ls_flags) & bits) { 3357 NFSUNLOCKSTATE(); 3358 error = NFSERR_INVAL; 3359 goto out; 3360 } 3361 stp->ls_flags = (bits | NFSLCK_OPEN); 3362 stp->ls_stateid.seqid++; 3363 if ((nd->nd_flag & ND_NFSV41) != 0 && 3364 stp->ls_stateid.seqid == 0) 3365 stp->ls_stateid.seqid = 1; 3366 NFSUNLOCKSTATE(); 3367 } 3368 3369 /* 3370 * If the client just confirmed its first open, write a timestamp 3371 * to the stable storage file. 3372 */ 3373 if (gotstate != 0) { 3374 nfsrv_writestable(client, len, NFSNST_NEWSTATE, p); 3375 nfsrv_backupstable(); 3376 } 3377 3378out: 3379 NFSEXITCODE2(error, nd); 3380 return (error); 3381} 3382 3383/* 3384 * Delegation update. Does the purge and return. 3385 */ 3386APPLESTATIC int 3387nfsrv_delegupdate(struct nfsrv_descript *nd, nfsquad_t clientid, 3388 nfsv4stateid_t *stateidp, vnode_t vp, int op, struct ucred *cred, 3389 NFSPROC_T *p) 3390{ 3391 struct nfsstate *stp; 3392 struct nfsclient *clp; 3393 int error = 0; 3394 fhandle_t fh; 3395 3396 /* 3397 * Do a sanity check against the file handle for DelegReturn. 3398 */ 3399 if (vp) { 3400 error = nfsvno_getfh(vp, &fh, p); 3401 if (error) 3402 goto out; 3403 } 3404 /* 3405 * Check for restart conditions (client and server). 3406 */ 3407 if (op == NFSV4OP_DELEGRETURN) 3408 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGRETURN, 3409 stateidp, 0); 3410 else 3411 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGPURGE, 3412 stateidp, 0); 3413 3414 NFSLOCKSTATE(); 3415 /* 3416 * Get the open structure via clientid and stateid. 3417 */ 3418 if (!error) 3419 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 3420 (nfsquad_t)((u_quad_t)0), 0, nd, p); 3421 if (error) { 3422 if (error == NFSERR_CBPATHDOWN) 3423 error = 0; 3424 if (error == NFSERR_STALECLIENTID && op == NFSV4OP_DELEGRETURN) 3425 error = NFSERR_STALESTATEID; 3426 } 3427 if (!error && op == NFSV4OP_DELEGRETURN) { 3428 error = nfsrv_getstate(clp, stateidp, NFSLCK_DELEGRETURN, &stp); 3429 if (!error && stp->ls_stateid.seqid != stateidp->seqid && 3430 ((nd->nd_flag & ND_NFSV41) == 0 || stateidp->seqid != 0)) 3431 error = NFSERR_OLDSTATEID; 3432 } 3433 /* 3434 * NFSERR_EXPIRED means that the state has gone away, 3435 * so Delegations have been purged. Just return ok. 3436 */ 3437 if (error == NFSERR_EXPIRED && op == NFSV4OP_DELEGPURGE) { 3438 NFSUNLOCKSTATE(); 3439 error = 0; 3440 goto out; 3441 } 3442 if (error) { 3443 NFSUNLOCKSTATE(); 3444 goto out; 3445 } 3446 3447 if (op == NFSV4OP_DELEGRETURN) { 3448 if (NFSBCMP((caddr_t)&fh, (caddr_t)&stp->ls_lfp->lf_fh, 3449 sizeof (fhandle_t))) { 3450 NFSUNLOCKSTATE(); 3451 error = NFSERR_BADSTATEID; 3452 goto out; 3453 } 3454 nfsrv_freedeleg(stp); 3455 } else { 3456 nfsrv_freedeleglist(&clp->lc_olddeleg); 3457 } 3458 NFSUNLOCKSTATE(); 3459 error = 0; 3460 3461out: 3462 NFSEXITCODE(error); 3463 return (error); 3464} 3465 3466/* 3467 * Release lock owner. 3468 */ 3469APPLESTATIC int 3470nfsrv_releaselckown(struct nfsstate *new_stp, nfsquad_t clientid, 3471 NFSPROC_T *p) 3472{ 3473 struct nfsstate *stp, *nstp, *openstp, *ownstp; 3474 struct nfsclient *clp; 3475 int error = 0; 3476 3477 /* 3478 * Check for restart conditions (client and server). 3479 */ 3480 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 3481 &new_stp->ls_stateid, 0); 3482 if (error) 3483 goto out; 3484 3485 NFSLOCKSTATE(); 3486 /* 3487 * Get the lock owner by name. 3488 */ 3489 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL, 3490 (nfsquad_t)((u_quad_t)0), 0, NULL, p); 3491 if (error) { 3492 NFSUNLOCKSTATE(); 3493 goto out; 3494 } 3495 LIST_FOREACH(ownstp, &clp->lc_open, ls_list) { 3496 LIST_FOREACH(openstp, &ownstp->ls_open, ls_list) { 3497 stp = LIST_FIRST(&openstp->ls_open); 3498 while (stp != NULL) { 3499 nstp = LIST_NEXT(stp, ls_list); 3500 /* 3501 * If the owner matches, check for locks and 3502 * then free or return an error. 3503 */ 3504 if (stp->ls_ownerlen == new_stp->ls_ownerlen && 3505 !NFSBCMP(stp->ls_owner, new_stp->ls_owner, 3506 stp->ls_ownerlen)){ 3507 if (LIST_EMPTY(&stp->ls_lock)) { 3508 nfsrv_freelockowner(stp, NULL, 0, p); 3509 } else { 3510 NFSUNLOCKSTATE(); 3511 error = NFSERR_LOCKSHELD; 3512 goto out; 3513 } 3514 } 3515 stp = nstp; 3516 } 3517 } 3518 } 3519 NFSUNLOCKSTATE(); 3520 3521out: 3522 NFSEXITCODE(error); 3523 return (error); 3524} 3525 3526/* 3527 * Get the file handle for a lock structure. 3528 */ 3529static int 3530nfsrv_getlockfh(vnode_t vp, u_short flags, struct nfslockfile *new_lfp, 3531 fhandle_t *nfhp, NFSPROC_T *p) 3532{ 3533 fhandle_t *fhp = NULL; 3534 int error; 3535 3536 /* 3537 * For lock, use the new nfslock structure, otherwise just 3538 * a fhandle_t on the stack. 3539 */ 3540 if (flags & NFSLCK_OPEN) { 3541 KASSERT(new_lfp != NULL, ("nfsrv_getlockfh: new_lfp NULL")); 3542 fhp = &new_lfp->lf_fh; 3543 } else if (nfhp) { 3544 fhp = nfhp; 3545 } else { 3546 panic("nfsrv_getlockfh"); 3547 } 3548 error = nfsvno_getfh(vp, fhp, p); 3549 NFSEXITCODE(error); 3550 return (error); 3551} 3552 3553/* 3554 * Get an nfs lock structure. Allocate one, as required, and return a 3555 * pointer to it. 3556 * Returns an NFSERR_xxx upon failure or -1 to indicate no current lock. 3557 */ 3558static int 3559nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 3560 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit) 3561{ 3562 struct nfslockfile *lfp; 3563 fhandle_t *fhp = NULL, *tfhp; 3564 struct nfslockhashhead *hp; 3565 struct nfslockfile *new_lfp = NULL; 3566 3567 /* 3568 * For lock, use the new nfslock structure, otherwise just 3569 * a fhandle_t on the stack. 3570 */ 3571 if (flags & NFSLCK_OPEN) { 3572 new_lfp = *new_lfpp; 3573 fhp = &new_lfp->lf_fh; 3574 } else if (nfhp) { 3575 fhp = nfhp; 3576 } else { 3577 panic("nfsrv_getlockfile"); 3578 } 3579 3580 hp = NFSLOCKHASH(fhp); 3581 LIST_FOREACH(lfp, hp, lf_hash) { 3582 tfhp = &lfp->lf_fh; 3583 if (NFSVNO_CMPFH(fhp, tfhp)) { 3584 if (lockit) 3585 nfsrv_locklf(lfp); 3586 *lfpp = lfp; 3587 return (0); 3588 } 3589 } 3590 if (!(flags & NFSLCK_OPEN)) 3591 return (-1); 3592 3593 /* 3594 * No match, so chain the new one into the list. 3595 */ 3596 LIST_INIT(&new_lfp->lf_open); 3597 LIST_INIT(&new_lfp->lf_lock); 3598 LIST_INIT(&new_lfp->lf_deleg); 3599 LIST_INIT(&new_lfp->lf_locallock); 3600 LIST_INIT(&new_lfp->lf_rollback); 3601 new_lfp->lf_locallock_lck.nfslock_usecnt = 0; 3602 new_lfp->lf_locallock_lck.nfslock_lock = 0; 3603 new_lfp->lf_usecount = 0; 3604 LIST_INSERT_HEAD(hp, new_lfp, lf_hash); 3605 *lfpp = new_lfp; 3606 *new_lfpp = NULL; 3607 return (0); 3608} 3609 3610/* 3611 * This function adds a nfslock lock structure to the list for the associated 3612 * nfsstate and nfslockfile structures. It will be inserted after the 3613 * entry pointed at by insert_lop. 3614 */ 3615static void 3616nfsrv_insertlock(struct nfslock *new_lop, struct nfslock *insert_lop, 3617 struct nfsstate *stp, struct nfslockfile *lfp) 3618{ 3619 struct nfslock *lop, *nlop; 3620 3621 new_lop->lo_stp = stp; 3622 new_lop->lo_lfp = lfp; 3623 3624 if (stp != NULL) { 3625 /* Insert in increasing lo_first order */ 3626 lop = LIST_FIRST(&lfp->lf_lock); 3627 if (lop == NULL || 3628 new_lop->lo_first <= lop->lo_first) { 3629 LIST_INSERT_HEAD(&lfp->lf_lock, new_lop, lo_lckfile); 3630 } else { 3631 nlop = LIST_NEXT(lop, lo_lckfile); 3632 while (nlop != NULL && 3633 nlop->lo_first < new_lop->lo_first) { 3634 lop = nlop; 3635 nlop = LIST_NEXT(lop, lo_lckfile); 3636 } 3637 LIST_INSERT_AFTER(lop, new_lop, lo_lckfile); 3638 } 3639 } else { 3640 new_lop->lo_lckfile.le_prev = NULL; /* list not used */ 3641 } 3642 3643 /* 3644 * Insert after insert_lop, which is overloaded as stp or lfp for 3645 * an empty list. 3646 */ 3647 if (stp == NULL && (struct nfslockfile *)insert_lop == lfp) 3648 LIST_INSERT_HEAD(&lfp->lf_locallock, new_lop, lo_lckowner); 3649 else if ((struct nfsstate *)insert_lop == stp) 3650 LIST_INSERT_HEAD(&stp->ls_lock, new_lop, lo_lckowner); 3651 else 3652 LIST_INSERT_AFTER(insert_lop, new_lop, lo_lckowner); 3653 if (stp != NULL) { 3654 nfsstatsv1.srvlocks++; 3655 nfsrv_openpluslock++; 3656 } 3657} 3658 3659/* 3660 * This function updates the locking for a lock owner and given file. It 3661 * maintains a list of lock ranges ordered on increasing file offset that 3662 * are NFSLCK_READ or NFSLCK_WRITE and non-overlapping (aka POSIX style). 3663 * It always adds new_lop to the list and sometimes uses the one pointed 3664 * at by other_lopp. 3665 */ 3666static void 3667nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 3668 struct nfslock **other_lopp, struct nfslockfile *lfp) 3669{ 3670 struct nfslock *new_lop = *new_lopp; 3671 struct nfslock *lop, *tlop, *ilop; 3672 struct nfslock *other_lop = *other_lopp; 3673 int unlock = 0, myfile = 0; 3674 u_int64_t tmp; 3675 3676 /* 3677 * Work down the list until the lock is merged. 3678 */ 3679 if (new_lop->lo_flags & NFSLCK_UNLOCK) 3680 unlock = 1; 3681 if (stp != NULL) { 3682 ilop = (struct nfslock *)stp; 3683 lop = LIST_FIRST(&stp->ls_lock); 3684 } else { 3685 ilop = (struct nfslock *)lfp; 3686 lop = LIST_FIRST(&lfp->lf_locallock); 3687 } 3688 while (lop != NULL) { 3689 /* 3690 * Only check locks for this file that aren't before the start of 3691 * new lock's range. 3692 */ 3693 if (lop->lo_lfp == lfp) { 3694 myfile = 1; 3695 if (lop->lo_end >= new_lop->lo_first) { 3696 if (new_lop->lo_end < lop->lo_first) { 3697 /* 3698 * If the new lock ends before the start of the 3699 * current lock's range, no merge, just insert 3700 * the new lock. 3701 */ 3702 break; 3703 } 3704 if (new_lop->lo_flags == lop->lo_flags || 3705 (new_lop->lo_first <= lop->lo_first && 3706 new_lop->lo_end >= lop->lo_end)) { 3707 /* 3708 * This lock can be absorbed by the new lock/unlock. 3709 * This happens when it covers the entire range 3710 * of the old lock or is contiguous 3711 * with the old lock and is of the same type or an 3712 * unlock. 3713 */ 3714 if (lop->lo_first < new_lop->lo_first) 3715 new_lop->lo_first = lop->lo_first; 3716 if (lop->lo_end > new_lop->lo_end) 3717 new_lop->lo_end = lop->lo_end; 3718 tlop = lop; 3719 lop = LIST_NEXT(lop, lo_lckowner); 3720 nfsrv_freenfslock(tlop); 3721 continue; 3722 } 3723 3724 /* 3725 * All these cases are for contiguous locks that are not the 3726 * same type, so they can't be merged. 3727 */ 3728 if (new_lop->lo_first <= lop->lo_first) { 3729 /* 3730 * This case is where the new lock overlaps with the 3731 * first part of the old lock. Move the start of the 3732 * old lock to just past the end of the new lock. The 3733 * new lock will be inserted in front of the old, since 3734 * ilop hasn't been updated. (We are done now.) 3735 */ 3736 lop->lo_first = new_lop->lo_end; 3737 break; 3738 } 3739 if (new_lop->lo_end >= lop->lo_end) { 3740 /* 3741 * This case is where the new lock overlaps with the 3742 * end of the old lock's range. Move the old lock's 3743 * end to just before the new lock's first and insert 3744 * the new lock after the old lock. 3745 * Might not be done yet, since the new lock could 3746 * overlap further locks with higher ranges. 3747 */ 3748 lop->lo_end = new_lop->lo_first; 3749 ilop = lop; 3750 lop = LIST_NEXT(lop, lo_lckowner); 3751 continue; 3752 } 3753 /* 3754 * The final case is where the new lock's range is in the 3755 * middle of the current lock's and splits the current lock 3756 * up. Use *other_lopp to handle the second part of the 3757 * split old lock range. (We are done now.) 3758 * For unlock, we use new_lop as other_lop and tmp, since 3759 * other_lop and new_lop are the same for this case. 3760 * We noted the unlock case above, so we don't need 3761 * new_lop->lo_flags any longer. 3762 */ 3763 tmp = new_lop->lo_first; 3764 if (other_lop == NULL) { 3765 if (!unlock) 3766 panic("nfsd srv update unlock"); 3767 other_lop = new_lop; 3768 *new_lopp = NULL; 3769 } 3770 other_lop->lo_first = new_lop->lo_end; 3771 other_lop->lo_end = lop->lo_end; 3772 other_lop->lo_flags = lop->lo_flags; 3773 other_lop->lo_stp = stp; 3774 other_lop->lo_lfp = lfp; 3775 lop->lo_end = tmp; 3776 nfsrv_insertlock(other_lop, lop, stp, lfp); 3777 *other_lopp = NULL; 3778 ilop = lop; 3779 break; 3780 } 3781 } 3782 ilop = lop; 3783 lop = LIST_NEXT(lop, lo_lckowner); 3784 if (myfile && (lop == NULL || lop->lo_lfp != lfp)) 3785 break; 3786 } 3787 3788 /* 3789 * Insert the new lock in the list at the appropriate place. 3790 */ 3791 if (!unlock) { 3792 nfsrv_insertlock(new_lop, ilop, stp, lfp); 3793 *new_lopp = NULL; 3794 } 3795} 3796 3797/* 3798 * This function handles sequencing of locks, etc. 3799 * It returns an error that indicates what the caller should do. 3800 */ 3801static int 3802nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 3803 struct nfsstate *stp, struct nfsrvcache *op) 3804{ 3805 int error = 0; 3806 3807 if ((nd->nd_flag & ND_NFSV41) != 0) 3808 /* NFSv4.1 ignores the open_seqid and lock_seqid. */ 3809 goto out; 3810 if (op != nd->nd_rp) 3811 panic("nfsrvstate checkseqid"); 3812 if (!(op->rc_flag & RC_INPROG)) 3813 panic("nfsrvstate not inprog"); 3814 if (stp->ls_op && stp->ls_op->rc_refcnt <= 0) { 3815 printf("refcnt=%d\n", stp->ls_op->rc_refcnt); 3816 panic("nfsrvstate op refcnt"); 3817 } 3818 if ((stp->ls_seq + 1) == seqid) { 3819 if (stp->ls_op) 3820 nfsrvd_derefcache(stp->ls_op); 3821 stp->ls_op = op; 3822 nfsrvd_refcache(op); 3823 stp->ls_seq = seqid; 3824 goto out; 3825 } else if (stp->ls_seq == seqid && stp->ls_op && 3826 op->rc_xid == stp->ls_op->rc_xid && 3827 op->rc_refcnt == 0 && 3828 op->rc_reqlen == stp->ls_op->rc_reqlen && 3829 op->rc_cksum == stp->ls_op->rc_cksum) { 3830 if (stp->ls_op->rc_flag & RC_INPROG) { 3831 error = NFSERR_DONTREPLY; 3832 goto out; 3833 } 3834 nd->nd_rp = stp->ls_op; 3835 nd->nd_rp->rc_flag |= RC_INPROG; 3836 nfsrvd_delcache(op); 3837 error = NFSERR_REPLYFROMCACHE; 3838 goto out; 3839 } 3840 error = NFSERR_BADSEQID; 3841 3842out: 3843 NFSEXITCODE2(error, nd); 3844 return (error); 3845} 3846 3847/* 3848 * Get the client ip address for callbacks. If the strings can't be parsed, 3849 * just set lc_program to 0 to indicate no callbacks are possible. 3850 * (For cases where the address can't be parsed or is 0.0.0.0.0.0, set 3851 * the address to the client's transport address. This won't be used 3852 * for callbacks, but can be printed out by nfsstats for info.) 3853 * Return error if the xdr can't be parsed, 0 otherwise. 3854 */ 3855APPLESTATIC int 3856nfsrv_getclientipaddr(struct nfsrv_descript *nd, struct nfsclient *clp) 3857{ 3858 u_int32_t *tl; 3859 u_char *cp, *cp2; 3860 int i, j; 3861 struct sockaddr_in *rad, *sad; 3862 u_char protocol[5], addr[24]; 3863 int error = 0, cantparse = 0; 3864 union { 3865 u_long ival; 3866 u_char cval[4]; 3867 } ip; 3868 union { 3869 u_short sval; 3870 u_char cval[2]; 3871 } port; 3872 3873 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3874 rad->sin_family = AF_INET; 3875 rad->sin_len = sizeof (struct sockaddr_in); 3876 rad->sin_addr.s_addr = 0; 3877 rad->sin_port = 0; 3878 clp->lc_req.nr_client = NULL; 3879 clp->lc_req.nr_lock = 0; 3880 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3881 i = fxdr_unsigned(int, *tl); 3882 if (i >= 3 && i <= 4) { 3883 error = nfsrv_mtostr(nd, protocol, i); 3884 if (error) 3885 goto nfsmout; 3886 if (!strcmp(protocol, "tcp")) { 3887 clp->lc_flags |= LCL_TCPCALLBACK; 3888 clp->lc_req.nr_sotype = SOCK_STREAM; 3889 clp->lc_req.nr_soproto = IPPROTO_TCP; 3890 } else if (!strcmp(protocol, "udp")) { 3891 clp->lc_req.nr_sotype = SOCK_DGRAM; 3892 clp->lc_req.nr_soproto = IPPROTO_UDP; 3893 } else { 3894 cantparse = 1; 3895 } 3896 } else { 3897 cantparse = 1; 3898 if (i > 0) { 3899 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3900 if (error) 3901 goto nfsmout; 3902 } 3903 } 3904 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3905 i = fxdr_unsigned(int, *tl); 3906 if (i < 0) { 3907 error = NFSERR_BADXDR; 3908 goto nfsmout; 3909 } else if (i == 0) { 3910 cantparse = 1; 3911 } else if (!cantparse && i <= 23 && i >= 11) { 3912 error = nfsrv_mtostr(nd, addr, i); 3913 if (error) 3914 goto nfsmout; 3915 3916 /* 3917 * Parse out the address fields. We expect 6 decimal numbers 3918 * separated by '.'s. 3919 */ 3920 cp = addr; 3921 i = 0; 3922 while (*cp && i < 6) { 3923 cp2 = cp; 3924 while (*cp2 && *cp2 != '.') 3925 cp2++; 3926 if (*cp2) 3927 *cp2++ = '\0'; 3928 else if (i != 5) { 3929 cantparse = 1; 3930 break; 3931 } 3932 j = nfsrv_getipnumber(cp); 3933 if (j >= 0) { 3934 if (i < 4) 3935 ip.cval[3 - i] = j; 3936 else 3937 port.cval[5 - i] = j; 3938 } else { 3939 cantparse = 1; 3940 break; 3941 } 3942 cp = cp2; 3943 i++; 3944 } 3945 if (!cantparse) { 3946 if (ip.ival != 0x0) { 3947 rad->sin_addr.s_addr = htonl(ip.ival); 3948 rad->sin_port = htons(port.sval); 3949 } else { 3950 cantparse = 1; 3951 } 3952 } 3953 } else { 3954 cantparse = 1; 3955 if (i > 0) { 3956 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3957 if (error) 3958 goto nfsmout; 3959 } 3960 } 3961 if (cantparse) { 3962 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3963 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3964 rad->sin_port = 0x0; 3965 clp->lc_program = 0; 3966 } 3967nfsmout: 3968 NFSEXITCODE2(error, nd); 3969 return (error); 3970} 3971 3972/* 3973 * Turn a string of up to three decimal digits into a number. Return -1 upon 3974 * error. 3975 */ 3976static int 3977nfsrv_getipnumber(u_char *cp) 3978{ 3979 int i = 0, j = 0; 3980 3981 while (*cp) { 3982 if (j > 2 || *cp < '0' || *cp > '9') 3983 return (-1); 3984 i *= 10; 3985 i += (*cp - '0'); 3986 cp++; 3987 j++; 3988 } 3989 if (i < 256) 3990 return (i); 3991 return (-1); 3992} 3993 3994/* 3995 * This function checks for restart conditions. 3996 */ 3997static int 3998nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 3999 nfsv4stateid_t *stateidp, int specialid) 4000{ 4001 int ret = 0; 4002 4003 /* 4004 * First check for a server restart. Open, LockT, ReleaseLockOwner 4005 * and DelegPurge have a clientid, the rest a stateid. 4006 */ 4007 if (flags & 4008 (NFSLCK_OPEN | NFSLCK_TEST | NFSLCK_RELEASE | NFSLCK_DELEGPURGE)) { 4009 if (clientid.lval[0] != nfsrvboottime) { 4010 ret = NFSERR_STALECLIENTID; 4011 goto out; 4012 } 4013 } else if (stateidp->other[0] != nfsrvboottime && 4014 specialid == 0) { 4015 ret = NFSERR_STALESTATEID; 4016 goto out; 4017 } 4018 4019 /* 4020 * Read, Write, Setattr and LockT can return NFSERR_GRACE and do 4021 * not use a lock/open owner seqid#, so the check can be done now. 4022 * (The others will be checked, as required, later.) 4023 */ 4024 if (!(flags & (NFSLCK_CHECK | NFSLCK_TEST))) 4025 goto out; 4026 4027 NFSLOCKSTATE(); 4028 ret = nfsrv_checkgrace(NULL, NULL, flags); 4029 NFSUNLOCKSTATE(); 4030 4031out: 4032 NFSEXITCODE(ret); 4033 return (ret); 4034} 4035 4036/* 4037 * Check for grace. 4038 */ 4039static int 4040nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp, 4041 u_int32_t flags) 4042{ 4043 int error = 0; 4044 4045 if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0) { 4046 if (flags & NFSLCK_RECLAIM) { 4047 error = NFSERR_NOGRACE; 4048 goto out; 4049 } 4050 } else { 4051 if (!(flags & NFSLCK_RECLAIM)) { 4052 error = NFSERR_GRACE; 4053 goto out; 4054 } 4055 if (nd != NULL && clp != NULL && 4056 (nd->nd_flag & ND_NFSV41) != 0 && 4057 (clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0) { 4058 error = NFSERR_NOGRACE; 4059 goto out; 4060 } 4061 4062 /* 4063 * If grace is almost over and we are still getting Reclaims, 4064 * extend grace a bit. 4065 */ 4066 if ((NFSD_MONOSEC + NFSRV_LEASEDELTA) > 4067 nfsrv_stablefirst.nsf_eograce) 4068 nfsrv_stablefirst.nsf_eograce = NFSD_MONOSEC + 4069 NFSRV_LEASEDELTA; 4070 } 4071 4072out: 4073 NFSEXITCODE(error); 4074 return (error); 4075} 4076 4077/* 4078 * Do a server callback. 4079 */ 4080static int 4081nfsrv_docallback(struct nfsclient *clp, int procnum, 4082 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, 4083 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p) 4084{ 4085 mbuf_t m; 4086 u_int32_t *tl; 4087 struct nfsrv_descript nfsd, *nd = &nfsd; 4088 struct ucred *cred; 4089 int error = 0; 4090 u_int32_t callback; 4091 struct nfsdsession *sep = NULL; 4092 4093 cred = newnfs_getcred(); 4094 NFSLOCKSTATE(); /* mostly for lc_cbref++ */ 4095 if (clp->lc_flags & LCL_NEEDSCONFIRM) { 4096 NFSUNLOCKSTATE(); 4097 panic("docallb"); 4098 } 4099 clp->lc_cbref++; 4100 4101 /* 4102 * Fill the callback program# and version into the request 4103 * structure for newnfs_connect() to use. 4104 */ 4105 clp->lc_req.nr_prog = clp->lc_program; 4106#ifdef notnow 4107 if ((clp->lc_flags & LCL_NFSV41) != 0) 4108 clp->lc_req.nr_vers = NFSV41_CBVERS; 4109 else 4110#endif 4111 clp->lc_req.nr_vers = NFSV4_CBVERS; 4112 4113 /* 4114 * First, fill in some of the fields of nd and cr. 4115 */ 4116 nd->nd_flag = ND_NFSV4; 4117 if (clp->lc_flags & LCL_GSS) 4118 nd->nd_flag |= ND_KERBV; 4119 if ((clp->lc_flags & LCL_NFSV41) != 0) 4120 nd->nd_flag |= ND_NFSV41; 4121 nd->nd_repstat = 0; 4122 cred->cr_uid = clp->lc_uid; 4123 cred->cr_gid = clp->lc_gid; 4124 callback = clp->lc_callback; 4125 NFSUNLOCKSTATE(); 4126 cred->cr_ngroups = 1; 4127 4128 /* 4129 * Get the first mbuf for the request. 4130 */ 4131 MGET(m, M_WAITOK, MT_DATA); 4132 mbuf_setlen(m, 0); 4133 nd->nd_mreq = nd->nd_mb = m; 4134 nd->nd_bpos = NFSMTOD(m, caddr_t); 4135 4136 /* 4137 * and build the callback request. 4138 */ 4139 if (procnum == NFSV4OP_CBGETATTR) { 4140 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 4141 error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBGETATTR, 4142 "CB Getattr", &sep); 4143 if (error != 0) { 4144 mbuf_freem(nd->nd_mreq); 4145 goto errout; 4146 } 4147 (void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 4148 (void)nfsrv_putattrbit(nd, attrbitp); 4149 } else if (procnum == NFSV4OP_CBRECALL) { 4150 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 4151 error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBRECALL, 4152 "CB Recall", &sep); 4153 if (error != 0) { 4154 mbuf_freem(nd->nd_mreq); 4155 goto errout; 4156 } 4157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 4158 *tl++ = txdr_unsigned(stateidp->seqid); 4159 NFSBCOPY((caddr_t)stateidp->other, (caddr_t)tl, 4160 NFSX_STATEIDOTHER); 4161 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4162 if (trunc) 4163 *tl = newnfs_true; 4164 else 4165 *tl = newnfs_false; 4166 (void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 4167 } else if (procnum == NFSV4PROC_CBNULL) { 4168 nd->nd_procnum = NFSV4PROC_CBNULL; 4169 if ((clp->lc_flags & LCL_NFSV41) != 0) { 4170 error = nfsv4_getcbsession(clp, &sep); 4171 if (error != 0) { 4172 mbuf_freem(nd->nd_mreq); 4173 goto errout; 4174 } 4175 } 4176 } else { 4177 error = NFSERR_SERVERFAULT; 4178 mbuf_freem(nd->nd_mreq); 4179 goto errout; 4180 } 4181 4182 /* 4183 * Call newnfs_connect(), as required, and then newnfs_request(). 4184 */ 4185 (void) newnfs_sndlock(&clp->lc_req.nr_lock); 4186 if (clp->lc_req.nr_client == NULL) { 4187 if ((clp->lc_flags & LCL_NFSV41) != 0) 4188 error = ECONNREFUSED; 4189 else if (nd->nd_procnum == NFSV4PROC_CBNULL) 4190 error = newnfs_connect(NULL, &clp->lc_req, cred, 4191 NULL, 1); 4192 else 4193 error = newnfs_connect(NULL, &clp->lc_req, cred, 4194 NULL, 3); 4195 } 4196 newnfs_sndunlock(&clp->lc_req.nr_lock); 4197 if (!error) { 4198 if ((nd->nd_flag & ND_NFSV41) != 0) { 4199 KASSERT(sep != NULL, ("sep NULL")); 4200 if (sep->sess_cbsess.nfsess_xprt != NULL) 4201 error = newnfs_request(nd, NULL, clp, 4202 &clp->lc_req, NULL, NULL, cred, 4203 clp->lc_program, clp->lc_req.nr_vers, NULL, 4204 1, NULL, &sep->sess_cbsess); 4205 else { 4206 /* 4207 * This should probably never occur, but if a 4208 * client somehow does an RPC without a 4209 * SequenceID Op that causes a callback just 4210 * after the nfsd threads have been terminated 4211 * and restarted we could conceivably get here 4212 * without a backchannel xprt. 4213 */ 4214 printf("nfsrv_docallback: no xprt\n"); 4215 error = ECONNREFUSED; 4216 } 4217 nfsrv_freesession(sep, NULL); 4218 } else 4219 error = newnfs_request(nd, NULL, clp, &clp->lc_req, 4220 NULL, NULL, cred, clp->lc_program, 4221 clp->lc_req.nr_vers, NULL, 1, NULL, NULL); 4222 } 4223errout: 4224 NFSFREECRED(cred); 4225 4226 /* 4227 * If error is set here, the Callback path isn't working 4228 * properly, so twiddle the appropriate LCL_ flags. 4229 * (nd_repstat != 0 indicates the Callback path is working, 4230 * but the callback failed on the client.) 4231 */ 4232 if (error) { 4233 /* 4234 * Mark the callback pathway down, which disabled issuing 4235 * of delegations and gets Renew to return NFSERR_CBPATHDOWN. 4236 */ 4237 NFSLOCKSTATE(); 4238 clp->lc_flags |= LCL_CBDOWN; 4239 NFSUNLOCKSTATE(); 4240 } else { 4241 /* 4242 * Callback worked. If the callback path was down, disable 4243 * callbacks, so no more delegations will be issued. (This 4244 * is done on the assumption that the callback pathway is 4245 * flakey.) 4246 */ 4247 NFSLOCKSTATE(); 4248 if (clp->lc_flags & LCL_CBDOWN) 4249 clp->lc_flags &= ~(LCL_CBDOWN | LCL_CALLBACKSON); 4250 NFSUNLOCKSTATE(); 4251 if (nd->nd_repstat) 4252 error = nd->nd_repstat; 4253 else if (error == 0 && procnum == NFSV4OP_CBGETATTR) 4254 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4255 NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 4256 p, NULL); 4257 mbuf_freem(nd->nd_mrep); 4258 } 4259 NFSLOCKSTATE(); 4260 clp->lc_cbref--; 4261 if ((clp->lc_flags & LCL_WAKEUPWANTED) && clp->lc_cbref == 0) { 4262 clp->lc_flags &= ~LCL_WAKEUPWANTED; 4263 wakeup(clp); 4264 } 4265 NFSUNLOCKSTATE(); 4266 4267 NFSEXITCODE(error); 4268 return (error); 4269} 4270 4271/* 4272 * Set up the compound RPC for the callback. 4273 */ 4274static int 4275nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp, 4276 uint32_t callback, int op, const char *optag, struct nfsdsession **sepp) 4277{ 4278 uint32_t *tl; 4279 int error, len; 4280 4281 len = strlen(optag); 4282 (void)nfsm_strtom(nd, optag, len); 4283 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4284 if ((nd->nd_flag & ND_NFSV41) != 0) { 4285 *tl++ = txdr_unsigned(NFSV41_MINORVERSION); 4286 *tl++ = txdr_unsigned(callback); 4287 *tl++ = txdr_unsigned(2); 4288 *tl = txdr_unsigned(NFSV4OP_CBSEQUENCE); 4289 error = nfsv4_setcbsequence(nd, clp, 1, sepp); 4290 if (error != 0) 4291 return (error); 4292 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4293 *tl = txdr_unsigned(op); 4294 } else { 4295 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 4296 *tl++ = txdr_unsigned(callback); 4297 *tl++ = txdr_unsigned(1); 4298 *tl = txdr_unsigned(op); 4299 } 4300 return (0); 4301} 4302 4303/* 4304 * Return the next index# for a clientid. Mostly just increment and return 4305 * the next one, but... if the 32bit unsigned does actually wrap around, 4306 * it should be rebooted. 4307 * At an average rate of one new client per second, it will wrap around in 4308 * approximately 136 years. (I think the server will have been shut 4309 * down or rebooted before then.) 4310 */ 4311static u_int32_t 4312nfsrv_nextclientindex(void) 4313{ 4314 static u_int32_t client_index = 0; 4315 4316 client_index++; 4317 if (client_index != 0) 4318 return (client_index); 4319 4320 printf("%s: out of clientids\n", __func__); 4321 return (client_index); 4322} 4323 4324/* 4325 * Return the next index# for a stateid. Mostly just increment and return 4326 * the next one, but... if the 32bit unsigned does actually wrap around 4327 * (will a BSD server stay up that long?), find 4328 * new start and end values. 4329 */ 4330static u_int32_t 4331nfsrv_nextstateindex(struct nfsclient *clp) 4332{ 4333 struct nfsstate *stp; 4334 int i; 4335 u_int32_t canuse, min_index, max_index; 4336 4337 if (!(clp->lc_flags & LCL_INDEXNOTOK)) { 4338 clp->lc_stateindex++; 4339 if (clp->lc_stateindex != clp->lc_statemaxindex) 4340 return (clp->lc_stateindex); 4341 } 4342 4343 /* 4344 * Yuck, we've hit the end. 4345 * Look for a new min and max. 4346 */ 4347 min_index = 0; 4348 max_index = 0xffffffff; 4349 for (i = 0; i < nfsrv_statehashsize; i++) { 4350 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 4351 if (stp->ls_stateid.other[2] > 0x80000000) { 4352 if (stp->ls_stateid.other[2] < max_index) 4353 max_index = stp->ls_stateid.other[2]; 4354 } else { 4355 if (stp->ls_stateid.other[2] > min_index) 4356 min_index = stp->ls_stateid.other[2]; 4357 } 4358 } 4359 } 4360 4361 /* 4362 * Yikes, highly unlikely, but I'll handle it anyhow. 4363 */ 4364 if (min_index == 0x80000000 && max_index == 0x80000001) { 4365 canuse = 0; 4366 /* 4367 * Loop around until we find an unused entry. Return that 4368 * and set LCL_INDEXNOTOK, so the search will continue next time. 4369 * (This is one of those rare cases where a goto is the 4370 * cleanest way to code the loop.) 4371 */ 4372tryagain: 4373 for (i = 0; i < nfsrv_statehashsize; i++) { 4374 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 4375 if (stp->ls_stateid.other[2] == canuse) { 4376 canuse++; 4377 goto tryagain; 4378 } 4379 } 4380 } 4381 clp->lc_flags |= LCL_INDEXNOTOK; 4382 return (canuse); 4383 } 4384 4385 /* 4386 * Ok to start again from min + 1. 4387 */ 4388 clp->lc_stateindex = min_index + 1; 4389 clp->lc_statemaxindex = max_index; 4390 clp->lc_flags &= ~LCL_INDEXNOTOK; 4391 return (clp->lc_stateindex); 4392} 4393 4394/* 4395 * The following functions handle the stable storage file that deals with 4396 * the edge conditions described in RFC3530 Sec. 8.6.3. 4397 * The file is as follows: 4398 * - a single record at the beginning that has the lease time of the 4399 * previous server instance (before the last reboot) and the nfsrvboottime 4400 * values for the previous server boots. 4401 * These previous boot times are used to ensure that the current 4402 * nfsrvboottime does not, somehow, get set to a previous one. 4403 * (This is important so that Stale ClientIDs and StateIDs can 4404 * be recognized.) 4405 * The number of previous nfsvrboottime values precedes the list. 4406 * - followed by some number of appended records with: 4407 * - client id string 4408 * - flag that indicates it is a record revoking state via lease 4409 * expiration or similar 4410 * OR has successfully acquired state. 4411 * These structures vary in length, with the client string at the end, up 4412 * to NFSV4_OPAQUELIMIT in size. 4413 * 4414 * At the end of the grace period, the file is truncated, the first 4415 * record is rewritten with updated information and any acquired state 4416 * records for successful reclaims of state are written. 4417 * 4418 * Subsequent records are appended when the first state is issued to 4419 * a client and when state is revoked for a client. 4420 * 4421 * When reading the file in, state issued records that come later in 4422 * the file override older ones, since the append log is in cronological order. 4423 * If, for some reason, the file can't be read, the grace period is 4424 * immediately terminated and all reclaims get NFSERR_NOGRACE. 4425 */ 4426 4427/* 4428 * Read in the stable storage file. Called by nfssvc() before the nfsd 4429 * processes start servicing requests. 4430 */ 4431APPLESTATIC void 4432nfsrv_setupstable(NFSPROC_T *p) 4433{ 4434 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4435 struct nfsrv_stable *sp, *nsp; 4436 struct nfst_rec *tsp; 4437 int error, i, tryagain; 4438 off_t off = 0; 4439 ssize_t aresid, len; 4440 4441 /* 4442 * If NFSNSF_UPDATEDONE is set, this is a restart of the nfsds without 4443 * a reboot, so state has not been lost. 4444 */ 4445 if (sf->nsf_flags & NFSNSF_UPDATEDONE) 4446 return; 4447 /* 4448 * Set Grace over just until the file reads successfully. 4449 */ 4450 nfsrvboottime = time_second; 4451 LIST_INIT(&sf->nsf_head); 4452 sf->nsf_flags = (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 4453 sf->nsf_eograce = NFSD_MONOSEC + NFSRV_LEASEDELTA; 4454 if (sf->nsf_fp == NULL) 4455 return; 4456 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 4457 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), off, UIO_SYSSPACE, 4458 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4459 if (error || aresid || sf->nsf_numboots == 0 || 4460 sf->nsf_numboots > NFSNSF_MAXNUMBOOTS) 4461 return; 4462 4463 /* 4464 * Now, read in the boottimes. 4465 */ 4466 sf->nsf_bootvals = (time_t *)malloc((sf->nsf_numboots + 1) * 4467 sizeof (time_t), M_TEMP, M_WAITOK); 4468 off = sizeof (struct nfsf_rec); 4469 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 4470 (caddr_t)sf->nsf_bootvals, sf->nsf_numboots * sizeof (time_t), off, 4471 UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4472 if (error || aresid) { 4473 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4474 sf->nsf_bootvals = NULL; 4475 return; 4476 } 4477 4478 /* 4479 * Make sure this nfsrvboottime is different from all recorded 4480 * previous ones. 4481 */ 4482 do { 4483 tryagain = 0; 4484 for (i = 0; i < sf->nsf_numboots; i++) { 4485 if (nfsrvboottime == sf->nsf_bootvals[i]) { 4486 nfsrvboottime++; 4487 tryagain = 1; 4488 break; 4489 } 4490 } 4491 } while (tryagain); 4492 4493 sf->nsf_flags |= NFSNSF_OK; 4494 off += (sf->nsf_numboots * sizeof (time_t)); 4495 4496 /* 4497 * Read through the file, building a list of records for grace 4498 * checking. 4499 * Each record is between sizeof (struct nfst_rec) and 4500 * sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1 4501 * and is actually sizeof (struct nfst_rec) + nst_len - 1. 4502 */ 4503 tsp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 4504 NFSV4_OPAQUELIMIT - 1, M_TEMP, M_WAITOK); 4505 do { 4506 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 4507 (caddr_t)tsp, sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1, 4508 off, UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4509 len = (sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1) - aresid; 4510 if (error || (len > 0 && (len < sizeof (struct nfst_rec) || 4511 len < (sizeof (struct nfst_rec) + tsp->len - 1)))) { 4512 /* 4513 * Yuck, the file has been corrupted, so just return 4514 * after clearing out any restart state, so the grace period 4515 * is over. 4516 */ 4517 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4518 LIST_REMOVE(sp, nst_list); 4519 free((caddr_t)sp, M_TEMP); 4520 } 4521 free((caddr_t)tsp, M_TEMP); 4522 sf->nsf_flags &= ~NFSNSF_OK; 4523 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4524 sf->nsf_bootvals = NULL; 4525 return; 4526 } 4527 if (len > 0) { 4528 off += sizeof (struct nfst_rec) + tsp->len - 1; 4529 /* 4530 * Search the list for a matching client. 4531 */ 4532 LIST_FOREACH(sp, &sf->nsf_head, nst_list) { 4533 if (tsp->len == sp->nst_len && 4534 !NFSBCMP(tsp->client, sp->nst_client, tsp->len)) 4535 break; 4536 } 4537 if (sp == NULL) { 4538 sp = (struct nfsrv_stable *)malloc(tsp->len + 4539 sizeof (struct nfsrv_stable) - 1, M_TEMP, 4540 M_WAITOK); 4541 NFSBCOPY((caddr_t)tsp, (caddr_t)&sp->nst_rec, 4542 sizeof (struct nfst_rec) + tsp->len - 1); 4543 LIST_INSERT_HEAD(&sf->nsf_head, sp, nst_list); 4544 } else { 4545 if (tsp->flag == NFSNST_REVOKE) 4546 sp->nst_flag |= NFSNST_REVOKE; 4547 else 4548 /* 4549 * A subsequent timestamp indicates the client 4550 * did a setclientid/confirm and any previous 4551 * revoke is no longer relevant. 4552 */ 4553 sp->nst_flag &= ~NFSNST_REVOKE; 4554 } 4555 } 4556 } while (len > 0); 4557 free((caddr_t)tsp, M_TEMP); 4558 sf->nsf_flags = NFSNSF_OK; 4559 sf->nsf_eograce = NFSD_MONOSEC + sf->nsf_lease + 4560 NFSRV_LEASEDELTA; 4561} 4562 4563/* 4564 * Update the stable storage file, now that the grace period is over. 4565 */ 4566APPLESTATIC void 4567nfsrv_updatestable(NFSPROC_T *p) 4568{ 4569 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4570 struct nfsrv_stable *sp, *nsp; 4571 int i; 4572 struct nfsvattr nva; 4573 vnode_t vp; 4574#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) 4575 mount_t mp = NULL; 4576#endif 4577 int error; 4578 4579 if (sf->nsf_fp == NULL || (sf->nsf_flags & NFSNSF_UPDATEDONE)) 4580 return; 4581 sf->nsf_flags |= NFSNSF_UPDATEDONE; 4582 /* 4583 * Ok, we need to rewrite the stable storage file. 4584 * - truncate to 0 length 4585 * - write the new first structure 4586 * - loop through the data structures, writing out any that 4587 * have timestamps older than the old boot 4588 */ 4589 if (sf->nsf_bootvals) { 4590 sf->nsf_numboots++; 4591 for (i = sf->nsf_numboots - 2; i >= 0; i--) 4592 sf->nsf_bootvals[i + 1] = sf->nsf_bootvals[i]; 4593 } else { 4594 sf->nsf_numboots = 1; 4595 sf->nsf_bootvals = (time_t *)malloc(sizeof (time_t), 4596 M_TEMP, M_WAITOK); 4597 } 4598 sf->nsf_bootvals[0] = nfsrvboottime; 4599 sf->nsf_lease = nfsrv_lease; 4600 NFSVNO_ATTRINIT(&nva); 4601 NFSVNO_SETATTRVAL(&nva, size, 0); 4602 vp = NFSFPVNODE(sf->nsf_fp); 4603 vn_start_write(vp, &mp, V_WAIT); 4604 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 4605 error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, 4606 NULL); 4607 NFSVOPUNLOCK(vp, 0); 4608 } else 4609 error = EPERM; 4610 vn_finished_write(mp); 4611 if (!error) 4612 error = NFSD_RDWR(UIO_WRITE, vp, 4613 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0, 4614 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4615 if (!error) 4616 error = NFSD_RDWR(UIO_WRITE, vp, 4617 (caddr_t)sf->nsf_bootvals, 4618 sf->nsf_numboots * sizeof (time_t), 4619 (off_t)(sizeof (struct nfsf_rec)), 4620 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4621 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4622 sf->nsf_bootvals = NULL; 4623 if (error) { 4624 sf->nsf_flags &= ~NFSNSF_OK; 4625 printf("EEK! Can't write NfsV4 stable storage file\n"); 4626 return; 4627 } 4628 sf->nsf_flags |= NFSNSF_OK; 4629 4630 /* 4631 * Loop through the list and write out timestamp records for 4632 * any clients that successfully reclaimed state. 4633 */ 4634 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4635 if (sp->nst_flag & NFSNST_GOTSTATE) { 4636 nfsrv_writestable(sp->nst_client, sp->nst_len, 4637 NFSNST_NEWSTATE, p); 4638 sp->nst_clp->lc_flags |= LCL_STAMPEDSTABLE; 4639 } 4640 LIST_REMOVE(sp, nst_list); 4641 free((caddr_t)sp, M_TEMP); 4642 } 4643 nfsrv_backupstable(); 4644} 4645 4646/* 4647 * Append a record to the stable storage file. 4648 */ 4649APPLESTATIC void 4650nfsrv_writestable(u_char *client, int len, int flag, NFSPROC_T *p) 4651{ 4652 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4653 struct nfst_rec *sp; 4654 int error; 4655 4656 if (!(sf->nsf_flags & NFSNSF_OK) || sf->nsf_fp == NULL) 4657 return; 4658 sp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 4659 len - 1, M_TEMP, M_WAITOK); 4660 sp->len = len; 4661 NFSBCOPY(client, sp->client, len); 4662 sp->flag = flag; 4663 error = NFSD_RDWR(UIO_WRITE, NFSFPVNODE(sf->nsf_fp), 4664 (caddr_t)sp, sizeof (struct nfst_rec) + len - 1, (off_t)0, 4665 UIO_SYSSPACE, (IO_SYNC | IO_APPEND), NFSFPCRED(sf->nsf_fp), NULL, p); 4666 free((caddr_t)sp, M_TEMP); 4667 if (error) { 4668 sf->nsf_flags &= ~NFSNSF_OK; 4669 printf("EEK! Can't write NfsV4 stable storage file\n"); 4670 } 4671} 4672 4673/* 4674 * This function is called during the grace period to mark a client 4675 * that successfully reclaimed state. 4676 */ 4677static void 4678nfsrv_markstable(struct nfsclient *clp) 4679{ 4680 struct nfsrv_stable *sp; 4681 4682 /* 4683 * First find the client structure. 4684 */ 4685 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4686 if (sp->nst_len == clp->lc_idlen && 4687 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4688 break; 4689 } 4690 if (sp == NULL) 4691 return; 4692 4693 /* 4694 * Now, just mark it and set the nfsclient back pointer. 4695 */ 4696 sp->nst_flag |= NFSNST_GOTSTATE; 4697 sp->nst_clp = clp; 4698} 4699 4700/* 4701 * This function is called for a reclaim, to see if it gets grace. 4702 * It returns 0 if a reclaim is allowed, 1 otherwise. 4703 */ 4704static int 4705nfsrv_checkstable(struct nfsclient *clp) 4706{ 4707 struct nfsrv_stable *sp; 4708 4709 /* 4710 * First, find the entry for the client. 4711 */ 4712 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4713 if (sp->nst_len == clp->lc_idlen && 4714 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4715 break; 4716 } 4717 4718 /* 4719 * If not in the list, state was revoked or no state was issued 4720 * since the previous reboot, a reclaim is denied. 4721 */ 4722 if (sp == NULL || 4723 (sp->nst_flag & NFSNST_REVOKE) || 4724 !(nfsrv_stablefirst.nsf_flags & NFSNSF_OK)) 4725 return (1); 4726 return (0); 4727} 4728 4729/* 4730 * Test for and try to clear out a conflicting client. This is called by 4731 * nfsrv_lockctrl() and nfsrv_openctrl() when conflicts with other clients 4732 * a found. 4733 * The trick here is that it can't revoke a conflicting client with an 4734 * expired lease unless it holds the v4root lock, so... 4735 * If no v4root lock, get the lock and return 1 to indicate "try again". 4736 * Return 0 to indicate the conflict can't be revoked and 1 to indicate 4737 * the revocation worked and the conflicting client is "bye, bye", so it 4738 * can be tried again. 4739 * Return 2 to indicate that the vnode is VI_DOOMED after NFSVOPLOCK(). 4740 * Unlocks State before a non-zero value is returned. 4741 */ 4742static int 4743nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp, 4744 NFSPROC_T *p) 4745{ 4746 int gotlock, lktype = 0; 4747 4748 /* 4749 * If lease hasn't expired, we can't fix it. 4750 */ 4751 if (clp->lc_expiry >= NFSD_MONOSEC || 4752 !(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) 4753 return (0); 4754 if (*haslockp == 0) { 4755 NFSUNLOCKSTATE(); 4756 if (vp != NULL) { 4757 lktype = NFSVOPISLOCKED(vp); 4758 NFSVOPUNLOCK(vp, 0); 4759 } 4760 NFSLOCKV4ROOTMUTEX(); 4761 nfsv4_relref(&nfsv4rootfs_lock); 4762 do { 4763 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4764 NFSV4ROOTLOCKMUTEXPTR, NULL); 4765 } while (!gotlock); 4766 NFSUNLOCKV4ROOTMUTEX(); 4767 *haslockp = 1; 4768 if (vp != NULL) { 4769 NFSVOPLOCK(vp, lktype | LK_RETRY); 4770 if ((vp->v_iflag & VI_DOOMED) != 0) 4771 return (2); 4772 } 4773 return (1); 4774 } 4775 NFSUNLOCKSTATE(); 4776 4777 /* 4778 * Ok, we can expire the conflicting client. 4779 */ 4780 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4781 nfsrv_backupstable(); 4782 nfsrv_cleanclient(clp, p); 4783 nfsrv_freedeleglist(&clp->lc_deleg); 4784 nfsrv_freedeleglist(&clp->lc_olddeleg); 4785 LIST_REMOVE(clp, lc_hash); 4786 nfsrv_zapclient(clp, p); 4787 return (1); 4788} 4789 4790/* 4791 * Resolve a delegation conflict. 4792 * Returns 0 to indicate the conflict was resolved without sleeping. 4793 * Return -1 to indicate that the caller should check for conflicts again. 4794 * Return > 0 for an error that should be returned, normally NFSERR_DELAY. 4795 * 4796 * Also, manipulate the nfsv4root_lock, as required. It isn't changed 4797 * for a return of 0, since there was no sleep and it could be required 4798 * later. It is released for a return of NFSERR_DELAY, since the caller 4799 * will return that error. It is released when a sleep was done waiting 4800 * for the delegation to be returned or expire (so that other nfsds can 4801 * handle ops). Then, it must be acquired for the write to stable storage. 4802 * (This function is somewhat similar to nfsrv_clientconflict(), but 4803 * the semantics differ in a couple of subtle ways. The return of 0 4804 * indicates the conflict was resolved without sleeping here, not 4805 * that the conflict can't be resolved and the handling of nfsv4root_lock 4806 * differs, as noted above.) 4807 * Unlocks State before returning a non-zero value. 4808 */ 4809static int 4810nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p, 4811 vnode_t vp) 4812{ 4813 struct nfsclient *clp = stp->ls_clp; 4814 int gotlock, error, lktype = 0, retrycnt, zapped_clp; 4815 nfsv4stateid_t tstateid; 4816 fhandle_t tfh; 4817 4818 /* 4819 * If the conflict is with an old delegation... 4820 */ 4821 if (stp->ls_flags & NFSLCK_OLDDELEG) { 4822 /* 4823 * You can delete it, if it has expired. 4824 */ 4825 if (clp->lc_delegtime < NFSD_MONOSEC) { 4826 nfsrv_freedeleg(stp); 4827 NFSUNLOCKSTATE(); 4828 error = -1; 4829 goto out; 4830 } 4831 NFSUNLOCKSTATE(); 4832 /* 4833 * During this delay, the old delegation could expire or it 4834 * could be recovered by the client via an Open with 4835 * CLAIM_DELEGATE_PREV. 4836 * Release the nfsv4root_lock, if held. 4837 */ 4838 if (*haslockp) { 4839 *haslockp = 0; 4840 NFSLOCKV4ROOTMUTEX(); 4841 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4842 NFSUNLOCKV4ROOTMUTEX(); 4843 } 4844 error = NFSERR_DELAY; 4845 goto out; 4846 } 4847 4848 /* 4849 * It's a current delegation, so: 4850 * - check to see if the delegation has expired 4851 * - if so, get the v4root lock and then expire it 4852 */ 4853 if (!(stp->ls_flags & NFSLCK_DELEGRECALL)) { 4854 /* 4855 * - do a recall callback, since not yet done 4856 * For now, never allow truncate to be set. To use 4857 * truncate safely, it must be guaranteed that the 4858 * Remove, Rename or Setattr with size of 0 will 4859 * succeed and that would require major changes to 4860 * the VFS/Vnode OPs. 4861 * Set the expiry time large enough so that it won't expire 4862 * until after the callback, then set it correctly, once 4863 * the callback is done. (The delegation will now time 4864 * out whether or not the Recall worked ok. The timeout 4865 * will be extended when ops are done on the delegation 4866 * stateid, up to the timelimit.) 4867 */ 4868 stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) + 4869 NFSRV_LEASEDELTA; 4870 stp->ls_delegtimelimit = NFSD_MONOSEC + (6 * nfsrv_lease) + 4871 NFSRV_LEASEDELTA; 4872 stp->ls_flags |= NFSLCK_DELEGRECALL; 4873 4874 /* 4875 * Loop NFSRV_CBRETRYCNT times while the CBRecall replies 4876 * NFSERR_BADSTATEID or NFSERR_BADHANDLE. This is done 4877 * in order to try and avoid a race that could happen 4878 * when a CBRecall request passed the Open reply with 4879 * the delegation in it when transitting the network. 4880 * Since nfsrv_docallback will sleep, don't use stp after 4881 * the call. 4882 */ 4883 NFSBCOPY((caddr_t)&stp->ls_stateid, (caddr_t)&tstateid, 4884 sizeof (tstateid)); 4885 NFSBCOPY((caddr_t)&stp->ls_lfp->lf_fh, (caddr_t)&tfh, 4886 sizeof (tfh)); 4887 NFSUNLOCKSTATE(); 4888 if (*haslockp) { 4889 *haslockp = 0; 4890 NFSLOCKV4ROOTMUTEX(); 4891 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4892 NFSUNLOCKV4ROOTMUTEX(); 4893 } 4894 retrycnt = 0; 4895 do { 4896 error = nfsrv_docallback(clp, NFSV4OP_CBRECALL, 4897 &tstateid, 0, &tfh, NULL, NULL, p); 4898 retrycnt++; 4899 } while ((error == NFSERR_BADSTATEID || 4900 error == NFSERR_BADHANDLE) && retrycnt < NFSV4_CBRETRYCNT); 4901 error = NFSERR_DELAY; 4902 goto out; 4903 } 4904 4905 if (clp->lc_expiry >= NFSD_MONOSEC && 4906 stp->ls_delegtime >= NFSD_MONOSEC) { 4907 NFSUNLOCKSTATE(); 4908 /* 4909 * A recall has been done, but it has not yet expired. 4910 * So, RETURN_DELAY. 4911 */ 4912 if (*haslockp) { 4913 *haslockp = 0; 4914 NFSLOCKV4ROOTMUTEX(); 4915 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4916 NFSUNLOCKV4ROOTMUTEX(); 4917 } 4918 error = NFSERR_DELAY; 4919 goto out; 4920 } 4921 4922 /* 4923 * If we don't yet have the lock, just get it and then return, 4924 * since we need that before deleting expired state, such as 4925 * this delegation. 4926 * When getting the lock, unlock the vnode, so other nfsds that 4927 * are in progress, won't get stuck waiting for the vnode lock. 4928 */ 4929 if (*haslockp == 0) { 4930 NFSUNLOCKSTATE(); 4931 if (vp != NULL) { 4932 lktype = NFSVOPISLOCKED(vp); 4933 NFSVOPUNLOCK(vp, 0); 4934 } 4935 NFSLOCKV4ROOTMUTEX(); 4936 nfsv4_relref(&nfsv4rootfs_lock); 4937 do { 4938 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4939 NFSV4ROOTLOCKMUTEXPTR, NULL); 4940 } while (!gotlock); 4941 NFSUNLOCKV4ROOTMUTEX(); 4942 *haslockp = 1; 4943 if (vp != NULL) { 4944 NFSVOPLOCK(vp, lktype | LK_RETRY); 4945 if ((vp->v_iflag & VI_DOOMED) != 0) { 4946 *haslockp = 0; 4947 NFSLOCKV4ROOTMUTEX(); 4948 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4949 NFSUNLOCKV4ROOTMUTEX(); 4950 error = NFSERR_PERM; 4951 goto out; 4952 } 4953 } 4954 error = -1; 4955 goto out; 4956 } 4957 4958 NFSUNLOCKSTATE(); 4959 /* 4960 * Ok, we can delete the expired delegation. 4961 * First, write the Revoke record to stable storage and then 4962 * clear out the conflict. 4963 * Since all other nfsd threads are now blocked, we can safely 4964 * sleep without the state changing. 4965 */ 4966 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4967 nfsrv_backupstable(); 4968 if (clp->lc_expiry < NFSD_MONOSEC) { 4969 nfsrv_cleanclient(clp, p); 4970 nfsrv_freedeleglist(&clp->lc_deleg); 4971 nfsrv_freedeleglist(&clp->lc_olddeleg); 4972 LIST_REMOVE(clp, lc_hash); 4973 zapped_clp = 1; 4974 } else { 4975 nfsrv_freedeleg(stp); 4976 zapped_clp = 0; 4977 } 4978 if (zapped_clp) 4979 nfsrv_zapclient(clp, p); 4980 error = -1; 4981 4982out: 4983 NFSEXITCODE(error); 4984 return (error); 4985} 4986 4987/* 4988 * Check for a remove allowed, if remove is set to 1 and get rid of 4989 * delegations. 4990 */ 4991APPLESTATIC int 4992nfsrv_checkremove(vnode_t vp, int remove, NFSPROC_T *p) 4993{ 4994 struct nfsstate *stp; 4995 struct nfslockfile *lfp; 4996 int error, haslock = 0; 4997 fhandle_t nfh; 4998 4999 /* 5000 * First, get the lock file structure. 5001 * (A return of -1 means no associated state, so remove ok.) 5002 */ 5003 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 5004tryagain: 5005 NFSLOCKSTATE(); 5006 if (!error) 5007 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 5008 if (error) { 5009 NFSUNLOCKSTATE(); 5010 if (haslock) { 5011 NFSLOCKV4ROOTMUTEX(); 5012 nfsv4_unlock(&nfsv4rootfs_lock, 1); 5013 NFSUNLOCKV4ROOTMUTEX(); 5014 } 5015 if (error == -1) 5016 error = 0; 5017 goto out; 5018 } 5019 5020 /* 5021 * Now, we must Recall any delegations. 5022 */ 5023 error = nfsrv_cleandeleg(vp, lfp, NULL, &haslock, p); 5024 if (error) { 5025 /* 5026 * nfsrv_cleandeleg() unlocks state for non-zero 5027 * return. 5028 */ 5029 if (error == -1) 5030 goto tryagain; 5031 if (haslock) { 5032 NFSLOCKV4ROOTMUTEX(); 5033 nfsv4_unlock(&nfsv4rootfs_lock, 1); 5034 NFSUNLOCKV4ROOTMUTEX(); 5035 } 5036 goto out; 5037 } 5038 5039 /* 5040 * Now, look for a conflicting open share. 5041 */ 5042 if (remove) { 5043 /* 5044 * If the entry in the directory was the last reference to the 5045 * corresponding filesystem object, the object can be destroyed 5046 * */ 5047 if(lfp->lf_usecount>1) 5048 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 5049 if (stp->ls_flags & NFSLCK_WRITEDENY) { 5050 error = NFSERR_FILEOPEN; 5051 break; 5052 } 5053 } 5054 } 5055 5056 NFSUNLOCKSTATE(); 5057 if (haslock) { 5058 NFSLOCKV4ROOTMUTEX(); 5059 nfsv4_unlock(&nfsv4rootfs_lock, 1); 5060 NFSUNLOCKV4ROOTMUTEX(); 5061 } 5062 5063out: 5064 NFSEXITCODE(error); 5065 return (error); 5066} 5067 5068/* 5069 * Clear out all delegations for the file referred to by lfp. 5070 * May return NFSERR_DELAY, if there will be a delay waiting for 5071 * delegations to expire. 5072 * Returns -1 to indicate it slept while recalling a delegation. 5073 * This function has the side effect of deleting the nfslockfile structure, 5074 * if it no longer has associated state and didn't have to sleep. 5075 * Unlocks State before a non-zero value is returned. 5076 */ 5077static int 5078nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 5079 struct nfsclient *clp, int *haslockp, NFSPROC_T *p) 5080{ 5081 struct nfsstate *stp, *nstp; 5082 int ret = 0; 5083 5084 stp = LIST_FIRST(&lfp->lf_deleg); 5085 while (stp != NULL) { 5086 nstp = LIST_NEXT(stp, ls_file); 5087 if (stp->ls_clp != clp) { 5088 ret = nfsrv_delegconflict(stp, haslockp, p, vp); 5089 if (ret) { 5090 /* 5091 * nfsrv_delegconflict() unlocks state 5092 * when it returns non-zero. 5093 */ 5094 goto out; 5095 } 5096 } 5097 stp = nstp; 5098 } 5099out: 5100 NFSEXITCODE(ret); 5101 return (ret); 5102} 5103 5104/* 5105 * There are certain operations that, when being done outside of NFSv4, 5106 * require that any NFSv4 delegation for the file be recalled. 5107 * This function is to be called for those cases: 5108 * VOP_RENAME() - When a delegation is being recalled for any reason, 5109 * the client may have to do Opens against the server, using the file's 5110 * final component name. If the file has been renamed on the server, 5111 * that component name will be incorrect and the Open will fail. 5112 * VOP_REMOVE() - Theoretically, a client could Open a file after it has 5113 * been removed on the server, if there is a delegation issued to 5114 * that client for the file. I say "theoretically" since clients 5115 * normally do an Access Op before the Open and that Access Op will 5116 * fail with ESTALE. Note that NFSv2 and 3 don't even do Opens, so 5117 * they will detect the file's removal in the same manner. (There is 5118 * one case where RFC3530 allows a client to do an Open without first 5119 * doing an Access Op, which is passage of a check against the ACE 5120 * returned with a Write delegation, but current practice is to ignore 5121 * the ACE and always do an Access Op.) 5122 * Since the functions can only be called with an unlocked vnode, this 5123 * can't be done at this time. 5124 * VOP_ADVLOCK() - When a client holds a delegation, it can issue byte range 5125 * locks locally in the client, which are not visible to the server. To 5126 * deal with this, issuing of delegations for a vnode must be disabled 5127 * and all delegations for the vnode recalled. This is done via the 5128 * second function, using the VV_DISABLEDELEG vflag on the vnode. 5129 */ 5130APPLESTATIC void 5131nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p) 5132{ 5133 time_t starttime; 5134 int error; 5135 5136 /* 5137 * First, check to see if the server is currently running and it has 5138 * been called for a regular file when issuing delegations. 5139 */ 5140 if (newnfs_numnfsd == 0 || vp->v_type != VREG || 5141 nfsrv_issuedelegs == 0) 5142 return; 5143 5144 KASSERT((NFSVOPISLOCKED(vp) != LK_EXCLUSIVE), ("vp %p is locked", vp)); 5145 /* 5146 * First, get a reference on the nfsv4rootfs_lock so that an 5147 * exclusive lock cannot be acquired by another thread. 5148 */ 5149 NFSLOCKV4ROOTMUTEX(); 5150 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 5151 NFSUNLOCKV4ROOTMUTEX(); 5152 5153 /* 5154 * Now, call nfsrv_checkremove() in a loop while it returns 5155 * NFSERR_DELAY. Return upon any other error or when timed out. 5156 */ 5157 starttime = NFSD_MONOSEC; 5158 do { 5159 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 5160 error = nfsrv_checkremove(vp, 0, p); 5161 NFSVOPUNLOCK(vp, 0); 5162 } else 5163 error = EPERM; 5164 if (error == NFSERR_DELAY) { 5165 if (NFSD_MONOSEC - starttime > NFS_REMOVETIMEO) 5166 break; 5167 /* Sleep for a short period of time */ 5168 (void) nfs_catnap(PZERO, 0, "nfsremove"); 5169 } 5170 } while (error == NFSERR_DELAY); 5171 NFSLOCKV4ROOTMUTEX(); 5172 nfsv4_relref(&nfsv4rootfs_lock); 5173 NFSUNLOCKV4ROOTMUTEX(); 5174} 5175 5176APPLESTATIC void 5177nfsd_disabledelegation(vnode_t vp, NFSPROC_T *p) 5178{ 5179 5180#ifdef VV_DISABLEDELEG 5181 /* 5182 * First, flag issuance of delegations disabled. 5183 */ 5184 atomic_set_long(&vp->v_vflag, VV_DISABLEDELEG); 5185#endif 5186 5187 /* 5188 * Then call nfsd_recalldelegation() to get rid of all extant 5189 * delegations. 5190 */ 5191 nfsd_recalldelegation(vp, p); 5192} 5193 5194/* 5195 * Check for conflicting locks, etc. and then get rid of delegations. 5196 * (At one point I thought that I should get rid of delegations for any 5197 * Setattr, since it could potentially disallow the I/O op (read or write) 5198 * allowed by the delegation. However, Setattr Ops that aren't changing 5199 * the size get a stateid of all 0s, so you can't tell if it is a delegation 5200 * for the same client or a different one, so I decided to only get rid 5201 * of delegations for other clients when the size is being changed.) 5202 * In general, a Setattr can disable NFS I/O Ops that are outstanding, such 5203 * as Write backs, even if there is no delegation, so it really isn't any 5204 * different?) 5205 */ 5206APPLESTATIC int 5207nfsrv_checksetattr(vnode_t vp, struct nfsrv_descript *nd, 5208 nfsv4stateid_t *stateidp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp, 5209 struct nfsexstuff *exp, NFSPROC_T *p) 5210{ 5211 struct nfsstate st, *stp = &st; 5212 struct nfslock lo, *lop = &lo; 5213 int error = 0; 5214 nfsquad_t clientid; 5215 5216 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE)) { 5217 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5218 lop->lo_first = nvap->na_size; 5219 } else { 5220 stp->ls_flags = 0; 5221 lop->lo_first = 0; 5222 } 5223 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) || 5224 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) || 5225 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_MODE) || 5226 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL)) 5227 stp->ls_flags |= NFSLCK_SETATTR; 5228 if (stp->ls_flags == 0) 5229 goto out; 5230 lop->lo_end = NFS64BITSSET; 5231 lop->lo_flags = NFSLCK_WRITE; 5232 stp->ls_ownerlen = 0; 5233 stp->ls_op = NULL; 5234 stp->ls_uid = nd->nd_cred->cr_uid; 5235 stp->ls_stateid.seqid = stateidp->seqid; 5236 clientid.lval[0] = stp->ls_stateid.other[0] = stateidp->other[0]; 5237 clientid.lval[1] = stp->ls_stateid.other[1] = stateidp->other[1]; 5238 stp->ls_stateid.other[2] = stateidp->other[2]; 5239 error = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5240 stateidp, exp, nd, p); 5241 5242out: 5243 NFSEXITCODE2(error, nd); 5244 return (error); 5245} 5246 5247/* 5248 * Check for a write delegation and do a CBGETATTR if there is one, updating 5249 * the attributes, as required. 5250 * Should I return an error if I can't get the attributes? (For now, I'll 5251 * just return ok. 5252 */ 5253APPLESTATIC int 5254nfsrv_checkgetattr(struct nfsrv_descript *nd, vnode_t vp, 5255 struct nfsvattr *nvap, nfsattrbit_t *attrbitp, struct ucred *cred, 5256 NFSPROC_T *p) 5257{ 5258 struct nfsstate *stp; 5259 struct nfslockfile *lfp; 5260 struct nfsclient *clp; 5261 struct nfsvattr nva; 5262 fhandle_t nfh; 5263 int error = 0; 5264 nfsattrbit_t cbbits; 5265 u_quad_t delegfilerev; 5266 5267 NFSCBGETATTR_ATTRBIT(attrbitp, &cbbits); 5268 if (!NFSNONZERO_ATTRBIT(&cbbits)) 5269 goto out; 5270 5271 /* 5272 * Get the lock file structure. 5273 * (A return of -1 means no associated state, so return ok.) 5274 */ 5275 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 5276 NFSLOCKSTATE(); 5277 if (!error) 5278 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 5279 if (error) { 5280 NFSUNLOCKSTATE(); 5281 if (error == -1) 5282 error = 0; 5283 goto out; 5284 } 5285 5286 /* 5287 * Now, look for a write delegation. 5288 */ 5289 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 5290 if (stp->ls_flags & NFSLCK_DELEGWRITE) 5291 break; 5292 } 5293 if (stp == NULL) { 5294 NFSUNLOCKSTATE(); 5295 goto out; 5296 } 5297 clp = stp->ls_clp; 5298 delegfilerev = stp->ls_filerev; 5299 5300 /* 5301 * If the Write delegation was issued as a part of this Compound RPC 5302 * or if we have an Implied Clientid (used in a previous Op in this 5303 * compound) and it is the client the delegation was issued to, 5304 * just return ok. 5305 * I also assume that it is from the same client iff the network 5306 * host IP address is the same as the callback address. (Not 5307 * exactly correct by the RFC, but avoids a lot of Getattr 5308 * callbacks.) 5309 */ 5310 if (nd->nd_compref == stp->ls_compref || 5311 ((nd->nd_flag & ND_IMPLIEDCLID) && 5312 clp->lc_clientid.qval == nd->nd_clientid.qval) || 5313 nfsaddr2_match(clp->lc_req.nr_nam, nd->nd_nam)) { 5314 NFSUNLOCKSTATE(); 5315 goto out; 5316 } 5317 5318 /* 5319 * We are now done with the delegation state structure, 5320 * so the statelock can be released and we can now tsleep(). 5321 */ 5322 5323 /* 5324 * Now, we must do the CB Getattr callback, to see if Change or Size 5325 * has changed. 5326 */ 5327 if (clp->lc_expiry >= NFSD_MONOSEC) { 5328 NFSUNLOCKSTATE(); 5329 NFSVNO_ATTRINIT(&nva); 5330 nva.na_filerev = NFS64BITSSET; 5331 error = nfsrv_docallback(clp, NFSV4OP_CBGETATTR, NULL, 5332 0, &nfh, &nva, &cbbits, p); 5333 if (!error) { 5334 if ((nva.na_filerev != NFS64BITSSET && 5335 nva.na_filerev > delegfilerev) || 5336 (NFSVNO_ISSETSIZE(&nva) && 5337 nva.na_size != nvap->na_size)) { 5338 error = nfsvno_updfilerev(vp, nvap, cred, p); 5339 if (NFSVNO_ISSETSIZE(&nva)) 5340 nvap->na_size = nva.na_size; 5341 } 5342 } else 5343 error = 0; /* Ignore callback errors for now. */ 5344 } else { 5345 NFSUNLOCKSTATE(); 5346 } 5347 5348out: 5349 NFSEXITCODE2(error, nd); 5350 return (error); 5351} 5352 5353/* 5354 * This function looks for openowners that haven't had any opens for 5355 * a while and throws them away. Called by an nfsd when NFSNSF_NOOPENS 5356 * is set. 5357 */ 5358APPLESTATIC void 5359nfsrv_throwawayopens(NFSPROC_T *p) 5360{ 5361 struct nfsclient *clp, *nclp; 5362 struct nfsstate *stp, *nstp; 5363 int i; 5364 5365 NFSLOCKSTATE(); 5366 nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NOOPENS; 5367 /* 5368 * For each client... 5369 */ 5370 for (i = 0; i < nfsrv_clienthashsize; i++) { 5371 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 5372 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { 5373 if (LIST_EMPTY(&stp->ls_open) && 5374 (stp->ls_noopens > NFSNOOPEN || 5375 (nfsrv_openpluslock * 2) > 5376 nfsrv_v4statelimit)) 5377 nfsrv_freeopenowner(stp, 0, p); 5378 } 5379 } 5380 } 5381 NFSUNLOCKSTATE(); 5382} 5383 5384/* 5385 * This function checks to see if the credentials are the same. 5386 * Returns 1 for not same, 0 otherwise. 5387 */ 5388static int 5389nfsrv_notsamecredname(struct nfsrv_descript *nd, struct nfsclient *clp) 5390{ 5391 5392 if (nd->nd_flag & ND_GSS) { 5393 if (!(clp->lc_flags & LCL_GSS)) 5394 return (1); 5395 if (clp->lc_flags & LCL_NAME) { 5396 if (nd->nd_princlen != clp->lc_namelen || 5397 NFSBCMP(nd->nd_principal, clp->lc_name, 5398 clp->lc_namelen)) 5399 return (1); 5400 else 5401 return (0); 5402 } 5403 if (nd->nd_cred->cr_uid == clp->lc_uid) 5404 return (0); 5405 else 5406 return (1); 5407 } else if (clp->lc_flags & LCL_GSS) 5408 return (1); 5409 /* 5410 * For AUTH_SYS, allow the same uid or root. (This is underspecified 5411 * in RFC3530, which talks about principals, but doesn't say anything 5412 * about uids for AUTH_SYS.) 5413 */ 5414 if (nd->nd_cred->cr_uid == clp->lc_uid || nd->nd_cred->cr_uid == 0) 5415 return (0); 5416 else 5417 return (1); 5418} 5419 5420/* 5421 * Calculate the lease expiry time. 5422 */ 5423static time_t 5424nfsrv_leaseexpiry(void) 5425{ 5426 5427 if (nfsrv_stablefirst.nsf_eograce > NFSD_MONOSEC) 5428 return (NFSD_MONOSEC + 2 * (nfsrv_lease + NFSRV_LEASEDELTA)); 5429 return (NFSD_MONOSEC + nfsrv_lease + NFSRV_LEASEDELTA); 5430} 5431 5432/* 5433 * Delay the delegation timeout as far as ls_delegtimelimit, as required. 5434 */ 5435static void 5436nfsrv_delaydelegtimeout(struct nfsstate *stp) 5437{ 5438 5439 if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0) 5440 return; 5441 5442 if ((stp->ls_delegtime + 15) > NFSD_MONOSEC && 5443 stp->ls_delegtime < stp->ls_delegtimelimit) { 5444 stp->ls_delegtime += nfsrv_lease; 5445 if (stp->ls_delegtime > stp->ls_delegtimelimit) 5446 stp->ls_delegtime = stp->ls_delegtimelimit; 5447 } 5448} 5449 5450/* 5451 * This function checks to see if there is any other state associated 5452 * with the openowner for this Open. 5453 * It returns 1 if there is no other state, 0 otherwise. 5454 */ 5455static int 5456nfsrv_nootherstate(struct nfsstate *stp) 5457{ 5458 struct nfsstate *tstp; 5459 5460 LIST_FOREACH(tstp, &stp->ls_openowner->ls_open, ls_list) { 5461 if (tstp != stp || !LIST_EMPTY(&tstp->ls_lock)) 5462 return (0); 5463 } 5464 return (1); 5465} 5466 5467/* 5468 * Create a list of lock deltas (changes to local byte range locking 5469 * that can be rolled back using the list) and apply the changes via 5470 * nfsvno_advlock(). Optionally, lock the list. It is expected that either 5471 * the rollback or update function will be called after this. 5472 * It returns an error (and rolls back, as required), if any nfsvno_advlock() 5473 * call fails. If it returns an error, it will unlock the list. 5474 */ 5475static int 5476nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 5477 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 5478{ 5479 struct nfslock *lop, *nlop; 5480 int error = 0; 5481 5482 /* Loop through the list of locks. */ 5483 lop = LIST_FIRST(&lfp->lf_locallock); 5484 while (first < end && lop != NULL) { 5485 nlop = LIST_NEXT(lop, lo_lckowner); 5486 if (first >= lop->lo_end) { 5487 /* not there yet */ 5488 lop = nlop; 5489 } else if (first < lop->lo_first) { 5490 /* new one starts before entry in list */ 5491 if (end <= lop->lo_first) { 5492 /* no overlap between old and new */ 5493 error = nfsrv_dolocal(vp, lfp, flags, 5494 NFSLCK_UNLOCK, first, end, cfp, p); 5495 if (error != 0) 5496 break; 5497 first = end; 5498 } else { 5499 /* handle fragment overlapped with new one */ 5500 error = nfsrv_dolocal(vp, lfp, flags, 5501 NFSLCK_UNLOCK, first, lop->lo_first, cfp, 5502 p); 5503 if (error != 0) 5504 break; 5505 first = lop->lo_first; 5506 } 5507 } else { 5508 /* new one overlaps this entry in list */ 5509 if (end <= lop->lo_end) { 5510 /* overlaps all of new one */ 5511 error = nfsrv_dolocal(vp, lfp, flags, 5512 lop->lo_flags, first, end, cfp, p); 5513 if (error != 0) 5514 break; 5515 first = end; 5516 } else { 5517 /* handle fragment overlapped with new one */ 5518 error = nfsrv_dolocal(vp, lfp, flags, 5519 lop->lo_flags, first, lop->lo_end, cfp, p); 5520 if (error != 0) 5521 break; 5522 first = lop->lo_end; 5523 lop = nlop; 5524 } 5525 } 5526 } 5527 if (first < end && error == 0) 5528 /* handle fragment past end of list */ 5529 error = nfsrv_dolocal(vp, lfp, flags, NFSLCK_UNLOCK, first, 5530 end, cfp, p); 5531 5532 NFSEXITCODE(error); 5533 return (error); 5534} 5535 5536/* 5537 * Local lock unlock. Unlock all byte ranges that are no longer locked 5538 * by NFSv4. To do this, unlock any subranges of first-->end that 5539 * do not overlap with the byte ranges of any lock in the lfp->lf_lock 5540 * list. This list has all locks for the file held by other 5541 * <clientid, lockowner> tuples. The list is ordered by increasing 5542 * lo_first value, but may have entries that overlap each other, for 5543 * the case of read locks. 5544 */ 5545static void 5546nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first, 5547 uint64_t init_end, NFSPROC_T *p) 5548{ 5549 struct nfslock *lop; 5550 uint64_t first, end, prevfirst; 5551 5552 first = init_first; 5553 end = init_end; 5554 while (first < init_end) { 5555 /* Loop through all nfs locks, adjusting first and end */ 5556 prevfirst = 0; 5557 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 5558 KASSERT(prevfirst <= lop->lo_first, 5559 ("nfsv4 locks out of order")); 5560 KASSERT(lop->lo_first < lop->lo_end, 5561 ("nfsv4 bogus lock")); 5562 prevfirst = lop->lo_first; 5563 if (first >= lop->lo_first && 5564 first < lop->lo_end) 5565 /* 5566 * Overlaps with initial part, so trim 5567 * off that initial part by moving first past 5568 * it. 5569 */ 5570 first = lop->lo_end; 5571 else if (end > lop->lo_first && 5572 lop->lo_first > first) { 5573 /* 5574 * This lock defines the end of the 5575 * segment to unlock, so set end to the 5576 * start of it and break out of the loop. 5577 */ 5578 end = lop->lo_first; 5579 break; 5580 } 5581 if (first >= end) 5582 /* 5583 * There is no segment left to do, so 5584 * break out of this loop and then exit 5585 * the outer while() since first will be set 5586 * to end, which must equal init_end here. 5587 */ 5588 break; 5589 } 5590 if (first < end) { 5591 /* Unlock this segment */ 5592 (void) nfsrv_dolocal(vp, lfp, NFSLCK_UNLOCK, 5593 NFSLCK_READ, first, end, NULL, p); 5594 nfsrv_locallock_commit(lfp, NFSLCK_UNLOCK, 5595 first, end); 5596 } 5597 /* 5598 * Now move past this segment and look for any further 5599 * segment in the range, if there is one. 5600 */ 5601 first = end; 5602 end = init_end; 5603 } 5604} 5605 5606/* 5607 * Do the local lock operation and update the rollback list, as required. 5608 * Perform the rollback and return the error if nfsvno_advlock() fails. 5609 */ 5610static int 5611nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, int oldflags, 5612 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 5613{ 5614 struct nfsrollback *rlp; 5615 int error = 0, ltype, oldltype; 5616 5617 if (flags & NFSLCK_WRITE) 5618 ltype = F_WRLCK; 5619 else if (flags & NFSLCK_READ) 5620 ltype = F_RDLCK; 5621 else 5622 ltype = F_UNLCK; 5623 if (oldflags & NFSLCK_WRITE) 5624 oldltype = F_WRLCK; 5625 else if (oldflags & NFSLCK_READ) 5626 oldltype = F_RDLCK; 5627 else 5628 oldltype = F_UNLCK; 5629 if (ltype == oldltype || (oldltype == F_WRLCK && ltype == F_RDLCK)) 5630 /* nothing to do */ 5631 goto out; 5632 error = nfsvno_advlock(vp, ltype, first, end, p); 5633 if (error != 0) { 5634 if (cfp != NULL) { 5635 cfp->cl_clientid.lval[0] = 0; 5636 cfp->cl_clientid.lval[1] = 0; 5637 cfp->cl_first = 0; 5638 cfp->cl_end = NFS64BITSSET; 5639 cfp->cl_flags = NFSLCK_WRITE; 5640 cfp->cl_ownerlen = 5; 5641 NFSBCOPY("LOCAL", cfp->cl_owner, 5); 5642 } 5643 nfsrv_locallock_rollback(vp, lfp, p); 5644 } else if (ltype != F_UNLCK) { 5645 rlp = malloc(sizeof (struct nfsrollback), M_NFSDROLLBACK, 5646 M_WAITOK); 5647 rlp->rlck_first = first; 5648 rlp->rlck_end = end; 5649 rlp->rlck_type = oldltype; 5650 LIST_INSERT_HEAD(&lfp->lf_rollback, rlp, rlck_list); 5651 } 5652 5653out: 5654 NFSEXITCODE(error); 5655 return (error); 5656} 5657 5658/* 5659 * Roll back local lock changes and free up the rollback list. 5660 */ 5661static void 5662nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, NFSPROC_T *p) 5663{ 5664 struct nfsrollback *rlp, *nrlp; 5665 5666 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) { 5667 (void) nfsvno_advlock(vp, rlp->rlck_type, rlp->rlck_first, 5668 rlp->rlck_end, p); 5669 free(rlp, M_NFSDROLLBACK); 5670 } 5671 LIST_INIT(&lfp->lf_rollback); 5672} 5673 5674/* 5675 * Update local lock list and delete rollback list (ie now committed to the 5676 * local locks). Most of the work is done by the internal function. 5677 */ 5678static void 5679nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, uint64_t first, 5680 uint64_t end) 5681{ 5682 struct nfsrollback *rlp, *nrlp; 5683 struct nfslock *new_lop, *other_lop; 5684 5685 new_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK); 5686 if (flags & (NFSLCK_READ | NFSLCK_WRITE)) 5687 other_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, 5688 M_WAITOK); 5689 else 5690 other_lop = NULL; 5691 new_lop->lo_flags = flags; 5692 new_lop->lo_first = first; 5693 new_lop->lo_end = end; 5694 nfsrv_updatelock(NULL, &new_lop, &other_lop, lfp); 5695 if (new_lop != NULL) 5696 free(new_lop, M_NFSDLOCK); 5697 if (other_lop != NULL) 5698 free(other_lop, M_NFSDLOCK); 5699 5700 /* and get rid of the rollback list */ 5701 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) 5702 free(rlp, M_NFSDROLLBACK); 5703 LIST_INIT(&lfp->lf_rollback); 5704} 5705 5706/* 5707 * Lock the struct nfslockfile for local lock updating. 5708 */ 5709static void 5710nfsrv_locklf(struct nfslockfile *lfp) 5711{ 5712 int gotlock; 5713 5714 /* lf_usecount ensures *lfp won't be free'd */ 5715 lfp->lf_usecount++; 5716 do { 5717 gotlock = nfsv4_lock(&lfp->lf_locallock_lck, 1, NULL, 5718 NFSSTATEMUTEXPTR, NULL); 5719 } while (gotlock == 0); 5720 lfp->lf_usecount--; 5721} 5722 5723/* 5724 * Unlock the struct nfslockfile after local lock updating. 5725 */ 5726static void 5727nfsrv_unlocklf(struct nfslockfile *lfp) 5728{ 5729 5730 nfsv4_unlock(&lfp->lf_locallock_lck, 0); 5731} 5732 5733/* 5734 * Clear out all state for the NFSv4 server. 5735 * Must be called by a thread that can sleep when no nfsds are running. 5736 */ 5737void 5738nfsrv_throwawayallstate(NFSPROC_T *p) 5739{ 5740 struct nfsclient *clp, *nclp; 5741 struct nfslockfile *lfp, *nlfp; 5742 int i; 5743 5744 /* 5745 * For each client, clean out the state and then free the structure. 5746 */ 5747 for (i = 0; i < nfsrv_clienthashsize; i++) { 5748 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 5749 nfsrv_cleanclient(clp, p); 5750 nfsrv_freedeleglist(&clp->lc_deleg); 5751 nfsrv_freedeleglist(&clp->lc_olddeleg); 5752 free(clp->lc_stateid, M_NFSDCLIENT); 5753 free(clp, M_NFSDCLIENT); 5754 } 5755 } 5756 5757 /* 5758 * Also, free up any remaining lock file structures. 5759 */ 5760 for (i = 0; i < nfsrv_lockhashsize; i++) { 5761 LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { 5762 printf("nfsd unload: fnd a lock file struct\n"); 5763 nfsrv_freenfslockfile(lfp); 5764 } 5765 } 5766} 5767 5768/* 5769 * Check the sequence# for the session and slot provided as an argument. 5770 * Also, renew the lease if the session will return NFS_OK. 5771 */ 5772int 5773nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid, 5774 uint32_t *highest_slotidp, uint32_t *target_highest_slotidp, int cache_this, 5775 uint32_t *sflagsp, NFSPROC_T *p) 5776{ 5777 struct nfsdsession *sep; 5778 struct nfssessionhash *shp; 5779 int error; 5780 SVCXPRT *savxprt; 5781 5782 shp = NFSSESSIONHASH(nd->nd_sessionid); 5783 NFSLOCKSESSION(shp); 5784 sep = nfsrv_findsession(nd->nd_sessionid); 5785 if (sep == NULL) { 5786 NFSUNLOCKSESSION(shp); 5787 return (NFSERR_BADSESSION); 5788 } 5789 error = nfsv4_seqsession(sequenceid, nd->nd_slotid, *highest_slotidp, 5790 sep->sess_slots, NULL, NFSV4_SLOTS - 1); 5791 if (error != 0) { 5792 NFSUNLOCKSESSION(shp); 5793 return (error); 5794 } 5795 if (cache_this != 0) 5796 nd->nd_flag |= ND_SAVEREPLY; 5797 /* Renew the lease. */ 5798 sep->sess_clp->lc_expiry = nfsrv_leaseexpiry(); 5799 nd->nd_clientid.qval = sep->sess_clp->lc_clientid.qval; 5800 nd->nd_flag |= ND_IMPLIEDCLID; 5801 5802 /* 5803 * If this session handles the backchannel, save the nd_xprt for this 5804 * RPC, since this is the one being used. 5805 */ 5806 if (sep->sess_clp->lc_req.nr_client != NULL && 5807 (sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) { 5808 savxprt = sep->sess_cbsess.nfsess_xprt; 5809 SVC_ACQUIRE(nd->nd_xprt); 5810 nd->nd_xprt->xp_p2 = 5811 sep->sess_clp->lc_req.nr_client->cl_private; 5812 nd->nd_xprt->xp_idletimeout = 0; /* Disable timeout. */ 5813 sep->sess_cbsess.nfsess_xprt = nd->nd_xprt; 5814 if (savxprt != NULL) 5815 SVC_RELEASE(savxprt); 5816 } 5817 5818 *sflagsp = 0; 5819 if (sep->sess_clp->lc_req.nr_client == NULL) 5820 *sflagsp |= NFSV4SEQ_CBPATHDOWN; 5821 NFSUNLOCKSESSION(shp); 5822 if (error == NFSERR_EXPIRED) { 5823 *sflagsp |= NFSV4SEQ_EXPIREDALLSTATEREVOKED; 5824 error = 0; 5825 } else if (error == NFSERR_ADMINREVOKED) { 5826 *sflagsp |= NFSV4SEQ_ADMINSTATEREVOKED; 5827 error = 0; 5828 } 5829 *highest_slotidp = *target_highest_slotidp = NFSV4_SLOTS - 1; 5830 return (0); 5831} 5832 5833/* 5834 * Check/set reclaim complete for this session/clientid. 5835 */ 5836int 5837nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd) 5838{ 5839 struct nfsdsession *sep; 5840 struct nfssessionhash *shp; 5841 int error = 0; 5842 5843 shp = NFSSESSIONHASH(nd->nd_sessionid); 5844 NFSLOCKSTATE(); 5845 NFSLOCKSESSION(shp); 5846 sep = nfsrv_findsession(nd->nd_sessionid); 5847 if (sep == NULL) { 5848 NFSUNLOCKSESSION(shp); 5849 NFSUNLOCKSTATE(); 5850 return (NFSERR_BADSESSION); 5851 } 5852 5853 /* Check to see if reclaim complete has already happened. */ 5854 if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0) 5855 error = NFSERR_COMPLETEALREADY; 5856 else 5857 sep->sess_clp->lc_flags |= LCL_RECLAIMCOMPLETE; 5858 NFSUNLOCKSESSION(shp); 5859 NFSUNLOCKSTATE(); 5860 return (error); 5861} 5862 5863/* 5864 * Cache the reply in a session slot. 5865 */ 5866void 5867nfsrv_cache_session(uint8_t *sessionid, uint32_t slotid, int repstat, 5868 struct mbuf **m) 5869{ 5870 struct nfsdsession *sep; 5871 struct nfssessionhash *shp; 5872 5873 shp = NFSSESSIONHASH(sessionid); 5874 NFSLOCKSESSION(shp); 5875 sep = nfsrv_findsession(sessionid); 5876 if (sep == NULL) { 5877 NFSUNLOCKSESSION(shp); 5878 printf("nfsrv_cache_session: no session\n"); 5879 m_freem(*m); 5880 return; 5881 } 5882 nfsv4_seqsess_cacherep(slotid, sep->sess_slots, repstat, m); 5883 NFSUNLOCKSESSION(shp); 5884} 5885 5886/* 5887 * Search for a session that matches the sessionid. 5888 */ 5889static struct nfsdsession * 5890nfsrv_findsession(uint8_t *sessionid) 5891{ 5892 struct nfsdsession *sep; 5893 struct nfssessionhash *shp; 5894 5895 shp = NFSSESSIONHASH(sessionid); 5896 LIST_FOREACH(sep, &shp->list, sess_hash) { 5897 if (!NFSBCMP(sessionid, sep->sess_sessionid, NFSX_V4SESSIONID)) 5898 break; 5899 } 5900 return (sep); 5901} 5902 5903/* 5904 * Destroy a session. 5905 */ 5906int 5907nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid) 5908{ 5909 int error, samesess; 5910 5911 samesess = 0; 5912 if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID)) { 5913 samesess = 1; 5914 if ((nd->nd_flag & ND_LASTOP) == 0) 5915 return (NFSERR_BADSESSION); 5916 } 5917 error = nfsrv_freesession(NULL, sessionid); 5918 if (error == 0 && samesess != 0) 5919 nd->nd_flag &= ~ND_HASSEQUENCE; 5920 return (error); 5921} 5922 5923/* 5924 * Free up a session structure. 5925 */ 5926static int 5927nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid) 5928{ 5929 struct nfssessionhash *shp; 5930 int i; 5931 5932 NFSLOCKSTATE(); 5933 if (sep == NULL) { 5934 shp = NFSSESSIONHASH(sessionid); 5935 NFSLOCKSESSION(shp); 5936 sep = nfsrv_findsession(sessionid); 5937 } else { 5938 shp = NFSSESSIONHASH(sep->sess_sessionid); 5939 NFSLOCKSESSION(shp); 5940 } 5941 if (sep != NULL) { 5942 sep->sess_refcnt--; 5943 if (sep->sess_refcnt > 0) { 5944 NFSUNLOCKSESSION(shp); 5945 NFSUNLOCKSTATE(); 5946 return (0); 5947 } 5948 LIST_REMOVE(sep, sess_hash); 5949 LIST_REMOVE(sep, sess_list); 5950 } 5951 NFSUNLOCKSESSION(shp); 5952 NFSUNLOCKSTATE(); 5953 if (sep == NULL) 5954 return (NFSERR_BADSESSION); 5955 for (i = 0; i < NFSV4_SLOTS; i++) 5956 if (sep->sess_slots[i].nfssl_reply != NULL) 5957 m_freem(sep->sess_slots[i].nfssl_reply); 5958 if (sep->sess_cbsess.nfsess_xprt != NULL) 5959 SVC_RELEASE(sep->sess_cbsess.nfsess_xprt); 5960 free(sep, M_NFSDSESSION); 5961 return (0); 5962} 5963 5964/* 5965 * Free a stateid. 5966 * RFC5661 says that it should fail when there are associated opens, locks 5967 * or delegations. Since stateids represent opens, I don't see how you can 5968 * free an open stateid (it will be free'd when closed), so this function 5969 * only works for lock stateids (freeing the lock_owner) or delegations. 5970 */ 5971int 5972nfsrv_freestateid(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, 5973 NFSPROC_T *p) 5974{ 5975 struct nfsclient *clp; 5976 struct nfsstate *stp; 5977 int error; 5978 5979 NFSLOCKSTATE(); 5980 /* 5981 * Look up the stateid 5982 */ 5983 error = nfsrv_getclient((nfsquad_t)((u_quad_t)0), CLOPS_RENEW, &clp, 5984 NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 5985 if (error == 0) { 5986 /* First, check for a delegation. */ 5987 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) { 5988 if (!NFSBCMP(stp->ls_stateid.other, stateidp->other, 5989 NFSX_STATEIDOTHER)) 5990 break; 5991 } 5992 if (stp != NULL) { 5993 nfsrv_freedeleg(stp); 5994 NFSUNLOCKSTATE(); 5995 return (error); 5996 } 5997 } 5998 /* Not a delegation, try for a lock_owner. */ 5999 if (error == 0) 6000 error = nfsrv_getstate(clp, stateidp, 0, &stp); 6001 if (error == 0 && ((stp->ls_flags & (NFSLCK_OPEN | NFSLCK_DELEGREAD | 6002 NFSLCK_DELEGWRITE)) != 0 || (stp->ls_flags & NFSLCK_LOCK) == 0)) 6003 /* Not a lock_owner stateid. */ 6004 error = NFSERR_LOCKSHELD; 6005 if (error == 0 && !LIST_EMPTY(&stp->ls_lock)) 6006 error = NFSERR_LOCKSHELD; 6007 if (error == 0) 6008 nfsrv_freelockowner(stp, NULL, 0, p); 6009 NFSUNLOCKSTATE(); 6010 return (error); 6011} 6012 6013/* 6014 * Generate the xdr for an NFSv4.1 CBSequence Operation. 6015 */ 6016static int 6017nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp, 6018 int dont_replycache, struct nfsdsession **sepp) 6019{ 6020 struct nfsdsession *sep; 6021 uint32_t *tl, slotseq = 0; 6022 int maxslot, slotpos; 6023 uint8_t sessionid[NFSX_V4SESSIONID]; 6024 int error; 6025 6026 error = nfsv4_getcbsession(clp, sepp); 6027 if (error != 0) 6028 return (error); 6029 sep = *sepp; 6030 (void)nfsv4_sequencelookup(NULL, &sep->sess_cbsess, &slotpos, &maxslot, 6031 &slotseq, sessionid); 6032 KASSERT(maxslot >= 0, ("nfsv4_setcbsequence neg maxslot")); 6033 6034 /* Build the Sequence arguments. */ 6035 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 5 * NFSX_UNSIGNED); 6036 bcopy(sessionid, tl, NFSX_V4SESSIONID); 6037 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 6038 nd->nd_slotseq = tl; 6039 *tl++ = txdr_unsigned(slotseq); 6040 *tl++ = txdr_unsigned(slotpos); 6041 *tl++ = txdr_unsigned(maxslot); 6042 if (dont_replycache == 0) 6043 *tl++ = newnfs_true; 6044 else 6045 *tl++ = newnfs_false; 6046 *tl = 0; /* No referring call list, for now. */ 6047 nd->nd_flag |= ND_HASSEQUENCE; 6048 return (0); 6049} 6050 6051/* 6052 * Get a session for the callback. 6053 */ 6054static int 6055nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp) 6056{ 6057 struct nfsdsession *sep; 6058 6059 NFSLOCKSTATE(); 6060 LIST_FOREACH(sep, &clp->lc_session, sess_list) { 6061 if ((sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) 6062 break; 6063 } 6064 if (sep == NULL) { 6065 NFSUNLOCKSTATE(); 6066 return (NFSERR_BADSESSION); 6067 } 6068 sep->sess_refcnt++; 6069 *sepp = sep; 6070 NFSUNLOCKSTATE(); 6071 return (0); 6072} 6073 6074/* 6075 * Free up all backchannel xprts. This needs to be done when the nfsd threads 6076 * exit, since those transports will all be going away. 6077 * This is only called after all the nfsd threads are done performing RPCs, 6078 * so locking shouldn't be an issue. 6079 */ 6080APPLESTATIC void 6081nfsrv_freeallbackchannel_xprts(void) 6082{ 6083 struct nfsdsession *sep; 6084 struct nfsclient *clp; 6085 SVCXPRT *xprt; 6086 int i; 6087 6088 for (i = 0; i < nfsrv_clienthashsize; i++) { 6089 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 6090 LIST_FOREACH(sep, &clp->lc_session, sess_list) { 6091 xprt = sep->sess_cbsess.nfsess_xprt; 6092 sep->sess_cbsess.nfsess_xprt = NULL; 6093 if (xprt != NULL) 6094 SVC_RELEASE(xprt); 6095 } 6096 } 6097 } 6098} 6099 6100