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