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