+ * Modify sup->su_nbyte counters for each deleted block; keep track
+ * of number of blocks removed for ip->i_blocks.
+ */
+ blocksreleased = 0;
+ num = 0;
+ lastseg = -1;
+
+ for (lbn = olastblock; lbn >= lastblock;) {
+ lfs_bmaparray(vp, lbn, &daddr, a, &depth);
+ if (lbn == olastblock)
+ for (i = NIADDR + 2; i--;)
+ a_end[i] = a[i];
+ switch (depth) {
+ case 0: /* Direct block. */
+ daddr = ip->i_db[lbn];
+ SEGDEC;
+ ip->i_db[lbn] = 0;
+ --lbn;
+ break;
+#ifdef DIAGNOSTIC
+ case 1: /* An indirect block. */
+ panic("lfs_truncate: lfs_bmaparray returned depth 1");
+ /* NOTREACHED */
+#endif
+ default: /* Chain of indirect blocks. */
+ ap = a + --depth;
+ if (ap->in_off > 0 && lbn != lastblock) {
+ lbn -= ap->in_off < lbn - lastblock ?
+ ap->in_off : lbn - lastblock;
+ break;
+ }
+ for (; depth && (ap->in_off == 0 || lbn == lastblock);
+ --ap, --depth) {
+ /*
+ * XXX
+ * The indirect block may not yet exist, so
+ * bread will create one just so we can free
+ * it.
+ */
+ if (bread(vp,
+ ap->in_lbn, fs->lfs_bsize, NOCRED, &bp))
+ panic("lfs_truncate: bread bno %d",
+ ap->in_lbn);
+ daddrp = bp->b_un.b_daddr + ap->in_off;
+ for (i = ap->in_off;
+ i++ <= a_end[depth].in_off;) {
+ daddr = *daddrp++;
+ SEGDEC;
+ }
+ a_end[depth].in_off=NINDIR(fs)-1;
+ if (ap->in_off > 0 && lbn == lastblock) {
+ bzero(bp->b_un.b_daddr + ap->in_off,
+ fs->lfs_bsize -
+ ap->in_off * sizeof(daddr_t));
+ LFS_UBWRITE(bp);
+ } else
+ brelse (bp);
+ }
+ if (a[1].in_off == 0) {
+ off = a[0].in_off;
+ daddr = ip->i_ib[off];
+ SEGDEC;
+ ip->i_ib[off] = 0;
+ }
+ if (lbn == lastblock)
+ --lbn;
+ else {
+ lbn -= NINDIR(fs);
+ if (lbn < lastblock)
+ lbn = lastblock;
+ }
+ }
+ }
+ UPDATE_SEGUSE;
+ ip->i_blocks -= blocksreleased;
+ /*