1 /* $NetBSD: nfs_vfsops.c,v 1.191 2008/01/03 01:26:30 pooka Exp $ */
4 * Copyright (c) 1989, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: nfs_vfsops.c,v 1.191 2008/01/03 01:26:30 pooka Exp $");
40 #if defined(_KERNEL_OPT)
41 #include "opt_compat_netbsd.h"
45 #include <sys/param.h>
46 #include <sys/ioctl.h>
47 #include <sys/signal.h>
49 #include <sys/namei.h>
50 #include <sys/device.h>
51 #include <sys/vnode.h>
52 #include <sys/kernel.h>
53 #include <sys/mount.h>
56 #include <sys/dirent.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/sysctl.h>
60 #include <sys/systm.h>
61 #include <sys/timetc.h>
62 #include <sys/kauth.h>
65 #include <net/route.h>
66 #include <netinet/in.h>
68 #include <nfs/rpcv2.h>
69 #include <nfs/nfsproto.h>
70 #include <nfs/nfsnode.h>
72 #include <nfs/nfsmount.h>
73 #include <nfs/xdr_subs.h>
74 #include <nfs/nfsm_subs.h>
75 #include <nfs/nfsdiskless.h>
76 #include <nfs/nfs_var.h>
78 extern struct nfsstats nfsstats
;
82 * keep a count of the nfs mounts to generate ficticious drive names
83 * for the per drive stats.
85 unsigned int nfs_mount_count
= 0;
91 extern const struct vnodeopv_desc nfsv2_vnodeop_opv_desc
;
92 extern const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc
;
93 extern const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc
;
95 const struct vnodeopv_desc
* const nfs_vnodeopv_descs
[] = {
96 &nfsv2_vnodeop_opv_desc
,
97 &spec_nfsv2nodeop_opv_desc
,
98 &fifo_nfsv2nodeop_opv_desc
,
102 struct vfsops nfs_vfsops
= {
104 sizeof (struct nfs_args
),
109 (void *)eopnotsupp
, /* vfs_quotactl */
119 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
121 (void *)eopnotsupp
, /* vfs_suspendctl */
126 VFS_ATTACH(nfs_vfsops
);
128 extern u_int32_t nfs_procids
[NFS_NPROCS
];
129 extern u_int32_t nfs_prog
, nfs_vers
;
131 static int nfs_mount_diskless
__P((struct nfs_dlmount
*, const char *,
132 struct mount
**, struct vnode
**, struct lwp
*));
142 struct lwp
*l
= curlwp
;
144 struct nfs_statfs
*sfp
;
148 char *bpos
, *dpos
, *cp2
;
149 struct nfsmount
*nmp
= VFSTONFS(mp
);
150 int error
= 0, retattr
;
154 int v3
= (nmp
->nm_flag
& NFSMNT_NFSV3
);
156 struct mbuf
*mreq
, *mrep
= NULL
, *md
, *mb
;
162 sfp
= (struct nfs_statfs
*)0;
166 cred
= kauth_cred_alloc();
168 if (v3
&& (nmp
->nm_iflag
& NFSMNT_GOTFSINFO
) == 0)
169 (void)nfs_fsinfo(nmp
, vp
, cred
, l
);
171 nfsstats
.rpccnt
[NFSPROC_FSSTAT
]++;
172 nfsm_reqhead(np
, NFSPROC_FSSTAT
, NFSX_FH(v3
));
174 nfsm_request(np
, NFSPROC_FSSTAT
, l
, cred
);
176 nfsm_postop_attr(vp
, retattr
, 0);
179 if (mrep
->m_next
!= NULL
)
180 printf("nfs_vfsops: nfs_statvfs would lose buffers\n");
185 nfsm_dissect(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
186 sbp
->f_flag
= nmp
->nm_flag
;
187 sbp
->f_iosize
= min(nmp
->nm_rsize
, nmp
->nm_wsize
);
189 sbp
->f_frsize
= sbp
->f_bsize
= NFS_FABLKSIZE
;
190 tquad
= fxdr_hyper(&sfp
->sf_tbytes
);
191 sbp
->f_blocks
= ((quad_t
)tquad
/ (quad_t
)NFS_FABLKSIZE
);
192 tquad
= fxdr_hyper(&sfp
->sf_fbytes
);
193 sbp
->f_bfree
= ((quad_t
)tquad
/ (quad_t
)NFS_FABLKSIZE
);
194 tquad
= fxdr_hyper(&sfp
->sf_abytes
);
195 tquad
= ((quad_t
)tquad
/ (quad_t
)NFS_FABLKSIZE
);
196 sbp
->f_bresvd
= sbp
->f_bfree
- tquad
;
197 sbp
->f_bavail
= tquad
;
199 /* Handle older NFS servers returning negative values */
200 if ((quad_t
)sbp
->f_bavail
< 0)
203 tquad
= fxdr_hyper(&sfp
->sf_tfiles
);
204 sbp
->f_files
= tquad
;
205 tquad
= fxdr_hyper(&sfp
->sf_ffiles
);
206 sbp
->f_ffree
= tquad
;
207 sbp
->f_favail
= tquad
;
209 sbp
->f_namemax
= MAXNAMLEN
;
211 sbp
->f_bsize
= NFS_FABLKSIZE
;
212 sbp
->f_frsize
= fxdr_unsigned(int32_t, sfp
->sf_bsize
);
213 sbp
->f_blocks
= fxdr_unsigned(int32_t, sfp
->sf_blocks
);
214 sbp
->f_bfree
= fxdr_unsigned(int32_t, sfp
->sf_bfree
);
215 sbp
->f_bavail
= fxdr_unsigned(int32_t, sfp
->sf_bavail
);
221 sbp
->f_namemax
= MAXNAMLEN
;
223 copy_statvfs_info(sbp
, mp
);
225 kauth_cred_free(cred
);
231 * nfs version 3 fsinfo rpc call
234 nfs_fsinfo(nmp
, vp
, cred
, l
)
235 struct nfsmount
*nmp
;
240 struct nfsv3_fsinfo
*fsp
;
243 u_int32_t
*tl
, pref
, xmax
;
244 char *bpos
, *dpos
, *cp2
;
245 int error
= 0, retattr
;
246 struct mbuf
*mreq
, *mrep
, *md
, *mb
;
248 struct nfsnode
*np
= VTONFS(vp
);
250 nfsstats
.rpccnt
[NFSPROC_FSINFO
]++;
251 nfsm_reqhead(np
, NFSPROC_FSINFO
, NFSX_FH(1));
253 nfsm_request(np
, NFSPROC_FSINFO
, l
, cred
);
254 nfsm_postop_attr(vp
, retattr
, 0);
256 nfsm_dissect(fsp
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
257 pref
= fxdr_unsigned(u_int32_t
, fsp
->fs_wtpref
);
258 if ((nmp
->nm_flag
& NFSMNT_WSIZE
) == 0 &&
259 pref
< nmp
->nm_wsize
&& pref
>= NFS_FABLKSIZE
)
260 nmp
->nm_wsize
= (pref
+ NFS_FABLKSIZE
- 1) &
261 ~(NFS_FABLKSIZE
- 1);
262 xmax
= fxdr_unsigned(u_int32_t
, fsp
->fs_wtmax
);
263 if (xmax
< nmp
->nm_wsize
&& xmax
> 0) {
264 nmp
->nm_wsize
= xmax
& ~(NFS_FABLKSIZE
- 1);
265 if (nmp
->nm_wsize
== 0)
266 nmp
->nm_wsize
= xmax
;
268 pref
= fxdr_unsigned(u_int32_t
, fsp
->fs_rtpref
);
269 if ((nmp
->nm_flag
& NFSMNT_RSIZE
) == 0 &&
270 pref
< nmp
->nm_rsize
&& pref
>= NFS_FABLKSIZE
)
271 nmp
->nm_rsize
= (pref
+ NFS_FABLKSIZE
- 1) &
272 ~(NFS_FABLKSIZE
- 1);
273 xmax
= fxdr_unsigned(u_int32_t
, fsp
->fs_rtmax
);
274 if (xmax
< nmp
->nm_rsize
&& xmax
> 0) {
275 nmp
->nm_rsize
= xmax
& ~(NFS_FABLKSIZE
- 1);
276 if (nmp
->nm_rsize
== 0)
277 nmp
->nm_rsize
= xmax
;
279 pref
= fxdr_unsigned(u_int32_t
, fsp
->fs_dtpref
);
280 if (pref
< nmp
->nm_readdirsize
&& pref
>= NFS_DIRFRAGSIZ
)
281 nmp
->nm_readdirsize
= (pref
+ NFS_DIRFRAGSIZ
- 1) &
282 ~(NFS_DIRFRAGSIZ
- 1);
283 if (xmax
< nmp
->nm_readdirsize
&& xmax
> 0) {
284 nmp
->nm_readdirsize
= xmax
& ~(NFS_DIRFRAGSIZ
- 1);
285 if (nmp
->nm_readdirsize
== 0)
286 nmp
->nm_readdirsize
= xmax
;
289 nmp
->nm_maxfilesize
= (u_int64_t
)0x80000000 * DEV_BSIZE
- 1;
290 maxfsize
= fxdr_hyper(&fsp
->fs_maxfilesize
);
291 if (maxfsize
> 0 && maxfsize
< nmp
->nm_maxfilesize
)
292 nmp
->nm_maxfilesize
= maxfsize
;
293 nmp
->nm_mountp
->mnt_fs_bshift
=
294 ffs(MIN(nmp
->nm_rsize
, nmp
->nm_wsize
)) - 1;
295 nmp
->nm_iflag
|= NFSMNT_GOTFSINFO
;
303 * Mount a remote root fs via. NFS. It goes like this:
304 * - Call nfs_boot_init() to fill in the nfs_diskless struct
305 * - build the rootfs mount point and call mountnfs() to do the rest.
311 struct nfs_diskless
*nd
;
319 l
= curlwp
; /* XXX */
321 if (device_class(root_device
) != DV_IFNET
)
325 * XXX time must be non-zero when we init the interface or else
326 * the arp code will wedge. [Fixed now in if_ether.c]
327 * However, the NFS attribute cache gives false "hits" when the
328 * current time < nfs_attrtimeo(nmp, np) so keep this in for now.
330 if (time_second
< NFS_MAXATTRTIMO
) {
331 ts
.tv_sec
= NFS_MAXATTRTIMO
;
337 * Call nfs_boot_init() to fill in the nfs_diskless struct.
338 * Side effect: Finds and configures a network interface.
340 nd
= kmem_alloc(sizeof(*nd
), KM_SLEEP
);
341 memset(nd
, 0, sizeof(*nd
));
342 error
= nfs_boot_init(nd
, l
);
344 kmem_free(nd
, sizeof(*nd
));
349 * Create the root mount point.
351 error
= nfs_mount_diskless(&nd
->nd_root
, "/", &mp
, &vp
, l
);
354 printf("root on %s\n", nd
->nd_root
.ndm_host
);
357 * Link it into the mount list.
359 mutex_enter(&mountlist_lock
);
360 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
361 mutex_exit(&mountlist_lock
);
363 mp
->mnt_vnodecovered
= NULLVP
;
366 /* Get root attributes (for the time). */
367 error
= VOP_GETATTR(vp
, &attr
, l
->l_cred
);
369 panic("nfs_mountroot: getattr for root");
370 n
= attr
.va_atime
.tv_sec
;
372 printf("root time: 0x%lx\n", n
);
378 nfs_boot_cleanup(nd
, l
);
379 kmem_free(nd
, sizeof(*nd
));
384 * Internal version of mount system call for diskless setup.
385 * Separate function because we used to call it twice.
386 * (once for root and once for swap)
389 nfs_mount_diskless(ndmntp
, mntname
, mpp
, vpp
, l
)
390 struct nfs_dlmount
*ndmntp
;
391 const char *mntname
; /* mount point name */
400 vfs_rootmountalloc(MOUNT_NFS
, mntname
, &mp
);
402 mp
->mnt_op
= &nfs_vfsops
;
405 * Historical practice expects NFS root file systems to
406 * be initially mounted r/w.
408 mp
->mnt_flag
&= ~MNT_RDONLY
;
410 /* Get mbuf for server sockaddr. */
411 m
= m_get(M_WAIT
, MT_SONAME
);
413 panic("nfs_mountroot: mget soname for %s", mntname
);
414 MCLAIM(m
, &nfs_mowner
);
415 memcpy(mtod(m
, void *), (void *)ndmntp
->ndm_args
.addr
,
416 (m
->m_len
= ndmntp
->ndm_args
.addr
->sa_len
));
418 error
= mountnfs(&ndmntp
->ndm_args
, mp
, m
, mntname
,
419 ndmntp
->ndm_args
.hostname
, vpp
, l
);
421 mp
->mnt_op
->vfs_refcount
--;
423 printf("nfs_mountroot: mount %s failed: %d\n",
433 nfs_decode_args(nmp
, argp
, l
)
434 struct nfsmount
*nmp
;
435 struct nfs_args
*argp
;
445 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
446 * no sense in that context.
448 if (argp
->sotype
== SOCK_STREAM
)
449 argp
->flags
&= ~NFSMNT_NOCONN
;
452 * Cookie translation is not needed for v2, silently ignore it.
454 if ((argp
->flags
& (NFSMNT_XLATECOOKIE
|NFSMNT_NFSV3
)) ==
456 argp
->flags
&= ~NFSMNT_XLATECOOKIE
;
458 /* Re-bind if rsrvd port requested and wasn't on one */
459 adjsock
= !(nmp
->nm_flag
& NFSMNT_RESVPORT
)
460 && (argp
->flags
& NFSMNT_RESVPORT
);
461 /* Also re-bind if we're switching to/from a connected UDP socket */
462 adjsock
|= ((nmp
->nm_flag
& NFSMNT_NOCONN
) !=
463 (argp
->flags
& NFSMNT_NOCONN
));
466 nmp
->nm_flag
= argp
->flags
;
469 if ((argp
->flags
& NFSMNT_TIMEO
) && argp
->timeo
> 0) {
470 nmp
->nm_timeo
= (argp
->timeo
* NFS_HZ
+ 5) / 10;
471 if (nmp
->nm_timeo
< NFS_MINTIMEO
)
472 nmp
->nm_timeo
= NFS_MINTIMEO
;
473 else if (nmp
->nm_timeo
> NFS_MAXTIMEO
)
474 nmp
->nm_timeo
= NFS_MAXTIMEO
;
477 if ((argp
->flags
& NFSMNT_RETRANS
) && argp
->retrans
> 1) {
478 nmp
->nm_retry
= argp
->retrans
;
479 if (nmp
->nm_retry
> NFS_MAXREXMIT
)
480 nmp
->nm_retry
= NFS_MAXREXMIT
;
484 if (argp
->flags
& NFSMNT_NFSV3
) {
485 if (argp
->sotype
== SOCK_DGRAM
)
486 maxio
= NFS_MAXDGRAMDATA
;
491 maxio
= NFS_V2MAXDATA
;
493 if ((argp
->flags
& NFSMNT_WSIZE
) && argp
->wsize
> 0) {
494 int osize
= nmp
->nm_wsize
;
495 nmp
->nm_wsize
= argp
->wsize
;
496 /* Round down to multiple of blocksize */
497 nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
498 if (nmp
->nm_wsize
<= 0)
499 nmp
->nm_wsize
= NFS_FABLKSIZE
;
500 adjsock
|= (nmp
->nm_wsize
!= osize
);
502 if (nmp
->nm_wsize
> maxio
)
503 nmp
->nm_wsize
= maxio
;
504 if (nmp
->nm_wsize
> MAXBSIZE
)
505 nmp
->nm_wsize
= MAXBSIZE
;
507 if ((argp
->flags
& NFSMNT_RSIZE
) && argp
->rsize
> 0) {
508 int osize
= nmp
->nm_rsize
;
509 nmp
->nm_rsize
= argp
->rsize
;
510 /* Round down to multiple of blocksize */
511 nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
512 if (nmp
->nm_rsize
<= 0)
513 nmp
->nm_rsize
= NFS_FABLKSIZE
;
514 adjsock
|= (nmp
->nm_rsize
!= osize
);
516 if (nmp
->nm_rsize
> maxio
)
517 nmp
->nm_rsize
= maxio
;
518 if (nmp
->nm_rsize
> MAXBSIZE
)
519 nmp
->nm_rsize
= MAXBSIZE
;
521 if ((argp
->flags
& NFSMNT_READDIRSIZE
) && argp
->readdirsize
> 0) {
522 nmp
->nm_readdirsize
= argp
->readdirsize
;
523 /* Round down to multiple of minimum blocksize */
524 nmp
->nm_readdirsize
&= ~(NFS_DIRFRAGSIZ
- 1);
525 if (nmp
->nm_readdirsize
< NFS_DIRFRAGSIZ
)
526 nmp
->nm_readdirsize
= NFS_DIRFRAGSIZ
;
527 /* Bigger than buffer size makes no sense */
528 if (nmp
->nm_readdirsize
> NFS_DIRBLKSIZ
)
529 nmp
->nm_readdirsize
= NFS_DIRBLKSIZ
;
530 } else if (argp
->flags
& NFSMNT_RSIZE
)
531 nmp
->nm_readdirsize
= nmp
->nm_rsize
;
533 if (nmp
->nm_readdirsize
> maxio
)
534 nmp
->nm_readdirsize
= maxio
;
536 if ((argp
->flags
& NFSMNT_MAXGRPS
) && argp
->maxgrouplist
>= 0 &&
537 argp
->maxgrouplist
<= NFS_MAXGRPS
)
538 nmp
->nm_numgrps
= argp
->maxgrouplist
;
539 if ((argp
->flags
& NFSMNT_READAHEAD
) && argp
->readahead
>= 0 &&
540 argp
->readahead
<= NFS_MAXRAHEAD
)
541 nmp
->nm_readahead
= argp
->readahead
;
542 if ((argp
->flags
& NFSMNT_DEADTHRESH
) && argp
->deadthresh
>= 1 &&
543 argp
->deadthresh
<= NFS_NEVERDEAD
)
544 nmp
->nm_deadthresh
= argp
->deadthresh
;
546 adjsock
|= ((nmp
->nm_sotype
!= argp
->sotype
) ||
547 (nmp
->nm_soproto
!= argp
->proto
));
548 nmp
->nm_sotype
= argp
->sotype
;
549 nmp
->nm_soproto
= argp
->proto
;
551 if (nmp
->nm_so
&& adjsock
) {
552 nfs_safedisconnect(nmp
);
553 if (nmp
->nm_sotype
== SOCK_DGRAM
)
554 while (nfs_connect(nmp
, (struct nfsreq
*)0, l
)) {
555 printf("nfs_args: retrying connect\n");
556 kpause("nfscn3", false, hz
, NULL
);
565 * It seems a bit dumb to copyinstr() the host and path here and then
566 * memcpy() them in mountnfs(), but I wanted to detect errors before
567 * doing the sockargs() call because sockargs() allocates an mbuf and
568 * an error after that means that I have to release the mbuf.
572 nfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
574 struct lwp
*l
= curlwp
;
576 struct nfs_args
*args
= data
;
578 struct nfsmount
*nmp
= VFSTONFS(mp
);
586 if (*data_len
< sizeof *args
)
590 if (mp
->mnt_flag
& MNT_GETARGS
) {
594 if (args
->addr
!= NULL
) {
595 sa
= mtod(nmp
->nm_nam
, struct sockaddr
*);
596 error
= copyout(sa
, args
->addr
, sa
->sa_len
);
599 args
->addrlen
= sa
->sa_len
;
603 args
->version
= NFS_ARGSVERSION
;
604 args
->sotype
= nmp
->nm_sotype
;
605 args
->proto
= nmp
->nm_soproto
;
608 args
->flags
= nmp
->nm_flag
;
609 args
->wsize
= nmp
->nm_wsize
;
610 args
->rsize
= nmp
->nm_rsize
;
611 args
->readdirsize
= nmp
->nm_readdirsize
;
612 args
->timeo
= nmp
->nm_timeo
;
613 args
->retrans
= nmp
->nm_retry
;
614 args
->maxgrouplist
= nmp
->nm_numgrps
;
615 args
->readahead
= nmp
->nm_readahead
;
616 args
->leaseterm
= 0; /* dummy */
617 args
->deadthresh
= nmp
->nm_deadthresh
;
618 args
->hostname
= NULL
;
619 *data_len
= sizeof *args
;
623 if (args
->version
!= NFS_ARGSVERSION
)
624 return (EPROGMISMATCH
);
625 if (args
->flags
& (NFSMNT_NQNFS
|NFSMNT_KERB
))
626 return (EPROGUNAVAIL
);
628 if (args
->flags
& NFSMNT_NFSV3
)
629 return (EPROGMISMATCH
);
631 if (mp
->mnt_flag
& MNT_UPDATE
) {
635 * When doing an update, we can't change from or to
636 * v3, or change cookie translation
638 args
->flags
= (args
->flags
& ~(NFSMNT_NFSV3
|NFSMNT_XLATECOOKIE
)) |
639 (nmp
->nm_flag
& (NFSMNT_NFSV3
|NFSMNT_XLATECOOKIE
));
640 nfs_decode_args(nmp
, args
, l
);
643 if (args
->fhsize
< 0 || args
->fhsize
> NFSX_V3FHMAX
)
645 MALLOC(nfh
, u_char
*, NFSX_V3FHMAX
, M_TEMP
, M_WAITOK
);
646 error
= copyin(args
->fh
, nfh
, args
->fhsize
);
649 MALLOC(pth
, char *, MNAMELEN
, M_TEMP
, M_WAITOK
);
650 error
= copyinstr(path
, pth
, MNAMELEN
- 1, &len
);
653 memset(&pth
[len
], 0, MNAMELEN
- len
);
654 MALLOC(hst
, char *, MNAMELEN
, M_TEMP
, M_WAITOK
);
655 error
= copyinstr(args
->hostname
, hst
, MNAMELEN
- 1, &len
);
658 memset(&hst
[len
], 0, MNAMELEN
- len
);
659 /* sockargs() call must be after above copyin() calls */
660 error
= sockargs(&nam
, args
->addr
, args
->addrlen
, MT_SONAME
);
663 MCLAIM(nam
, &nfs_mowner
);
665 error
= mountnfs(args
, mp
, nam
, pth
, hst
, &vp
, l
);
678 * Common code for mount and mountroot
681 mountnfs(argp
, mp
, nam
, pth
, hst
, vpp
, l
)
682 struct nfs_args
*argp
;
685 const char *pth
, *hst
;
689 struct nfsmount
*nmp
;
694 char iosname
[IOSTATNAMELEN
];
697 * If the number of nfs iothreads to use has never
698 * been set, create a reasonable number of them.
701 if (nfs_niothreads
< 0) {
702 nfs_set_niothreads(NFS_DEFAULT_NIOTHREADS
);
705 if (mp
->mnt_flag
& MNT_UPDATE
) {
707 /* update paths, file handles, etc, here XXX */
711 nmp
= kmem_zalloc(sizeof(*nmp
), KM_SLEEP
);
713 TAILQ_INIT(&nmp
->nm_uidlruhead
);
714 TAILQ_INIT(&nmp
->nm_bufq
);
715 rw_init(&nmp
->nm_writeverflock
);
716 mutex_init(&nmp
->nm_lock
, MUTEX_DEFAULT
, IPL_NONE
);
717 cv_init(&nmp
->nm_rcvcv
, "nfsrcv");
718 cv_init(&nmp
->nm_sndcv
, "nfssnd");
719 cv_init(&nmp
->nm_aiocv
, "nfsaio");
720 cv_init(&nmp
->nm_disconcv
, "nfsdis");
726 if ((argp
->flags
& NFSMNT_NFSV3
) == 0)
730 * V2 can only handle 32 bit filesizes. For v3, nfs_fsinfo
733 nmp
->nm_maxfilesize
= 0xffffffffLL
;
734 if (argp
->fhsize
!= NFSX_V2FH
) {
739 nmp
->nm_timeo
= NFS_TIMEO
;
740 nmp
->nm_retry
= NFS_RETRANS
;
741 nmp
->nm_wsize
= NFS_WSIZE
;
742 nmp
->nm_rsize
= NFS_RSIZE
;
743 nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
744 nmp
->nm_numgrps
= NFS_MAXGRPS
;
745 nmp
->nm_readahead
= NFS_DEFRAHEAD
;
746 nmp
->nm_deadthresh
= NFS_DEFDEADTHRESH
;
747 error
= set_statvfs_info(pth
, UIO_SYSSPACE
, hst
, UIO_SYSSPACE
,
748 mp
->mnt_op
->vfs_name
, mp
, l
);
753 /* Set up the sockets and per-host congestion */
754 nmp
->nm_sotype
= argp
->sotype
;
755 nmp
->nm_soproto
= argp
->proto
;
757 nfs_decode_args(nmp
, argp
, l
);
759 mp
->mnt_fs_bshift
= ffs(MIN(nmp
->nm_rsize
, nmp
->nm_wsize
)) - 1;
760 mp
->mnt_dev_bshift
= DEV_BSHIFT
;
763 * For Connection based sockets (TCP,...) defer the connect until
764 * the first request, in case the server is not responding.
766 if (nmp
->nm_sotype
== SOCK_DGRAM
&&
767 (error
= nfs_connect(nmp
, (struct nfsreq
*)0, l
)))
771 * This is silly, but it has to be set so that vinifod() works.
772 * We do not want to do an nfs_statvfs() here since we can get
773 * stuck on a dead server and we are holding a lock on the mount
776 mp
->mnt_stat
.f_iosize
= NFS_MAXDGRAMDATA
;
777 error
= nfs_nget(mp
, (nfsfh_t
*)argp
->fh
, argp
->fhsize
, &np
);
781 MALLOC(attrs
, struct vattr
*, sizeof(struct vattr
), M_TEMP
, M_WAITOK
);
782 VOP_GETATTR(*vpp
, attrs
, l
->l_cred
);
783 if ((nmp
->nm_flag
& NFSMNT_NFSV3
) && ((*vpp
)->v_type
== VDIR
)) {
784 cr
= kauth_cred_alloc();
785 kauth_cred_setuid(cr
, attrs
->va_uid
);
786 kauth_cred_seteuid(cr
, attrs
->va_uid
);
787 kauth_cred_setsvuid(cr
, attrs
->va_uid
);
788 kauth_cred_setgid(cr
, attrs
->va_gid
);
789 kauth_cred_setegid(cr
, attrs
->va_gid
);
790 kauth_cred_setsvgid(cr
, attrs
->va_gid
);
791 nfs_cookieheuristic(*vpp
, &nmp
->nm_iflag
, l
, cr
);
797 * A reference count is needed on the nfsnode representing the
798 * remote root. If this object is not persistent, then backward
799 * traversals of the mount point (i.e. "..") will not work if
800 * the nfsnode gets flushed out of the cache. Ufs does not have
801 * this problem, because one can identify root inodes by their
802 * number == ROOTINO (2). So, just unlock, but no rele.
805 nmp
->nm_vnode
= *vpp
;
808 snprintf(iosname
, sizeof(iosname
), "nfs%u", nfs_mount_count
++);
809 nmp
->nm_stats
= iostat_alloc(IOSTAT_NFS
, nmp
, iosname
);
814 rw_destroy(&nmp
->nm_writeverflock
);
815 mutex_destroy(&nmp
->nm_lock
);
816 cv_destroy(&nmp
->nm_rcvcv
);
817 cv_destroy(&nmp
->nm_sndcv
);
818 cv_destroy(&nmp
->nm_aiocv
);
819 cv_destroy(&nmp
->nm_disconcv
);
820 kmem_free(nmp
, sizeof(*nmp
));
826 * unmount system call
829 nfs_unmount(struct mount
*mp
, int mntflags
)
831 struct nfsmount
*nmp
;
833 int error
, flags
= 0;
835 if (mntflags
& MNT_FORCE
)
839 * Goes something like this..
840 * - Check for activity on the root vnode (other than ourselves).
841 * - Call vflush() to clear out vnodes for this file system,
842 * except for the root vnode.
843 * - Decrement reference on the vnode representing remote root.
845 * - Free up the data structures
848 * We need to decrement the ref. count on the nfsnode representing
849 * the remote root. See comment in mountnfs(). The VFS unmount()
850 * has done vput on this vnode, otherwise we would get deadlock!
853 error
= vget(vp
, LK_EXCLUSIVE
| LK_RETRY
);
857 if ((mntflags
& MNT_FORCE
) == 0 && vp
->v_usecount
> 2) {
862 error
= vflush(mp
, vp
, flags
);
869 * We are now committed to the unmount; mark the mount structure
870 * as doomed so that any sleepers kicked awake by nfs_disconnect
871 * will go away cleanly.
873 nmp
->nm_iflag
|= NFSMNT_DISMNT
;
876 * Clean up the stats... note that we carefully avoid decrementing
877 * nfs_mount_count here for good reason - we may not be unmounting
878 * the last thing mounted.
880 iostat_free(nmp
->nm_stats
);
883 * There are two reference counts to get rid of here
884 * (see comment in mountnfs()).
889 m_freem(nmp
->nm_nam
);
891 rw_destroy(&nmp
->nm_writeverflock
);
892 mutex_destroy(&nmp
->nm_lock
);
893 cv_destroy(&nmp
->nm_rcvcv
);
894 cv_destroy(&nmp
->nm_sndcv
);
895 cv_destroy(&nmp
->nm_aiocv
);
896 cv_destroy(&nmp
->nm_disconcv
);
897 kmem_free(nmp
, sizeof(*nmp
));
902 * Return root of a filesystem
910 struct nfsmount
*nmp
;
915 error
= vget(vp
, LK_EXCLUSIVE
| LK_RETRY
);
918 if (vp
->v_type
== VNON
)
920 vp
->v_vflag
= VV_ROOT
;
928 * Flush out the buffer cache
932 nfs_sync(mp
, waitfor
, cred
)
937 struct vnode
*vp
, *mvp
;
938 int error
, allerror
= 0;
941 * Force stale buffer cache information to be flushed.
943 if ((mvp
= vnalloc(mp
)) == NULL
)
947 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
948 * and vclean() can be called indirectly
950 mutex_enter(&mntvnode_lock
);
951 for (vp
= TAILQ_FIRST(&mp
->mnt_vnodelist
); vp
; vp
= vunmark(mvp
)) {
953 if (vp
->v_mount
!= mp
|| vismarker(vp
))
955 mutex_enter(&vp
->v_interlock
);
956 /* XXX MNT_LAZY cannot be right? */
957 if (waitfor
== MNT_LAZY
|| VOP_ISLOCKED(vp
) ||
958 (LIST_EMPTY(&vp
->v_dirtyblkhd
) &&
959 UVM_OBJ_IS_CLEAN(&vp
->v_uobj
))) {
960 mutex_exit(&vp
->v_interlock
);
963 mutex_exit(&mntvnode_lock
);
964 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
)) {
968 error
= VOP_FSYNC(vp
, cred
,
969 waitfor
== MNT_WAIT
? FSYNC_WAIT
: 0, 0, 0);
973 mutex_enter(&mntvnode_lock
);
975 mutex_exit(&mntvnode_lock
);
981 * NFS flat namespace lookup.
982 * Currently unsupported.
986 nfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
993 * Do that sysctl thang...
996 sysctl_vfs_nfs_iothreads(SYSCTLFN_ARGS
)
998 struct sysctlnode node
;
1002 val
= nfs_niothreads
;
1004 node
.sysctl_data
= &val
;
1005 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1006 if (error
|| newp
== NULL
)
1009 return nfs_set_niothreads(val
);
1012 SYSCTL_SETUP(sysctl_vfs_nfs_setup
, "sysctl vfs.nfs subtree setup")
1015 sysctl_createv(clog
, 0, NULL
, NULL
,
1017 CTLTYPE_NODE
, "vfs", NULL
,
1020 sysctl_createv(clog
, 0, NULL
, NULL
,
1022 CTLTYPE_NODE
, "nfs",
1023 SYSCTL_DESCR("NFS vfs options"),
1025 CTL_VFS
, 2, CTL_EOL
);
1027 * XXX the "2" above could be dynamic, thereby eliminating one
1028 * more instance of the "number to vfs" mapping problem, but
1029 * "2" is the order as taken from sys/mount.h
1032 sysctl_createv(clog
, 0, NULL
, NULL
,
1033 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
1034 CTLTYPE_STRUCT
, "nfsstats",
1035 SYSCTL_DESCR("NFS operation statistics"),
1036 NULL
, 0, &nfsstats
, sizeof(nfsstats
),
1037 CTL_VFS
, 2, NFS_NFSSTATS
, CTL_EOL
);
1038 sysctl_createv(clog
, 0, NULL
, NULL
,
1039 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
1040 CTLTYPE_INT
, "iothreads",
1041 SYSCTL_DESCR("Number of NFS client processes desired"),
1042 sysctl_vfs_nfs_iothreads
, 0, NULL
, 0,
1043 CTL_VFS
, 2, NFS_IOTHREADS
, CTL_EOL
);
1048 nfs_fhtovp(struct mount
*mp
, struct fid
*fid
, struct vnode
**vpp
)
1056 fidsize
= fid
->fid_len
;
1057 if (fidsize
< sizeof(*fid
)) {
1060 fhsize
= fidsize
- sizeof(*fid
);
1061 if ((fhsize
% NFSX_UNSIGNED
) != 0) {
1064 if ((VFSTONFS(mp
)->nm_flag
& NFSMNT_NFSV3
) != 0) {
1065 if (fhsize
> NFSX_V3FHMAX
|| fhsize
== 0) {
1069 if (fhsize
!= NFSX_V2FH
) {
1073 error
= nfs_nget(mp
, (void *)fid
->fid_data
, fhsize
, &np
);
1078 error
= VOP_GETATTR(*vpp
, &va
, kauth_cred_get());
1087 nfs_vptofh(struct vnode
*vp
, struct fid
*buf
, size_t *bufsize
)
1095 fidsize
= sizeof(*fid
) + np
->n_fhsize
;
1096 if (*bufsize
< fidsize
) {
1101 struct fid fid_store
;
1104 memset(fid
, 0, sizeof(*fid
));
1105 fid
->fid_len
= fidsize
;
1106 memcpy(buf
, fid
, sizeof(*fid
));
1107 memcpy(buf
->fid_data
, np
->n_fhp
, np
->n_fhsize
);
1113 * Vfs start routine, a no-op.
1117 nfs_start(struct mount
*mp
, int flags
)