Line data Source code
1 : /* $OpenBSD: nfs_vfsops.c,v 1.122 2018/07/02 20:56:22 bluhm Exp $ */
2 : /* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1989, 1993, 1995
6 : * The Regents of the University of California. All rights reserved.
7 : *
8 : * This code is derived from software contributed to Berkeley by
9 : * Rick Macklem at The University of Guelph.
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : * 1. Redistributions of source code must retain the above copyright
15 : * notice, this list of conditions and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : * 3. Neither the name of the University nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : *
35 : * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
36 : */
37 :
38 : #include <sys/param.h>
39 : #include <sys/conf.h>
40 : #include <sys/ioctl.h>
41 : #include <sys/signal.h>
42 : #include <sys/proc.h>
43 : #include <sys/namei.h>
44 : #include <sys/vnode.h>
45 : #include <sys/lock.h>
46 : #include <sys/kernel.h>
47 : #include <sys/mount.h>
48 : #include <sys/swap.h>
49 : #include <sys/buf.h>
50 : #include <sys/mbuf.h>
51 : #include <sys/dirent.h>
52 : #include <sys/socket.h>
53 : #include <sys/socketvar.h>
54 : #include <sys/systm.h>
55 : #include <sys/sysctl.h>
56 : #include <sys/queue.h>
57 :
58 : #include <netinet/in.h>
59 :
60 : #include <nfs/rpcv2.h>
61 : #include <nfs/nfsproto.h>
62 : #include <nfs/nfsnode.h>
63 : #include <nfs/nfs.h>
64 : #include <nfs/nfsmount.h>
65 : #include <nfs/xdr_subs.h>
66 : #include <nfs/nfsm_subs.h>
67 : #include <nfs/nfsdiskless.h>
68 : #include <nfs/nfs_var.h>
69 :
70 : extern struct nfsstats nfsstats;
71 : extern int nfs_ticks;
72 : extern u_int32_t nfs_procids[NFS_NPROCS];
73 :
74 : int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
75 : struct proc *);
76 : int nfs_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
77 : struct mount *nfs_mount_diskless(struct nfs_dlmount *, char *, int,
78 : struct vnode **, struct proc *p);
79 : int mountnfs(struct nfs_args *, struct mount *, struct mbuf *,
80 : const char *, char *, struct vnode **, struct proc *p);
81 : int nfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
82 : int nfs_root(struct mount *, struct vnode **);
83 : int nfs_start(struct mount *, int, struct proc *);
84 : int nfs_statfs(struct mount *, struct statfs *, struct proc *);
85 : int nfs_sync(struct mount *, int, int, struct ucred *, struct proc *);
86 : int nfs_unmount(struct mount *, int, struct proc *);
87 : void nfs_reaper(void *);
88 : int nfs_vget(struct mount *, ino_t, struct vnode **);
89 : int nfs_vptofh(struct vnode *, struct fid *);
90 : int nfs_mountroot(void);
91 : void nfs_decode_args(struct nfsmount *, struct nfs_args *,
92 : struct nfs_args *);
93 : int nfs_fhtovp(struct mount *, struct fid *, struct vnode **);
94 :
95 : /*
96 : * nfs vfs operations.
97 : */
98 : const struct vfsops nfs_vfsops = {
99 : nfs_mount,
100 : nfs_start,
101 : nfs_unmount,
102 : nfs_root,
103 : nfs_quotactl,
104 : nfs_statfs,
105 : nfs_sync,
106 : nfs_vget,
107 : nfs_fhtovp,
108 : nfs_vptofh,
109 : nfs_vfs_init,
110 : nfs_sysctl,
111 : nfs_checkexp
112 : };
113 :
114 : /*
115 : * nfs statfs call
116 : */
117 : int
118 0 : nfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
119 : {
120 0 : struct vnode *vp;
121 : struct nfs_statfs *sfp = NULL;
122 0 : struct nfsm_info info;
123 : u_int32_t *tl;
124 : int32_t t1;
125 0 : caddr_t cp2;
126 0 : struct nfsmount *nmp = VFSTONFS(mp);
127 : int error = 0, retattr;
128 : struct ucred *cred;
129 : u_quad_t tquad;
130 :
131 0 : info.nmi_v3 = (nmp->nm_flag & NFSMNT_NFSV3);
132 :
133 0 : error = nfs_root(mp, &vp);
134 0 : if (error)
135 0 : return (error);
136 0 : cred = crget();
137 0 : cred->cr_ngroups = 0;
138 0 : if (info.nmi_v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
139 0 : (void)nfs_fsinfo(nmp, vp, cred, p);
140 0 : nfsstats.rpccnt[NFSPROC_FSSTAT]++;
141 0 : info.nmi_mb = info.nmi_mreq = nfsm_reqhead(NFSX_FH(info.nmi_v3));
142 0 : nfsm_fhtom(&info, vp, info.nmi_v3);
143 :
144 0 : info.nmi_procp = p;
145 0 : info.nmi_cred = cred;
146 0 : error = nfs_request(vp, NFSPROC_FSSTAT, &info);
147 0 : if (info.nmi_v3)
148 0 : nfsm_postop_attr(vp, retattr);
149 0 : if (error) {
150 0 : m_freem(info.nmi_mrep);
151 0 : goto nfsmout;
152 : }
153 :
154 0 : nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(info.nmi_v3));
155 0 : sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
156 0 : if (info.nmi_v3) {
157 0 : sbp->f_bsize = NFS_FABLKSIZE;
158 0 : tquad = fxdr_hyper(&sfp->sf_tbytes);
159 0 : sbp->f_blocks = tquad / (u_quad_t)NFS_FABLKSIZE;
160 0 : tquad = fxdr_hyper(&sfp->sf_fbytes);
161 0 : sbp->f_bfree = tquad / (u_quad_t)NFS_FABLKSIZE;
162 0 : tquad = fxdr_hyper(&sfp->sf_abytes);
163 0 : sbp->f_bavail = (quad_t)tquad / (quad_t)NFS_FABLKSIZE;
164 :
165 0 : tquad = fxdr_hyper(&sfp->sf_tfiles);
166 0 : sbp->f_files = tquad;
167 0 : tquad = fxdr_hyper(&sfp->sf_ffiles);
168 0 : sbp->f_ffree = tquad;
169 0 : sbp->f_favail = tquad;
170 0 : } else {
171 0 : sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
172 0 : sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
173 0 : sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
174 0 : sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
175 0 : sbp->f_files = 0;
176 0 : sbp->f_ffree = 0;
177 0 : sbp->f_favail = 0;
178 : }
179 0 : copy_statfs_info(sbp, mp);
180 0 : m_freem(info.nmi_mrep);
181 : nfsmout:
182 0 : vput(vp);
183 0 : crfree(cred);
184 0 : return (error);
185 0 : }
186 :
187 : /*
188 : * nfs version 3 fsinfo rpc call
189 : */
190 : int
191 0 : nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
192 : struct proc *p)
193 : {
194 : struct nfsv3_fsinfo *fsp;
195 0 : struct nfsm_info info;
196 : int32_t t1;
197 : u_int32_t *tl, pref, max;
198 0 : caddr_t cp2;
199 : int error = 0, retattr;
200 :
201 0 : nfsstats.rpccnt[NFSPROC_FSINFO]++;
202 0 : info.nmi_mb = info.nmi_mreq = nfsm_reqhead(NFSX_FH(1));
203 0 : nfsm_fhtom(&info, vp, 1);
204 :
205 0 : info.nmi_procp = p;
206 0 : info.nmi_cred = cred;
207 0 : error = nfs_request(vp, NFSPROC_FSINFO, &info);
208 :
209 0 : nfsm_postop_attr(vp, retattr);
210 0 : if (error) {
211 0 : m_freem(info.nmi_mrep);
212 0 : goto nfsmout;
213 : }
214 :
215 0 : nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
216 0 : pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
217 0 : if (pref < nmp->nm_wsize)
218 0 : nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
219 : ~(NFS_FABLKSIZE - 1);
220 0 : max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
221 0 : if (max < nmp->nm_wsize) {
222 0 : nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
223 0 : if (nmp->nm_wsize == 0)
224 0 : nmp->nm_wsize = max;
225 : }
226 0 : pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
227 0 : if (pref < nmp->nm_rsize)
228 0 : nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
229 : ~(NFS_FABLKSIZE - 1);
230 0 : max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
231 0 : if (max < nmp->nm_rsize) {
232 0 : nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
233 0 : if (nmp->nm_rsize == 0)
234 0 : nmp->nm_rsize = max;
235 : }
236 0 : pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
237 0 : if (pref < nmp->nm_readdirsize)
238 0 : nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
239 : ~(NFS_DIRBLKSIZ - 1);
240 0 : if (max < nmp->nm_readdirsize) {
241 0 : nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
242 0 : if (nmp->nm_readdirsize == 0)
243 0 : nmp->nm_readdirsize = max;
244 : }
245 0 : nmp->nm_flag |= NFSMNT_GOTFSINFO;
246 :
247 0 : m_freem(info.nmi_mrep);
248 : nfsmout:
249 0 : return (error);
250 0 : }
251 :
252 : struct nfs_diskless nfs_diskless;
253 :
254 : /*
255 : * Mount a remote root fs via. NFS. It goes like this:
256 : * - Call nfs_boot_init() to fill in the nfs_diskless struct
257 : * (using RARP, bootparam RPC, mountd RPC)
258 : * - hand craft the swap nfs vnode hanging off a fake mount point
259 : * if swdevt[0].sw_dev == NODEV
260 : * - build the rootfs mount point and call mountnfs() to do the rest.
261 : */
262 : int
263 0 : nfs_mountroot(void)
264 : {
265 0 : struct vattr attr;
266 : struct mount *mp;
267 0 : struct vnode *vp;
268 : struct proc *procp;
269 : long n;
270 : int error;
271 :
272 0 : procp = curproc; /* XXX */
273 :
274 : /*
275 : * Call nfs_boot_init() to fill in the nfs_diskless struct.
276 : * Side effect: Finds and configures a network interface.
277 : */
278 0 : nfs_boot_init(&nfs_diskless, procp);
279 :
280 : /*
281 : * Create the root mount point.
282 : */
283 0 : if (nfs_boot_getfh(&nfs_diskless.nd_boot, "root", &nfs_diskless.nd_root, -1))
284 0 : panic("nfs_mountroot: root");
285 0 : mp = nfs_mount_diskless(&nfs_diskless.nd_root, "/", 0, &vp, procp);
286 0 : printf("root on %s\n", nfs_diskless.nd_root.ndm_host);
287 :
288 : /*
289 : * Link it into the mount list.
290 : */
291 0 : TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
292 0 : rootvp = vp;
293 0 : vfs_unbusy(mp);
294 :
295 : /* Get root attributes (for the time). */
296 0 : error = VOP_GETATTR(rootvp, &attr, procp->p_ucred, procp);
297 0 : if (error) panic("nfs_mountroot: getattr for root");
298 0 : n = attr.va_atime.tv_sec;
299 : #ifdef DEBUG
300 : printf("root time: 0x%lx\n", n);
301 : #endif
302 0 : inittodr(n);
303 :
304 : #ifdef notyet
305 : /* Set up swap credentials. */
306 : proc0.p_ucred->cr_uid = ntohl(nfs_diskless.swap_ucred.cr_uid);
307 : proc0.p_ucred->cr_gid = ntohl(nfs_diskless.swap_ucred.cr_gid);
308 : if ((proc0.p_ucred->cr_ngroups = ntohs(nfs_diskless.swap_ucred.cr_ngroups)) >
309 : NGROUPS_MAX)
310 : proc0.p_ucred->cr_ngroups = NGROUPS_MAX;
311 : for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
312 : proc0.p_ucred->cr_groups[i] = ntohl(nfs_diskless.swap_ucred.cr_groups[i]);
313 : #endif
314 :
315 : /*
316 : * "Mount" the swap device.
317 : *
318 : * On a "dataless" configuration (swap on disk) we will have:
319 : * (swdevt[0].sw_dev != NODEV) identifying the swap device.
320 : */
321 0 : if (swdevt[0].sw_dev != NODEV) {
322 0 : if (bdevvp(swapdev, &swapdev_vp))
323 0 : panic("nfs_mountroot: can't setup swap vp");
324 0 : printf("swap on device 0x%x\n", swdevt[0].sw_dev);
325 0 : return (0);
326 : }
327 :
328 : /*
329 : * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV)
330 : * Create a fake mount point just for the swap vnode so that the
331 : * swap file can be on a different server from the rootfs.
332 : *
333 : * Wait 5 retries, finally no swap is cool. -mickey
334 : */
335 0 : error = nfs_boot_getfh(&nfs_diskless.nd_boot, "swap", &nfs_diskless.nd_swap, 5);
336 0 : if (!error) {
337 0 : mp = nfs_mount_diskless(&nfs_diskless.nd_swap, "/swap", 0, &vp,
338 : procp);
339 0 : vfs_unbusy(mp);
340 :
341 : /*
342 : * Since the swap file is not the root dir of a file system,
343 : * hack it to a regular file.
344 : */
345 0 : vp->v_type = VREG;
346 0 : vp->v_flag = 0;
347 :
348 : /*
349 : * Next line is a hack to make swapmount() work on NFS
350 : * swap files.
351 : */
352 0 : swdevt[0].sw_dev = NETDEV;
353 : /* end hack */
354 0 : nfs_diskless.sw_vp = vp;
355 :
356 : /*
357 : * Find out how large the swap file is.
358 : */
359 0 : error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
360 0 : if (error)
361 0 : printf("nfs_mountroot: getattr for swap\n");
362 0 : n = (long) (attr.va_size >> DEV_BSHIFT);
363 :
364 0 : printf("swap on %s\n", nfs_diskless.nd_swap.ndm_host);
365 : #ifdef DEBUG
366 : printf("swap size: 0x%lx (blocks)\n", n);
367 : #endif
368 0 : return (0);
369 : }
370 :
371 0 : printf("WARNING: no swap\n");
372 0 : swdevt[0].sw_dev = NODEV;
373 0 : return (0);
374 0 : }
375 :
376 : /*
377 : * Internal version of mount system call for diskless setup.
378 : */
379 : struct mount *
380 0 : nfs_mount_diskless(struct nfs_dlmount *ndmntp, char *mntname, int mntflag,
381 : struct vnode **vpp, struct proc *p)
382 : {
383 0 : struct mount *mp;
384 : struct mbuf *m;
385 : int error;
386 :
387 0 : if (vfs_rootmountalloc("nfs", mntname, &mp))
388 0 : panic("nfs_mount_diskless: vfs_rootmountalloc failed");
389 0 : mp->mnt_flag |= mntflag;
390 :
391 : /* Get mbuf for server sockaddr. */
392 0 : m = m_get(M_WAIT, MT_SONAME);
393 0 : bcopy(ndmntp->ndm_args.addr, mtod(m, caddr_t),
394 0 : (m->m_len = ndmntp->ndm_args.addr->sa_len));
395 :
396 0 : error = mountnfs(&ndmntp->ndm_args, mp, m, mntname,
397 0 : ndmntp->ndm_args.hostname, vpp, p);
398 0 : if (error)
399 0 : panic("nfs_mountroot: mount %s failed: %d", mntname, error);
400 :
401 0 : return (mp);
402 0 : }
403 :
404 : void
405 0 : nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp,
406 : struct nfs_args *nargp)
407 : {
408 : int adjsock = 0;
409 : int maxio;
410 :
411 : #if 0
412 : /* Re-bind if rsrvd port requested and wasn't on one */
413 : adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
414 : && (argp->flags & NFSMNT_RESVPORT);
415 : #endif
416 : /* Also re-bind if we're switching to/from a connected UDP socket */
417 0 : adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
418 0 : (argp->flags & NFSMNT_NOCONN));
419 :
420 0 : nmp->nm_flag =
421 0 : (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL);
422 :
423 0 : if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
424 0 : nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
425 0 : if (nmp->nm_timeo < NFS_MINTIMEO)
426 0 : nmp->nm_timeo = NFS_MINTIMEO;
427 0 : else if (nmp->nm_timeo > NFS_MAXTIMEO)
428 0 : nmp->nm_timeo = NFS_MAXTIMEO;
429 : }
430 :
431 0 : if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1)
432 0 : nmp->nm_retry = MIN(argp->retrans, NFS_MAXREXMIT);
433 0 : if (!(nmp->nm_flag & NFSMNT_SOFT))
434 0 : nmp->nm_retry = NFS_MAXREXMIT + 1; /* past clip limit */
435 :
436 0 : if (argp->flags & NFSMNT_NFSV3) {
437 0 : if (argp->sotype == SOCK_DGRAM)
438 0 : maxio = NFS_MAXDGRAMDATA;
439 : else
440 : maxio = NFS_MAXDATA;
441 : } else
442 : maxio = NFS_V2MAXDATA;
443 :
444 0 : if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
445 0 : int osize = nmp->nm_wsize;
446 : nmp->nm_wsize = argp->wsize;
447 : /* Round down to multiple of blocksize */
448 0 : nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
449 0 : if (nmp->nm_wsize <= 0)
450 0 : nmp->nm_wsize = NFS_FABLKSIZE;
451 0 : adjsock |= (nmp->nm_wsize != osize);
452 0 : }
453 0 : if (nmp->nm_wsize > maxio)
454 0 : nmp->nm_wsize = maxio;
455 0 : if (nmp->nm_wsize > MAXBSIZE)
456 0 : nmp->nm_wsize = MAXBSIZE;
457 :
458 0 : if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
459 0 : int osize = nmp->nm_rsize;
460 : nmp->nm_rsize = argp->rsize;
461 : /* Round down to multiple of blocksize */
462 0 : nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
463 0 : if (nmp->nm_rsize <= 0)
464 0 : nmp->nm_rsize = NFS_FABLKSIZE;
465 0 : adjsock |= (nmp->nm_rsize != osize);
466 0 : }
467 0 : if (nmp->nm_rsize > maxio)
468 0 : nmp->nm_rsize = maxio;
469 0 : if (nmp->nm_rsize > MAXBSIZE)
470 0 : nmp->nm_rsize = MAXBSIZE;
471 :
472 0 : if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
473 0 : nmp->nm_readdirsize = argp->readdirsize;
474 : /* Round down to multiple of blocksize */
475 0 : nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
476 0 : if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
477 0 : nmp->nm_readdirsize = NFS_DIRBLKSIZ;
478 0 : } else if (argp->flags & NFSMNT_RSIZE)
479 0 : nmp->nm_readdirsize = nmp->nm_rsize;
480 :
481 0 : if (nmp->nm_readdirsize > maxio)
482 0 : nmp->nm_readdirsize = maxio;
483 :
484 0 : if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
485 0 : argp->maxgrouplist <= NFS_MAXGRPS)
486 0 : nmp->nm_numgrps = argp->maxgrouplist;
487 0 : if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
488 0 : argp->readahead <= NFS_MAXRAHEAD)
489 0 : nmp->nm_readahead = argp->readahead;
490 0 : if (argp->flags & NFSMNT_ACREGMIN && argp->acregmin >= 0) {
491 0 : if (argp->acregmin > 0xffff)
492 0 : nmp->nm_acregmin = 0xffff;
493 : else
494 0 : nmp->nm_acregmin = argp->acregmin;
495 : }
496 0 : if (argp->flags & NFSMNT_ACREGMAX && argp->acregmax >= 0) {
497 0 : if (argp->acregmax > 0xffff)
498 0 : nmp->nm_acregmax = 0xffff;
499 : else
500 0 : nmp->nm_acregmax = argp->acregmax;
501 : }
502 0 : if (nmp->nm_acregmin > nmp->nm_acregmax)
503 0 : nmp->nm_acregmin = nmp->nm_acregmax;
504 :
505 0 : if (argp->flags & NFSMNT_ACDIRMIN && argp->acdirmin >= 0) {
506 0 : if (argp->acdirmin > 0xffff)
507 0 : nmp->nm_acdirmin = 0xffff;
508 : else
509 0 : nmp->nm_acdirmin = argp->acdirmin;
510 : }
511 0 : if (argp->flags & NFSMNT_ACDIRMAX && argp->acdirmax >= 0) {
512 0 : if (argp->acdirmax > 0xffff)
513 0 : nmp->nm_acdirmax = 0xffff;
514 : else
515 0 : nmp->nm_acdirmax = argp->acdirmax;
516 : }
517 0 : if (nmp->nm_acdirmin > nmp->nm_acdirmax)
518 0 : nmp->nm_acdirmin = nmp->nm_acdirmax;
519 :
520 0 : if (nmp->nm_so && adjsock) {
521 0 : nfs_disconnect(nmp);
522 0 : if (nmp->nm_sotype == SOCK_DGRAM)
523 0 : while (nfs_connect(nmp, NULL)) {
524 0 : printf("nfs_args: retrying connect\n");
525 0 : (void) tsleep(&lbolt,
526 : PSOCK, "nfscon", 0);
527 : }
528 : }
529 :
530 : /* Update nargp based on nmp */
531 0 : nargp->wsize = nmp->nm_wsize;
532 0 : nargp->rsize = nmp->nm_rsize;
533 0 : nargp->readdirsize = nmp->nm_readdirsize;
534 0 : nargp->timeo = nmp->nm_timeo;
535 0 : nargp->retrans = nmp->nm_retry;
536 0 : nargp->maxgrouplist = nmp->nm_numgrps;
537 0 : nargp->readahead = nmp->nm_readahead;
538 0 : nargp->acregmin = nmp->nm_acregmin;
539 0 : nargp->acregmax = nmp->nm_acregmax;
540 0 : nargp->acdirmin = nmp->nm_acdirmin;
541 0 : nargp->acdirmax = nmp->nm_acdirmax;
542 0 : }
543 :
544 : /*
545 : * VFS Operations.
546 : *
547 : * mount system call
548 : * It seems a bit dumb to copyinstr() the host here and then
549 : * bcopy() it in mountnfs(), but I wanted to detect errors before
550 : * doing the sockargs() call because sockargs() allocates an mbuf and
551 : * an error after that means that I have to release the mbuf.
552 : */
553 : /* ARGSUSED */
554 : int
555 0 : nfs_mount(struct mount *mp, const char *path, void *data,
556 : struct nameidata *ndp, struct proc *p)
557 : {
558 : int error;
559 0 : struct nfs_args *args = data;
560 0 : struct mbuf *nam;
561 0 : struct vnode *vp;
562 0 : char hst[MNAMELEN];
563 0 : size_t len;
564 0 : u_char nfh[NFSX_V3FHMAX];
565 :
566 0 : if (args &&
567 0 : (args->flags & (NFSMNT_NFSV3|NFSMNT_RDIRPLUS)) == NFSMNT_RDIRPLUS)
568 0 : return (EINVAL);
569 :
570 0 : if (nfs_niothreads < 0) {
571 0 : nfs_niothreads = 4;
572 0 : nfs_getset_niothreads(1);
573 0 : }
574 :
575 0 : if (mp->mnt_flag & MNT_UPDATE) {
576 0 : struct nfsmount *nmp = VFSTONFS(mp);
577 :
578 0 : if (nmp == NULL)
579 0 : return (EIO);
580 : /*
581 : * When doing an update, we can't change from or to
582 : * v3.
583 : */
584 0 : if (args) {
585 0 : args->flags = (args->flags & ~(NFSMNT_NFSV3)) |
586 0 : (nmp->nm_flag & (NFSMNT_NFSV3));
587 0 : nfs_decode_args(nmp, args, &mp->mnt_stat.mount_info.nfs_args);
588 0 : }
589 0 : return (0);
590 : }
591 0 : if (args->fhsize < 0 || args->fhsize > NFSX_V3FHMAX)
592 0 : return (EINVAL);
593 0 : error = copyin(args->fh, nfh, args->fhsize);
594 0 : if (error)
595 0 : return (error);
596 0 : error = copyinstr(args->hostname, hst, MNAMELEN-1, &len);
597 0 : if (error)
598 0 : return (error);
599 0 : memset(&hst[len], 0, MNAMELEN - len);
600 : /* sockargs() call must be after above copyin() calls */
601 0 : error = sockargs(&nam, args->addr, args->addrlen, MT_SONAME);
602 0 : if (error)
603 0 : return (error);
604 0 : args->fh = nfh;
605 0 : error = mountnfs(args, mp, nam, path, hst, &vp, p);
606 0 : return (error);
607 0 : }
608 :
609 : /*
610 : * Common code for mount and mountroot
611 : */
612 : int
613 0 : mountnfs(struct nfs_args *argp, struct mount *mp, struct mbuf *nam,
614 : const char *pth, char *hst, struct vnode **vpp, struct proc *p)
615 : {
616 : struct nfsmount *nmp;
617 0 : struct nfsnode *np;
618 : struct vnode *vp;
619 0 : struct vattr attr;
620 : int error;
621 :
622 0 : if (mp->mnt_flag & MNT_UPDATE) {
623 0 : nmp = VFSTONFS(mp);
624 : /* update paths, file handles, etc, here XXX */
625 0 : m_freem(nam);
626 0 : return (0);
627 : } else {
628 0 : nmp = malloc(sizeof(*nmp), M_NFSMNT,
629 : M_WAITOK|M_ZERO);
630 0 : mp->mnt_data = nmp;
631 : }
632 :
633 0 : vfs_getnewfsid(mp);
634 0 : nmp->nm_mountp = mp;
635 0 : nmp->nm_timeo = NFS_TIMEO;
636 0 : nmp->nm_retry = NFS_RETRANS;
637 0 : nmp->nm_wsize = NFS_WSIZE;
638 0 : nmp->nm_rsize = NFS_RSIZE;
639 0 : nmp->nm_readdirsize = NFS_READDIRSIZE;
640 0 : nmp->nm_numgrps = NFS_MAXGRPS;
641 0 : nmp->nm_readahead = NFS_DEFRAHEAD;
642 0 : nmp->nm_acregmin = NFS_MINATTRTIMO;
643 0 : nmp->nm_acregmax = NFS_MAXATTRTIMO;
644 0 : nmp->nm_acdirmin = NFS_MINATTRTIMO;
645 0 : nmp->nm_acdirmax = NFS_MAXATTRTIMO;
646 0 : mp->mnt_stat.f_namemax = MAXNAMLEN;
647 0 : memset(mp->mnt_stat.f_mntonname, 0, MNAMELEN);
648 0 : strlcpy(mp->mnt_stat.f_mntonname, pth, MNAMELEN);
649 0 : memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
650 0 : strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
651 0 : memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
652 0 : strlcpy(mp->mnt_stat.f_mntfromspec, hst, MNAMELEN);
653 0 : bcopy(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp));
654 0 : nmp->nm_nam = nam;
655 0 : nfs_decode_args(nmp, argp, &mp->mnt_stat.mount_info.nfs_args);
656 :
657 0 : nfs_ninit(nmp);
658 0 : TAILQ_INIT(&nmp->nm_reqsq);
659 0 : timeout_set_proc(&nmp->nm_rtimeout, nfs_timer, nmp);
660 :
661 : /* Set up the sockets and per-host congestion */
662 0 : nmp->nm_sotype = argp->sotype;
663 0 : nmp->nm_soproto = argp->proto;
664 :
665 : /*
666 : * For Connection based sockets (TCP,...) defer the connect until
667 : * the first request, in case the server is not responding.
668 : */
669 0 : if (nmp->nm_sotype == SOCK_DGRAM &&
670 0 : (error = nfs_connect(nmp, NULL)))
671 : goto bad;
672 :
673 : /*
674 : * This is silly, but it has to be set so that vinifod() works.
675 : * We do not want to do an nfs_statfs() here since we can get
676 : * stuck on a dead server and we are holding a lock on the mount
677 : * point.
678 : */
679 0 : mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
680 0 : error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np);
681 0 : if (error)
682 : goto bad;
683 0 : vp = NFSTOV(np);
684 0 : error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
685 0 : if (error) {
686 0 : vput(vp);
687 0 : goto bad;
688 : }
689 :
690 : /*
691 : * A reference count is needed on the nfsnode representing the
692 : * remote root. If this object is not persistent, then backward
693 : * traversals of the mount point (i.e. "..") will not work if
694 : * the nfsnode gets flushed out of the cache. Ufs does not have
695 : * this problem, because one can identify root inodes by their
696 : * number == ROOTINO (2). So, just unlock, but no rele.
697 : */
698 0 : nmp->nm_vnode = vp;
699 0 : if (vp->v_type == VNON)
700 0 : vp->v_type = VDIR;
701 0 : vp->v_flag = VROOT;
702 0 : VOP_UNLOCK(vp);
703 0 : *vpp = vp;
704 :
705 0 : return (0);
706 : bad:
707 0 : nfs_disconnect(nmp);
708 0 : free(nmp, M_NFSMNT, sizeof(*nmp));
709 0 : m_freem(nam);
710 0 : return (error);
711 0 : }
712 :
713 : /* unmount system call */
714 : int
715 0 : nfs_unmount(struct mount *mp, int mntflags, struct proc *p)
716 : {
717 : struct nfsmount *nmp;
718 0 : struct vnode *vp;
719 : int error, flags = 0;
720 :
721 0 : nmp = VFSTONFS(mp);
722 0 : error = nfs_root(mp, &vp);
723 0 : if (error)
724 0 : return (error);
725 :
726 0 : if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 2) {
727 0 : vput(vp);
728 0 : return (EBUSY);
729 : }
730 :
731 0 : if (mntflags & MNT_FORCE)
732 0 : flags |= FORCECLOSE;
733 :
734 0 : error = vflush(mp, vp, flags);
735 0 : if (error) {
736 0 : vput(vp);
737 0 : return (error);
738 : }
739 :
740 : /*
741 : * There are two references count to get rid of here: one
742 : * from mountnfs() and one from nfs_root() above.
743 : */
744 0 : vrele(vp);
745 0 : vput(vp);
746 0 : vgone(vp);
747 0 : nfs_disconnect(nmp);
748 0 : m_freem(nmp->nm_nam);
749 0 : timeout_del(&nmp->nm_rtimeout);
750 0 : timeout_set_proc(&nmp->nm_rtimeout, nfs_reaper, nmp);
751 0 : timeout_add(&nmp->nm_rtimeout, 0);
752 0 : mp->mnt_data = NULL;
753 0 : return (0);
754 0 : }
755 :
756 : /*
757 : * Delay nfs mount point free until pending or sleeping timeouts have finished.
758 : */
759 : void
760 0 : nfs_reaper(void *arg)
761 : {
762 0 : struct nfsmount *nmp = arg;
763 :
764 0 : free(nmp, M_NFSMNT, sizeof(*nmp));
765 0 : }
766 :
767 : /*
768 : * Return root of a filesystem
769 : */
770 : int
771 0 : nfs_root(struct mount *mp, struct vnode **vpp)
772 : {
773 : struct vnode *vp;
774 : struct nfsmount *nmp;
775 : int error;
776 :
777 0 : nmp = VFSTONFS(mp);
778 0 : vp = nmp->nm_vnode;
779 0 : vref(vp);
780 0 : error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
781 0 : if (error) {
782 0 : vrele(vp);
783 0 : return (error);
784 : }
785 0 : *vpp = vp;
786 0 : return (0);
787 0 : }
788 :
789 : /*
790 : * Flush out the buffer cache
791 : */
792 : int
793 0 : nfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
794 : {
795 : struct vnode *vp;
796 : int error, allerror = 0;
797 :
798 : /*
799 : * Don't traverse the vnode list if we want to skip all of them.
800 : */
801 0 : if (waitfor == MNT_LAZY)
802 0 : return (allerror);
803 :
804 : /*
805 : * Force stale buffer cache information to be flushed.
806 : */
807 : loop:
808 0 : LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
809 : /*
810 : * If the vnode that we are about to sync is no longer
811 : * associated with this mount point, start over.
812 : */
813 0 : if (vp->v_mount != mp)
814 0 : goto loop;
815 0 : if (VOP_ISLOCKED(vp) || LIST_EMPTY(&vp->v_dirtyblkhd))
816 : continue;
817 0 : if (vget(vp, LK_EXCLUSIVE))
818 0 : goto loop;
819 0 : error = VOP_FSYNC(vp, cred, waitfor, p);
820 0 : if (error)
821 0 : allerror = error;
822 0 : vput(vp);
823 0 : }
824 :
825 0 : return (allerror);
826 0 : }
827 :
828 : /*
829 : * NFS flat namespace lookup.
830 : * Currently unsupported.
831 : */
832 : /* ARGSUSED */
833 : int
834 0 : nfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
835 : {
836 :
837 0 : return (EOPNOTSUPP);
838 : }
839 :
840 : /*
841 : * Do that sysctl thang...
842 : */
843 : int
844 0 : nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
845 : size_t newlen, struct proc *p)
846 : {
847 : int rv;
848 :
849 : /*
850 : * All names at this level are terminal.
851 : */
852 0 : if(namelen > 1)
853 0 : return ENOTDIR; /* overloaded */
854 :
855 0 : switch(name[0]) {
856 : case NFS_NFSSTATS:
857 0 : if(!oldp) {
858 0 : *oldlenp = sizeof nfsstats;
859 0 : return 0;
860 : }
861 :
862 0 : if(*oldlenp < sizeof nfsstats) {
863 0 : *oldlenp = sizeof nfsstats;
864 0 : return ENOMEM;
865 : }
866 :
867 0 : rv = copyout(&nfsstats, oldp, sizeof nfsstats);
868 0 : if(rv) return rv;
869 :
870 0 : if(newp && newlen != sizeof nfsstats)
871 0 : return EINVAL;
872 :
873 0 : if(newp) {
874 0 : return copyin(newp, &nfsstats, sizeof nfsstats);
875 : }
876 0 : return 0;
877 :
878 : case NFS_NIOTHREADS:
879 0 : nfs_getset_niothreads(0);
880 :
881 0 : rv = sysctl_int(oldp, oldlenp, newp, newlen, &nfs_niothreads);
882 0 : if (newp)
883 0 : nfs_getset_niothreads(1);
884 :
885 0 : return rv;
886 :
887 : default:
888 0 : return EOPNOTSUPP;
889 : }
890 0 : }
891 :
892 :
893 : /*
894 : * At this point, this should never happen
895 : */
896 : /* ARGSUSED */
897 : int
898 0 : nfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
899 : {
900 0 : return (EINVAL);
901 : }
902 :
903 : /*
904 : * Vnode pointer to File handle, should never happen either
905 : */
906 : /* ARGSUSED */
907 : int
908 0 : nfs_vptofh(struct vnode *vp, struct fid *fhp)
909 : {
910 0 : return (EINVAL);
911 : }
912 :
913 : /*
914 : * Vfs start routine, a no-op.
915 : */
916 : /* ARGSUSED */
917 : int
918 0 : nfs_start(struct mount *mp, int flags, struct proc *p)
919 : {
920 0 : return (0);
921 : }
922 :
923 : /*
924 : * Do operations associated with quotas, not supported
925 : */
926 : /* ARGSUSED */
927 : int
928 0 : nfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg, struct proc *p)
929 : {
930 0 : return (EOPNOTSUPP);
931 : }
932 :
933 : /*
934 : * check export permission, not supported
935 : */
936 : /* ARGUSED */
937 : int
938 0 : nfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
939 : struct ucred **credanonp)
940 : {
941 0 : return (EOPNOTSUPP);
942 : }
943 :
|