• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_types.h"
21 #include "xfs_bit.h"
22 #include "xfs_log.h"
23 #include "xfs_inum.h"
24 #include "xfs_trans.h"
25 #include "xfs_sb.h"
26 #include "xfs_ag.h"
27 #include "xfs_dir2.h"
28 #include "xfs_dmapi.h"
29 #include "xfs_mount.h"
30 #include "xfs_bmap_btree.h"
31 #include "xfs_alloc_btree.h"
32 #include "xfs_ialloc_btree.h"
33 #include "xfs_dir2_sf.h"
34 #include "xfs_attr_sf.h"
35 #include "xfs_dinode.h"
36 #include "xfs_inode.h"
37 #include "xfs_btree.h"
38 #include "xfs_btree_trace.h"
39 #include "xfs_ialloc.h"
40 #include "xfs_alloc.h"
41 #include "xfs_error.h"
42 
43 
44 STATIC struct xfs_btree_cur *
xfs_allocbt_dup_cursor(struct xfs_btree_cur * cur)45 xfs_allocbt_dup_cursor(
46 	struct xfs_btree_cur	*cur)
47 {
48 	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
49 			cur->bc_private.a.agbp, cur->bc_private.a.agno,
50 			cur->bc_btnum);
51 }
52 
53 STATIC void
xfs_allocbt_set_root(struct xfs_btree_cur * cur,union xfs_btree_ptr * ptr,int inc)54 xfs_allocbt_set_root(
55 	struct xfs_btree_cur	*cur,
56 	union xfs_btree_ptr	*ptr,
57 	int			inc)
58 {
59 	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
60 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
61 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno);
62 	int			btnum = cur->bc_btnum;
63 
64 	ASSERT(ptr->s != 0);
65 
66 	agf->agf_roots[btnum] = ptr->s;
67 	be32_add_cpu(&agf->agf_levels[btnum], inc);
68 	cur->bc_mp->m_perag[seqno].pagf_levels[btnum] += inc;
69 
70 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
71 }
72 
73 STATIC int
xfs_allocbt_alloc_block(struct xfs_btree_cur * cur,union xfs_btree_ptr * start,union xfs_btree_ptr * new,int length,int * stat)74 xfs_allocbt_alloc_block(
75 	struct xfs_btree_cur	*cur,
76 	union xfs_btree_ptr	*start,
77 	union xfs_btree_ptr	*new,
78 	int			length,
79 	int			*stat)
80 {
81 	int			error;
82 	xfs_agblock_t		bno;
83 
84 	XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
85 
86 	/* Allocate the new block from the freelist. If we can't, give up.  */
87 	error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
88 				       &bno, 1);
89 	if (error) {
90 		XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
91 		return error;
92 	}
93 
94 	if (bno == NULLAGBLOCK) {
95 		XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
96 		*stat = 0;
97 		return 0;
98 	}
99 
100 	xfs_trans_agbtree_delta(cur->bc_tp, 1);
101 	new->s = cpu_to_be32(bno);
102 
103 	XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
104 	*stat = 1;
105 	return 0;
106 }
107 
108 STATIC int
xfs_allocbt_free_block(struct xfs_btree_cur * cur,struct xfs_buf * bp)109 xfs_allocbt_free_block(
110 	struct xfs_btree_cur	*cur,
111 	struct xfs_buf		*bp)
112 {
113 	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
114 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
115 	xfs_agblock_t		bno;
116 	int			error;
117 
118 	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
119 	error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1);
120 	if (error)
121 		return error;
122 
123 	/*
124 	 * Since blocks move to the free list without the coordination used in
125 	 * xfs_bmap_finish, we can't allow block to be available for
126 	 * reallocation and non-transaction writing (user data) until we know
127 	 * that the transaction that moved it to the free list is permanently
128 	 * on disk. We track the blocks by declaring these blocks as "busy";
129 	 * the busy list is maintained on a per-ag basis and each transaction
130 	 * records which entries should be removed when the iclog commits to
131 	 * disk. If a busy block is allocated, the iclog is pushed up to the
132 	 * LSN that freed the block.
133 	 */
134 	xfs_alloc_mark_busy(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
135 	xfs_trans_agbtree_delta(cur->bc_tp, -1);
136 	return 0;
137 }
138 
139 /*
140  * Update the longest extent in the AGF
141  */
142 STATIC void
xfs_allocbt_update_lastrec(struct xfs_btree_cur * cur,struct xfs_btree_block * block,union xfs_btree_rec * rec,int ptr,int reason)143 xfs_allocbt_update_lastrec(
144 	struct xfs_btree_cur	*cur,
145 	struct xfs_btree_block	*block,
146 	union xfs_btree_rec	*rec,
147 	int			ptr,
148 	int			reason)
149 {
150 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
151 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno);
152 	__be32			len;
153 	int			numrecs;
154 
155 	ASSERT(cur->bc_btnum == XFS_BTNUM_CNT);
156 
157 	switch (reason) {
158 	case LASTREC_UPDATE:
159 		/*
160 		 * If this is the last leaf block and it's the last record,
161 		 * then update the size of the longest extent in the AG.
162 		 */
163 		if (ptr != xfs_btree_get_numrecs(block))
164 			return;
165 		len = rec->alloc.ar_blockcount;
166 		break;
167 	case LASTREC_INSREC:
168 		if (be32_to_cpu(rec->alloc.ar_blockcount) <=
169 		    be32_to_cpu(agf->agf_longest))
170 			return;
171 		len = rec->alloc.ar_blockcount;
172 		break;
173 	case LASTREC_DELREC:
174 		numrecs = xfs_btree_get_numrecs(block);
175 		if (ptr <= numrecs)
176 			return;
177 		ASSERT(ptr == numrecs + 1);
178 
179 		if (numrecs) {
180 			xfs_alloc_rec_t *rrp;
181 
182 			rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs);
183 			len = rrp->ar_blockcount;
184 		} else {
185 			len = 0;
186 		}
187 
188 		break;
189 	default:
190 		ASSERT(0);
191 		return;
192 	}
193 
194 	agf->agf_longest = len;
195 	cur->bc_mp->m_perag[seqno].pagf_longest = be32_to_cpu(len);
196 	xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST);
197 }
198 
199 STATIC int
xfs_allocbt_get_minrecs(struct xfs_btree_cur * cur,int level)200 xfs_allocbt_get_minrecs(
201 	struct xfs_btree_cur	*cur,
202 	int			level)
203 {
204 	return cur->bc_mp->m_alloc_mnr[level != 0];
205 }
206 
207 STATIC int
xfs_allocbt_get_maxrecs(struct xfs_btree_cur * cur,int level)208 xfs_allocbt_get_maxrecs(
209 	struct xfs_btree_cur	*cur,
210 	int			level)
211 {
212 	return cur->bc_mp->m_alloc_mxr[level != 0];
213 }
214 
215 STATIC void
xfs_allocbt_init_key_from_rec(union xfs_btree_key * key,union xfs_btree_rec * rec)216 xfs_allocbt_init_key_from_rec(
217 	union xfs_btree_key	*key,
218 	union xfs_btree_rec	*rec)
219 {
220 	ASSERT(rec->alloc.ar_startblock != 0);
221 
222 	key->alloc.ar_startblock = rec->alloc.ar_startblock;
223 	key->alloc.ar_blockcount = rec->alloc.ar_blockcount;
224 }
225 
226 STATIC void
xfs_allocbt_init_rec_from_key(union xfs_btree_key * key,union xfs_btree_rec * rec)227 xfs_allocbt_init_rec_from_key(
228 	union xfs_btree_key	*key,
229 	union xfs_btree_rec	*rec)
230 {
231 	ASSERT(key->alloc.ar_startblock != 0);
232 
233 	rec->alloc.ar_startblock = key->alloc.ar_startblock;
234 	rec->alloc.ar_blockcount = key->alloc.ar_blockcount;
235 }
236 
237 STATIC void
xfs_allocbt_init_rec_from_cur(struct xfs_btree_cur * cur,union xfs_btree_rec * rec)238 xfs_allocbt_init_rec_from_cur(
239 	struct xfs_btree_cur	*cur,
240 	union xfs_btree_rec	*rec)
241 {
242 	ASSERT(cur->bc_rec.a.ar_startblock != 0);
243 
244 	rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
245 	rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
246 }
247 
248 STATIC void
xfs_allocbt_init_ptr_from_cur(struct xfs_btree_cur * cur,union xfs_btree_ptr * ptr)249 xfs_allocbt_init_ptr_from_cur(
250 	struct xfs_btree_cur	*cur,
251 	union xfs_btree_ptr	*ptr)
252 {
253 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
254 
255 	ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno));
256 	ASSERT(agf->agf_roots[cur->bc_btnum] != 0);
257 
258 	ptr->s = agf->agf_roots[cur->bc_btnum];
259 }
260 
261 STATIC __int64_t
xfs_allocbt_key_diff(struct xfs_btree_cur * cur,union xfs_btree_key * key)262 xfs_allocbt_key_diff(
263 	struct xfs_btree_cur	*cur,
264 	union xfs_btree_key	*key)
265 {
266 	xfs_alloc_rec_incore_t	*rec = &cur->bc_rec.a;
267 	xfs_alloc_key_t		*kp = &key->alloc;
268 	__int64_t		diff;
269 
270 	if (cur->bc_btnum == XFS_BTNUM_BNO) {
271 		return (__int64_t)be32_to_cpu(kp->ar_startblock) -
272 				rec->ar_startblock;
273 	}
274 
275 	diff = (__int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount;
276 	if (diff)
277 		return diff;
278 
279 	return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
280 }
281 
282 STATIC int
xfs_allocbt_kill_root(struct xfs_btree_cur * cur,struct xfs_buf * bp,int level,union xfs_btree_ptr * newroot)283 xfs_allocbt_kill_root(
284 	struct xfs_btree_cur	*cur,
285 	struct xfs_buf		*bp,
286 	int			level,
287 	union xfs_btree_ptr	*newroot)
288 {
289 	int			error;
290 
291 	XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
292 	XFS_BTREE_STATS_INC(cur, killroot);
293 
294 	/*
295 	 * Update the root pointer, decreasing the level by 1 and then
296 	 * free the old root.
297 	 */
298 	xfs_allocbt_set_root(cur, newroot, -1);
299 	error = xfs_allocbt_free_block(cur, bp);
300 	if (error) {
301 		XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
302 		return error;
303 	}
304 
305 	XFS_BTREE_STATS_INC(cur, free);
306 
307 	xfs_btree_setbuf(cur, level, NULL);
308 	cur->bc_nlevels--;
309 
310 	XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
311 	return 0;
312 }
313 
314 #ifdef DEBUG
315 STATIC int
xfs_allocbt_keys_inorder(struct xfs_btree_cur * cur,union xfs_btree_key * k1,union xfs_btree_key * k2)316 xfs_allocbt_keys_inorder(
317 	struct xfs_btree_cur	*cur,
318 	union xfs_btree_key	*k1,
319 	union xfs_btree_key	*k2)
320 {
321 	if (cur->bc_btnum == XFS_BTNUM_BNO) {
322 		return be32_to_cpu(k1->alloc.ar_startblock) <
323 		       be32_to_cpu(k2->alloc.ar_startblock);
324 	} else {
325 		return be32_to_cpu(k1->alloc.ar_blockcount) <
326 			be32_to_cpu(k2->alloc.ar_blockcount) ||
327 			(k1->alloc.ar_blockcount == k2->alloc.ar_blockcount &&
328 			 be32_to_cpu(k1->alloc.ar_startblock) <
329 			 be32_to_cpu(k2->alloc.ar_startblock));
330 	}
331 }
332 
333 STATIC int
xfs_allocbt_recs_inorder(struct xfs_btree_cur * cur,union xfs_btree_rec * r1,union xfs_btree_rec * r2)334 xfs_allocbt_recs_inorder(
335 	struct xfs_btree_cur	*cur,
336 	union xfs_btree_rec	*r1,
337 	union xfs_btree_rec	*r2)
338 {
339 	if (cur->bc_btnum == XFS_BTNUM_BNO) {
340 		return be32_to_cpu(r1->alloc.ar_startblock) +
341 			be32_to_cpu(r1->alloc.ar_blockcount) <=
342 			be32_to_cpu(r2->alloc.ar_startblock);
343 	} else {
344 		return be32_to_cpu(r1->alloc.ar_blockcount) <
345 			be32_to_cpu(r2->alloc.ar_blockcount) ||
346 			(r1->alloc.ar_blockcount == r2->alloc.ar_blockcount &&
347 			 be32_to_cpu(r1->alloc.ar_startblock) <
348 			 be32_to_cpu(r2->alloc.ar_startblock));
349 	}
350 }
351 #endif	/* DEBUG */
352 
353 #ifdef XFS_BTREE_TRACE
354 ktrace_t	*xfs_allocbt_trace_buf;
355 
356 STATIC void
xfs_allocbt_trace_enter(struct xfs_btree_cur * cur,const char * func,char * s,int type,int line,__psunsigned_t a0,__psunsigned_t a1,__psunsigned_t a2,__psunsigned_t a3,__psunsigned_t a4,__psunsigned_t a5,__psunsigned_t a6,__psunsigned_t a7,__psunsigned_t a8,__psunsigned_t a9,__psunsigned_t a10)357 xfs_allocbt_trace_enter(
358 	struct xfs_btree_cur	*cur,
359 	const char		*func,
360 	char			*s,
361 	int			type,
362 	int			line,
363 	__psunsigned_t		a0,
364 	__psunsigned_t		a1,
365 	__psunsigned_t		a2,
366 	__psunsigned_t		a3,
367 	__psunsigned_t		a4,
368 	__psunsigned_t		a5,
369 	__psunsigned_t		a6,
370 	__psunsigned_t		a7,
371 	__psunsigned_t		a8,
372 	__psunsigned_t		a9,
373 	__psunsigned_t		a10)
374 {
375 	ktrace_enter(xfs_allocbt_trace_buf, (void *)(__psint_t)type,
376 		(void *)func, (void *)s, NULL, (void *)cur,
377 		(void *)a0, (void *)a1, (void *)a2, (void *)a3,
378 		(void *)a4, (void *)a5, (void *)a6, (void *)a7,
379 		(void *)a8, (void *)a9, (void *)a10);
380 }
381 
382 STATIC void
xfs_allocbt_trace_cursor(struct xfs_btree_cur * cur,__uint32_t * s0,__uint64_t * l0,__uint64_t * l1)383 xfs_allocbt_trace_cursor(
384 	struct xfs_btree_cur	*cur,
385 	__uint32_t		*s0,
386 	__uint64_t		*l0,
387 	__uint64_t		*l1)
388 {
389 	*s0 = cur->bc_private.a.agno;
390 	*l0 = cur->bc_rec.a.ar_startblock;
391 	*l1 = cur->bc_rec.a.ar_blockcount;
392 }
393 
394 STATIC void
xfs_allocbt_trace_key(struct xfs_btree_cur * cur,union xfs_btree_key * key,__uint64_t * l0,__uint64_t * l1)395 xfs_allocbt_trace_key(
396 	struct xfs_btree_cur	*cur,
397 	union xfs_btree_key	*key,
398 	__uint64_t		*l0,
399 	__uint64_t		*l1)
400 {
401 	*l0 = be32_to_cpu(key->alloc.ar_startblock);
402 	*l1 = be32_to_cpu(key->alloc.ar_blockcount);
403 }
404 
405 STATIC void
xfs_allocbt_trace_record(struct xfs_btree_cur * cur,union xfs_btree_rec * rec,__uint64_t * l0,__uint64_t * l1,__uint64_t * l2)406 xfs_allocbt_trace_record(
407 	struct xfs_btree_cur	*cur,
408 	union xfs_btree_rec	*rec,
409 	__uint64_t		*l0,
410 	__uint64_t		*l1,
411 	__uint64_t		*l2)
412 {
413 	*l0 = be32_to_cpu(rec->alloc.ar_startblock);
414 	*l1 = be32_to_cpu(rec->alloc.ar_blockcount);
415 	*l2 = 0;
416 }
417 #endif /* XFS_BTREE_TRACE */
418 
419 static const struct xfs_btree_ops xfs_allocbt_ops = {
420 	.rec_len		= sizeof(xfs_alloc_rec_t),
421 	.key_len		= sizeof(xfs_alloc_key_t),
422 
423 	.dup_cursor		= xfs_allocbt_dup_cursor,
424 	.set_root		= xfs_allocbt_set_root,
425 	.kill_root		= xfs_allocbt_kill_root,
426 	.alloc_block		= xfs_allocbt_alloc_block,
427 	.free_block		= xfs_allocbt_free_block,
428 	.update_lastrec		= xfs_allocbt_update_lastrec,
429 	.get_minrecs		= xfs_allocbt_get_minrecs,
430 	.get_maxrecs		= xfs_allocbt_get_maxrecs,
431 	.init_key_from_rec	= xfs_allocbt_init_key_from_rec,
432 	.init_rec_from_key	= xfs_allocbt_init_rec_from_key,
433 	.init_rec_from_cur	= xfs_allocbt_init_rec_from_cur,
434 	.init_ptr_from_cur	= xfs_allocbt_init_ptr_from_cur,
435 	.key_diff		= xfs_allocbt_key_diff,
436 
437 #ifdef DEBUG
438 	.keys_inorder		= xfs_allocbt_keys_inorder,
439 	.recs_inorder		= xfs_allocbt_recs_inorder,
440 #endif
441 
442 #ifdef XFS_BTREE_TRACE
443 	.trace_enter		= xfs_allocbt_trace_enter,
444 	.trace_cursor		= xfs_allocbt_trace_cursor,
445 	.trace_key		= xfs_allocbt_trace_key,
446 	.trace_record		= xfs_allocbt_trace_record,
447 #endif
448 };
449 
450 /*
451  * Allocate a new allocation btree cursor.
452  */
453 struct xfs_btree_cur *			/* new alloc btree cursor */
xfs_allocbt_init_cursor(struct xfs_mount * mp,struct xfs_trans * tp,struct xfs_buf * agbp,xfs_agnumber_t agno,xfs_btnum_t btnum)454 xfs_allocbt_init_cursor(
455 	struct xfs_mount	*mp,		/* file system mount point */
456 	struct xfs_trans	*tp,		/* transaction pointer */
457 	struct xfs_buf		*agbp,		/* buffer for agf structure */
458 	xfs_agnumber_t		agno,		/* allocation group number */
459 	xfs_btnum_t		btnum)		/* btree identifier */
460 {
461 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
462 	struct xfs_btree_cur	*cur;
463 
464 	ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT);
465 
466 	cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
467 
468 	cur->bc_tp = tp;
469 	cur->bc_mp = mp;
470 	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[btnum]);
471 	cur->bc_btnum = btnum;
472 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
473 
474 	cur->bc_ops = &xfs_allocbt_ops;
475 	if (btnum == XFS_BTNUM_CNT)
476 		cur->bc_flags = XFS_BTREE_LASTREC_UPDATE;
477 
478 	cur->bc_private.a.agbp = agbp;
479 	cur->bc_private.a.agno = agno;
480 
481 	return cur;
482 }
483 
484 /*
485  * Calculate number of records in an alloc btree block.
486  */
487 int
xfs_allocbt_maxrecs(struct xfs_mount * mp,int blocklen,int leaf)488 xfs_allocbt_maxrecs(
489 	struct xfs_mount	*mp,
490 	int			blocklen,
491 	int			leaf)
492 {
493 	blocklen -= XFS_ALLOC_BLOCK_LEN(mp);
494 
495 	if (leaf)
496 		return blocklen / sizeof(xfs_alloc_rec_t);
497 	return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t));
498 }
499