1*84d9c625SLionel Sambuc /* $NetBSD: lfs_inode.c,v 1.136 2013/10/17 21:01:08 christos Exp $ */ 2d65f6f70SBen Gras 3d65f6f70SBen Gras /*- 4d65f6f70SBen Gras * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc. 5d65f6f70SBen Gras * All rights reserved. 6d65f6f70SBen Gras * 7d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation 8d65f6f70SBen Gras * by Konrad E. Schroder <perseant@hhhh.org>. 9d65f6f70SBen Gras * 10d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without 11d65f6f70SBen Gras * modification, are permitted provided that the following conditions 12d65f6f70SBen Gras * are met: 13d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright 14d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer. 15d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright 16d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the 17d65f6f70SBen Gras * documentation and/or other materials provided with the distribution. 18d65f6f70SBen Gras * 19d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20d65f6f70SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21d65f6f70SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22d65f6f70SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23d65f6f70SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24d65f6f70SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25d65f6f70SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26d65f6f70SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27d65f6f70SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28d65f6f70SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29d65f6f70SBen Gras * POSSIBILITY OF SUCH DAMAGE. 30d65f6f70SBen Gras */ 31d65f6f70SBen Gras /* 32d65f6f70SBen Gras * Copyright (c) 1986, 1989, 1991, 1993 33d65f6f70SBen Gras * The Regents of the University of California. All rights reserved. 34d65f6f70SBen Gras * 35d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without 36d65f6f70SBen Gras * modification, are permitted provided that the following conditions 37d65f6f70SBen Gras * are met: 38d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright 39d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer. 40d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright 41d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the 42d65f6f70SBen Gras * documentation and/or other materials provided with the distribution. 43d65f6f70SBen Gras * 3. Neither the name of the University nor the names of its contributors 44d65f6f70SBen Gras * may be used to endorse or promote products derived from this software 45d65f6f70SBen Gras * without specific prior written permission. 46d65f6f70SBen Gras * 47d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48d65f6f70SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49d65f6f70SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50d65f6f70SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51d65f6f70SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52d65f6f70SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53d65f6f70SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54d65f6f70SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55d65f6f70SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57d65f6f70SBen Gras * SUCH DAMAGE. 58d65f6f70SBen Gras * 59d65f6f70SBen Gras * @(#)lfs_inode.c 8.9 (Berkeley) 5/8/95 60d65f6f70SBen Gras */ 61d65f6f70SBen Gras 62d65f6f70SBen Gras #include <sys/cdefs.h> 63*84d9c625SLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.136 2013/10/17 21:01:08 christos Exp $"); 64d65f6f70SBen Gras 65d65f6f70SBen Gras #if defined(_KERNEL_OPT) 66d65f6f70SBen Gras #include "opt_quota.h" 67d65f6f70SBen Gras #endif 68d65f6f70SBen Gras 69d65f6f70SBen Gras #include <sys/param.h> 70d65f6f70SBen Gras #include <sys/systm.h> 71d65f6f70SBen Gras #include <sys/mount.h> 72d65f6f70SBen Gras #include <sys/malloc.h> 73d65f6f70SBen Gras #include <sys/proc.h> 74d65f6f70SBen Gras #include <sys/file.h> 75d65f6f70SBen Gras #include <sys/buf.h> 76d65f6f70SBen Gras #include <sys/vnode.h> 77d65f6f70SBen Gras #include <sys/kernel.h> 78d65f6f70SBen Gras #include <sys/trace.h> 79d65f6f70SBen Gras #include <sys/resourcevar.h> 80d65f6f70SBen Gras #include <sys/kauth.h> 81d65f6f70SBen Gras 82*84d9c625SLionel Sambuc #include <ufs/lfs/ulfs_quotacommon.h> 83*84d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h> 84*84d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h> 85*84d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h> 86d65f6f70SBen Gras 87d65f6f70SBen Gras #include <ufs/lfs/lfs.h> 88d65f6f70SBen Gras #include <ufs/lfs/lfs_extern.h> 89*84d9c625SLionel Sambuc #include <ufs/lfs/lfs_kernel.h> 90d65f6f70SBen Gras 91d65f6f70SBen Gras static int lfs_update_seguse(struct lfs *, struct inode *ip, long, size_t); 92d65f6f70SBen Gras static int lfs_indirtrunc (struct inode *, daddr_t, daddr_t, 93d65f6f70SBen Gras daddr_t, int, long *, long *, long *, size_t *); 94d65f6f70SBen Gras static int lfs_blkfree (struct lfs *, struct inode *, daddr_t, size_t, long *, size_t *); 95d65f6f70SBen Gras static int lfs_vtruncbuf(struct vnode *, daddr_t, bool, int); 96d65f6f70SBen Gras 97d65f6f70SBen Gras /* Search a block for a specific dinode. */ 98*84d9c625SLionel Sambuc struct ulfs1_dinode * 99d65f6f70SBen Gras lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp) 100d65f6f70SBen Gras { 101*84d9c625SLionel Sambuc struct ulfs1_dinode *dip = (struct ulfs1_dinode *)bp->b_data; 102*84d9c625SLionel Sambuc struct ulfs1_dinode *ldip, *fin; 103d65f6f70SBen Gras 104d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs); 105d65f6f70SBen Gras /* 106d65f6f70SBen Gras * Read the inode block backwards, since later versions of the 107d65f6f70SBen Gras * inode will supercede earlier ones. Though it is unlikely, it is 108d65f6f70SBen Gras * possible that the same inode will appear in the same inode block. 109d65f6f70SBen Gras */ 110*84d9c625SLionel Sambuc fin = dip + LFS_INOPB(fs); 111d65f6f70SBen Gras for (ldip = fin - 1; ldip >= dip; --ldip) 112d65f6f70SBen Gras if (ldip->di_inumber == ino) 113d65f6f70SBen Gras return (ldip); 114d65f6f70SBen Gras 115d65f6f70SBen Gras printf("searched %d entries\n", (int)(fin - dip)); 116d65f6f70SBen Gras printf("offset is 0x%x (seg %d)\n", fs->lfs_offset, 117*84d9c625SLionel Sambuc lfs_dtosn(fs, fs->lfs_offset)); 118d65f6f70SBen Gras printf("block is 0x%llx (seg %lld)\n", 119*84d9c625SLionel Sambuc (unsigned long long)LFS_DBTOFSB(fs, bp->b_blkno), 120*84d9c625SLionel Sambuc (long long)lfs_dtosn(fs, LFS_DBTOFSB(fs, bp->b_blkno))); 121d65f6f70SBen Gras 122d65f6f70SBen Gras return NULL; 123d65f6f70SBen Gras } 124d65f6f70SBen Gras 125d65f6f70SBen Gras int 126d65f6f70SBen Gras lfs_update(struct vnode *vp, const struct timespec *acc, 127d65f6f70SBen Gras const struct timespec *mod, int updflags) 128d65f6f70SBen Gras { 129d65f6f70SBen Gras struct inode *ip; 130*84d9c625SLionel Sambuc struct lfs *fs = VFSTOULFS(vp->v_mount)->um_lfs; 131d65f6f70SBen Gras int flags; 132d65f6f70SBen Gras 133d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs); 134d65f6f70SBen Gras if (vp->v_mount->mnt_flag & MNT_RDONLY) 135d65f6f70SBen Gras return (0); 136d65f6f70SBen Gras ip = VTOI(vp); 137d65f6f70SBen Gras 138d65f6f70SBen Gras /* 139d65f6f70SBen Gras * If we are called from vinvalbuf, and the file's blocks have 140d65f6f70SBen Gras * already been scheduled for writing, but the writes have not 141d65f6f70SBen Gras * yet completed, lfs_vflush will not be called, and vinvalbuf 142d65f6f70SBen Gras * will cause a panic. So, we must wait until any pending write 143d65f6f70SBen Gras * for our inode completes, if we are called with UPDATE_WAIT set. 144d65f6f70SBen Gras */ 145d65f6f70SBen Gras mutex_enter(vp->v_interlock); 146d65f6f70SBen Gras while ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT && 147d65f6f70SBen Gras WRITEINPROG(vp)) { 148d65f6f70SBen Gras DLOG((DLOG_SEG, "lfs_update: sleeping on ino %d" 149d65f6f70SBen Gras " (in progress)\n", ip->i_number)); 150d65f6f70SBen Gras cv_wait(&vp->v_cv, vp->v_interlock); 151d65f6f70SBen Gras } 152d65f6f70SBen Gras mutex_exit(vp->v_interlock); 153d65f6f70SBen Gras LFS_ITIMES(ip, acc, mod, NULL); 154d65f6f70SBen Gras if (updflags & UPDATE_CLOSE) 155d65f6f70SBen Gras flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING); 156d65f6f70SBen Gras else 157d65f6f70SBen Gras flags = ip->i_flag & (IN_MODIFIED | IN_CLEANING); 158d65f6f70SBen Gras if (flags == 0) 159d65f6f70SBen Gras return (0); 160d65f6f70SBen Gras 161d65f6f70SBen Gras /* If sync, push back the vnode and any dirty blocks it may have. */ 162d65f6f70SBen Gras if ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT) { 163d65f6f70SBen Gras /* Avoid flushing VU_DIROP. */ 164d65f6f70SBen Gras mutex_enter(&lfs_lock); 165d65f6f70SBen Gras ++fs->lfs_diropwait; 166d65f6f70SBen Gras while (vp->v_uflag & VU_DIROP) { 167d65f6f70SBen Gras DLOG((DLOG_DIROP, "lfs_update: sleeping on inode %d" 168d65f6f70SBen Gras " (dirops)\n", ip->i_number)); 169d65f6f70SBen Gras DLOG((DLOG_DIROP, "lfs_update: vflags 0x%x, iflags" 170d65f6f70SBen Gras " 0x%x\n", 171d65f6f70SBen Gras vp->v_iflag | vp->v_vflag | vp->v_uflag, 172d65f6f70SBen Gras ip->i_flag)); 173d65f6f70SBen Gras if (fs->lfs_dirops == 0) 174d65f6f70SBen Gras lfs_flush_fs(fs, SEGM_SYNC); 175d65f6f70SBen Gras else 176d65f6f70SBen Gras mtsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync", 177d65f6f70SBen Gras 0, &lfs_lock); 178d65f6f70SBen Gras /* XXX KS - by falling out here, are we writing the vn 179d65f6f70SBen Gras twice? */ 180d65f6f70SBen Gras } 181d65f6f70SBen Gras --fs->lfs_diropwait; 182d65f6f70SBen Gras mutex_exit(&lfs_lock); 183d65f6f70SBen Gras return lfs_vflush(vp); 184d65f6f70SBen Gras } 185d65f6f70SBen Gras return 0; 186d65f6f70SBen Gras } 187d65f6f70SBen Gras 188d65f6f70SBen Gras #define SINGLE 0 /* index of single indirect block */ 189d65f6f70SBen Gras #define DOUBLE 1 /* index of double indirect block */ 190d65f6f70SBen Gras #define TRIPLE 2 /* index of triple indirect block */ 191d65f6f70SBen Gras /* 192d65f6f70SBen Gras * Truncate the inode oip to at most length size, freeing the 193d65f6f70SBen Gras * disk blocks. 194d65f6f70SBen Gras */ 195*84d9c625SLionel Sambuc /* VOP_BWRITE 1 + ULFS_NIADDR + lfs_balloc == 2 + 2*ULFS_NIADDR times */ 196d65f6f70SBen Gras 197d65f6f70SBen Gras int 198d65f6f70SBen Gras lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred) 199d65f6f70SBen Gras { 200d65f6f70SBen Gras daddr_t lastblock; 201d65f6f70SBen Gras struct inode *oip = VTOI(ovp); 202*84d9c625SLionel Sambuc daddr_t bn, lbn, lastiblock[ULFS_NIADDR], indir_lbn[ULFS_NIADDR]; 203d65f6f70SBen Gras /* XXX ondisk32 */ 204*84d9c625SLionel Sambuc int32_t newblks[ULFS_NDADDR + ULFS_NIADDR]; 205d65f6f70SBen Gras struct lfs *fs; 206d65f6f70SBen Gras struct buf *bp; 207d65f6f70SBen Gras int offset, size, level; 208d65f6f70SBen Gras long count, rcount, blocksreleased = 0, real_released = 0; 209d65f6f70SBen Gras int i, nblocks; 210d65f6f70SBen Gras int aflags, error, allerror = 0; 211d65f6f70SBen Gras off_t osize; 212d65f6f70SBen Gras long lastseg; 213d65f6f70SBen Gras size_t bc; 214d65f6f70SBen Gras int obufsize, odb; 215d65f6f70SBen Gras int usepc; 216d65f6f70SBen Gras 217d65f6f70SBen Gras if (ovp->v_type == VCHR || ovp->v_type == VBLK || 218d65f6f70SBen Gras ovp->v_type == VFIFO || ovp->v_type == VSOCK) { 219d65f6f70SBen Gras KASSERT(oip->i_size == 0); 220d65f6f70SBen Gras return 0; 221d65f6f70SBen Gras } 222d65f6f70SBen Gras 223d65f6f70SBen Gras if (length < 0) 224d65f6f70SBen Gras return (EINVAL); 225d65f6f70SBen Gras 226d65f6f70SBen Gras /* 227d65f6f70SBen Gras * Just return and not update modification times. 228d65f6f70SBen Gras */ 229d65f6f70SBen Gras if (oip->i_size == length) { 230d65f6f70SBen Gras /* still do a uvm_vnp_setsize() as writesize may be larger */ 231d65f6f70SBen Gras uvm_vnp_setsize(ovp, length); 232d65f6f70SBen Gras return (0); 233d65f6f70SBen Gras } 234d65f6f70SBen Gras 235*84d9c625SLionel Sambuc fs = oip->i_lfs; 236*84d9c625SLionel Sambuc 237d65f6f70SBen Gras if (ovp->v_type == VLNK && 238*84d9c625SLionel Sambuc (oip->i_size < fs->um_maxsymlinklen || 239*84d9c625SLionel Sambuc (fs->um_maxsymlinklen == 0 && 240d65f6f70SBen Gras oip->i_ffs1_blocks == 0))) { 241d65f6f70SBen Gras #ifdef DIAGNOSTIC 242d65f6f70SBen Gras if (length != 0) 243d65f6f70SBen Gras panic("lfs_truncate: partial truncate of symlink"); 244d65f6f70SBen Gras #endif 245d65f6f70SBen Gras memset((char *)SHORTLINK(oip), 0, (u_int)oip->i_size); 246d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = 0; 247d65f6f70SBen Gras oip->i_flag |= IN_CHANGE | IN_UPDATE; 248d65f6f70SBen Gras return (lfs_update(ovp, NULL, NULL, 0)); 249d65f6f70SBen Gras } 250d65f6f70SBen Gras if (oip->i_size == length) { 251d65f6f70SBen Gras oip->i_flag |= IN_CHANGE | IN_UPDATE; 252d65f6f70SBen Gras return (lfs_update(ovp, NULL, NULL, 0)); 253d65f6f70SBen Gras } 254d65f6f70SBen Gras lfs_imtime(fs); 255d65f6f70SBen Gras osize = oip->i_size; 256d65f6f70SBen Gras usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode); 257d65f6f70SBen Gras 258d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs); 259d65f6f70SBen Gras /* 260d65f6f70SBen Gras * Lengthen the size of the file. We must ensure that the 261d65f6f70SBen Gras * last byte of the file is allocated. Since the smallest 262d65f6f70SBen Gras * value of osize is 0, length will be at least 1. 263d65f6f70SBen Gras */ 264d65f6f70SBen Gras if (osize < length) { 265*84d9c625SLionel Sambuc if (length > fs->um_maxfilesize) 266d65f6f70SBen Gras return (EFBIG); 267d65f6f70SBen Gras aflags = B_CLRBUF; 268d65f6f70SBen Gras if (ioflag & IO_SYNC) 269d65f6f70SBen Gras aflags |= B_SYNC; 270d65f6f70SBen Gras if (usepc) { 271*84d9c625SLionel Sambuc if (lfs_lblkno(fs, osize) < ULFS_NDADDR && 272*84d9c625SLionel Sambuc lfs_lblkno(fs, osize) != lfs_lblkno(fs, length) && 273*84d9c625SLionel Sambuc lfs_blkroundup(fs, osize) != osize) { 274d65f6f70SBen Gras off_t eob; 275d65f6f70SBen Gras 276*84d9c625SLionel Sambuc eob = lfs_blkroundup(fs, osize); 277d65f6f70SBen Gras uvm_vnp_setwritesize(ovp, eob); 278*84d9c625SLionel Sambuc error = ulfs_balloc_range(ovp, osize, 279d65f6f70SBen Gras eob - osize, cred, aflags); 280d65f6f70SBen Gras if (error) { 281d65f6f70SBen Gras (void) lfs_truncate(ovp, osize, 282d65f6f70SBen Gras ioflag & IO_SYNC, cred); 283d65f6f70SBen Gras return error; 284d65f6f70SBen Gras } 285d65f6f70SBen Gras if (ioflag & IO_SYNC) { 286d65f6f70SBen Gras mutex_enter(ovp->v_interlock); 287d65f6f70SBen Gras VOP_PUTPAGES(ovp, 288d65f6f70SBen Gras trunc_page(osize & fs->lfs_bmask), 289d65f6f70SBen Gras round_page(eob), 290d65f6f70SBen Gras PGO_CLEANIT | PGO_SYNCIO); 291d65f6f70SBen Gras } 292d65f6f70SBen Gras } 293d65f6f70SBen Gras uvm_vnp_setwritesize(ovp, length); 294*84d9c625SLionel Sambuc error = ulfs_balloc_range(ovp, length - 1, 1, cred, 295d65f6f70SBen Gras aflags); 296d65f6f70SBen Gras if (error) { 297d65f6f70SBen Gras (void) lfs_truncate(ovp, osize, 298d65f6f70SBen Gras ioflag & IO_SYNC, cred); 299d65f6f70SBen Gras return error; 300d65f6f70SBen Gras } 301d65f6f70SBen Gras uvm_vnp_setsize(ovp, length); 302d65f6f70SBen Gras oip->i_flag |= IN_CHANGE | IN_UPDATE; 303d65f6f70SBen Gras KASSERT(ovp->v_size == oip->i_size); 304*84d9c625SLionel Sambuc oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1; 305d65f6f70SBen Gras return (lfs_update(ovp, NULL, NULL, 0)); 306d65f6f70SBen Gras } else { 307d65f6f70SBen Gras error = lfs_reserve(fs, ovp, NULL, 308*84d9c625SLionel Sambuc lfs_btofsb(fs, (ULFS_NIADDR + 2) << fs->lfs_bshift)); 309d65f6f70SBen Gras if (error) 310d65f6f70SBen Gras return (error); 311d65f6f70SBen Gras error = lfs_balloc(ovp, length - 1, 1, cred, 312d65f6f70SBen Gras aflags, &bp); 313d65f6f70SBen Gras lfs_reserve(fs, ovp, NULL, 314*84d9c625SLionel Sambuc -lfs_btofsb(fs, (ULFS_NIADDR + 2) << fs->lfs_bshift)); 315d65f6f70SBen Gras if (error) 316d65f6f70SBen Gras return (error); 317d65f6f70SBen Gras oip->i_ffs1_size = oip->i_size = length; 318d65f6f70SBen Gras uvm_vnp_setsize(ovp, length); 319d65f6f70SBen Gras (void) VOP_BWRITE(bp->b_vp, bp); 320d65f6f70SBen Gras oip->i_flag |= IN_CHANGE | IN_UPDATE; 321*84d9c625SLionel Sambuc oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1; 322d65f6f70SBen Gras return (lfs_update(ovp, NULL, NULL, 0)); 323d65f6f70SBen Gras } 324d65f6f70SBen Gras } 325d65f6f70SBen Gras 326d65f6f70SBen Gras if ((error = lfs_reserve(fs, ovp, NULL, 327*84d9c625SLionel Sambuc lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift))) != 0) 328d65f6f70SBen Gras return (error); 329d65f6f70SBen Gras 330d65f6f70SBen Gras /* 331d65f6f70SBen Gras * Shorten the size of the file. If the file is not being 332d65f6f70SBen Gras * truncated to a block boundary, the contents of the 333d65f6f70SBen Gras * partial block following the end of the file must be 334d65f6f70SBen Gras * zero'ed in case it ever becomes accessible again because 335d65f6f70SBen Gras * of subsequent file growth. Directories however are not 336d65f6f70SBen Gras * zero'ed as they should grow back initialized to empty. 337d65f6f70SBen Gras */ 338*84d9c625SLionel Sambuc offset = lfs_blkoff(fs, length); 339d65f6f70SBen Gras lastseg = -1; 340d65f6f70SBen Gras bc = 0; 341d65f6f70SBen Gras 342d65f6f70SBen Gras if (ovp != fs->lfs_ivnode) 343d65f6f70SBen Gras lfs_seglock(fs, SEGM_PROT); 344d65f6f70SBen Gras if (offset == 0) { 345d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = length; 346d65f6f70SBen Gras } else if (!usepc) { 347*84d9c625SLionel Sambuc lbn = lfs_lblkno(fs, length); 348d65f6f70SBen Gras aflags = B_CLRBUF; 349d65f6f70SBen Gras if (ioflag & IO_SYNC) 350d65f6f70SBen Gras aflags |= B_SYNC; 351d65f6f70SBen Gras error = lfs_balloc(ovp, length - 1, 1, cred, aflags, &bp); 352d65f6f70SBen Gras if (error) { 353d65f6f70SBen Gras lfs_reserve(fs, ovp, NULL, 354*84d9c625SLionel Sambuc -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift)); 355d65f6f70SBen Gras goto errout; 356d65f6f70SBen Gras } 357d65f6f70SBen Gras obufsize = bp->b_bufsize; 358*84d9c625SLionel Sambuc odb = lfs_btofsb(fs, bp->b_bcount); 359d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = length; 360*84d9c625SLionel Sambuc size = lfs_blksize(fs, oip, lbn); 361d65f6f70SBen Gras if (ovp->v_type != VDIR) 362d65f6f70SBen Gras memset((char *)bp->b_data + offset, 0, 363d65f6f70SBen Gras (u_int)(size - offset)); 364d65f6f70SBen Gras allocbuf(bp, size, 1); 365d65f6f70SBen Gras if ((bp->b_flags & B_LOCKED) != 0 && bp->b_iodone == NULL) { 366d65f6f70SBen Gras mutex_enter(&lfs_lock); 367d65f6f70SBen Gras locked_queue_bytes -= obufsize - bp->b_bufsize; 368d65f6f70SBen Gras mutex_exit(&lfs_lock); 369d65f6f70SBen Gras } 370d65f6f70SBen Gras if (bp->b_oflags & BO_DELWRI) 371*84d9c625SLionel Sambuc fs->lfs_avail += odb - lfs_btofsb(fs, size); 372d65f6f70SBen Gras (void) VOP_BWRITE(bp->b_vp, bp); 373d65f6f70SBen Gras } else { /* vp->v_type == VREG && length < osize && offset != 0 */ 374d65f6f70SBen Gras /* 375d65f6f70SBen Gras * When truncating a regular file down to a non-block-aligned 376d65f6f70SBen Gras * size, we must zero the part of last block which is past 377d65f6f70SBen Gras * the new EOF. We must synchronously flush the zeroed pages 378d65f6f70SBen Gras * to disk since the new pages will be invalidated as soon 379d65f6f70SBen Gras * as we inform the VM system of the new, smaller size. 380d65f6f70SBen Gras * We must do this before acquiring the GLOCK, since fetching 381d65f6f70SBen Gras * the pages will acquire the GLOCK internally. 382d65f6f70SBen Gras * So there is a window where another thread could see a whole 383d65f6f70SBen Gras * zeroed page past EOF, but that's life. 384d65f6f70SBen Gras */ 385d65f6f70SBen Gras daddr_t xlbn; 386d65f6f70SBen Gras voff_t eoz; 387d65f6f70SBen Gras 388d65f6f70SBen Gras aflags = ioflag & IO_SYNC ? B_SYNC : 0; 389*84d9c625SLionel Sambuc error = ulfs_balloc_range(ovp, length - 1, 1, cred, aflags); 390d65f6f70SBen Gras if (error) { 391d65f6f70SBen Gras lfs_reserve(fs, ovp, NULL, 392*84d9c625SLionel Sambuc -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift)); 393d65f6f70SBen Gras goto errout; 394d65f6f70SBen Gras } 395*84d9c625SLionel Sambuc xlbn = lfs_lblkno(fs, length); 396*84d9c625SLionel Sambuc size = lfs_blksize(fs, oip, xlbn); 397*84d9c625SLionel Sambuc eoz = MIN(lfs_lblktosize(fs, xlbn) + size, osize); 398d65f6f70SBen Gras ubc_zerorange(&ovp->v_uobj, length, eoz - length, 399d65f6f70SBen Gras UBC_UNMAP_FLAG(ovp)); 400d65f6f70SBen Gras if (round_page(eoz) > round_page(length)) { 401d65f6f70SBen Gras mutex_enter(ovp->v_interlock); 402d65f6f70SBen Gras error = VOP_PUTPAGES(ovp, round_page(length), 403d65f6f70SBen Gras round_page(eoz), 404d65f6f70SBen Gras PGO_CLEANIT | PGO_DEACTIVATE | 405d65f6f70SBen Gras ((ioflag & IO_SYNC) ? PGO_SYNCIO : 0)); 406d65f6f70SBen Gras if (error) { 407d65f6f70SBen Gras lfs_reserve(fs, ovp, NULL, 408*84d9c625SLionel Sambuc -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift)); 409d65f6f70SBen Gras goto errout; 410d65f6f70SBen Gras } 411d65f6f70SBen Gras } 412d65f6f70SBen Gras } 413d65f6f70SBen Gras 414d65f6f70SBen Gras genfs_node_wrlock(ovp); 415d65f6f70SBen Gras 416d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = length; 417d65f6f70SBen Gras uvm_vnp_setsize(ovp, length); 418d65f6f70SBen Gras 419d65f6f70SBen Gras /* 420d65f6f70SBen Gras * Calculate index into inode's block list of 421d65f6f70SBen Gras * last direct and indirect blocks (if any) 422d65f6f70SBen Gras * which we want to keep. Lastblock is -1 when 423d65f6f70SBen Gras * the file is truncated to 0. 424d65f6f70SBen Gras */ 425d65f6f70SBen Gras /* Avoid sign overflow - XXX assumes that off_t is a quad_t. */ 426d65f6f70SBen Gras if (length > QUAD_MAX - fs->lfs_bsize) 427*84d9c625SLionel Sambuc lastblock = lfs_lblkno(fs, QUAD_MAX - fs->lfs_bsize); 428d65f6f70SBen Gras else 429*84d9c625SLionel Sambuc lastblock = lfs_lblkno(fs, length + fs->lfs_bsize - 1) - 1; 430*84d9c625SLionel Sambuc lastiblock[SINGLE] = lastblock - ULFS_NDADDR; 431*84d9c625SLionel Sambuc lastiblock[DOUBLE] = lastiblock[SINGLE] - LFS_NINDIR(fs); 432*84d9c625SLionel Sambuc lastiblock[TRIPLE] = lastiblock[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs); 433*84d9c625SLionel Sambuc nblocks = lfs_btofsb(fs, fs->lfs_bsize); 434d65f6f70SBen Gras /* 435d65f6f70SBen Gras * Record changed file and block pointers before we start 436d65f6f70SBen Gras * freeing blocks. lastiblock values are also normalized to -1 437d65f6f70SBen Gras * for calls to lfs_indirtrunc below. 438d65f6f70SBen Gras */ 439d65f6f70SBen Gras memcpy((void *)newblks, (void *)&oip->i_ffs1_db[0], sizeof newblks); 440d65f6f70SBen Gras for (level = TRIPLE; level >= SINGLE; level--) 441d65f6f70SBen Gras if (lastiblock[level] < 0) { 442*84d9c625SLionel Sambuc newblks[ULFS_NDADDR+level] = 0; 443d65f6f70SBen Gras lastiblock[level] = -1; 444d65f6f70SBen Gras } 445*84d9c625SLionel Sambuc for (i = ULFS_NDADDR - 1; i > lastblock; i--) 446d65f6f70SBen Gras newblks[i] = 0; 447d65f6f70SBen Gras 448d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = osize; 449d65f6f70SBen Gras error = lfs_vtruncbuf(ovp, lastblock + 1, false, 0); 450d65f6f70SBen Gras if (error && !allerror) 451d65f6f70SBen Gras allerror = error; 452d65f6f70SBen Gras 453d65f6f70SBen Gras /* 454d65f6f70SBen Gras * Indirect blocks first. 455d65f6f70SBen Gras */ 456*84d9c625SLionel Sambuc indir_lbn[SINGLE] = -ULFS_NDADDR; 457*84d9c625SLionel Sambuc indir_lbn[DOUBLE] = indir_lbn[SINGLE] - LFS_NINDIR(fs) - 1; 458*84d9c625SLionel Sambuc indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs) - 1; 459d65f6f70SBen Gras for (level = TRIPLE; level >= SINGLE; level--) { 460d65f6f70SBen Gras bn = oip->i_ffs1_ib[level]; 461d65f6f70SBen Gras if (bn != 0) { 462d65f6f70SBen Gras error = lfs_indirtrunc(oip, indir_lbn[level], 463d65f6f70SBen Gras bn, lastiblock[level], 464d65f6f70SBen Gras level, &count, &rcount, 465d65f6f70SBen Gras &lastseg, &bc); 466d65f6f70SBen Gras if (error) 467d65f6f70SBen Gras allerror = error; 468d65f6f70SBen Gras real_released += rcount; 469d65f6f70SBen Gras blocksreleased += count; 470d65f6f70SBen Gras if (lastiblock[level] < 0) { 471d65f6f70SBen Gras if (oip->i_ffs1_ib[level] > 0) 472d65f6f70SBen Gras real_released += nblocks; 473d65f6f70SBen Gras blocksreleased += nblocks; 474d65f6f70SBen Gras oip->i_ffs1_ib[level] = 0; 475d65f6f70SBen Gras lfs_blkfree(fs, oip, bn, fs->lfs_bsize, 476d65f6f70SBen Gras &lastseg, &bc); 477d65f6f70SBen Gras lfs_deregister_block(ovp, bn); 478d65f6f70SBen Gras } 479d65f6f70SBen Gras } 480d65f6f70SBen Gras if (lastiblock[level] >= 0) 481d65f6f70SBen Gras goto done; 482d65f6f70SBen Gras } 483d65f6f70SBen Gras 484d65f6f70SBen Gras /* 485d65f6f70SBen Gras * All whole direct blocks or frags. 486d65f6f70SBen Gras */ 487*84d9c625SLionel Sambuc for (i = ULFS_NDADDR - 1; i > lastblock; i--) { 488d65f6f70SBen Gras long bsize, obsize; 489d65f6f70SBen Gras 490d65f6f70SBen Gras bn = oip->i_ffs1_db[i]; 491d65f6f70SBen Gras if (bn == 0) 492d65f6f70SBen Gras continue; 493*84d9c625SLionel Sambuc bsize = lfs_blksize(fs, oip, i); 494d65f6f70SBen Gras if (oip->i_ffs1_db[i] > 0) { 495d65f6f70SBen Gras /* Check for fragment size changes */ 496d65f6f70SBen Gras obsize = oip->i_lfs_fragsize[i]; 497*84d9c625SLionel Sambuc real_released += lfs_btofsb(fs, obsize); 498d65f6f70SBen Gras oip->i_lfs_fragsize[i] = 0; 499d65f6f70SBen Gras } else 500d65f6f70SBen Gras obsize = 0; 501*84d9c625SLionel Sambuc blocksreleased += lfs_btofsb(fs, bsize); 502d65f6f70SBen Gras oip->i_ffs1_db[i] = 0; 503d65f6f70SBen Gras lfs_blkfree(fs, oip, bn, obsize, &lastseg, &bc); 504d65f6f70SBen Gras lfs_deregister_block(ovp, bn); 505d65f6f70SBen Gras } 506d65f6f70SBen Gras if (lastblock < 0) 507d65f6f70SBen Gras goto done; 508d65f6f70SBen Gras 509d65f6f70SBen Gras /* 510d65f6f70SBen Gras * Finally, look for a change in size of the 511d65f6f70SBen Gras * last direct block; release any frags. 512d65f6f70SBen Gras */ 513d65f6f70SBen Gras bn = oip->i_ffs1_db[lastblock]; 514d65f6f70SBen Gras if (bn != 0) { 515d65f6f70SBen Gras long oldspace, newspace; 516d65f6f70SBen Gras #if 0 517d65f6f70SBen Gras long olddspace; 518d65f6f70SBen Gras #endif 519d65f6f70SBen Gras 520d65f6f70SBen Gras /* 521d65f6f70SBen Gras * Calculate amount of space we're giving 522d65f6f70SBen Gras * back as old block size minus new block size. 523d65f6f70SBen Gras */ 524*84d9c625SLionel Sambuc oldspace = lfs_blksize(fs, oip, lastblock); 525d65f6f70SBen Gras #if 0 526d65f6f70SBen Gras olddspace = oip->i_lfs_fragsize[lastblock]; 527d65f6f70SBen Gras #endif 528d65f6f70SBen Gras 529d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = length; 530*84d9c625SLionel Sambuc newspace = lfs_blksize(fs, oip, lastblock); 531d65f6f70SBen Gras if (newspace == 0) 532d65f6f70SBen Gras panic("itrunc: newspace"); 533d65f6f70SBen Gras if (oldspace - newspace > 0) { 534*84d9c625SLionel Sambuc blocksreleased += lfs_btofsb(fs, oldspace - newspace); 535d65f6f70SBen Gras } 536d65f6f70SBen Gras #if 0 537d65f6f70SBen Gras if (bn > 0 && olddspace - newspace > 0) { 538d65f6f70SBen Gras /* No segment accounting here, just vnode */ 539*84d9c625SLionel Sambuc real_released += lfs_btofsb(fs, olddspace - newspace); 540d65f6f70SBen Gras } 541d65f6f70SBen Gras #endif 542d65f6f70SBen Gras } 543d65f6f70SBen Gras 544d65f6f70SBen Gras done: 545d65f6f70SBen Gras /* Finish segment accounting corrections */ 546d65f6f70SBen Gras lfs_update_seguse(fs, oip, lastseg, bc); 547d65f6f70SBen Gras #ifdef DIAGNOSTIC 548d65f6f70SBen Gras for (level = SINGLE; level <= TRIPLE; level++) 549*84d9c625SLionel Sambuc if ((newblks[ULFS_NDADDR + level] == 0) != 550d65f6f70SBen Gras ((oip->i_ffs1_ib[level]) == 0)) { 551d65f6f70SBen Gras panic("lfs itrunc1"); 552d65f6f70SBen Gras } 553*84d9c625SLionel Sambuc for (i = 0; i < ULFS_NDADDR; i++) 554d65f6f70SBen Gras if ((newblks[i] == 0) != (oip->i_ffs1_db[i] == 0)) { 555d65f6f70SBen Gras panic("lfs itrunc2"); 556d65f6f70SBen Gras } 557d65f6f70SBen Gras if (length == 0 && 558d65f6f70SBen Gras (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd))) 559d65f6f70SBen Gras panic("lfs itrunc3"); 560d65f6f70SBen Gras #endif /* DIAGNOSTIC */ 561d65f6f70SBen Gras /* 562d65f6f70SBen Gras * Put back the real size. 563d65f6f70SBen Gras */ 564d65f6f70SBen Gras oip->i_size = oip->i_ffs1_size = length; 565d65f6f70SBen Gras oip->i_lfs_effnblks -= blocksreleased; 566d65f6f70SBen Gras oip->i_ffs1_blocks -= real_released; 567d65f6f70SBen Gras mutex_enter(&lfs_lock); 568d65f6f70SBen Gras fs->lfs_bfree += blocksreleased; 569d65f6f70SBen Gras mutex_exit(&lfs_lock); 570d65f6f70SBen Gras #ifdef DIAGNOSTIC 571d65f6f70SBen Gras if (oip->i_size == 0 && 572d65f6f70SBen Gras (oip->i_ffs1_blocks != 0 || oip->i_lfs_effnblks != 0)) { 573d65f6f70SBen Gras printf("lfs_truncate: truncate to 0 but %d blks/%d effblks\n", 574d65f6f70SBen Gras oip->i_ffs1_blocks, oip->i_lfs_effnblks); 575d65f6f70SBen Gras panic("lfs_truncate: persistent blocks"); 576d65f6f70SBen Gras } 577d65f6f70SBen Gras #endif 578d65f6f70SBen Gras 579d65f6f70SBen Gras /* 580d65f6f70SBen Gras * If we truncated to zero, take us off the paging queue. 581d65f6f70SBen Gras */ 582d65f6f70SBen Gras mutex_enter(&lfs_lock); 583d65f6f70SBen Gras if (oip->i_size == 0 && oip->i_flags & IN_PAGING) { 584d65f6f70SBen Gras oip->i_flags &= ~IN_PAGING; 585d65f6f70SBen Gras TAILQ_REMOVE(&fs->lfs_pchainhd, oip, i_lfs_pchain); 586d65f6f70SBen Gras } 587d65f6f70SBen Gras mutex_exit(&lfs_lock); 588d65f6f70SBen Gras 589d65f6f70SBen Gras oip->i_flag |= IN_CHANGE; 590*84d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 591*84d9c625SLionel Sambuc (void) lfs_chkdq(oip, -blocksreleased, NOCRED, 0); 592d65f6f70SBen Gras #endif 593d65f6f70SBen Gras lfs_reserve(fs, ovp, NULL, 594*84d9c625SLionel Sambuc -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift)); 595d65f6f70SBen Gras genfs_node_unlock(ovp); 596d65f6f70SBen Gras errout: 597*84d9c625SLionel Sambuc oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1; 598d65f6f70SBen Gras if (ovp != fs->lfs_ivnode) 599d65f6f70SBen Gras lfs_segunlock(fs); 600d65f6f70SBen Gras return (allerror ? allerror : error); 601d65f6f70SBen Gras } 602d65f6f70SBen Gras 603d65f6f70SBen Gras /* Update segment and avail usage information when removing a block. */ 604d65f6f70SBen Gras static int 605d65f6f70SBen Gras lfs_blkfree(struct lfs *fs, struct inode *ip, daddr_t daddr, 606d65f6f70SBen Gras size_t bsize, long *lastseg, size_t *num) 607d65f6f70SBen Gras { 608d65f6f70SBen Gras long seg; 609d65f6f70SBen Gras int error = 0; 610d65f6f70SBen Gras 611d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 612*84d9c625SLionel Sambuc bsize = lfs_fragroundup(fs, bsize); 613d65f6f70SBen Gras if (daddr > 0) { 614*84d9c625SLionel Sambuc if (*lastseg != (seg = lfs_dtosn(fs, daddr))) { 615d65f6f70SBen Gras error = lfs_update_seguse(fs, ip, *lastseg, *num); 616d65f6f70SBen Gras *num = bsize; 617d65f6f70SBen Gras *lastseg = seg; 618d65f6f70SBen Gras } else 619d65f6f70SBen Gras *num += bsize; 620d65f6f70SBen Gras } 621d65f6f70SBen Gras 622d65f6f70SBen Gras return error; 623d65f6f70SBen Gras } 624d65f6f70SBen Gras 625d65f6f70SBen Gras /* Finish the accounting updates for a segment. */ 626d65f6f70SBen Gras static int 627d65f6f70SBen Gras lfs_update_seguse(struct lfs *fs, struct inode *ip, long lastseg, size_t num) 628d65f6f70SBen Gras { 629d65f6f70SBen Gras struct segdelta *sd; 630d65f6f70SBen Gras 631d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 632d65f6f70SBen Gras if (lastseg < 0 || num == 0) 633d65f6f70SBen Gras return 0; 634d65f6f70SBen Gras 635d65f6f70SBen Gras LIST_FOREACH(sd, &ip->i_lfs_segdhd, list) 636d65f6f70SBen Gras if (sd->segnum == lastseg) 637d65f6f70SBen Gras break; 638d65f6f70SBen Gras if (sd == NULL) { 639d65f6f70SBen Gras sd = malloc(sizeof(*sd), M_SEGMENT, M_WAITOK); 640d65f6f70SBen Gras sd->segnum = lastseg; 641d65f6f70SBen Gras sd->num = 0; 642d65f6f70SBen Gras LIST_INSERT_HEAD(&ip->i_lfs_segdhd, sd, list); 643d65f6f70SBen Gras } 644d65f6f70SBen Gras sd->num += num; 645d65f6f70SBen Gras 646d65f6f70SBen Gras return 0; 647d65f6f70SBen Gras } 648d65f6f70SBen Gras 649d65f6f70SBen Gras static void 650d65f6f70SBen Gras lfs_finalize_seguse(struct lfs *fs, void *v) 651d65f6f70SBen Gras { 652d65f6f70SBen Gras SEGUSE *sup; 653d65f6f70SBen Gras struct buf *bp; 654d65f6f70SBen Gras struct segdelta *sd; 655d65f6f70SBen Gras LIST_HEAD(, segdelta) *hd = v; 656d65f6f70SBen Gras 657d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 658d65f6f70SBen Gras while((sd = LIST_FIRST(hd)) != NULL) { 659d65f6f70SBen Gras LIST_REMOVE(sd, list); 660d65f6f70SBen Gras LFS_SEGENTRY(sup, fs, sd->segnum, bp); 661d65f6f70SBen Gras if (sd->num > sup->su_nbytes) { 662d65f6f70SBen Gras printf("lfs_finalize_seguse: segment %ld short by %ld\n", 663d65f6f70SBen Gras sd->segnum, (long)(sd->num - sup->su_nbytes)); 664d65f6f70SBen Gras panic("lfs_finalize_seguse: negative bytes"); 665d65f6f70SBen Gras sup->su_nbytes = sd->num; 666d65f6f70SBen Gras } 667d65f6f70SBen Gras sup->su_nbytes -= sd->num; 668d65f6f70SBen Gras LFS_WRITESEGENTRY(sup, fs, sd->segnum, bp); 669d65f6f70SBen Gras free(sd, M_SEGMENT); 670d65f6f70SBen Gras } 671d65f6f70SBen Gras } 672d65f6f70SBen Gras 673d65f6f70SBen Gras /* Finish the accounting updates for a segment. */ 674d65f6f70SBen Gras void 675d65f6f70SBen Gras lfs_finalize_ino_seguse(struct lfs *fs, struct inode *ip) 676d65f6f70SBen Gras { 677d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 678d65f6f70SBen Gras lfs_finalize_seguse(fs, &ip->i_lfs_segdhd); 679d65f6f70SBen Gras } 680d65f6f70SBen Gras 681d65f6f70SBen Gras /* Finish the accounting updates for a segment. */ 682d65f6f70SBen Gras void 683d65f6f70SBen Gras lfs_finalize_fs_seguse(struct lfs *fs) 684d65f6f70SBen Gras { 685d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 686d65f6f70SBen Gras lfs_finalize_seguse(fs, &fs->lfs_segdhd); 687d65f6f70SBen Gras } 688d65f6f70SBen Gras 689d65f6f70SBen Gras /* 690d65f6f70SBen Gras * Release blocks associated with the inode ip and stored in the indirect 691d65f6f70SBen Gras * block bn. Blocks are free'd in LIFO order up to (but not including) 692d65f6f70SBen Gras * lastbn. If level is greater than SINGLE, the block is an indirect block 693d65f6f70SBen Gras * and recursive calls to indirtrunc must be used to cleanse other indirect 694d65f6f70SBen Gras * blocks. 695d65f6f70SBen Gras * 696d65f6f70SBen Gras * NB: triple indirect blocks are untested. 697d65f6f70SBen Gras */ 698d65f6f70SBen Gras static int 699d65f6f70SBen Gras lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, 700d65f6f70SBen Gras daddr_t lastbn, int level, long *countp, 701d65f6f70SBen Gras long *rcountp, long *lastsegp, size_t *bcp) 702d65f6f70SBen Gras { 703d65f6f70SBen Gras int i; 704d65f6f70SBen Gras struct buf *bp; 705d65f6f70SBen Gras struct lfs *fs = ip->i_lfs; 706d65f6f70SBen Gras int32_t *bap; /* XXX ondisk32 */ 707d65f6f70SBen Gras struct vnode *vp; 708d65f6f70SBen Gras daddr_t nb, nlbn, last; 709d65f6f70SBen Gras int32_t *copy = NULL; /* XXX ondisk32 */ 710d65f6f70SBen Gras long blkcount, rblkcount, factor; 711d65f6f70SBen Gras int nblocks, blocksreleased = 0, real_released = 0; 712d65f6f70SBen Gras int error = 0, allerror = 0; 713d65f6f70SBen Gras 714d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 715d65f6f70SBen Gras /* 716d65f6f70SBen Gras * Calculate index in current block of last 717d65f6f70SBen Gras * block to be kept. -1 indicates the entire 718d65f6f70SBen Gras * block so we need not calculate the index. 719d65f6f70SBen Gras */ 720d65f6f70SBen Gras factor = 1; 721d65f6f70SBen Gras for (i = SINGLE; i < level; i++) 722*84d9c625SLionel Sambuc factor *= LFS_NINDIR(fs); 723d65f6f70SBen Gras last = lastbn; 724d65f6f70SBen Gras if (lastbn > 0) 725d65f6f70SBen Gras last /= factor; 726*84d9c625SLionel Sambuc nblocks = lfs_btofsb(fs, fs->lfs_bsize); 727d65f6f70SBen Gras /* 728d65f6f70SBen Gras * Get buffer of block pointers, zero those entries corresponding 729d65f6f70SBen Gras * to blocks to be free'd, and update on disk copy first. Since 730d65f6f70SBen Gras * double(triple) indirect before single(double) indirect, calls 731d65f6f70SBen Gras * to bmap on these blocks will fail. However, we already have 732d65f6f70SBen Gras * the on disk address, so we have to set the b_blkno field 733d65f6f70SBen Gras * explicitly instead of letting bread do everything for us. 734d65f6f70SBen Gras */ 735d65f6f70SBen Gras vp = ITOV(ip); 736d65f6f70SBen Gras bp = getblk(vp, lbn, (int)fs->lfs_bsize, 0, 0); 737d65f6f70SBen Gras if (bp->b_oflags & (BO_DONE | BO_DELWRI)) { 738d65f6f70SBen Gras /* Braces must be here in case trace evaluates to nothing. */ 739d65f6f70SBen Gras trace(TR_BREADHIT, pack(vp, fs->lfs_bsize), lbn); 740d65f6f70SBen Gras } else { 741d65f6f70SBen Gras trace(TR_BREADMISS, pack(vp, fs->lfs_bsize), lbn); 742d65f6f70SBen Gras curlwp->l_ru.ru_inblock++; /* pay for read */ 743d65f6f70SBen Gras bp->b_flags |= B_READ; 744d65f6f70SBen Gras if (bp->b_bcount > bp->b_bufsize) 745d65f6f70SBen Gras panic("lfs_indirtrunc: bad buffer size"); 746*84d9c625SLionel Sambuc bp->b_blkno = LFS_FSBTODB(fs, dbn); 747d65f6f70SBen Gras VOP_STRATEGY(vp, bp); 748d65f6f70SBen Gras error = biowait(bp); 749d65f6f70SBen Gras } 750d65f6f70SBen Gras if (error) { 751d65f6f70SBen Gras brelse(bp, 0); 752d65f6f70SBen Gras *countp = *rcountp = 0; 753d65f6f70SBen Gras return (error); 754d65f6f70SBen Gras } 755d65f6f70SBen Gras 756d65f6f70SBen Gras bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 757d65f6f70SBen Gras if (lastbn >= 0) { 758d65f6f70SBen Gras copy = (int32_t *)lfs_malloc(fs, fs->lfs_bsize, LFS_NB_IBLOCK); 759d65f6f70SBen Gras memcpy((void *)copy, (void *)bap, (u_int)fs->lfs_bsize); 760d65f6f70SBen Gras memset((void *)&bap[last + 1], 0, 761d65f6f70SBen Gras /* XXX ondisk32 */ 762*84d9c625SLionel Sambuc (u_int)(LFS_NINDIR(fs) - (last + 1)) * sizeof (int32_t)); 763d65f6f70SBen Gras error = VOP_BWRITE(bp->b_vp, bp); 764d65f6f70SBen Gras if (error) 765d65f6f70SBen Gras allerror = error; 766d65f6f70SBen Gras bap = copy; 767d65f6f70SBen Gras } 768d65f6f70SBen Gras 769d65f6f70SBen Gras /* 770d65f6f70SBen Gras * Recursively free totally unused blocks. 771d65f6f70SBen Gras */ 772*84d9c625SLionel Sambuc for (i = LFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 773d65f6f70SBen Gras i--, nlbn += factor) { 774d65f6f70SBen Gras nb = bap[i]; 775d65f6f70SBen Gras if (nb == 0) 776d65f6f70SBen Gras continue; 777d65f6f70SBen Gras if (level > SINGLE) { 778d65f6f70SBen Gras error = lfs_indirtrunc(ip, nlbn, nb, 779d65f6f70SBen Gras (daddr_t)-1, level - 1, 780d65f6f70SBen Gras &blkcount, &rblkcount, 781d65f6f70SBen Gras lastsegp, bcp); 782d65f6f70SBen Gras if (error) 783d65f6f70SBen Gras allerror = error; 784d65f6f70SBen Gras blocksreleased += blkcount; 785d65f6f70SBen Gras real_released += rblkcount; 786d65f6f70SBen Gras } 787d65f6f70SBen Gras lfs_blkfree(fs, ip, nb, fs->lfs_bsize, lastsegp, bcp); 788d65f6f70SBen Gras if (bap[i] > 0) 789d65f6f70SBen Gras real_released += nblocks; 790d65f6f70SBen Gras blocksreleased += nblocks; 791d65f6f70SBen Gras } 792d65f6f70SBen Gras 793d65f6f70SBen Gras /* 794d65f6f70SBen Gras * Recursively free last partial block. 795d65f6f70SBen Gras */ 796d65f6f70SBen Gras if (level > SINGLE && lastbn >= 0) { 797d65f6f70SBen Gras last = lastbn % factor; 798d65f6f70SBen Gras nb = bap[i]; 799d65f6f70SBen Gras if (nb != 0) { 800d65f6f70SBen Gras error = lfs_indirtrunc(ip, nlbn, nb, 801d65f6f70SBen Gras last, level - 1, &blkcount, 802d65f6f70SBen Gras &rblkcount, lastsegp, bcp); 803d65f6f70SBen Gras if (error) 804d65f6f70SBen Gras allerror = error; 805d65f6f70SBen Gras real_released += rblkcount; 806d65f6f70SBen Gras blocksreleased += blkcount; 807d65f6f70SBen Gras } 808d65f6f70SBen Gras } 809d65f6f70SBen Gras 810d65f6f70SBen Gras if (copy != NULL) { 811d65f6f70SBen Gras lfs_free(fs, copy, LFS_NB_IBLOCK); 812d65f6f70SBen Gras } else { 813d65f6f70SBen Gras mutex_enter(&bufcache_lock); 814d65f6f70SBen Gras if (bp->b_oflags & BO_DELWRI) { 815d65f6f70SBen Gras LFS_UNLOCK_BUF(bp); 816*84d9c625SLionel Sambuc fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount); 817d65f6f70SBen Gras wakeup(&fs->lfs_avail); 818d65f6f70SBen Gras } 819d65f6f70SBen Gras brelsel(bp, BC_INVAL); 820d65f6f70SBen Gras mutex_exit(&bufcache_lock); 821d65f6f70SBen Gras } 822d65f6f70SBen Gras 823d65f6f70SBen Gras *countp = blocksreleased; 824d65f6f70SBen Gras *rcountp = real_released; 825d65f6f70SBen Gras return (allerror); 826d65f6f70SBen Gras } 827d65f6f70SBen Gras 828d65f6f70SBen Gras /* 829d65f6f70SBen Gras * Destroy any in core blocks past the truncation length. 830d65f6f70SBen Gras * Inlined from vtruncbuf, so that lfs_avail could be updated. 831d65f6f70SBen Gras * We take the seglock to prevent cleaning from occurring while we are 832d65f6f70SBen Gras * invalidating blocks. 833d65f6f70SBen Gras */ 834d65f6f70SBen Gras static int 835d65f6f70SBen Gras lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, bool catch, int slptimeo) 836d65f6f70SBen Gras { 837d65f6f70SBen Gras struct buf *bp, *nbp; 838d65f6f70SBen Gras int error; 839d65f6f70SBen Gras struct lfs *fs; 840d65f6f70SBen Gras voff_t off; 841d65f6f70SBen Gras 842d65f6f70SBen Gras off = round_page((voff_t)lbn << vp->v_mount->mnt_fs_bshift); 843d65f6f70SBen Gras mutex_enter(vp->v_interlock); 844d65f6f70SBen Gras error = VOP_PUTPAGES(vp, off, 0, PGO_FREE | PGO_SYNCIO); 845d65f6f70SBen Gras if (error) 846d65f6f70SBen Gras return error; 847d65f6f70SBen Gras 848d65f6f70SBen Gras fs = VTOI(vp)->i_lfs; 849d65f6f70SBen Gras 850d65f6f70SBen Gras ASSERT_SEGLOCK(fs); 851d65f6f70SBen Gras 852d65f6f70SBen Gras mutex_enter(&bufcache_lock); 853d65f6f70SBen Gras restart: 854d65f6f70SBen Gras for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { 855d65f6f70SBen Gras nbp = LIST_NEXT(bp, b_vnbufs); 856d65f6f70SBen Gras if (bp->b_lblkno < lbn) 857d65f6f70SBen Gras continue; 858d65f6f70SBen Gras error = bbusy(bp, catch, slptimeo, NULL); 859d65f6f70SBen Gras if (error == EPASSTHROUGH) 860d65f6f70SBen Gras goto restart; 861d65f6f70SBen Gras if (error != 0) { 862d65f6f70SBen Gras mutex_exit(&bufcache_lock); 863d65f6f70SBen Gras return (error); 864d65f6f70SBen Gras } 865d65f6f70SBen Gras mutex_enter(bp->b_objlock); 866d65f6f70SBen Gras if (bp->b_oflags & BO_DELWRI) { 867d65f6f70SBen Gras bp->b_oflags &= ~BO_DELWRI; 868*84d9c625SLionel Sambuc fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount); 869d65f6f70SBen Gras wakeup(&fs->lfs_avail); 870d65f6f70SBen Gras } 871d65f6f70SBen Gras mutex_exit(bp->b_objlock); 872d65f6f70SBen Gras LFS_UNLOCK_BUF(bp); 873d65f6f70SBen Gras brelsel(bp, BC_INVAL | BC_VFLUSH); 874d65f6f70SBen Gras } 875d65f6f70SBen Gras 876d65f6f70SBen Gras for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 877d65f6f70SBen Gras nbp = LIST_NEXT(bp, b_vnbufs); 878d65f6f70SBen Gras if (bp->b_lblkno < lbn) 879d65f6f70SBen Gras continue; 880d65f6f70SBen Gras error = bbusy(bp, catch, slptimeo, NULL); 881d65f6f70SBen Gras if (error == EPASSTHROUGH) 882d65f6f70SBen Gras goto restart; 883d65f6f70SBen Gras if (error != 0) { 884d65f6f70SBen Gras mutex_exit(&bufcache_lock); 885d65f6f70SBen Gras return (error); 886d65f6f70SBen Gras } 887d65f6f70SBen Gras mutex_enter(bp->b_objlock); 888d65f6f70SBen Gras if (bp->b_oflags & BO_DELWRI) { 889d65f6f70SBen Gras bp->b_oflags &= ~BO_DELWRI; 890*84d9c625SLionel Sambuc fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount); 891d65f6f70SBen Gras wakeup(&fs->lfs_avail); 892d65f6f70SBen Gras } 893d65f6f70SBen Gras mutex_exit(bp->b_objlock); 894d65f6f70SBen Gras LFS_UNLOCK_BUF(bp); 895d65f6f70SBen Gras brelsel(bp, BC_INVAL | BC_VFLUSH); 896d65f6f70SBen Gras } 897d65f6f70SBen Gras mutex_exit(&bufcache_lock); 898d65f6f70SBen Gras 899d65f6f70SBen Gras return (0); 900d65f6f70SBen Gras } 901d65f6f70SBen Gras 902