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@ongs.co.jp>, ONGS Inc.
6 * Copyright (c) 2006 Daichi Goto <daichi@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$
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/resourcevar.h>
54
55 #ifdef MAC
56 #include <sys/mac.h>
57 #endif
58
59 #include <vm/uma.h>
60
61 #include <fs/unionfs/union.h>
62
63 MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
64 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
65
66 /*
67 * Initialize
68 */
69 int
70 unionfs_init(struct vfsconf *vfsp)
71 {
72 UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
73 return (0);
74 }
75
76 /*
77 * Uninitialize
78 */
79 int
80 unionfs_uninit(struct vfsconf *vfsp)
81 {
82 return (0);
83 }
84
85 /*
86 * Make a new or get existing unionfs node.
87 *
88 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
89 * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
90 * you should not lock plurality simultaneously.
91 */
92 int
93 unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
94 struct vnode *lowervp, struct vnode *dvp,
95 struct vnode **vpp, struct componentname *cnp,
96 struct thread *td)
97 {
98 struct unionfs_mount *ump;
99 struct unionfs_node *unp;
100 struct vnode *vp;
101 int error;
102 int lkflags;
103 char *path;
104
105 ump = MOUNTTOUNIONFSMOUNT(mp);
106 lkflags = (cnp ? cnp->cn_lkflags : 0);
107 path = (cnp ? cnp->cn_nameptr : NULL);
108
109 if (uppervp == NULLVP && lowervp == NULLVP)
110 panic("unionfs_nodeget: upper and lower is null");
111
112 /* If it has no ISLASTCN flag, path check is skipped. */
113 if (cnp && !(cnp->cn_flags & ISLASTCN))
114 path = NULL;
115
116 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
117 (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
118 if (dvp == NULLVP)
119 return (EINVAL);
120 }
121
122 /*
123 * Do the MALLOC before the getnewvnode since doing so afterward
124 * might cause a bogus v_data pointer to get dereferenced elsewhere
125 * if MALLOC should block.
126 */
127 MALLOC(unp, struct unionfs_node *, sizeof(struct unionfs_node),
128 M_UNIONFSNODE, M_WAITOK | M_ZERO);
129
130 error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
131 if (error != 0) {
132 FREE(unp, M_UNIONFSNODE);
133 return (error);
134 }
135 if (dvp != NULLVP)
136 vref(dvp);
137 if (uppervp != NULLVP)
138 vref(uppervp);
139 if (lowervp != NULLVP)
140 vref(lowervp);
141
142 unp->un_vnode = vp;
143 unp->un_uppervp = uppervp;
144 unp->un_lowervp = lowervp;
145 unp->un_dvp = dvp;
146 if (uppervp != NULLVP)
147 vp->v_vnlock = uppervp->v_vnlock;
148 else
149 vp->v_vnlock = lowervp->v_vnlock;
150
151 if (path != NULL) {
152 unp->un_path = (char *)
153 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
154 bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
155 unp->un_path[cnp->cn_namelen] = '\0';
156 }
157 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
158 vp->v_data = unp;
159
160 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
161 (lowervp != NULLVP && ump->um_lowervp == lowervp))
162 vp->v_vflag |= VV_ROOT;
163
164 if (lkflags & LK_TYPE_MASK)
165 vn_lock(vp, lkflags | LK_RETRY, td);
166
167 *vpp = vp;
168
169 return (0);
170 }
171
172 /*
173 * Clean up the unionfs node.
174 */
175 void
176 unionfs_noderem(struct vnode *vp, struct thread *td)
177 {
178 int vfslocked;
179 struct unionfs_node *unp;
180 struct unionfs_node_status *unsp, *unsp_tmp;
181 struct vnode *lvp;
182 struct vnode *uvp;
183
184 /*
185 * Use the interlock to protect the clearing of v_data to
186 * prevent faults in unionfs_lock().
187 */
188 VI_LOCK(vp);
189 unp = VTOUNIONFS(vp);
190 lvp = unp->un_lowervp;
191 uvp = unp->un_uppervp;
192 unp->un_lowervp = unp->un_uppervp = NULLVP;
193
194 vp->v_vnlock = &(vp->v_lock);
195 vp->v_data = NULL;
196 lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_INTERLOCK, VI_MTX(vp), td);
197 if (lvp != NULLVP)
198 VOP_UNLOCK(lvp, 0, td);
199 if (uvp != NULLVP)
200 VOP_UNLOCK(uvp, 0, td);
201 vp->v_object = NULL;
202
203 if (lvp != NULLVP) {
204 vfslocked = VFS_LOCK_GIANT(lvp->v_mount);
205 vrele(lvp);
206 VFS_UNLOCK_GIANT(vfslocked);
207 }
208 if (uvp != NULLVP) {
209 vfslocked = VFS_LOCK_GIANT(uvp->v_mount);
210 vrele(uvp);
211 VFS_UNLOCK_GIANT(vfslocked);
212 }
213 if (unp->un_dvp != NULLVP) {
214 vfslocked = VFS_LOCK_GIANT(unp->un_dvp->v_mount);
215 vrele(unp->un_dvp);
216 VFS_UNLOCK_GIANT(vfslocked);
217 unp->un_dvp = NULLVP;
218 }
219 if (unp->un_path) {
220 free(unp->un_path, M_UNIONFSPATH);
221 unp->un_path = NULL;
222 }
223
224 LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) {
225 LIST_REMOVE(unsp, uns_list);
226 free(unsp, M_TEMP);
227 }
228 FREE(unp, M_UNIONFSNODE);
229 }
230
231 /*
232 * Get the unionfs node status.
233 * You need exclusive lock this vnode.
234 */
235 void
236 unionfs_get_node_status(struct unionfs_node *unp, struct thread *td,
237 struct unionfs_node_status **unspp)
238 {
239 struct unionfs_node_status *unsp;
240
241 KASSERT(NULL != unspp, ("null pointer"));
242 ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
243
244 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
245 if (unsp->uns_tid == td->td_tid) {
246 *unspp = unsp;
247 return;
248 }
249 }
250
251 /* create a new unionfs node status */
252 MALLOC(unsp, struct unionfs_node_status *,
253 sizeof(struct unionfs_node_status), M_TEMP, M_WAITOK | M_ZERO);
254
255 unsp->uns_tid = td->td_tid;
256 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
257
258 *unspp = unsp;
259 }
260
261 /*
262 * Remove the unionfs node status, if you can.
263 * You need exclusive lock this vnode.
264 */
265 void
266 unionfs_tryrem_node_status(struct unionfs_node *unp, struct thread *td,
267 struct unionfs_node_status *unsp)
268 {
269 KASSERT(NULL != unsp, ("null pointer"));
270 ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
271
272 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
273 return;
274
275 LIST_REMOVE(unsp, uns_list);
276 free(unsp, M_TEMP);
277 }
278
279 /*
280 * Create upper node attr.
281 */
282 void
283 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
284 struct vattr *lva,
285 struct vattr *uva,
286 struct thread *td)
287 {
288 VATTR_NULL(uva);
289 uva->va_type = lva->va_type;
290 uva->va_atime = lva->va_atime;
291 uva->va_mtime = lva->va_mtime;
292 uva->va_ctime = lva->va_ctime;
293
294 switch (ump->um_copymode) {
295 case UNIONFS_TRANSPARENT:
296 uva->va_mode = lva->va_mode;
297 uva->va_uid = lva->va_uid;
298 uva->va_gid = lva->va_gid;
299 break;
300 case UNIONFS_MASQUERADE:
301 if (ump->um_uid == lva->va_uid) {
302 uva->va_mode = lva->va_mode & 077077;
303 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
304 uva->va_uid = lva->va_uid;
305 uva->va_gid = lva->va_gid;
306 } else {
307 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
308 uva->va_uid = ump->um_uid;
309 uva->va_gid = ump->um_gid;
310 }
311 break;
312 default: /* UNIONFS_TRADITIONAL */
313 FILEDESC_LOCK_FAST(td->td_proc->p_fd);
314 uva->va_mode = 0777 & ~td->td_proc->p_fd->fd_cmask;
315 FILEDESC_UNLOCK_FAST(td->td_proc->p_fd);
316 uva->va_uid = ump->um_uid;
317 uva->va_gid = ump->um_gid;
318 break;
319 }
320 }
321
322 /*
323 * Create upper node attr.
324 */
325 int
326 unionfs_create_uppervattr(struct unionfs_mount *ump,
327 struct vnode *lvp,
328 struct vattr *uva,
329 struct ucred *cred,
330 struct thread *td)
331 {
332 int error;
333 struct vattr lva;
334
335 if ((error = VOP_GETATTR(lvp, &lva, cred, td)))
336 return (error);
337
338 unionfs_create_uppervattr_core(ump, &lva, uva, td);
339
340 return (error);
341 }
342
343 /*
344 * relookup
345 *
346 * dvp should be locked on entry and will be locked on return.
347 *
348 * If an error is returned, *vpp will be invalid, otherwise it will hold a
349 * locked, referenced vnode. If *vpp == dvp then remember that only one
350 * LK_EXCLUSIVE lock is held.
351 */
352 static int
353 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
354 struct componentname *cnp, struct componentname *cn,
355 struct thread *td, char *path, int pathlen, u_long nameiop)
356 {
357 int error;
358
359 cn->cn_namelen = pathlen;
360 cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
361 bcopy(path, cn->cn_pnbuf, pathlen);
362 cn->cn_pnbuf[pathlen] = '\0';
363
364 cn->cn_nameiop = nameiop;
365 cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
366 cn->cn_lkflags = LK_EXCLUSIVE;
367 cn->cn_thread = td;
368 cn->cn_cred = cnp->cn_cred;
369
370 cn->cn_nameptr = cn->cn_pnbuf;
371 cn->cn_consume = cnp->cn_consume;
372
373 if (nameiop == DELETE)
374 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
375 else if (RENAME == nameiop)
376 cn->cn_flags |= (cnp->cn_flags & SAVESTART);
377
378 vref(dvp);
379 VOP_UNLOCK(dvp, 0, td);
380
381 if ((error = relookup(dvp, vpp, cn))) {
382 uma_zfree(namei_zone, cn->cn_pnbuf);
383 cn->cn_flags &= ~HASBUF;
384 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
385 } else
386 vrele(dvp);
387
388 return (error);
389 }
390
391 /*
392 * relookup for CREATE namei operation.
393 *
394 * dvp is unionfs vnode. dvp should be locked.
395 *
396 * If it called 'unionfs_copyfile' function by unionfs_link etc,
397 * VOP_LOOKUP information is broken.
398 * So it need relookup in order to create link etc.
399 */
400 int
401 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp,
402 struct thread *td)
403 {
404 int error;
405 struct vnode *udvp;
406 struct vnode *vp;
407 struct componentname cn;
408
409 udvp = UNIONFSVPTOUPPERVP(dvp);
410 vp = NULLVP;
411
412 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
413 strlen(cnp->cn_nameptr), CREATE);
414 if (error)
415 return (error);
416
417 if (vp != NULLVP) {
418 if (udvp == vp)
419 vrele(vp);
420 else
421 vput(vp);
422
423 error = EEXIST;
424 }
425
426 if (cn.cn_flags & HASBUF) {
427 uma_zfree(namei_zone, cn.cn_pnbuf);
428 cn.cn_flags &= ~HASBUF;
429 }
430
431 if (!error) {
432 cn.cn_flags |= (cnp->cn_flags & HASBUF);
433 cnp->cn_flags = cn.cn_flags;
434 }
435
436 return (error);
437 }
438
439 /*
440 * relookup for DELETE namei operation.
441 *
442 * dvp is unionfs vnode. dvp should be locked.
443 */
444 int
445 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp,
446 struct thread *td)
447 {
448 int error;
449 struct vnode *udvp;
450 struct vnode *vp;
451 struct componentname cn;
452
453 udvp = UNIONFSVPTOUPPERVP(dvp);
454 vp = NULLVP;
455
456 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
457 strlen(cnp->cn_nameptr), DELETE);
458 if (error)
459 return (error);
460
461 if (vp == NULLVP)
462 error = ENOENT;
463 else {
464 if (udvp == vp)
465 vrele(vp);
466 else
467 vput(vp);
468 }
469
470 if (cn.cn_flags & HASBUF) {
471 uma_zfree(namei_zone, cn.cn_pnbuf);
472 cn.cn_flags &= ~HASBUF;
473 }
474
475 if (!error) {
476 cn.cn_flags |= (cnp->cn_flags & HASBUF);
477 cnp->cn_flags = cn.cn_flags;
478 }
479
480 return (error);
481 }
482
483 /*
484 * relookup for RENAME namei operation.
485 *
486 * dvp is unionfs vnode. dvp should be locked.
487 */
488 int
489 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp,
490 struct thread *td)
491 {
492 int error;
493 struct vnode *udvp;
494 struct vnode *vp;
495 struct componentname cn;
496
497 udvp = UNIONFSVPTOUPPERVP(dvp);
498 vp = NULLVP;
499
500 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
501 strlen(cnp->cn_nameptr), RENAME);
502 if (error)
503 return (error);
504
505 if (vp != NULLVP) {
506 if (udvp == vp)
507 vrele(vp);
508 else
509 vput(vp);
510 }
511
512 if (cn.cn_flags & HASBUF) {
513 uma_zfree(namei_zone, cn.cn_pnbuf);
514 cn.cn_flags &= ~HASBUF;
515 }
516
517 if (!error) {
518 cn.cn_flags |= (cnp->cn_flags & HASBUF);
519 cnp->cn_flags = cn.cn_flags;
520 }
521
522 return (error);
523
524 }
525
526 /*
527 * Update the unionfs_node.
528 *
529 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
530 * uvp's lock and lower's lock will be unlocked.
531 */
532 static void
533 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
534 struct thread *td)
535 {
536 int count, lockcnt;
537 struct vnode *vp;
538 struct vnode *lvp;
539
540 vp = UNIONFSTOV(unp);
541 lvp = unp->un_lowervp;
542
543 /*
544 * lock update
545 */
546 VI_LOCK(vp);
547 unp->un_uppervp = uvp;
548 vp->v_vnlock = uvp->v_vnlock;
549 lockcnt = lvp->v_vnlock->lk_exclusivecount;
550 if (lockcnt <= 0)
551 panic("unionfs: no exclusive lock");
552 VI_UNLOCK(vp);
553 for (count = 1; count < lockcnt; count++)
554 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
555 }
556
557 /*
558 * Create a new shadow dir.
559 *
560 * udvp should be locked on entry and will be locked on return.
561 *
562 * If no error returned, unp will be updated.
563 */
564 int
565 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
566 struct unionfs_node *unp, struct componentname *cnp,
567 struct thread *td)
568 {
569 int error;
570 struct vnode *lvp;
571 struct vnode *uvp;
572 struct vattr va;
573 struct vattr lva;
574 struct componentname cn;
575 struct mount *mp;
576 struct ucred *cred;
577 struct ucred *credbk;
578 struct uidinfo *rootinfo;
579
580 if (unp->un_uppervp != NULLVP)
581 return (EEXIST);
582
583 lvp = unp->un_lowervp;
584 uvp = NULLVP;
585 credbk = cnp->cn_cred;
586
587 /* Authority change to root */
588 rootinfo = uifind((uid_t)0);
589 cred = crdup(cnp->cn_cred);
590 chgproccnt(cred->cr_ruidinfo, 1, 0);
591 change_euid(cred, rootinfo);
592 change_ruid(cred, rootinfo);
593 change_svuid(cred, (uid_t)0);
594 uifree(rootinfo);
595 cnp->cn_cred = cred;
596
597 memset(&cn, 0, sizeof(cn));
598
599 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred, td)))
600 goto unionfs_mkshadowdir_abort;
601
602 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
603 goto unionfs_mkshadowdir_abort;
604 if (uvp != NULLVP) {
605 if (udvp == uvp)
606 vrele(uvp);
607 else
608 vput(uvp);
609
610 error = EEXIST;
611 goto unionfs_mkshadowdir_free_out;
612 }
613
614 if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
615 goto unionfs_mkshadowdir_free_out;
616 if ((error = VOP_LEASE(udvp, td, cn.cn_cred, LEASE_WRITE))) {
617 vn_finished_write(mp);
618 goto unionfs_mkshadowdir_free_out;
619 }
620 unionfs_create_uppervattr_core(ump, &lva, &va, td);
621
622 error = VOP_MKDIR(udvp, &uvp, &cn, &va);
623
624 if (!error) {
625 unionfs_node_update(unp, uvp, td);
626
627 /*
628 * XXX The bug which cannot set uid/gid was corrected.
629 * Ignore errors.
630 */
631 va.va_type = VNON;
632 VOP_SETATTR(uvp, &va, cn.cn_cred, td);
633 }
634 vn_finished_write(mp);
635
636 unionfs_mkshadowdir_free_out:
637 if (cn.cn_flags & HASBUF) {
638 uma_zfree(namei_zone, cn.cn_pnbuf);
639 cn.cn_flags &= ~HASBUF;
640 }
641
642 unionfs_mkshadowdir_abort:
643 cnp->cn_cred = credbk;
644 chgproccnt(cred->cr_ruidinfo, -1, 0);
645 crfree(cred);
646
647 return (error);
648 }
649
650 /*
651 * Create a new whiteout.
652 *
653 * dvp should be locked on entry and will be locked on return.
654 */
655 int
656 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
657 struct thread *td, char *path)
658 {
659 int error;
660 struct vnode *wvp;
661 struct componentname cn;
662 struct mount *mp;
663
664 if (path == NULL)
665 path = cnp->cn_nameptr;
666
667 wvp = NULLVP;
668 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, td, path, strlen(path), CREATE)))
669 return (error);
670 if (wvp != NULLVP) {
671 if (cn.cn_flags & HASBUF) {
672 uma_zfree(namei_zone, cn.cn_pnbuf);
673 cn.cn_flags &= ~HASBUF;
674 }
675 if (dvp == wvp)
676 vrele(wvp);
677 else
678 vput(wvp);
679
680 return (EEXIST);
681 }
682
683 if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
684 goto unionfs_mkwhiteout_free_out;
685 if (!(error = VOP_LEASE(dvp, td, td->td_ucred, LEASE_WRITE)))
686 error = VOP_WHITEOUT(dvp, &cn, CREATE);
687
688 vn_finished_write(mp);
689
690 unionfs_mkwhiteout_free_out:
691 if (cn.cn_flags & HASBUF) {
692 uma_zfree(namei_zone, cn.cn_pnbuf);
693 cn.cn_flags &= ~HASBUF;
694 }
695
696 return (error);
697 }
698
699 /*
700 * Create a new vnode for create a new shadow file.
701 *
702 * If an error is returned, *vpp will be invalid, otherwise it will hold a
703 * locked, referenced and opened vnode.
704 *
705 * unp is never updated.
706 */
707 static int
708 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
709 struct unionfs_node *unp, struct vattr *uvap,
710 struct thread *td)
711 {
712 struct unionfs_mount *ump;
713 struct vnode *vp;
714 struct vnode *lvp;
715 struct ucred *cred;
716 struct vattr lva;
717 int fmode;
718 int error;
719 struct componentname cn;
720
721 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
722 vp = NULLVP;
723 lvp = unp->un_lowervp;
724 cred = td->td_ucred;
725 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
726 error = 0;
727
728 if ((error = VOP_GETATTR(lvp, &lva, cred, td)) != 0)
729 return (error);
730 unionfs_create_uppervattr_core(ump, &lva, uvap, td);
731
732 if (unp->un_path == NULL)
733 panic("unionfs: un_path is null");
734
735 cn.cn_namelen = strlen(unp->un_path);
736 cn.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
737 bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1);
738 cn.cn_nameiop = CREATE;
739 cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
740 cn.cn_lkflags = LK_EXCLUSIVE;
741 cn.cn_thread = td;
742 cn.cn_cred = cred;
743 cn.cn_nameptr = cn.cn_pnbuf;
744 cn.cn_consume = 0;
745
746 vref(udvp);
747 if ((error = relookup(udvp, &vp, &cn)) != 0)
748 goto unionfs_vn_create_on_upper_free_out2;
749 vrele(udvp);
750
751 if (vp != NULLVP) {
752 if (vp == udvp)
753 vrele(vp);
754 else
755 vput(vp);
756 error = EEXIST;
757 goto unionfs_vn_create_on_upper_free_out1;
758 }
759
760 if ((error = VOP_LEASE(udvp, td, cred, LEASE_WRITE)) != 0)
761 goto unionfs_vn_create_on_upper_free_out1;
762
763 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
764 goto unionfs_vn_create_on_upper_free_out1;
765
766 if ((error = VOP_OPEN(vp, fmode, cred, td, -1)) != 0) {
767 vput(vp);
768 goto unionfs_vn_create_on_upper_free_out1;
769 }
770 vp->v_writecount++;
771 *vpp = vp;
772
773 unionfs_vn_create_on_upper_free_out1:
774 VOP_UNLOCK(udvp, 0, td);
775
776 unionfs_vn_create_on_upper_free_out2:
777 if (cn.cn_flags & HASBUF) {
778 uma_zfree(namei_zone, cn.cn_pnbuf);
779 cn.cn_flags &= ~HASBUF;
780 }
781
782 return (error);
783 }
784
785 /*
786 * Copy from lvp to uvp.
787 *
788 * lvp and uvp should be locked and opened on entry and will be locked and
789 * opened on return.
790 */
791 static int
792 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
793 struct ucred *cred, struct thread *td)
794 {
795 int error;
796 off_t offset;
797 int count;
798 int bufoffset;
799 char *buf;
800 struct uio uio;
801 struct iovec iov;
802
803 error = 0;
804 memset(&uio, 0, sizeof(uio));
805
806 uio.uio_td = td;
807 uio.uio_segflg = UIO_SYSSPACE;
808 uio.uio_offset = 0;
809
810 if ((error = VOP_LEASE(lvp, td, cred, LEASE_READ)) != 0)
811 return (error);
812 if ((error = VOP_LEASE(uvp, td, cred, LEASE_WRITE)) != 0)
813 return (error);
814 buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
815
816 while (error == 0) {
817 offset = uio.uio_offset;
818
819 uio.uio_iov = &iov;
820 uio.uio_iovcnt = 1;
821 iov.iov_base = buf;
822 iov.iov_len = MAXBSIZE;
823 uio.uio_resid = iov.iov_len;
824 uio.uio_rw = UIO_READ;
825
826 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
827 break;
828 if ((count = MAXBSIZE - uio.uio_resid) == 0)
829 break;
830
831 bufoffset = 0;
832 while (bufoffset < count) {
833 uio.uio_iov = &iov;
834 uio.uio_iovcnt = 1;
835 iov.iov_base = buf + bufoffset;
836 iov.iov_len = count - bufoffset;
837 uio.uio_offset = offset + bufoffset;
838 uio.uio_resid = iov.iov_len;
839 uio.uio_rw = UIO_WRITE;
840
841 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
842 break;
843
844 bufoffset += (count - bufoffset) - uio.uio_resid;
845 }
846
847 uio.uio_offset = offset + bufoffset;
848 }
849
850 free(buf, M_TEMP);
851
852 return (error);
853 }
854
855 /*
856 * Copy file from lower to upper.
857 *
858 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
859 * docopy.
860 *
861 * If no error returned, unp will be updated.
862 */
863 int
864 unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
865 struct thread *td)
866 {
867 int error;
868 struct mount *mp;
869 struct vnode *udvp;
870 struct vnode *lvp;
871 struct vnode *uvp;
872 struct vattr uva;
873
874 lvp = unp->un_lowervp;
875 uvp = NULLVP;
876
877 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
878 return (EROFS);
879 if (unp->un_dvp == NULLVP)
880 return (EINVAL);
881 if (unp->un_uppervp != NULLVP)
882 return (EEXIST);
883 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
884 if (udvp == NULLVP)
885 return (EROFS);
886 if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
887 return (EROFS);
888
889 error = VOP_ACCESS(lvp, VREAD, cred, td);
890 if (error != 0)
891 return (error);
892
893 if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
894 return (error);
895 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
896 if (error != 0) {
897 vn_finished_write(mp);
898 return (error);
899 }
900
901 if (docopy != 0) {
902 error = VOP_OPEN(lvp, FREAD, cred, td, -1);
903 if (error == 0) {
904 error = unionfs_copyfile_core(lvp, uvp, cred, td);
905 VOP_CLOSE(lvp, FREAD, cred, td);
906 }
907 }
908 VOP_CLOSE(uvp, FWRITE, cred, td);
909 uvp->v_writecount--;
910
911 vn_finished_write(mp);
912
913 if (error == 0) {
914 /* Reset the attributes. Ignore errors. */
915 uva.va_type = VNON;
916 VOP_SETATTR(uvp, &uva, cred, td);
917 }
918
919 unionfs_node_update(unp, uvp, td);
920
921 return (error);
922 }
923
924 /*
925 * It checks whether vp can rmdir. (check empty)
926 *
927 * vp is unionfs vnode.
928 * vp should be locked.
929 */
930 int
931 unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
932 {
933 int error;
934 int eofflag;
935 int lookuperr;
936 struct vnode *uvp;
937 struct vnode *lvp;
938 struct vnode *tvp;
939 struct vattr va;
940 struct componentname cn;
941 /*
942 * The size of buf needs to be larger than DIRBLKSIZ.
943 */
944 char buf[256 * 6];
945 struct dirent *dp;
946 struct dirent *edp;
947 struct uio uio;
948 struct iovec iov;
949
950 ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
951
952 eofflag = 0;
953 uvp = UNIONFSVPTOUPPERVP(vp);
954 lvp = UNIONFSVPTOLOWERVP(vp);
955
956 /* check opaque */
957 if ((error = VOP_GETATTR(uvp, &va, cred, td)) != 0)
958 return (error);
959 if (va.va_flags & OPAQUE)
960 return (0);
961
962 /* open vnode */
963 #ifdef MAC
964 if ((error = mac_check_vnode_open(cred, vp, VEXEC|VREAD)) != 0)
965 return (error);
966 #endif
967 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
968 return (error);
969 if ((error = VOP_OPEN(vp, FREAD, cred, td, -1)) != 0)
970 return (error);
971
972 uio.uio_rw = UIO_READ;
973 uio.uio_segflg = UIO_SYSSPACE;
974 uio.uio_td = td;
975 uio.uio_offset = 0;
976
977 #ifdef MAC
978 error = mac_check_vnode_readdir(td->td_ucred, lvp);
979 #endif
980 while (!error && !eofflag) {
981 iov.iov_base = buf;
982 iov.iov_len = sizeof(buf);
983 uio.uio_iov = &iov;
984 uio.uio_iovcnt = 1;
985 uio.uio_resid = iov.iov_len;
986
987 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
988 if (error)
989 break;
990
991 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
992 for (dp = (struct dirent*)buf; !error && dp < edp;
993 dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
994 if (dp->d_type == DT_WHT ||
995 (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
996 (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
997 continue;
998
999 cn.cn_namelen = dp->d_namlen;
1000 cn.cn_pnbuf = NULL;
1001 cn.cn_nameptr = dp->d_name;
1002 cn.cn_nameiop = LOOKUP;
1003 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1004 cn.cn_lkflags = LK_EXCLUSIVE;
1005 cn.cn_thread = td;
1006 cn.cn_cred = cred;
1007 cn.cn_consume = 0;
1008
1009 /*
1010 * check entry in lower.
1011 * Sometimes, readdir function returns
1012 * wrong entry.
1013 */
1014 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
1015
1016 if (!lookuperr)
1017 vput(tvp);
1018 else
1019 continue; /* skip entry */
1020
1021 /*
1022 * check entry
1023 * If it has no exist/whiteout entry in upper,
1024 * directory is not empty.
1025 */
1026 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1027 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
1028
1029 if (!lookuperr)
1030 vput(tvp);
1031
1032 /* ignore exist or whiteout entry */
1033 if (!lookuperr ||
1034 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
1035 continue;
1036
1037 error = ENOTEMPTY;
1038 }
1039 }
1040
1041 /* close vnode */
1042 VOP_CLOSE(vp, FREAD, cred, td);
1043
1044 return (error);
1045 }
1046
1047 #ifdef DIAGNOSTIC
1048
1049 struct vnode *
1050 unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
1051 {
1052 struct unionfs_node *unp;
1053
1054 unp = VTOUNIONFS(vp);
1055
1056 #ifdef notyet
1057 if (vp->v_op != unionfs_vnodeop_p) {
1058 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
1059 #ifdef KDB
1060 kdb_enter("unionfs_checkuppervp: on non-unionfs-node.\n");
1061 #endif
1062 panic("unionfs_checkuppervp");
1063 };
1064 #endif
1065 return (unp->un_uppervp);
1066 }
1067
1068 struct vnode *
1069 unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
1070 {
1071 struct unionfs_node *unp;
1072
1073 unp = VTOUNIONFS(vp);
1074
1075 #ifdef notyet
1076 if (vp->v_op != unionfs_vnodeop_p) {
1077 printf("unionfs_checklowervp: on non-unionfs-node.\n");
1078 #ifdef KDB
1079 kdb_enter("unionfs_checklowervp: on non-unionfs-node.\n");
1080 #endif
1081 panic("unionfs_checklowervp");
1082 };
1083 #endif
1084 return (unp->un_lowervp);
1085 }
1086 #endif
Cache object: 3adc17c7829edfba9c58acbd6acb584b
|