xref: /freebsd/sys/ufs/ffs/ffs_subr.c (revision 076ad2f8)
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *	@(#)ffs_subr.c	8.5 (Berkeley) 3/21/95
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 
37 #ifndef _KERNEL
38 #include <ufs/ufs/dinode.h>
39 #include <ufs/ffs/fs.h>
40 #else
41 #include <sys/systm.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/bio.h>
47 #include <sys/buf.h>
48 #include <sys/ucred.h>
49 
50 #include <ufs/ufs/quota.h>
51 #include <ufs/ufs/inode.h>
52 #include <ufs/ufs/extattr.h>
53 #include <ufs/ufs/ufsmount.h>
54 #include <ufs/ufs/ufs_extern.h>
55 #include <ufs/ffs/ffs_extern.h>
56 #include <ufs/ffs/fs.h>
57 
58 /*
59  * Return buffer with the contents of block "offset" from the beginning of
60  * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
61  * remaining space in the directory.
62  */
63 int
64 ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
65 {
66 	struct inode *ip;
67 	struct fs *fs;
68 	struct buf *bp;
69 	ufs_lbn_t lbn;
70 	int bsize, error;
71 
72 	ip = VTOI(vp);
73 	fs = ITOFS(ip);
74 	lbn = lblkno(fs, offset);
75 	bsize = blksize(fs, ip, lbn);
76 
77 	*bpp = NULL;
78 	error = bread(vp, lbn, bsize, NOCRED, &bp);
79 	if (error) {
80 		brelse(bp);
81 		return (error);
82 	}
83 	if (res)
84 		*res = (char *)bp->b_data + blkoff(fs, offset);
85 	*bpp = bp;
86 	return (0);
87 }
88 
89 /*
90  * Load up the contents of an inode and copy the appropriate pieces
91  * to the incore copy.
92  */
93 void
94 ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
95 {
96 
97 	if (I_IS_UFS1(ip)) {
98 		*ip->i_din1 =
99 		    *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
100 		ip->i_mode = ip->i_din1->di_mode;
101 		ip->i_nlink = ip->i_din1->di_nlink;
102 		ip->i_size = ip->i_din1->di_size;
103 		ip->i_flags = ip->i_din1->di_flags;
104 		ip->i_gen = ip->i_din1->di_gen;
105 		ip->i_uid = ip->i_din1->di_uid;
106 		ip->i_gid = ip->i_din1->di_gid;
107 	} else {
108 		*ip->i_din2 =
109 		    *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
110 		ip->i_mode = ip->i_din2->di_mode;
111 		ip->i_nlink = ip->i_din2->di_nlink;
112 		ip->i_size = ip->i_din2->di_size;
113 		ip->i_flags = ip->i_din2->di_flags;
114 		ip->i_gen = ip->i_din2->di_gen;
115 		ip->i_uid = ip->i_din2->di_uid;
116 		ip->i_gid = ip->i_din2->di_gid;
117 	}
118 }
119 #endif /* KERNEL */
120 
121 /*
122  * Update the frsum fields to reflect addition or deletion
123  * of some frags.
124  */
125 void
126 ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt)
127 {
128 	int inblk;
129 	int field, subfield;
130 	int siz, pos;
131 
132 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
133 	fragmap <<= 1;
134 	for (siz = 1; siz < fs->fs_frag; siz++) {
135 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
136 			continue;
137 		field = around[siz];
138 		subfield = inside[siz];
139 		for (pos = siz; pos <= fs->fs_frag; pos++) {
140 			if ((fragmap & field) == subfield) {
141 				fraglist[siz] += cnt;
142 				pos += siz;
143 				field <<= siz;
144 				subfield <<= siz;
145 			}
146 			field <<= 1;
147 			subfield <<= 1;
148 		}
149 	}
150 }
151 
152 /*
153  * block operations
154  *
155  * check if a block is available
156  */
157 int
158 ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
159 {
160 	unsigned char mask;
161 
162 	switch ((int)fs->fs_frag) {
163 	case 8:
164 		return (cp[h] == 0xff);
165 	case 4:
166 		mask = 0x0f << ((h & 0x1) << 2);
167 		return ((cp[h >> 1] & mask) == mask);
168 	case 2:
169 		mask = 0x03 << ((h & 0x3) << 1);
170 		return ((cp[h >> 2] & mask) == mask);
171 	case 1:
172 		mask = 0x01 << (h & 0x7);
173 		return ((cp[h >> 3] & mask) == mask);
174 	default:
175 #ifdef _KERNEL
176 		panic("ffs_isblock");
177 #endif
178 		break;
179 	}
180 	return (0);
181 }
182 
183 /*
184  * check if a block is free
185  */
186 int
187 ffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h)
188 {
189 
190 	switch ((int)fs->fs_frag) {
191 	case 8:
192 		return (cp[h] == 0);
193 	case 4:
194 		return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
195 	case 2:
196 		return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
197 	case 1:
198 		return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
199 	default:
200 #ifdef _KERNEL
201 		panic("ffs_isfreeblock");
202 #endif
203 		break;
204 	}
205 	return (0);
206 }
207 
208 /*
209  * take a block out of the map
210  */
211 void
212 ffs_clrblock(struct fs *fs, u_char *cp, ufs1_daddr_t h)
213 {
214 
215 	switch ((int)fs->fs_frag) {
216 	case 8:
217 		cp[h] = 0;
218 		return;
219 	case 4:
220 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
221 		return;
222 	case 2:
223 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
224 		return;
225 	case 1:
226 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
227 		return;
228 	default:
229 #ifdef _KERNEL
230 		panic("ffs_clrblock");
231 #endif
232 		break;
233 	}
234 }
235 
236 /*
237  * put a block into the map
238  */
239 void
240 ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
241 {
242 
243 	switch ((int)fs->fs_frag) {
244 
245 	case 8:
246 		cp[h] = 0xff;
247 		return;
248 	case 4:
249 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
250 		return;
251 	case 2:
252 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
253 		return;
254 	case 1:
255 		cp[h >> 3] |= (0x01 << (h & 0x7));
256 		return;
257 	default:
258 #ifdef _KERNEL
259 		panic("ffs_setblock");
260 #endif
261 		break;
262 	}
263 }
264 
265 /*
266  * Update the cluster map because of an allocation or free.
267  *
268  * Cnt == 1 means free; cnt == -1 means allocating.
269  */
270 void
271 ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt)
272 {
273 	int32_t *sump;
274 	int32_t *lp;
275 	u_char *freemapp, *mapp;
276 	int i, start, end, forw, back, map, bit;
277 
278 	if (fs->fs_contigsumsize <= 0)
279 		return;
280 	freemapp = cg_clustersfree(cgp);
281 	sump = cg_clustersum(cgp);
282 	/*
283 	 * Allocate or clear the actual block.
284 	 */
285 	if (cnt > 0)
286 		setbit(freemapp, blkno);
287 	else
288 		clrbit(freemapp, blkno);
289 	/*
290 	 * Find the size of the cluster going forward.
291 	 */
292 	start = blkno + 1;
293 	end = start + fs->fs_contigsumsize;
294 	if (end >= cgp->cg_nclusterblks)
295 		end = cgp->cg_nclusterblks;
296 	mapp = &freemapp[start / NBBY];
297 	map = *mapp++;
298 	bit = 1 << (start % NBBY);
299 	for (i = start; i < end; i++) {
300 		if ((map & bit) == 0)
301 			break;
302 		if ((i & (NBBY - 1)) != (NBBY - 1)) {
303 			bit <<= 1;
304 		} else {
305 			map = *mapp++;
306 			bit = 1;
307 		}
308 	}
309 	forw = i - start;
310 	/*
311 	 * Find the size of the cluster going backward.
312 	 */
313 	start = blkno - 1;
314 	end = start - fs->fs_contigsumsize;
315 	if (end < 0)
316 		end = -1;
317 	mapp = &freemapp[start / NBBY];
318 	map = *mapp--;
319 	bit = 1 << (start % NBBY);
320 	for (i = start; i > end; i--) {
321 		if ((map & bit) == 0)
322 			break;
323 		if ((i & (NBBY - 1)) != 0) {
324 			bit >>= 1;
325 		} else {
326 			map = *mapp--;
327 			bit = 1 << (NBBY - 1);
328 		}
329 	}
330 	back = start - i;
331 	/*
332 	 * Account for old cluster and the possibly new forward and
333 	 * back clusters.
334 	 */
335 	i = back + forw + 1;
336 	if (i > fs->fs_contigsumsize)
337 		i = fs->fs_contigsumsize;
338 	sump[i] += cnt;
339 	if (back > 0)
340 		sump[back] -= cnt;
341 	if (forw > 0)
342 		sump[forw] -= cnt;
343 	/*
344 	 * Update cluster summary information.
345 	 */
346 	lp = &sump[fs->fs_contigsumsize];
347 	for (i = fs->fs_contigsumsize; i > 0; i--)
348 		if (*lp-- > 0)
349 			break;
350 	fs->fs_maxcluster[cgp->cg_cgx] = i;
351 }
352