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