unionfs_subr.c revision 1.4 1 /*-
2 * Copyright (c) 1994 Jan-Simon Pendry
3 * Copyright (c) 1994
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa (at) ongs.co.jp>, ONGS Inc.
6 * Copyright (c) 2006 Daichi Goto <daichi (at) freebsd.org>
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
36 * $FreeBSD: src/sys/fs/unionfs/union_subr.c,v 1.99 2008/01/24 12:34:27 attilio Exp $
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/namei.h>
47 #include <sys/proc.h>
48 #include <sys/vnode.h>
49 #include <sys/dirent.h>
50 #include <sys/fcntl.h>
51 #include <sys/filedesc.h>
52 #include <sys/stat.h>
53 #include <sys/kauth.h>
54 #include <sys/resourcevar.h>
55
56 #include <fs/unionfs/unionfs.h>
57
58 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
59
60 /*
61 * Make a new or get existing unionfs node.
62 *
63 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
64 * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
65 * you should not lock plurality simultaneously.
66 */
67 int
68 unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
69 struct vnode *lowervp, struct vnode *dvp,
70 struct vnode **vpp, struct componentname *cnp)
71 {
72 struct unionfs_mount *ump;
73 struct unionfs_node *unp;
74 struct vnode *vp;
75 int error;
76 const char *path;
77
78 ump = MOUNTTOUNIONFSMOUNT(mp);
79 path = (cnp ? cnp->cn_nameptr : NULL);
80
81 if (uppervp == NULLVP && lowervp == NULLVP)
82 panic("unionfs_nodeget: upper and lower is null");
83
84 /* If it has no ISLASTCN flag, path check is skipped. */
85 if (cnp && !(cnp->cn_flags & ISLASTCN))
86 path = NULL;
87
88 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
89 (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
90 if (dvp == NULLVP)
91 return (EINVAL);
92 }
93
94 unp = kmem_zalloc(sizeof(*unp), KM_SLEEP);
95 if (unp == NULL)
96 return (ENOMEM);
97 error = getnewvnode(VT_UNION, mp, unionfs_vnodeop_p, &vp);
98 if (error != 0) {
99 kmem_free(unp, sizeof(*unp));
100 return (error);
101 }
102 if (dvp != NULLVP)
103 vref(dvp);
104 if (uppervp != NULLVP)
105 vref(uppervp);
106 if (lowervp != NULLVP)
107 vref(lowervp);
108
109 unp->un_vnode = vp;
110 unp->un_uppervp = uppervp;
111 unp->un_lowervp = lowervp;
112 unp->un_dvp = dvp;
113 if (uppervp != NULLVP)
114 vp->v_vnlock = uppervp->v_vnlock;
115 else
116 vp->v_vnlock = lowervp->v_vnlock;
117
118 if (path != NULL) {
119 unp->un_path = (char *)
120 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
121 memcpy(unp->un_path, cnp->cn_nameptr, cnp->cn_namelen);
122 unp->un_path[cnp->cn_namelen] = '\0';
123 }
124 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
125 vp->v_data = unp;
126 uvm_vnp_setsize(vp, 0);
127
128 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
129 (lowervp != NULLVP && ump->um_lowervp == lowervp))
130 vp->v_vflag |= VV_ROOT;
131
132 *vpp = vp;
133
134 return (0);
135 }
136
137 /*
138 * Clean up the unionfs node.
139 */
140 void
141 unionfs_noderem(struct vnode *vp)
142 {
143 struct unionfs_mount *ump;
144 struct unionfs_node *unp;
145 struct unionfs_node_status *unsp;
146 struct vnode *lvp;
147 struct vnode *uvp;
148
149 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount);
150
151 /*
152 * Use the interlock to protect the clearing of v_data to
153 * prevent faults in unionfs_lock().
154 */
155 unp = VTOUNIONFS(vp);
156 lvp = unp->un_lowervp;
157 uvp = unp->un_uppervp;
158 unp->un_lowervp = unp->un_uppervp = NULLVP;
159 vp->v_vnlock = &(vp->v_lock);
160 vp->v_data = NULL;
161
162 if (lvp != NULLVP)
163 vrele(lvp);
164 if (uvp != NULLVP)
165 vrele(uvp);
166 if (unp->un_dvp != NULLVP) {
167 vrele(unp->un_dvp);
168 unp->un_dvp = NULLVP;
169 }
170 if (unp->un_path) {
171 free(unp->un_path, M_UNIONFSPATH);
172 unp->un_path = NULL;
173 }
174
175 while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) {
176 LIST_REMOVE(unsp, uns_list);
177 free(unsp, M_TEMP);
178 }
179 kmem_free(unp, sizeof(*unp));
180 }
181
182 /*
183 * Get the unionfs node status.
184 * You need exclusive lock this vnode.
185 */
186 void
187 unionfs_get_node_status(struct unionfs_node *unp,
188 struct unionfs_node_status **unspp)
189 {
190 struct unionfs_node_status *unsp;
191 pid_t pid;
192 lwpid_t lid;
193
194 KASSERT(NULL != unspp);
195 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
196
197 pid = curproc->p_pid;
198 lid = curlwp->l_lid;
199
200 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
201 if (unsp->uns_pid == pid && unsp->uns_lid == lid) {
202 *unspp = unsp;
203 return;
204 }
205 }
206
207 /* create a new unionfs node status */
208 unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP);
209 unsp->uns_pid = pid;
210 unsp->uns_lid = lid;
211 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
212
213 *unspp = unsp;
214 }
215
216 /*
217 * Remove the unionfs node status, if you can.
218 * You need exclusive lock this vnode.
219 */
220 void
221 unionfs_tryrem_node_status(struct unionfs_node *unp,
222 struct unionfs_node_status *unsp)
223 {
224 KASSERT(NULL != unsp);
225 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
226
227 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
228 return;
229
230 LIST_REMOVE(unsp, uns_list);
231 kmem_free(unsp, sizeof(*unsp));
232 }
233
234 /*
235 * Create upper node attr.
236 */
237 void
238 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
239 struct vattr *lva,
240 struct vattr *uva)
241 {
242 VATTR_NULL(uva);
243 uva->va_type = lva->va_type;
244 uva->va_atime = lva->va_atime;
245 uva->va_mtime = lva->va_mtime;
246 uva->va_ctime = lva->va_ctime;
247
248 switch (ump->um_copymode) {
249 case UNIONFS_TRANSPARENT:
250 uva->va_mode = lva->va_mode;
251 uva->va_uid = lva->va_uid;
252 uva->va_gid = lva->va_gid;
253 break;
254 case UNIONFS_MASQUERADE:
255 if (ump->um_uid == lva->va_uid) {
256 uva->va_mode = lva->va_mode & 077077;
257 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
258 uva->va_uid = lva->va_uid;
259 uva->va_gid = lva->va_gid;
260 } else {
261 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
262 uva->va_uid = ump->um_uid;
263 uva->va_gid = ump->um_gid;
264 }
265 break;
266 default: /* UNIONFS_TRADITIONAL */
267 uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask;
268 uva->va_uid = ump->um_uid;
269 uva->va_gid = ump->um_gid;
270 break;
271 }
272 }
273
274 /*
275 * Create upper node attr.
276 */
277 int
278 unionfs_create_uppervattr(struct unionfs_mount *ump,
279 struct vnode *lvp,
280 struct vattr *uva,
281 kauth_cred_t cred)
282 {
283 int error;
284 struct vattr lva;
285
286 if ((error = VOP_GETATTR(lvp, &lva, cred)))
287 return (error);
288
289 unionfs_create_uppervattr_core(ump, &lva, uva);
290
291 return (error);
292 }
293
294 /*
295 * relookup
296 *
297 * dvp should be locked on entry and will be locked on return.
298 *
299 * If an error is returned, *vpp will be invalid, otherwise it will hold a
300 * locked, referenced vnode. If *vpp == dvp then remember that only one
301 * LK_EXCLUSIVE lock is held.
302 */
303 static int
304 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
305 struct componentname *cnp, struct componentname *cn,
306 const char *path, int pathlen, u_long nameiop)
307 {
308 int error;
309
310 cn->cn_namelen = pathlen;
311 cn->cn_pnbuf = PNBUF_GET();
312 memcpy(cn->cn_pnbuf, path, pathlen);
313 cn->cn_pnbuf[pathlen] = '\0';
314
315 cn->cn_nameiop = nameiop;
316 cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
317 cn->cn_cred = cnp->cn_cred;
318
319 cn->cn_nameptr = cn->cn_pnbuf;
320 cn->cn_consume = cnp->cn_consume;
321
322 if (nameiop == DELETE)
323 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
324 else if (RENAME == nameiop)
325 cn->cn_flags |= (cnp->cn_flags & SAVESTART);
326
327 vref(dvp);
328 VOP_UNLOCK(dvp, 0);
329
330 if ((error = relookup(dvp, vpp, cn))) {
331 PNBUF_PUT(cn->cn_pnbuf);
332 cn->cn_flags &= ~HASBUF;
333 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
334 } else
335 vrele(dvp);
336
337 return (error);
338 }
339
340 /*
341 * relookup for CREATE namei operation.
342 *
343 * dvp is unionfs vnode. dvp should be locked.
344 *
345 * If it called 'unionfs_copyfile' function by unionfs_link etc,
346 * VOP_LOOKUP information is broken.
347 * So it need relookup in order to create link etc.
348 */
349 int
350 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp)
351 {
352 int error;
353 struct vnode *udvp;
354 struct vnode *vp;
355 struct componentname cn;
356
357 udvp = UNIONFSVPTOUPPERVP(dvp);
358 vp = NULLVP;
359
360 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
361 strlen(cnp->cn_nameptr), CREATE);
362 if (error)
363 return (error);
364
365 if (vp != NULLVP) {
366 if (udvp == vp)
367 vrele(vp);
368 else
369 vput(vp);
370
371 error = EEXIST;
372 }
373
374 if (cn.cn_flags & HASBUF) {
375 PNBUF_PUT(cn.cn_pnbuf);
376 cn.cn_flags &= ~HASBUF;
377 }
378
379 if (!error) {
380 cn.cn_flags |= (cnp->cn_flags & HASBUF);
381 cnp->cn_flags = cn.cn_flags;
382 }
383
384 return (error);
385 }
386
387 /*
388 * relookup for DELETE namei operation.
389 *
390 * dvp is unionfs vnode. dvp should be locked.
391 */
392 int
393 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp)
394 {
395 int error;
396 struct vnode *udvp;
397 struct vnode *vp;
398 struct componentname cn;
399
400 udvp = UNIONFSVPTOUPPERVP(dvp);
401 vp = NULLVP;
402
403 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
404 strlen(cnp->cn_nameptr), DELETE);
405 if (error)
406 return (error);
407
408 if (vp == NULLVP)
409 error = ENOENT;
410 else {
411 if (udvp == vp)
412 vrele(vp);
413 else
414 vput(vp);
415 }
416
417 if (cn.cn_flags & HASBUF) {
418 PNBUF_PUT(cn.cn_pnbuf);
419 cn.cn_flags &= ~HASBUF;
420 }
421
422 if (!error) {
423 cn.cn_flags |= (cnp->cn_flags & HASBUF);
424 cnp->cn_flags = cn.cn_flags;
425 }
426
427 return (error);
428 }
429
430 /*
431 * relookup for RENAME namei operation.
432 *
433 * dvp is unionfs vnode. dvp should be locked.
434 */
435 int
436 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp)
437 {
438 int error;
439 struct vnode *udvp;
440 struct vnode *vp;
441 struct componentname cn;
442
443 udvp = UNIONFSVPTOUPPERVP(dvp);
444 vp = NULLVP;
445
446 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
447 strlen(cnp->cn_nameptr), RENAME);
448 if (error)
449 return (error);
450
451 if (vp != NULLVP) {
452 if (udvp == vp)
453 vrele(vp);
454 else
455 vput(vp);
456 }
457
458 if (cn.cn_flags & HASBUF) {
459 PNBUF_PUT(cn.cn_pnbuf);
460 cn.cn_flags &= ~HASBUF;
461 }
462
463 if (!error) {
464 cn.cn_flags |= (cnp->cn_flags & HASBUF);
465 cnp->cn_flags = cn.cn_flags;
466 }
467
468 return (error);
469
470 }
471
472 /*
473 * Update the unionfs_node.
474 *
475 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
476 * uvp's lock and lower's lock will be unlocked.
477 */
478 static void
479 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp)
480 {
481 int count, lockcnt;
482 struct vnode *vp;
483 struct vnode *lvp;
484
485 vp = UNIONFSTOV(unp);
486 lvp = unp->un_lowervp;
487
488 /*
489 * lock update
490 */
491 mutex_enter(&vp->v_interlock);
492 unp->un_uppervp = uvp;
493 vp->v_vnlock = uvp->v_vnlock;
494 lockcnt = lvp->v_vnlock->vl_recursecnt +
495 rw_write_held(&lvp->v_vnlock->vl_lock);
496 if (lockcnt <= 0)
497 panic("unionfs: no exclusive lock");
498 mutex_exit(&vp->v_interlock);
499 for (count = 1; count < lockcnt; count++)
500 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
501 }
502
503 /*
504 * Create a new shadow dir.
505 *
506 * udvp should be locked on entry and will be locked on return.
507 *
508 * If no error returned, unp will be updated.
509 */
510 int
511 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
512 struct unionfs_node *unp, struct componentname *cnp)
513 {
514 int error;
515 struct vnode *lvp;
516 struct vnode *uvp;
517 struct vattr va;
518 struct vattr lva;
519 struct componentname cn;
520
521 if (unp->un_uppervp != NULLVP)
522 return (EEXIST);
523
524 lvp = unp->un_lowervp;
525 uvp = NULLVP;
526
527 memset(&cn, 0, sizeof(cn));
528
529 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
530 goto unionfs_mkshadowdir_abort;
531
532 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
533 goto unionfs_mkshadowdir_abort;
534 if (uvp != NULLVP) {
535 if (udvp == uvp)
536 vrele(uvp);
537 else
538 vput(uvp);
539
540 error = EEXIST;
541 goto unionfs_mkshadowdir_free_out;
542 }
543
544 unionfs_create_uppervattr_core(ump, &lva, &va);
545
546 error = VOP_MKDIR(udvp, &uvp, &cn, &va);
547
548 if (!error) {
549 unionfs_node_update(unp, uvp);
550
551 /*
552 * XXX The bug which cannot set uid/gid was corrected.
553 * Ignore errors. XXXNETBSD Why is this done as root?
554 */
555 va.va_type = VNON;
556 VOP_SETATTR(uvp, &va, lwp0.l_cred);
557 }
558
559 unionfs_mkshadowdir_free_out:
560 if (cn.cn_flags & HASBUF) {
561 PNBUF_PUT(cn.cn_pnbuf);
562 cn.cn_flags &= ~HASBUF;
563 }
564
565 unionfs_mkshadowdir_abort:
566
567 return (error);
568 }
569
570 /*
571 * Create a new whiteout.
572 *
573 * dvp should be locked on entry and will be locked on return.
574 */
575 int
576 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path)
577 {
578 int error;
579 struct vnode *wvp;
580 struct componentname cn;
581
582 if (path == NULL)
583 path = cnp->cn_nameptr;
584
585 wvp = NULLVP;
586 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, path, strlen(path), CREATE)))
587 return (error);
588 if (wvp != NULLVP) {
589 if (cn.cn_flags & HASBUF) {
590 PNBUF_PUT(cn.cn_pnbuf);
591 cn.cn_flags &= ~HASBUF;
592 }
593 if (dvp == wvp)
594 vrele(wvp);
595 else
596 vput(wvp);
597
598 return (EEXIST);
599 }
600
601 if (cn.cn_flags & HASBUF) {
602 PNBUF_PUT(cn.cn_pnbuf);
603 cn.cn_flags &= ~HASBUF;
604 }
605
606 return (error);
607 }
608
609 /*
610 * Create a new vnode for create a new shadow file.
611 *
612 * If an error is returned, *vpp will be invalid, otherwise it will hold a
613 * locked, referenced and opened vnode.
614 *
615 * unp is never updated.
616 */
617 static int
618 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
619 struct unionfs_node *unp, struct vattr *uvap)
620 {
621 struct unionfs_mount *ump;
622 struct vnode *vp;
623 struct vnode *lvp;
624 kauth_cred_t cred;
625 struct vattr lva;
626 int fmode;
627 int error;
628 struct componentname cn;
629
630 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
631 vp = NULLVP;
632 lvp = unp->un_lowervp;
633 cred = kauth_cred_get();
634 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
635 error = 0;
636
637 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
638 return (error);
639 unionfs_create_uppervattr_core(ump, &lva, uvap);
640
641 if (unp->un_path == NULL)
642 panic("unionfs: un_path is null");
643
644 cn.cn_namelen = strlen(unp->un_path);
645 cn.cn_pnbuf = PNBUF_GET();
646 memcpy(cn.cn_pnbuf, unp->un_path, cn.cn_namelen + 1);
647 cn.cn_nameiop = CREATE;
648 cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
649 cn.cn_cred = cred;
650 cn.cn_nameptr = cn.cn_pnbuf;
651 cn.cn_consume = 0;
652
653 vref(udvp);
654 if ((error = relookup(udvp, &vp, &cn)) != 0)
655 goto unionfs_vn_create_on_upper_free_out2;
656 vrele(udvp);
657
658 if (vp != NULLVP) {
659 if (vp == udvp)
660 vrele(vp);
661 else
662 vput(vp);
663 error = EEXIST;
664 goto unionfs_vn_create_on_upper_free_out1;
665 }
666
667 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
668 goto unionfs_vn_create_on_upper_free_out1;
669
670 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) {
671 vput(vp);
672 goto unionfs_vn_create_on_upper_free_out1;
673 }
674 vp->v_writecount++;
675 *vpp = vp;
676
677 unionfs_vn_create_on_upper_free_out1:
678 VOP_UNLOCK(udvp, 0);
679
680 unionfs_vn_create_on_upper_free_out2:
681 if (cn.cn_flags & HASBUF) {
682 PNBUF_PUT(cn.cn_pnbuf);
683 cn.cn_flags &= ~HASBUF;
684 }
685
686 return (error);
687 }
688
689 /*
690 * Copy from lvp to uvp.
691 *
692 * lvp and uvp should be locked and opened on entry and will be locked and
693 * opened on return.
694 */
695 static int
696 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
697 kauth_cred_t cred)
698 {
699 int error;
700 off_t offset;
701 int count;
702 int bufoffset;
703 char *buf;
704 struct uio uio;
705 struct iovec iov;
706
707 error = 0;
708 memset(&uio, 0, sizeof(uio));
709 UIO_SETUP_SYSSPACE(&uio);
710 uio.uio_offset = 0;
711
712 buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
713 if (buf == NULL)
714 return ENOMEM;
715
716 while (error == 0) {
717 offset = uio.uio_offset;
718
719 uio.uio_iov = &iov;
720 uio.uio_iovcnt = 1;
721 iov.iov_base = buf;
722 iov.iov_len = MAXBSIZE;
723 uio.uio_resid = iov.iov_len;
724 uio.uio_rw = UIO_READ;
725
726 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
727 break;
728 if ((count = MAXBSIZE - uio.uio_resid) == 0)
729 break;
730
731 bufoffset = 0;
732 while (bufoffset < count) {
733 uio.uio_iov = &iov;
734 uio.uio_iovcnt = 1;
735 iov.iov_base = buf + bufoffset;
736 iov.iov_len = count - bufoffset;
737 uio.uio_offset = offset + bufoffset;
738 uio.uio_resid = iov.iov_len;
739 uio.uio_rw = UIO_WRITE;
740
741 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
742 break;
743
744 bufoffset += (count - bufoffset) - uio.uio_resid;
745 }
746
747 uio.uio_offset = offset + bufoffset;
748 }
749
750 kmem_free(buf, MAXBSIZE);
751
752 return (error);
753 }
754
755 /*
756 * Copy file from lower to upper.
757 *
758 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
759 * docopy.
760 *
761 * If no error returned, unp will be updated.
762 */
763 int
764 unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred)
765 {
766 int error;
767 struct vnode *udvp;
768 struct vnode *lvp;
769 struct vnode *uvp;
770 struct vattr uva;
771
772 lvp = unp->un_lowervp;
773 uvp = NULLVP;
774
775 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
776 return (EROFS);
777 if (unp->un_dvp == NULLVP)
778 return (EINVAL);
779 if (unp->un_uppervp != NULLVP)
780 return (EEXIST);
781 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
782 if (udvp == NULLVP)
783 return (EROFS);
784 if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
785 return (EROFS);
786
787 error = VOP_ACCESS(lvp, VREAD, cred);
788 if (error != 0)
789 return (error);
790
791 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva);
792 if (error != 0)
793 return (error);
794
795 if (docopy != 0) {
796 error = VOP_OPEN(lvp, FREAD, cred);
797 if (error == 0) {
798 error = unionfs_copyfile_core(lvp, uvp, cred);
799 VOP_CLOSE(lvp, FREAD, cred);
800 }
801 }
802 VOP_CLOSE(uvp, FWRITE, cred);
803 uvp->v_writecount--;
804
805 if (error == 0) {
806 /* Reset the attributes. Ignore errors. */
807 uva.va_type = VNON;
808 VOP_SETATTR(uvp, &uva, cred);
809 }
810
811 unionfs_node_update(unp, uvp);
812
813 return (error);
814 }
815
816 /*
817 * It checks whether vp can rmdir. (check empty)
818 *
819 * vp is unionfs vnode.
820 * vp should be locked.
821 */
822 int
823 unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred)
824 {
825 int error;
826 int eofflag;
827 int lookuperr;
828 struct vnode *uvp;
829 struct vnode *lvp;
830 struct vnode *tvp;
831 struct vattr va;
832 struct componentname cn;
833 /*
834 * The size of buf needs to be larger than DIRBLKSIZ.
835 */
836 char buf[256 * 6];
837 struct dirent *dp;
838 struct dirent *edp;
839 struct uio uio;
840 struct iovec iov;
841
842 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
843
844 eofflag = 0;
845 uvp = UNIONFSVPTOUPPERVP(vp);
846 lvp = UNIONFSVPTOLOWERVP(vp);
847
848 /* check opaque */
849 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
850 return (error);
851 if (va.va_flags & OPAQUE)
852 return (0);
853
854 /* open vnode */
855 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0)
856 return (error);
857 if ((error = VOP_OPEN(vp, FREAD, cred)) != 0)
858 return (error);
859
860 UIO_SETUP_SYSSPACE(&uio);
861 uio.uio_rw = UIO_READ;
862 uio.uio_offset = 0;
863
864 while (!error && !eofflag) {
865 iov.iov_base = buf;
866 iov.iov_len = sizeof(buf);
867 uio.uio_iov = &iov;
868 uio.uio_iovcnt = 1;
869 uio.uio_resid = iov.iov_len;
870
871 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
872 if (error)
873 break;
874
875 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
876 for (dp = (struct dirent*)buf; !error && dp < edp;
877 dp = (struct dirent*)((char *)dp + dp->d_reclen)) {
878 if (dp->d_type == DT_WHT ||
879 (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
880 (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2)))
881 continue;
882
883 cn.cn_namelen = dp->d_namlen;
884 cn.cn_pnbuf = NULL;
885 cn.cn_nameptr = dp->d_name;
886 cn.cn_nameiop = LOOKUP;
887 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
888 cn.cn_cred = cred;
889 cn.cn_consume = 0;
890
891 /*
892 * check entry in lower.
893 * Sometimes, readdir function returns
894 * wrong entry.
895 */
896 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
897
898 if (!lookuperr)
899 vput(tvp);
900 else
901 continue; /* skip entry */
902
903 /*
904 * check entry
905 * If it has no exist/whiteout entry in upper,
906 * directory is not empty.
907 */
908 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
909 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
910
911 if (!lookuperr)
912 vput(tvp);
913
914 /* ignore exist or whiteout entry */
915 if (!lookuperr ||
916 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
917 continue;
918
919 error = ENOTEMPTY;
920 }
921 }
922
923 /* close vnode */
924 VOP_CLOSE(vp, FREAD, cred);
925
926 return (error);
927 }
928
929 #ifdef DIAGNOSTIC
930
931 struct vnode *
932 unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno)
933 {
934 struct unionfs_node *unp;
935
936 unp = VTOUNIONFS(vp);
937
938 #ifdef notyet
939 if (vp->v_op != unionfs_vnodeop_p) {
940 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
941 #ifdef KDB
942 kdb_enter(KDB_WHY_UNIONFS,
943 "unionfs_checkuppervp: on non-unionfs-node.\n");
944 #endif
945 panic("unionfs_checkuppervp");
946 };
947 #endif
948 return (unp->un_uppervp);
949 }
950
951 struct vnode *
952 unionfs_checklowervp(struct vnode *vp, const char *fil, int lno)
953 {
954 struct unionfs_node *unp;
955
956 unp = VTOUNIONFS(vp);
957
958 #ifdef notyet
959 if (vp->v_op != unionfs_vnodeop_p) {
960 printf("unionfs_checklowervp: on non-unionfs-node.\n");
961 #ifdef KDB
962 kdb_enter(KDB_WHY_UNIONFS,
963 "unionfs_checklowervp: on non-unionfs-node.\n");
964 #endif
965 panic("unionfs_checklowervp");
966 };
967 #endif
968 return (unp->un_lowervp);
969 }
970 #endif
971