1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1994 Jan-Simon Pendry
5 * Copyright (c) 1994
6 * The Regents of the University of California. All rights reserved.
7 * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
8 * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org>
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/ktr.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/malloc.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/proc.h>
50 #include <sys/vnode.h>
51 #include <sys/dirent.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
54 #include <sys/stat.h>
55 #include <sys/resourcevar.h>
56
57 #include <security/mac/mac_framework.h>
58
59 #include <vm/uma.h>
60
61 #include <fs/unionfs/union.h>
62
63 #define NUNIONFSNODECACHE 16
64
65 static MALLOC_DEFINE(M_UNIONFSHASH, "UNIONFS hash", "UNIONFS hash table");
66 MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
67 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
68
69 /*
70 * Initialize
71 */
72 int
unionfs_init(struct vfsconf * vfsp)73 unionfs_init(struct vfsconf *vfsp)
74 {
75 UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
76 return (0);
77 }
78
79 /*
80 * Uninitialize
81 */
82 int
unionfs_uninit(struct vfsconf * vfsp)83 unionfs_uninit(struct vfsconf *vfsp)
84 {
85 return (0);
86 }
87
88 static struct unionfs_node_hashhead *
unionfs_get_hashhead(struct vnode * dvp,char * path)89 unionfs_get_hashhead(struct vnode *dvp, char *path)
90 {
91 int count;
92 char hash;
93 struct unionfs_node *unp;
94
95 hash = 0;
96 unp = VTOUNIONFS(dvp);
97 if (path != NULL) {
98 for (count = 0; path[count]; count++)
99 hash += path[count];
100 }
101
102 return (&(unp->un_hashtbl[hash & (unp->un_hashmask)]));
103 }
104
105 /*
106 * Get the cached vnode.
107 */
108 static struct vnode *
unionfs_get_cached_vnode(struct vnode * uvp,struct vnode * lvp,struct vnode * dvp,char * path)109 unionfs_get_cached_vnode(struct vnode *uvp, struct vnode *lvp,
110 struct vnode *dvp, char *path)
111 {
112 struct unionfs_node_hashhead *hd;
113 struct unionfs_node *unp;
114 struct vnode *vp;
115
116 KASSERT((uvp == NULLVP || uvp->v_type == VDIR),
117 ("unionfs_get_cached_vnode: v_type != VDIR"));
118 KASSERT((lvp == NULLVP || lvp->v_type == VDIR),
119 ("unionfs_get_cached_vnode: v_type != VDIR"));
120
121 VI_LOCK(dvp);
122 hd = unionfs_get_hashhead(dvp, path);
123 LIST_FOREACH(unp, hd, un_hash) {
124 if (!strcmp(unp->un_path, path)) {
125 vp = UNIONFSTOV(unp);
126 VI_LOCK_FLAGS(vp, MTX_DUPOK);
127 VI_UNLOCK(dvp);
128 vp->v_iflag &= ~VI_OWEINACT;
129 if (VN_IS_DOOMED(vp) ||
130 ((vp->v_iflag & VI_DOINGINACT) != 0)) {
131 VI_UNLOCK(vp);
132 vp = NULLVP;
133 } else
134 VI_UNLOCK(vp);
135 return (vp);
136 }
137 }
138 VI_UNLOCK(dvp);
139
140 return (NULLVP);
141 }
142
143 /*
144 * Add the new vnode into cache.
145 */
146 static struct vnode *
unionfs_ins_cached_vnode(struct unionfs_node * uncp,struct vnode * dvp,char * path)147 unionfs_ins_cached_vnode(struct unionfs_node *uncp,
148 struct vnode *dvp, char *path)
149 {
150 struct unionfs_node_hashhead *hd;
151 struct unionfs_node *unp;
152 struct vnode *vp;
153
154 KASSERT((uncp->un_uppervp==NULLVP || uncp->un_uppervp->v_type==VDIR),
155 ("unionfs_ins_cached_vnode: v_type != VDIR"));
156 KASSERT((uncp->un_lowervp==NULLVP || uncp->un_lowervp->v_type==VDIR),
157 ("unionfs_ins_cached_vnode: v_type != VDIR"));
158
159 VI_LOCK(dvp);
160 hd = unionfs_get_hashhead(dvp, path);
161 LIST_FOREACH(unp, hd, un_hash) {
162 if (!strcmp(unp->un_path, path)) {
163 vp = UNIONFSTOV(unp);
164 VI_LOCK_FLAGS(vp, MTX_DUPOK);
165 vp->v_iflag &= ~VI_OWEINACT;
166 if (VN_IS_DOOMED(vp) ||
167 ((vp->v_iflag & VI_DOINGINACT) != 0)) {
168 LIST_INSERT_HEAD(hd, uncp, un_hash);
169 VI_UNLOCK(vp);
170 vp = NULLVP;
171 } else
172 VI_UNLOCK(vp);
173 VI_UNLOCK(dvp);
174 return (vp);
175 }
176 }
177
178 LIST_INSERT_HEAD(hd, uncp, un_hash);
179 VI_UNLOCK(dvp);
180
181 return (NULLVP);
182 }
183
184 /*
185 * Remove the vnode.
186 */
187 static void
unionfs_rem_cached_vnode(struct unionfs_node * unp,struct vnode * dvp)188 unionfs_rem_cached_vnode(struct unionfs_node *unp, struct vnode *dvp)
189 {
190 KASSERT((unp != NULL), ("unionfs_rem_cached_vnode: null node"));
191 KASSERT((dvp != NULLVP),
192 ("unionfs_rem_cached_vnode: null parent vnode"));
193 KASSERT((unp->un_hash.le_prev != NULL),
194 ("unionfs_rem_cached_vnode: null hash"));
195
196 VI_LOCK(dvp);
197 LIST_REMOVE(unp, un_hash);
198 unp->un_hash.le_next = NULL;
199 unp->un_hash.le_prev = NULL;
200 VI_UNLOCK(dvp);
201 }
202
203 /*
204 * Make a new or get existing unionfs node.
205 *
206 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
207 * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
208 * you should not lock plurality simultaneously.
209 */
210 int
unionfs_nodeget(struct mount * mp,struct vnode * uppervp,struct vnode * lowervp,struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct thread * td)211 unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
212 struct vnode *lowervp, struct vnode *dvp,
213 struct vnode **vpp, struct componentname *cnp,
214 struct thread *td)
215 {
216 struct unionfs_mount *ump;
217 struct unionfs_node *unp;
218 struct vnode *vp;
219 int error;
220 int lkflags;
221 enum vtype vt;
222 char *path;
223
224 ump = MOUNTTOUNIONFSMOUNT(mp);
225 lkflags = (cnp ? cnp->cn_lkflags : 0);
226 path = (cnp ? cnp->cn_nameptr : NULL);
227 *vpp = NULLVP;
228
229 if (uppervp == NULLVP && lowervp == NULLVP)
230 panic("unionfs_nodeget: upper and lower is null");
231
232 vt = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
233
234 /* If it has no ISLASTCN flag, path check is skipped. */
235 if (cnp && !(cnp->cn_flags & ISLASTCN))
236 path = NULL;
237
238 /* check the cache */
239 if (path != NULL && dvp != NULLVP && vt == VDIR) {
240 vp = unionfs_get_cached_vnode(uppervp, lowervp, dvp, path);
241 if (vp != NULLVP) {
242 vref(vp);
243 *vpp = vp;
244 goto unionfs_nodeget_out;
245 }
246 }
247
248 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
249 (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
250 /* dvp will be NULLVP only in case of root vnode. */
251 if (dvp == NULLVP)
252 return (EINVAL);
253 }
254 unp = malloc(sizeof(struct unionfs_node),
255 M_UNIONFSNODE, M_WAITOK | M_ZERO);
256
257 error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
258 if (error != 0) {
259 free(unp, M_UNIONFSNODE);
260 return (error);
261 }
262 error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
263 if (error != 0) {
264 free(unp, M_UNIONFSNODE);
265 return (error);
266 }
267 if (dvp != NULLVP)
268 vref(dvp);
269 if (uppervp != NULLVP)
270 vref(uppervp);
271 if (lowervp != NULLVP)
272 vref(lowervp);
273
274 if (vt == VDIR)
275 unp->un_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH,
276 &(unp->un_hashmask));
277
278 unp->un_vnode = vp;
279 unp->un_uppervp = uppervp;
280 unp->un_lowervp = lowervp;
281 unp->un_dvp = dvp;
282 if (uppervp != NULLVP)
283 vp->v_vnlock = uppervp->v_vnlock;
284 else
285 vp->v_vnlock = lowervp->v_vnlock;
286
287 if (path != NULL) {
288 unp->un_path = (char *)
289 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
290 bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
291 unp->un_path[cnp->cn_namelen] = '\0';
292 }
293 vp->v_type = vt;
294 vp->v_data = unp;
295
296 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
297 (lowervp != NULLVP && ump->um_lowervp == lowervp))
298 vp->v_vflag |= VV_ROOT;
299
300 if (path != NULL && dvp != NULLVP && vt == VDIR)
301 *vpp = unionfs_ins_cached_vnode(unp, dvp, path);
302 if ((*vpp) != NULLVP) {
303 if (dvp != NULLVP)
304 vrele(dvp);
305 if (uppervp != NULLVP)
306 vrele(uppervp);
307 if (lowervp != NULLVP)
308 vrele(lowervp);
309
310 unp->un_uppervp = NULLVP;
311 unp->un_lowervp = NULLVP;
312 unp->un_dvp = NULLVP;
313 vrele(vp);
314 vp = *vpp;
315 vref(vp);
316 } else
317 *vpp = vp;
318
319 unionfs_nodeget_out:
320 if (lkflags & LK_TYPE_MASK)
321 vn_lock(vp, lkflags | LK_RETRY);
322
323 return (0);
324 }
325
326 /*
327 * Clean up the unionfs node.
328 */
329 void
unionfs_noderem(struct vnode * vp,struct thread * td)330 unionfs_noderem(struct vnode *vp, struct thread *td)
331 {
332 int count;
333 struct unionfs_node *unp, *unp_t1, *unp_t2;
334 struct unionfs_node_hashhead *hd;
335 struct unionfs_node_status *unsp, *unsp_tmp;
336 struct vnode *lvp;
337 struct vnode *uvp;
338 struct vnode *dvp;
339
340 /*
341 * Use the interlock to protect the clearing of v_data to
342 * prevent faults in unionfs_lock().
343 */
344 VI_LOCK(vp);
345 unp = VTOUNIONFS(vp);
346 lvp = unp->un_lowervp;
347 uvp = unp->un_uppervp;
348 dvp = unp->un_dvp;
349 unp->un_lowervp = unp->un_uppervp = NULLVP;
350 vp->v_vnlock = &(vp->v_lock);
351 vp->v_data = NULL;
352 vp->v_object = NULL;
353 if (vp->v_writecount > 0) {
354 if (uvp != NULL)
355 VOP_ADD_WRITECOUNT(uvp, -vp->v_writecount);
356 else if (lvp != NULL)
357 VOP_ADD_WRITECOUNT(lvp, -vp->v_writecount);
358 } else if (vp->v_writecount < 0)
359 vp->v_writecount = 0;
360 VI_UNLOCK(vp);
361
362 if (lvp != NULLVP)
363 VOP_UNLOCK(lvp);
364 if (uvp != NULLVP)
365 VOP_UNLOCK(uvp);
366
367 if (dvp != NULLVP && unp->un_hash.le_prev != NULL)
368 unionfs_rem_cached_vnode(unp, dvp);
369
370 if (lockmgr(vp->v_vnlock, LK_EXCLUSIVE, VI_MTX(vp)) != 0)
371 panic("the lock for deletion is unacquirable.");
372
373 if (lvp != NULLVP)
374 vrele(lvp);
375 if (uvp != NULLVP)
376 vrele(uvp);
377 if (dvp != NULLVP) {
378 vrele(dvp);
379 unp->un_dvp = NULLVP;
380 }
381 if (unp->un_path != NULL) {
382 free(unp->un_path, M_UNIONFSPATH);
383 unp->un_path = NULL;
384 }
385
386 if (unp->un_hashtbl != NULL) {
387 for (count = 0; count <= unp->un_hashmask; count++) {
388 hd = unp->un_hashtbl + count;
389 LIST_FOREACH_SAFE(unp_t1, hd, un_hash, unp_t2) {
390 LIST_REMOVE(unp_t1, un_hash);
391 unp_t1->un_hash.le_next = NULL;
392 unp_t1->un_hash.le_prev = NULL;
393 }
394 }
395 hashdestroy(unp->un_hashtbl, M_UNIONFSHASH, unp->un_hashmask);
396 }
397
398 LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) {
399 LIST_REMOVE(unsp, uns_list);
400 free(unsp, M_TEMP);
401 }
402 free(unp, M_UNIONFSNODE);
403 }
404
405 /*
406 * Get the unionfs node status.
407 * You need exclusive lock this vnode.
408 */
409 void
unionfs_get_node_status(struct unionfs_node * unp,struct thread * td,struct unionfs_node_status ** unspp)410 unionfs_get_node_status(struct unionfs_node *unp, struct thread *td,
411 struct unionfs_node_status **unspp)
412 {
413 struct unionfs_node_status *unsp;
414 pid_t pid = td->td_proc->p_pid;
415
416 KASSERT(NULL != unspp, ("null pointer"));
417 ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
418
419 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
420 if (unsp->uns_pid == pid) {
421 *unspp = unsp;
422 return;
423 }
424 }
425
426 /* create a new unionfs node status */
427 unsp = malloc(sizeof(struct unionfs_node_status),
428 M_TEMP, M_WAITOK | M_ZERO);
429
430 unsp->uns_pid = pid;
431 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
432
433 *unspp = unsp;
434 }
435
436 /*
437 * Remove the unionfs node status, if you can.
438 * You need exclusive lock this vnode.
439 */
440 void
unionfs_tryrem_node_status(struct unionfs_node * unp,struct unionfs_node_status * unsp)441 unionfs_tryrem_node_status(struct unionfs_node *unp,
442 struct unionfs_node_status *unsp)
443 {
444 KASSERT(NULL != unsp, ("null pointer"));
445 ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
446
447 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
448 return;
449
450 LIST_REMOVE(unsp, uns_list);
451 free(unsp, M_TEMP);
452 }
453
454 /*
455 * Create upper node attr.
456 */
457 void
unionfs_create_uppervattr_core(struct unionfs_mount * ump,struct vattr * lva,struct vattr * uva,struct thread * td)458 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
459 struct vattr *lva,
460 struct vattr *uva,
461 struct thread *td)
462 {
463 VATTR_NULL(uva);
464 uva->va_type = lva->va_type;
465 uva->va_atime = lva->va_atime;
466 uva->va_mtime = lva->va_mtime;
467 uva->va_ctime = lva->va_ctime;
468
469 switch (ump->um_copymode) {
470 case UNIONFS_TRANSPARENT:
471 uva->va_mode = lva->va_mode;
472 uva->va_uid = lva->va_uid;
473 uva->va_gid = lva->va_gid;
474 break;
475 case UNIONFS_MASQUERADE:
476 if (ump->um_uid == lva->va_uid) {
477 uva->va_mode = lva->va_mode & 077077;
478 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
479 uva->va_uid = lva->va_uid;
480 uva->va_gid = lva->va_gid;
481 } else {
482 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
483 uva->va_uid = ump->um_uid;
484 uva->va_gid = ump->um_gid;
485 }
486 break;
487 default: /* UNIONFS_TRADITIONAL */
488 uva->va_mode = 0777 & ~td->td_proc->p_pd->pd_cmask;
489 uva->va_uid = ump->um_uid;
490 uva->va_gid = ump->um_gid;
491 break;
492 }
493 }
494
495 /*
496 * Create upper node attr.
497 */
498 int
unionfs_create_uppervattr(struct unionfs_mount * ump,struct vnode * lvp,struct vattr * uva,struct ucred * cred,struct thread * td)499 unionfs_create_uppervattr(struct unionfs_mount *ump,
500 struct vnode *lvp,
501 struct vattr *uva,
502 struct ucred *cred,
503 struct thread *td)
504 {
505 int error;
506 struct vattr lva;
507
508 if ((error = VOP_GETATTR(lvp, &lva, cred)))
509 return (error);
510
511 unionfs_create_uppervattr_core(ump, &lva, uva, td);
512
513 return (error);
514 }
515
516 /*
517 * relookup
518 *
519 * dvp should be locked on entry and will be locked on return.
520 *
521 * If an error is returned, *vpp will be invalid, otherwise it will hold a
522 * locked, referenced vnode. If *vpp == dvp then remember that only one
523 * LK_EXCLUSIVE lock is held.
524 */
525 int
unionfs_relookup(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct componentname * cn,struct thread * td,char * path,int pathlen,u_long nameiop)526 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
527 struct componentname *cnp, struct componentname *cn,
528 struct thread *td, char *path, int pathlen, u_long nameiop)
529 {
530 int error;
531
532 cn->cn_namelen = pathlen;
533 cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
534 bcopy(path, cn->cn_pnbuf, pathlen);
535 cn->cn_pnbuf[pathlen] = '\0';
536
537 cn->cn_nameiop = nameiop;
538 cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
539 cn->cn_lkflags = LK_EXCLUSIVE;
540 cn->cn_thread = td;
541 cn->cn_cred = cnp->cn_cred;
542
543 cn->cn_nameptr = cn->cn_pnbuf;
544
545 if (nameiop == DELETE)
546 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
547 else if (RENAME == nameiop)
548 cn->cn_flags |= (cnp->cn_flags & SAVESTART);
549 else if (nameiop == CREATE)
550 cn->cn_flags |= NOCACHE;
551
552 vref(dvp);
553 VOP_UNLOCK(dvp);
554
555 if ((error = relookup(dvp, vpp, cn))) {
556 uma_zfree(namei_zone, cn->cn_pnbuf);
557 cn->cn_flags &= ~HASBUF;
558 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
559 } else
560 vrele(dvp);
561
562 return (error);
563 }
564
565 /*
566 * relookup for CREATE namei operation.
567 *
568 * dvp is unionfs vnode. dvp should be locked.
569 *
570 * If it called 'unionfs_copyfile' function by unionfs_link etc,
571 * VOP_LOOKUP information is broken.
572 * So it need relookup in order to create link etc.
573 */
574 int
unionfs_relookup_for_create(struct vnode * dvp,struct componentname * cnp,struct thread * td)575 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp,
576 struct thread *td)
577 {
578 int error;
579 struct vnode *udvp;
580 struct vnode *vp;
581 struct componentname cn;
582
583 udvp = UNIONFSVPTOUPPERVP(dvp);
584 vp = NULLVP;
585
586 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
587 strlen(cnp->cn_nameptr), CREATE);
588 if (error)
589 return (error);
590
591 if (vp != NULLVP) {
592 if (udvp == vp)
593 vrele(vp);
594 else
595 vput(vp);
596
597 error = EEXIST;
598 }
599
600 if (cn.cn_flags & HASBUF) {
601 uma_zfree(namei_zone, cn.cn_pnbuf);
602 cn.cn_flags &= ~HASBUF;
603 }
604
605 if (!error) {
606 cn.cn_flags |= (cnp->cn_flags & HASBUF);
607 cnp->cn_flags = cn.cn_flags;
608 }
609
610 return (error);
611 }
612
613 /*
614 * relookup for DELETE namei operation.
615 *
616 * dvp is unionfs vnode. dvp should be locked.
617 */
618 int
unionfs_relookup_for_delete(struct vnode * dvp,struct componentname * cnp,struct thread * td)619 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp,
620 struct thread *td)
621 {
622 int error;
623 struct vnode *udvp;
624 struct vnode *vp;
625 struct componentname cn;
626
627 udvp = UNIONFSVPTOUPPERVP(dvp);
628 vp = NULLVP;
629
630 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
631 strlen(cnp->cn_nameptr), DELETE);
632 if (error)
633 return (error);
634
635 if (vp == NULLVP)
636 error = ENOENT;
637 else {
638 if (udvp == vp)
639 vrele(vp);
640 else
641 vput(vp);
642 }
643
644 if (cn.cn_flags & HASBUF) {
645 uma_zfree(namei_zone, cn.cn_pnbuf);
646 cn.cn_flags &= ~HASBUF;
647 }
648
649 if (!error) {
650 cn.cn_flags |= (cnp->cn_flags & HASBUF);
651 cnp->cn_flags = cn.cn_flags;
652 }
653
654 return (error);
655 }
656
657 /*
658 * relookup for RENAME namei operation.
659 *
660 * dvp is unionfs vnode. dvp should be locked.
661 */
662 int
unionfs_relookup_for_rename(struct vnode * dvp,struct componentname * cnp,struct thread * td)663 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp,
664 struct thread *td)
665 {
666 int error;
667 struct vnode *udvp;
668 struct vnode *vp;
669 struct componentname cn;
670
671 udvp = UNIONFSVPTOUPPERVP(dvp);
672 vp = NULLVP;
673
674 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
675 strlen(cnp->cn_nameptr), RENAME);
676 if (error)
677 return (error);
678
679 if (vp != NULLVP) {
680 if (udvp == vp)
681 vrele(vp);
682 else
683 vput(vp);
684 }
685
686 if (cn.cn_flags & HASBUF) {
687 uma_zfree(namei_zone, cn.cn_pnbuf);
688 cn.cn_flags &= ~HASBUF;
689 }
690
691 if (!error) {
692 cn.cn_flags |= (cnp->cn_flags & HASBUF);
693 cnp->cn_flags = cn.cn_flags;
694 }
695
696 return (error);
697
698 }
699
700 /*
701 * Update the unionfs_node.
702 *
703 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
704 * uvp's lock and lower's lock will be unlocked.
705 */
706 static void
unionfs_node_update(struct unionfs_node * unp,struct vnode * uvp,struct thread * td)707 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
708 struct thread *td)
709 {
710 unsigned count, lockrec;
711 struct vnode *vp;
712 struct vnode *lvp;
713 struct vnode *dvp;
714
715 vp = UNIONFSTOV(unp);
716 lvp = unp->un_lowervp;
717 ASSERT_VOP_ELOCKED(lvp, "unionfs_node_update");
718 dvp = unp->un_dvp;
719
720 /*
721 * lock update
722 */
723 VI_LOCK(vp);
724 unp->un_uppervp = uvp;
725 vp->v_vnlock = uvp->v_vnlock;
726 VI_UNLOCK(vp);
727 lockrec = lvp->v_vnlock->lk_recurse;
728 for (count = 0; count < lockrec; count++)
729 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
730
731 /*
732 * cache update
733 */
734 if (unp->un_path != NULL && dvp != NULLVP && vp->v_type == VDIR) {
735 static struct unionfs_node_hashhead *hd;
736
737 VI_LOCK(dvp);
738 hd = unionfs_get_hashhead(dvp, unp->un_path);
739 LIST_REMOVE(unp, un_hash);
740 LIST_INSERT_HEAD(hd, unp, un_hash);
741 VI_UNLOCK(dvp);
742 }
743 }
744
745 /*
746 * Create a new shadow dir.
747 *
748 * udvp should be locked on entry and will be locked on return.
749 *
750 * If no error returned, unp will be updated.
751 */
752 int
unionfs_mkshadowdir(struct unionfs_mount * ump,struct vnode * udvp,struct unionfs_node * unp,struct componentname * cnp,struct thread * td)753 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
754 struct unionfs_node *unp, struct componentname *cnp,
755 struct thread *td)
756 {
757 int error;
758 struct vnode *lvp;
759 struct vnode *uvp;
760 struct vattr va;
761 struct vattr lva;
762 struct nameidata nd;
763 struct mount *mp;
764 struct ucred *cred;
765 struct ucred *credbk;
766 struct uidinfo *rootinfo;
767
768 if (unp->un_uppervp != NULLVP)
769 return (EEXIST);
770
771 lvp = unp->un_lowervp;
772 uvp = NULLVP;
773 credbk = cnp->cn_cred;
774
775 /* Authority change to root */
776 rootinfo = uifind((uid_t)0);
777 cred = crdup(cnp->cn_cred);
778 change_euid(cred, rootinfo);
779 change_ruid(cred, rootinfo);
780 change_svuid(cred, (uid_t)0);
781 uifree(rootinfo);
782 cnp->cn_cred = cred;
783
784 memset(&nd.ni_cnd, 0, sizeof(struct componentname));
785 NDPREINIT(&nd);
786
787 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
788 goto unionfs_mkshadowdir_abort;
789
790 if ((error = unionfs_relookup(udvp, &uvp, cnp, &nd.ni_cnd, td,
791 cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
792 goto unionfs_mkshadowdir_abort;
793 if (uvp != NULLVP) {
794 if (udvp == uvp)
795 vrele(uvp);
796 else
797 vput(uvp);
798
799 error = EEXIST;
800 goto unionfs_mkshadowdir_free_out;
801 }
802
803 if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
804 goto unionfs_mkshadowdir_free_out;
805 unionfs_create_uppervattr_core(ump, &lva, &va, td);
806
807 error = VOP_MKDIR(udvp, &uvp, &nd.ni_cnd, &va);
808
809 if (!error) {
810 unionfs_node_update(unp, uvp, td);
811
812 /*
813 * XXX The bug which cannot set uid/gid was corrected.
814 * Ignore errors.
815 */
816 va.va_type = VNON;
817 VOP_SETATTR(uvp, &va, nd.ni_cnd.cn_cred);
818 }
819 vn_finished_write(mp);
820
821 unionfs_mkshadowdir_free_out:
822 if (nd.ni_cnd.cn_flags & HASBUF) {
823 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
824 nd.ni_cnd.cn_flags &= ~HASBUF;
825 }
826
827 unionfs_mkshadowdir_abort:
828 cnp->cn_cred = credbk;
829 crfree(cred);
830
831 return (error);
832 }
833
834 /*
835 * Create a new whiteout.
836 *
837 * dvp should be locked on entry and will be locked on return.
838 */
839 int
unionfs_mkwhiteout(struct vnode * dvp,struct componentname * cnp,struct thread * td,char * path)840 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
841 struct thread *td, char *path)
842 {
843 int error;
844 struct vnode *wvp;
845 struct nameidata nd;
846 struct mount *mp;
847
848 if (path == NULL)
849 path = cnp->cn_nameptr;
850
851 wvp = NULLVP;
852 NDPREINIT(&nd);
853 if ((error = unionfs_relookup(dvp, &wvp, cnp, &nd.ni_cnd, td, path,
854 strlen(path), CREATE)))
855 return (error);
856 if (wvp != NULLVP) {
857 if (nd.ni_cnd.cn_flags & HASBUF) {
858 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
859 nd.ni_cnd.cn_flags &= ~HASBUF;
860 }
861 if (dvp == wvp)
862 vrele(wvp);
863 else
864 vput(wvp);
865
866 return (EEXIST);
867 }
868
869 if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
870 goto unionfs_mkwhiteout_free_out;
871 error = VOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE);
872
873 vn_finished_write(mp);
874
875 unionfs_mkwhiteout_free_out:
876 if (nd.ni_cnd.cn_flags & HASBUF) {
877 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
878 nd.ni_cnd.cn_flags &= ~HASBUF;
879 }
880
881 return (error);
882 }
883
884 /*
885 * Create a new vnode for create a new shadow file.
886 *
887 * If an error is returned, *vpp will be invalid, otherwise it will hold a
888 * locked, referenced and opened vnode.
889 *
890 * unp is never updated.
891 */
892 static int
unionfs_vn_create_on_upper(struct vnode ** vpp,struct vnode * udvp,struct unionfs_node * unp,struct vattr * uvap,struct thread * td)893 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
894 struct unionfs_node *unp, struct vattr *uvap,
895 struct thread *td)
896 {
897 struct unionfs_mount *ump;
898 struct vnode *vp;
899 struct vnode *lvp;
900 struct ucred *cred;
901 struct vattr lva;
902 int fmode;
903 int error;
904 struct nameidata nd;
905
906 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
907 vp = NULLVP;
908 lvp = unp->un_lowervp;
909 cred = td->td_ucred;
910 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
911 error = 0;
912
913 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
914 return (error);
915 unionfs_create_uppervattr_core(ump, &lva, uvap, td);
916
917 if (unp->un_path == NULL)
918 panic("unionfs: un_path is null");
919
920 nd.ni_cnd.cn_namelen = strlen(unp->un_path);
921 nd.ni_cnd.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
922 bcopy(unp->un_path, nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_namelen + 1);
923 nd.ni_cnd.cn_nameiop = CREATE;
924 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME |
925 ISLASTCN;
926 nd.ni_cnd.cn_lkflags = LK_EXCLUSIVE;
927 nd.ni_cnd.cn_thread = td;
928 nd.ni_cnd.cn_cred = cred;
929 nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
930 NDPREINIT(&nd);
931
932 vref(udvp);
933 if ((error = relookup(udvp, &vp, &nd.ni_cnd)) != 0)
934 goto unionfs_vn_create_on_upper_free_out2;
935 vrele(udvp);
936
937 if (vp != NULLVP) {
938 if (vp == udvp)
939 vrele(vp);
940 else
941 vput(vp);
942 error = EEXIST;
943 goto unionfs_vn_create_on_upper_free_out1;
944 }
945
946 if ((error = VOP_CREATE(udvp, &vp, &nd.ni_cnd, uvap)) != 0)
947 goto unionfs_vn_create_on_upper_free_out1;
948
949 if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) {
950 vput(vp);
951 goto unionfs_vn_create_on_upper_free_out1;
952 }
953 error = VOP_ADD_WRITECOUNT(vp, 1);
954 CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", __func__, vp,
955 vp->v_writecount);
956 if (error == 0) {
957 *vpp = vp;
958 } else {
959 VOP_CLOSE(vp, fmode, cred, td);
960 }
961
962 unionfs_vn_create_on_upper_free_out1:
963 VOP_UNLOCK(udvp);
964
965 unionfs_vn_create_on_upper_free_out2:
966 if (nd.ni_cnd.cn_flags & HASBUF) {
967 uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
968 nd.ni_cnd.cn_flags &= ~HASBUF;
969 }
970
971 return (error);
972 }
973
974 /*
975 * Copy from lvp to uvp.
976 *
977 * lvp and uvp should be locked and opened on entry and will be locked and
978 * opened on return.
979 */
980 static int
unionfs_copyfile_core(struct vnode * lvp,struct vnode * uvp,struct ucred * cred,struct thread * td)981 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
982 struct ucred *cred, struct thread *td)
983 {
984 int error;
985 off_t offset;
986 int count;
987 int bufoffset;
988 char *buf;
989 struct uio uio;
990 struct iovec iov;
991
992 error = 0;
993 memset(&uio, 0, sizeof(uio));
994
995 uio.uio_td = td;
996 uio.uio_segflg = UIO_SYSSPACE;
997 uio.uio_offset = 0;
998
999 buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
1000
1001 while (error == 0) {
1002 offset = uio.uio_offset;
1003
1004 uio.uio_iov = &iov;
1005 uio.uio_iovcnt = 1;
1006 iov.iov_base = buf;
1007 iov.iov_len = MAXBSIZE;
1008 uio.uio_resid = iov.iov_len;
1009 uio.uio_rw = UIO_READ;
1010
1011 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
1012 break;
1013 if ((count = MAXBSIZE - uio.uio_resid) == 0)
1014 break;
1015
1016 bufoffset = 0;
1017 while (bufoffset < count) {
1018 uio.uio_iov = &iov;
1019 uio.uio_iovcnt = 1;
1020 iov.iov_base = buf + bufoffset;
1021 iov.iov_len = count - bufoffset;
1022 uio.uio_offset = offset + bufoffset;
1023 uio.uio_resid = iov.iov_len;
1024 uio.uio_rw = UIO_WRITE;
1025
1026 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
1027 break;
1028
1029 bufoffset += (count - bufoffset) - uio.uio_resid;
1030 }
1031
1032 uio.uio_offset = offset + bufoffset;
1033 }
1034
1035 free(buf, M_TEMP);
1036
1037 return (error);
1038 }
1039
1040 /*
1041 * Copy file from lower to upper.
1042 *
1043 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
1044 * docopy.
1045 *
1046 * If no error returned, unp will be updated.
1047 */
1048 int
unionfs_copyfile(struct unionfs_node * unp,int docopy,struct ucred * cred,struct thread * td)1049 unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
1050 struct thread *td)
1051 {
1052 int error;
1053 struct mount *mp;
1054 struct vnode *udvp;
1055 struct vnode *lvp;
1056 struct vnode *uvp;
1057 struct vattr uva;
1058
1059 lvp = unp->un_lowervp;
1060 uvp = NULLVP;
1061
1062 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
1063 return (EROFS);
1064 if (unp->un_dvp == NULLVP)
1065 return (EINVAL);
1066 if (unp->un_uppervp != NULLVP)
1067 return (EEXIST);
1068 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
1069 if (udvp == NULLVP)
1070 return (EROFS);
1071 if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
1072 return (EROFS);
1073
1074 error = VOP_ACCESS(lvp, VREAD, cred, td);
1075 if (error != 0)
1076 return (error);
1077
1078 if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
1079 return (error);
1080 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
1081 if (error != 0) {
1082 vn_finished_write(mp);
1083 return (error);
1084 }
1085
1086 if (docopy != 0) {
1087 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
1088 if (error == 0) {
1089 error = unionfs_copyfile_core(lvp, uvp, cred, td);
1090 VOP_CLOSE(lvp, FREAD, cred, td);
1091 }
1092 }
1093 VOP_CLOSE(uvp, FWRITE, cred, td);
1094 VOP_ADD_WRITECOUNT_CHECKED(uvp, -1);
1095 CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", __func__, uvp,
1096 uvp->v_writecount);
1097
1098 vn_finished_write(mp);
1099
1100 if (error == 0) {
1101 /* Reset the attributes. Ignore errors. */
1102 uva.va_type = VNON;
1103 VOP_SETATTR(uvp, &uva, cred);
1104 }
1105
1106 unionfs_node_update(unp, uvp, td);
1107
1108 return (error);
1109 }
1110
1111 /*
1112 * It checks whether vp can rmdir. (check empty)
1113 *
1114 * vp is unionfs vnode.
1115 * vp should be locked.
1116 */
1117 int
unionfs_check_rmdir(struct vnode * vp,struct ucred * cred,struct thread * td)1118 unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
1119 {
1120 int error;
1121 int eofflag;
1122 int lookuperr;
1123 struct vnode *uvp;
1124 struct vnode *lvp;
1125 struct vnode *tvp;
1126 struct vattr va;
1127 struct componentname cn;
1128 /*
1129 * The size of buf needs to be larger than DIRBLKSIZ.
1130 */
1131 char buf[256 * 6];
1132 struct dirent *dp;
1133 struct dirent *edp;
1134 struct uio uio;
1135 struct iovec iov;
1136
1137 ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
1138
1139 eofflag = 0;
1140 uvp = UNIONFSVPTOUPPERVP(vp);
1141 lvp = UNIONFSVPTOLOWERVP(vp);
1142
1143 /* check opaque */
1144 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
1145 return (error);
1146 if (va.va_flags & OPAQUE)
1147 return (0);
1148
1149 /* open vnode */
1150 #ifdef MAC
1151 if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
1152 return (error);
1153 #endif
1154 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
1155 return (error);
1156 if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
1157 return (error);
1158
1159 uio.uio_rw = UIO_READ;
1160 uio.uio_segflg = UIO_SYSSPACE;
1161 uio.uio_td = td;
1162 uio.uio_offset = 0;
1163
1164 #ifdef MAC
1165 error = mac_vnode_check_readdir(td->td_ucred, lvp);
1166 #endif
1167 while (!error && !eofflag) {
1168 iov.iov_base = buf;
1169 iov.iov_len = sizeof(buf);
1170 uio.uio_iov = &iov;
1171 uio.uio_iovcnt = 1;
1172 uio.uio_resid = iov.iov_len;
1173
1174 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
1175 if (error != 0)
1176 break;
1177 if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
1178 #ifdef DIAGNOSTIC
1179 panic("bad readdir response from lower FS.");
1180 #endif
1181 break;
1182 }
1183
1184 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
1185 for (dp = (struct dirent*)buf; !error && dp < edp;
1186 dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
1187 if (dp->d_type == DT_WHT || dp->d_fileno == 0 ||
1188 (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
1189 (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
1190 continue;
1191
1192 cn.cn_namelen = dp->d_namlen;
1193 cn.cn_pnbuf = NULL;
1194 cn.cn_nameptr = dp->d_name;
1195 cn.cn_nameiop = LOOKUP;
1196 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1197 cn.cn_lkflags = LK_EXCLUSIVE;
1198 cn.cn_thread = td;
1199 cn.cn_cred = cred;
1200
1201 /*
1202 * check entry in lower.
1203 * Sometimes, readdir function returns
1204 * wrong entry.
1205 */
1206 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
1207
1208 if (!lookuperr)
1209 vput(tvp);
1210 else
1211 continue; /* skip entry */
1212
1213 /*
1214 * check entry
1215 * If it has no exist/whiteout entry in upper,
1216 * directory is not empty.
1217 */
1218 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1219 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
1220
1221 if (!lookuperr)
1222 vput(tvp);
1223
1224 /* ignore exist or whiteout entry */
1225 if (!lookuperr ||
1226 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
1227 continue;
1228
1229 error = ENOTEMPTY;
1230 }
1231 }
1232
1233 /* close vnode */
1234 VOP_CLOSE(vp, FREAD, cred, td);
1235
1236 return (error);
1237 }
1238
1239 #ifdef DIAGNOSTIC
1240
1241 struct vnode *
unionfs_checkuppervp(struct vnode * vp,char * fil,int lno)1242 unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
1243 {
1244 struct unionfs_node *unp;
1245
1246 unp = VTOUNIONFS(vp);
1247
1248 #ifdef notyet
1249 if (vp->v_op != unionfs_vnodeop_p) {
1250 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
1251 #ifdef KDB
1252 kdb_enter(KDB_WHY_UNIONFS,
1253 "unionfs_checkuppervp: on non-unionfs-node.\n");
1254 #endif
1255 panic("unionfs_checkuppervp");
1256 }
1257 #endif
1258 return (unp->un_uppervp);
1259 }
1260
1261 struct vnode *
unionfs_checklowervp(struct vnode * vp,char * fil,int lno)1262 unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
1263 {
1264 struct unionfs_node *unp;
1265
1266 unp = VTOUNIONFS(vp);
1267
1268 #ifdef notyet
1269 if (vp->v_op != unionfs_vnodeop_p) {
1270 printf("unionfs_checklowervp: on non-unionfs-node.\n");
1271 #ifdef KDB
1272 kdb_enter(KDB_WHY_UNIONFS,
1273 "unionfs_checklowervp: on non-unionfs-node.\n");
1274 #endif
1275 panic("unionfs_checklowervp");
1276 }
1277 #endif
1278 return (unp->un_lowervp);
1279 }
1280 #endif
1281