1 /*
2  * Copyright (c) 1992, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)null_vfsops.c	8.6 (Berkeley) 05/10/95
11  *
12  * @(#)lofs_vfsops.c	1.2 (Berkeley) 6/18/92
13  * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
14  */
15 
16 /*
17  * Null Layer
18  * (See null_vnops.c for a description of what this does.)
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/vnode.h>
26 #include <sys/mount.h>
27 #include <sys/namei.h>
28 #include <sys/malloc.h>
29 #include <miscfs/nullfs/null.h>
30 
31 /*
32  * Mount null layer
33  */
34 int
35 nullfs_mount(mp, path, data, ndp, p)
36 	struct mount *mp;
37 	char *path;
38 	caddr_t data;
39 	struct nameidata *ndp;
40 	struct proc *p;
41 {
42 	int error = 0;
43 	struct null_args args;
44 	struct vnode *lowerrootvp, *vp;
45 	struct vnode *nullm_rootvp;
46 	struct null_mount *xmp;
47 	u_int size;
48 
49 #ifdef NULLFS_DIAGNOSTIC
50 	printf("nullfs_mount(mp = %x)\n", mp);
51 #endif
52 
53 	/*
54 	 * Update is a no-op
55 	 */
56 	if (mp->mnt_flag & MNT_UPDATE) {
57 		return (EOPNOTSUPP);
58 		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
59 	}
60 
61 	/*
62 	 * Get argument
63 	 */
64 	if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
65 		return (error);
66 
67 	/*
68 	 * Find lower node
69 	 */
70 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
71 		UIO_USERSPACE, args.target, p);
72 	if (error = namei(ndp))
73 		return (error);
74 
75 	/*
76 	 * Sanity check on lower vnode
77 	 */
78 	lowerrootvp = ndp->ni_vp;
79 
80 	vrele(ndp->ni_dvp);
81 	ndp->ni_dvp = NULL;
82 
83 	xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
84 				M_UFSMNT, M_WAITOK);	/* XXX */
85 
86 	/*
87 	 * Save reference to underlying FS
88 	 */
89 	xmp->nullm_vfs = lowerrootvp->v_mount;
90 
91 	/*
92 	 * Save reference.  Each mount also holds
93 	 * a reference on the root vnode.
94 	 */
95 	error = null_node_create(mp, lowerrootvp, &vp);
96 	/*
97 	 * Unlock the node (either the lower or the alias)
98 	 */
99 	VOP_UNLOCK(vp);
100 	/*
101 	 * Make sure the node alias worked
102 	 */
103 	if (error) {
104 		vrele(lowerrootvp);
105 		free(xmp, M_UFSMNT);	/* XXX */
106 		return (error);
107 	}
108 
109 	/*
110 	 * Keep a held reference to the root vnode.
111 	 * It is vrele'd in nullfs_unmount.
112 	 */
113 	nullm_rootvp = vp;
114 	nullm_rootvp->v_flag |= VROOT;
115 	xmp->nullm_rootvp = nullm_rootvp;
116 	if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
117 		mp->mnt_flag |= MNT_LOCAL;
118 	mp->mnt_data = (qaddr_t) xmp;
119 	vfs_getnewfsid(mp);
120 
121 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
122 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
123 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
124 	    &size);
125 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
126 #ifdef NULLFS_DIAGNOSTIC
127 	printf("nullfs_mount: lower %s, alias at %s\n",
128 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
129 #endif
130 	return (0);
131 }
132 
133 /*
134  * VFS start.  Nothing needed here - the start routine
135  * on the underlying filesystem will have been called
136  * when that filesystem was mounted.
137  */
138 int
139 nullfs_start(mp, flags, p)
140 	struct mount *mp;
141 	int flags;
142 	struct proc *p;
143 {
144 	return (0);
145 	/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
146 }
147 
148 /*
149  * Free reference to null layer
150  */
151 int
152 nullfs_unmount(mp, mntflags, p)
153 	struct mount *mp;
154 	int mntflags;
155 	struct proc *p;
156 {
157 	struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
158 	int error;
159 	int flags = 0;
160 
161 #ifdef NULLFS_DIAGNOSTIC
162 	printf("nullfs_unmount(mp = %x)\n", mp);
163 #endif
164 
165 	if (mntflags & MNT_FORCE)
166 		flags |= FORCECLOSE;
167 
168 	/*
169 	 * Clear out buffer cache.  I don't think we
170 	 * ever get anything cached at this level at the
171 	 * moment, but who knows...
172 	 */
173 #if 0
174 	mntflushbuf(mp, 0);
175 	if (mntinvalbuf(mp, 1))
176 		return (EBUSY);
177 #endif
178 	if (nullm_rootvp->v_usecount > 1)
179 		return (EBUSY);
180 	if (error = vflush(mp, nullm_rootvp, flags))
181 		return (error);
182 
183 #ifdef NULLFS_DIAGNOSTIC
184 	vprint("alias root of lower", nullm_rootvp);
185 #endif
186 	/*
187 	 * Release reference on underlying root vnode
188 	 */
189 	vrele(nullm_rootvp);
190 	/*
191 	 * And blow it away for future re-use
192 	 */
193 	vgone(nullm_rootvp);
194 	/*
195 	 * Finally, throw away the null_mount structure
196 	 */
197 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
198 	mp->mnt_data = 0;
199 	return 0;
200 }
201 
202 int
203 nullfs_root(mp, vpp)
204 	struct mount *mp;
205 	struct vnode **vpp;
206 {
207 	struct vnode *vp;
208 
209 #ifdef NULLFS_DIAGNOSTIC
210 	printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
211 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
212 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
213 			);
214 #endif
215 
216 	/*
217 	 * Return locked reference to root.
218 	 */
219 	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
220 	VREF(vp);
221 	VOP_LOCK(vp);
222 	*vpp = vp;
223 	return 0;
224 }
225 
226 int
227 nullfs_quotactl(mp, cmd, uid, arg, p)
228 	struct mount *mp;
229 	int cmd;
230 	uid_t uid;
231 	caddr_t arg;
232 	struct proc *p;
233 {
234 	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
235 }
236 
237 int
238 nullfs_statfs(mp, sbp, p)
239 	struct mount *mp;
240 	struct statfs *sbp;
241 	struct proc *p;
242 {
243 	int error;
244 	struct statfs mstat;
245 
246 #ifdef NULLFS_DIAGNOSTIC
247 	printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
248 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
249 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
250 			);
251 #endif
252 
253 	bzero(&mstat, sizeof(mstat));
254 
255 	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
256 	if (error)
257 		return (error);
258 
259 	/* now copy across the "interesting" information and fake the rest */
260 	sbp->f_type = mstat.f_type;
261 	sbp->f_flags = mstat.f_flags;
262 	sbp->f_bsize = mstat.f_bsize;
263 	sbp->f_iosize = mstat.f_iosize;
264 	sbp->f_blocks = mstat.f_blocks;
265 	sbp->f_bfree = mstat.f_bfree;
266 	sbp->f_bavail = mstat.f_bavail;
267 	sbp->f_files = mstat.f_files;
268 	sbp->f_ffree = mstat.f_ffree;
269 	if (sbp != &mp->mnt_stat) {
270 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
271 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
272 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
273 	}
274 	return (0);
275 }
276 
277 int
278 nullfs_sync(mp, waitfor, cred, p)
279 	struct mount *mp;
280 	int waitfor;
281 	struct ucred *cred;
282 	struct proc *p;
283 {
284 	/*
285 	 * XXX - Assumes no data cached at null layer.
286 	 */
287 	return (0);
288 }
289 
290 int
291 nullfs_vget(mp, ino, vpp)
292 	struct mount *mp;
293 	ino_t ino;
294 	struct vnode **vpp;
295 {
296 
297 	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
298 }
299 
300 int
301 nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
302 	struct mount *mp;
303 	struct fid *fidp;
304 	struct mbuf *nam;
305 	struct vnode **vpp;
306 	int *exflagsp;
307 	struct ucred**credanonp;
308 {
309 
310 	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
311 }
312 
313 int
314 nullfs_vptofh(vp, fhp)
315 	struct vnode *vp;
316 	struct fid *fhp;
317 {
318 	return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
319 }
320 
321 int nullfs_init __P((struct vfsconf *));
322 
323 #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
324 	    size_t, struct proc *)))eopnotsupp)
325 
326 struct vfsops null_vfsops = {
327 	nullfs_mount,
328 	nullfs_start,
329 	nullfs_unmount,
330 	nullfs_root,
331 	nullfs_quotactl,
332 	nullfs_statfs,
333 	nullfs_sync,
334 	nullfs_vget,
335 	nullfs_fhtovp,
336 	nullfs_vptofh,
337 	nullfs_init,
338 	nullfs_sysctl,
339 };
340