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