xref: /minix3/sys/ufs/lfs/lfs_inode.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: lfs_inode.c,v 1.147 2015/09/01 06:13:09 dholland 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*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.147 2015/09/01 06:13:09 dholland 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 
8284d9c625SLionel Sambuc #include <ufs/lfs/ulfs_quotacommon.h>
8384d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
8484d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h>
8584d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
86d65f6f70SBen Gras 
87d65f6f70SBen Gras #include <ufs/lfs/lfs.h>
88*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
89d65f6f70SBen Gras #include <ufs/lfs/lfs_extern.h>
9084d9c625SLionel Sambuc #include <ufs/lfs/lfs_kernel.h>
91d65f6f70SBen Gras 
92d65f6f70SBen Gras static int lfs_update_seguse(struct lfs *, struct inode *ip, long, size_t);
93d65f6f70SBen Gras static int lfs_indirtrunc(struct inode *, daddr_t, daddr_t,
94*0a6a1f1dSLionel Sambuc 			  daddr_t, int, daddr_t *, daddr_t *,
95*0a6a1f1dSLionel Sambuc 			  long *, size_t *);
96d65f6f70SBen Gras static int lfs_blkfree (struct lfs *, struct inode *, daddr_t, size_t, long *, size_t *);
97d65f6f70SBen Gras static int lfs_vtruncbuf(struct vnode *, daddr_t, bool, int);
98d65f6f70SBen Gras 
99d65f6f70SBen Gras /* Search a block for a specific dinode. */
100*0a6a1f1dSLionel Sambuc union lfs_dinode *
lfs_ifind(struct lfs * fs,ino_t ino,struct buf * bp)101d65f6f70SBen Gras lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp)
102d65f6f70SBen Gras {
103*0a6a1f1dSLionel Sambuc 	union lfs_dinode *ldip;
104*0a6a1f1dSLionel Sambuc 	unsigned num, i;
105d65f6f70SBen Gras 
106d65f6f70SBen Gras 	ASSERT_NO_SEGLOCK(fs);
107d65f6f70SBen Gras 	/*
108d65f6f70SBen Gras 	 * Read the inode block backwards, since later versions of the
109d65f6f70SBen Gras 	 * inode will supercede earlier ones.  Though it is unlikely, it is
110d65f6f70SBen Gras 	 * possible that the same inode will appear in the same inode block.
111d65f6f70SBen Gras 	 */
112*0a6a1f1dSLionel Sambuc 	num = LFS_INOPB(fs);
113*0a6a1f1dSLionel Sambuc 	for (i = num; i-- > 0; ) {
114*0a6a1f1dSLionel Sambuc 		ldip = DINO_IN_BLOCK(fs, bp->b_data, i);
115*0a6a1f1dSLionel Sambuc 		if (lfs_dino_getinumber(fs, ldip) == ino)
116d65f6f70SBen Gras 			return (ldip);
117*0a6a1f1dSLionel Sambuc 	}
118d65f6f70SBen Gras 
119*0a6a1f1dSLionel Sambuc 	printf("searched %u entries for %ju\n", num, (uintmax_t)ino);
120*0a6a1f1dSLionel Sambuc 	printf("offset is 0x%jx (seg %d)\n", (uintmax_t)lfs_sb_getoffset(fs),
121*0a6a1f1dSLionel Sambuc 	       lfs_dtosn(fs, lfs_sb_getoffset(fs)));
122*0a6a1f1dSLionel Sambuc 	printf("block is 0x%jx (seg %d)\n",
123*0a6a1f1dSLionel Sambuc 	       (uintmax_t)LFS_DBTOFSB(fs, bp->b_blkno),
124*0a6a1f1dSLionel Sambuc 	       lfs_dtosn(fs, LFS_DBTOFSB(fs, bp->b_blkno)));
125d65f6f70SBen Gras 
126d65f6f70SBen Gras 	return NULL;
127d65f6f70SBen Gras }
128d65f6f70SBen Gras 
129d65f6f70SBen Gras int
lfs_update(struct vnode * vp,const struct timespec * acc,const struct timespec * mod,int updflags)130d65f6f70SBen Gras lfs_update(struct vnode *vp, const struct timespec *acc,
131d65f6f70SBen Gras     const struct timespec *mod, int updflags)
132d65f6f70SBen Gras {
133d65f6f70SBen Gras 	struct inode *ip;
13484d9c625SLionel Sambuc 	struct lfs *fs = VFSTOULFS(vp->v_mount)->um_lfs;
135d65f6f70SBen Gras 	int flags;
136d65f6f70SBen Gras 
137d65f6f70SBen Gras 	ASSERT_NO_SEGLOCK(fs);
138d65f6f70SBen Gras 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
139d65f6f70SBen Gras 		return (0);
140d65f6f70SBen Gras 	ip = VTOI(vp);
141d65f6f70SBen Gras 
142d65f6f70SBen Gras 	/*
143d65f6f70SBen Gras 	 * If we are called from vinvalbuf, and the file's blocks have
144d65f6f70SBen Gras 	 * already been scheduled for writing, but the writes have not
145d65f6f70SBen Gras 	 * yet completed, lfs_vflush will not be called, and vinvalbuf
146d65f6f70SBen Gras 	 * will cause a panic.	So, we must wait until any pending write
147d65f6f70SBen Gras 	 * for our inode completes, if we are called with UPDATE_WAIT set.
148d65f6f70SBen Gras 	 */
149d65f6f70SBen Gras 	mutex_enter(vp->v_interlock);
150d65f6f70SBen Gras 	while ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT &&
151d65f6f70SBen Gras 	    WRITEINPROG(vp)) {
152d65f6f70SBen Gras 		DLOG((DLOG_SEG, "lfs_update: sleeping on ino %d"
153d65f6f70SBen Gras 		      " (in progress)\n", ip->i_number));
154d65f6f70SBen Gras 		cv_wait(&vp->v_cv, vp->v_interlock);
155d65f6f70SBen Gras 	}
156d65f6f70SBen Gras 	mutex_exit(vp->v_interlock);
157d65f6f70SBen Gras 	LFS_ITIMES(ip, acc, mod, NULL);
158d65f6f70SBen Gras 	if (updflags & UPDATE_CLOSE)
159d65f6f70SBen Gras 		flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING);
160d65f6f70SBen Gras 	else
161d65f6f70SBen Gras 		flags = ip->i_flag & (IN_MODIFIED | IN_CLEANING);
162d65f6f70SBen Gras 	if (flags == 0)
163d65f6f70SBen Gras 		return (0);
164d65f6f70SBen Gras 
165d65f6f70SBen Gras 	/* If sync, push back the vnode and any dirty blocks it may have. */
166d65f6f70SBen Gras 	if ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT) {
167d65f6f70SBen Gras 		/* Avoid flushing VU_DIROP. */
168d65f6f70SBen Gras 		mutex_enter(&lfs_lock);
169d65f6f70SBen Gras 		++fs->lfs_diropwait;
170d65f6f70SBen Gras 		while (vp->v_uflag & VU_DIROP) {
171d65f6f70SBen Gras 			DLOG((DLOG_DIROP, "lfs_update: sleeping on inode %d"
172d65f6f70SBen Gras 			      " (dirops)\n", ip->i_number));
173d65f6f70SBen Gras 			DLOG((DLOG_DIROP, "lfs_update: vflags 0x%x, iflags"
174d65f6f70SBen Gras 			      " 0x%x\n",
175d65f6f70SBen Gras 			      vp->v_iflag | vp->v_vflag | vp->v_uflag,
176d65f6f70SBen Gras 			      ip->i_flag));
177d65f6f70SBen Gras 			if (fs->lfs_dirops == 0)
178d65f6f70SBen Gras 				lfs_flush_fs(fs, SEGM_SYNC);
179d65f6f70SBen Gras 			else
180d65f6f70SBen Gras 				mtsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync",
181d65f6f70SBen Gras 					0, &lfs_lock);
182d65f6f70SBen Gras 			/* XXX KS - by falling out here, are we writing the vn
183d65f6f70SBen Gras 			twice? */
184d65f6f70SBen Gras 		}
185d65f6f70SBen Gras 		--fs->lfs_diropwait;
186d65f6f70SBen Gras 		mutex_exit(&lfs_lock);
187d65f6f70SBen Gras 		return lfs_vflush(vp);
188d65f6f70SBen Gras 	}
189d65f6f70SBen Gras 	return 0;
190d65f6f70SBen Gras }
191d65f6f70SBen Gras 
192d65f6f70SBen Gras #define	SINGLE	0	/* index of single indirect block */
193d65f6f70SBen Gras #define	DOUBLE	1	/* index of double indirect block */
194d65f6f70SBen Gras #define	TRIPLE	2	/* index of triple indirect block */
195d65f6f70SBen Gras /*
196d65f6f70SBen Gras  * Truncate the inode oip to at most length size, freeing the
197d65f6f70SBen Gras  * disk blocks.
198d65f6f70SBen Gras  */
19984d9c625SLionel Sambuc /* VOP_BWRITE 1 + ULFS_NIADDR + lfs_balloc == 2 + 2*ULFS_NIADDR times */
200d65f6f70SBen Gras 
201d65f6f70SBen Gras int
lfs_truncate(struct vnode * ovp,off_t length,int ioflag,kauth_cred_t cred)202d65f6f70SBen Gras lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
203d65f6f70SBen Gras {
204d65f6f70SBen Gras 	daddr_t lastblock;
205d65f6f70SBen Gras 	struct inode *oip = VTOI(ovp);
20684d9c625SLionel Sambuc 	daddr_t bn, lbn, lastiblock[ULFS_NIADDR], indir_lbn[ULFS_NIADDR];
207*0a6a1f1dSLionel Sambuc 	/* note: newblks is set but only actually used if DIAGNOSTIC */
208*0a6a1f1dSLionel Sambuc 	daddr_t newblks[ULFS_NDADDR + ULFS_NIADDR] __diagused;
209d65f6f70SBen Gras 	struct lfs *fs;
210d65f6f70SBen Gras 	struct buf *bp;
211d65f6f70SBen Gras 	int offset, size, level;
212*0a6a1f1dSLionel Sambuc 	daddr_t count, rcount;
213*0a6a1f1dSLionel Sambuc 	daddr_t blocksreleased = 0, real_released = 0;
214d65f6f70SBen Gras 	int i, nblocks;
215d65f6f70SBen Gras 	int aflags, error, allerror = 0;
216d65f6f70SBen Gras 	off_t osize;
217d65f6f70SBen Gras 	long lastseg;
218d65f6f70SBen Gras 	size_t bc;
219d65f6f70SBen Gras 	int obufsize, odb;
220d65f6f70SBen Gras 	int usepc;
221d65f6f70SBen Gras 
222d65f6f70SBen Gras 	if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
223d65f6f70SBen Gras 	    ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
224d65f6f70SBen Gras 		KASSERT(oip->i_size == 0);
225d65f6f70SBen Gras 		return 0;
226d65f6f70SBen Gras 	}
227d65f6f70SBen Gras 
228d65f6f70SBen Gras 	if (length < 0)
229d65f6f70SBen Gras 		return (EINVAL);
230d65f6f70SBen Gras 
231d65f6f70SBen Gras 	/*
232d65f6f70SBen Gras 	 * Just return and not update modification times.
233d65f6f70SBen Gras 	 */
234d65f6f70SBen Gras 	if (oip->i_size == length) {
235d65f6f70SBen Gras 		/* still do a uvm_vnp_setsize() as writesize may be larger */
236d65f6f70SBen Gras 		uvm_vnp_setsize(ovp, length);
237d65f6f70SBen Gras 		return (0);
238d65f6f70SBen Gras 	}
239d65f6f70SBen Gras 
24084d9c625SLionel Sambuc 	fs = oip->i_lfs;
24184d9c625SLionel Sambuc 
242d65f6f70SBen Gras 	if (ovp->v_type == VLNK &&
24384d9c625SLionel Sambuc 	    (oip->i_size < fs->um_maxsymlinklen ||
24484d9c625SLionel Sambuc 	     (fs->um_maxsymlinklen == 0 &&
245*0a6a1f1dSLionel Sambuc 	      lfs_dino_getblocks(fs, oip->i_din) == 0))) {
246d65f6f70SBen Gras #ifdef DIAGNOSTIC
247d65f6f70SBen Gras 		if (length != 0)
248d65f6f70SBen Gras 			panic("lfs_truncate: partial truncate of symlink");
249d65f6f70SBen Gras #endif
250d65f6f70SBen Gras 		memset((char *)SHORTLINK(oip), 0, (u_int)oip->i_size);
251*0a6a1f1dSLionel Sambuc 		oip->i_size = 0;
252*0a6a1f1dSLionel Sambuc 		lfs_dino_setsize(fs, oip->i_din, 0);
253d65f6f70SBen Gras 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
254d65f6f70SBen Gras 		return (lfs_update(ovp, NULL, NULL, 0));
255d65f6f70SBen Gras 	}
256d65f6f70SBen Gras 	if (oip->i_size == length) {
257d65f6f70SBen Gras 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
258d65f6f70SBen Gras 		return (lfs_update(ovp, NULL, NULL, 0));
259d65f6f70SBen Gras 	}
260d65f6f70SBen Gras 	lfs_imtime(fs);
261d65f6f70SBen Gras 	osize = oip->i_size;
262d65f6f70SBen Gras 	usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode);
263d65f6f70SBen Gras 
264d65f6f70SBen Gras 	ASSERT_NO_SEGLOCK(fs);
265d65f6f70SBen Gras 	/*
266d65f6f70SBen Gras 	 * Lengthen the size of the file. We must ensure that the
267d65f6f70SBen Gras 	 * last byte of the file is allocated. Since the smallest
268d65f6f70SBen Gras 	 * value of osize is 0, length will be at least 1.
269d65f6f70SBen Gras 	 */
270d65f6f70SBen Gras 	if (osize < length) {
27184d9c625SLionel Sambuc 		if (length > fs->um_maxfilesize)
272d65f6f70SBen Gras 			return (EFBIG);
273d65f6f70SBen Gras 		aflags = B_CLRBUF;
274d65f6f70SBen Gras 		if (ioflag & IO_SYNC)
275d65f6f70SBen Gras 			aflags |= B_SYNC;
276d65f6f70SBen Gras 		if (usepc) {
27784d9c625SLionel Sambuc 			if (lfs_lblkno(fs, osize) < ULFS_NDADDR &&
27884d9c625SLionel Sambuc 			    lfs_lblkno(fs, osize) != lfs_lblkno(fs, length) &&
27984d9c625SLionel Sambuc 			    lfs_blkroundup(fs, osize) != osize) {
280d65f6f70SBen Gras 				off_t eob;
281d65f6f70SBen Gras 
28284d9c625SLionel Sambuc 				eob = lfs_blkroundup(fs, osize);
283d65f6f70SBen Gras 				uvm_vnp_setwritesize(ovp, eob);
28484d9c625SLionel Sambuc 				error = ulfs_balloc_range(ovp, osize,
285d65f6f70SBen Gras 				    eob - osize, cred, aflags);
286d65f6f70SBen Gras 				if (error) {
287d65f6f70SBen Gras 					(void) lfs_truncate(ovp, osize,
288d65f6f70SBen Gras 						    ioflag & IO_SYNC, cred);
289d65f6f70SBen Gras 					return error;
290d65f6f70SBen Gras 				}
291d65f6f70SBen Gras 				if (ioflag & IO_SYNC) {
292d65f6f70SBen Gras 					mutex_enter(ovp->v_interlock);
293d65f6f70SBen Gras 					VOP_PUTPAGES(ovp,
294*0a6a1f1dSLionel Sambuc 					    trunc_page(osize & lfs_sb_getbmask(fs)),
295d65f6f70SBen Gras 					    round_page(eob),
296d65f6f70SBen Gras 					    PGO_CLEANIT | PGO_SYNCIO);
297d65f6f70SBen Gras 				}
298d65f6f70SBen Gras 			}
299d65f6f70SBen Gras 			uvm_vnp_setwritesize(ovp, length);
30084d9c625SLionel Sambuc 			error = ulfs_balloc_range(ovp, length - 1, 1, cred,
301d65f6f70SBen Gras 						 aflags);
302d65f6f70SBen Gras 			if (error) {
303d65f6f70SBen Gras 				(void) lfs_truncate(ovp, osize,
304d65f6f70SBen Gras 						    ioflag & IO_SYNC, cred);
305d65f6f70SBen Gras 				return error;
306d65f6f70SBen Gras 			}
307d65f6f70SBen Gras 			uvm_vnp_setsize(ovp, length);
308d65f6f70SBen Gras 			oip->i_flag |= IN_CHANGE | IN_UPDATE;
309d65f6f70SBen Gras 			KASSERT(ovp->v_size == oip->i_size);
310*0a6a1f1dSLionel Sambuc 			oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + lfs_sb_getbsize(fs) - 1) - 1;
311d65f6f70SBen Gras 			return (lfs_update(ovp, NULL, NULL, 0));
312d65f6f70SBen Gras 		} else {
313d65f6f70SBen Gras 			error = lfs_reserve(fs, ovp, NULL,
314*0a6a1f1dSLionel Sambuc 			    lfs_btofsb(fs, (ULFS_NIADDR + 2) << lfs_sb_getbshift(fs)));
315d65f6f70SBen Gras 			if (error)
316d65f6f70SBen Gras 				return (error);
317d65f6f70SBen Gras 			error = lfs_balloc(ovp, length - 1, 1, cred,
318d65f6f70SBen Gras 					   aflags, &bp);
319d65f6f70SBen Gras 			lfs_reserve(fs, ovp, NULL,
320*0a6a1f1dSLionel Sambuc 			    -lfs_btofsb(fs, (ULFS_NIADDR + 2) << lfs_sb_getbshift(fs)));
321d65f6f70SBen Gras 			if (error)
322d65f6f70SBen Gras 				return (error);
323*0a6a1f1dSLionel Sambuc 			oip->i_size = length;
324*0a6a1f1dSLionel Sambuc 			lfs_dino_setsize(fs, oip->i_din, oip->i_size);
325d65f6f70SBen Gras 			uvm_vnp_setsize(ovp, length);
326d65f6f70SBen Gras 			(void) VOP_BWRITE(bp->b_vp, bp);
327d65f6f70SBen Gras 			oip->i_flag |= IN_CHANGE | IN_UPDATE;
328*0a6a1f1dSLionel Sambuc 			oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + lfs_sb_getbsize(fs) - 1) - 1;
329d65f6f70SBen Gras 			return (lfs_update(ovp, NULL, NULL, 0));
330d65f6f70SBen Gras 		}
331d65f6f70SBen Gras 	}
332d65f6f70SBen Gras 
333d65f6f70SBen Gras 	if ((error = lfs_reserve(fs, ovp, NULL,
334*0a6a1f1dSLionel Sambuc 	    lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << lfs_sb_getbshift(fs)))) != 0)
335d65f6f70SBen Gras 		return (error);
336d65f6f70SBen Gras 
337d65f6f70SBen Gras 	/*
338d65f6f70SBen Gras 	 * Shorten the size of the file. If the file is not being
339d65f6f70SBen Gras 	 * truncated to a block boundary, the contents of the
340d65f6f70SBen Gras 	 * partial block following the end of the file must be
341d65f6f70SBen Gras 	 * zero'ed in case it ever becomes accessible again because
342d65f6f70SBen Gras 	 * of subsequent file growth. Directories however are not
343d65f6f70SBen Gras 	 * zero'ed as they should grow back initialized to empty.
344d65f6f70SBen Gras 	 */
34584d9c625SLionel Sambuc 	offset = lfs_blkoff(fs, length);
346d65f6f70SBen Gras 	lastseg = -1;
347d65f6f70SBen Gras 	bc = 0;
348d65f6f70SBen Gras 
349d65f6f70SBen Gras 	if (ovp != fs->lfs_ivnode)
350d65f6f70SBen Gras 		lfs_seglock(fs, SEGM_PROT);
351d65f6f70SBen Gras 	if (offset == 0) {
352*0a6a1f1dSLionel Sambuc 		oip->i_size = length;
353*0a6a1f1dSLionel Sambuc 		lfs_dino_setsize(fs, oip->i_din, oip->i_size);
354d65f6f70SBen Gras 	} else if (!usepc) {
35584d9c625SLionel Sambuc 		lbn = lfs_lblkno(fs, length);
356d65f6f70SBen Gras 		aflags = B_CLRBUF;
357d65f6f70SBen Gras 		if (ioflag & IO_SYNC)
358d65f6f70SBen Gras 			aflags |= B_SYNC;
359d65f6f70SBen Gras 		error = lfs_balloc(ovp, length - 1, 1, cred, aflags, &bp);
360d65f6f70SBen Gras 		if (error) {
361d65f6f70SBen Gras 			lfs_reserve(fs, ovp, NULL,
362*0a6a1f1dSLionel Sambuc 			    -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << lfs_sb_getbshift(fs)));
363d65f6f70SBen Gras 			goto errout;
364d65f6f70SBen Gras 		}
365d65f6f70SBen Gras 		obufsize = bp->b_bufsize;
36684d9c625SLionel Sambuc 		odb = lfs_btofsb(fs, bp->b_bcount);
367*0a6a1f1dSLionel Sambuc 		oip->i_size = length;
368*0a6a1f1dSLionel Sambuc 		lfs_dino_setsize(fs, oip->i_din, oip->i_size);
36984d9c625SLionel Sambuc 		size = lfs_blksize(fs, oip, lbn);
370d65f6f70SBen Gras 		if (ovp->v_type != VDIR)
371d65f6f70SBen Gras 			memset((char *)bp->b_data + offset, 0,
372d65f6f70SBen Gras 			       (u_int)(size - offset));
373d65f6f70SBen Gras 		allocbuf(bp, size, 1);
374d65f6f70SBen Gras 		if ((bp->b_flags & B_LOCKED) != 0 && bp->b_iodone == NULL) {
375d65f6f70SBen Gras 			mutex_enter(&lfs_lock);
376d65f6f70SBen Gras 			locked_queue_bytes -= obufsize - bp->b_bufsize;
377d65f6f70SBen Gras 			mutex_exit(&lfs_lock);
378d65f6f70SBen Gras 		}
379*0a6a1f1dSLionel Sambuc 		if (bp->b_oflags & BO_DELWRI) {
380*0a6a1f1dSLionel Sambuc 			lfs_sb_addavail(fs, odb - lfs_btofsb(fs, size));
381*0a6a1f1dSLionel Sambuc 			/* XXX shouldn't this wake up on lfs_availsleep? */
382*0a6a1f1dSLionel Sambuc 		}
383d65f6f70SBen Gras 		(void) VOP_BWRITE(bp->b_vp, bp);
384d65f6f70SBen Gras 	} else { /* vp->v_type == VREG && length < osize && offset != 0 */
385d65f6f70SBen Gras 		/*
386d65f6f70SBen Gras 		 * When truncating a regular file down to a non-block-aligned
387d65f6f70SBen Gras 		 * size, we must zero the part of last block which is past
388d65f6f70SBen Gras 		 * the new EOF.  We must synchronously flush the zeroed pages
389d65f6f70SBen Gras 		 * to disk since the new pages will be invalidated as soon
390d65f6f70SBen Gras 		 * as we inform the VM system of the new, smaller size.
391d65f6f70SBen Gras 		 * We must do this before acquiring the GLOCK, since fetching
392d65f6f70SBen Gras 		 * the pages will acquire the GLOCK internally.
393d65f6f70SBen Gras 		 * So there is a window where another thread could see a whole
394d65f6f70SBen Gras 		 * zeroed page past EOF, but that's life.
395d65f6f70SBen Gras 		 */
396d65f6f70SBen Gras 		daddr_t xlbn;
397d65f6f70SBen Gras 		voff_t eoz;
398d65f6f70SBen Gras 
399d65f6f70SBen Gras 		aflags = ioflag & IO_SYNC ? B_SYNC : 0;
40084d9c625SLionel Sambuc 		error = ulfs_balloc_range(ovp, length - 1, 1, cred, aflags);
401d65f6f70SBen Gras 		if (error) {
402d65f6f70SBen Gras 			lfs_reserve(fs, ovp, NULL,
403*0a6a1f1dSLionel Sambuc 				    -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << lfs_sb_getbshift(fs)));
404d65f6f70SBen Gras 			goto errout;
405d65f6f70SBen Gras 		}
40684d9c625SLionel Sambuc 		xlbn = lfs_lblkno(fs, length);
40784d9c625SLionel Sambuc 		size = lfs_blksize(fs, oip, xlbn);
40884d9c625SLionel Sambuc 		eoz = MIN(lfs_lblktosize(fs, xlbn) + size, osize);
409d65f6f70SBen Gras 		ubc_zerorange(&ovp->v_uobj, length, eoz - length,
410d65f6f70SBen Gras 		    UBC_UNMAP_FLAG(ovp));
411d65f6f70SBen Gras 		if (round_page(eoz) > round_page(length)) {
412d65f6f70SBen Gras 			mutex_enter(ovp->v_interlock);
413d65f6f70SBen Gras 			error = VOP_PUTPAGES(ovp, round_page(length),
414d65f6f70SBen Gras 			    round_page(eoz),
415d65f6f70SBen Gras 			    PGO_CLEANIT | PGO_DEACTIVATE |
416d65f6f70SBen Gras 			    ((ioflag & IO_SYNC) ? PGO_SYNCIO : 0));
417d65f6f70SBen Gras 			if (error) {
418d65f6f70SBen Gras 				lfs_reserve(fs, ovp, NULL,
419*0a6a1f1dSLionel Sambuc 					    -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << lfs_sb_getbshift(fs)));
420d65f6f70SBen Gras 				goto errout;
421d65f6f70SBen Gras 			}
422d65f6f70SBen Gras 		}
423d65f6f70SBen Gras 	}
424d65f6f70SBen Gras 
425d65f6f70SBen Gras 	genfs_node_wrlock(ovp);
426d65f6f70SBen Gras 
427*0a6a1f1dSLionel Sambuc 	oip->i_size = length;
428*0a6a1f1dSLionel Sambuc 	lfs_dino_setsize(fs, oip->i_din, oip->i_size);
429d65f6f70SBen Gras 	uvm_vnp_setsize(ovp, length);
430d65f6f70SBen Gras 
431d65f6f70SBen Gras 	/*
432d65f6f70SBen Gras 	 * Calculate index into inode's block list of
433d65f6f70SBen Gras 	 * last direct and indirect blocks (if any)
434d65f6f70SBen Gras 	 * which we want to keep.  Lastblock is -1 when
435d65f6f70SBen Gras 	 * the file is truncated to 0.
436d65f6f70SBen Gras 	 */
437d65f6f70SBen Gras 	/* Avoid sign overflow - XXX assumes that off_t is a quad_t. */
438*0a6a1f1dSLionel Sambuc 	if (length > QUAD_MAX - lfs_sb_getbsize(fs))
439*0a6a1f1dSLionel Sambuc 		lastblock = lfs_lblkno(fs, QUAD_MAX - lfs_sb_getbsize(fs));
440d65f6f70SBen Gras 	else
441*0a6a1f1dSLionel Sambuc 		lastblock = lfs_lblkno(fs, length + lfs_sb_getbsize(fs) - 1) - 1;
44284d9c625SLionel Sambuc 	lastiblock[SINGLE] = lastblock - ULFS_NDADDR;
44384d9c625SLionel Sambuc 	lastiblock[DOUBLE] = lastiblock[SINGLE] - LFS_NINDIR(fs);
44484d9c625SLionel Sambuc 	lastiblock[TRIPLE] = lastiblock[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs);
445*0a6a1f1dSLionel Sambuc 	nblocks = lfs_btofsb(fs, lfs_sb_getbsize(fs));
446d65f6f70SBen Gras 	/*
447d65f6f70SBen Gras 	 * Record changed file and block pointers before we start
448d65f6f70SBen Gras 	 * freeing blocks.  lastiblock values are also normalized to -1
449d65f6f70SBen Gras 	 * for calls to lfs_indirtrunc below.
450d65f6f70SBen Gras 	 */
451*0a6a1f1dSLionel Sambuc 	for (i=0; i<ULFS_NDADDR; i++) {
452*0a6a1f1dSLionel Sambuc 		newblks[i] = lfs_dino_getdb(fs, oip->i_din, i);
453*0a6a1f1dSLionel Sambuc 	}
454*0a6a1f1dSLionel Sambuc 	for (i=0; i<ULFS_NIADDR; i++) {
455*0a6a1f1dSLionel Sambuc 		newblks[ULFS_NDADDR + i] = lfs_dino_getib(fs, oip->i_din, i);
456*0a6a1f1dSLionel Sambuc 	}
457d65f6f70SBen Gras 	for (level = TRIPLE; level >= SINGLE; level--)
458d65f6f70SBen Gras 		if (lastiblock[level] < 0) {
45984d9c625SLionel Sambuc 			newblks[ULFS_NDADDR+level] = 0;
460d65f6f70SBen Gras 			lastiblock[level] = -1;
461d65f6f70SBen Gras 		}
46284d9c625SLionel Sambuc 	for (i = ULFS_NDADDR - 1; i > lastblock; i--)
463d65f6f70SBen Gras 		newblks[i] = 0;
464d65f6f70SBen Gras 
465*0a6a1f1dSLionel Sambuc 	oip->i_size = osize;
466*0a6a1f1dSLionel Sambuc 	lfs_dino_setsize(fs, oip->i_din, oip->i_size);
467d65f6f70SBen Gras 	error = lfs_vtruncbuf(ovp, lastblock + 1, false, 0);
468d65f6f70SBen Gras 	if (error && !allerror)
469d65f6f70SBen Gras 		allerror = error;
470d65f6f70SBen Gras 
471d65f6f70SBen Gras 	/*
472d65f6f70SBen Gras 	 * Indirect blocks first.
473d65f6f70SBen Gras 	 */
47484d9c625SLionel Sambuc 	indir_lbn[SINGLE] = -ULFS_NDADDR;
47584d9c625SLionel Sambuc 	indir_lbn[DOUBLE] = indir_lbn[SINGLE] - LFS_NINDIR(fs) - 1;
47684d9c625SLionel Sambuc 	indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs) - 1;
477d65f6f70SBen Gras 	for (level = TRIPLE; level >= SINGLE; level--) {
478*0a6a1f1dSLionel Sambuc 		bn = lfs_dino_getib(fs, oip->i_din, level);
479d65f6f70SBen Gras 		if (bn != 0) {
480d65f6f70SBen Gras 			error = lfs_indirtrunc(oip, indir_lbn[level],
481d65f6f70SBen Gras 					       bn, lastiblock[level],
482d65f6f70SBen Gras 					       level, &count, &rcount,
483d65f6f70SBen Gras 					       &lastseg, &bc);
484d65f6f70SBen Gras 			if (error)
485d65f6f70SBen Gras 				allerror = error;
486d65f6f70SBen Gras 			real_released += rcount;
487d65f6f70SBen Gras 			blocksreleased += count;
488d65f6f70SBen Gras 			if (lastiblock[level] < 0) {
489*0a6a1f1dSLionel Sambuc 				if (lfs_dino_getib(fs, oip->i_din, level) > 0)
490d65f6f70SBen Gras 					real_released += nblocks;
491d65f6f70SBen Gras 				blocksreleased += nblocks;
492*0a6a1f1dSLionel Sambuc 				lfs_dino_setib(fs, oip->i_din, level, 0);
493*0a6a1f1dSLionel Sambuc 				lfs_blkfree(fs, oip, bn, lfs_sb_getbsize(fs),
494d65f6f70SBen Gras 					    &lastseg, &bc);
495d65f6f70SBen Gras         			lfs_deregister_block(ovp, bn);
496d65f6f70SBen Gras 			}
497d65f6f70SBen Gras 		}
498d65f6f70SBen Gras 		if (lastiblock[level] >= 0)
499d65f6f70SBen Gras 			goto done;
500d65f6f70SBen Gras 	}
501d65f6f70SBen Gras 
502d65f6f70SBen Gras 	/*
503d65f6f70SBen Gras 	 * All whole direct blocks or frags.
504d65f6f70SBen Gras 	 */
50584d9c625SLionel Sambuc 	for (i = ULFS_NDADDR - 1; i > lastblock; i--) {
506d65f6f70SBen Gras 		long bsize, obsize;
507d65f6f70SBen Gras 
508*0a6a1f1dSLionel Sambuc 		bn = lfs_dino_getdb(fs, oip->i_din, i);
509d65f6f70SBen Gras 		if (bn == 0)
510d65f6f70SBen Gras 			continue;
51184d9c625SLionel Sambuc 		bsize = lfs_blksize(fs, oip, i);
512*0a6a1f1dSLionel Sambuc 		if (lfs_dino_getdb(fs, oip->i_din, i) > 0) {
513d65f6f70SBen Gras 			/* Check for fragment size changes */
514d65f6f70SBen Gras 			obsize = oip->i_lfs_fragsize[i];
51584d9c625SLionel Sambuc 			real_released += lfs_btofsb(fs, obsize);
516d65f6f70SBen Gras 			oip->i_lfs_fragsize[i] = 0;
517d65f6f70SBen Gras 		} else
518d65f6f70SBen Gras 			obsize = 0;
51984d9c625SLionel Sambuc 		blocksreleased += lfs_btofsb(fs, bsize);
520*0a6a1f1dSLionel Sambuc 		lfs_dino_setdb(fs, oip->i_din, i, 0);
521d65f6f70SBen Gras 		lfs_blkfree(fs, oip, bn, obsize, &lastseg, &bc);
522d65f6f70SBen Gras         	lfs_deregister_block(ovp, bn);
523d65f6f70SBen Gras 	}
524d65f6f70SBen Gras 	if (lastblock < 0)
525d65f6f70SBen Gras 		goto done;
526d65f6f70SBen Gras 
527d65f6f70SBen Gras 	/*
528d65f6f70SBen Gras 	 * Finally, look for a change in size of the
529d65f6f70SBen Gras 	 * last direct block; release any frags.
530d65f6f70SBen Gras 	 */
531*0a6a1f1dSLionel Sambuc 	bn = lfs_dino_getdb(fs, oip->i_din, lastblock);
532d65f6f70SBen Gras 	if (bn != 0) {
533d65f6f70SBen Gras 		long oldspace, newspace;
534d65f6f70SBen Gras #if 0
535d65f6f70SBen Gras 		long olddspace;
536d65f6f70SBen Gras #endif
537d65f6f70SBen Gras 
538d65f6f70SBen Gras 		/*
539d65f6f70SBen Gras 		 * Calculate amount of space we're giving
540d65f6f70SBen Gras 		 * back as old block size minus new block size.
541d65f6f70SBen Gras 		 */
54284d9c625SLionel Sambuc 		oldspace = lfs_blksize(fs, oip, lastblock);
543d65f6f70SBen Gras #if 0
544d65f6f70SBen Gras 		olddspace = oip->i_lfs_fragsize[lastblock];
545d65f6f70SBen Gras #endif
546d65f6f70SBen Gras 
547*0a6a1f1dSLionel Sambuc 		oip->i_size = length;
548*0a6a1f1dSLionel Sambuc 		lfs_dino_setsize(fs, oip->i_din, oip->i_size);
54984d9c625SLionel Sambuc 		newspace = lfs_blksize(fs, oip, lastblock);
550d65f6f70SBen Gras 		if (newspace == 0)
551d65f6f70SBen Gras 			panic("itrunc: newspace");
552d65f6f70SBen Gras 		if (oldspace - newspace > 0) {
55384d9c625SLionel Sambuc 			blocksreleased += lfs_btofsb(fs, oldspace - newspace);
554d65f6f70SBen Gras 		}
555d65f6f70SBen Gras #if 0
556d65f6f70SBen Gras 		if (bn > 0 && olddspace - newspace > 0) {
557d65f6f70SBen Gras 			/* No segment accounting here, just vnode */
55884d9c625SLionel Sambuc 			real_released += lfs_btofsb(fs, olddspace - newspace);
559d65f6f70SBen Gras 		}
560d65f6f70SBen Gras #endif
561d65f6f70SBen Gras 	}
562d65f6f70SBen Gras 
563d65f6f70SBen Gras done:
564d65f6f70SBen Gras 	/* Finish segment accounting corrections */
565d65f6f70SBen Gras 	lfs_update_seguse(fs, oip, lastseg, bc);
566d65f6f70SBen Gras #ifdef DIAGNOSTIC
567d65f6f70SBen Gras 	for (level = SINGLE; level <= TRIPLE; level++)
56884d9c625SLionel Sambuc 		if ((newblks[ULFS_NDADDR + level] == 0) !=
569*0a6a1f1dSLionel Sambuc 		    (lfs_dino_getib(fs, oip->i_din, level) == 0)) {
570d65f6f70SBen Gras 			panic("lfs itrunc1");
571d65f6f70SBen Gras 		}
57284d9c625SLionel Sambuc 	for (i = 0; i < ULFS_NDADDR; i++)
573*0a6a1f1dSLionel Sambuc 		if ((newblks[i] == 0) !=
574*0a6a1f1dSLionel Sambuc 		    (lfs_dino_getdb(fs, oip->i_din, i) == 0)) {
575d65f6f70SBen Gras 			panic("lfs itrunc2");
576d65f6f70SBen Gras 		}
577d65f6f70SBen Gras 	if (length == 0 &&
578d65f6f70SBen Gras 	    (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd)))
579d65f6f70SBen Gras 		panic("lfs itrunc3");
580d65f6f70SBen Gras #endif /* DIAGNOSTIC */
581d65f6f70SBen Gras 	/*
582d65f6f70SBen Gras 	 * Put back the real size.
583d65f6f70SBen Gras 	 */
584*0a6a1f1dSLionel Sambuc 	oip->i_size = length;
585*0a6a1f1dSLionel Sambuc 	lfs_dino_setsize(fs, oip->i_din, oip->i_size);
586d65f6f70SBen Gras 	oip->i_lfs_effnblks -= blocksreleased;
587*0a6a1f1dSLionel Sambuc 	lfs_dino_setblocks(fs, oip->i_din,
588*0a6a1f1dSLionel Sambuc 	    lfs_dino_getblocks(fs, oip->i_din) - real_released);
589d65f6f70SBen Gras 	mutex_enter(&lfs_lock);
590*0a6a1f1dSLionel Sambuc 	lfs_sb_addbfree(fs, blocksreleased);
591d65f6f70SBen Gras 	mutex_exit(&lfs_lock);
592d65f6f70SBen Gras #ifdef DIAGNOSTIC
593d65f6f70SBen Gras 	if (oip->i_size == 0 &&
594*0a6a1f1dSLionel Sambuc 	    (lfs_dino_getblocks(fs, oip->i_din) != 0 || oip->i_lfs_effnblks != 0)) {
595*0a6a1f1dSLionel Sambuc 		printf("lfs_truncate: truncate to 0 but %jd blks/%jd effblks\n",
596*0a6a1f1dSLionel Sambuc 		       (intmax_t)lfs_dino_getblocks(fs, oip->i_din),
597*0a6a1f1dSLionel Sambuc 		       (intmax_t)oip->i_lfs_effnblks);
598d65f6f70SBen Gras 		panic("lfs_truncate: persistent blocks");
599d65f6f70SBen Gras 	}
600d65f6f70SBen Gras #endif
601d65f6f70SBen Gras 
602d65f6f70SBen Gras 	/*
603d65f6f70SBen Gras 	 * If we truncated to zero, take us off the paging queue.
604d65f6f70SBen Gras 	 */
605d65f6f70SBen Gras 	mutex_enter(&lfs_lock);
606d65f6f70SBen Gras 	if (oip->i_size == 0 && oip->i_flags & IN_PAGING) {
607d65f6f70SBen Gras 		oip->i_flags &= ~IN_PAGING;
608d65f6f70SBen Gras 		TAILQ_REMOVE(&fs->lfs_pchainhd, oip, i_lfs_pchain);
609d65f6f70SBen Gras 	}
610d65f6f70SBen Gras 	mutex_exit(&lfs_lock);
611d65f6f70SBen Gras 
612d65f6f70SBen Gras 	oip->i_flag |= IN_CHANGE;
61384d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
61484d9c625SLionel Sambuc 	(void) lfs_chkdq(oip, -blocksreleased, NOCRED, 0);
615d65f6f70SBen Gras #endif
616d65f6f70SBen Gras 	lfs_reserve(fs, ovp, NULL,
617*0a6a1f1dSLionel Sambuc 	    -lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << lfs_sb_getbshift(fs)));
618d65f6f70SBen Gras 	genfs_node_unlock(ovp);
619d65f6f70SBen Gras   errout:
620*0a6a1f1dSLionel Sambuc 	oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + lfs_sb_getbsize(fs) - 1) - 1;
621d65f6f70SBen Gras 	if (ovp != fs->lfs_ivnode)
622d65f6f70SBen Gras 		lfs_segunlock(fs);
623d65f6f70SBen Gras 	return (allerror ? allerror : error);
624d65f6f70SBen Gras }
625d65f6f70SBen Gras 
626d65f6f70SBen Gras /* Update segment and avail usage information when removing a block. */
627d65f6f70SBen Gras static int
lfs_blkfree(struct lfs * fs,struct inode * ip,daddr_t daddr,size_t bsize,long * lastseg,size_t * num)628d65f6f70SBen Gras lfs_blkfree(struct lfs *fs, struct inode *ip, daddr_t daddr,
629d65f6f70SBen Gras 	    size_t bsize, long *lastseg, size_t *num)
630d65f6f70SBen Gras {
631d65f6f70SBen Gras 	long seg;
632d65f6f70SBen Gras 	int error = 0;
633d65f6f70SBen Gras 
634d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
63584d9c625SLionel Sambuc 	bsize = lfs_fragroundup(fs, bsize);
636d65f6f70SBen Gras 	if (daddr > 0) {
63784d9c625SLionel Sambuc 		if (*lastseg != (seg = lfs_dtosn(fs, daddr))) {
638d65f6f70SBen Gras 			error = lfs_update_seguse(fs, ip, *lastseg, *num);
639d65f6f70SBen Gras 			*num = bsize;
640d65f6f70SBen Gras 			*lastseg = seg;
641d65f6f70SBen Gras 		} else
642d65f6f70SBen Gras 			*num += bsize;
643d65f6f70SBen Gras 	}
644d65f6f70SBen Gras 
645d65f6f70SBen Gras 	return error;
646d65f6f70SBen Gras }
647d65f6f70SBen Gras 
648d65f6f70SBen Gras /* Finish the accounting updates for a segment. */
649d65f6f70SBen Gras static int
lfs_update_seguse(struct lfs * fs,struct inode * ip,long lastseg,size_t num)650d65f6f70SBen Gras lfs_update_seguse(struct lfs *fs, struct inode *ip, long lastseg, size_t num)
651d65f6f70SBen Gras {
652d65f6f70SBen Gras 	struct segdelta *sd;
653d65f6f70SBen Gras 
654d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
655d65f6f70SBen Gras 	if (lastseg < 0 || num == 0)
656d65f6f70SBen Gras 		return 0;
657d65f6f70SBen Gras 
658d65f6f70SBen Gras 	LIST_FOREACH(sd, &ip->i_lfs_segdhd, list)
659d65f6f70SBen Gras 		if (sd->segnum == lastseg)
660d65f6f70SBen Gras 			break;
661d65f6f70SBen Gras 	if (sd == NULL) {
662d65f6f70SBen Gras 		sd = malloc(sizeof(*sd), M_SEGMENT, M_WAITOK);
663d65f6f70SBen Gras 		sd->segnum = lastseg;
664d65f6f70SBen Gras 		sd->num = 0;
665d65f6f70SBen Gras 		LIST_INSERT_HEAD(&ip->i_lfs_segdhd, sd, list);
666d65f6f70SBen Gras 	}
667d65f6f70SBen Gras 	sd->num += num;
668d65f6f70SBen Gras 
669d65f6f70SBen Gras 	return 0;
670d65f6f70SBen Gras }
671d65f6f70SBen Gras 
672d65f6f70SBen Gras static void
lfs_finalize_seguse(struct lfs * fs,void * v)673d65f6f70SBen Gras lfs_finalize_seguse(struct lfs *fs, void *v)
674d65f6f70SBen Gras {
675d65f6f70SBen Gras 	SEGUSE *sup;
676d65f6f70SBen Gras 	struct buf *bp;
677d65f6f70SBen Gras 	struct segdelta *sd;
678d65f6f70SBen Gras 	LIST_HEAD(, segdelta) *hd = v;
679d65f6f70SBen Gras 
680d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
681d65f6f70SBen Gras 	while((sd = LIST_FIRST(hd)) != NULL) {
682d65f6f70SBen Gras 		LIST_REMOVE(sd, list);
683d65f6f70SBen Gras 		LFS_SEGENTRY(sup, fs, sd->segnum, bp);
684d65f6f70SBen Gras 		if (sd->num > sup->su_nbytes) {
685d65f6f70SBen Gras 			printf("lfs_finalize_seguse: segment %ld short by %ld\n",
686d65f6f70SBen Gras 				sd->segnum, (long)(sd->num - sup->su_nbytes));
687d65f6f70SBen Gras 			panic("lfs_finalize_seguse: negative bytes");
688d65f6f70SBen Gras 			sup->su_nbytes = sd->num;
689d65f6f70SBen Gras 		}
690d65f6f70SBen Gras 		sup->su_nbytes -= sd->num;
691d65f6f70SBen Gras 		LFS_WRITESEGENTRY(sup, fs, sd->segnum, bp);
692d65f6f70SBen Gras 		free(sd, M_SEGMENT);
693d65f6f70SBen Gras 	}
694d65f6f70SBen Gras }
695d65f6f70SBen Gras 
696d65f6f70SBen Gras /* Finish the accounting updates for a segment. */
697d65f6f70SBen Gras void
lfs_finalize_ino_seguse(struct lfs * fs,struct inode * ip)698d65f6f70SBen Gras lfs_finalize_ino_seguse(struct lfs *fs, struct inode *ip)
699d65f6f70SBen Gras {
700d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
701d65f6f70SBen Gras 	lfs_finalize_seguse(fs, &ip->i_lfs_segdhd);
702d65f6f70SBen Gras }
703d65f6f70SBen Gras 
704d65f6f70SBen Gras /* Finish the accounting updates for a segment. */
705d65f6f70SBen Gras void
lfs_finalize_fs_seguse(struct lfs * fs)706d65f6f70SBen Gras lfs_finalize_fs_seguse(struct lfs *fs)
707d65f6f70SBen Gras {
708d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
709d65f6f70SBen Gras 	lfs_finalize_seguse(fs, &fs->lfs_segdhd);
710d65f6f70SBen Gras }
711d65f6f70SBen Gras 
712d65f6f70SBen Gras /*
713d65f6f70SBen Gras  * Release blocks associated with the inode ip and stored in the indirect
714d65f6f70SBen Gras  * block bn.  Blocks are free'd in LIFO order up to (but not including)
715d65f6f70SBen Gras  * lastbn.  If level is greater than SINGLE, the block is an indirect block
716d65f6f70SBen Gras  * and recursive calls to indirtrunc must be used to cleanse other indirect
717d65f6f70SBen Gras  * blocks.
718d65f6f70SBen Gras  *
719d65f6f70SBen Gras  * NB: triple indirect blocks are untested.
720d65f6f70SBen Gras  */
721d65f6f70SBen Gras static int
lfs_indirtrunc(struct inode * ip,daddr_t lbn,daddr_t dbn,daddr_t lastbn,int level,daddr_t * countp,daddr_t * rcountp,long * lastsegp,size_t * bcp)722d65f6f70SBen Gras lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
723*0a6a1f1dSLionel Sambuc 	       daddr_t lastbn, int level, daddr_t *countp,
724*0a6a1f1dSLionel Sambuc 	       daddr_t *rcountp, long *lastsegp, size_t *bcp)
725d65f6f70SBen Gras {
726d65f6f70SBen Gras 	int i;
727d65f6f70SBen Gras 	struct buf *bp;
728d65f6f70SBen Gras 	struct lfs *fs = ip->i_lfs;
729*0a6a1f1dSLionel Sambuc 	void *bap;
730*0a6a1f1dSLionel Sambuc 	bool bap_needs_free;
731d65f6f70SBen Gras 	struct vnode *vp;
732d65f6f70SBen Gras 	daddr_t nb, nlbn, last;
733*0a6a1f1dSLionel Sambuc 	daddr_t blkcount, rblkcount, factor;
734*0a6a1f1dSLionel Sambuc 	int nblocks;
735*0a6a1f1dSLionel Sambuc 	daddr_t blocksreleased = 0, real_released = 0;
736d65f6f70SBen Gras 	int error = 0, allerror = 0;
737d65f6f70SBen Gras 
738d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
739d65f6f70SBen Gras 	/*
740d65f6f70SBen Gras 	 * Calculate index in current block of last
741d65f6f70SBen Gras 	 * block to be kept.  -1 indicates the entire
742d65f6f70SBen Gras 	 * block so we need not calculate the index.
743d65f6f70SBen Gras 	 */
744d65f6f70SBen Gras 	factor = 1;
745d65f6f70SBen Gras 	for (i = SINGLE; i < level; i++)
74684d9c625SLionel Sambuc 		factor *= LFS_NINDIR(fs);
747d65f6f70SBen Gras 	last = lastbn;
748d65f6f70SBen Gras 	if (lastbn > 0)
749d65f6f70SBen Gras 		last /= factor;
750*0a6a1f1dSLionel Sambuc 	nblocks = lfs_btofsb(fs, lfs_sb_getbsize(fs));
751d65f6f70SBen Gras 	/*
752d65f6f70SBen Gras 	 * Get buffer of block pointers, zero those entries corresponding
753d65f6f70SBen Gras 	 * to blocks to be free'd, and update on disk copy first.  Since
754d65f6f70SBen Gras 	 * double(triple) indirect before single(double) indirect, calls
755d65f6f70SBen Gras 	 * to bmap on these blocks will fail.  However, we already have
756d65f6f70SBen Gras 	 * the on disk address, so we have to set the b_blkno field
757d65f6f70SBen Gras 	 * explicitly instead of letting bread do everything for us.
758d65f6f70SBen Gras 	 */
759d65f6f70SBen Gras 	vp = ITOV(ip);
760*0a6a1f1dSLionel Sambuc 	bp = getblk(vp, lbn, lfs_sb_getbsize(fs), 0, 0);
761d65f6f70SBen Gras 	if (bp->b_oflags & (BO_DONE | BO_DELWRI)) {
762d65f6f70SBen Gras 		/* Braces must be here in case trace evaluates to nothing. */
763*0a6a1f1dSLionel Sambuc 		trace(TR_BREADHIT, pack(vp, lfs_sb_getbsize(fs)), lbn);
764d65f6f70SBen Gras 	} else {
765*0a6a1f1dSLionel Sambuc 		trace(TR_BREADMISS, pack(vp, lfs_sb_getbsize(fs)), lbn);
766d65f6f70SBen Gras 		curlwp->l_ru.ru_inblock++; /* pay for read */
767d65f6f70SBen Gras 		bp->b_flags |= B_READ;
768d65f6f70SBen Gras 		if (bp->b_bcount > bp->b_bufsize)
769d65f6f70SBen Gras 			panic("lfs_indirtrunc: bad buffer size");
77084d9c625SLionel Sambuc 		bp->b_blkno = LFS_FSBTODB(fs, dbn);
771d65f6f70SBen Gras 		VOP_STRATEGY(vp, bp);
772d65f6f70SBen Gras 		error = biowait(bp);
773d65f6f70SBen Gras 	}
774d65f6f70SBen Gras 	if (error) {
775d65f6f70SBen Gras 		brelse(bp, 0);
776d65f6f70SBen Gras 		*countp = *rcountp = 0;
777d65f6f70SBen Gras 		return (error);
778d65f6f70SBen Gras 	}
779d65f6f70SBen Gras 
780d65f6f70SBen Gras 	if (lastbn >= 0) {
781*0a6a1f1dSLionel Sambuc 		/*
782*0a6a1f1dSLionel Sambuc 		 * We still need this block, so copy the data for
783*0a6a1f1dSLionel Sambuc 		 * subsequent processing; then in the original block,
784*0a6a1f1dSLionel Sambuc 		 * zero out the dying block pointers and send it off.
785*0a6a1f1dSLionel Sambuc 		 */
786*0a6a1f1dSLionel Sambuc 		bap = lfs_malloc(fs, lfs_sb_getbsize(fs), LFS_NB_IBLOCK);
787*0a6a1f1dSLionel Sambuc 		memcpy(bap, bp->b_data, lfs_sb_getbsize(fs));
788*0a6a1f1dSLionel Sambuc 		bap_needs_free = true;
789*0a6a1f1dSLionel Sambuc 
790*0a6a1f1dSLionel Sambuc 		for (i = last + 1; i < LFS_NINDIR(fs); i++) {
791*0a6a1f1dSLionel Sambuc 			lfs_iblock_set(fs, bp->b_data, i, 0);
792*0a6a1f1dSLionel Sambuc 		}
793d65f6f70SBen Gras 		error = VOP_BWRITE(bp->b_vp, bp);
794d65f6f70SBen Gras 		if (error)
795d65f6f70SBen Gras 			allerror = error;
796*0a6a1f1dSLionel Sambuc 	} else {
797*0a6a1f1dSLionel Sambuc 		bap = bp->b_data;
798*0a6a1f1dSLionel Sambuc 		bap_needs_free = false;
799d65f6f70SBen Gras 	}
800d65f6f70SBen Gras 
801d65f6f70SBen Gras 	/*
802d65f6f70SBen Gras 	 * Recursively free totally unused blocks.
803d65f6f70SBen Gras 	 */
80484d9c625SLionel Sambuc 	for (i = LFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
805d65f6f70SBen Gras 	    i--, nlbn += factor) {
806*0a6a1f1dSLionel Sambuc 		nb = lfs_iblock_get(fs, bap, i);
807d65f6f70SBen Gras 		if (nb == 0)
808d65f6f70SBen Gras 			continue;
809d65f6f70SBen Gras 		if (level > SINGLE) {
810d65f6f70SBen Gras 			error = lfs_indirtrunc(ip, nlbn, nb,
811d65f6f70SBen Gras 					       (daddr_t)-1, level - 1,
812d65f6f70SBen Gras 					       &blkcount, &rblkcount,
813d65f6f70SBen Gras 					       lastsegp, bcp);
814d65f6f70SBen Gras 			if (error)
815d65f6f70SBen Gras 				allerror = error;
816d65f6f70SBen Gras 			blocksreleased += blkcount;
817d65f6f70SBen Gras 			real_released += rblkcount;
818d65f6f70SBen Gras 		}
819*0a6a1f1dSLionel Sambuc 		lfs_blkfree(fs, ip, nb, lfs_sb_getbsize(fs), lastsegp, bcp);
820*0a6a1f1dSLionel Sambuc 		if (lfs_iblock_get(fs, bap, i) > 0)
821d65f6f70SBen Gras 			real_released += nblocks;
822d65f6f70SBen Gras 		blocksreleased += nblocks;
823d65f6f70SBen Gras 	}
824d65f6f70SBen Gras 
825d65f6f70SBen Gras 	/*
826d65f6f70SBen Gras 	 * Recursively free last partial block.
827d65f6f70SBen Gras 	 */
828d65f6f70SBen Gras 	if (level > SINGLE && lastbn >= 0) {
829d65f6f70SBen Gras 		last = lastbn % factor;
830*0a6a1f1dSLionel Sambuc 		nb = lfs_iblock_get(fs, bap, i);
831d65f6f70SBen Gras 		if (nb != 0) {
832d65f6f70SBen Gras 			error = lfs_indirtrunc(ip, nlbn, nb,
833d65f6f70SBen Gras 					       last, level - 1, &blkcount,
834d65f6f70SBen Gras 					       &rblkcount, lastsegp, bcp);
835d65f6f70SBen Gras 			if (error)
836d65f6f70SBen Gras 				allerror = error;
837d65f6f70SBen Gras 			real_released += rblkcount;
838d65f6f70SBen Gras 			blocksreleased += blkcount;
839d65f6f70SBen Gras 		}
840d65f6f70SBen Gras 	}
841d65f6f70SBen Gras 
842*0a6a1f1dSLionel Sambuc 	if (bap_needs_free) {
843*0a6a1f1dSLionel Sambuc 		lfs_free(fs, bap, LFS_NB_IBLOCK);
844d65f6f70SBen Gras 	} else {
845d65f6f70SBen Gras 		mutex_enter(&bufcache_lock);
846d65f6f70SBen Gras 		if (bp->b_oflags & BO_DELWRI) {
847d65f6f70SBen Gras 			LFS_UNLOCK_BUF(bp);
848*0a6a1f1dSLionel Sambuc 			lfs_sb_addavail(fs, lfs_btofsb(fs, bp->b_bcount));
849*0a6a1f1dSLionel Sambuc 			wakeup(&fs->lfs_availsleep);
850d65f6f70SBen Gras 		}
851d65f6f70SBen Gras 		brelsel(bp, BC_INVAL);
852d65f6f70SBen Gras 		mutex_exit(&bufcache_lock);
853d65f6f70SBen Gras 	}
854d65f6f70SBen Gras 
855d65f6f70SBen Gras 	*countp = blocksreleased;
856d65f6f70SBen Gras 	*rcountp = real_released;
857d65f6f70SBen Gras 	return (allerror);
858d65f6f70SBen Gras }
859d65f6f70SBen Gras 
860d65f6f70SBen Gras /*
861d65f6f70SBen Gras  * Destroy any in core blocks past the truncation length.
862d65f6f70SBen Gras  * Inlined from vtruncbuf, so that lfs_avail could be updated.
863d65f6f70SBen Gras  * We take the seglock to prevent cleaning from occurring while we are
864d65f6f70SBen Gras  * invalidating blocks.
865d65f6f70SBen Gras  */
866d65f6f70SBen Gras static int
lfs_vtruncbuf(struct vnode * vp,daddr_t lbn,bool catch,int slptimeo)867d65f6f70SBen Gras lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, bool catch, int slptimeo)
868d65f6f70SBen Gras {
869d65f6f70SBen Gras 	struct buf *bp, *nbp;
870d65f6f70SBen Gras 	int error;
871d65f6f70SBen Gras 	struct lfs *fs;
872d65f6f70SBen Gras 	voff_t off;
873d65f6f70SBen Gras 
874d65f6f70SBen Gras 	off = round_page((voff_t)lbn << vp->v_mount->mnt_fs_bshift);
875d65f6f70SBen Gras 	mutex_enter(vp->v_interlock);
876d65f6f70SBen Gras 	error = VOP_PUTPAGES(vp, off, 0, PGO_FREE | PGO_SYNCIO);
877d65f6f70SBen Gras 	if (error)
878d65f6f70SBen Gras 		return error;
879d65f6f70SBen Gras 
880d65f6f70SBen Gras 	fs = VTOI(vp)->i_lfs;
881d65f6f70SBen Gras 
882d65f6f70SBen Gras 	ASSERT_SEGLOCK(fs);
883d65f6f70SBen Gras 
884d65f6f70SBen Gras 	mutex_enter(&bufcache_lock);
885d65f6f70SBen Gras restart:
886d65f6f70SBen Gras 	for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
887d65f6f70SBen Gras 		nbp = LIST_NEXT(bp, b_vnbufs);
888d65f6f70SBen Gras 		if (bp->b_lblkno < lbn)
889d65f6f70SBen Gras 			continue;
890d65f6f70SBen Gras 		error = bbusy(bp, catch, slptimeo, NULL);
891d65f6f70SBen Gras 		if (error == EPASSTHROUGH)
892d65f6f70SBen Gras 			goto restart;
893d65f6f70SBen Gras 		if (error != 0) {
894d65f6f70SBen Gras 			mutex_exit(&bufcache_lock);
895d65f6f70SBen Gras 			return (error);
896d65f6f70SBen Gras 		}
897d65f6f70SBen Gras 		mutex_enter(bp->b_objlock);
898d65f6f70SBen Gras 		if (bp->b_oflags & BO_DELWRI) {
899d65f6f70SBen Gras 			bp->b_oflags &= ~BO_DELWRI;
900*0a6a1f1dSLionel Sambuc 			lfs_sb_addavail(fs, lfs_btofsb(fs, bp->b_bcount));
901*0a6a1f1dSLionel Sambuc 			wakeup(&fs->lfs_availsleep);
902d65f6f70SBen Gras 		}
903d65f6f70SBen Gras 		mutex_exit(bp->b_objlock);
904d65f6f70SBen Gras 		LFS_UNLOCK_BUF(bp);
905d65f6f70SBen Gras 		brelsel(bp, BC_INVAL | BC_VFLUSH);
906d65f6f70SBen Gras 	}
907d65f6f70SBen Gras 
908d65f6f70SBen Gras 	for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
909d65f6f70SBen Gras 		nbp = LIST_NEXT(bp, b_vnbufs);
910d65f6f70SBen Gras 		if (bp->b_lblkno < lbn)
911d65f6f70SBen Gras 			continue;
912d65f6f70SBen Gras 		error = bbusy(bp, catch, slptimeo, NULL);
913d65f6f70SBen Gras 		if (error == EPASSTHROUGH)
914d65f6f70SBen Gras 			goto restart;
915d65f6f70SBen Gras 		if (error != 0) {
916d65f6f70SBen Gras 			mutex_exit(&bufcache_lock);
917d65f6f70SBen Gras 			return (error);
918d65f6f70SBen Gras 		}
919d65f6f70SBen Gras 		mutex_enter(bp->b_objlock);
920d65f6f70SBen Gras 		if (bp->b_oflags & BO_DELWRI) {
921d65f6f70SBen Gras 			bp->b_oflags &= ~BO_DELWRI;
922*0a6a1f1dSLionel Sambuc 			lfs_sb_addavail(fs, lfs_btofsb(fs, bp->b_bcount));
923*0a6a1f1dSLionel Sambuc 			wakeup(&fs->lfs_availsleep);
924d65f6f70SBen Gras 		}
925d65f6f70SBen Gras 		mutex_exit(bp->b_objlock);
926d65f6f70SBen Gras 		LFS_UNLOCK_BUF(bp);
927d65f6f70SBen Gras 		brelsel(bp, BC_INVAL | BC_VFLUSH);
928d65f6f70SBen Gras 	}
929d65f6f70SBen Gras 	mutex_exit(&bufcache_lock);
930d65f6f70SBen Gras 
931d65f6f70SBen Gras 	return (0);
932d65f6f70SBen Gras }
933d65f6f70SBen Gras 
934