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