1 /* $Id: nfs_vfsops.c,v 1.38 2003/11/05 14:59:01 rees Exp $ */
2
3 /*-
4 * copyright (c) 2003
5 * the regents of the university of michigan
6 * all rights reserved
7 *
8 * permission is granted to use, copy, create derivative works and redistribute
9 * this software and such derivative works for any purpose, so long as the name
10 * of the university of michigan is not used in any advertising or publicity
11 * pertaining to the use or distribution of this software without specific,
12 * written prior authorization. if the above copyright notice or any other
13 * identification of the university of michigan is included in any copy of any
14 * portion of this software, then the disclaimer below must also be included.
15 *
16 * this software is provided as is, without representation from the university
17 * of michigan as to its fitness for any purpose, and without warranty by the
18 * university of michigan of any kind, either express or implied, including
19 * without limitation the implied warranties of merchantability and fitness for
20 * a particular purpose. the regents of the university of michigan shall not be
21 * liable for any damages, including special, indirect, incidental, or
22 * consequential damages, with respect to any claim arising out of or in
23 * connection with the use of the software, even if it has been or is hereafter
24 * advised of the possibility of such damages.
25 */
26
27 /*-
28 * Copyright (c) 1989, 1993, 1995
29 * The Regents of the University of California. All rights reserved.
30 *
31 * This code is derived from software contributed to Berkeley by
32 * Rick Macklem at The University of Guelph.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
59 */
60
61 #include <sys/cdefs.h>
62 __FBSDID("$FreeBSD$");
63
64 #include "opt_bootp.h"
65 #include "opt_nfsroot.h"
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/kthread.h>
71 #include <sys/limits.h>
72 #include <sys/lock.h>
73 #include <sys/malloc.h>
74 #include <sys/mbuf.h>
75 #include <sys/module.h>
76 #include <sys/mount.h>
77 #include <sys/proc.h>
78 #include <sys/socket.h>
79 #include <sys/socketvar.h>
80 #include <sys/sockio.h>
81 #include <sys/sysctl.h>
82 #include <sys/unistd.h>
83 #include <sys/vnode.h>
84 #include <sys/signalvar.h>
85
86 #include <vm/vm.h>
87 #include <vm/vm_extern.h>
88 #include <vm/uma.h>
89
90 #include <net/if.h>
91 #include <net/route.h>
92 #include <netinet/in.h>
93 #include <netinet/in_var.h>
94
95 #include <rpc/rpcclnt.h>
96
97 #include <nfs/rpcv2.h>
98 #include <nfs/nfsproto.h>
99 #include <nfsclient/nfs.h>
100 #include <nfs4client/nfs4.h>
101 #include <nfsclient/nfsnode.h>
102 #include <nfsclient/nfsmount.h>
103 #include <nfs/xdr_subs.h>
104 #include <nfsclient/nfsm_subs.h>
105 #include <nfsclient/nfsdiskless.h>
106
107 #include <nfs4client/nfs4m_subs.h>
108 #include <nfs4client/nfs4_vfs.h>
109
110 #include <nfs4client/nfs4_dev.h>
111 #include <nfs4client/nfs4_idmap.h>
112
113 SYSCTL_NODE(_vfs, OID_AUTO, nfs4, CTLFLAG_RW, 0, "NFS4 filesystem");
114 SYSCTL_STRUCT(_vfs_nfs4, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
115 &nfsstats, nfsstats, "S,nfsstats");
116
117 static void nfs4_decode_args(struct nfsmount *nmp, struct nfs_args *argp);
118 static void nfs4_daemon(void *arg);
119 static int mountnfs(struct nfs_args *, struct mount *,
120 struct sockaddr *, char *, struct vnode **,
121 struct ucred *cred);
122 static int nfs4_do_setclientid(struct nfsmount *nmp, struct ucred *cred);
123 static vfs_mount_t nfs4_mount;
124 static vfs_cmount_t nfs4_cmount;
125 static vfs_unmount_t nfs4_unmount;
126 static vfs_root_t nfs4_root;
127 static vfs_statfs_t nfs4_statfs;
128 static vfs_sync_t nfs4_sync;
129
130 /*
131 * nfs vfs operations.
132 */
133 static struct vfsops nfs4_vfsops = {
134 .vfs_init = nfs4_init,
135 .vfs_mount = nfs4_mount,
136 .vfs_cmount = nfs4_cmount,
137 .vfs_root = nfs4_root,
138 .vfs_statfs = nfs4_statfs,
139 .vfs_sync = nfs4_sync,
140 .vfs_uninit = nfs4_uninit,
141 .vfs_unmount = nfs4_unmount,
142 };
143 VFS_SET(nfs4_vfsops, nfs4, VFCF_NETWORK);
144
145 static struct nfs_rpcops nfs4_rpcops = {
146 nfs4_readrpc,
147 nfs4_writerpc,
148 nfs4_writebp,
149 nfs4_readlinkrpc,
150 nfs4_invaldir,
151 nfs4_commit,
152 };
153
154 /* So that loader and kldload(2) can find us, wherever we are.. */
155 MODULE_VERSION(nfs4, 1);
156
157 void nfsargs_ntoh(struct nfs_args *);
158
159 int
160 nfs4_init(struct vfsconf *vfsp)
161 {
162
163 rpcclnt_init();
164 nfs4dev_init();
165 idmap_init();
166 nfsm_v4init();
167
168 return (0);
169 }
170
171 int
172 nfs4_uninit(struct vfsconf *vfsp)
173 {
174
175 rpcclnt_uninit();
176 nfs4dev_uninit();
177 idmap_uninit();
178
179 return (0);
180 }
181
182 /*
183 * nfs statfs call
184 */
185 static int
186 nfs4_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
187 {
188 struct vnode *vp;
189 struct nfs_statfs *sfp;
190 caddr_t bpos, dpos;
191 struct nfsmount *nmp = VFSTONFS(mp);
192 int error = 0;
193 struct mbuf *mreq, *mrep = NULL, *md, *mb;
194 struct nfsnode *np;
195 struct nfs4_compound cp;
196 struct nfs4_oparg_getattr ga;
197 struct nfsv4_fattr *fap = &ga.fa;
198
199 #ifndef nolint
200 sfp = NULL;
201 #endif
202 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
203 if (error)
204 return (error);
205 vp = NFSTOV(np);
206 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
207 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, NFSX_FH(1));
208 mb = mreq;
209 bpos = mtod(mb, caddr_t);
210
211 ga.bm = &nfsv4_fsattrbm;
212 nfs_v4initcompound(&cp);
213
214 nfsm_v4build_compound(&cp, "statfs()");
215 nfsm_v4build_putfh(&cp, vp);
216 nfsm_v4build_getattr(&cp, &ga);
217 nfsm_v4build_finalize(&cp);
218
219 nfsm_request(vp, NFSV4PROC_COMPOUND, td, td->td_ucred);
220 if (error != 0)
221 goto nfsmout;
222
223 nfsm_v4dissect_compound(&cp);
224 nfsm_v4dissect_putfh(&cp);
225 nfsm_v4dissect_getattr(&cp, &ga);
226
227 nfs4_vfsop_statfs(fap, sbp, mp);
228
229 nfsmout:
230 error = nfs_v4postop(&cp, error);
231
232 vput(vp);
233 if (mrep != NULL)
234 m_freem(mrep);
235
236 return (error);
237 }
238
239 static void
240 nfs4_decode_args(struct nfsmount *nmp, struct nfs_args *argp)
241 {
242 int s;
243 int adjsock;
244 int maxio;
245
246 s = splnet();
247
248 /*
249 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
250 * no sense in that context. Also, set appropriate retransmit
251 * and soft timeout behavior.
252 */
253 if (argp->sotype == SOCK_STREAM) {
254 nmp->nm_flag &= ~NFSMNT_NOCONN;
255 nmp->nm_flag |= NFSMNT_DUMBTIMR;
256 nmp->nm_timeo = NFS_MAXTIMEO;
257 nmp->nm_retry = NFS_RETRANS_TCP;
258 }
259
260 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
261
262 /* Re-bind if rsrvd port requested and wasn't on one */
263 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
264 && (argp->flags & NFSMNT_RESVPORT);
265 /* Also re-bind if we're switching to/from a connected UDP socket */
266 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
267 (argp->flags & NFSMNT_NOCONN));
268
269 /* Update flags atomically. Don't change the lock bits. */
270 nmp->nm_flag = argp->flags | nmp->nm_flag;
271 splx(s);
272
273 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
274 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
275 if (nmp->nm_timeo < NFS_MINTIMEO)
276 nmp->nm_timeo = NFS_MINTIMEO;
277 else if (nmp->nm_timeo > NFS_MAXTIMEO)
278 nmp->nm_timeo = NFS_MAXTIMEO;
279 }
280
281 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
282 nmp->nm_retry = argp->retrans;
283 if (nmp->nm_retry > NFS_MAXREXMIT)
284 nmp->nm_retry = NFS_MAXREXMIT;
285 }
286
287 if (argp->flags & NFSMNT_NFSV3) {
288 if (argp->sotype == SOCK_DGRAM)
289 maxio = NFS_MAXDGRAMDATA;
290 else
291 maxio = NFS_MAXDATA;
292 } else
293 maxio = NFS_V2MAXDATA;
294
295 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
296 nmp->nm_wsize = argp->wsize;
297 /* Round down to multiple of blocksize */
298 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
299 if (nmp->nm_wsize <= 0)
300 nmp->nm_wsize = NFS_FABLKSIZE;
301 }
302 if (nmp->nm_wsize > maxio)
303 nmp->nm_wsize = maxio;
304 if (nmp->nm_wsize > MAXBSIZE)
305 nmp->nm_wsize = MAXBSIZE;
306
307 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
308 nmp->nm_rsize = argp->rsize;
309 /* Round down to multiple of blocksize */
310 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
311 if (nmp->nm_rsize <= 0)
312 nmp->nm_rsize = NFS_FABLKSIZE;
313 }
314 if (nmp->nm_rsize > maxio)
315 nmp->nm_rsize = maxio;
316 if (nmp->nm_rsize > MAXBSIZE)
317 nmp->nm_rsize = MAXBSIZE;
318
319 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
320 nmp->nm_readdirsize = argp->readdirsize;
321 }
322 if (nmp->nm_readdirsize > maxio)
323 nmp->nm_readdirsize = maxio;
324 if (nmp->nm_readdirsize > nmp->nm_rsize)
325 nmp->nm_readdirsize = nmp->nm_rsize;
326
327 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
328 nmp->nm_acregmin = argp->acregmin;
329 else
330 nmp->nm_acregmin = NFS_MINATTRTIMO;
331 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
332 nmp->nm_acregmax = argp->acregmax;
333 else
334 nmp->nm_acregmax = NFS_MAXATTRTIMO;
335 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
336 nmp->nm_acdirmin = argp->acdirmin;
337 else
338 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
339 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
340 nmp->nm_acdirmax = argp->acdirmax;
341 else
342 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
343 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
344 nmp->nm_acdirmin = nmp->nm_acdirmax;
345 if (nmp->nm_acregmin > nmp->nm_acregmax)
346 nmp->nm_acregmin = nmp->nm_acregmax;
347
348 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) {
349 if (argp->maxgrouplist <= NFS_MAXGRPS)
350 nmp->nm_numgrps = argp->maxgrouplist;
351 else
352 nmp->nm_numgrps = NFS_MAXGRPS;
353 }
354 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
355 if (argp->readahead <= NFS_MAXRAHEAD)
356 nmp->nm_readahead = argp->readahead;
357 else
358 nmp->nm_readahead = NFS_MAXRAHEAD;
359 }
360 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 0) {
361 if (argp->deadthresh <= NFS_MAXDEADTHRESH)
362 nmp->nm_deadthresh = argp->deadthresh;
363 else
364 nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
365 }
366
367 adjsock |= ((nmp->nm_sotype != argp->sotype) ||
368 (nmp->nm_soproto != argp->proto));
369 nmp->nm_sotype = argp->sotype;
370 nmp->nm_soproto = argp->proto;
371
372 if (nmp->nm_rpcclnt.rc_so && adjsock) {
373 nfs_safedisconnect(nmp);
374 if (nmp->nm_sotype == SOCK_DGRAM) {
375 while (nfs4_connect(nmp)) {
376 printf("nfs4_decode_args: retrying connect\n");
377 (void)tsleep(&lbolt, PSOCK, "nfscon", 0);
378 }
379 }
380 }
381 }
382
383 /*
384 * VFS Operations.
385 *
386 * mount system call
387 * It seems a bit dumb to copyinstr() the host and path here and then
388 * bcopy() them in mountnfs(), but I wanted to detect errors before
389 * doing the sockargs() call because sockargs() allocates an mbuf and
390 * an error after that means that I have to release the mbuf.
391 */
392 /* ARGSUSED */
393 static int
394 nfs4_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
395 {
396 struct nfs_args args;
397 int error;
398
399 error = copyin(data, &args, sizeof(struct nfs_args));
400 if (error)
401 return (error);
402 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
403 error = kernel_mount(ma, flags);
404 return (error);
405 }
406
407 static int
408 nfs4_mount(struct mount *mp, struct thread *td)
409 {
410 int error;
411 struct nfs_args args;
412 struct sockaddr *nam;
413 struct vnode *vp;
414 char hst[MNAMELEN];
415 size_t len;
416
417 if (mp->mnt_flag & MNT_ROOTFS) {
418 printf("nfs4_mountroot not supported\n");
419 return (EINVAL);
420 }
421 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, sizeof args);
422 if (error)
423 return (error);
424
425 if (args.version != NFS_ARGSVERSION)
426 return (EPROGMISMATCH);
427 if (mp->mnt_flag & MNT_UPDATE) {
428 struct nfsmount *nmp = VFSTONFS(mp);
429
430 if (nmp == NULL)
431 return (EIO);
432 /*
433 * When doing an update, we can't change from or to
434 * v3, switch lockd strategies or change cookie translation
435 */
436 args.flags = (args.flags &
437 ~(NFSMNT_NFSV3 | NFSMNT_NFSV4 | NFSMNT_NOLOCKD)) |
438 (nmp->nm_flag &
439 (NFSMNT_NFSV3 | NFSMNT_NFSV4 | NFSMNT_NOLOCKD));
440 nfs4_decode_args(nmp, &args);
441 return (0);
442 }
443
444 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
445 if (error)
446 return (error);
447 bzero(&hst[len], MNAMELEN - len);
448 /* sockargs() call must be after above copyin() calls */
449 error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
450 if (error)
451 return (error);
452 error = mountnfs(&args, mp, nam, hst, &vp, td->td_ucred);
453 return (error);
454 }
455
456 /*
457 * renew should be done async
458 * should re-scan mount queue each time
459 */
460 struct proc *nfs4_daemonproc;
461
462 static int
463 nfs4_do_renew(struct nfsmount *nmp, struct ucred *cred)
464 {
465 struct nfs4_compound cp;
466 struct mbuf *mreq, *mrep = NULL, *md, *mb;
467 caddr_t bpos, dpos;
468 int error;
469
470 mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, sizeof(uint64_t));
471 mb = mreq;
472 bpos = mtod(mb, caddr_t);
473
474 nfs_v4initcompound(&cp);
475
476 nfsm_v4build_compound(&cp, "nfs4_do_renew()");
477 nfsm_v4build_renew(&cp, nmp->nm_clientid);
478 nfsm_v4build_finalize(&cp);
479
480 nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
481 if (error != 0)
482 goto nfsmout;
483
484 nfsm_v4dissect_compound(&cp);
485 nfsm_v4dissect_renew(&cp);
486 nmp->nm_last_renewal = time_second;
487 return (0);
488
489 nfsmout:
490 error = nfs_v4postop(&cp, error);
491
492 /* XXX */
493 if (mrep != NULL)
494 m_freem(mrep);
495 return (error);
496 }
497
498 static void
499 nfs4_daemon(void *arg)
500 {
501 struct mount *mp;
502 struct nfsmount *nmp;
503 int nmounts;
504
505 while (1) {
506 nmounts = 0;
507 mtx_lock(&mountlist_mtx);
508 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
509 if (strcmp(mp->mnt_vfc->vfc_name, "nfs4") != 0)
510 continue;
511 nmounts++;
512 nmp = VFSTONFS(mp);
513 if (time_second < nmp->nm_last_renewal + nmp->nm_lease_time - 4)
514 continue;
515 mtx_unlock(&mountlist_mtx);
516 mtx_lock(&Giant);
517 nfs4_do_renew(nmp, (struct ucred *) arg);
518 mtx_unlock(&Giant);
519 mtx_lock(&mountlist_mtx);
520 }
521 mtx_unlock(&mountlist_mtx);
522
523 /* Must kill the daemon here, or module unload will cause a panic */
524 if (nmounts == 0) {
525 mtx_lock(&Giant);
526 nfs4_daemonproc = NULL;
527 mtx_unlock(&Giant);
528 /*printf("nfsv4 renewd exiting\n");*/
529 kthread_exit(0);
530 }
531 tsleep(&nfs4_daemonproc, PVFS, "nfs4", 2 * hz);
532 }
533 }
534
535 /*
536 * Common code for mount and mountroot
537 */
538 static int
539 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
540 char *hst, struct vnode **vpp, struct ucred *cred)
541 {
542 struct nfsmount *nmp;
543 char *rpth, *cp1, *cp2;
544 int nlkup = 0, error;
545 struct nfs4_compound cp;
546 struct mbuf *mreq, *mrep = NULL, *md, *mb;
547 caddr_t bpos, dpos;
548 struct nfs4_oparg_lookup lkup;
549 struct nfs4_oparg_getfh gfh;
550 struct nfs4_oparg_getattr ga;
551 struct thread *td = curthread; /* XXX */
552
553 if (mp->mnt_flag & MNT_UPDATE) {
554 nmp = VFSTONFS(mp);
555 /* update paths, file handles, etc, here XXX */
556 FREE(nam, M_SONAME);
557 return (0);
558 } else {
559 nmp = uma_zalloc(nfsmount_zone, M_WAITOK);
560 bzero((caddr_t)nmp, sizeof (struct nfsmount));
561 TAILQ_INIT(&nmp->nm_bufq);
562 mp->mnt_data = (qaddr_t)nmp;
563 }
564
565 vfs_getnewfsid(mp);
566 nmp->nm_mountp = mp;
567 mtx_init(&nmp->nm_mtx, "NFS4mount lock", NULL, MTX_DEF);
568
569 nmp->nm_maxfilesize = 0xffffffffLL;
570 nmp->nm_timeo = NFS_TIMEO;
571 nmp->nm_retry = NFS_RETRANS;
572 nmp->nm_wsize = NFS_WSIZE;
573 nmp->nm_rsize = NFS_RSIZE;
574 nmp->nm_readdirsize = NFS_READDIRSIZE;
575 nmp->nm_numgrps = NFS_MAXGRPS;
576 nmp->nm_readahead = NFS_DEFRAHEAD;
577 nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
578 vfs_mountedfrom(mp, hst);
579 nmp->nm_nam = nam;
580 /* Set up the sockets and per-host congestion */
581 nmp->nm_sotype = argp->sotype;
582 nmp->nm_soproto = argp->proto;
583 nmp->nm_rpcops = &nfs4_rpcops;
584 /* XXX */
585 mp->mnt_stat.f_iosize = PAGE_SIZE;
586
587 argp->flags |= (NFSMNT_NFSV3 | NFSMNT_NFSV4);
588
589 nfs4_decode_args(nmp, argp);
590
591 if ((error = nfs4_connect(nmp)))
592 goto bad;
593
594 mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
595 mb = mreq;
596 bpos = mtod(mb, caddr_t);
597
598 ga.bm = &nfsv4_fsinfobm;
599 nfs_v4initcompound(&cp);
600
601 /* Get remote path */
602 rpth = hst;
603 strsep(&rpth, ":");
604
605 nfsm_v4build_compound(&cp, "mountnfs()");
606 nfsm_v4build_putrootfh(&cp);
607 for (cp1 = rpth; cp1 && *cp1; cp1 = cp2) {
608 while (*cp1 == '/')
609 cp1++;
610 if (!*cp1)
611 break;
612 for (cp2 = cp1; *cp2 && *cp2 != '/'; cp2++)
613 ;
614 lkup.name = cp1;
615 lkup.namelen = cp2 - cp1;
616 nfsm_v4build_lookup(&cp, &lkup);
617 nlkup++;
618 }
619 nfsm_v4build_getfh(&cp, &gfh);
620 nfsm_v4build_getattr(&cp, &ga);
621 nfsm_v4build_finalize(&cp);
622
623 nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, td, cred);
624 if (error != 0)
625 goto nfsmout;
626
627 nfsm_v4dissect_compound(&cp);
628 nfsm_v4dissect_putrootfh(&cp);
629 while (nlkup--)
630 nfsm_v4dissect_lookup(&cp);
631 nfsm_v4dissect_getfh(&cp, &gfh);
632 nfsm_v4dissect_getattr(&cp, &ga);
633
634 nfs4_vfsop_fsinfo(&ga.fa, nmp);
635 nmp->nm_state |= NFSSTA_GOTFSINFO;
636
637 /* Copy root fh into nfsmount. */
638 nmp->nm_fhsize = gfh.fh_len;
639 bcopy(&gfh.fh_val, nmp->nm_fh, nmp->nm_fhsize);
640 nmp->nm_last_renewal = time_second;
641
642 if ((error = nfs4_do_setclientid(nmp, cred)) != 0)
643 goto nfsmout;
644
645 /* Start renewd if it isn't already running */
646 if (nfs4_daemonproc == NULL)
647 kthread_create(nfs4_daemon, crdup(cred), &nfs4_daemonproc,
648 (RFPROC|RFMEM), 0, "nfs4rd");
649
650 return (0);
651 nfsmout:
652 error = nfs_v4postop(&cp, error);
653
654 /* XXX */
655 if (mrep != NULL)
656 m_freem(mrep);
657 bad:
658 mtx_destroy(&nmp->nm_mtx);
659 nfs4_disconnect(nmp);
660 uma_zfree(nfsmount_zone, nmp);
661 FREE(nam, M_SONAME);
662
663 return (error);
664 }
665
666 /*
667 * unmount system call
668 */
669 static int
670 nfs4_unmount(struct mount *mp, int mntflags, struct thread *td)
671 {
672 struct nfsmount *nmp;
673 int error, flags = 0;
674
675 if (mntflags & MNT_FORCE)
676 flags |= FORCECLOSE;
677 nmp = VFSTONFS(mp);
678 /*
679 * Goes something like this..
680 * - Call vflush(, td) to clear out vnodes for this filesystem
681 * - Close the socket
682 * - Free up the data structures
683 */
684 /* In the forced case, cancel any outstanding requests. */
685 if (flags & FORCECLOSE) {
686 error = nfs_nmcancelreqs(nmp);
687 if (error)
688 return (error);
689 nfs4dev_purge();
690 }
691
692 error = vflush(mp, 0, flags, td);
693 if (error)
694 return (error);
695
696 /*
697 * We are now committed to the unmount.
698 */
699 nfs4_disconnect(nmp);
700 FREE(nmp->nm_nam, M_SONAME);
701
702 /* XXX there's a race condition here for SMP */
703 wakeup(&nfs4_daemonproc);
704
705 mtx_destroy(&nmp->nm_mtx);
706 uma_zfree(nfsmount_zone, nmp);
707 return (0);
708 }
709
710 /*
711 * Return root of a filesystem
712 */
713 static int
714 nfs4_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
715 {
716 struct vnode *vp;
717 struct nfsmount *nmp;
718 struct nfsnode *np;
719 int error;
720
721 nmp = VFSTONFS(mp);
722 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np,
723 LK_EXCLUSIVE);
724 if (error)
725 return (error);
726 vp = NFSTOV(np);
727 if (vp->v_type == VNON)
728 vp->v_type = VDIR;
729 vp->v_vflag |= VV_ROOT;
730 *vpp = vp;
731
732 return (0);
733 }
734
735 /*
736 * Flush out the buffer cache
737 */
738 static int
739 nfs4_sync(struct mount *mp, int waitfor, struct thread *td)
740 {
741 struct vnode *vp, *mvp;
742 int error, allerror = 0;
743
744 /*
745 * Force stale buffer cache information to be flushed.
746 */
747 MNT_ILOCK(mp);
748 loop:
749 MNT_VNODE_FOREACH(vp, mp, mvp) {
750 VI_LOCK(vp);
751 MNT_IUNLOCK(mp);
752 if (VOP_ISLOCKED(vp, NULL) ||
753 vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
754 waitfor == MNT_LAZY) {
755 VI_UNLOCK(vp);
756 MNT_ILOCK(mp);
757 continue;
758 }
759 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
760 MNT_ILOCK(mp);
761 MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
762 goto loop;
763 }
764 error = VOP_FSYNC(vp, waitfor, td);
765 if (error)
766 allerror = error;
767 VOP_UNLOCK(vp, 0, td);
768 vrele(vp);
769
770 MNT_ILOCK(mp);
771 }
772 MNT_IUNLOCK(mp);
773 return (allerror);
774 }
775
776 static int
777 nfs4_do_setclientid(struct nfsmount *nmp, struct ucred *cred)
778 {
779 struct nfs4_oparg_setclientid scid;
780 struct nfs4_compound cp;
781 struct mbuf *mreq, *mrep = NULL, *md, *mb;
782 caddr_t bpos, dpos;
783 struct route ro;
784 char *ipsrc = NULL, uaddr[24], name[24];
785 int try = 0;
786 static unsigned long seq;
787 int error;
788
789 #ifndef NFS4_USE_RPCCLNT
790 return (0);
791 #endif
792 if (nmp->nm_clientid) {
793 printf("nfs4_do_setclientid: already have clientid!\n");
794 error = 0;
795 goto nfsmout;
796 }
797
798 /* Try not to re-use clientids */
799 if (seq == 0)
800 seq = time_second;
801
802 #ifdef NFS4_USE_RPCCLNT
803 scid.cb_netid = (nmp->nm_rpcclnt.rc_sotype == SOCK_STREAM) ? "tcp" : "udp";
804 #endif
805 scid.cb_netid = "tcp";
806 scid.cb_netidlen = 3;
807 scid.cb_prog = 0x1234; /* XXX */
808
809 /* Do a route lookup to find our source address for talking to this server */
810 bzero(&ro, sizeof ro);
811
812 #ifdef NFS4_USE_RPCCLNT
813 ro.ro_dst = *nmp->nm_rpcclnt.rc_name;
814 #endif
815 rtalloc(&ro);
816 if (ro.ro_rt == NULL) {
817 error = EHOSTUNREACH;
818 goto nfsmout;
819 }
820 ipsrc = inet_ntoa(IA_SIN(ifatoia(ro.ro_rt->rt_ifa))->sin_addr);
821 sprintf(uaddr, "%s.12.48", ipsrc);
822 scid.cb_univaddr = uaddr;
823 scid.cb_univaddrlen = strlen(uaddr);
824 RTFREE(ro.ro_rt);
825
826 try_again:
827 sprintf(name, "%s-%d", ipsrc, (int) ((seq + try) % 1000000L));
828 scid.namelen = strlen(name);
829 scid.name = name;
830 nfs_v4initcompound(&cp);
831
832 mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
833 mb = mreq;
834 bpos = mtod(mb, caddr_t);
835
836 nfsm_v4build_compound(&cp, "nfs4_do_setclientid()");
837 nfsm_v4build_setclientid(&cp, &scid);
838 nfsm_v4build_finalize(&cp);
839
840 nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
841 if (error != 0)
842 goto nfsmout;
843
844 nfsm_v4dissect_compound(&cp);
845 nfsm_v4dissect_setclientid(&cp, &scid);
846 nmp->nm_clientid = scid.clientid;
847
848 error = nfs_v4postop(&cp, error);
849
850 /* Confirm */
851 m_freem(mrep);
852 mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
853 mb = mreq;
854 bpos = mtod(mb, caddr_t);
855
856 nfs_v4initcompound(&cp);
857
858 nfsm_v4build_compound(&cp, "nfs4_do_setclientid() (confirm)");
859 nfsm_v4build_setclientid_confirm(&cp, &scid);
860 nfsm_v4build_finalize(&cp);
861
862 nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
863 if (error != 0)
864 goto nfsmout;
865
866 nfsm_v4dissect_compound(&cp);
867 nfsm_v4dissect_setclientid_confirm(&cp);
868
869 nfsmout:
870 error = nfs_v4postop(&cp, error);
871
872 if (mrep)
873 m_freem(mrep);
874 if (error == NFSERR_CLID_INUSE && (++try < NFS4_SETCLIENTID_MAXTRIES))
875 goto try_again;
876
877 return (error);
878 }
Cache object: cb7523b43e878e8db3e32e3b64eb35a4
|