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