Commit | Line | Data |
---|---|---|
a1fa407d JSP |
1 | /* |
2 | * Copyright (c) 1992, 1993, 1994 The Regents of the University of California. | |
3 | * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
12abe7b1 | 7 | * Jan-Simon Pendry. |
a1fa407d JSP |
8 | * |
9 | * %sccs.include.redist.c% | |
10 | * | |
82abec62 | 11 | * @(#)union_vnops.c 8.1 (Berkeley) %G% |
a1fa407d JSP |
12 | */ |
13 | ||
14 | #include <sys/param.h> | |
15 | #include <sys/systm.h> | |
16 | #include <sys/proc.h> | |
17 | #include <sys/file.h> | |
a1fa407d JSP |
18 | #include <sys/time.h> |
19 | #include <sys/types.h> | |
20 | #include <sys/vnode.h> | |
21 | #include <sys/mount.h> | |
22 | #include <sys/namei.h> | |
23 | #include <sys/malloc.h> | |
24 | #include <sys/buf.h> | |
58572fc0 | 25 | #include <sys/queue.h> |
a1fa407d JSP |
26 | #include "union.h" |
27 | ||
a1fa407d | 28 | static int |
79f80c71 JSP |
29 | union_lookup1(udvp, dvp, vpp, cnp) |
30 | struct vnode *udvp; | |
a1fa407d JSP |
31 | struct vnode *dvp; |
32 | struct vnode **vpp; | |
33 | struct componentname *cnp; | |
34 | { | |
35 | int error; | |
36 | struct vnode *tdvp; | |
37 | struct mount *mp; | |
38 | ||
81be6ee0 JSP |
39 | /* |
40 | * If stepping up the directory tree, check for going | |
41 | * back across the mount point, in which case do what | |
42 | * lookup would do by stepping back down the mount | |
43 | * hierarchy. | |
44 | */ | |
a1fa407d JSP |
45 | if (cnp->cn_flags & ISDOTDOT) { |
46 | for (;;) { | |
692a90df JSP |
47 | /* |
48 | * Don't do the NOCROSSMOUNT check | |
49 | * at this level. By definition, | |
50 | * union fs deals with namespaces, not | |
51 | * filesystems. | |
52 | */ | |
53 | if ((dvp->v_flag & VROOT) == 0) | |
a1fa407d JSP |
54 | break; |
55 | ||
56 | tdvp = dvp; | |
57 | dvp = dvp->v_mount->mnt_vnodecovered; | |
58 | vput(tdvp); | |
59 | VREF(dvp); | |
60 | VOP_LOCK(dvp); | |
61 | } | |
62 | } | |
ed5969c8 | 63 | |
a1fa407d JSP |
64 | error = VOP_LOOKUP(dvp, &tdvp, cnp); |
65 | if (error) | |
66 | return (error); | |
67 | ||
81be6ee0 | 68 | /* |
ed5969c8 JSP |
69 | * The parent directory will have been unlocked, unless lookup |
70 | * found the last component. In which case, re-lock the node | |
71 | * here to allow it to be unlocked again (phew) in union_lookup. | |
81be6ee0 | 72 | */ |
ed5969c8 | 73 | if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) |
81be6ee0 JSP |
74 | VOP_LOCK(dvp); |
75 | ||
a1fa407d | 76 | dvp = tdvp; |
81be6ee0 JSP |
77 | |
78 | /* | |
79 | * Lastly check if the current node is a mount point in | |
692a90df | 80 | * which case walk up the mount hierarchy making sure not to |
81be6ee0 JSP |
81 | * bump into the root of the mount tree (ie. dvp != udvp). |
82 | */ | |
79f80c71 | 83 | while (dvp != udvp && (dvp->v_type == VDIR) && |
692a90df | 84 | (mp = dvp->v_mountedhere)) { |
a1fa407d JSP |
85 | |
86 | if (mp->mnt_flag & MNT_MLOCK) { | |
87 | mp->mnt_flag |= MNT_MWAIT; | |
88 | sleep((caddr_t) mp, PVFS); | |
89 | continue; | |
90 | } | |
91 | ||
92 | if (error = VFS_ROOT(mp, &tdvp)) { | |
93 | vput(dvp); | |
94 | return (error); | |
95 | } | |
96 | ||
01dac67e | 97 | vput(dvp); |
a1fa407d JSP |
98 | dvp = tdvp; |
99 | } | |
100 | ||
101 | *vpp = dvp; | |
102 | return (0); | |
103 | } | |
104 | ||
105 | int | |
106 | union_lookup(ap) | |
107 | struct vop_lookup_args /* { | |
108 | struct vnodeop_desc *a_desc; | |
109 | struct vnode *a_dvp; | |
110 | struct vnode **a_vpp; | |
111 | struct componentname *a_cnp; | |
112 | } */ *ap; | |
113 | { | |
01dac67e | 114 | int error; |
a1fa407d JSP |
115 | int uerror, lerror; |
116 | struct vnode *uppervp, *lowervp; | |
117 | struct vnode *upperdvp, *lowerdvp; | |
118 | struct vnode *dvp = ap->a_dvp; | |
79f80c71 | 119 | struct union_node *dun = VTOUNION(dvp); |
a1fa407d JSP |
120 | struct componentname *cnp = ap->a_cnp; |
121 | int lockparent = cnp->cn_flags & LOCKPARENT; | |
81be6ee0 | 122 | int rdonly = cnp->cn_flags & RDONLY; |
3b293975 | 123 | struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); |
a1fa407d | 124 | |
01dac67e JSP |
125 | cnp->cn_flags |= LOCKPARENT; |
126 | ||
a1fa407d JSP |
127 | upperdvp = dun->un_uppervp; |
128 | lowerdvp = dun->un_lowervp; | |
3b293975 JSP |
129 | uppervp = NULLVP; |
130 | lowervp = NULLVP; | |
a1fa407d JSP |
131 | |
132 | /* | |
133 | * do the lookup in the upper level. | |
134 | * if that level comsumes additional pathnames, | |
135 | * then assume that something special is going | |
136 | * on and just return that vnode. | |
137 | */ | |
a1fa407d | 138 | if (upperdvp) { |
3b293975 JSP |
139 | uerror = union_lookup1(um->um_uppervp, upperdvp, |
140 | &uppervp, cnp); | |
e2a2f3a7 JSP |
141 | /*if (uppervp == upperdvp) |
142 | dun->un_flags |= UN_KLOCK;*/ | |
01dac67e | 143 | |
a1fa407d JSP |
144 | if (cnp->cn_consume != 0) { |
145 | *ap->a_vpp = uppervp; | |
01dac67e JSP |
146 | if (!lockparent) |
147 | cnp->cn_flags &= ~LOCKPARENT; | |
a1fa407d JSP |
148 | return (uerror); |
149 | } | |
a1fa407d JSP |
150 | } else { |
151 | uerror = ENOENT; | |
152 | } | |
153 | ||
154 | /* | |
155 | * in a similar way to the upper layer, do the lookup | |
156 | * in the lower layer. this time, if there is some | |
157 | * component magic going on, then vput whatever we got | |
158 | * back from the upper layer and return the lower vnode | |
159 | * instead. | |
160 | */ | |
a1fa407d | 161 | if (lowerdvp) { |
e2a2f3a7 JSP |
162 | int nameiop; |
163 | ||
01dac67e | 164 | VOP_LOCK(lowerdvp); |
e2a2f3a7 JSP |
165 | |
166 | /* | |
167 | * Only do a LOOKUP on the bottom node, since | |
168 | * we won't be making changes to it anyway. | |
169 | */ | |
170 | nameiop = cnp->cn_nameiop; | |
171 | cnp->cn_nameiop = LOOKUP; | |
3b293975 | 172 | lerror = union_lookup1(um->um_lowervp, lowerdvp, |
e2a2f3a7 JSP |
173 | &lowervp, cnp); |
174 | cnp->cn_nameiop = nameiop; | |
175 | ||
79f80c71 JSP |
176 | if (lowervp != lowerdvp) |
177 | VOP_UNLOCK(lowerdvp); | |
01dac67e | 178 | |
a1fa407d JSP |
179 | if (cnp->cn_consume != 0) { |
180 | if (uppervp) { | |
e2a2f3a7 JSP |
181 | if (uppervp == upperdvp) |
182 | vrele(uppervp); | |
183 | else | |
184 | vput(uppervp); | |
3b293975 | 185 | uppervp = NULLVP; |
a1fa407d JSP |
186 | } |
187 | *ap->a_vpp = lowervp; | |
01dac67e JSP |
188 | if (!lockparent) |
189 | cnp->cn_flags &= ~LOCKPARENT; | |
a1fa407d JSP |
190 | return (lerror); |
191 | } | |
a1fa407d JSP |
192 | } else { |
193 | lerror = ENOENT; | |
194 | } | |
195 | ||
01dac67e JSP |
196 | if (!lockparent) |
197 | cnp->cn_flags &= ~LOCKPARENT; | |
198 | ||
a1fa407d JSP |
199 | /* |
200 | * at this point, we have uerror and lerror indicating | |
201 | * possible errors with the lookups in the upper and lower | |
202 | * layers. additionally, uppervp and lowervp are (locked) | |
203 | * references to existing vnodes in the upper and lower layers. | |
204 | * | |
205 | * there are now three cases to consider. | |
206 | * 1. if both layers returned an error, then return whatever | |
207 | * error the upper layer generated. | |
208 | * | |
209 | * 2. if the top layer failed and the bottom layer succeeded | |
210 | * then two subcases occur. | |
211 | * a. the bottom vnode is not a directory, in which | |
212 | * case just return a new union vnode referencing | |
213 | * an empty top layer and the existing bottom layer. | |
214 | * b. the bottom vnode is a directory, in which case | |
215 | * create a new directory in the top-level and | |
216 | * continue as in case 3. | |
217 | * | |
218 | * 3. if the top layer succeeded then return a new union | |
219 | * vnode referencing whatever the new top layer and | |
220 | * whatever the bottom layer returned. | |
221 | */ | |
222 | ||
ed5969c8 JSP |
223 | *ap->a_vpp = NULLVP; |
224 | ||
a1fa407d JSP |
225 | /* case 1. */ |
226 | if ((uerror != 0) && (lerror != 0)) { | |
a1fa407d JSP |
227 | return (uerror); |
228 | } | |
229 | ||
230 | /* case 2. */ | |
231 | if (uerror != 0 /* && (lerror == 0) */ ) { | |
232 | if (lowervp->v_type == VDIR) { /* case 2b. */ | |
e2a2f3a7 JSP |
233 | dun->un_flags &= ~UN_ULOCK; |
234 | VOP_UNLOCK(upperdvp); | |
3b293975 | 235 | uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); |
e2a2f3a7 JSP |
236 | VOP_LOCK(upperdvp); |
237 | dun->un_flags |= UN_ULOCK; | |
238 | ||
a1fa407d JSP |
239 | if (uerror) { |
240 | if (lowervp) { | |
241 | vput(lowervp); | |
3b293975 | 242 | lowervp = NULLVP; |
a1fa407d JSP |
243 | } |
244 | return (uerror); | |
245 | } | |
246 | } | |
247 | } | |
248 | ||
01dac67e JSP |
249 | if (lowervp) |
250 | VOP_UNLOCK(lowervp); | |
251 | ||
3b293975 JSP |
252 | error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, |
253 | uppervp, lowervp); | |
254 | ||
01dac67e JSP |
255 | if (error) { |
256 | if (uppervp) | |
e2a2f3a7 | 257 | vput(uppervp); |
01dac67e JSP |
258 | if (lowervp) |
259 | vrele(lowervp); | |
260 | } else { | |
81be6ee0 JSP |
261 | if (*ap->a_vpp != dvp) |
262 | if (!lockparent || !(cnp->cn_flags & ISLASTCN)) | |
263 | VOP_UNLOCK(dvp); | |
01dac67e JSP |
264 | } |
265 | ||
266 | return (error); | |
a1fa407d JSP |
267 | } |
268 | ||
12abe7b1 JSP |
269 | int |
270 | union_create(ap) | |
271 | struct vop_create_args /* { | |
272 | struct vnode *a_dvp; | |
273 | struct vnode **a_vpp; | |
274 | struct componentname *a_cnp; | |
275 | struct vattr *a_vap; | |
276 | } */ *ap; | |
277 | { | |
278 | struct union_node *un = VTOUNION(ap->a_dvp); | |
279 | struct vnode *dvp = un->un_uppervp; | |
280 | ||
281 | if (dvp) { | |
282 | int error; | |
283 | struct vnode *vp; | |
12abe7b1 JSP |
284 | |
285 | VREF(dvp); | |
e2a2f3a7 | 286 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
287 | vput(ap->a_dvp); |
288 | error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); | |
289 | if (error) | |
290 | return (error); | |
291 | ||
292 | error = union_allocvp( | |
293 | ap->a_vpp, | |
79f80c71 JSP |
294 | ap->a_dvp->v_mount, |
295 | ap->a_dvp, | |
01dac67e | 296 | NULLVP, |
12abe7b1 JSP |
297 | ap->a_cnp, |
298 | vp, | |
299 | NULLVP); | |
01dac67e | 300 | if (error) |
e2a2f3a7 | 301 | vput(vp); |
12abe7b1 JSP |
302 | return (error); |
303 | } | |
304 | ||
305 | vput(ap->a_dvp); | |
306 | return (EROFS); | |
307 | } | |
308 | ||
309 | int | |
310 | union_mknod(ap) | |
311 | struct vop_mknod_args /* { | |
312 | struct vnode *a_dvp; | |
313 | struct vnode **a_vpp; | |
314 | struct componentname *a_cnp; | |
315 | struct vattr *a_vap; | |
316 | } */ *ap; | |
317 | { | |
318 | struct union_node *un = VTOUNION(ap->a_dvp); | |
319 | struct vnode *dvp = un->un_uppervp; | |
320 | ||
321 | if (dvp) { | |
322 | int error; | |
323 | struct vnode *vp; | |
12abe7b1 JSP |
324 | |
325 | VREF(dvp); | |
e2a2f3a7 | 326 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
327 | vput(ap->a_dvp); |
328 | error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); | |
329 | if (error) | |
330 | return (error); | |
331 | ||
01dac67e JSP |
332 | if (vp) { |
333 | error = union_allocvp( | |
334 | ap->a_vpp, | |
79f80c71 JSP |
335 | ap->a_dvp->v_mount, |
336 | ap->a_dvp, | |
01dac67e JSP |
337 | NULLVP, |
338 | ap->a_cnp, | |
339 | vp, | |
340 | NULLVP); | |
01dac67e | 341 | if (error) |
e2a2f3a7 | 342 | vput(vp); |
01dac67e | 343 | } |
12abe7b1 JSP |
344 | return (error); |
345 | } | |
346 | ||
347 | vput(ap->a_dvp); | |
348 | return (EROFS); | |
349 | } | |
350 | ||
a1fa407d JSP |
351 | int |
352 | union_open(ap) | |
353 | struct vop_open_args /* { | |
354 | struct vnodeop_desc *a_desc; | |
355 | struct vnode *a_vp; | |
356 | int a_mode; | |
357 | struct ucred *a_cred; | |
358 | struct proc *a_p; | |
359 | } */ *ap; | |
360 | { | |
361 | struct union_node *un = VTOUNION(ap->a_vp); | |
01dac67e | 362 | struct vnode *tvp; |
a1fa407d JSP |
363 | int mode = ap->a_mode; |
364 | struct ucred *cred = ap->a_cred; | |
365 | struct proc *p = ap->a_p; | |
01dac67e | 366 | int error; |
a1fa407d JSP |
367 | |
368 | /* | |
369 | * If there is an existing upper vp then simply open that. | |
370 | */ | |
01dac67e JSP |
371 | tvp = un->un_uppervp; |
372 | if (tvp == NULLVP) { | |
a1fa407d | 373 | /* |
01dac67e JSP |
374 | * If the lower vnode is being opened for writing, then |
375 | * copy the file contents to the upper vnode and open that, | |
376 | * otherwise can simply open the lower vnode. | |
a1fa407d | 377 | */ |
01dac67e JSP |
378 | tvp = un->un_lowervp; |
379 | if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { | |
81be6ee0 | 380 | struct vnode *vp; |
3b293975 | 381 | int i; |
01dac67e JSP |
382 | |
383 | /* | |
384 | * Open the named file in the upper layer. Note that | |
385 | * the file may have come into existence *since* the | |
386 | * lookup was done, since the upper layer may really | |
387 | * be a loopback mount of some other filesystem... | |
388 | * so open the file with exclusive create and barf if | |
389 | * it already exists. | |
ed5969c8 | 390 | * XXX - perhaps should re-lookup the node (once more |
01dac67e JSP |
391 | * with feeling) and simply open that. Who knows. |
392 | */ | |
3b293975 | 393 | error = union_vn_create(&vp, un, p); |
01dac67e JSP |
394 | if (error) |
395 | return (error); | |
e2a2f3a7 | 396 | |
01dac67e | 397 | /* at this point, uppervp is locked */ |
58572fc0 | 398 | union_newupper(un, vp); |
e2a2f3a7 | 399 | un->un_flags |= UN_ULOCK; |
01dac67e JSP |
400 | |
401 | /* | |
402 | * Now, if the file is being opened with truncation, | |
403 | * then the (new) upper vnode is ready to fly, | |
404 | * otherwise the data from the lower vnode must be | |
405 | * copied to the upper layer first. This only works | |
406 | * for regular files (check is made above). | |
407 | */ | |
408 | if ((mode & O_TRUNC) == 0) { | |
409 | /* | |
410 | * XXX - should not ignore errors | |
411 | * from VOP_CLOSE | |
412 | */ | |
81be6ee0 | 413 | VOP_LOCK(tvp); |
01dac67e JSP |
414 | error = VOP_OPEN(tvp, FREAD, cred, p); |
415 | if (error == 0) { | |
416 | error = union_copyfile(p, cred, | |
417 | tvp, un->un_uppervp); | |
418 | VOP_UNLOCK(tvp); | |
419 | (void) VOP_CLOSE(tvp, FREAD); | |
420 | } else { | |
421 | VOP_UNLOCK(tvp); | |
422 | } | |
e2a2f3a7 JSP |
423 | |
424 | un->un_flags &= ~UN_ULOCK; | |
01dac67e | 425 | VOP_UNLOCK(un->un_uppervp); |
15a86f7e | 426 | union_vn_close(un->un_uppervp, FWRITE, cred, p); |
01dac67e | 427 | VOP_LOCK(un->un_uppervp); |
e2a2f3a7 JSP |
428 | un->un_flags |= UN_ULOCK; |
429 | ||
3b293975 | 430 | if (!error) |
ed5969c8 | 431 | uprintf("union: copied up %s\n", |
3b293975 JSP |
432 | un->un_path); |
433 | } | |
434 | ||
435 | /* | |
436 | * Subsequent IOs will go to the top layer, so | |
437 | * call close on the lower vnode and open on the | |
438 | * upper vnode to ensure that the filesystem keeps | |
439 | * its references counts right. This doesn't do | |
440 | * the right thing with (cred) and (FREAD) though. | |
441 | * Ignoring error returns is not righ, either. | |
442 | */ | |
ed5969c8 | 443 | for (i = 0; i < un->un_openl; i++) { |
3b293975 JSP |
444 | (void) VOP_CLOSE(tvp, FREAD); |
445 | (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p); | |
a1fa407d | 446 | } |
ed5969c8 | 447 | un->un_openl = 0; |
3b293975 | 448 | |
01dac67e JSP |
449 | if (error == 0) |
450 | error = VOP_OPEN(un->un_uppervp, mode, cred, p); | |
01dac67e | 451 | return (error); |
a1fa407d | 452 | } |
e2a2f3a7 JSP |
453 | |
454 | /* | |
455 | * Just open the lower vnode | |
456 | */ | |
ed5969c8 | 457 | un->un_openl++; |
e2a2f3a7 JSP |
458 | VOP_LOCK(tvp); |
459 | error = VOP_OPEN(tvp, mode, cred, p); | |
460 | VOP_UNLOCK(tvp); | |
461 | ||
462 | return (error); | |
a1fa407d JSP |
463 | } |
464 | ||
01dac67e | 465 | error = VOP_OPEN(tvp, mode, cred, p); |
01dac67e JSP |
466 | |
467 | return (error); | |
a1fa407d JSP |
468 | } |
469 | ||
12abe7b1 JSP |
470 | int |
471 | union_close(ap) | |
472 | struct vop_close_args /* { | |
473 | struct vnode *a_vp; | |
474 | int a_fflag; | |
475 | struct ucred *a_cred; | |
476 | struct proc *a_p; | |
477 | } */ *ap; | |
478 | { | |
3b293975 JSP |
479 | struct union_node *un = VTOUNION(ap->a_vp); |
480 | struct vnode *vp; | |
12abe7b1 | 481 | |
3b293975 JSP |
482 | if (un->un_uppervp) { |
483 | vp = un->un_uppervp; | |
484 | } else { | |
ed5969c8 JSP |
485 | #ifdef UNION_DIAGNOSTIC |
486 | if (un->un_openl <= 0) | |
487 | panic("union: un_openl cnt"); | |
3b293975 | 488 | #endif |
ed5969c8 | 489 | --un->un_openl; |
3b293975 JSP |
490 | vp = un->un_lowervp; |
491 | } | |
ed5969c8 | 492 | |
3b293975 | 493 | return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p)); |
12abe7b1 JSP |
494 | } |
495 | ||
496 | /* | |
497 | * Check access permission on the union vnode. | |
498 | * The access check being enforced is to check | |
499 | * against both the underlying vnode, and any | |
500 | * copied vnode. This ensures that no additional | |
501 | * file permissions are given away simply because | |
502 | * the user caused an implicit file copy. | |
503 | */ | |
504 | int | |
505 | union_access(ap) | |
506 | struct vop_access_args /* { | |
507 | struct vnodeop_desc *a_desc; | |
508 | struct vnode *a_vp; | |
509 | int a_mode; | |
510 | struct ucred *a_cred; | |
511 | struct proc *a_p; | |
512 | } */ *ap; | |
513 | { | |
514 | struct union_node *un = VTOUNION(ap->a_vp); | |
01dac67e | 515 | int error = 0; |
12abe7b1 JSP |
516 | struct vnode *vp; |
517 | ||
518 | if (vp = un->un_lowervp) { | |
01dac67e | 519 | VOP_LOCK(vp); |
12abe7b1 | 520 | error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); |
01dac67e | 521 | VOP_UNLOCK(vp); |
12abe7b1 JSP |
522 | if (error) |
523 | return (error); | |
524 | } | |
525 | ||
e2a2f3a7 | 526 | if (vp = un->un_uppervp) |
01dac67e | 527 | error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); |
01dac67e JSP |
528 | |
529 | return (error); | |
12abe7b1 JSP |
530 | } |
531 | ||
a1fa407d JSP |
532 | /* |
533 | * We handle getattr only to change the fsid. | |
534 | */ | |
535 | int | |
536 | union_getattr(ap) | |
537 | struct vop_getattr_args /* { | |
538 | struct vnode *a_vp; | |
539 | struct vattr *a_vap; | |
540 | struct ucred *a_cred; | |
541 | struct proc *a_p; | |
542 | } */ *ap; | |
543 | { | |
544 | int error; | |
01dac67e | 545 | struct vnode *vp = OTHERVP(ap->a_vp); |
e2a2f3a7 | 546 | int dolock = (vp == LOWERVP(ap->a_vp)); |
01dac67e | 547 | |
e2a2f3a7 JSP |
548 | if (dolock) |
549 | VOP_LOCK(vp); | |
01dac67e | 550 | error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p); |
e2a2f3a7 JSP |
551 | if (dolock) |
552 | VOP_UNLOCK(vp); | |
a1fa407d | 553 | |
a1fa407d JSP |
554 | /* Requires that arguments be restored. */ |
555 | ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; | |
556 | return (0); | |
557 | } | |
558 | ||
a1fa407d | 559 | int |
01dac67e | 560 | union_setattr(ap) |
12abe7b1 | 561 | struct vop_setattr_args /* { |
a1fa407d | 562 | struct vnode *a_vp; |
12abe7b1 | 563 | struct vattr *a_vap; |
a1fa407d | 564 | struct ucred *a_cred; |
12abe7b1 | 565 | struct proc *a_p; |
a1fa407d JSP |
566 | } */ *ap; |
567 | { | |
568 | struct union_node *un = VTOUNION(ap->a_vp); | |
12abe7b1 | 569 | int error; |
a1fa407d | 570 | |
12abe7b1 | 571 | if (un->un_uppervp) { |
12abe7b1 JSP |
572 | error = VOP_SETATTR(un->un_uppervp, ap->a_vap, |
573 | ap->a_cred, ap->a_p); | |
12abe7b1 JSP |
574 | } else { |
575 | /* | |
576 | * XXX should do a copyfile (perhaps only if | |
577 | * the file permission change, which would not | |
578 | * track va_ctime correctly). | |
579 | */ | |
580 | error = EROFS; | |
581 | } | |
a1fa407d | 582 | |
12abe7b1 | 583 | return (error); |
a1fa407d JSP |
584 | } |
585 | ||
586 | int | |
12abe7b1 JSP |
587 | union_read(ap) |
588 | struct vop_read_args /* { | |
a1fa407d | 589 | struct vnode *a_vp; |
12abe7b1 JSP |
590 | struct uio *a_uio; |
591 | int a_ioflag; | |
592 | struct ucred *a_cred; | |
a1fa407d JSP |
593 | } */ *ap; |
594 | { | |
12abe7b1 JSP |
595 | int error; |
596 | struct vnode *vp = OTHERVP(ap->a_vp); | |
e2a2f3a7 | 597 | int dolock = (vp == LOWERVP(ap->a_vp)); |
a1fa407d | 598 | |
e2a2f3a7 JSP |
599 | if (dolock) |
600 | VOP_LOCK(vp); | |
12abe7b1 | 601 | error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); |
e2a2f3a7 JSP |
602 | if (dolock) |
603 | VOP_UNLOCK(vp); | |
12abe7b1 JSP |
604 | |
605 | return (error); | |
a1fa407d JSP |
606 | } |
607 | ||
608 | int | |
12abe7b1 JSP |
609 | union_write(ap) |
610 | struct vop_read_args /* { | |
a1fa407d | 611 | struct vnode *a_vp; |
12abe7b1 JSP |
612 | struct uio *a_uio; |
613 | int a_ioflag; | |
614 | struct ucred *a_cred; | |
a1fa407d JSP |
615 | } */ *ap; |
616 | { | |
12abe7b1 JSP |
617 | int error; |
618 | struct vnode *vp = OTHERVP(ap->a_vp); | |
e2a2f3a7 | 619 | int dolock = (vp == LOWERVP(ap->a_vp)); |
a1fa407d | 620 | |
e2a2f3a7 JSP |
621 | if (dolock) |
622 | VOP_LOCK(vp); | |
12abe7b1 | 623 | error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); |
e2a2f3a7 JSP |
624 | if (dolock) |
625 | VOP_UNLOCK(vp); | |
a1fa407d | 626 | |
12abe7b1 JSP |
627 | return (error); |
628 | } | |
a1fa407d JSP |
629 | |
630 | int | |
12abe7b1 JSP |
631 | union_ioctl(ap) |
632 | struct vop_ioctl_args /* { | |
a1fa407d | 633 | struct vnode *a_vp; |
12abe7b1 JSP |
634 | int a_command; |
635 | caddr_t a_data; | |
636 | int a_fflag; | |
637 | struct ucred *a_cred; | |
638 | struct proc *a_p; | |
a1fa407d JSP |
639 | } */ *ap; |
640 | { | |
a1fa407d | 641 | |
12abe7b1 JSP |
642 | return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, |
643 | ap->a_fflag, ap->a_cred, ap->a_p)); | |
a1fa407d JSP |
644 | } |
645 | ||
a1fa407d | 646 | int |
12abe7b1 JSP |
647 | union_select(ap) |
648 | struct vop_select_args /* { | |
649 | struct vnode *a_vp; | |
650 | int a_which; | |
651 | int a_fflags; | |
652 | struct ucred *a_cred; | |
653 | struct proc *a_p; | |
654 | } */ *ap; | |
655 | { | |
656 | ||
657 | return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, | |
658 | ap->a_cred, ap->a_p)); | |
659 | } | |
660 | ||
661 | int | |
662 | union_mmap(ap) | |
663 | struct vop_mmap_args /* { | |
664 | struct vnode *a_vp; | |
665 | int a_fflags; | |
666 | struct ucred *a_cred; | |
667 | struct proc *a_p; | |
668 | } */ *ap; | |
669 | { | |
670 | ||
671 | return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, | |
672 | ap->a_cred, ap->a_p)); | |
673 | } | |
674 | ||
675 | int | |
676 | union_fsync(ap) | |
677 | struct vop_fsync_args /* { | |
678 | struct vnode *a_vp; | |
679 | struct ucred *a_cred; | |
680 | int a_waitfor; | |
681 | struct proc *a_p; | |
682 | } */ *ap; | |
683 | { | |
684 | int error = 0; | |
685 | struct vnode *targetvp = OTHERVP(ap->a_vp); | |
686 | ||
687 | if (targetvp) { | |
e2a2f3a7 JSP |
688 | int dolock = (targetvp == LOWERVP(ap->a_vp)); |
689 | ||
690 | if (dolock) | |
691 | VOP_LOCK(targetvp); | |
12abe7b1 JSP |
692 | error = VOP_FSYNC(targetvp, ap->a_cred, |
693 | ap->a_waitfor, ap->a_p); | |
e2a2f3a7 JSP |
694 | if (dolock) |
695 | VOP_UNLOCK(targetvp); | |
12abe7b1 JSP |
696 | } |
697 | ||
698 | return (error); | |
699 | } | |
700 | ||
701 | int | |
702 | union_seek(ap) | |
703 | struct vop_seek_args /* { | |
704 | struct vnode *a_vp; | |
705 | off_t a_oldoff; | |
706 | off_t a_newoff; | |
707 | struct ucred *a_cred; | |
708 | } */ *ap; | |
709 | { | |
710 | ||
711 | return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); | |
712 | } | |
713 | ||
714 | int | |
715 | union_remove(ap) | |
716 | struct vop_remove_args /* { | |
717 | struct vnode *a_dvp; | |
718 | struct vnode *a_vp; | |
719 | struct componentname *a_cnp; | |
a1fa407d JSP |
720 | } */ *ap; |
721 | { | |
a1fa407d | 722 | int error; |
12abe7b1 JSP |
723 | struct union_node *dun = VTOUNION(ap->a_dvp); |
724 | struct union_node *un = VTOUNION(ap->a_vp); | |
a1fa407d | 725 | |
12abe7b1 JSP |
726 | if (dun->un_uppervp && un->un_uppervp) { |
727 | struct vnode *dvp = dun->un_uppervp; | |
728 | struct vnode *vp = un->un_uppervp; | |
a1fa407d | 729 | |
12abe7b1 | 730 | VREF(dvp); |
e2a2f3a7 | 731 | dun->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
732 | vput(ap->a_dvp); |
733 | VREF(vp); | |
e2a2f3a7 | 734 | un->un_flags |= UN_KLOCK; |
12abe7b1 | 735 | vput(ap->a_vp); |
a1fa407d | 736 | |
12abe7b1 | 737 | error = VOP_REMOVE(dvp, vp, ap->a_cnp); |
ed5969c8 JSP |
738 | if (!error) |
739 | union_removed_upper(un); | |
740 | ||
741 | /* | |
742 | * XXX: should create a whiteout here | |
743 | */ | |
12abe7b1 JSP |
744 | } else { |
745 | /* | |
746 | * XXX: should create a whiteout here | |
747 | */ | |
748 | vput(ap->a_dvp); | |
749 | vput(ap->a_vp); | |
750 | error = EROFS; | |
751 | } | |
752 | ||
753 | return (error); | |
754 | } | |
755 | ||
756 | int | |
757 | union_link(ap) | |
758 | struct vop_link_args /* { | |
759 | struct vnode *a_vp; | |
760 | struct vnode *a_tdvp; | |
761 | struct componentname *a_cnp; | |
762 | } */ *ap; | |
763 | { | |
764 | int error; | |
765 | struct union_node *dun = VTOUNION(ap->a_vp); | |
766 | struct union_node *un = VTOUNION(ap->a_tdvp); | |
767 | ||
768 | if (dun->un_uppervp && un->un_uppervp) { | |
769 | struct vnode *dvp = dun->un_uppervp; | |
770 | struct vnode *vp = un->un_uppervp; | |
771 | ||
772 | VREF(dvp); | |
e2a2f3a7 | 773 | dun->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
774 | vput(ap->a_vp); |
775 | VREF(vp); | |
776 | vrele(ap->a_tdvp); | |
777 | ||
778 | error = VOP_LINK(dvp, vp, ap->a_cnp); | |
779 | } else { | |
780 | /* | |
781 | * XXX: need to copy to upper layer | |
782 | * and do the link there. | |
783 | */ | |
784 | vput(ap->a_vp); | |
785 | vrele(ap->a_tdvp); | |
786 | error = EROFS; | |
787 | } | |
a1fa407d JSP |
788 | |
789 | return (error); | |
790 | } | |
791 | ||
12abe7b1 JSP |
792 | int |
793 | union_rename(ap) | |
794 | struct vop_rename_args /* { | |
795 | struct vnode *a_fdvp; | |
796 | struct vnode *a_fvp; | |
797 | struct componentname *a_fcnp; | |
798 | struct vnode *a_tdvp; | |
799 | struct vnode *a_tvp; | |
800 | struct componentname *a_tcnp; | |
801 | } */ *ap; | |
802 | { | |
803 | int error; | |
804 | ||
805 | struct vnode *fdvp = ap->a_fdvp; | |
806 | struct vnode *fvp = ap->a_fvp; | |
807 | struct vnode *tdvp = ap->a_tdvp; | |
808 | struct vnode *tvp = ap->a_tvp; | |
809 | ||
810 | if (fdvp->v_op == union_vnodeop_p) { /* always true */ | |
811 | struct union_node *un = VTOUNION(fdvp); | |
3b293975 | 812 | if (un->un_uppervp == NULLVP) { |
12abe7b1 JSP |
813 | error = EROFS; |
814 | goto bad; | |
815 | } | |
816 | ||
817 | fdvp = un->un_uppervp; | |
818 | VREF(fdvp); | |
819 | vrele(ap->a_fdvp); | |
820 | } | |
821 | ||
822 | if (fvp->v_op == union_vnodeop_p) { /* always true */ | |
823 | struct union_node *un = VTOUNION(fvp); | |
3b293975 | 824 | if (un->un_uppervp == NULLVP) { |
12abe7b1 JSP |
825 | error = EROFS; |
826 | goto bad; | |
827 | } | |
828 | ||
829 | fvp = un->un_uppervp; | |
830 | VREF(fvp); | |
831 | vrele(ap->a_fvp); | |
832 | } | |
833 | ||
834 | if (tdvp->v_op == union_vnodeop_p) { | |
835 | struct union_node *un = VTOUNION(tdvp); | |
3b293975 | 836 | if (un->un_uppervp == NULLVP) { |
12abe7b1 JSP |
837 | error = EROFS; |
838 | goto bad; | |
839 | } | |
840 | ||
841 | tdvp = un->un_uppervp; | |
842 | VREF(tdvp); | |
e2a2f3a7 | 843 | un->un_flags |= UN_KLOCK; |
3b293975 | 844 | vput(ap->a_tdvp); |
12abe7b1 JSP |
845 | } |
846 | ||
847 | if (tvp && tvp->v_op == union_vnodeop_p) { | |
848 | struct union_node *un = VTOUNION(tvp); | |
3b293975 | 849 | if (un->un_uppervp == NULLVP) { |
12abe7b1 JSP |
850 | error = EROFS; |
851 | goto bad; | |
852 | } | |
853 | ||
854 | tvp = un->un_uppervp; | |
855 | VREF(tvp); | |
e2a2f3a7 | 856 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
857 | vput(ap->a_tvp); |
858 | } | |
859 | ||
860 | return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); | |
861 | ||
862 | bad: | |
863 | vrele(fdvp); | |
864 | vrele(fvp); | |
865 | vput(tdvp); | |
866 | if (tvp) | |
867 | vput(tvp); | |
868 | ||
869 | return (error); | |
870 | } | |
871 | ||
872 | int | |
873 | union_mkdir(ap) | |
874 | struct vop_mkdir_args /* { | |
875 | struct vnode *a_dvp; | |
876 | struct vnode **a_vpp; | |
877 | struct componentname *a_cnp; | |
878 | struct vattr *a_vap; | |
879 | } */ *ap; | |
880 | { | |
881 | struct union_node *un = VTOUNION(ap->a_dvp); | |
882 | struct vnode *dvp = un->un_uppervp; | |
883 | ||
884 | if (dvp) { | |
885 | int error; | |
886 | struct vnode *vp; | |
12abe7b1 JSP |
887 | |
888 | VREF(dvp); | |
e2a2f3a7 | 889 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
890 | vput(ap->a_dvp); |
891 | error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); | |
892 | if (error) | |
893 | return (error); | |
894 | ||
895 | error = union_allocvp( | |
896 | ap->a_vpp, | |
79f80c71 JSP |
897 | ap->a_dvp->v_mount, |
898 | ap->a_dvp, | |
01dac67e | 899 | NULLVP, |
12abe7b1 JSP |
900 | ap->a_cnp, |
901 | vp, | |
902 | NULLVP); | |
01dac67e | 903 | if (error) |
e2a2f3a7 | 904 | vput(vp); |
12abe7b1 JSP |
905 | return (error); |
906 | } | |
907 | ||
908 | vput(ap->a_dvp); | |
909 | return (EROFS); | |
910 | } | |
911 | ||
912 | int | |
913 | union_rmdir(ap) | |
914 | struct vop_rmdir_args /* { | |
915 | struct vnode *a_dvp; | |
916 | struct vnode *a_vp; | |
917 | struct componentname *a_cnp; | |
918 | } */ *ap; | |
919 | { | |
920 | int error; | |
921 | struct union_node *dun = VTOUNION(ap->a_dvp); | |
922 | struct union_node *un = VTOUNION(ap->a_vp); | |
923 | ||
924 | if (dun->un_uppervp && un->un_uppervp) { | |
925 | struct vnode *dvp = dun->un_uppervp; | |
926 | struct vnode *vp = un->un_uppervp; | |
927 | ||
928 | VREF(dvp); | |
e2a2f3a7 | 929 | dun->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
930 | vput(ap->a_dvp); |
931 | VREF(vp); | |
e2a2f3a7 | 932 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
933 | vput(ap->a_vp); |
934 | ||
e2a2f3a7 | 935 | error = VOP_RMDIR(dvp, vp, ap->a_cnp); |
ed5969c8 JSP |
936 | if (!error) |
937 | union_removed_upper(un); | |
938 | ||
939 | /* | |
940 | * XXX: should create a whiteout here | |
941 | */ | |
12abe7b1 JSP |
942 | } else { |
943 | /* | |
944 | * XXX: should create a whiteout here | |
945 | */ | |
946 | vput(ap->a_dvp); | |
947 | vput(ap->a_vp); | |
948 | error = EROFS; | |
949 | } | |
950 | ||
951 | return (error); | |
952 | } | |
953 | ||
954 | int | |
955 | union_symlink(ap) | |
956 | struct vop_symlink_args /* { | |
957 | struct vnode *a_dvp; | |
958 | struct vnode **a_vpp; | |
959 | struct componentname *a_cnp; | |
960 | struct vattr *a_vap; | |
961 | char *a_target; | |
962 | } */ *ap; | |
963 | { | |
964 | struct union_node *un = VTOUNION(ap->a_dvp); | |
965 | struct vnode *dvp = un->un_uppervp; | |
966 | ||
967 | if (dvp) { | |
968 | int error; | |
969 | struct vnode *vp; | |
970 | struct mount *mp = ap->a_dvp->v_mount; | |
971 | ||
972 | VREF(dvp); | |
e2a2f3a7 | 973 | un->un_flags |= UN_KLOCK; |
12abe7b1 JSP |
974 | vput(ap->a_dvp); |
975 | error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, | |
976 | ap->a_vap, ap->a_target); | |
3b293975 | 977 | *ap->a_vpp = NULLVP; |
12abe7b1 JSP |
978 | return (error); |
979 | } | |
980 | ||
981 | vput(ap->a_dvp); | |
982 | return (EROFS); | |
983 | } | |
a1fa407d JSP |
984 | |
985 | /* | |
12abe7b1 JSP |
986 | * union_readdir works in concert with getdirentries and |
987 | * readdir(3) to provide a list of entries in the unioned | |
988 | * directories. getdirentries is responsible for walking | |
989 | * down the union stack. readdir(3) is responsible for | |
990 | * eliminating duplicate names from the returned data stream. | |
a1fa407d JSP |
991 | */ |
992 | int | |
12abe7b1 JSP |
993 | union_readdir(ap) |
994 | struct vop_readdir_args /* { | |
995 | struct vnodeop_desc *a_desc; | |
996 | struct vnode *a_vp; | |
997 | struct uio *a_uio; | |
998 | struct ucred *a_cred; | |
999 | } */ *ap; | |
1000 | { | |
1001 | int error = 0; | |
1002 | struct union_node *un = VTOUNION(ap->a_vp); | |
1003 | ||
e2a2f3a7 JSP |
1004 | if (un->un_uppervp) |
1005 | error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred); | |
12abe7b1 JSP |
1006 | |
1007 | return (error); | |
1008 | } | |
1009 | ||
1010 | int | |
1011 | union_readlink(ap) | |
1012 | struct vop_readlink_args /* { | |
1013 | struct vnode *a_vp; | |
1014 | struct uio *a_uio; | |
1015 | struct ucred *a_cred; | |
a1fa407d JSP |
1016 | } */ *ap; |
1017 | { | |
a1fa407d | 1018 | int error; |
12abe7b1 | 1019 | struct vnode *vp = OTHERVP(ap->a_vp); |
e2a2f3a7 | 1020 | int dolock = (vp == LOWERVP(ap->a_vp)); |
a1fa407d | 1021 | |
e2a2f3a7 JSP |
1022 | if (dolock) |
1023 | VOP_LOCK(vp); | |
12abe7b1 | 1024 | error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); |
e2a2f3a7 JSP |
1025 | if (dolock) |
1026 | VOP_UNLOCK(vp); | |
a1fa407d | 1027 | |
12abe7b1 JSP |
1028 | return (error); |
1029 | } | |
a1fa407d | 1030 | |
12abe7b1 JSP |
1031 | int |
1032 | union_abortop(ap) | |
1033 | struct vop_abortop_args /* { | |
1034 | struct vnode *a_dvp; | |
1035 | struct componentname *a_cnp; | |
1036 | } */ *ap; | |
1037 | { | |
1038 | int error; | |
01dac67e | 1039 | struct vnode *vp = OTHERVP(ap->a_dvp); |
12abe7b1 JSP |
1040 | struct union_node *un = VTOUNION(ap->a_dvp); |
1041 | int islocked = un->un_flags & UN_LOCKED; | |
e2a2f3a7 | 1042 | int dolock = (vp == LOWERVP(ap->a_dvp)); |
a1fa407d | 1043 | |
e2a2f3a7 | 1044 | if (islocked && dolock) |
12abe7b1 JSP |
1045 | VOP_LOCK(vp); |
1046 | error = VOP_ABORTOP(vp, ap->a_cnp); | |
e2a2f3a7 | 1047 | if (islocked && dolock) |
12abe7b1 | 1048 | VOP_UNLOCK(vp); |
a1fa407d JSP |
1049 | |
1050 | return (error); | |
1051 | } | |
1052 | ||
12abe7b1 JSP |
1053 | int |
1054 | union_inactive(ap) | |
1055 | struct vop_inactive_args /* { | |
1056 | struct vnode *a_vp; | |
1057 | } */ *ap; | |
1058 | { | |
1059 | ||
1060 | /* | |
1061 | * Do nothing (and _don't_ bypass). | |
1062 | * Wait to vrele lowervp until reclaim, | |
1063 | * so that until then our union_node is in the | |
1064 | * cache and reusable. | |
1065 | * | |
1066 | * NEEDSWORK: Someday, consider inactive'ing | |
1067 | * the lowervp and then trying to reactivate it | |
1068 | * with capabilities (v_id) | |
1069 | * like they do in the name lookup cache code. | |
1070 | * That's too much work for now. | |
1071 | */ | |
79f80c71 | 1072 | |
ed5969c8 | 1073 | #ifdef UNION_DIAGNOSTIC |
79f80c71 JSP |
1074 | struct union_node *un = VTOUNION(ap->a_vp); |
1075 | ||
1076 | if (un->un_flags & UN_LOCKED) | |
1077 | panic("union: inactivating locked node"); | |
1078 | #endif | |
1079 | ||
12abe7b1 JSP |
1080 | return (0); |
1081 | } | |
1082 | ||
1083 | int | |
1084 | union_reclaim(ap) | |
1085 | struct vop_reclaim_args /* { | |
1086 | struct vnode *a_vp; | |
1087 | } */ *ap; | |
1088 | { | |
12abe7b1 | 1089 | |
58572fc0 JSP |
1090 | union_freevp(ap->a_vp); |
1091 | ||
12abe7b1 JSP |
1092 | return (0); |
1093 | } | |
1094 | ||
a1fa407d JSP |
1095 | int |
1096 | union_lock(ap) | |
1097 | struct vop_lock_args *ap; | |
1098 | { | |
1099 | struct union_node *un = VTOUNION(ap->a_vp); | |
1100 | ||
e2a2f3a7 JSP |
1101 | if (un->un_uppervp) { |
1102 | if ((un->un_flags & UN_ULOCK) == 0) { | |
1103 | VOP_LOCK(un->un_uppervp); | |
1104 | un->un_flags |= UN_ULOCK; | |
1105 | } | |
1106 | #ifdef DIAGNOSTIC | |
1107 | if (un->un_flags & UN_KLOCK) | |
1108 | panic("union: dangling upper lock"); | |
1109 | #endif | |
1110 | } | |
1111 | ||
01dac67e | 1112 | while (un->un_flags & UN_LOCKED) { |
a1fa407d | 1113 | #ifdef DIAGNOSTIC |
79f80c71 JSP |
1114 | if (curproc && un->un_pid == curproc->p_pid && |
1115 | un->un_pid > -1 && curproc->p_pid > -1) | |
1116 | panic("union: locking against myself"); | |
a1fa407d | 1117 | #endif |
a1fa407d JSP |
1118 | un->un_flags |= UN_WANT; |
1119 | sleep((caddr_t) &un->un_flags, PINOD); | |
1120 | } | |
1121 | un->un_flags |= UN_LOCKED; | |
79f80c71 | 1122 | |
a1fa407d | 1123 | #ifdef DIAGNOSTIC |
79f80c71 JSP |
1124 | if (curproc) |
1125 | un->un_pid = curproc->p_pid; | |
1126 | else | |
1127 | un->un_pid = -1; | |
a1fa407d | 1128 | #endif |
15a86f7e JSP |
1129 | |
1130 | return (0); | |
a1fa407d JSP |
1131 | } |
1132 | ||
1133 | int | |
1134 | union_unlock(ap) | |
1135 | struct vop_lock_args *ap; | |
1136 | { | |
1137 | struct union_node *un = VTOUNION(ap->a_vp); | |
1138 | ||
1139 | #ifdef DIAGNOSTIC | |
a1fa407d JSP |
1140 | if ((un->un_flags & UN_LOCKED) == 0) |
1141 | panic("union: unlock unlocked node"); | |
79f80c71 JSP |
1142 | if (curproc && un->un_pid != curproc->p_pid && |
1143 | curproc->p_pid > -1 && un->un_pid > -1) | |
01dac67e | 1144 | panic("union: unlocking other process's union node"); |
a1fa407d JSP |
1145 | #endif |
1146 | ||
a1fa407d | 1147 | un->un_flags &= ~UN_LOCKED; |
e2a2f3a7 JSP |
1148 | |
1149 | if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) | |
1150 | VOP_UNLOCK(un->un_uppervp); | |
1151 | ||
1152 | un->un_flags &= ~(UN_ULOCK|UN_KLOCK); | |
1153 | ||
a1fa407d JSP |
1154 | if (un->un_flags & UN_WANT) { |
1155 | un->un_flags &= ~UN_WANT; | |
1156 | wakeup((caddr_t) &un->un_flags); | |
1157 | } | |
1158 | ||
1159 | #ifdef DIAGNOSTIC | |
1160 | un->un_pid = 0; | |
1161 | #endif | |
15a86f7e JSP |
1162 | |
1163 | return (0); | |
a1fa407d JSP |
1164 | } |
1165 | ||
12abe7b1 JSP |
1166 | int |
1167 | union_bmap(ap) | |
1168 | struct vop_bmap_args /* { | |
1169 | struct vnode *a_vp; | |
1170 | daddr_t a_bn; | |
1171 | struct vnode **a_vpp; | |
1172 | daddr_t *a_bnp; | |
1173 | int *a_runp; | |
1174 | } */ *ap; | |
1175 | { | |
1176 | int error; | |
1177 | struct vnode *vp = OTHERVP(ap->a_vp); | |
e2a2f3a7 | 1178 | int dolock = (vp == LOWERVP(ap->a_vp)); |
12abe7b1 | 1179 | |
e2a2f3a7 JSP |
1180 | if (dolock) |
1181 | VOP_LOCK(vp); | |
12abe7b1 | 1182 | error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); |
e2a2f3a7 JSP |
1183 | if (dolock) |
1184 | VOP_UNLOCK(vp); | |
12abe7b1 JSP |
1185 | |
1186 | return (error); | |
1187 | } | |
1188 | ||
1189 | int | |
1190 | union_print(ap) | |
1191 | struct vop_print_args /* { | |
1192 | struct vnode *a_vp; | |
1193 | } */ *ap; | |
1194 | { | |
1195 | struct vnode *vp = ap->a_vp; | |
1196 | ||
1197 | printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n", | |
1198 | vp, UPPERVP(vp), LOWERVP(vp)); | |
1199 | return (0); | |
1200 | } | |
1201 | ||
1202 | int | |
1203 | union_islocked(ap) | |
1204 | struct vop_islocked_args /* { | |
1205 | struct vnode *a_vp; | |
1206 | } */ *ap; | |
1207 | { | |
1208 | ||
1209 | return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); | |
1210 | } | |
1211 | ||
1212 | int | |
1213 | union_pathconf(ap) | |
1214 | struct vop_pathconf_args /* { | |
1215 | struct vnode *a_vp; | |
1216 | int a_name; | |
1217 | int *a_retval; | |
1218 | } */ *ap; | |
1219 | { | |
1220 | int error; | |
1221 | struct vnode *vp = OTHERVP(ap->a_vp); | |
e2a2f3a7 | 1222 | int dolock = (vp == LOWERVP(ap->a_vp)); |
12abe7b1 | 1223 | |
e2a2f3a7 JSP |
1224 | if (dolock) |
1225 | VOP_LOCK(vp); | |
12abe7b1 | 1226 | error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); |
e2a2f3a7 JSP |
1227 | if (dolock) |
1228 | VOP_UNLOCK(vp); | |
12abe7b1 JSP |
1229 | |
1230 | return (error); | |
1231 | } | |
1232 | ||
1233 | int | |
1234 | union_advlock(ap) | |
1235 | struct vop_advlock_args /* { | |
1236 | struct vnode *a_vp; | |
1237 | caddr_t a_id; | |
1238 | int a_op; | |
1239 | struct flock *a_fl; | |
1240 | int a_flags; | |
1241 | } */ *ap; | |
1242 | { | |
1243 | ||
1244 | return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, | |
1245 | ap->a_fl, ap->a_flags)); | |
1246 | } | |
1247 | ||
1248 | ||
a1fa407d | 1249 | /* |
12abe7b1 JSP |
1250 | * XXX - vop_strategy must be hand coded because it has no |
1251 | * vnode in its arguments. | |
1252 | * This goes away with a merged VM/buffer cache. | |
a1fa407d | 1253 | */ |
12abe7b1 JSP |
1254 | int |
1255 | union_strategy(ap) | |
1256 | struct vop_strategy_args /* { | |
1257 | struct buf *a_bp; | |
1258 | } */ *ap; | |
1259 | { | |
1260 | struct buf *bp = ap->a_bp; | |
1261 | int error; | |
1262 | struct vnode *savedvp; | |
1263 | ||
1264 | savedvp = bp->b_vp; | |
1265 | bp->b_vp = OTHERVP(bp->b_vp); | |
a1fa407d | 1266 | |
12abe7b1 | 1267 | #ifdef DIAGNOSTIC |
3b293975 | 1268 | if (bp->b_vp == NULLVP) |
12abe7b1 JSP |
1269 | panic("union_strategy: nil vp"); |
1270 | if (((bp->b_flags & B_READ) == 0) && | |
1271 | (bp->b_vp == LOWERVP(savedvp))) | |
1272 | panic("union_strategy: writing to lowervp"); | |
1273 | #endif | |
a1fa407d | 1274 | |
12abe7b1 JSP |
1275 | error = VOP_STRATEGY(bp); |
1276 | bp->b_vp = savedvp; | |
a1fa407d | 1277 | |
12abe7b1 JSP |
1278 | return (error); |
1279 | } | |
a1fa407d | 1280 | |
12abe7b1 JSP |
1281 | /* |
1282 | * Global vfs data structures | |
1283 | */ | |
1284 | int (**union_vnodeop_p)(); | |
01dac67e | 1285 | struct vnodeopv_entry_desc union_vnodeop_entries[] = { |
12abe7b1 JSP |
1286 | { &vop_default_desc, vn_default_error }, |
1287 | { &vop_lookup_desc, union_lookup }, /* lookup */ | |
1288 | { &vop_create_desc, union_create }, /* create */ | |
1289 | { &vop_mknod_desc, union_mknod }, /* mknod */ | |
1290 | { &vop_open_desc, union_open }, /* open */ | |
1291 | { &vop_close_desc, union_close }, /* close */ | |
1292 | { &vop_access_desc, union_access }, /* access */ | |
1293 | { &vop_getattr_desc, union_getattr }, /* getattr */ | |
1294 | { &vop_setattr_desc, union_setattr }, /* setattr */ | |
1295 | { &vop_read_desc, union_read }, /* read */ | |
1296 | { &vop_write_desc, union_write }, /* write */ | |
1297 | { &vop_ioctl_desc, union_ioctl }, /* ioctl */ | |
1298 | { &vop_select_desc, union_select }, /* select */ | |
1299 | { &vop_mmap_desc, union_mmap }, /* mmap */ | |
1300 | { &vop_fsync_desc, union_fsync }, /* fsync */ | |
1301 | { &vop_seek_desc, union_seek }, /* seek */ | |
1302 | { &vop_remove_desc, union_remove }, /* remove */ | |
1303 | { &vop_link_desc, union_link }, /* link */ | |
1304 | { &vop_rename_desc, union_rename }, /* rename */ | |
1305 | { &vop_mkdir_desc, union_mkdir }, /* mkdir */ | |
1306 | { &vop_rmdir_desc, union_rmdir }, /* rmdir */ | |
1307 | { &vop_symlink_desc, union_symlink }, /* symlink */ | |
1308 | { &vop_readdir_desc, union_readdir }, /* readdir */ | |
1309 | { &vop_readlink_desc, union_readlink }, /* readlink */ | |
1310 | { &vop_abortop_desc, union_abortop }, /* abortop */ | |
1311 | { &vop_inactive_desc, union_inactive }, /* inactive */ | |
1312 | { &vop_reclaim_desc, union_reclaim }, /* reclaim */ | |
1313 | { &vop_lock_desc, union_lock }, /* lock */ | |
1314 | { &vop_unlock_desc, union_unlock }, /* unlock */ | |
1315 | { &vop_bmap_desc, union_bmap }, /* bmap */ | |
1316 | { &vop_strategy_desc, union_strategy }, /* strategy */ | |
1317 | { &vop_print_desc, union_print }, /* print */ | |
1318 | { &vop_islocked_desc, union_islocked }, /* islocked */ | |
1319 | { &vop_pathconf_desc, union_pathconf }, /* pathconf */ | |
1320 | { &vop_advlock_desc, union_advlock }, /* advlock */ | |
1321 | #ifdef notdef | |
1322 | { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ | |
1323 | { &vop_valloc_desc, union_valloc }, /* valloc */ | |
1324 | { &vop_vfree_desc, union_vfree }, /* vfree */ | |
1325 | { &vop_truncate_desc, union_truncate }, /* truncate */ | |
1326 | { &vop_update_desc, union_update }, /* update */ | |
1327 | { &vop_bwrite_desc, union_bwrite }, /* bwrite */ | |
1328 | #endif | |
a1fa407d JSP |
1329 | { (struct vnodeop_desc*)NULL, (int(*)())NULL } |
1330 | }; | |
1331 | struct vnodeopv_desc union_vnodeop_opv_desc = | |
1332 | { &union_vnodeop_p, union_vnodeop_entries }; |