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