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