nfs_nfsdstate.c revision 1.6 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