Commit | Line | Data |
---|---|---|
05df3b37 WJ |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Rick Macklem at The University of Guelph. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * @(#)nfs_vfsops.c 7.31 (Berkeley) 5/6/91 | |
37 | */ | |
38 | ||
39 | #include "param.h" | |
40 | #include "conf.h" | |
41 | #include "ioctl.h" | |
42 | #include "signal.h" | |
43 | #include "proc.h" | |
44 | #include "namei.h" | |
45 | #include "vnode.h" | |
46 | #include "mount.h" | |
47 | #include "buf.h" | |
48 | #include "mbuf.h" | |
49 | #include "socket.h" | |
50 | #include "systm.h" | |
51 | ||
52 | #include "../net/if.h" | |
53 | #include "../net/route.h" | |
54 | #include "../netinet/in.h" | |
55 | ||
56 | #include "nfsv2.h" | |
57 | #include "nfsnode.h" | |
58 | #include "nfsmount.h" | |
59 | #include "nfs.h" | |
60 | #include "xdr_subs.h" | |
61 | #include "nfsm_subs.h" | |
62 | #include "nfsdiskless.h" | |
63 | ||
64 | /* | |
65 | * nfs vfs operations. | |
66 | */ | |
67 | struct vfsops nfs_vfsops = { | |
68 | nfs_mount, | |
69 | nfs_start, | |
70 | nfs_unmount, | |
71 | nfs_root, | |
72 | nfs_quotactl, | |
73 | nfs_statfs, | |
74 | nfs_sync, | |
75 | nfs_fhtovp, | |
76 | nfs_vptofh, | |
77 | nfs_init, | |
78 | }; | |
79 | ||
80 | static u_char nfs_mntid; | |
81 | extern u_long nfs_procids[NFS_NPROCS]; | |
82 | extern u_long nfs_prog, nfs_vers; | |
83 | struct nfs_diskless nfs_diskless; | |
84 | void nfs_disconnect(); | |
85 | ||
86 | #define TRUE 1 | |
87 | #define FALSE 0 | |
88 | ||
89 | /* | |
90 | * nfs statfs call | |
91 | */ | |
92 | nfs_statfs(mp, sbp, p) | |
93 | struct mount *mp; | |
94 | register struct statfs *sbp; | |
95 | struct proc *p; | |
96 | { | |
97 | register struct vnode *vp; | |
98 | register struct nfsv2_statfs *sfp; | |
99 | register caddr_t cp; | |
100 | register long t1; | |
101 | caddr_t bpos, dpos, cp2; | |
102 | u_long xid; | |
103 | int error = 0; | |
104 | struct mbuf *mreq, *mrep, *md, *mb, *mb2; | |
105 | struct nfsmount *nmp; | |
106 | struct ucred *cred; | |
107 | struct nfsnode *np; | |
108 | ||
109 | nmp = VFSTONFS(mp); | |
110 | if (error = nfs_nget(mp, &nmp->nm_fh, &np)) | |
111 | return (error); | |
112 | vp = NFSTOV(np); | |
113 | nfsstats.rpccnt[NFSPROC_STATFS]++; | |
114 | cred = crget(); | |
115 | cred->cr_ngroups = 1; | |
116 | nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); | |
117 | nfsm_fhtom(vp); | |
118 | nfsm_request(vp, NFSPROC_STATFS, p, 0); | |
119 | nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); | |
120 | sbp->f_type = MOUNT_NFS; | |
121 | sbp->f_flags = nmp->nm_flag; | |
122 | sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); | |
123 | sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); | |
124 | sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); | |
125 | sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); | |
126 | sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); | |
127 | sbp->f_files = 0; | |
128 | sbp->f_ffree = 0; | |
129 | if (sbp != &mp->mnt_stat) { | |
130 | bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); | |
131 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); | |
132 | } | |
133 | nfsm_reqdone; | |
134 | nfs_nput(vp); | |
135 | crfree(cred); | |
136 | return (error); | |
137 | } | |
138 | ||
139 | /* | |
140 | * Mount a remote root fs via. nfs. This depends on the info in the | |
141 | * nfs_diskless structure that has been filled in properly by some primary | |
142 | * bootstrap. | |
143 | * It goes something like this: | |
144 | * - do enough of "ifconfig" by calling ifioctl() so that the system | |
145 | * can talk to the server | |
146 | * - If nfs_diskless.mygateway is filled in, use that address as | |
147 | * a default gateway. | |
148 | * (This is done the 4.3 way with rtioctl() and should be changed) | |
149 | * - hand craft the swap nfs vnode hanging off a fake mount point | |
150 | * - build the rootfs mount point and call mountnfs() to do the rest. | |
151 | */ | |
152 | nfs_mountroot() | |
153 | { | |
154 | register struct mount *mp; | |
155 | register struct mbuf *m; | |
156 | struct socket *so; | |
157 | struct vnode *vp; | |
158 | int error; | |
159 | ||
160 | /* | |
161 | * Do enough of ifconfig(8) so that critical net interface can | |
162 | * talk to the server. | |
163 | */ | |
164 | if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) | |
165 | panic("nfs ifconf"); | |
166 | if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif)) | |
167 | panic("nfs ifconf2"); | |
168 | soclose(so); | |
169 | ||
170 | /* | |
171 | * If the gateway field is filled in, set it as the default route. | |
172 | */ | |
173 | #ifdef COMPAT_43 | |
174 | if (nfs_diskless.mygateway.sa_family == AF_INET) { | |
175 | struct ortentry rt; | |
176 | struct sockaddr_in *sin; | |
177 | ||
178 | sin = (struct sockaddr_in *) &rt.rt_dst; | |
179 | sin->sin_len = sizeof (struct sockaddr_in); | |
180 | sin->sin_family = AF_INET; | |
181 | sin->sin_addr.s_addr = 0; /* default */ | |
182 | bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway, | |
183 | sizeof (struct sockaddr_in)); | |
184 | rt.rt_flags = (RTF_UP | RTF_GATEWAY); | |
185 | if (rtioctl(SIOCADDRT, (caddr_t)&rt)) | |
186 | panic("nfs root route"); | |
187 | } | |
188 | #endif /* COMPAT_43 */ | |
189 | ||
190 | /* | |
191 | * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): | |
192 | * Create a fake mount point just for the swap vnode so that the | |
193 | * swap file can be on a different server from the rootfs. | |
194 | */ | |
195 | if (swdevt[0].sw_dev == NODEV) { | |
196 | mp = (struct mount *)malloc((u_long)sizeof(struct mount), | |
197 | M_MOUNT, M_NOWAIT); | |
198 | if (mp == NULL) | |
199 | panic("nfs root mount"); | |
200 | mp->mnt_op = &nfs_vfsops; | |
201 | mp->mnt_flag = 0; | |
202 | mp->mnt_exroot = 0; | |
203 | mp->mnt_mounth = NULLVP; | |
204 | ||
205 | /* | |
206 | * Set up the diskless nfs_args for the swap mount point | |
207 | * and then call mountnfs() to mount it. | |
208 | * Since the swap file is not the root dir of a file system, | |
209 | * hack it to a regular file. | |
210 | */ | |
211 | nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh; | |
212 | MGET(m, MT_SONAME, M_DONTWAIT); | |
213 | if (m == NULL) | |
214 | panic("nfs root mbuf"); | |
215 | bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t), | |
216 | nfs_diskless.swap_saddr.sa_len); | |
217 | m->m_len = nfs_diskless.swap_saddr.sa_len; | |
218 | if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap", | |
219 | nfs_diskless.swap_hostnam, &vp)) | |
220 | panic("nfs swap"); | |
221 | vp->v_type = VREG; | |
222 | vp->v_flag = 0; | |
223 | swapdev_vp = vp; | |
224 | VREF(vp); | |
225 | swdevt[0].sw_vp = vp; | |
226 | } | |
227 | ||
228 | /* | |
229 | * Create the rootfs mount point. | |
230 | */ | |
231 | mp = (struct mount *)malloc((u_long)sizeof(struct mount), | |
232 | M_MOUNT, M_NOWAIT); | |
233 | if (mp == NULL) | |
234 | panic("nfs root mount2"); | |
235 | mp->mnt_op = &nfs_vfsops; | |
236 | mp->mnt_flag = MNT_RDONLY; | |
237 | mp->mnt_exroot = 0; | |
238 | mp->mnt_mounth = NULLVP; | |
239 | ||
240 | /* | |
241 | * Set up the root fs args and call mountnfs() to do the rest. | |
242 | */ | |
243 | nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh; | |
244 | MGET(m, MT_SONAME, M_DONTWAIT); | |
245 | if (m == NULL) | |
246 | panic("nfs root mbuf2"); | |
247 | bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t), | |
248 | nfs_diskless.root_saddr.sa_len); | |
249 | m->m_len = nfs_diskless.root_saddr.sa_len; | |
250 | if (mountnfs(&nfs_diskless.root_args, mp, m, "/", | |
251 | nfs_diskless.root_hostnam, &vp)) | |
252 | panic("nfs root"); | |
253 | if (vfs_lock(mp)) | |
254 | panic("nfs root2"); | |
255 | rootfs = mp; | |
256 | mp->mnt_next = mp; | |
257 | mp->mnt_prev = mp; | |
258 | mp->mnt_vnodecovered = NULLVP; | |
259 | vfs_unlock(mp); | |
260 | rootvp = vp; | |
261 | inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */ | |
262 | return (0); | |
263 | } | |
264 | ||
265 | /* | |
266 | * VFS Operations. | |
267 | * | |
268 | * mount system call | |
269 | * It seems a bit dumb to copyinstr() the host and path here and then | |
270 | * bcopy() them in mountnfs(), but I wanted to detect errors before | |
271 | * doing the sockargs() call because sockargs() allocates an mbuf and | |
272 | * an error after that means that I have to release the mbuf. | |
273 | */ | |
274 | /* ARGSUSED */ | |
275 | nfs_mount(mp, path, data, ndp, p) | |
276 | struct mount *mp; | |
277 | char *path; | |
278 | caddr_t data; | |
279 | struct nameidata *ndp; | |
280 | struct proc *p; | |
281 | { | |
282 | int error; | |
283 | struct nfs_args args; | |
284 | struct mbuf *nam; | |
285 | struct vnode *vp; | |
286 | char pth[MNAMELEN], hst[MNAMELEN]; | |
287 | u_int len; | |
288 | nfsv2fh_t nfh; | |
289 | ||
290 | if (mp->mnt_flag & MNT_UPDATE) | |
291 | return (0); | |
292 | if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) | |
293 | return (error); | |
294 | if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) | |
295 | return (error); | |
296 | if (error = copyinstr(path, pth, MNAMELEN-1, &len)) | |
297 | return (error); | |
298 | bzero(&pth[len], MNAMELEN - len); | |
299 | if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) | |
300 | return (error); | |
301 | bzero(&hst[len], MNAMELEN - len); | |
302 | /* sockargs() call must be after above copyin() calls */ | |
303 | if (error = sockargs(&nam, (caddr_t)args.addr, | |
304 | sizeof (struct sockaddr), MT_SONAME)) | |
305 | return (error); | |
306 | args.fh = &nfh; | |
307 | error = mountnfs(&args, mp, nam, pth, hst, &vp); | |
308 | return (error); | |
309 | } | |
310 | ||
311 | /* | |
312 | * Common code for mount and mountroot | |
313 | */ | |
314 | mountnfs(argp, mp, nam, pth, hst, vpp) | |
315 | register struct nfs_args *argp; | |
316 | register struct mount *mp; | |
317 | struct mbuf *nam; | |
318 | char *pth, *hst; | |
319 | struct vnode **vpp; | |
320 | { | |
321 | register struct nfsmount *nmp; | |
322 | struct proc *p = curproc; /* XXX */ | |
323 | struct nfsnode *np; | |
324 | int error; | |
325 | fsid_t tfsid; | |
326 | ||
327 | MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); | |
328 | bzero((caddr_t)nmp, sizeof *nmp); | |
329 | mp->mnt_data = (qaddr_t)nmp; | |
330 | /* | |
331 | * Generate a unique nfs mount id. The problem is that a dev number | |
332 | * is not unique across multiple systems. The techique is as follows: | |
333 | * 1) Set to nblkdev,0 which will never be used otherwise | |
334 | * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is | |
335 | * NOT 0 | |
336 | * 3) Loop searching the mount list for another one with same id | |
337 | * If a match, increment val[0] and try again | |
338 | * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } | |
339 | * so that nfs is not limited to 255 mount points | |
340 | * Incrementing the high order bits does no real harm, since it | |
341 | * simply makes the major dev number tick up. The upper bound is | |
342 | * set to major dev 127 to avoid any sign extention problems | |
343 | */ | |
344 | mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); | |
345 | mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; | |
346 | if (++nfs_mntid == 0) | |
347 | ++nfs_mntid; | |
348 | tfsid.val[0] = makedev(nblkdev, nfs_mntid); | |
349 | tfsid.val[1] = MOUNT_NFS; | |
350 | while (rootfs && getvfs(&tfsid)) { | |
351 | tfsid.val[0]++; | |
352 | nfs_mntid++; | |
353 | } | |
354 | if (major(tfsid.val[0]) > 127) { | |
355 | error = ENOENT; | |
356 | goto bad; | |
357 | } | |
358 | mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; | |
359 | nmp->nm_mountp = mp; | |
360 | nmp->nm_flag = argp->flags; | |
361 | nmp->nm_rto = NFS_TIMEO; | |
362 | nmp->nm_rtt = -1; | |
363 | nmp->nm_rttvar = nmp->nm_rto << 1; | |
364 | nmp->nm_retry = NFS_RETRANS; | |
365 | nmp->nm_wsize = NFS_WSIZE; | |
366 | nmp->nm_rsize = NFS_RSIZE; | |
367 | bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); | |
368 | bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); | |
369 | bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); | |
370 | nmp->nm_nam = nam; | |
371 | ||
372 | if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { | |
373 | nmp->nm_rto = argp->timeo; | |
374 | /* NFS timeouts are specified in 1/10 sec. */ | |
375 | nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; | |
376 | if (nmp->nm_rto < NFS_MINTIMEO) | |
377 | nmp->nm_rto = NFS_MINTIMEO; | |
378 | else if (nmp->nm_rto > NFS_MAXTIMEO) | |
379 | nmp->nm_rto = NFS_MAXTIMEO; | |
380 | nmp->nm_rttvar = nmp->nm_rto << 1; | |
381 | } | |
382 | ||
383 | if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { | |
384 | nmp->nm_retry = argp->retrans; | |
385 | if (nmp->nm_retry > NFS_MAXREXMIT) | |
386 | nmp->nm_retry = NFS_MAXREXMIT; | |
387 | } | |
388 | ||
389 | if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { | |
390 | nmp->nm_wsize = argp->wsize; | |
391 | /* Round down to multiple of blocksize */ | |
392 | nmp->nm_wsize &= ~0x1ff; | |
393 | if (nmp->nm_wsize <= 0) | |
394 | nmp->nm_wsize = 512; | |
395 | else if (nmp->nm_wsize > NFS_MAXDATA) | |
396 | nmp->nm_wsize = NFS_MAXDATA; | |
397 | } | |
398 | if (nmp->nm_wsize > MAXBSIZE) | |
399 | nmp->nm_wsize = MAXBSIZE; | |
400 | ||
401 | if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { | |
402 | nmp->nm_rsize = argp->rsize; | |
403 | /* Round down to multiple of blocksize */ | |
404 | nmp->nm_rsize &= ~0x1ff; | |
405 | if (nmp->nm_rsize <= 0) | |
406 | nmp->nm_rsize = 512; | |
407 | else if (nmp->nm_rsize > NFS_MAXDATA) | |
408 | nmp->nm_rsize = NFS_MAXDATA; | |
409 | } | |
410 | if (nmp->nm_rsize > MAXBSIZE) | |
411 | nmp->nm_rsize = MAXBSIZE; | |
412 | /* Set up the sockets and per-host congestion */ | |
413 | nmp->nm_sotype = argp->sotype; | |
414 | nmp->nm_soproto = argp->proto; | |
415 | if (error = nfs_connect(nmp)) | |
416 | goto bad; | |
417 | ||
418 | if (error = nfs_statfs(mp, &mp->mnt_stat, p)) | |
419 | goto bad; | |
420 | /* | |
421 | * A reference count is needed on the nfsnode representing the | |
422 | * remote root. If this object is not persistent, then backward | |
423 | * traversals of the mount point (i.e. "..") will not work if | |
424 | * the nfsnode gets flushed out of the cache. Ufs does not have | |
425 | * this problem, because one can identify root inodes by their | |
426 | * number == ROOTINO (2). | |
427 | */ | |
428 | if (error = nfs_nget(mp, &nmp->nm_fh, &np)) | |
429 | goto bad; | |
430 | /* | |
431 | * Unlock it, but keep the reference count. | |
432 | */ | |
433 | nfs_unlock(NFSTOV(np)); | |
434 | *vpp = NFSTOV(np); | |
435 | ||
436 | return (0); | |
437 | bad: | |
438 | nfs_disconnect(nmp); | |
439 | FREE(nmp, M_NFSMNT); | |
440 | m_freem(nam); | |
441 | return (error); | |
442 | } | |
443 | ||
444 | /* | |
445 | * unmount system call | |
446 | */ | |
447 | nfs_unmount(mp, mntflags, p) | |
448 | struct mount *mp; | |
449 | int mntflags; | |
450 | struct proc *p; | |
451 | { | |
452 | register struct nfsmount *nmp; | |
453 | struct nfsnode *np; | |
454 | struct vnode *vp; | |
455 | int error, flags = 0; | |
456 | extern int doforce; | |
457 | ||
458 | if (mntflags & MNT_FORCE) { | |
459 | if (!doforce || mp == rootfs) | |
460 | return (EINVAL); | |
461 | flags |= FORCECLOSE; | |
462 | } | |
463 | nmp = VFSTONFS(mp); | |
464 | /* | |
465 | * Clear out the buffer cache | |
466 | */ | |
467 | mntflushbuf(mp, 0); | |
468 | if (mntinvalbuf(mp)) | |
469 | return (EBUSY); | |
470 | /* | |
471 | * Goes something like this.. | |
472 | * - Check for activity on the root vnode (other than ourselves). | |
473 | * - Call vflush() to clear out vnodes for this file system, | |
474 | * except for the root vnode. | |
475 | * - Decrement reference on the vnode representing remote root. | |
476 | * - Close the socket | |
477 | * - Free up the data structures | |
478 | */ | |
479 | /* | |
480 | * We need to decrement the ref. count on the nfsnode representing | |
481 | * the remote root. See comment in mountnfs(). The VFS unmount() | |
482 | * has done vput on this vnode, otherwise we would get deadlock! | |
483 | */ | |
484 | if (error = nfs_nget(mp, &nmp->nm_fh, &np)) | |
485 | return(error); | |
486 | vp = NFSTOV(np); | |
487 | if (vp->v_usecount > 2) { | |
488 | vput(vp); | |
489 | return (EBUSY); | |
490 | } | |
491 | if (error = vflush(mp, vp, flags)) { | |
492 | vput(vp); | |
493 | return (error); | |
494 | } | |
495 | /* | |
496 | * Get rid of two reference counts, and unlock it on the second. | |
497 | */ | |
498 | vrele(vp); | |
499 | vput(vp); | |
500 | nfs_disconnect(nmp); | |
501 | m_freem(nmp->nm_nam); | |
502 | free((caddr_t)nmp, M_NFSMNT); | |
503 | return (0); | |
504 | } | |
505 | ||
506 | /* | |
507 | * Return root of a filesystem | |
508 | */ | |
509 | nfs_root(mp, vpp) | |
510 | struct mount *mp; | |
511 | struct vnode **vpp; | |
512 | { | |
513 | register struct vnode *vp; | |
514 | struct nfsmount *nmp; | |
515 | struct nfsnode *np; | |
516 | int error; | |
517 | ||
518 | nmp = VFSTONFS(mp); | |
519 | if (error = nfs_nget(mp, &nmp->nm_fh, &np)) | |
520 | return (error); | |
521 | vp = NFSTOV(np); | |
522 | vp->v_type = VDIR; | |
523 | vp->v_flag = VROOT; | |
524 | *vpp = vp; | |
525 | return (0); | |
526 | } | |
527 | ||
528 | extern int syncprt; | |
529 | ||
530 | /* | |
531 | * Flush out the buffer cache | |
532 | */ | |
533 | /* ARGSUSED */ | |
534 | nfs_sync(mp, waitfor) | |
535 | struct mount *mp; | |
536 | int waitfor; | |
537 | { | |
538 | if (syncprt) | |
539 | bufstats(); | |
540 | /* | |
541 | * Force stale buffer cache information to be flushed. | |
542 | */ | |
543 | mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); | |
544 | return (0); | |
545 | } | |
546 | ||
547 | /* | |
548 | * At this point, this should never happen | |
549 | */ | |
550 | /* ARGSUSED */ | |
551 | nfs_fhtovp(mp, fhp, vpp) | |
552 | struct mount *mp; | |
553 | struct fid *fhp; | |
554 | struct vnode **vpp; | |
555 | { | |
556 | ||
557 | return (EINVAL); | |
558 | } | |
559 | ||
560 | /* | |
561 | * Vnode pointer to File handle, should never happen either | |
562 | */ | |
563 | /* ARGSUSED */ | |
564 | nfs_vptofh(vp, fhp) | |
565 | struct vnode *vp; | |
566 | struct fid *fhp; | |
567 | { | |
568 | ||
569 | return (EINVAL); | |
570 | } | |
571 | ||
572 | /* | |
573 | * Vfs start routine, a no-op. | |
574 | */ | |
575 | /* ARGSUSED */ | |
576 | nfs_start(mp, flags, p) | |
577 | struct mount *mp; | |
578 | int flags; | |
579 | struct proc *p; | |
580 | { | |
581 | ||
582 | return (0); | |
583 | } | |
584 | ||
585 | /* | |
586 | * Do operations associated with quotas, not supported | |
587 | */ | |
588 | nfs_quotactl(mp, cmd, uid, arg, p) | |
589 | struct mount *mp; | |
590 | int cmd; | |
591 | uid_t uid; | |
592 | caddr_t arg; | |
593 | struct proc *p; | |
594 | { | |
595 | #ifdef lint | |
596 | mp = mp; cmd = cmd; uid = uid; arg = arg; | |
597 | #endif /* lint */ | |
598 | return (EOPNOTSUPP); | |
599 | } |