checkpoint
[unix-history] / usr / src / sys / miscfs / union / union_vfsops.c
CommitLineData
a1fa407d
JSP
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 *
79f80c71 11 * @(#)union_vfsops.c 1.4 (Berkeley) %G%
a1fa407d
JSP
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 */
33int
34union_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 */
126int
127union_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 */
139int
140union_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);
01dac67e
JSP
164 if (um_rootvp->v_usecount > 1) {
165 vput(um_rootvp);
a1fa407d 166 return (EBUSY);
01dac67e
JSP
167 }
168 if (error = vflush(mp, um_rootvp, flags)) {
169 vput(um_rootvp);
a1fa407d 170 return (error);
01dac67e 171 }
a1fa407d
JSP
172
173#ifdef UNION_DIAGNOSTIC
174 vprint("alias root of lower", um_rootvp);
175#endif
176 /*
177 * Discard references to upper and lower target vnodes.
178 */
179 vrele(um->um_lowervp);
180 vrele(um->um_uppervp);
181 crfree(um->um_cred);
182 /*
183 * Release reference on underlying root vnode
184 */
01dac67e 185 vput(um_rootvp);
a1fa407d
JSP
186 /*
187 * And blow it away for future re-use
188 */
189 vgone(um_rootvp);
190 /*
191 * Finally, throw away the union_mount structure
192 */
193 free(mp->mnt_data, M_UFSMNT); /* XXX */
194 mp->mnt_data = 0;
195 return 0;
196}
197
198int
199union_root(mp, vpp)
200 struct mount *mp;
201 struct vnode **vpp;
202{
203 struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
204 int error;
205
206#ifdef UNION_DIAGNOSTIC
207 printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp,
208 um->um_lowervp,
209 um->um_uppervp);
210#endif
211
212 /*
213 * Return locked reference to root.
214 */
01dac67e
JSP
215 VREF(um->um_uppervp);
216 VREF(um->um_lowervp);
79f80c71
JSP
217 error = union_allocvp(vpp, mp,
218 (struct vnode *) 0,
219 (struct vnode *) 0,
a1fa407d
JSP
220 (struct componentname *) 0,
221 um->um_uppervp,
222 um->um_lowervp);
01dac67e
JSP
223
224 if (error) {
225 vrele(um->um_uppervp);
226 vrele(um->um_lowervp);
227 } else {
a1fa407d 228 (*vpp)->v_flag |= VROOT;
01dac67e 229 }
a1fa407d
JSP
230
231 return (error);
232}
233
234int
235union_quotactl(mp, cmd, uid, arg, p)
236 struct mount *mp;
237 int cmd;
238 uid_t uid;
239 caddr_t arg;
240 struct proc *p;
241{
242
243 return (EOPNOTSUPP);
244}
245
246int
247union_statfs(mp, sbp, p)
248 struct mount *mp;
249 struct statfs *sbp;
250 struct proc *p;
251{
252 int error;
253 struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
254 struct statfs mstat;
255 int lbsize;
256
257#ifdef UNION_DIAGNOSTIC
258 printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
259 um->um_lowervp,
260 um->um_uppervp);
261#endif
262
263 bzero(&mstat, sizeof(mstat));
264
265 error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
266 if (error)
267 return (error);
268
269 /* now copy across the "interesting" information and fake the rest */
270#if 0
271 sbp->f_type = mstat.f_type;
272 sbp->f_flags = mstat.f_flags;
273 sbp->f_bsize = mstat.f_bsize;
274 sbp->f_iosize = mstat.f_iosize;
275#endif
276 lbsize = mstat.f_bsize;
277 sbp->f_blocks = mstat.f_blocks;
278 sbp->f_bfree = mstat.f_bfree;
279 sbp->f_bavail = mstat.f_bavail;
280 sbp->f_files = mstat.f_files;
281 sbp->f_ffree = mstat.f_ffree;
282
283 error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
284 if (error)
285 return (error);
286
287 sbp->f_type = mstat.f_type;
288 sbp->f_flags = mstat.f_flags;
289 sbp->f_bsize = mstat.f_bsize;
290 sbp->f_iosize = mstat.f_iosize;
291
292 /*
293 * if the lower and upper blocksizes differ, then frig the
294 * block counts so that the sizes reported by df make some
295 * kind of sense. none of this makes sense though.
296 */
297
298 if (mstat.f_bsize != lbsize) {
299 sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
300 sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize;
301 sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize;
302 }
303 sbp->f_blocks += mstat.f_blocks;
304 sbp->f_bfree += mstat.f_bfree;
305 sbp->f_bavail += mstat.f_bavail;
306 sbp->f_files += mstat.f_files;
307 sbp->f_ffree += mstat.f_ffree;
308
309 if (sbp != &mp->mnt_stat) {
310 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
311 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
312 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
313 }
314 return (0);
315}
316
317int
318union_sync(mp, waitfor, cred, p)
319 struct mount *mp;
320 int waitfor;
321 struct ucred *cred;
322 struct proc *p;
323{
324
325 /*
326 * XXX - Assumes no data cached at union layer.
327 */
328 return (0);
329}
330
331int
332union_vget(mp, ino, vpp)
333 struct mount *mp;
334 ino_t ino;
335 struct vnode **vpp;
336{
337
338 return (EOPNOTSUPP);
339}
340
341int
342union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
343 struct mount *mp;
344 struct fid *fidp;
345 struct mbuf *nam;
346 struct vnode **vpp;
347 int *exflagsp;
348 struct ucred **credanonp;
349{
350
351 return (EOPNOTSUPP);
352}
353
354int
355union_vptofh(vp, fhp)
356 struct vnode *vp;
357 struct fid *fhp;
358{
359
360 return (EOPNOTSUPP);
361}
362
363int union_init __P((void));
364
365struct vfsops union_vfsops = {
366 union_mount,
367 union_start,
368 union_unmount,
369 union_root,
370 union_quotactl,
371 union_statfs,
372 union_sync,
373 union_vget,
374 union_fhtovp,
375 union_vptofh,
376 union_init,
377};