1 /*
2  * Copyright (c) 1994 The Regents of the University of California.
3  * Copyright (c) 1994 Jan-Simon Pendry.
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)union_vfsops.c	1.2 (Berkeley) 02/01/94
12  */
13 
14 /*
15  * Null Layer
16  * (See union_vnops.c for a description of what this does.)
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/proc.h>
24 #include <sys/vnode.h>
25 #include <sys/mount.h>
26 #include <sys/namei.h>
27 #include <sys/malloc.h>
28 #include "union.h"
29 
30 /*
31  * Mount union filesystem
32  */
33 int
34 union_mount(mp, path, data, ndp, p)
35 	struct mount *mp;
36 	char *path;
37 	caddr_t data;
38 	struct nameidata *ndp;
39 	struct proc *p;
40 {
41 	int error = 0;
42 	struct union_args args;
43 	struct vnode *lowerrootvp;
44 	struct vnode *upperrootvp;
45 	struct union_mount *um;
46 	u_int size;
47 
48 #ifdef UNION_DIAGNOSTIC
49 	printf("union_mount(mp = %x)\n", mp);
50 #endif
51 
52 	/*
53 	 * Update is a no-op
54 	 */
55 	if (mp->mnt_flag & MNT_UPDATE)
56 		return (EOPNOTSUPP);
57 
58 	/*
59 	 * Get argument
60 	 */
61 	if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args)))
62 		return (error);
63 
64 	lowerrootvp = mp->mnt_vnodecovered;
65 	VREF(lowerrootvp);
66 
67 	/*
68 	 * Find upper node
69 	 */
70 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
71 	       UIO_USERSPACE, args.target, p);
72 	if (error = namei(ndp)) {
73 		vrele(lowerrootvp);
74 		return (error);
75 	}
76 	upperrootvp = ndp->ni_vp;
77 	vrele(ndp->ni_dvp);
78 	ndp->ni_dvp = NULL;
79 
80 	if (upperrootvp->v_type != VDIR) {
81 		vrele(upperrootvp);
82 		return (EINVAL);
83 	}
84 
85 	um = (struct union_mount *) malloc(sizeof(struct union_mount),
86 				M_UFSMNT, M_WAITOK);	/* XXX */
87 
88 	/*
89 	 * Keep a held reference to the target vnodes.
90 	 * They are vrele'd in union_unmount.
91 	 */
92 	um->um_lowervp = lowerrootvp;
93 	um->um_uppervp = upperrootvp;
94 	/*
95 	 * Take a copy of the process's credentials.  This isn't
96 	 * quite right since the euid will always be zero and we
97 	 * want to get the "real" users credentials.  So fix up
98 	 * the uid field after taking the copy.
99 	 */
100 	um->um_cred = crdup(p->p_ucred);
101 	um->um_cred->cr_uid = p->p_cred->p_ruid;
102 
103 	if ((lowerrootvp->v_mount->mnt_flag & MNT_LOCAL) ||
104 	    (upperrootvp->v_mount->mnt_flag & MNT_LOCAL))
105 		mp->mnt_flag |= MNT_LOCAL;
106 	mp->mnt_data = (qaddr_t) um;
107 	getnewfsid(mp, MOUNT_UNION);
108 
109 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
110 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
111 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
112 	    &size);
113 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
114 #ifdef UNION_DIAGNOSTIC
115 	printf("union_mount: upper %s, lower at %s\n",
116 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
117 #endif
118 	return (0);
119 }
120 
121 /*
122  * VFS start.  Nothing needed here - the start routine
123  * on the underlying filesystem(s) will have been called
124  * when that filesystem was mounted.
125  */
126 int
127 union_start(mp, flags, p)
128 	struct mount *mp;
129 	int flags;
130 	struct proc *p;
131 {
132 
133 	return (0);
134 }
135 
136 /*
137  * Free reference to union layer
138  */
139 int
140 union_unmount(mp, mntflags, p)
141 	struct mount *mp;
142 	int mntflags;
143 	struct proc *p;
144 {
145 	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
146 	struct vnode *um_rootvp;
147 	int error;
148 	int flags = 0;
149 	extern int doforce;
150 
151 #ifdef UNION_DIAGNOSTIC
152 	printf("union_unmount(mp = %x)\n", mp);
153 #endif
154 
155 	if (mntflags & MNT_FORCE) {
156 		/* union can never be rootfs so don't check for it */
157 		if (!doforce)
158 			return (EINVAL);
159 		flags |= FORCECLOSE;
160 	}
161 
162 	if (error = union_root(mp, &um_rootvp))
163 		return (error);
164 	if (um_rootvp->v_usecount > 1)
165 		return (EBUSY);
166 	if (error = vflush(mp, um_rootvp, flags))
167 		return (error);
168 
169 #ifdef UNION_DIAGNOSTIC
170 	vprint("alias root of lower", um_rootvp);
171 #endif
172 	/*
173 	 * Discard references to upper and lower target vnodes.
174 	 */
175 	vrele(um->um_lowervp);
176 	vrele(um->um_uppervp);
177 	crfree(um->um_cred);
178 	/*
179 	 * Release reference on underlying root vnode
180 	 */
181 	vrele(um_rootvp);
182 	/*
183 	 * And blow it away for future re-use
184 	 */
185 	vgone(um_rootvp);
186 	/*
187 	 * Finally, throw away the union_mount structure
188 	 */
189 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
190 	mp->mnt_data = 0;
191 	return 0;
192 }
193 
194 int
195 union_root(mp, vpp)
196 	struct mount *mp;
197 	struct vnode **vpp;
198 {
199 	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
200 	int error;
201 
202 #ifdef UNION_DIAGNOSTIC
203 	printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp,
204 			um->um_lowervp,
205 			um->um_uppervp);
206 #endif
207 
208 	/*
209 	 * Return locked reference to root.
210 	 */
211 	error = union_allocvp(vpp, mp, (struct vnode *) 0,
212 			      (struct componentname *) 0,
213 			      um->um_uppervp,
214 			      um->um_lowervp);
215 	if (error == 0)
216 		(*vpp)->v_flag |= VROOT;
217 
218 	return (error);
219 }
220 
221 int
222 union_quotactl(mp, cmd, uid, arg, p)
223 	struct mount *mp;
224 	int cmd;
225 	uid_t uid;
226 	caddr_t arg;
227 	struct proc *p;
228 {
229 
230 	return (EOPNOTSUPP);
231 }
232 
233 int
234 union_statfs(mp, sbp, p)
235 	struct mount *mp;
236 	struct statfs *sbp;
237 	struct proc *p;
238 {
239 	int error;
240 	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
241 	struct statfs mstat;
242 	int lbsize;
243 
244 #ifdef UNION_DIAGNOSTIC
245 	printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
246 			um->um_lowervp,
247 	       		um->um_uppervp);
248 #endif
249 
250 	bzero(&mstat, sizeof(mstat));
251 
252 	error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
253 	if (error)
254 		return (error);
255 
256 	/* now copy across the "interesting" information and fake the rest */
257 #if 0
258 	sbp->f_type = mstat.f_type;
259 	sbp->f_flags = mstat.f_flags;
260 	sbp->f_bsize = mstat.f_bsize;
261 	sbp->f_iosize = mstat.f_iosize;
262 #endif
263 	lbsize = mstat.f_bsize;
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 
270 	error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
271 	if (error)
272 		return (error);
273 
274 	sbp->f_type = mstat.f_type;
275 	sbp->f_flags = mstat.f_flags;
276 	sbp->f_bsize = mstat.f_bsize;
277 	sbp->f_iosize = mstat.f_iosize;
278 
279 	/*
280 	 * if the lower and upper blocksizes differ, then frig the
281 	 * block counts so that the sizes reported by df make some
282 	 * kind of sense.  none of this makes sense though.
283 	 */
284 
285 	if (mstat.f_bsize != lbsize) {
286 		sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
287 		sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize;
288 		sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize;
289 	}
290 	sbp->f_blocks += mstat.f_blocks;
291 	sbp->f_bfree += mstat.f_bfree;
292 	sbp->f_bavail += mstat.f_bavail;
293 	sbp->f_files += mstat.f_files;
294 	sbp->f_ffree += mstat.f_ffree;
295 
296 	if (sbp != &mp->mnt_stat) {
297 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
298 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
299 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
300 	}
301 	return (0);
302 }
303 
304 int
305 union_sync(mp, waitfor, cred, p)
306 	struct mount *mp;
307 	int waitfor;
308 	struct ucred *cred;
309 	struct proc *p;
310 {
311 
312 	/*
313 	 * XXX - Assumes no data cached at union layer.
314 	 */
315 	return (0);
316 }
317 
318 int
319 union_vget(mp, ino, vpp)
320 	struct mount *mp;
321 	ino_t ino;
322 	struct vnode **vpp;
323 {
324 
325 	return (EOPNOTSUPP);
326 }
327 
328 int
329 union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
330 	struct mount *mp;
331 	struct fid *fidp;
332 	struct mbuf *nam;
333 	struct vnode **vpp;
334 	int *exflagsp;
335 	struct ucred **credanonp;
336 {
337 
338 	return (EOPNOTSUPP);
339 }
340 
341 int
342 union_vptofh(vp, fhp)
343 	struct vnode *vp;
344 	struct fid *fhp;
345 {
346 
347 	return (EOPNOTSUPP);
348 }
349 
350 int union_init __P((void));
351 
352 struct vfsops union_vfsops = {
353 	union_mount,
354 	union_start,
355 	union_unmount,
356 	union_root,
357 	union_quotactl,
358 	union_statfs,
359 	union_sync,
360 	union_vget,
361 	union_fhtovp,
362 	union_vptofh,
363 	union_init,
364 };
365