Module Name: src Committed By: hannken Date: Wed Aug 10 06:27:02 UTC 2011
Modified Files: src/sys/fs/union: union_vnops.c src/tests/fs/union: t_pr.c Log Message: For devices, sockets and fifos ignore setting the file size to zero to make open(..., O_TRUNC) happy and allow them to write through the lower layer. Fixes PR #43560 (writing to null device in unionfs fails) To generate a diff of this commit: cvs rdiff -u -r1.42 -r1.43 src/sys/fs/union/union_vnops.c cvs rdiff -u -r1.7 -r1.8 src/tests/fs/union/t_pr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/union/union_vnops.c diff -u src/sys/fs/union/union_vnops.c:1.42 src/sys/fs/union/union_vnops.c:1.43 --- src/sys/fs/union/union_vnops.c:1.42 Sun Aug 7 06:01:51 2011 +++ src/sys/fs/union/union_vnops.c Wed Aug 10 06:27:02 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: union_vnops.c,v 1.42 2011/08/07 06:01:51 hannken Exp $ */ +/* $NetBSD: union_vnops.c,v 1.43 2011/08/10 06:27:02 hannken Exp $ */ /* * Copyright (c) 1992, 1993, 1994, 1995 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.42 2011/08/07 06:01:51 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.43 2011/08/10 06:27:02 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -888,12 +888,14 @@ struct vattr *vap = ap->a_vap; struct vnode *vp = ap->a_vp; struct union_node *un = VTOUNION(vp); + bool size_only; /* All but va_size are VNOVAL. */ int error; - if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || - vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && - (vp->v_mount->mnt_flag & MNT_RDONLY)) + size_only = (vap->va_flags == VNOVAL && vap->va_uid == (uid_t)VNOVAL && + vap->va_gid == (gid_t)VNOVAL && vap->va_atime.tv_sec == VNOVAL && + vap->va_mtime.tv_sec == VNOVAL && vap->va_mode == (mode_t)VNOVAL); + + if (!size_only && (vp->v_mount->mnt_flag & MNT_RDONLY)) return (EROFS); if (vap->va_size != VNOVAL) { switch (vp->v_type) { @@ -931,8 +933,9 @@ } /* - * Try to set attributes in upper layer, - * otherwise return read-only filesystem error. + * Try to set attributes in upper layer, ignore size change to zero + * for devices to handle O_TRUNC and return read-only filesystem error + * otherwise. */ if (un->un_uppervp != NULLVP) { FIXUP(un); @@ -940,7 +943,22 @@ if ((error == 0) && (vap->va_size != VNOVAL)) union_newsize(ap->a_vp, vap->va_size, VNOVAL); } else { - error = EROFS; + KASSERT(un->un_lowervp != NULLVP); + switch (un->un_lowervp->v_type) { + case VCHR: + case VBLK: + case VSOCK: + case VFIFO: + if (size_only && + (vap->va_size == 0 || vap->va_size == VNOVAL)) + error = 0; + else + error = EROFS; + break; + default: + error = EROFS; + break; + } } return (error); @@ -1003,8 +1021,23 @@ struct union_node *un = VTOUNION(ap->a_vp); vp = UPPERVP(ap->a_vp); - if (vp == NULLVP) - panic("union: missing upper layer in write"); + if (vp == NULLVP) { + vp = LOWERVP(ap->a_vp); + KASSERT(vp != NULL); + switch (vp->v_type) { + case VBLK: + case VCHR: + case VSOCK: + case VFIFO: + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, + ap->a_cred); + VOP_UNLOCK(vp); + return error; + default: + panic("union: missing upper layer in write"); + } + } FIXUP(un); error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); Index: src/tests/fs/union/t_pr.c diff -u src/tests/fs/union/t_pr.c:1.7 src/tests/fs/union/t_pr.c:1.8 --- src/tests/fs/union/t_pr.c:1.7 Sat Jul 3 13:37:22 2010 +++ src/tests/fs/union/t_pr.c Wed Aug 10 06:27:02 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: t_pr.c,v 1.7 2010/07/03 13:37:22 pooka Exp $ */ +/* $NetBSD: t_pr.c,v 1.8 2011/08/10 06:27:02 hannken Exp $ */ #include <sys/types.h> #include <sys/mount.h> @@ -50,7 +50,6 @@ unionargs.target = __UNCONST("/Tunion2/B"); unionargs.mntflags = UNMNT_BELOW; - /* atf_tc_expect_signal(-1, "PR kern/23986"); */ rump_sys_mount(MOUNT_UNION, "/Tunion", 0,&unionargs,sizeof(unionargs)); } @@ -64,7 +63,7 @@ ATF_TC_BODY(devnull1, tc) { struct union_args unionargs; - int fd; + int fd, res; rump_init(); @@ -80,14 +79,12 @@ fd = rump_sys_open("/mp/null", O_WRONLY | O_CREAT | O_TRUNC); - atf_tc_expect_fail("PR kern/43560"); - if (fd == -1 && errno == EROFS) { - atf_tc_fail("open returned EROFS"); - } else if (fd == -1) { - atf_tc_expect_pass(); - atf_tc_fail_errno("open fail"); - } + if (fd == -1) + atf_tc_fail_errno("open"); + res = rump_sys_write(fd, &fd, sizeof(fd)); + if (res != sizeof(fd)) + atf_tc_fail("write"); } ATF_TC(devnull2); @@ -100,7 +97,7 @@ ATF_TC_BODY(devnull2, tc) { struct union_args unionargs; - int fd; + int fd, res; rump_init(); @@ -118,8 +115,9 @@ if (fd == -1) atf_tc_fail_errno("open"); - atf_tc_expect_signal(-1, "PR kern/43560"); - rump_sys_write(fd, &fd, sizeof(fd)); + res = rump_sys_write(fd, &fd, sizeof(fd)); + if (res != sizeof(fd)) + atf_tc_fail("write"); } ATF_TP_ADD_TCS(tp)