ext2_subr.c revision 331722
1/*-
2 *  modified for Lites 1.1
3 *
4 *  Aug 1995, Godmar Back (gback@cs.utah.edu)
5 *  University of Utah, Department of Computer Science
6 */
7/*-
8 * Copyright (c) 1982, 1986, 1989, 1993
9 *	The Regents of the University of California.  All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	@(#)ffs_subr.c	8.2 (Berkeley) 9/21/93
36 * $FreeBSD: stable/11/sys/fs/ext2fs/ext2_subr.c 331722 2018-03-29 02:50:57Z eadler $
37 */
38
39#include <sys/param.h>
40
41#include <sys/proc.h>
42#include <sys/systm.h>
43#include <sys/bio.h>
44#include <sys/buf.h>
45#include <sys/lock.h>
46#include <sys/ucred.h>
47#include <sys/vnode.h>
48
49#include <fs/ext2fs/inode.h>
50#include <fs/ext2fs/ext2_extern.h>
51#include <fs/ext2fs/ext2fs.h>
52#include <fs/ext2fs/fs.h>
53#include <fs/ext2fs/ext2_extents.h>
54#include <fs/ext2fs/ext2_mount.h>
55#include <fs/ext2fs/ext2_dinode.h>
56
57/*
58 * Return buffer with the contents of block "offset" from the beginning of
59 * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
60 * remaining space in the directory.
61 */
62int
63ext2_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
64{
65	struct inode *ip;
66	struct m_ext2fs *fs;
67	struct buf *bp;
68	e2fs_lbn_t lbn;
69	int bsize, error;
70	daddr_t newblk;
71	struct ext4_extent *ep;
72	struct ext4_extent_path path;
73
74	ip = VTOI(vp);
75	fs = ip->i_e2fs;
76	lbn = lblkno(fs, offset);
77	bsize = blksize(fs, ip, lbn);
78	*bpp = NULL;
79
80	/*
81	 * IN_E4EXTENTS requires special treatment as we can otherwise fall
82	 * back to the normal path.
83	 */
84	if (!(ip->i_flag & IN_E4EXTENTS))
85		goto normal;
86
87	memset(&path, 0, sizeof(path));
88	if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL)
89		goto normal;
90	ep = path.ep_ext;
91	if (ep == NULL)
92		goto normal;
93
94	newblk = lbn - ep->e_blk +
95	    (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32);
96
97	if (path.ep_bp != NULL) {
98		brelse(path.ep_bp);
99		path.ep_bp = NULL;
100	}
101	error = bread(ip->i_devvp, fsbtodb(fs, newblk), bsize, NOCRED, &bp);
102	if (error != 0) {
103		brelse(bp);
104		return (error);
105	}
106	if (res)
107		*res = (char *)bp->b_data + blkoff(fs, offset);
108	/*
109	 * If IN_E4EXTENTS is enabled we would get a wrong offset so
110	 * reset b_offset here.
111	 */
112	bp->b_offset = lbn * bsize;
113	*bpp = bp;
114	return (0);
115
116normal:
117	if (*bpp == NULL) {
118		if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
119			brelse(bp);
120			return (error);
121		}
122		if (res)
123			*res = (char *)bp->b_data + blkoff(fs, offset);
124		*bpp = bp;
125	}
126	return (0);
127}
128
129/*
130 * Update the cluster map because of an allocation of free like ffs.
131 *
132 * Cnt == 1 means free; cnt == -1 means allocating.
133 */
134void
135ext2_clusteracct(struct m_ext2fs *fs, char *bbp, int cg, daddr_t bno, int cnt)
136{
137	int32_t *sump = fs->e2fs_clustersum[cg].cs_sum;
138	int32_t *lp;
139	int back, bit, end, forw, i, loc, start;
140
141	/* Initialize the cluster summary array. */
142	if (fs->e2fs_clustersum[cg].cs_init == 0) {
143		int run = 0;
144
145		bit = 1;
146		loc = 0;
147
148		for (i = 0; i < fs->e2fs->e2fs_fpg; i++) {
149			if ((bbp[loc] & bit) == 0)
150				run++;
151			else if (run != 0) {
152				if (run > fs->e2fs_contigsumsize)
153					run = fs->e2fs_contigsumsize;
154				sump[run]++;
155				run = 0;
156			}
157			if ((i & (NBBY - 1)) != (NBBY - 1))
158				bit <<= 1;
159			else {
160				loc++;
161				bit = 1;
162			}
163		}
164		if (run != 0) {
165			if (run > fs->e2fs_contigsumsize)
166				run = fs->e2fs_contigsumsize;
167			sump[run]++;
168		}
169		fs->e2fs_clustersum[cg].cs_init = 1;
170	}
171
172	if (fs->e2fs_contigsumsize <= 0)
173		return;
174
175	/* Find the size of the cluster going forward. */
176	start = bno + 1;
177	end = start + fs->e2fs_contigsumsize;
178	if (end > fs->e2fs->e2fs_fpg)
179		end = fs->e2fs->e2fs_fpg;
180	loc = start / NBBY;
181	bit = 1 << (start % NBBY);
182	for (i = start; i < end; i++) {
183		if ((bbp[loc] & bit) != 0)
184			break;
185		if ((i & (NBBY - 1)) != (NBBY - 1))
186			bit <<= 1;
187		else {
188			loc++;
189			bit = 1;
190		}
191	}
192	forw = i - start;
193
194	/* Find the size of the cluster going backward. */
195	start = bno - 1;
196	end = start - fs->e2fs_contigsumsize;
197	if (end < 0)
198		end = -1;
199	loc = start / NBBY;
200	bit = 1 << (start % NBBY);
201	for (i = start; i > end; i--) {
202		if ((bbp[loc] & bit) != 0)
203			break;
204		if ((i & (NBBY - 1)) != 0)
205			bit >>= 1;
206		else {
207			loc--;
208			bit = 1 << (NBBY - 1);
209		}
210	}
211	back = start - i;
212
213	/*
214	 * Account for old cluster and the possibly new forward and
215	 * back clusters.
216	 */
217	i = back + forw + 1;
218	if (i > fs->e2fs_contigsumsize)
219		i = fs->e2fs_contigsumsize;
220	sump[i] += cnt;
221	if (back > 0)
222		sump[back] -= cnt;
223	if (forw > 0)
224		sump[forw] -= cnt;
225
226	/* Update cluster summary information. */
227	lp = &sump[fs->e2fs_contigsumsize];
228	for (i = fs->e2fs_contigsumsize; i > 0; i--)
229		if (*lp-- > 0)
230			break;
231	fs->e2fs_maxcluster[cg] = i;
232}
233