1*84d9c625SLionel Sambuc /* $NetBSD: ext2fs_readwrite.c,v 1.64 2013/06/23 07:28:37 dholland Exp $ */ 2d65f6f70SBen Gras 3d65f6f70SBen Gras /*- 4d65f6f70SBen Gras * Copyright (c) 1993 5d65f6f70SBen Gras * The Regents of the University of California. All rights reserved. 6d65f6f70SBen Gras * 7d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without 8d65f6f70SBen Gras * modification, are permitted provided that the following conditions 9d65f6f70SBen Gras * are met: 10d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright 11d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer. 12d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright 13d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the 14d65f6f70SBen Gras * documentation and/or other materials provided with the distribution. 15d65f6f70SBen Gras * 3. Neither the name of the University nor the names of its contributors 16d65f6f70SBen Gras * may be used to endorse or promote products derived from this software 17d65f6f70SBen Gras * without specific prior written permission. 18d65f6f70SBen Gras * 19d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20d65f6f70SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21d65f6f70SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22d65f6f70SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23d65f6f70SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24d65f6f70SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25d65f6f70SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26d65f6f70SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27d65f6f70SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29d65f6f70SBen Gras * SUCH DAMAGE. 30d65f6f70SBen Gras * 31d65f6f70SBen Gras * @(#)ufs_readwrite.c 8.8 (Berkeley) 8/4/94 32d65f6f70SBen Gras * Modified for ext2fs by Manuel Bouyer. 33d65f6f70SBen Gras */ 34d65f6f70SBen Gras 35d65f6f70SBen Gras /*- 36d65f6f70SBen Gras * Copyright (c) 1997 Manuel Bouyer. 37d65f6f70SBen Gras * 38d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without 39d65f6f70SBen Gras * modification, are permitted provided that the following conditions 40d65f6f70SBen Gras * are met: 41d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright 42d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer. 43d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright 44d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the 45d65f6f70SBen Gras * documentation and/or other materials provided with the distribution. 46d65f6f70SBen Gras * 47d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48d65f6f70SBen Gras * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49d65f6f70SBen Gras * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50d65f6f70SBen Gras * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51d65f6f70SBen Gras * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52d65f6f70SBen Gras * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53d65f6f70SBen Gras * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54d65f6f70SBen Gras * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55d65f6f70SBen Gras * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56d65f6f70SBen Gras * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57d65f6f70SBen Gras * 58d65f6f70SBen Gras * @(#)ufs_readwrite.c 8.8 (Berkeley) 8/4/94 59d65f6f70SBen Gras * Modified for ext2fs by Manuel Bouyer. 60d65f6f70SBen Gras */ 61d65f6f70SBen Gras 62d65f6f70SBen Gras #include <sys/cdefs.h> 63*84d9c625SLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.64 2013/06/23 07:28:37 dholland Exp $"); 64d65f6f70SBen Gras 65d65f6f70SBen Gras #include <sys/param.h> 66d65f6f70SBen Gras #include <sys/systm.h> 67d65f6f70SBen Gras #include <sys/resourcevar.h> 68d65f6f70SBen Gras #include <sys/kernel.h> 69d65f6f70SBen Gras #include <sys/file.h> 70d65f6f70SBen Gras #include <sys/stat.h> 71d65f6f70SBen Gras #include <sys/buf.h> 72d65f6f70SBen Gras #include <sys/proc.h> 73d65f6f70SBen Gras #include <sys/mount.h> 74d65f6f70SBen Gras #include <sys/vnode.h> 75d65f6f70SBen Gras #include <sys/malloc.h> 76d65f6f70SBen Gras #include <sys/signalvar.h> 77d65f6f70SBen Gras #include <sys/kauth.h> 78d65f6f70SBen Gras 79d65f6f70SBen Gras #include <ufs/ufs/inode.h> 80d65f6f70SBen Gras #include <ufs/ufs/ufsmount.h> 81d65f6f70SBen Gras #include <ufs/ufs/ufs_extern.h> 82d65f6f70SBen Gras #include <ufs/ext2fs/ext2fs.h> 83d65f6f70SBen Gras #include <ufs/ext2fs/ext2fs_extern.h> 84d65f6f70SBen Gras 85d65f6f70SBen Gras 86d65f6f70SBen Gras #define doclusterread 0 /* XXX underway */ 87d65f6f70SBen Gras #define doclusterwrite 0 88d65f6f70SBen Gras 89d65f6f70SBen Gras /* 90d65f6f70SBen Gras * Vnode op for reading. 91d65f6f70SBen Gras */ 92d65f6f70SBen Gras /* ARGSUSED */ 93d65f6f70SBen Gras int 94d65f6f70SBen Gras ext2fs_read(void *v) 95d65f6f70SBen Gras { 96d65f6f70SBen Gras struct vop_read_args /* { 97d65f6f70SBen Gras struct vnode *a_vp; 98d65f6f70SBen Gras struct uio *a_uio; 99d65f6f70SBen Gras int a_ioflag; 100d65f6f70SBen Gras kauth_cred_t a_cred; 101d65f6f70SBen Gras } */ *ap = v; 102d65f6f70SBen Gras struct vnode *vp; 103d65f6f70SBen Gras struct inode *ip; 104d65f6f70SBen Gras struct uio *uio; 105d65f6f70SBen Gras struct m_ext2fs *fs; 106d65f6f70SBen Gras struct buf *bp; 107d65f6f70SBen Gras struct ufsmount *ump; 108d65f6f70SBen Gras vsize_t bytelen; 109d65f6f70SBen Gras daddr_t lbn, nextlbn; 110d65f6f70SBen Gras off_t bytesinfile; 111d65f6f70SBen Gras long size, xfersize, blkoffset; 112d65f6f70SBen Gras int error; 113d65f6f70SBen Gras 114d65f6f70SBen Gras vp = ap->a_vp; 115d65f6f70SBen Gras ip = VTOI(vp); 116d65f6f70SBen Gras ump = ip->i_ump; 117d65f6f70SBen Gras uio = ap->a_uio; 118d65f6f70SBen Gras error = 0; 119d65f6f70SBen Gras 120d65f6f70SBen Gras #ifdef DIAGNOSTIC 121d65f6f70SBen Gras if (uio->uio_rw != UIO_READ) 122d65f6f70SBen Gras panic("%s: mode", "ext2fs_read"); 123d65f6f70SBen Gras 124d65f6f70SBen Gras if (vp->v_type == VLNK) { 125d65f6f70SBen Gras if (ext2fs_size(ip) < ump->um_maxsymlinklen || 126*84d9c625SLionel Sambuc (ump->um_maxsymlinklen == 0 && ext2fs_nblock(ip) == 0)) 127d65f6f70SBen Gras panic("%s: short symlink", "ext2fs_read"); 128d65f6f70SBen Gras } else if (vp->v_type != VREG && vp->v_type != VDIR) 129d65f6f70SBen Gras panic("%s: type %d", "ext2fs_read", vp->v_type); 130d65f6f70SBen Gras #endif 131d65f6f70SBen Gras fs = ip->i_e2fs; 132d65f6f70SBen Gras if ((uint64_t)uio->uio_offset > ump->um_maxfilesize) 133d65f6f70SBen Gras return (EFBIG); 134d65f6f70SBen Gras if (uio->uio_resid == 0) 135d65f6f70SBen Gras return (0); 136d65f6f70SBen Gras if (uio->uio_offset >= ext2fs_size(ip)) 137d65f6f70SBen Gras goto out; 138d65f6f70SBen Gras 139d65f6f70SBen Gras if (vp->v_type == VREG) { 140d65f6f70SBen Gras const int advice = IO_ADV_DECODE(ap->a_ioflag); 141d65f6f70SBen Gras 142d65f6f70SBen Gras while (uio->uio_resid > 0) { 143d65f6f70SBen Gras bytelen = MIN(ext2fs_size(ip) - uio->uio_offset, 144d65f6f70SBen Gras uio->uio_resid); 145d65f6f70SBen Gras if (bytelen == 0) 146d65f6f70SBen Gras break; 147d65f6f70SBen Gras 148d65f6f70SBen Gras error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, 149d65f6f70SBen Gras UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 150d65f6f70SBen Gras if (error) 151d65f6f70SBen Gras break; 152d65f6f70SBen Gras } 153d65f6f70SBen Gras goto out; 154d65f6f70SBen Gras } 155d65f6f70SBen Gras 156d65f6f70SBen Gras for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { 157d65f6f70SBen Gras bytesinfile = ext2fs_size(ip) - uio->uio_offset; 158d65f6f70SBen Gras if (bytesinfile <= 0) 159d65f6f70SBen Gras break; 160*84d9c625SLionel Sambuc lbn = ext2_lblkno(fs, uio->uio_offset); 161d65f6f70SBen Gras nextlbn = lbn + 1; 162d65f6f70SBen Gras size = fs->e2fs_bsize; 163*84d9c625SLionel Sambuc blkoffset = ext2_blkoff(fs, uio->uio_offset); 164d65f6f70SBen Gras xfersize = fs->e2fs_bsize - blkoffset; 165d65f6f70SBen Gras if (uio->uio_resid < xfersize) 166d65f6f70SBen Gras xfersize = uio->uio_resid; 167d65f6f70SBen Gras if (bytesinfile < xfersize) 168d65f6f70SBen Gras xfersize = bytesinfile; 169d65f6f70SBen Gras 170*84d9c625SLionel Sambuc if (ext2_lblktosize(fs, nextlbn) >= ext2fs_size(ip)) 171d65f6f70SBen Gras error = bread(vp, lbn, size, NOCRED, 0, &bp); 172d65f6f70SBen Gras else { 173d65f6f70SBen Gras int nextsize = fs->e2fs_bsize; 174d65f6f70SBen Gras error = breadn(vp, lbn, 175d65f6f70SBen Gras size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp); 176d65f6f70SBen Gras } 177d65f6f70SBen Gras if (error) 178d65f6f70SBen Gras break; 179d65f6f70SBen Gras 180d65f6f70SBen Gras /* 181d65f6f70SBen Gras * We should only get non-zero b_resid when an I/O error 182d65f6f70SBen Gras * has occurred, which should cause us to break above. 183d65f6f70SBen Gras * However, if the short read did not cause an error, 184d65f6f70SBen Gras * then we want to ensure that we do not uiomove bad 185d65f6f70SBen Gras * or uninitialized data. 186d65f6f70SBen Gras */ 187d65f6f70SBen Gras size -= bp->b_resid; 188d65f6f70SBen Gras if (size < xfersize) { 189d65f6f70SBen Gras if (size == 0) 190d65f6f70SBen Gras break; 191d65f6f70SBen Gras xfersize = size; 192d65f6f70SBen Gras } 193d65f6f70SBen Gras error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); 194d65f6f70SBen Gras if (error) 195d65f6f70SBen Gras break; 196d65f6f70SBen Gras brelse(bp, 0); 197d65f6f70SBen Gras } 198d65f6f70SBen Gras if (bp != NULL) 199d65f6f70SBen Gras brelse(bp, 0); 200d65f6f70SBen Gras 201d65f6f70SBen Gras out: 202d65f6f70SBen Gras if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) { 203d65f6f70SBen Gras ip->i_flag |= IN_ACCESS; 204d65f6f70SBen Gras if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) 205d65f6f70SBen Gras error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT); 206d65f6f70SBen Gras } 207d65f6f70SBen Gras return (error); 208d65f6f70SBen Gras } 209d65f6f70SBen Gras 210d65f6f70SBen Gras /* 211d65f6f70SBen Gras * Vnode op for writing. 212d65f6f70SBen Gras */ 213d65f6f70SBen Gras int 214d65f6f70SBen Gras ext2fs_write(void *v) 215d65f6f70SBen Gras { 216d65f6f70SBen Gras struct vop_write_args /* { 217d65f6f70SBen Gras struct vnode *a_vp; 218d65f6f70SBen Gras struct uio *a_uio; 219d65f6f70SBen Gras int a_ioflag; 220d65f6f70SBen Gras kauth_cred_t a_cred; 221d65f6f70SBen Gras } */ *ap = v; 222d65f6f70SBen Gras struct vnode *vp; 223d65f6f70SBen Gras struct uio *uio; 224d65f6f70SBen Gras struct inode *ip; 225d65f6f70SBen Gras struct m_ext2fs *fs; 226d65f6f70SBen Gras struct buf *bp; 227d65f6f70SBen Gras struct ufsmount *ump; 228d65f6f70SBen Gras daddr_t lbn; 229d65f6f70SBen Gras off_t osize; 230d65f6f70SBen Gras int blkoffset, error, flags, ioflag, resid, xfersize; 231d65f6f70SBen Gras vsize_t bytelen; 232d65f6f70SBen Gras off_t oldoff = 0; /* XXX */ 233d65f6f70SBen Gras bool async; 234d65f6f70SBen Gras int extended = 0; 235d65f6f70SBen Gras int advice; 236d65f6f70SBen Gras 237d65f6f70SBen Gras ioflag = ap->a_ioflag; 238d65f6f70SBen Gras advice = IO_ADV_DECODE(ioflag); 239d65f6f70SBen Gras uio = ap->a_uio; 240d65f6f70SBen Gras vp = ap->a_vp; 241d65f6f70SBen Gras ip = VTOI(vp); 242d65f6f70SBen Gras ump = ip->i_ump; 243d65f6f70SBen Gras error = 0; 244d65f6f70SBen Gras 245d65f6f70SBen Gras #ifdef DIAGNOSTIC 246d65f6f70SBen Gras if (uio->uio_rw != UIO_WRITE) 247d65f6f70SBen Gras panic("%s: mode", "ext2fs_write"); 248d65f6f70SBen Gras #endif 249d65f6f70SBen Gras 250d65f6f70SBen Gras switch (vp->v_type) { 251d65f6f70SBen Gras case VREG: 252d65f6f70SBen Gras if (ioflag & IO_APPEND) 253d65f6f70SBen Gras uio->uio_offset = ext2fs_size(ip); 254d65f6f70SBen Gras if ((ip->i_e2fs_flags & EXT2_APPEND) && 255d65f6f70SBen Gras uio->uio_offset != ext2fs_size(ip)) 256d65f6f70SBen Gras return (EPERM); 257d65f6f70SBen Gras /* FALLTHROUGH */ 258d65f6f70SBen Gras case VLNK: 259d65f6f70SBen Gras break; 260d65f6f70SBen Gras case VDIR: 261d65f6f70SBen Gras if ((ioflag & IO_SYNC) == 0) 262d65f6f70SBen Gras panic("%s: nonsync dir write", "ext2fs_write"); 263d65f6f70SBen Gras break; 264d65f6f70SBen Gras default: 265d65f6f70SBen Gras panic("%s: type", "ext2fs_write"); 266d65f6f70SBen Gras } 267d65f6f70SBen Gras 268d65f6f70SBen Gras fs = ip->i_e2fs; 269d65f6f70SBen Gras if (uio->uio_offset < 0 || 270d65f6f70SBen Gras (uint64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize) 271d65f6f70SBen Gras return (EFBIG); 272d65f6f70SBen Gras if (uio->uio_resid == 0) 273d65f6f70SBen Gras return (0); 274d65f6f70SBen Gras 275d65f6f70SBen Gras async = vp->v_mount->mnt_flag & MNT_ASYNC; 276d65f6f70SBen Gras resid = uio->uio_resid; 277d65f6f70SBen Gras osize = ext2fs_size(ip); 278d65f6f70SBen Gras 279d65f6f70SBen Gras if (vp->v_type == VREG) { 280d65f6f70SBen Gras while (uio->uio_resid > 0) { 281d65f6f70SBen Gras oldoff = uio->uio_offset; 282*84d9c625SLionel Sambuc blkoffset = ext2_blkoff(fs, uio->uio_offset); 283d65f6f70SBen Gras bytelen = MIN(fs->e2fs_bsize - blkoffset, 284d65f6f70SBen Gras uio->uio_resid); 285d65f6f70SBen Gras 286d65f6f70SBen Gras if (vp->v_size < oldoff + bytelen) { 287d65f6f70SBen Gras uvm_vnp_setwritesize(vp, oldoff + bytelen); 288d65f6f70SBen Gras } 289d65f6f70SBen Gras error = ufs_balloc_range(vp, uio->uio_offset, 290d65f6f70SBen Gras bytelen, ap->a_cred, 0); 291d65f6f70SBen Gras if (error) 292d65f6f70SBen Gras break; 293d65f6f70SBen Gras error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, 294d65f6f70SBen Gras UBC_WRITE | UBC_UNMAP_FLAG(vp)); 295d65f6f70SBen Gras if (error) 296d65f6f70SBen Gras break; 297d65f6f70SBen Gras 298d65f6f70SBen Gras /* 299d65f6f70SBen Gras * update UVM's notion of the size now that we've 300d65f6f70SBen Gras * copied the data into the vnode's pages. 301d65f6f70SBen Gras */ 302d65f6f70SBen Gras 303d65f6f70SBen Gras if (vp->v_size < uio->uio_offset) { 304d65f6f70SBen Gras uvm_vnp_setsize(vp, uio->uio_offset); 305d65f6f70SBen Gras extended = 1; 306d65f6f70SBen Gras } 307d65f6f70SBen Gras 308d65f6f70SBen Gras /* 309d65f6f70SBen Gras * flush what we just wrote if necessary. 310d65f6f70SBen Gras * XXXUBC simplistic async flushing. 311d65f6f70SBen Gras */ 312d65f6f70SBen Gras 313d65f6f70SBen Gras if (!async && oldoff >> 16 != uio->uio_offset >> 16) { 314d65f6f70SBen Gras mutex_enter(vp->v_interlock); 315d65f6f70SBen Gras error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, 316*84d9c625SLionel Sambuc (uio->uio_offset >> 16) << 16, 317*84d9c625SLionel Sambuc PGO_CLEANIT | PGO_LAZY); 318d65f6f70SBen Gras } 319d65f6f70SBen Gras } 320d65f6f70SBen Gras if (error == 0 && ioflag & IO_SYNC) { 321d65f6f70SBen Gras mutex_enter(vp->v_interlock); 322d65f6f70SBen Gras error = VOP_PUTPAGES(vp, trunc_page(oldoff), 323*84d9c625SLionel Sambuc round_page(ext2_blkroundup(fs, uio->uio_offset)), 324d65f6f70SBen Gras PGO_CLEANIT | PGO_SYNCIO); 325d65f6f70SBen Gras } 326d65f6f70SBen Gras 327d65f6f70SBen Gras goto out; 328d65f6f70SBen Gras } 329d65f6f70SBen Gras 330d65f6f70SBen Gras flags = ioflag & IO_SYNC ? B_SYNC : 0; 331d65f6f70SBen Gras for (error = 0; uio->uio_resid > 0;) { 332*84d9c625SLionel Sambuc lbn = ext2_lblkno(fs, uio->uio_offset); 333*84d9c625SLionel Sambuc blkoffset = ext2_blkoff(fs, uio->uio_offset); 334d65f6f70SBen Gras xfersize = MIN(fs->e2fs_bsize - blkoffset, uio->uio_resid); 335d65f6f70SBen Gras if (xfersize < fs->e2fs_bsize) 336d65f6f70SBen Gras flags |= B_CLRBUF; 337d65f6f70SBen Gras else 338d65f6f70SBen Gras flags &= ~B_CLRBUF; 339d65f6f70SBen Gras error = ext2fs_balloc(ip, 340d65f6f70SBen Gras lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); 341d65f6f70SBen Gras if (error) 342d65f6f70SBen Gras break; 343d65f6f70SBen Gras if (ext2fs_size(ip) < uio->uio_offset + xfersize) { 344d65f6f70SBen Gras error = ext2fs_setsize(ip, uio->uio_offset + xfersize); 345d65f6f70SBen Gras if (error) 346d65f6f70SBen Gras break; 347d65f6f70SBen Gras } 348d65f6f70SBen Gras error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); 349d65f6f70SBen Gras 350d65f6f70SBen Gras /* 351d65f6f70SBen Gras * update UVM's notion of the size now that we've 352d65f6f70SBen Gras * copied the data into the vnode's pages. 353d65f6f70SBen Gras */ 354d65f6f70SBen Gras 355d65f6f70SBen Gras if (vp->v_size < uio->uio_offset) { 356d65f6f70SBen Gras uvm_vnp_setsize(vp, uio->uio_offset); 357d65f6f70SBen Gras extended = 1; 358d65f6f70SBen Gras } 359d65f6f70SBen Gras 360d65f6f70SBen Gras if (ioflag & IO_SYNC) 361d65f6f70SBen Gras (void)bwrite(bp); 362d65f6f70SBen Gras else if (xfersize + blkoffset == fs->e2fs_bsize) 363d65f6f70SBen Gras bawrite(bp); 364d65f6f70SBen Gras else 365d65f6f70SBen Gras bdwrite(bp); 366d65f6f70SBen Gras if (error || xfersize == 0) 367d65f6f70SBen Gras break; 368d65f6f70SBen Gras } 369d65f6f70SBen Gras 370d65f6f70SBen Gras /* 371d65f6f70SBen Gras * If we successfully wrote any data, and we are not the superuser 372d65f6f70SBen Gras * we clear the setuid and setgid bits as a precaution against 373d65f6f70SBen Gras * tampering. 374d65f6f70SBen Gras */ 375d65f6f70SBen Gras 376d65f6f70SBen Gras out: 377d65f6f70SBen Gras ip->i_flag |= IN_CHANGE | IN_UPDATE; 378d65f6f70SBen Gras if (vp->v_mount->mnt_flag & MNT_RELATIME) 379d65f6f70SBen Gras ip->i_flag |= IN_ACCESS; 380*84d9c625SLionel Sambuc if (resid > uio->uio_resid && ap->a_cred) { 381*84d9c625SLionel Sambuc if (ip->i_e2fs_mode & ISUID) { 382*84d9c625SLionel Sambuc if (kauth_authorize_vnode(ap->a_cred, 383*84d9c625SLionel Sambuc KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) 384*84d9c625SLionel Sambuc ip->i_e2fs_mode &= ISUID; 385*84d9c625SLionel Sambuc } 386*84d9c625SLionel Sambuc 387*84d9c625SLionel Sambuc if (ip->i_e2fs_mode & ISGID) { 388*84d9c625SLionel Sambuc if (kauth_authorize_vnode(ap->a_cred, 389*84d9c625SLionel Sambuc KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) 390*84d9c625SLionel Sambuc ip->i_e2fs_mode &= ~ISGID; 391*84d9c625SLionel Sambuc } 392*84d9c625SLionel Sambuc } 393d65f6f70SBen Gras if (resid > uio->uio_resid) 394d65f6f70SBen Gras VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); 395d65f6f70SBen Gras if (error) { 396d65f6f70SBen Gras (void) ext2fs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred); 397d65f6f70SBen Gras uio->uio_offset -= resid - uio->uio_resid; 398d65f6f70SBen Gras uio->uio_resid = resid; 399d65f6f70SBen Gras } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) 400d65f6f70SBen Gras error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT); 401d65f6f70SBen Gras KASSERT(vp->v_size == ext2fs_size(ip)); 402d65f6f70SBen Gras return (error); 403d65f6f70SBen Gras } 404