|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23: /*
24: * Copyright (c) 1994 Jan-Simon Pendry
25: * Copyright (c) 1994
26: * The Regents of the University of California. All rights reserved.
27: *
28: * This code is derived from software contributed to Berkeley by
29: * Jan-Simon Pendry.
30: *
31: * Redistribution and use in source and binary forms, with or without
32: * modification, are permitted provided that the following conditions
33: * are met:
34: * 1. Redistributions of source code must retain the above copyright
35: * notice, this list of conditions and the following disclaimer.
36: * 2. Redistributions in binary form must reproduce the above copyright
37: * notice, this list of conditions and the following disclaimer in the
38: * documentation and/or other materials provided with the distribution.
39: * 3. All advertising materials mentioning features or use of this software
40: * must display the following acknowledgement:
41: * This product includes software developed by the University of
42: * California, Berkeley and its contributors.
43: * 4. Neither the name of the University nor the names of its contributors
44: * may be used to endorse or promote products derived from this software
45: * without specific prior written permission.
46: *
47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57: * SUCH DAMAGE.
58: *
59: * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
60: */
61:
62: #include <sys/param.h>
63: #include <sys/systm.h>
64: #include <sys/proc.h>
65: #include <sys/time.h>
66: #include <sys/kernel.h>
67: #include <sys/vnode.h>
68: #include <sys/namei.h>
69: #include <sys/malloc.h>
70: #include <sys/file.h>
71: #include <sys/filedesc.h>
72: #include <sys/queue.h>
73: #include <sys/mount.h>
74: #include <sys/stat.h>
75: #include <miscfs/union/union.h>
76:
77: #if DIAGNOSTIC
78: #include <sys/proc.h>
79: #endif
80:
81: /* must be power of two, otherwise change UNION_HASH() */
82: #define NHASH 32
83:
84: /* unsigned int ... */
85: #define UNION_HASH(u, l) \
86: (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
87:
88: static LIST_HEAD(unhead, union_node) unhead[NHASH];
89: static int unvplock[NHASH];
90:
91: int
92: union_init()
93: {
94: int i;
95:
96: for (i = 0; i < NHASH; i++)
97: LIST_INIT(&unhead[i]);
98: bzero((caddr_t) unvplock, sizeof(unvplock));
99: }
100:
101: static int
102: union_list_lock(ix)
103: int ix;
104: {
105:
106: if (unvplock[ix] & UN_LOCKED) {
107: unvplock[ix] |= UN_WANT;
108: sleep((caddr_t) &unvplock[ix], PINOD);
109: return (1);
110: }
111:
112: unvplock[ix] |= UN_LOCKED;
113:
114: return (0);
115: }
116:
117: static void
118: union_list_unlock(ix)
119: int ix;
120: {
121:
122: unvplock[ix] &= ~UN_LOCKED;
123:
124: if (unvplock[ix] & UN_WANT) {
125: unvplock[ix] &= ~UN_WANT;
126: wakeup((caddr_t) &unvplock[ix]);
127: }
128: }
129:
130: void
131: union_updatevp(un, uppervp, lowervp)
132: struct union_node *un;
133: struct vnode *uppervp;
134: struct vnode *lowervp;
135: {
136: int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
137: int nhash = UNION_HASH(uppervp, lowervp);
138: int docache = (lowervp != NULLVP || uppervp != NULLVP);
139: int lhash, hhash, uhash;
140:
141: /*
142: * Ensure locking is ordered from lower to higher
143: * to avoid deadlocks.
144: */
145: if (nhash < ohash) {
146: lhash = nhash;
147: uhash = ohash;
148: } else {
149: lhash = ohash;
150: uhash = nhash;
151: }
152:
153: if (lhash != uhash)
154: while (union_list_lock(lhash))
155: continue;
156:
157: while (union_list_lock(uhash))
158: continue;
159:
160: if (ohash != nhash || !docache) {
161: if (un->un_flags & UN_CACHED) {
162: un->un_flags &= ~UN_CACHED;
163: LIST_REMOVE(un, un_cache);
164: }
165: }
166:
167: if (ohash != nhash)
168: union_list_unlock(ohash);
169:
170: if (un->un_lowervp != lowervp) {
171: if (un->un_lowervp) {
172: vrele(un->un_lowervp);
173: if (un->un_path) {
174: _FREE(un->un_path, M_TEMP);
175: un->un_path = 0;
176: }
177: if (un->un_dirvp) {
178: vrele(un->un_dirvp);
179: un->un_dirvp = NULLVP;
180: }
181: }
182: un->un_lowervp = lowervp;
183: un->un_lowersz = VNOVAL;
184: }
185:
186: if (un->un_uppervp != uppervp) {
187: if (un->un_uppervp)
188: vrele(un->un_uppervp);
189:
190: un->un_uppervp = uppervp;
191: un->un_uppersz = VNOVAL;
192: }
193:
194: if (docache && (ohash != nhash)) {
195: LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
196: un->un_flags |= UN_CACHED;
197: }
198:
199: union_list_unlock(nhash);
200: }
201:
202: void
203: union_newlower(un, lowervp)
204: struct union_node *un;
205: struct vnode *lowervp;
206: {
207:
208: union_updatevp(un, un->un_uppervp, lowervp);
209: }
210:
211: void
212: union_newupper(un, uppervp)
213: struct union_node *un;
214: struct vnode *uppervp;
215: {
216:
217: union_updatevp(un, uppervp, un->un_lowervp);
218: }
219:
220: /*
221: * Keep track of size changes in the underlying vnodes.
222: * If the size changes, then callback to the vm layer
223: * giving priority to the upper layer size.
224: */
225: void
226: union_newsize(vp, uppersz, lowersz)
227: struct vnode *vp;
228: off_t uppersz, lowersz;
229: {
230: struct union_node *un;
231: off_t sz;
232:
233: /* only interested in regular files */
234: if (vp->v_type != VREG)
235: return;
236:
237: un = VTOUNION(vp);
238: sz = VNOVAL;
239:
240: if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) {
241: un->un_uppersz = uppersz;
242: if (sz == VNOVAL)
243: sz = un->un_uppersz;
244: }
245:
246: if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) {
247: un->un_lowersz = lowersz;
248: if (sz == VNOVAL)
249: sz = un->un_lowersz;
250: }
251:
252: if (sz != VNOVAL) {
253: #ifdef UNION_DIAGNOSTIC
254: printf("union: %s size now %ld\n",
255: uppersz != VNOVAL ? "upper" : "lower", (long) sz);
256: #endif
257: vnode_pager_setsize(vp, sz);
258: }
259: }
260:
261: /*
262: * allocate a union_node/vnode pair. the vnode is
263: * referenced and locked. the new vnode is returned
264: * via (vpp). (mp) is the mountpoint of the union filesystem,
265: * (dvp) is the parent directory where the upper layer object
266: * should exist (but doesn't) and (cnp) is the componentname
267: * information which is partially copied to allow the upper
268: * layer object to be created at a later time. (uppervp)
269: * and (lowervp) reference the upper and lower layer objects
270: * being mapped. either, but not both, can be nil.
271: * if supplied, (uppervp) is locked.
272: * the reference is either maintained in the new union_node
273: * object which is allocated, or they are vrele'd.
274: *
275: * all union_nodes are maintained on a singly-linked
276: * list. new nodes are only allocated when they cannot
277: * be found on this list. entries on the list are
278: * removed when the vfs reclaim entry is called.
279: *
280: * a single lock is kept for the entire list. this is
281: * needed because the getnewvnode() function can block
282: * waiting for a vnode to become free, in which case there
283: * may be more than one process trying to get the same
284: * vnode. this lock is only taken if we are going to
285: * call getnewvnode, since the kernel itself is single-threaded.
286: *
287: * if an entry is found on the list, then call vget() to
288: * take a reference. this is done because there may be
289: * zero references to it and so it needs to removed from
290: * the vnode free list.
291: */
292: int
293: union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache)
294: struct vnode **vpp;
295: struct mount *mp;
296: struct vnode *undvp; /* parent union vnode */
297: struct vnode *dvp; /* may be null */
298: struct componentname *cnp; /* may be null */
299: struct vnode *uppervp; /* may be null */
300: struct vnode *lowervp; /* may be null */
301: int docache;
302: {
303: int error;
304: struct union_node *un;
305: struct union_node **pp;
306: struct vnode *xlowervp = NULLVP;
307: struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
308: int hash;
309: int vflag;
310: int try;
311: struct union_node *unp;
312:
313: if (uppervp == NULLVP && lowervp == NULLVP)
314: panic("union: unidentifiable allocation");
315:
316: if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
317: xlowervp = lowervp;
318: lowervp = NULLVP;
319: }
320:
321: /* detect the root vnode (and aliases) */
322: vflag = 0;
323: if ((uppervp == um->um_uppervp) &&
324: ((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
325: if (lowervp == NULLVP) {
326: lowervp = um->um_lowervp;
327: if (lowervp != NULLVP)
328: VREF(lowervp);
329: }
330: vflag = VROOT;
331: }
332:
333: loop:
334: if (!docache) {
335: un = 0;
336: } else for (try = 0; try < 3; try++) {
337: switch (try) {
338: case 0:
339: if (lowervp == NULLVP)
340: continue;
341: hash = UNION_HASH(uppervp, lowervp);
342: break;
343:
344: case 1:
345: if (uppervp == NULLVP)
346: continue;
347: hash = UNION_HASH(uppervp, NULLVP);
348: break;
349:
350: case 2:
351: if (lowervp == NULLVP)
352: continue;
353: hash = UNION_HASH(NULLVP, lowervp);
354: break;
355: }
356:
357: while (union_list_lock(hash))
358: continue;
359:
360: for (un = unhead[hash].lh_first; un != 0;
361: un = un->un_cache.le_next) {
362: if ((un->un_lowervp == lowervp ||
363: un->un_lowervp == NULLVP) &&
364: (un->un_uppervp == uppervp ||
365: un->un_uppervp == NULLVP) &&
366: (UNIONTOV(un)->v_mount == mp)) {
367: if (vget(UNIONTOV(un), 0,
368: cnp ? cnp->cn_proc : NULL)) {
369: union_list_unlock(hash);
370: goto loop;
371: }
372: break;
373: }
374: }
375:
376: union_list_unlock(hash);
377:
378: if (un)
379: break;
380: }
381:
382: if (un) {
383: /*
384: * Obtain a lock on the union_node.
385: * uppervp is locked, though un->un_uppervp
386: * may not be. this doesn't break the locking
387: * hierarchy since in the case that un->un_uppervp
388: * is not yet locked it will be vrele'd and replaced
389: * with uppervp.
390: */
391:
392: if ((dvp != NULLVP) && (uppervp == dvp)) {
393: /*
394: * Access ``.'', so (un) will already
395: * be locked. Since this process has
396: * the lock on (uppervp) no other
397: * process can hold the lock on (un).
398: */
399: #if DIAGNOSTIC
400: if ((un->un_flags & UN_LOCKED) == 0)
401: panic("union: . not locked");
402: else if (current_proc() && un->un_pid != current_proc()->p_pid &&
403: un->un_pid > -1 && current_proc()->p_pid > -1)
404: panic("union: allocvp not lock owner");
405: #endif
406: } else {
407: if (un->un_flags & UN_LOCKED) {
408: vrele(UNIONTOV(un));
409: un->un_flags |= UN_WANT;
410: sleep((caddr_t) &un->un_flags, PINOD);
411: goto loop;
412: }
413: un->un_flags |= UN_LOCKED;
414:
415: #if DIAGNOSTIC
416: if (current_proc())
417: un->un_pid = current_proc()->p_pid;
418: else
419: un->un_pid = -1;
420: #endif
421: }
422:
423: /*
424: * At this point, the union_node is locked,
425: * un->un_uppervp may not be locked, and uppervp
426: * is locked or nil.
427: */
428:
429: /*
430: * Save information about the upper layer.
431: */
432: if (uppervp != un->un_uppervp) {
433: union_newupper(un, uppervp);
434: } else if (uppervp) {
435: vrele(uppervp);
436: }
437:
438: if (un->un_uppervp) {
439: un->un_flags |= UN_ULOCK;
440: un->un_flags &= ~UN_KLOCK;
441: }
442:
443: /*
444: * Save information about the lower layer.
445: * This needs to keep track of pathname
446: * and directory information which union_vn_create
447: * might need.
448: */
449: if (lowervp != un->un_lowervp) {
450: union_newlower(un, lowervp);
451: if (cnp && (lowervp != NULLVP)) {
452: un->un_hash = cnp->cn_hash;
453: MALLOC(un->un_path, caddr_t, cnp->cn_namelen+1,
454: M_TEMP, M_WAITOK);
455: bcopy(cnp->cn_nameptr, un->un_path,
456: cnp->cn_namelen);
457: un->un_path[cnp->cn_namelen] = '\0';
458: VREF(dvp);
459: un->un_dirvp = dvp;
460: }
461: } else if (lowervp) {
462: vrele(lowervp);
463: }
464: *vpp = UNIONTOV(un);
465: return (0);
466: }
467:
468: if (docache) {
469: /*
470: * otherwise lock the vp list while we call getnewvnode
471: * since that can block.
472: */
473: hash = UNION_HASH(uppervp, lowervp);
474:
475: if (union_list_lock(hash))
476: goto loop;
477: }
478:
479: MALLOC(unp, void *, sizeof(struct union_node), M_TEMP, M_WAITOK);
480: error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
481: if (error) {
482: FREE(unp, M_TEMP);
483: if (uppervp) {
484: if (dvp == uppervp)
485: vrele(uppervp);
486: else
487: vput(uppervp);
488: }
489: if (lowervp)
490: vrele(lowervp);
491:
492: goto out;
493: }
494:
495: (*vpp)->v_data = unp;
496: (*vpp)->v_flag |= vflag;
497: if (uppervp)
498: (*vpp)->v_type = uppervp->v_type;
499: else
500: (*vpp)->v_type = lowervp->v_type;
501: un = VTOUNION(*vpp);
502: un->un_vnode = *vpp;
503: un->un_uppervp = uppervp;
504: un->un_uppersz = VNOVAL;
505: un->un_lowervp = lowervp;
506: un->un_lowersz = VNOVAL;
507: un->un_pvp = undvp;
508: if (undvp != NULLVP)
509: VREF(undvp);
510: un->un_dircache = 0;
511: un->un_openl = 0;
512: un->un_flags = UN_LOCKED;
513: if (un->un_uppervp)
514: un->un_flags |= UN_ULOCK;
515: #if DIAGNOSTIC
516: if (current_proc())
517: un->un_pid = current_proc()->p_pid;
518: else
519: un->un_pid = -1;
520: #endif
521: if (cnp && (lowervp != NULLVP)) {
522: un->un_hash = cnp->cn_hash;
523: un->un_path = _MALLOC(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
524: bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
525: un->un_path[cnp->cn_namelen] = '\0';
526: VREF(dvp);
527: un->un_dirvp = dvp;
528: } else {
529: un->un_hash = 0;
530: un->un_path = 0;
531: un->un_dirvp = 0;
532: }
533:
534: if (docache) {
535: LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
536: un->un_flags |= UN_CACHED;
537: }
538:
539: if (xlowervp)
540: vrele(xlowervp);
541:
542: out:
543: if (docache)
544: union_list_unlock(hash);
545:
546: return (error);
547: }
548:
549: int
550: union_freevp(vp)
551: struct vnode *vp;
552: {
553: struct union_node *un = VTOUNION(vp);
554:
555: if (un->un_flags & UN_CACHED) {
556: un->un_flags &= ~UN_CACHED;
557: LIST_REMOVE(un, un_cache);
558: }
559:
560: if (un->un_pvp != NULLVP)
561: vrele(un->un_pvp);
562: if (un->un_uppervp != NULLVP)
563: vrele(un->un_uppervp);
564: if (un->un_lowervp != NULLVP)
565: vrele(un->un_lowervp);
566: if (un->un_dirvp != NULLVP)
567: vrele(un->un_dirvp);
568: if (un->un_path)
569: _FREE(un->un_path, M_TEMP);
570:
571: FREE(vp->v_data, M_TEMP);
572: vp->v_data = 0;
573:
574: return (0);
575: }
576:
577: /*
578: * copyfile. copy the vnode (fvp) to the vnode (tvp)
579: * using a sequence of reads and writes. both (fvp)
580: * and (tvp) are locked on entry and exit.
581: */
582: int
583: union_copyfile(fvp, tvp, cred, p)
584: struct vnode *fvp;
585: struct vnode *tvp;
586: struct ucred *cred;
587: struct proc *p;
588: {
589: char *buf;
590: struct uio uio;
591: struct iovec iov;
592: int error = 0;
593:
594: /*
595: * strategy:
596: * allocate a buffer of size MAXPHYSIO.
597: * loop doing reads and writes, keeping track
598: * of the current uio offset.
599: * give up at the first sign of trouble.
600: */
601:
602: uio.uio_procp = p;
603: uio.uio_segflg = UIO_SYSSPACE;
604: uio.uio_offset = 0;
605:
606: VOP_UNLOCK(fvp, 0, p); /* XXX */
607: VOP_LEASE(fvp, p, cred, LEASE_READ);
608: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
609: VOP_UNLOCK(tvp, 0, p); /* XXX */
610: VOP_LEASE(tvp, p, cred, LEASE_WRITE);
611: vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
612:
613: buf = _MALLOC(MAXPHYSIO, M_TEMP, M_WAITOK);
614:
615: /* ugly loop follows... */
616: do {
617: off_t offset = uio.uio_offset;
618:
619: uio.uio_iov = &iov;
620: uio.uio_iovcnt = 1;
621: iov.iov_base = buf;
622: iov.iov_len = MAXPHYSIO;
623: uio.uio_resid = iov.iov_len;
624: uio.uio_rw = UIO_READ;
625: error = VOP_READ(fvp, &uio, 0, cred);
626:
627: if (error == 0) {
628: uio.uio_iov = &iov;
629: uio.uio_iovcnt = 1;
630: iov.iov_base = buf;
631: iov.iov_len = MAXPHYSIO - uio.uio_resid;
632: uio.uio_offset = offset;
633: uio.uio_rw = UIO_WRITE;
634: uio.uio_resid = iov.iov_len;
635:
636: if (uio.uio_resid == 0)
637: break;
638:
639: do {
640: error = VOP_WRITE(tvp, &uio, 0, cred);
641: } while ((uio.uio_resid > 0) && (error == 0));
642: }
643:
644: } while (error == 0);
645:
646: _FREE(buf, M_TEMP);
647: return (error);
648: }
649:
650: /*
651: * (un) is assumed to be locked on entry and remains
652: * locked on exit.
653: */
654: int
655: union_copyup(un, docopy, cred, p)
656: struct union_node *un;
657: int docopy;
658: struct ucred *cred;
659: struct proc *p;
660: {
661: int error;
662: struct vnode *lvp, *uvp;
663:
664: error = union_vn_create(&uvp, un, p);
665: if (error)
666: return (error);
667:
668: /* at this point, uppervp is locked */
669: union_newupper(un, uvp);
670: un->un_flags |= UN_ULOCK;
671:
672: lvp = un->un_lowervp;
673:
674: if (docopy) {
675: /*
676: * XX - should not ignore errors
677: * from VOP_CLOSE
678: */
679: vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
680: error = VOP_OPEN(lvp, FREAD, cred, p);
681: if (error == 0) {
682: error = union_copyfile(lvp, uvp, cred, p);
683: VOP_UNLOCK(lvp, 0, p);
684: (void) VOP_CLOSE(lvp, FREAD, cred, p);
685: }
686: #ifdef UNION_DIAGNOSTIC
687: if (error == 0)
688: uprintf("union: copied up %s\n", un->un_path);
689: #endif
690:
691: }
692: un->un_flags &= ~UN_ULOCK;
693: VOP_UNLOCK(uvp, 0, p);
694: union_vn_close(uvp, FWRITE, cred, p);
695: vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p);
696: un->un_flags |= UN_ULOCK;
697:
698: /*
699: * Subsequent IOs will go to the top layer, so
700: * call close on the lower vnode and open on the
701: * upper vnode to ensure that the filesystem keeps
702: * its references counts right. This doesn't do
703: * the right thing with (cred) and (FREAD) though.
704: * Ignoring error returns is not right, either.
705: */
706: if (error == 0) {
707: int i;
708:
709: for (i = 0; i < un->un_openl; i++) {
710: (void) VOP_CLOSE(lvp, FREAD, cred, p);
711: (void) VOP_OPEN(uvp, FREAD, cred, p);
712: }
713: un->un_openl = 0;
714: }
715:
716: return (error);
717:
718: }
719:
720: static int
721: union_relookup(um, dvp, vpp, cnp, cn, path, pathlen)
722: struct union_mount *um;
723: struct vnode *dvp;
724: struct vnode **vpp;
725: struct componentname *cnp;
726: struct componentname *cn;
727: char *path;
728: int pathlen;
729: {
730: int error;
731:
732: /*
733: * A new componentname structure must be faked up because
734: * there is no way to know where the upper level cnp came
735: * from or what it is being used for. This must duplicate
736: * some of the work done by NDINIT, some of the work done
737: * by namei, some of the work done by lookup and some of
738: * the work done by VOP_LOOKUP when given a CREATE flag.
739: * Conclusion: Horrible.
740: *
741: * The pathname buffer will be FREEed by VOP_MKDIR.
742: */
743: cn->cn_namelen = pathlen;
744: cn->cn_pnbuf = _MALLOC_ZONE(cn->cn_namelen+1, M_NAMEI, M_WAITOK);
745: cn->cn_pnlen = cn->cn_namelen+1;
746: bcopy(path, cn->cn_pnbuf, cn->cn_namelen);
747: cn->cn_pnbuf[cn->cn_namelen] = '\0';
748:
749: cn->cn_nameiop = CREATE;
750: cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
751: cn->cn_proc = cnp->cn_proc;
752: if (um->um_op == UNMNT_ABOVE)
753: cn->cn_cred = cnp->cn_cred;
754: else
755: cn->cn_cred = um->um_cred;
756: cn->cn_nameptr = cn->cn_pnbuf;
757: cn->cn_hash = cnp->cn_hash;
758: cn->cn_consume = cnp->cn_consume;
759:
760: VREF(dvp);
761: error = relookup(dvp, vpp, cn);
762: if (!error)
763: vrele(dvp);
764:
765: return (error);
766: }
767:
768: /*
769: * Create a shadow directory in the upper layer.
770: * The new vnode is returned locked.
771: *
772: * (um) points to the union mount structure for access to the
773: * the mounting process's credentials.
774: * (dvp) is the directory in which to create the shadow directory.
775: * it is unlocked on entry and exit.
776: * (cnp) is the componentname to be created.
777: * (vpp) is the returned newly created shadow directory, which
778: * is returned locked.
779: */
780: int
781: union_mkshadow(um, dvp, cnp, vpp)
782: struct union_mount *um;
783: struct vnode *dvp;
784: struct componentname *cnp;
785: struct vnode **vpp;
786: {
787: int error;
788: struct vattr va;
789: struct proc *p = cnp->cn_proc;
790: struct componentname cn;
791:
792: error = union_relookup(um, dvp, vpp, cnp, &cn,
793: cnp->cn_nameptr, cnp->cn_namelen);
794: if (error)
795: return (error);
796:
797: if (*vpp) {
798: VOP_ABORTOP(dvp, &cn);
799: VOP_UNLOCK(dvp, 0, p);
800: vrele(*vpp);
801: *vpp = NULLVP;
802: return (EEXIST);
803: }
804:
805: /*
806: * policy: when creating the shadow directory in the
807: * upper layer, create it owned by the user who did
808: * the mount, group from parent directory, and mode
809: * 777 modified by umask (ie mostly identical to the
810: * mkdir syscall). (jsp, kb)
811: */
812:
813: VATTR_NULL(&va);
814: va.va_type = VDIR;
815: va.va_mode = um->um_cmode;
816:
817: /* VOP_LEASE: dvp is locked */
818: VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE);
819:
820: error = VOP_MKDIR(dvp, vpp, &cn, &va);
821: return (error);
822: }
823:
824: /*
825: * Create a whiteout entry in the upper layer.
826: *
827: * (um) points to the union mount structure for access to the
828: * the mounting process's credentials.
829: * (dvp) is the directory in which to create the whiteout.
830: * it is locked on entry and exit.
831: * (cnp) is the componentname to be created.
832: */
833: int
834: union_mkwhiteout(um, dvp, cnp, path)
835: struct union_mount *um;
836: struct vnode *dvp;
837: struct componentname *cnp;
838: char *path;
839: {
840: int error;
841: struct vattr va;
842: struct proc *p = cnp->cn_proc;
843: struct vnode *wvp;
844: struct componentname cn;
845:
846: VOP_UNLOCK(dvp, 0, p);
847: error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
848: if (error) {
849: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
850: return (error);
851: }
852:
853: if (wvp) {
854: VOP_ABORTOP(dvp, &cn);
855: vrele(dvp);
856: vrele(wvp);
857: return (EEXIST);
858: }
859:
860: /* VOP_LEASE: dvp is locked */
861: VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE);
862:
863: error = VOP_WHITEOUT(dvp, &cn, CREATE);
864: if (error)
865: VOP_ABORTOP(dvp, &cn);
866:
867: vrele(dvp);
868:
869: return (error);
870: }
871:
872: /*
873: * union_vn_create: creates and opens a new shadow file
874: * on the upper union layer. this function is similar
875: * in spirit to calling vn_open but it avoids calling namei().
876: * the problem with calling namei is that a) it locks too many
877: * things, and b) it doesn't start at the "right" directory,
878: * whereas relookup is told where to start.
879: */
880: int
881: union_vn_create(vpp, un, p)
882: struct vnode **vpp;
883: struct union_node *un;
884: struct proc *p;
885: {
886: struct vnode *vp;
887: struct ucred *cred = p->p_ucred;
888: struct vattr vat;
889: struct vattr *vap = &vat;
890: int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
891: int error;
892: int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
893: char *cp;
894: struct componentname cn;
895:
896: *vpp = NULLVP;
897:
898: /*
899: * Build a new componentname structure (for the same
900: * reasons outlines in union_mkshadow).
901: * The difference here is that the file is owned by
902: * the current user, rather than by the person who
903: * did the mount, since the current user needs to be
904: * able to write the file (that's why it is being
905: * copied in the first place).
906: */
907: cn.cn_namelen = strlen(un->un_path);
908: cn.cn_pnbuf = (caddr_t) _MALLOC_ZONE(cn.cn_namelen+1,
909: M_NAMEI, M_WAITOK);
910: cn.cn_pnlen = cn.cn_namelen+1;
911: bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
912: cn.cn_nameiop = CREATE;
913: cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
914: cn.cn_proc = p;
915: cn.cn_cred = p->p_ucred;
916: cn.cn_nameptr = cn.cn_pnbuf;
917: cn.cn_hash = un->un_hash;
918: cn.cn_consume = 0;
919:
920: VREF(un->un_dirvp);
921: if (error = relookup(un->un_dirvp, &vp, &cn))
922: return (error);
923: vrele(un->un_dirvp);
924:
925: if (vp) {
926: VOP_ABORTOP(un->un_dirvp, &cn);
927: if (un->un_dirvp == vp)
928: vrele(un->un_dirvp);
929: else
930: vput(un->un_dirvp);
931: vrele(vp);
932: return (EEXIST);
933: }
934:
935: /*
936: * Good - there was no race to create the file
937: * so go ahead and create it. The permissions
938: * on the file will be 0666 modified by the
939: * current user's umask. Access to the file, while
940: * it is unioned, will require access to the top *and*
941: * bottom files. Access when not unioned will simply
942: * require access to the top-level file.
943: * TODO: confirm choice of access permissions.
944: */
945: VATTR_NULL(vap);
946: vap->va_type = VREG;
947: vap->va_mode = cmode;
948: VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE);
949: if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap))
950: return (error);
951:
952: if (error = VOP_OPEN(vp, fmode, cred, p)) {
953: vput(vp);
954: return (error);
955: }
956:
957: if (++vp->v_writecount <= 0)
958: panic("union: v_writecount");
959: *vpp = vp;
960: return (0);
961: }
962:
963: int
964: union_vn_close(vp, fmode, cred, p)
965: struct vnode *vp;
966: int fmode;
967: struct ucred *cred;
968: struct proc *p;
969: {
970:
971: if (fmode & FWRITE)
972: --vp->v_writecount;
973: return (VOP_CLOSE(vp, fmode, cred, p));
974: }
975:
976: void
977: union_removed_upper(un)
978: struct union_node *un;
979: {
980: struct proc *p = current_proc(); /* XXX */
981:
982: union_newupper(un, NULLVP);
983: if (un->un_flags & UN_CACHED) {
984: un->un_flags &= ~UN_CACHED;
985: LIST_REMOVE(un, un_cache);
986: }
987:
988: if (un->un_flags & UN_ULOCK) {
989: un->un_flags &= ~UN_ULOCK;
990: VOP_UNLOCK(un->un_uppervp, 0, p);
991: }
992: }
993:
994: #if 0
995: struct vnode *
996: union_lowervp(vp)
997: struct vnode *vp;
998: {
999: struct union_node *un = VTOUNION(vp);
1000:
1001: if ((un->un_lowervp != NULLVP) &&
1002: (vp->v_type == un->un_lowervp->v_type)) {
1003: if (vget(un->un_lowervp, 0) == 0)
1004: return (un->un_lowervp);
1005: }
1006:
1007: return (NULLVP);
1008: }
1009: #endif
1010:
1011: /*
1012: * determine whether a whiteout is needed
1013: * during a remove/rmdir operation.
1014: */
1015: int
1016: union_dowhiteout(un, cred, p)
1017: struct union_node *un;
1018: struct ucred *cred;
1019: struct proc *p;
1020: {
1021: struct vattr va;
1022:
1023: if (un->un_lowervp != NULLVP)
1024: return (1);
1025:
1026: if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 &&
1027: (va.va_flags & OPAQUE))
1028: return (1);
1029:
1030: return (0);
1031: }
1032:
1033: static void
1034: union_dircache_r(vp, vppp, cntp)
1035: struct vnode *vp;
1036: struct vnode ***vppp;
1037: int *cntp;
1038: {
1039: struct union_node *un;
1040:
1041: if (vp->v_op != union_vnodeop_p) {
1042: if (vppp) {
1043: VREF(vp);
1044: *(*vppp)++ = vp;
1045: if (--(*cntp) == 0)
1046: panic("union: dircache table too small");
1047: } else {
1048: (*cntp)++;
1049: }
1050:
1051: return;
1052: }
1053:
1054: un = VTOUNION(vp);
1055: if (un->un_uppervp != NULLVP)
1056: union_dircache_r(un->un_uppervp, vppp, cntp);
1057: if (un->un_lowervp != NULLVP)
1058: union_dircache_r(un->un_lowervp, vppp, cntp);
1059: }
1060:
1061: struct vnode *
1062: union_dircache(vp, p)
1063: struct vnode *vp;
1064: struct proc *p;
1065: {
1066: int cnt;
1067: struct vnode *nvp;
1068: struct vnode **vpp;
1069: struct vnode **dircache;
1070: struct union_node *un;
1071: int error;
1072:
1073: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1074: dircache = VTOUNION(vp)->un_dircache;
1075:
1076: nvp = NULLVP;
1077:
1078: if (dircache == 0) {
1079: cnt = 0;
1080: union_dircache_r(vp, 0, &cnt);
1081: cnt++;
1082: dircache = (struct vnode **)
1083: _MALLOC(cnt * sizeof(struct vnode *),
1084: M_TEMP, M_WAITOK);
1085: vpp = dircache;
1086: union_dircache_r(vp, &vpp, &cnt);
1087: *vpp = NULLVP;
1088: vpp = dircache + 1;
1089: } else {
1090: vpp = dircache;
1091: do {
1092: if (*vpp++ == VTOUNION(vp)->un_uppervp)
1093: break;
1094: } while (*vpp != NULLVP);
1095: }
1096:
1097: if (*vpp == NULLVP)
1098: goto out;
1099:
1100: vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
1101: VREF(*vpp);
1102: error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0);
1103: if (error)
1104: goto out;
1105:
1106: VTOUNION(vp)->un_dircache = 0;
1107: un = VTOUNION(nvp);
1108: un->un_dircache = dircache;
1109:
1110: out:
1111: VOP_UNLOCK(vp, 0, p);
1112: return (nvp);
1113: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.