]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfs4client/nfs4_vfsops.c
This commit was generated by cvs2svn to compensate for changes in r160814,
[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         /*
250          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
251          * no sense in that context.  Also, set appropriate retransmit
252          * and soft timeout behavior.
253          */
254         if (argp->sotype == SOCK_STREAM) {
255                 nmp->nm_flag &= ~NFSMNT_NOCONN;
256                 nmp->nm_flag |= NFSMNT_DUMBTIMR;
257                 nmp->nm_timeo = NFS_MAXTIMEO;
258                 nmp->nm_retry = NFS_RETRANS_TCP;
259         }
260
261         nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
262
263         /* Re-bind if rsrvd port requested and wasn't on one */
264         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
265                   && (argp->flags & NFSMNT_RESVPORT);
266         /* Also re-bind if we're switching to/from a connected UDP socket */
267         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
268                     (argp->flags & NFSMNT_NOCONN));
269
270         /* Update flags atomically.  Don't change the lock bits. */
271         nmp->nm_flag = argp->flags | nmp->nm_flag;
272         splx(s);
273
274         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
275                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
276                 if (nmp->nm_timeo < NFS_MINTIMEO)
277                         nmp->nm_timeo = NFS_MINTIMEO;
278                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
279                         nmp->nm_timeo = NFS_MAXTIMEO;
280         }
281
282         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
283                 nmp->nm_retry = argp->retrans;
284                 if (nmp->nm_retry > NFS_MAXREXMIT)
285                         nmp->nm_retry = NFS_MAXREXMIT;
286         }
287
288         if (argp->flags & NFSMNT_NFSV3) {
289                 if (argp->sotype == SOCK_DGRAM)
290                         maxio = NFS_MAXDGRAMDATA;
291                 else
292                         maxio = NFS_MAXDATA;
293         } else
294                 maxio = NFS_V2MAXDATA;
295
296         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
297                 nmp->nm_wsize = argp->wsize;
298                 /* Round down to multiple of blocksize */
299                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
300                 if (nmp->nm_wsize <= 0)
301                         nmp->nm_wsize = NFS_FABLKSIZE;
302         }
303         if (nmp->nm_wsize > maxio)
304                 nmp->nm_wsize = maxio;
305         if (nmp->nm_wsize > MAXBSIZE)
306                 nmp->nm_wsize = MAXBSIZE;
307
308         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
309                 nmp->nm_rsize = argp->rsize;
310                 /* Round down to multiple of blocksize */
311                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
312                 if (nmp->nm_rsize <= 0)
313                         nmp->nm_rsize = NFS_FABLKSIZE;
314         }
315         if (nmp->nm_rsize > maxio)
316                 nmp->nm_rsize = maxio;
317         if (nmp->nm_rsize > MAXBSIZE)
318                 nmp->nm_rsize = MAXBSIZE;
319
320         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
321                 nmp->nm_readdirsize = argp->readdirsize;
322         }
323         if (nmp->nm_readdirsize > maxio)
324                 nmp->nm_readdirsize = maxio;
325         if (nmp->nm_readdirsize > nmp->nm_rsize)
326                 nmp->nm_readdirsize = nmp->nm_rsize;
327
328         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
329                 nmp->nm_acregmin = argp->acregmin;
330         else
331                 nmp->nm_acregmin = NFS_MINATTRTIMO;
332         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
333                 nmp->nm_acregmax = argp->acregmax;
334         else
335                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
336         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
337                 nmp->nm_acdirmin = argp->acdirmin;
338         else
339                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
340         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
341                 nmp->nm_acdirmax = argp->acdirmax;
342         else
343                 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
344         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
345                 nmp->nm_acdirmin = nmp->nm_acdirmax;
346         if (nmp->nm_acregmin > nmp->nm_acregmax)
347                 nmp->nm_acregmin = nmp->nm_acregmax;
348
349         if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) {
350                 if (argp->maxgrouplist <= NFS_MAXGRPS)
351                         nmp->nm_numgrps = argp->maxgrouplist;
352                 else
353                         nmp->nm_numgrps = NFS_MAXGRPS;
354         }
355         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
356                 if (argp->readahead <= NFS_MAXRAHEAD)
357                         nmp->nm_readahead = argp->readahead;
358                 else
359                         nmp->nm_readahead = NFS_MAXRAHEAD;
360         }
361         if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 0) {
362                 if (argp->deadthresh <= NFS_MAXDEADTHRESH)
363                         nmp->nm_deadthresh = argp->deadthresh;
364                 else
365                         nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
366         }
367
368         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
369                     (nmp->nm_soproto != argp->proto));
370         nmp->nm_sotype = argp->sotype;
371         nmp->nm_soproto = argp->proto;
372
373         if (nmp->nm_rpcclnt.rc_so && adjsock) {
374                 nfs_safedisconnect(nmp);
375                 if (nmp->nm_sotype == SOCK_DGRAM) {
376                         while (nfs4_connect(nmp)) {
377                                 printf("nfs_args: retrying connect\n");
378                                 (void) tsleep((caddr_t)&lbolt,
379                                               PSOCK, "nfscon", 0);
380                         }
381                 }
382         }
383 }
384
385 /*
386  * VFS Operations.
387  *
388  * mount system call
389  * It seems a bit dumb to copyinstr() the host and path here and then
390  * bcopy() them in mountnfs(), but I wanted to detect errors before
391  * doing the sockargs() call because sockargs() allocates an mbuf and
392  * an error after that means that I have to release the mbuf.
393  */
394 /* ARGSUSED */
395 static int
396 nfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
397 {
398         struct nfs_args args;
399         int error;
400
401         error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
402         if (error)
403                 return (error);
404
405         ma = mount_arg(ma, "nfs_args", &args, sizeof args);
406
407         error = kernel_mount(ma, flags);
408
409          return (error);
410 }
411
412 static int
413 nfs_mount(struct mount *mp, struct thread *td)
414 {
415         int error;
416         struct nfs_args args;
417         struct sockaddr *nam;
418         struct vnode *vp;
419         char hst[MNAMELEN];
420         size_t len;
421
422         if (mp->mnt_flag & MNT_ROOTFS) {
423                 printf("NFSv4: nfs_mountroot not supported\n");
424                 return EINVAL;
425         }
426         error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, sizeof args);
427         if (error)
428                 return (error);
429
430         if (args.version != NFS_ARGSVERSION)
431                 return (EPROGMISMATCH);
432         if (mp->mnt_flag & MNT_UPDATE) {
433                 struct nfsmount *nmp = VFSTONFS(mp);
434
435                 if (nmp == NULL)
436                         return (EIO);
437                 /*
438                  * When doing an update, we can't change from or to
439                  * v3, switch lockd strategies or change cookie translation
440                  */
441                 args.flags = (args.flags &
442                     ~(NFSMNT_NFSV3 | NFSMNT_NFSV4 | NFSMNT_NOLOCKD)) |
443                     (nmp->nm_flag &
444                         (NFSMNT_NFSV3 | NFSMNT_NFSV4 | NFSMNT_NOLOCKD));
445                 nfs_decode_args(nmp, &args);
446                 return (0);
447         }
448
449         error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
450         if (error)
451                 return (error);
452         bzero(&hst[len], MNAMELEN - len);
453         /* sockargs() call must be after above copyin() calls */
454         error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
455         if (error)
456                 return (error);
457         error = mountnfs(&args, mp, nam, hst, &vp, td->td_ucred);
458         return (error);
459 }
460
461 /*
462  * renew should be done async
463  * should re-scan mount queue each time
464  */
465 struct proc *nfs4_daemonproc;
466
467 static int
468 nfs4_do_renew(struct nfsmount *nmp, struct ucred *cred)
469 {
470         struct nfs4_compound cp;
471         struct mbuf *mreq, *mrep = NULL, *md, *mb;
472         caddr_t bpos, dpos;     
473         int error;
474
475         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, sizeof(uint64_t));
476         mb = mreq;
477         bpos = mtod(mb, caddr_t);
478
479         nfs_v4initcompound(&cp);
480
481         nfsm_v4build_compound(&cp, "nfs4_do_renew()");
482         nfsm_v4build_renew(&cp, nmp->nm_clientid);
483         nfsm_v4build_finalize(&cp);
484
485         nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
486         if (error != 0)
487                 goto nfsmout;
488
489         nfsm_v4dissect_compound(&cp);
490         nfsm_v4dissect_renew(&cp);
491         nmp->nm_last_renewal = time_second;
492         return (0);
493
494  nfsmout:
495         error = nfs_v4postop(&cp, error);
496
497         /* XXX */
498         if (mrep != NULL)
499                 m_freem(mrep);
500         return (error);
501 }
502
503 static void
504 nfs4_daemon(void *arg)
505 {
506         struct mount *mp;
507         struct nfsmount *nmp;
508         int nmounts;
509
510         while (1) {
511                 nmounts = 0;
512                 mtx_lock(&mountlist_mtx);
513                 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
514                         if (strcmp(mp->mnt_vfc->vfc_name, "nfs4") != 0)
515                                 continue;
516                         nmounts++;
517                         nmp = VFSTONFS(mp);
518                         if (time_second < nmp->nm_last_renewal + nmp->nm_lease_time - 4)
519                                 continue;
520                         mtx_unlock(&mountlist_mtx);
521                         mtx_lock(&Giant);
522                         nfs4_do_renew(nmp, (struct ucred *) arg);
523                         mtx_unlock(&Giant);
524                         mtx_lock(&mountlist_mtx);
525                 }
526                 mtx_unlock(&mountlist_mtx);
527
528                 /* Must kill the daemon here, or module unload will cause a panic */
529                 if (nmounts == 0) {
530                         mtx_lock(&Giant);
531                         nfs4_daemonproc = NULL;
532                         mtx_unlock(&Giant);
533                         /*printf("nfsv4 renewd exiting\n");*/
534                         kthread_exit(0);
535                 }
536                 tsleep(&nfs4_daemonproc, PVFS, "nfs4", 2 * hz);
537         }
538 }
539
540 /*
541  * Common code for mount and mountroot
542  */
543 static int
544 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
545     char *hst, struct vnode **vpp, struct ucred *cred)
546 {
547         struct nfsmount *nmp;
548         char *rpth, *cp1, *cp2;
549         int nlkup = 0, error;
550         struct nfs4_compound cp;
551         struct mbuf *mreq, *mrep = NULL, *md, *mb;
552         caddr_t bpos, dpos;     
553         struct nfs4_oparg_lookup lkup;
554         struct nfs4_oparg_getfh gfh;
555         struct nfs4_oparg_getattr ga;
556         struct thread *td = curthread; /* XXX */
557
558         if (mp->mnt_flag & MNT_UPDATE) {
559                 nmp = VFSTONFS(mp);
560                 /* update paths, file handles, etc, here        XXX */
561                 FREE(nam, M_SONAME);
562                 return (0);
563         } else {
564                 nmp = uma_zalloc(nfsmount_zone, M_WAITOK);
565                 bzero((caddr_t)nmp, sizeof (struct nfsmount));
566                 TAILQ_INIT(&nmp->nm_bufq);
567                 mp->mnt_data = (qaddr_t)nmp;
568         }
569
570         vfs_getnewfsid(mp);
571         nmp->nm_mountp = mp;
572         mtx_init(&nmp->nm_mtx, "NFS4mount lock", NULL, MTX_DEF);                        
573
574         nmp->nm_maxfilesize = 0xffffffffLL;
575         nmp->nm_timeo = NFS_TIMEO;
576         nmp->nm_retry = NFS_RETRANS;
577         nmp->nm_wsize = NFS_WSIZE;
578         nmp->nm_rsize = NFS_RSIZE;
579         nmp->nm_readdirsize = NFS_READDIRSIZE;
580         nmp->nm_numgrps = NFS_MAXGRPS;
581         nmp->nm_readahead = NFS_DEFRAHEAD;
582         nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
583         vfs_mountedfrom(mp, hst);
584         nmp->nm_nam = nam;
585         /* Set up the sockets and per-host congestion */
586         nmp->nm_sotype = argp->sotype;
587         nmp->nm_soproto = argp->proto;
588         nmp->nm_rpcops = &nfs4_rpcops;
589         /* XXX */
590         mp->mnt_stat.f_iosize = PAGE_SIZE;
591
592         argp->flags |= (NFSMNT_NFSV3 | NFSMNT_NFSV4);
593
594         nfs_decode_args(nmp, argp);
595
596         if ((error = nfs4_connect(nmp)))
597                 goto bad;
598
599         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
600         mb = mreq;
601         bpos = mtod(mb, caddr_t);
602
603         ga.bm = &nfsv4_fsinfobm;
604         nfs_v4initcompound(&cp);
605
606         /* Get remote path */
607         rpth = hst;
608         strsep(&rpth, ":");
609
610         nfsm_v4build_compound(&cp, "mountnfs()");
611         nfsm_v4build_putrootfh(&cp);
612         for (cp1 = rpth; cp1 && *cp1; cp1 = cp2)  {
613                 while (*cp1 == '/')
614                         cp1++;
615                 if (!*cp1)
616                         break;
617                 for (cp2 = cp1; *cp2 && *cp2 != '/'; cp2++)
618                         ;
619                 lkup.name = cp1;
620                 lkup.namelen = cp2 - cp1;
621                 nfsm_v4build_lookup(&cp, &lkup);
622                 nlkup++;
623         }
624         nfsm_v4build_getfh(&cp, &gfh);
625         nfsm_v4build_getattr(&cp, &ga);
626         nfsm_v4build_finalize(&cp);
627
628         nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, td, cred);
629         if (error != 0)
630                 goto nfsmout;
631
632         nfsm_v4dissect_compound(&cp);
633         nfsm_v4dissect_putrootfh(&cp);
634         while (nlkup--)
635                 nfsm_v4dissect_lookup(&cp);
636         nfsm_v4dissect_getfh(&cp, &gfh);
637         nfsm_v4dissect_getattr(&cp, &ga);
638
639         nfs4_vfsop_fsinfo(&ga.fa, nmp);
640         nmp->nm_state |= NFSSTA_GOTFSINFO;
641
642         /* Copy root fh into nfsmount. */
643         nmp->nm_fhsize = gfh.fh_len;
644         bcopy(&gfh.fh_val, nmp->nm_fh, nmp->nm_fhsize);
645         nmp->nm_last_renewal = time_second;
646
647         if ((error = nfs4_do_setclientid(nmp, cred)) != 0)
648                 goto nfsmout;
649
650         /* Start renewd if it isn't already running */
651         if (nfs4_daemonproc == NULL)
652                 kthread_create(nfs4_daemon, crdup(cred), &nfs4_daemonproc,
653                                (RFPROC|RFMEM), 0, "nfs4rd");
654
655         return (0);
656  nfsmout:
657         error = nfs_v4postop(&cp, error);
658
659         /* XXX */
660         if (mrep != NULL)
661                 m_freem(mrep);
662 bad:
663         mtx_destroy(&nmp->nm_mtx);
664         nfs4_disconnect(nmp);
665         uma_zfree(nfsmount_zone, nmp);
666         FREE(nam, M_SONAME);
667
668         return (error);
669 }
670
671 /*
672  * unmount system call
673  */
674 static int
675 nfs_unmount(struct mount *mp, int mntflags, struct thread *td)
676 {
677         struct nfsmount *nmp;
678         int error, flags = 0;
679
680         if (mntflags & MNT_FORCE)
681                 flags |= FORCECLOSE;
682         nmp = VFSTONFS(mp);
683         /*
684          * Goes something like this..
685          * - Call vflush(, td) to clear out vnodes for this filesystem
686          * - Close the socket
687          * - Free up the data structures
688          */
689         /* In the forced case, cancel any outstanding requests. */
690         if (flags & FORCECLOSE) {
691                 error = nfs_nmcancelreqs(nmp);
692                 if (error)
693                         return (error);
694                 nfs4dev_purge();
695         }
696
697         error = vflush(mp, 0, flags, td);
698         if (error)
699                 return (error);
700
701         /*
702          * We are now committed to the unmount.
703          */
704         nfs4_disconnect(nmp);
705         FREE(nmp->nm_nam, M_SONAME);
706
707         /* XXX there's a race condition here for SMP */
708         wakeup(&nfs4_daemonproc);
709
710         mtx_destroy(&nmp->nm_mtx);
711         uma_zfree(nfsmount_zone, nmp);
712         return (0);
713 }
714
715 /*
716  * Return root of a filesystem
717  */
718 static int
719 nfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
720 {
721         struct vnode *vp;
722         struct nfsmount *nmp;
723         struct nfsnode *np;
724         int error;
725
726         nmp = VFSTONFS(mp);
727         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
728         if (error)
729                 return (error);
730         vp = NFSTOV(np);
731         if (vp->v_type == VNON)
732             vp->v_type = VDIR;
733         vp->v_vflag |= VV_ROOT;
734         *vpp = vp;
735
736         return (0);
737 }
738
739 /*
740  * Flush out the buffer cache
741  */
742 /* ARGSUSED */
743 static int
744 nfs_sync(struct mount *mp, int waitfor, struct thread *td)
745 {
746         struct vnode *vp, *mvp;
747         int error, allerror = 0;
748
749         /*
750          * Force stale buffer cache information to be flushed.
751          */
752         MNT_ILOCK(mp);
753 loop:
754         MNT_VNODE_FOREACH(vp, mp, mvp) {
755                 VI_LOCK(vp);
756                 MNT_IUNLOCK(mp);
757                 if (VOP_ISLOCKED(vp, NULL) ||
758                     vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
759                     waitfor == MNT_LAZY) {
760                         VI_UNLOCK(vp);
761                         MNT_ILOCK(mp);
762                         continue;
763                 }
764                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
765                         MNT_ILOCK(mp);
766                         MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
767                         goto loop;
768                 }
769                 error = VOP_FSYNC(vp, waitfor, td);
770                 if (error)
771                         allerror = error;
772                 VOP_UNLOCK(vp, 0, td);
773                 vrele(vp);
774
775                 MNT_ILOCK(mp);
776         }
777         MNT_IUNLOCK(mp);
778         return (allerror);
779 }
780
781 static int
782 nfs4_do_setclientid(struct nfsmount *nmp, struct ucred *cred)
783 {
784         struct nfs4_oparg_setclientid scid;
785         struct nfs4_compound cp;
786         struct mbuf *mreq, *mrep = NULL, *md, *mb;
787         caddr_t bpos, dpos;     
788         struct route ro;
789         char *ipsrc = NULL, uaddr[24], name[24];
790         int try = 0;
791         static unsigned long seq;
792         int error;
793
794 #ifndef NFS4_USE_RPCCLNT
795         return (0);
796 #endif
797         if (nmp->nm_clientid) {
798                 printf("nfs4_do_setclientid: already have clientid!\n");
799                 error = 0;
800                 goto nfsmout;
801         }
802
803         /* Try not to re-use clientids */
804         if (seq == 0)
805                 seq = time_second;
806
807 #ifdef NFS4_USE_RPCCLNT
808         scid.cb_netid = (nmp->nm_rpcclnt.rc_sotype == SOCK_STREAM) ? "tcp" : "udp";
809 #endif
810         scid.cb_netid = "tcp";
811         scid.cb_netidlen = 3;
812         scid.cb_prog = 0x1234; /* XXX */
813
814         /* Do a route lookup to find our source address for talking to this server */
815         bzero(&ro, sizeof ro);
816
817 #ifdef NFS4_USE_RPCCLNT
818         ro.ro_dst = *nmp->nm_rpcclnt.rc_name;
819 #endif
820         rtalloc(&ro);
821         if (ro.ro_rt == NULL) {
822                 error = EHOSTUNREACH;
823                 goto nfsmout;
824         }
825         ipsrc = inet_ntoa(IA_SIN(ifatoia(ro.ro_rt->rt_ifa))->sin_addr);
826         sprintf(uaddr, "%s.12.48", ipsrc);
827         scid.cb_univaddr = uaddr;
828         scid.cb_univaddrlen = strlen(uaddr);
829         RTFREE(ro.ro_rt);
830
831  try_again:
832         sprintf(name, "%s-%d", ipsrc, (int) ((seq + try) % 1000000L));
833         scid.namelen = strlen(name);
834         scid.name = name;
835         nfs_v4initcompound(&cp);
836
837         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
838         mb = mreq;
839         bpos = mtod(mb, caddr_t);
840
841         nfsm_v4build_compound(&cp, "nfs4_do_setclientid()");
842         nfsm_v4build_setclientid(&cp, &scid);
843         nfsm_v4build_finalize(&cp);
844
845         nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
846         if (error != 0)
847                 goto nfsmout;
848
849         nfsm_v4dissect_compound(&cp);
850         nfsm_v4dissect_setclientid(&cp, &scid);
851         nmp->nm_clientid = scid.clientid;
852
853         error = nfs_v4postop(&cp, error);
854
855         /* Confirm */
856         m_freem(mrep);
857         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, NFSX_FH(1));
858         mb = mreq;
859         bpos = mtod(mb, caddr_t);
860
861         nfs_v4initcompound(&cp);
862
863         nfsm_v4build_compound(&cp, "nfs4_do_setclientid() (confirm)");
864         nfsm_v4build_setclientid_confirm(&cp, &scid);
865         nfsm_v4build_finalize(&cp);
866
867         nfsm_request_mnt(nmp, NFSV4PROC_COMPOUND, curthread, cred);
868         if (error != 0)
869                 goto nfsmout;
870
871         nfsm_v4dissect_compound(&cp);
872         nfsm_v4dissect_setclientid_confirm(&cp);
873
874  nfsmout:
875         error = nfs_v4postop(&cp, error);
876
877         if (mrep)
878                 m_freem(mrep);
879         if (error == NFSERR_CLID_INUSE && (++try < NFS4_SETCLIENTID_MAXTRIES))
880                 goto try_again;
881
882         return (error);
883 }