1 1.91 riastrad /* $NetBSD: ext2fs_inode.c,v 1.91 2023/08/26 05:22:50 riastradh Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /* 4 1.1 bouyer * Copyright (c) 1982, 1986, 1989, 1993 5 1.1 bouyer * The Regents of the University of California. All rights reserved. 6 1.1 bouyer * 7 1.1 bouyer * Redistribution and use in source and binary forms, with or without 8 1.1 bouyer * modification, are permitted provided that the following conditions 9 1.1 bouyer * are met: 10 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 11 1.1 bouyer * notice, this list of conditions and the following disclaimer. 12 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 14 1.1 bouyer * documentation and/or other materials provided with the distribution. 15 1.35 agc * 3. Neither the name of the University nor the names of its contributors 16 1.35 agc * may be used to endorse or promote products derived from this software 17 1.35 agc * without specific prior written permission. 18 1.35 agc * 19 1.35 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.35 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.35 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.35 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.35 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.35 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.35 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.35 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.35 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.35 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.35 agc * SUCH DAMAGE. 30 1.35 agc * 31 1.35 agc * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94 32 1.35 agc * Modified for ext2fs by Manuel Bouyer. 33 1.35 agc */ 34 1.35 agc 35 1.35 agc /* 36 1.35 agc * Copyright (c) 1997 Manuel Bouyer. 37 1.35 agc * 38 1.35 agc * Redistribution and use in source and binary forms, with or without 39 1.35 agc * modification, are permitted provided that the following conditions 40 1.35 agc * are met: 41 1.35 agc * 1. Redistributions of source code must retain the above copyright 42 1.35 agc * notice, this list of conditions and the following disclaimer. 43 1.35 agc * 2. Redistributions in binary form must reproduce the above copyright 44 1.35 agc * notice, this list of conditions and the following disclaimer in the 45 1.35 agc * documentation and/or other materials provided with the distribution. 46 1.1 bouyer * 47 1.40 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 1.40 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49 1.40 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 1.40 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51 1.40 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52 1.40 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 1.40 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 1.40 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 1.40 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 1.40 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 1.1 bouyer * 58 1.1 bouyer * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94 59 1.1 bouyer * Modified for ext2fs by Manuel Bouyer. 60 1.1 bouyer */ 61 1.27 lukem 62 1.27 lukem #include <sys/cdefs.h> 63 1.91 riastrad __KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.91 2023/08/26 05:22:50 riastradh Exp $"); 64 1.5 mrg 65 1.1 bouyer #include <sys/param.h> 66 1.1 bouyer #include <sys/systm.h> 67 1.1 bouyer #include <sys/mount.h> 68 1.1 bouyer #include <sys/proc.h> 69 1.1 bouyer #include <sys/file.h> 70 1.1 bouyer #include <sys/buf.h> 71 1.1 bouyer #include <sys/vnode.h> 72 1.1 bouyer #include <sys/kernel.h> 73 1.75 para #include <sys/kmem.h> 74 1.1 bouyer #include <sys/trace.h> 75 1.1 bouyer #include <sys/resourcevar.h> 76 1.54 elad #include <sys/kauth.h> 77 1.1 bouyer 78 1.1 bouyer #include <ufs/ufs/inode.h> 79 1.1 bouyer #include <ufs/ufs/ufsmount.h> 80 1.1 bouyer #include <ufs/ufs/ufs_extern.h> 81 1.1 bouyer 82 1.1 bouyer #include <ufs/ext2fs/ext2fs.h> 83 1.1 bouyer #include <ufs/ext2fs/ext2fs_extern.h> 84 1.1 bouyer 85 1.47 xtraeme static int ext2fs_indirtrunc(struct inode *, daddr_t, daddr_t, 86 1.47 xtraeme daddr_t, int, long *); 87 1.1 bouyer 88 1.1 bouyer /* 89 1.78 dholland * These are fortunately the same values; it is likely that there is 90 1.78 dholland * code that assumes they're equal. In any event, neither ought to 91 1.78 dholland * ever change because it's a property of the on-disk formats. 92 1.78 dholland */ 93 1.78 dholland CTASSERT(EXT2FS_NDADDR == UFS_NDADDR); 94 1.78 dholland CTASSERT(EXT2FS_NIADDR == UFS_NIADDR); 95 1.78 dholland 96 1.78 dholland /* 97 1.44 ws * Get the size of an inode. 98 1.44 ws */ 99 1.69 tsutsui uint64_t 100 1.44 ws ext2fs_size(struct inode *ip) 101 1.44 ws { 102 1.69 tsutsui uint64_t size = ip->i_e2fs_size; 103 1.44 ws 104 1.44 ws if ((ip->i_e2fs_mode & IFMT) == IFREG) 105 1.84 jdolecek size |= (uint64_t)ip->i_din.e2fs_din->e2di_size_high << 32; 106 1.44 ws return size; 107 1.44 ws } 108 1.44 ws 109 1.44 ws int 110 1.69 tsutsui ext2fs_setsize(struct inode *ip, uint64_t size) 111 1.44 ws { 112 1.44 ws if ((ip->i_e2fs_mode & IFMT) == IFREG || 113 1.44 ws ip->i_e2fs_mode == 0) { 114 1.84 jdolecek ip->i_din.e2fs_din->e2di_size_high = size >> 32; 115 1.44 ws if (size >= 0x80000000U) { 116 1.44 ws struct m_ext2fs *fs = ip->i_e2fs; 117 1.44 ws 118 1.44 ws if (fs->e2fs.e2fs_rev <= E2FS_REV0) { 119 1.44 ws /* Linux automagically upgrades to REV1 here! */ 120 1.44 ws return EFBIG; 121 1.44 ws } 122 1.86 jdolecek if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, 123 1.86 jdolecek EXT2F_ROCOMPAT_LARGEFILE)) { 124 1.44 ws fs->e2fs.e2fs_features_rocompat |= 125 1.44 ws EXT2F_ROCOMPAT_LARGEFILE; 126 1.44 ws fs->e2fs_fmod = 1; 127 1.44 ws } 128 1.44 ws } 129 1.44 ws } else if (size >= 0x80000000U) 130 1.44 ws return EFBIG; 131 1.44 ws 132 1.44 ws ip->i_e2fs_size = size; 133 1.44 ws 134 1.44 ws return 0; 135 1.44 ws } 136 1.44 ws 137 1.76 jakllsch uint64_t 138 1.76 jakllsch ext2fs_nblock(struct inode *ip) 139 1.76 jakllsch { 140 1.76 jakllsch uint64_t nblock = ip->i_e2fs_nblock; 141 1.76 jakllsch struct m_ext2fs * const fs = ip->i_e2fs; 142 1.76 jakllsch 143 1.86 jdolecek if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE)) { 144 1.76 jakllsch nblock |= (uint64_t)ip->i_e2fs_nblock_high << 32; 145 1.76 jakllsch 146 1.76 jakllsch if ((ip->i_e2fs_flags & EXT2_HUGE_FILE)) { 147 1.80 dholland nblock = EXT2_FSBTODB(fs, nblock); 148 1.76 jakllsch } 149 1.76 jakllsch } 150 1.76 jakllsch 151 1.76 jakllsch return nblock; 152 1.76 jakllsch } 153 1.76 jakllsch 154 1.76 jakllsch int 155 1.76 jakllsch ext2fs_setnblock(struct inode *ip, uint64_t nblock) 156 1.76 jakllsch { 157 1.76 jakllsch struct m_ext2fs * const fs = ip->i_e2fs; 158 1.76 jakllsch 159 1.76 jakllsch if (nblock <= 0xffffffffULL) { 160 1.76 jakllsch CLR(ip->i_e2fs_flags, EXT2_HUGE_FILE); 161 1.76 jakllsch ip->i_e2fs_nblock = nblock; 162 1.76 jakllsch return 0; 163 1.76 jakllsch } 164 1.76 jakllsch 165 1.91 riastrad if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE)) 166 1.76 jakllsch return EFBIG; 167 1.76 jakllsch 168 1.76 jakllsch if (nblock <= 0xffffffffffffULL) { 169 1.76 jakllsch CLR(ip->i_e2fs_flags, EXT2_HUGE_FILE); 170 1.76 jakllsch ip->i_e2fs_nblock = nblock & 0xffffffff; 171 1.76 jakllsch ip->i_e2fs_nblock_high = (nblock >> 32) & 0xffff; 172 1.76 jakllsch return 0; 173 1.76 jakllsch } 174 1.76 jakllsch 175 1.80 dholland if (EXT2_DBTOFSB(fs, nblock) <= 0xffffffffffffULL) { 176 1.76 jakllsch SET(ip->i_e2fs_flags, EXT2_HUGE_FILE); 177 1.80 dholland ip->i_e2fs_nblock = EXT2_DBTOFSB(fs, nblock) & 0xffffffff; 178 1.80 dholland ip->i_e2fs_nblock_high = (EXT2_DBTOFSB(fs, nblock) >> 32) & 0xffff; 179 1.76 jakllsch return 0; 180 1.76 jakllsch } 181 1.76 jakllsch 182 1.76 jakllsch return EFBIG; 183 1.76 jakllsch } 184 1.76 jakllsch 185 1.44 ws /* 186 1.1 bouyer * Last reference to an inode. If necessary, write or delete it. 187 1.1 bouyer */ 188 1.1 bouyer int 189 1.47 xtraeme ext2fs_inactive(void *v) 190 1.45 perry { 191 1.87 riastrad struct vop_inactive_v2_args /* { 192 1.1 bouyer struct vnode *a_vp; 193 1.63 ad bool *a_recycle; 194 1.1 bouyer } */ *ap = v; 195 1.6 fvdl struct vnode *vp = ap->a_vp; 196 1.6 fvdl struct inode *ip = VTOI(vp); 197 1.6 fvdl int error = 0; 198 1.45 perry 199 1.1 bouyer /* Get rid of inodes related to stale file handles. */ 200 1.6 fvdl if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0) 201 1.6 fvdl goto out; 202 1.1 bouyer 203 1.1 bouyer error = 0; 204 1.1 bouyer if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 205 1.63 ad /* Defer final inode free and update to reclaim.*/ 206 1.44 ws if (ext2fs_size(ip) != 0) { 207 1.62 pooka error = ext2fs_truncate(vp, (off_t)0, 0, NOCRED); 208 1.23 chs } 209 1.56 chs ip->i_e2fs_dtime = time_second; 210 1.64 ad ip->i_flag |= IN_CHANGE | IN_UPDATE; 211 1.73 hannken ip->i_omode = 1; 212 1.64 ad } 213 1.64 ad if (ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) { 214 1.50 yamt ext2fs_update(vp, NULL, NULL, 0); 215 1.37 hannken } 216 1.6 fvdl out: 217 1.1 bouyer /* 218 1.1 bouyer * If we are done with the inode, reclaim it 219 1.1 bouyer * so that it can be reused immediately. 220 1.1 bouyer */ 221 1.63 ad *ap->a_recycle = (ip->i_e2fs_dtime != 0); 222 1.87 riastrad 223 1.85 christos return error; 224 1.45 perry } 225 1.1 bouyer 226 1.1 bouyer 227 1.1 bouyer /* 228 1.1 bouyer * Update the access, modified, and inode change times as specified by the 229 1.1 bouyer * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is 230 1.1 bouyer * used to specify that the inode needs to be updated but that the times have 231 1.1 bouyer * already been set. The access and modified times are taken from the second 232 1.1 bouyer * and third parameters; the inode change time is always taken from the current 233 1.15 perseant * time. If UPDATE_WAIT or UPDATE_DIROP is set, then wait for the disk 234 1.15 perseant * write of the inode to complete. 235 1.1 bouyer */ 236 1.1 bouyer int 237 1.50 yamt ext2fs_update(struct vnode *vp, const struct timespec *acc, 238 1.50 yamt const struct timespec *mod, int updflags) 239 1.1 bouyer { 240 1.14 augustss struct m_ext2fs *fs; 241 1.1 bouyer struct buf *bp; 242 1.1 bouyer struct inode *ip; 243 1.1 bouyer int error; 244 1.57 christos void *cp; 245 1.18 mycroft int flags; 246 1.1 bouyer 247 1.50 yamt if (vp->v_mount->mnt_flag & MNT_RDONLY) 248 1.85 christos return 0; 249 1.50 yamt ip = VTOI(vp); 250 1.50 yamt EXT2FS_ITIMES(ip, acc, mod, NULL); 251 1.50 yamt if (updflags & UPDATE_CLOSE) 252 1.41 mycroft flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED); 253 1.41 mycroft else 254 1.41 mycroft flags = ip->i_flag & IN_MODIFIED; 255 1.18 mycroft if (flags == 0) 256 1.85 christos return 0; 257 1.1 bouyer fs = ip->i_e2fs; 258 1.18 mycroft 259 1.1 bouyer error = bread(ip->i_devvp, 260 1.80 dholland EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)), 261 1.82 maxv (int)fs->e2fs_bsize, B_MODIFY, &bp); 262 1.1 bouyer if (error) { 263 1.85 christos return error; 264 1.1 bouyer } 265 1.19 mycroft ip->i_flag &= ~(IN_MODIFIED | IN_ACCESSED); 266 1.57 christos cp = (char *)bp->b_data + 267 1.68 christos (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs)); 268 1.83 jdolecek e2fs_isave(ip->i_din.e2fs_din, (struct ext2fs_dinode *)cp, EXT2_DINODE_SIZE(fs)); 269 1.50 yamt if ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) != 0 && 270 1.18 mycroft (flags & IN_MODIFIED) != 0 && 271 1.50 yamt (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) 272 1.85 christos return bwrite(bp); 273 1.1 bouyer else { 274 1.1 bouyer bdwrite(bp); 275 1.85 christos return 0; 276 1.1 bouyer } 277 1.1 bouyer } 278 1.1 bouyer 279 1.1 bouyer #define SINGLE 0 /* index of single indirect block */ 280 1.1 bouyer #define DOUBLE 1 /* index of double indirect block */ 281 1.1 bouyer #define TRIPLE 2 /* index of triple indirect block */ 282 1.1 bouyer /* 283 1.1 bouyer * Truncate the inode oip to at most length size, freeing the 284 1.1 bouyer * disk blocks. 285 1.1 bouyer */ 286 1.1 bouyer int 287 1.50 yamt ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag, 288 1.62 pooka kauth_cred_t cred) 289 1.1 bouyer { 290 1.29 fvdl daddr_t lastblock; 291 1.43 mycroft struct inode *oip = VTOI(ovp); 292 1.78 dholland daddr_t bn, lastiblock[EXT2FS_NIADDR], indir_lbn[EXT2FS_NIADDR]; 293 1.30 fvdl /* XXX ondisk32 */ 294 1.78 dholland int32_t oldblks[EXT2FS_NDADDR + EXT2FS_NIADDR], newblks[EXT2FS_NDADDR + EXT2FS_NIADDR]; 295 1.14 augustss struct m_ext2fs *fs; 296 1.1 bouyer int offset, size, level; 297 1.43 mycroft long count, blocksreleased = 0; 298 1.50 yamt int i, nblocks; 299 1.21 chs int error, allerror = 0; 300 1.1 bouyer off_t osize; 301 1.43 mycroft int sync; 302 1.43 mycroft struct ufsmount *ump = oip->i_ump; 303 1.1 bouyer 304 1.51 yamt if (ovp->v_type == VCHR || ovp->v_type == VBLK || 305 1.51 yamt ovp->v_type == VFIFO || ovp->v_type == VSOCK) { 306 1.51 yamt return 0; 307 1.51 yamt } 308 1.51 yamt 309 1.1 bouyer if (length < 0) 310 1.85 christos return EINVAL; 311 1.1 bouyer 312 1.1 bouyer if (ovp->v_type == VLNK && 313 1.44 ws (ext2fs_size(oip) < ump->um_maxsymlinklen || 314 1.76 jakllsch (ump->um_maxsymlinklen == 0 && ext2fs_nblock(oip) == 0))) { 315 1.43 mycroft KDASSERT(length == 0); 316 1.31 fvdl memset((char *)&oip->i_din.e2fs_din->e2di_shortlink, 0, 317 1.44 ws (u_int)ext2fs_size(oip)); 318 1.44 ws (void)ext2fs_setsize(oip, 0); 319 1.85 christos goto update; 320 1.1 bouyer } 321 1.44 ws if (ext2fs_size(oip) == length) { 322 1.71 bouyer /* still do a uvm_vnp_setsize() as writesize may be larger */ 323 1.71 bouyer uvm_vnp_setsize(ovp, length); 324 1.85 christos goto update; 325 1.1 bouyer } 326 1.1 bouyer fs = oip->i_e2fs; 327 1.43 mycroft if (length > ump->um_maxfilesize) 328 1.85 christos return EFBIG; 329 1.43 mycroft 330 1.44 ws osize = ext2fs_size(oip); 331 1.43 mycroft 332 1.1 bouyer /* 333 1.1 bouyer * Lengthen the size of the file. We must ensure that the 334 1.1 bouyer * last byte of the file is allocated. Since the smallest 335 1.1 bouyer * value of osize is 0, length will be at least 1. 336 1.1 bouyer */ 337 1.1 bouyer if (osize < length) { 338 1.59 yamt uvm_vnp_setwritesize(ovp, length); 339 1.50 yamt error = ufs_balloc_range(ovp, length - 1, 1, cred, 340 1.43 mycroft ioflag & IO_SYNC ? B_SYNC : 0); 341 1.43 mycroft if (error) { 342 1.50 yamt (void) ext2fs_truncate(ovp, osize, ioflag & IO_SYNC, 343 1.62 pooka cred); 344 1.85 christos return error; 345 1.43 mycroft } 346 1.43 mycroft uvm_vnp_setsize(ovp, length); 347 1.46 kml KASSERT(error || ovp->v_size == ext2fs_size(oip)); 348 1.85 christos goto update; 349 1.1 bouyer } 350 1.1 bouyer /* 351 1.1 bouyer * Shorten the size of the file. If the file is not being 352 1.90 andvar * truncated to a block boundary, the contents of the 353 1.1 bouyer * partial block following the end of the file must be 354 1.24 wiz * zero'ed in case it ever become accessible again because 355 1.1 bouyer * of subsequent file growth. 356 1.1 bouyer */ 357 1.79 dholland offset = ext2_blkoff(fs, length); 358 1.21 chs if (offset != 0) { 359 1.1 bouyer size = fs->e2fs_bsize; 360 1.21 chs 361 1.21 chs /* XXXUBC we should handle more than just VREG */ 362 1.74 hannken ubc_zerorange(&ovp->v_uobj, length, size - offset, 363 1.89 ad UBC_VNODE_FLAGS(ovp)); 364 1.1 bouyer } 365 1.44 ws (void)ext2fs_setsize(oip, length); 366 1.6 fvdl uvm_vnp_setsize(ovp, length); 367 1.1 bouyer /* 368 1.1 bouyer * Calculate index into inode's block list of 369 1.1 bouyer * last direct and indirect blocks (if any) 370 1.1 bouyer * which we want to keep. Lastblock is -1 when 371 1.1 bouyer * the file is truncated to 0. 372 1.1 bouyer */ 373 1.81 dholland lastblock = ext2_lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 374 1.78 dholland lastiblock[SINGLE] = lastblock - EXT2FS_NDADDR; 375 1.79 dholland lastiblock[DOUBLE] = lastiblock[SINGLE] - EXT2_NINDIR(fs); 376 1.79 dholland lastiblock[TRIPLE] = lastiblock[DOUBLE] - EXT2_NINDIR(fs) * EXT2_NINDIR(fs); 377 1.1 bouyer nblocks = btodb(fs->e2fs_bsize); 378 1.1 bouyer /* 379 1.1 bouyer * Update file and block pointers on disk before we start freeing 380 1.1 bouyer * blocks. If we crash before free'ing blocks below, the blocks 381 1.1 bouyer * will be returned to the free list. lastiblock values are also 382 1.1 bouyer * normalized to -1 for calls to ext2fs_indirtrunc below. 383 1.1 bouyer */ 384 1.57 christos memcpy((void *)oldblks, (void *)&oip->i_e2fs_blocks[0], sizeof oldblks); 385 1.43 mycroft sync = 0; 386 1.43 mycroft for (level = TRIPLE; level >= SINGLE; level--) { 387 1.78 dholland if (lastiblock[level] < 0 && oldblks[EXT2FS_NDADDR + level] != 0) { 388 1.43 mycroft sync = 1; 389 1.78 dholland oip->i_e2fs_blocks[EXT2FS_NDADDR + level] = 0; 390 1.1 bouyer lastiblock[level] = -1; 391 1.1 bouyer } 392 1.43 mycroft } 393 1.78 dholland for (i = 0; i < EXT2FS_NDADDR; i++) { 394 1.43 mycroft if (i > lastblock && oldblks[i] != 0) { 395 1.43 mycroft sync = 1; 396 1.43 mycroft oip->i_e2fs_blocks[i] = 0; 397 1.43 mycroft } 398 1.43 mycroft } 399 1.1 bouyer oip->i_flag |= IN_CHANGE | IN_UPDATE; 400 1.43 mycroft if (sync) { 401 1.50 yamt error = ext2fs_update(ovp, NULL, NULL, UPDATE_WAIT); 402 1.43 mycroft if (error && !allerror) 403 1.43 mycroft allerror = error; 404 1.43 mycroft } 405 1.16 mycroft 406 1.1 bouyer /* 407 1.1 bouyer * Having written the new inode to disk, save its new configuration 408 1.1 bouyer * and put back the old block pointers long enough to process them. 409 1.1 bouyer * Note that we save the new block configuration so we can check it 410 1.1 bouyer * when we are done. 411 1.1 bouyer */ 412 1.57 christos memcpy((void *)newblks, (void *)&oip->i_e2fs_blocks[0], sizeof newblks); 413 1.57 christos memcpy((void *)&oip->i_e2fs_blocks[0], (void *)oldblks, sizeof oldblks); 414 1.43 mycroft 415 1.44 ws (void)ext2fs_setsize(oip, osize); 416 1.16 mycroft error = vtruncbuf(ovp, lastblock + 1, 0, 0); 417 1.16 mycroft if (error && !allerror) 418 1.16 mycroft allerror = error; 419 1.1 bouyer 420 1.1 bouyer /* 421 1.1 bouyer * Indirect blocks first. 422 1.1 bouyer */ 423 1.78 dholland indir_lbn[SINGLE] = -EXT2FS_NDADDR; 424 1.79 dholland indir_lbn[DOUBLE] = indir_lbn[SINGLE] - EXT2_NINDIR(fs) -1; 425 1.79 dholland indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - EXT2_NINDIR(fs) * EXT2_NINDIR(fs) - 1; 426 1.1 bouyer for (level = TRIPLE; level >= SINGLE; level--) { 427 1.29 fvdl /* XXX ondisk32 */ 428 1.78 dholland bn = fs2h32(oip->i_e2fs_blocks[EXT2FS_NDADDR + level]); 429 1.1 bouyer if (bn != 0) { 430 1.1 bouyer error = ext2fs_indirtrunc(oip, indir_lbn[level], 431 1.80 dholland EXT2_FSBTODB(fs, bn), lastiblock[level], level, &count); 432 1.1 bouyer if (error) 433 1.1 bouyer allerror = error; 434 1.1 bouyer blocksreleased += count; 435 1.1 bouyer if (lastiblock[level] < 0) { 436 1.78 dholland oip->i_e2fs_blocks[EXT2FS_NDADDR + level] = 0; 437 1.1 bouyer ext2fs_blkfree(oip, bn); 438 1.1 bouyer blocksreleased += nblocks; 439 1.1 bouyer } 440 1.1 bouyer } 441 1.1 bouyer if (lastiblock[level] >= 0) 442 1.1 bouyer goto done; 443 1.1 bouyer } 444 1.1 bouyer 445 1.1 bouyer /* 446 1.1 bouyer * All whole direct blocks or frags. 447 1.1 bouyer */ 448 1.78 dholland for (i = EXT2FS_NDADDR - 1; i > lastblock; i--) { 449 1.29 fvdl /* XXX ondisk32 */ 450 1.3 bouyer bn = fs2h32(oip->i_e2fs_blocks[i]); 451 1.1 bouyer if (bn == 0) 452 1.1 bouyer continue; 453 1.1 bouyer oip->i_e2fs_blocks[i] = 0; 454 1.1 bouyer ext2fs_blkfree(oip, bn); 455 1.1 bouyer blocksreleased += btodb(fs->e2fs_bsize); 456 1.1 bouyer } 457 1.1 bouyer 458 1.1 bouyer done: 459 1.1 bouyer #ifdef DIAGNOSTIC 460 1.1 bouyer for (level = SINGLE; level <= TRIPLE; level++) 461 1.78 dholland if (newblks[EXT2FS_NDADDR + level] != 462 1.78 dholland oip->i_e2fs_blocks[EXT2FS_NDADDR + level]) 463 1.21 chs panic("ext2fs_truncate1"); 464 1.78 dholland for (i = 0; i < EXT2FS_NDADDR; i++) 465 1.16 mycroft if (newblks[i] != oip->i_e2fs_blocks[i]) 466 1.21 chs panic("ext2fs_truncate2"); 467 1.1 bouyer if (length == 0 && 468 1.21 chs (!LIST_EMPTY(&ovp->v_cleanblkhd) || 469 1.21 chs !LIST_EMPTY(&ovp->v_dirtyblkhd))) 470 1.21 chs panic("ext2fs_truncate3"); 471 1.1 bouyer #endif /* DIAGNOSTIC */ 472 1.1 bouyer /* 473 1.1 bouyer * Put back the real size. 474 1.1 bouyer */ 475 1.44 ws (void)ext2fs_setsize(oip, length); 476 1.76 jakllsch error = ext2fs_setnblock(oip, ext2fs_nblock(oip) - blocksreleased); 477 1.76 jakllsch if (error != 0) 478 1.76 jakllsch allerror = error; 479 1.1 bouyer oip->i_flag |= IN_CHANGE; 480 1.46 kml KASSERT(ovp->v_type != VREG || ovp->v_size == ext2fs_size(oip)); 481 1.85 christos return allerror; 482 1.85 christos update: 483 1.85 christos oip->i_flag |= IN_CHANGE | IN_UPDATE; 484 1.85 christos return ext2fs_update(ovp, NULL, NULL, 0); 485 1.1 bouyer } 486 1.1 bouyer 487 1.1 bouyer /* 488 1.1 bouyer * Release blocks associated with the inode ip and stored in the indirect 489 1.1 bouyer * block bn. Blocks are free'd in LIFO order up to (but not including) 490 1.1 bouyer * lastbn. If level is greater than SINGLE, the block is an indirect block 491 1.1 bouyer * and recursive calls to indirtrunc must be used to cleanse other indirect 492 1.1 bouyer * blocks. 493 1.1 bouyer * 494 1.1 bouyer * NB: triple indirect blocks are untested. 495 1.1 bouyer */ 496 1.1 bouyer static int 497 1.47 xtraeme ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn, 498 1.47 xtraeme int level, long *countp) 499 1.1 bouyer { 500 1.14 augustss int i; 501 1.1 bouyer struct buf *bp; 502 1.14 augustss struct m_ext2fs *fs = ip->i_e2fs; 503 1.29 fvdl int32_t *bap; /* XXX ondisk32 */ 504 1.1 bouyer struct vnode *vp; 505 1.29 fvdl daddr_t nb, nlbn, last; 506 1.29 fvdl int32_t *copy = NULL; /* XXX ondisk32 */ 507 1.1 bouyer long blkcount, factor; 508 1.1 bouyer int nblocks, blocksreleased = 0; 509 1.1 bouyer int error = 0, allerror = 0; 510 1.1 bouyer 511 1.1 bouyer /* 512 1.1 bouyer * Calculate index in current block of last 513 1.1 bouyer * block to be kept. -1 indicates the entire 514 1.1 bouyer * block so we need not calculate the index. 515 1.1 bouyer */ 516 1.1 bouyer factor = 1; 517 1.1 bouyer for (i = SINGLE; i < level; i++) 518 1.79 dholland factor *= EXT2_NINDIR(fs); 519 1.1 bouyer last = lastbn; 520 1.1 bouyer if (lastbn > 0) 521 1.1 bouyer last /= factor; 522 1.1 bouyer nblocks = btodb(fs->e2fs_bsize); 523 1.1 bouyer /* 524 1.1 bouyer * Get buffer of block pointers, zero those entries corresponding 525 1.1 bouyer * to blocks to be free'd, and update on disk copy first. Since 526 1.1 bouyer * double(triple) indirect before single(double) indirect, calls 527 1.1 bouyer * to bmap on these blocks will fail. However, we already have 528 1.1 bouyer * the on disk address, so we have to set the b_blkno field 529 1.1 bouyer * explicitly instead of letting bread do everything for us. 530 1.1 bouyer */ 531 1.1 bouyer vp = ITOV(ip); 532 1.1 bouyer bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0); 533 1.63 ad if (bp->b_oflags & (BO_DONE | BO_DELWRI)) { 534 1.1 bouyer /* Braces must be here in case trace evaluates to nothing. */ 535 1.1 bouyer trace(TR_BREADHIT, pack(vp, fs->e2fs_bsize), lbn); 536 1.1 bouyer } else { 537 1.1 bouyer trace(TR_BREADMISS, pack(vp, fs->e2fs_bsize), lbn); 538 1.65 ad curlwp->l_ru.ru_inblock++; /* pay for read */ 539 1.1 bouyer bp->b_flags |= B_READ; 540 1.1 bouyer if (bp->b_bcount > bp->b_bufsize) 541 1.1 bouyer panic("ext2fs_indirtrunc: bad buffer size"); 542 1.1 bouyer bp->b_blkno = dbn; 543 1.39 hannken VOP_STRATEGY(vp, bp); 544 1.1 bouyer error = biowait(bp); 545 1.1 bouyer } 546 1.1 bouyer if (error) { 547 1.60 ad brelse(bp, 0); 548 1.1 bouyer *countp = 0; 549 1.85 christos return error; 550 1.1 bouyer } 551 1.1 bouyer 552 1.29 fvdl bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ 553 1.17 mycroft if (lastbn >= 0) { 554 1.29 fvdl /* XXX ondisk32 */ 555 1.75 para copy = kmem_alloc(fs->e2fs_bsize, KM_SLEEP); 556 1.57 christos memcpy((void *)copy, (void *)bap, (u_int)fs->e2fs_bsize); 557 1.57 christos memset((void *)&bap[last + 1], 0, 558 1.79 dholland (u_int)(EXT2_NINDIR(fs) - (last + 1)) * sizeof (uint32_t)); 559 1.1 bouyer error = bwrite(bp); 560 1.1 bouyer if (error) 561 1.1 bouyer allerror = error; 562 1.1 bouyer bap = copy; 563 1.1 bouyer } 564 1.1 bouyer 565 1.1 bouyer /* 566 1.1 bouyer * Recursively free totally unused blocks. 567 1.1 bouyer */ 568 1.79 dholland for (i = EXT2_NINDIR(fs) - 1, 569 1.1 bouyer nlbn = lbn + 1 - i * factor; i > last; 570 1.1 bouyer i--, nlbn += factor) { 571 1.29 fvdl /* XXX ondisk32 */ 572 1.3 bouyer nb = fs2h32(bap[i]); 573 1.1 bouyer if (nb == 0) 574 1.1 bouyer continue; 575 1.1 bouyer if (level > SINGLE) { 576 1.80 dholland error = ext2fs_indirtrunc(ip, nlbn, EXT2_FSBTODB(fs, nb), 577 1.29 fvdl (daddr_t)-1, level - 1, 578 1.1 bouyer &blkcount); 579 1.1 bouyer if (error) 580 1.1 bouyer allerror = error; 581 1.1 bouyer blocksreleased += blkcount; 582 1.1 bouyer } 583 1.1 bouyer ext2fs_blkfree(ip, nb); 584 1.1 bouyer blocksreleased += nblocks; 585 1.1 bouyer } 586 1.1 bouyer 587 1.1 bouyer /* 588 1.1 bouyer * Recursively free last partial block. 589 1.1 bouyer */ 590 1.1 bouyer if (level > SINGLE && lastbn >= 0) { 591 1.1 bouyer last = lastbn % factor; 592 1.29 fvdl /* XXX ondisk32 */ 593 1.3 bouyer nb = fs2h32(bap[i]); 594 1.1 bouyer if (nb != 0) { 595 1.80 dholland error = ext2fs_indirtrunc(ip, nlbn, EXT2_FSBTODB(fs, nb), 596 1.1 bouyer last, level - 1, &blkcount); 597 1.1 bouyer if (error) 598 1.1 bouyer allerror = error; 599 1.1 bouyer blocksreleased += blkcount; 600 1.1 bouyer } 601 1.1 bouyer } 602 1.1 bouyer 603 1.1 bouyer if (copy != NULL) { 604 1.75 para kmem_free(copy, fs->e2fs_bsize); 605 1.1 bouyer } else { 606 1.60 ad brelse(bp, BC_INVAL); 607 1.1 bouyer } 608 1.1 bouyer 609 1.1 bouyer *countp = blocksreleased; 610 1.85 christos return allerror; 611 1.1 bouyer } 612