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