|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1994, 1995 The Regents of the University of California.
28: * Copyright (c) 1994, 1995 Jan-Simon Pendry.
29: * All rights reserved.
30: *
31: * This code is derived from software donated to Berkeley by
32: * Jan-Simon Pendry.
33: *
34: * Redistribution and use in source and binary forms, with or without
35: * modification, are permitted provided that the following conditions
36: * are met:
37: * 1. Redistributions of source code must retain the above copyright
38: * notice, this list of conditions and the following disclaimer.
39: * 2. Redistributions in binary form must reproduce the above copyright
40: * notice, this list of conditions and the following disclaimer in the
41: * documentation and/or other materials provided with the distribution.
42: * 3. All advertising materials mentioning features or use of this software
43: * must display the following acknowledgement:
44: * This product includes software developed by the University of
45: * California, Berkeley and its contributors.
46: * 4. Neither the name of the University nor the names of its contributors
47: * may be used to endorse or promote products derived from this software
48: * without specific prior written permission.
49: *
50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60: * SUCH DAMAGE.
61: *
62: * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
63: */
64:
65: /*
66: * Union Layer
67: */
68:
69: #include <sys/param.h>
70: #include <sys/systm.h>
71: #include <sys/time.h>
72: #include <sys/types.h>
73: #include <sys/proc.h>
74: #include <sys/vnode.h>
75: #include <sys/mount.h>
76: #include <sys/namei.h>
77: #include <sys/malloc.h>
78: #include <sys/filedesc.h>
79: #include <sys/queue.h>
80: #include <miscfs/union/union.h>
81:
82: /*
83: * Mount union filesystem
84: */
85: int
86: union_mount(mp, path, data, ndp, p)
87: struct mount *mp;
88: char *path;
89: caddr_t data;
90: struct nameidata *ndp;
91: struct proc *p;
92: {
93: int error = 0;
94: struct union_args args;
95: struct vnode *lowerrootvp = NULLVP;
96: struct vnode *upperrootvp = NULLVP;
97: struct union_mount *um = 0;
98: struct ucred *cred = 0;
99: struct ucred *scred;
100: struct vattr va;
101: char *cp;
102: int len;
103: u_int size;
104:
105: #ifdef UNION_DIAGNOSTIC
106: printf("union_mount(mp = %x)\n", mp);
107: #endif
108:
109: /*
110: * Update is a no-op
111: */
112: if (mp->mnt_flag & MNT_UPDATE) {
113: /*
114: * Need to provide.
115: * 1. a way to convert between rdonly and rdwr mounts.
116: * 2. support for nfs exports.
117: */
118: error = EOPNOTSUPP;
119: goto bad;
120: }
121:
122: /*
123: * Get argument
124: */
125: if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args)))
126: goto bad;
127:
128: lowerrootvp = mp->mnt_vnodecovered;
129: VREF(lowerrootvp);
130:
131: /*
132: * Find upper node.
133: */
134: NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
135: UIO_USERSPACE, args.target, p);
136:
137: if (error = namei(ndp))
138: goto bad;
139:
140: upperrootvp = ndp->ni_vp;
141: vrele(ndp->ni_dvp);
142: ndp->ni_dvp = NULL;
143:
144: if (upperrootvp->v_type != VDIR) {
145: error = EINVAL;
146: goto bad;
147: }
148:
149: // um = (struct union_mount *) malloc(sizeof(struct union_mount),
150: // M_UFSMNT, M_WAITOK); /* XXX */
151: MALLOC(um, struct union_mount *, sizeof(struct union_mount),
152: M_UFSMNT, M_WAITOK);
153:
154: /*
155: * Keep a held reference to the target vnodes.
156: * They are vrele'd in union_unmount.
157: *
158: * Depending on the _BELOW flag, the filesystems are
159: * viewed in a different order. In effect, this is the
160: * same as providing a mount under option to the mount syscall.
161: */
162:
163: um->um_op = args.mntflags & UNMNT_OPMASK;
164: switch (um->um_op) {
165: case UNMNT_ABOVE:
166: um->um_lowervp = lowerrootvp;
167: um->um_uppervp = upperrootvp;
168: break;
169:
170: case UNMNT_BELOW:
171: um->um_lowervp = upperrootvp;
172: um->um_uppervp = lowerrootvp;
173: break;
174:
175: case UNMNT_REPLACE:
176: vrele(lowerrootvp);
177: lowerrootvp = NULLVP;
178: um->um_uppervp = upperrootvp;
179: um->um_lowervp = lowerrootvp;
180: break;
181:
182: default:
183: error = EINVAL;
184: goto bad;
185: }
186:
187: /*
188: * Unless the mount is readonly, ensure that the top layer
189: * supports whiteout operations
190: */
191: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
192: error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
193: if (error)
194: goto bad;
195: }
196:
197: um->um_cred = p->p_ucred;
198: crhold(um->um_cred);
199: um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
200:
201: /*
202: * Depending on what you think the MNT_LOCAL flag might mean,
203: * you may want the && to be || on the conditional below.
204: * At the moment it has been defined that the filesystem is
205: * only local if it is all local, ie the MNT_LOCAL flag implies
206: * that the entire namespace is local. If you think the MNT_LOCAL
207: * flag implies that some of the files might be stored locally
208: * then you will want to change the conditional.
209: */
210: if (um->um_op == UNMNT_ABOVE) {
211: if (((um->um_lowervp == NULLVP) ||
212: (um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) &&
213: (um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
214: mp->mnt_flag |= MNT_LOCAL;
215: }
216:
217: /*
218: * Copy in the upper layer's RDONLY flag. This is for the benefit
219: * of lookup() which explicitly checks the flag, rather than asking
220: * the filesystem for it's own opinion. This means, that an update
221: * mount of the underlying filesystem to go from rdonly to rdwr
222: * will leave the unioned view as read-only.
223: */
224: mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
225:
226: mp->mnt_data = (qaddr_t) um;
227: vfs_getnewfsid(mp);
228:
229: (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
230: bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
231:
232: switch (um->um_op) {
233: case UNMNT_ABOVE:
234: cp = "<above>:";
235: break;
236: case UNMNT_BELOW:
237: cp = "<below>:";
238: break;
239: case UNMNT_REPLACE:
240: cp = "";
241: break;
242: }
243: len = strlen(cp);
244: bcopy(cp, mp->mnt_stat.f_mntfromname, len);
245:
246: cp = mp->mnt_stat.f_mntfromname + len;
247: len = MNAMELEN - len;
248:
249: (void) copyinstr(args.target, cp, len - 1, &size);
250: bzero(cp + size, len - size);
251:
252: #ifdef UNION_DIAGNOSTIC
253: printf("union_mount: from %s, on %s\n",
254: mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
255: #endif
256: return (0);
257:
258: bad:
259: if (um)
260: _FREE(um, M_UFSMNT);
261: if (cred != NOCRED)
262: crfree(cred);
263: if (upperrootvp)
264: vrele(upperrootvp);
265: if (lowerrootvp)
266: vrele(lowerrootvp);
267: return (error);
268: }
269:
270: /*
271: * VFS start. Nothing needed here - the start routine
272: * on the underlying filesystem(s) will have been called
273: * when that filesystem was mounted.
274: */
275: int
276: union_start(mp, flags, p)
277: struct mount *mp;
278: int flags;
279: struct proc *p;
280: {
281:
282: return (0);
283: }
284:
285: /*
286: * Free reference to union layer
287: */
288: int
289: union_unmount(mp, mntflags, p)
290: struct mount *mp;
291: int mntflags;
292: struct proc *p;
293: {
294: struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
295: struct vnode *um_rootvp;
296: int error;
297: int freeing;
298: int flags = 0;
299: struct ucred *cred;
300:
301: #ifdef UNION_DIAGNOSTIC
302: printf("union_unmount(mp = %x)\n", mp);
303: #endif
304:
305: if (mntflags & MNT_FORCE)
306: flags |= FORCECLOSE;
307:
308: if (error = union_root(mp, &um_rootvp))
309: return (error);
310:
311: /*
312: * Keep flushing vnodes from the mount list.
313: * This is needed because of the un_pvp held
314: * reference to the parent vnode.
315: * If more vnodes have been freed on a given pass,
316: * the try again. The loop will iterate at most
317: * (d) times, where (d) is the maximum tree depth
318: * in the filesystem.
319: */
320: for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
321: struct vnode *vp;
322: int n;
323:
324: /* count #vnodes held on mount list */
325: for (n = 0, vp = mp->mnt_vnodelist.lh_first;
326: vp != NULLVP;
327: vp = vp->v_mntvnodes.le_next)
328: n++;
329:
330: /* if this is unchanged then stop */
331: if (n == freeing)
332: break;
333:
334: /* otherwise try once more time */
335: freeing = n;
336: }
337:
338: /* At this point the root vnode should have a single reference */
339: if (um_rootvp->v_usecount > 1) {
340: vput(um_rootvp);
341: return (EBUSY);
342: }
343:
344: #ifdef UNION_DIAGNOSTIC
345: vprint("union root", um_rootvp);
346: #endif
347: /*
348: * Discard references to upper and lower target vnodes.
349: */
350: if (um->um_lowervp)
351: vrele(um->um_lowervp);
352: vrele(um->um_uppervp);
353: cred = um->um_cred;
354: if (cred != NOCRED) {
355: um->um_cred = NOCRED;
356: crfree(cred);
357: }
358: /*
359: * Release reference on underlying root vnode
360: */
361: vput(um_rootvp);
362: /*
363: * And blow it away for future re-use
364: */
365: vgone(um_rootvp);
366: /*
367: * Finally, throw away the union_mount structure
368: */
369: _FREE(mp->mnt_data, M_UFSMNT); /* XXX */
370: mp->mnt_data = 0;
371: return (0);
372: }
373:
374: int
375: union_root(mp, vpp)
376: struct mount *mp;
377: struct vnode **vpp;
378: {
379: struct proc *p = current_proc(); /* XXX */
380: struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
381: int error;
382: int loselock;
383:
384: /*
385: * Return locked reference to root.
386: */
387: VREF(um->um_uppervp);
388: if ((um->um_op == UNMNT_BELOW) &&
389: VOP_ISLOCKED(um->um_uppervp)) {
390: loselock = 1;
391: } else {
392: vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
393: loselock = 0;
394: }
395: if (um->um_lowervp)
396: VREF(um->um_lowervp);
397: error = union_allocvp(vpp, mp,
398: (struct vnode *) 0,
399: (struct vnode *) 0,
400: (struct componentname *) 0,
401: um->um_uppervp,
402: um->um_lowervp,
403: 1);
404:
405: if (error) {
406: if (loselock)
407: vrele(um->um_uppervp);
408: else
409: vput(um->um_uppervp);
410: if (um->um_lowervp)
411: vrele(um->um_lowervp);
412: } else {
413: if (loselock)
414: VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
415: }
416:
417: return (error);
418: }
419:
420: int
421: union_statfs(mp, sbp, p)
422: struct mount *mp;
423: struct statfs *sbp;
424: struct proc *p;
425: {
426: int error;
427: struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
428: struct statfs mstat;
429: int lbsize;
430:
431: #ifdef UNION_DIAGNOSTIC
432: printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
433: um->um_lowervp,
434: um->um_uppervp);
435: #endif
436:
437: bzero(&mstat, sizeof(mstat));
438:
439: if (um->um_lowervp) {
440: error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
441: if (error)
442: return (error);
443: }
444:
445: /* now copy across the "interesting" information and fake the rest */
446: #if 0
447: sbp->f_type = mstat.f_type;
448: sbp->f_flags = mstat.f_flags;
449: sbp->f_bsize = mstat.f_bsize;
450: sbp->f_iosize = mstat.f_iosize;
451: #endif
452: lbsize = mstat.f_bsize;
453: sbp->f_blocks = mstat.f_blocks;
454: sbp->f_bfree = mstat.f_bfree;
455: sbp->f_bavail = mstat.f_bavail;
456: sbp->f_files = mstat.f_files;
457: sbp->f_ffree = mstat.f_ffree;
458:
459: error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
460: if (error)
461: return (error);
462:
463: sbp->f_flags = mstat.f_flags;
464: sbp->f_bsize = mstat.f_bsize;
465: sbp->f_iosize = mstat.f_iosize;
466:
467: /*
468: * if the lower and upper blocksizes differ, then frig the
469: * block counts so that the sizes reported by df make some
470: * kind of sense. none of this makes sense though.
471: */
472:
473: if (mstat.f_bsize != lbsize)
474: sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
475:
476: /*
477: * The "total" fields count total resources in all layers,
478: * the "free" fields count only those resources which are
479: * free in the upper layer (since only the upper layer
480: * is writeable).
481: */
482: sbp->f_blocks += mstat.f_blocks;
483: sbp->f_bfree = mstat.f_bfree;
484: sbp->f_bavail = mstat.f_bavail;
485: sbp->f_files += mstat.f_files;
486: sbp->f_ffree = mstat.f_ffree;
487:
488: if (sbp != &mp->mnt_stat) {
489: sbp->f_type = mp->mnt_vfc->vfc_typenum;
490: bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
491: bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
492: bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
493: }
494: return (0);
495: }
496:
497: /*
498: * XXX - Assumes no data cached at union layer.
499: */
500: #define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \
501: struct proc *)))nullop)
502:
503: #define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \
504: struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
505: int union_init __P((struct vfsconf *));
506: #define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
507: struct proc *)))eopnotsupp)
508: #define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
509: size_t, struct proc *)))eopnotsupp)
510: #define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
511: eopnotsupp)
512: #define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
513:
514: struct vfsops union_vfsops = {
515: union_mount,
516: union_start,
517: union_unmount,
518: union_root,
519: union_quotactl,
520: union_statfs,
521: union_sync,
522: union_vget,
523: union_fhtovp,
524: union_vptofh,
525: union_init,
526: union_sysctl,
527: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.