1139778Simp/*-
212115Sdyson *  modified for Lites 1.1
312115Sdyson *
412115Sdyson *  Aug 1995, Godmar Back (gback@cs.utah.edu)
512115Sdyson *  University of Utah, Department of Computer Science
612115Sdyson */
7139778Simp/*-
812115Sdyson * Copyright (c) 1982, 1986, 1989, 1993
912115Sdyson *	The Regents of the University of California.  All rights reserved.
1012115Sdyson *
1112115Sdyson * Redistribution and use in source and binary forms, with or without
1212115Sdyson * modification, are permitted provided that the following conditions
1312115Sdyson * are met:
1412115Sdyson * 1. Redistributions of source code must retain the above copyright
1512115Sdyson *    notice, this list of conditions and the following disclaimer.
1612115Sdyson * 2. Redistributions in binary form must reproduce the above copyright
1712115Sdyson *    notice, this list of conditions and the following disclaimer in the
1812115Sdyson *    documentation and/or other materials provided with the distribution.
1912115Sdyson * 4. Neither the name of the University nor the names of its contributors
2012115Sdyson *    may be used to endorse or promote products derived from this software
2112115Sdyson *    without specific prior written permission.
2212115Sdyson *
2312115Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2412115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2512115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2612115Sdyson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2712115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2812115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2912115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3012115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3112115Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3212115Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3312115Sdyson * SUCH DAMAGE.
3412115Sdyson *
3593015Sbde *	@(#)ffs_subr.c	8.2 (Berkeley) 9/21/93
3660041Sphk * $FreeBSD: stable/11/sys/fs/ext2fs/ext2_subr.c 311231 2017-01-04 02:42:17Z pfg $
3712115Sdyson */
3812115Sdyson
3912115Sdyson#include <sys/param.h>
4012115Sdyson
4176166Smarkm#include <sys/proc.h>
4276166Smarkm#include <sys/systm.h>
4376166Smarkm#include <sys/bio.h>
4476166Smarkm#include <sys/buf.h>
4531561Sbde#include <sys/lock.h>
4669517Sbde#include <sys/ucred.h>
4712115Sdyson#include <sys/vnode.h>
4876166Smarkm
49202283Slulf#include <fs/ext2fs/inode.h>
50202283Slulf#include <fs/ext2fs/ext2_extern.h>
51202283Slulf#include <fs/ext2fs/ext2fs.h>
52202283Slulf#include <fs/ext2fs/fs.h>
53254260Spfg#include <fs/ext2fs/ext2_extents.h>
54254260Spfg#include <fs/ext2fs/ext2_mount.h>
55254260Spfg#include <fs/ext2fs/ext2_dinode.h>
5676166Smarkm
5712115Sdyson/*
5812115Sdyson * Return buffer with the contents of block "offset" from the beginning of
5912115Sdyson * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
6012115Sdyson * remaining space in the directory.
6112115Sdyson */
6212115Sdysonint
63246634Spfgext2_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
6412115Sdyson{
6512115Sdyson	struct inode *ip;
66202283Slulf	struct m_ext2fs *fs;
6712115Sdyson	struct buf *bp;
68252103Spfg	e2fs_lbn_t lbn;
6912115Sdyson	int bsize, error;
70254260Spfg	daddr_t newblk;
71254260Spfg	struct ext4_extent *ep;
72254260Spfg	struct ext4_extent_path path;
7312115Sdyson
7430474Sphk	ip = VTOI(vp);
7512115Sdyson	fs = ip->i_e2fs;
7630474Sphk	lbn = lblkno(fs, offset);
7712115Sdyson	bsize = blksize(fs, ip, lbn);
78254260Spfg	*bpp = NULL;
7912115Sdyson
80254260Spfg	/*
81261235Spfg	 * IN_E4EXTENTS requires special treatment as we can otherwise fall
82260988Spfg	 * back to the normal path.
83254260Spfg	 */
84261235Spfg	if (!(ip->i_flag & IN_E4EXTENTS))
85254260Spfg		goto normal;
86254260Spfg
87254260Spfg	memset(&path, 0, sizeof(path));
88254260Spfg	if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL)
89254260Spfg		goto normal;
90254260Spfg	ep = path.ep_ext;
91254260Spfg	if (ep == NULL)
92254260Spfg		goto normal;
93254260Spfg
94254260Spfg	newblk = lbn - ep->e_blk +
95254260Spfg	    (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32);
96254260Spfg
97254260Spfg	if (path.ep_bp != NULL) {
98254260Spfg		brelse(path.ep_bp);
99254260Spfg		path.ep_bp = NULL;
100254260Spfg	}
101254260Spfg	error = bread(ip->i_devvp, fsbtodb(fs, newblk), bsize, NOCRED, &bp);
102254260Spfg	if (error != 0) {
10312115Sdyson		brelse(bp);
10412115Sdyson		return (error);
10512115Sdyson	}
10630474Sphk	if (res)
10730474Sphk		*res = (char *)bp->b_data + blkoff(fs, offset);
108254260Spfg	/*
109261235Spfg	 * If IN_E4EXTENTS is enabled we would get a wrong offset so
110254260Spfg	 * reset b_offset here.
111254260Spfg	 */
112254260Spfg	bp->b_offset = lbn * bsize;
11330474Sphk	*bpp = bp;
11412115Sdyson	return (0);
115254260Spfg
116254260Spfgnormal:
117254260Spfg	if (*bpp == NULL) {
118254260Spfg		if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
119254260Spfg			brelse(bp);
120254260Spfg			return (error);
121254260Spfg		}
122254260Spfg		if (res)
123254260Spfg			*res = (char *)bp->b_data + blkoff(fs, offset);
124254260Spfg		*bpp = bp;
125254260Spfg	}
126254260Spfg	return (0);
12712115Sdyson}
12812115Sdyson
129228539Spfg/*
130228539Spfg * Update the cluster map because of an allocation of free like ffs.
131228539Spfg *
132228539Spfg * Cnt == 1 means free; cnt == -1 means allocating.
133228539Spfg */
134228539Spfgvoid
135228539Spfgext2_clusteracct(struct m_ext2fs *fs, char *bbp, int cg, daddr_t bno, int cnt)
136228539Spfg{
137228539Spfg	int32_t *sump = fs->e2fs_clustersum[cg].cs_sum;
138228539Spfg	int32_t *lp;
139228539Spfg	int back, bit, end, forw, i, loc, start;
140228539Spfg
141228539Spfg	/* Initialize the cluster summary array. */
142228539Spfg	if (fs->e2fs_clustersum[cg].cs_init == 0) {
143228539Spfg		int run = 0;
144311231Spfg
145228539Spfg		bit = 1;
146228539Spfg		loc = 0;
147228539Spfg
148228539Spfg		for (i = 0; i < fs->e2fs->e2fs_fpg; i++) {
149228539Spfg			if ((bbp[loc] & bit) == 0)
150228539Spfg				run++;
151228539Spfg			else if (run != 0) {
152228539Spfg				if (run > fs->e2fs_contigsumsize)
153228539Spfg					run = fs->e2fs_contigsumsize;
154228539Spfg				sump[run]++;
155228539Spfg				run = 0;
156228539Spfg			}
157228539Spfg			if ((i & (NBBY - 1)) != (NBBY - 1))
158228539Spfg				bit <<= 1;
159228539Spfg			else {
160228539Spfg				loc++;
161228539Spfg				bit = 1;
162228539Spfg			}
163228539Spfg		}
164228539Spfg		if (run != 0) {
165228539Spfg			if (run > fs->e2fs_contigsumsize)
166228539Spfg				run = fs->e2fs_contigsumsize;
167228539Spfg			sump[run]++;
168228539Spfg		}
169228539Spfg		fs->e2fs_clustersum[cg].cs_init = 1;
170228539Spfg	}
171228539Spfg
172228539Spfg	if (fs->e2fs_contigsumsize <= 0)
173228539Spfg		return;
174228539Spfg
175228539Spfg	/* Find the size of the cluster going forward. */
176228539Spfg	start = bno + 1;
177228539Spfg	end = start + fs->e2fs_contigsumsize;
178228539Spfg	if (end > fs->e2fs->e2fs_fpg)
179228539Spfg		end = fs->e2fs->e2fs_fpg;
180228539Spfg	loc = start / NBBY;
181228539Spfg	bit = 1 << (start % NBBY);
182228539Spfg	for (i = start; i < end; i++) {
183228539Spfg		if ((bbp[loc] & bit) != 0)
184228539Spfg			break;
185228539Spfg		if ((i & (NBBY - 1)) != (NBBY - 1))
186228539Spfg			bit <<= 1;
187228539Spfg		else {
188228539Spfg			loc++;
189228539Spfg			bit = 1;
190228539Spfg		}
191228539Spfg	}
192228539Spfg	forw = i - start;
193228539Spfg
194228539Spfg	/* Find the size of the cluster going backward. */
195228539Spfg	start = bno - 1;
196228539Spfg	end = start - fs->e2fs_contigsumsize;
197228539Spfg	if (end < 0)
198228539Spfg		end = -1;
199228539Spfg	loc = start / NBBY;
200228539Spfg	bit = 1 << (start % NBBY);
201228539Spfg	for (i = start; i > end; i--) {
202228539Spfg		if ((bbp[loc] & bit) != 0)
203228539Spfg			break;
204228539Spfg		if ((i & (NBBY - 1)) != 0)
205228539Spfg			bit >>= 1;
206228539Spfg		else {
207228539Spfg			loc--;
208228539Spfg			bit = 1 << (NBBY - 1);
209228539Spfg		}
210228539Spfg	}
211228539Spfg	back = start - i;
212228539Spfg
213228539Spfg	/*
214228539Spfg	 * Account for old cluster and the possibly new forward and
215228539Spfg	 * back clusters.
216228539Spfg	 */
217228539Spfg	i = back + forw + 1;
218228539Spfg	if (i > fs->e2fs_contigsumsize)
219228539Spfg		i = fs->e2fs_contigsumsize;
220228539Spfg	sump[i] += cnt;
221228539Spfg	if (back > 0)
222228539Spfg		sump[back] -= cnt;
223228539Spfg	if (forw > 0)
224228539Spfg		sump[forw] -= cnt;
225228539Spfg
226228539Spfg	/* Update cluster summary information. */
227228539Spfg	lp = &sump[fs->e2fs_contigsumsize];
228228539Spfg	for (i = fs->e2fs_contigsumsize; i > 0; i--)
229228539Spfg		if (*lp-- > 0)
230228539Spfg			break;
231228539Spfg	fs->e2fs_maxcluster[cg] = i;
232228539Spfg}
233