1 /*
2  * Copyright (c) 2000-2002,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_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_trans.h"
24 #include "xfs_sb.h"
25 #include "xfs_ag.h"
26 #include "xfs_mount.h"
27 #include "xfs_da_btree.h"
28 #include "xfs_bmap_btree.h"
29 #include "xfs_dinode.h"
30 #include "xfs_inode.h"
31 #include "xfs_dir2_format.h"
32 #include "xfs_dir2_priv.h"
33 #include "xfs_error.h"
34 
35 STATIC xfs_dir2_data_free_t *
36 xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup);
37 
38 #ifdef DEBUG
39 /*
40  * Check the consistency of the data block.
41  * The input can also be a block-format directory.
42  * Pop an assert if we find anything bad.
43  */
44 void
xfs_dir2_data_check(xfs_inode_t * dp,xfs_dabuf_t * bp)45 xfs_dir2_data_check(
46 	xfs_inode_t		*dp,		/* incore inode pointer */
47 	xfs_dabuf_t		*bp)		/* data block's buffer */
48 {
49 	xfs_dir2_dataptr_t	addr;		/* addr for leaf lookup */
50 	xfs_dir2_data_free_t	*bf;		/* bestfree table */
51 	xfs_dir2_block_tail_t	*btp=NULL;	/* block tail */
52 	int			count;		/* count of entries found */
53 	xfs_dir2_data_hdr_t	*hdr;		/* data block header */
54 	xfs_dir2_data_entry_t	*dep;		/* data entry */
55 	xfs_dir2_data_free_t	*dfp;		/* bestfree entry */
56 	xfs_dir2_data_unused_t	*dup;		/* unused entry */
57 	char			*endp;		/* end of useful data */
58 	int			freeseen;	/* mask of bestfrees seen */
59 	xfs_dahash_t		hash;		/* hash of current name */
60 	int			i;		/* leaf index */
61 	int			lastfree;	/* last entry was unused */
62 	xfs_dir2_leaf_entry_t	*lep=NULL;	/* block leaf entries */
63 	xfs_mount_t		*mp;		/* filesystem mount point */
64 	char			*p;		/* current data position */
65 	int			stale;		/* count of stale leaves */
66 	struct xfs_name		name;
67 
68 	mp = dp->i_mount;
69 	hdr = bp->data;
70 	bf = hdr->bestfree;
71 	p = (char *)(hdr + 1);
72 
73 	if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
74 		btp = xfs_dir2_block_tail_p(mp, hdr);
75 		lep = xfs_dir2_block_leaf_p(btp);
76 		endp = (char *)lep;
77 	} else {
78 		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC));
79 		endp = (char *)hdr + mp->m_dirblksize;
80 	}
81 
82 	count = lastfree = freeseen = 0;
83 	/*
84 	 * Account for zero bestfree entries.
85 	 */
86 	if (!bf[0].length) {
87 		ASSERT(!bf[0].offset);
88 		freeseen |= 1 << 0;
89 	}
90 	if (!bf[1].length) {
91 		ASSERT(!bf[1].offset);
92 		freeseen |= 1 << 1;
93 	}
94 	if (!bf[2].length) {
95 		ASSERT(!bf[2].offset);
96 		freeseen |= 1 << 2;
97 	}
98 	ASSERT(be16_to_cpu(bf[0].length) >= be16_to_cpu(bf[1].length));
99 	ASSERT(be16_to_cpu(bf[1].length) >= be16_to_cpu(bf[2].length));
100 	/*
101 	 * Loop over the data/unused entries.
102 	 */
103 	while (p < endp) {
104 		dup = (xfs_dir2_data_unused_t *)p;
105 		/*
106 		 * If it's unused, look for the space in the bestfree table.
107 		 * If we find it, account for that, else make sure it
108 		 * doesn't need to be there.
109 		 */
110 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
111 			ASSERT(lastfree == 0);
112 			ASSERT(be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
113 			       (char *)dup - (char *)hdr);
114 			dfp = xfs_dir2_data_freefind(hdr, dup);
115 			if (dfp) {
116 				i = (int)(dfp - bf);
117 				ASSERT((freeseen & (1 << i)) == 0);
118 				freeseen |= 1 << i;
119 			} else {
120 				ASSERT(be16_to_cpu(dup->length) <=
121 				       be16_to_cpu(bf[2].length));
122 			}
123 			p += be16_to_cpu(dup->length);
124 			lastfree = 1;
125 			continue;
126 		}
127 		/*
128 		 * It's a real entry.  Validate the fields.
129 		 * If this is a block directory then make sure it's
130 		 * in the leaf section of the block.
131 		 * The linear search is crude but this is DEBUG code.
132 		 */
133 		dep = (xfs_dir2_data_entry_t *)p;
134 		ASSERT(dep->namelen != 0);
135 		ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0);
136 		ASSERT(be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
137 		       (char *)dep - (char *)hdr);
138 		count++;
139 		lastfree = 0;
140 		if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
141 			addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
142 				(xfs_dir2_data_aoff_t)
143 				((char *)dep - (char *)hdr));
144 			name.name = dep->name;
145 			name.len = dep->namelen;
146 			hash = mp->m_dirnameops->hashname(&name);
147 			for (i = 0; i < be32_to_cpu(btp->count); i++) {
148 				if (be32_to_cpu(lep[i].address) == addr &&
149 				    be32_to_cpu(lep[i].hashval) == hash)
150 					break;
151 			}
152 			ASSERT(i < be32_to_cpu(btp->count));
153 		}
154 		p += xfs_dir2_data_entsize(dep->namelen);
155 	}
156 	/*
157 	 * Need to have seen all the entries and all the bestfree slots.
158 	 */
159 	ASSERT(freeseen == 7);
160 	if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
161 		for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
162 			if (lep[i].address ==
163 			    cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
164 				stale++;
165 			if (i > 0)
166 				ASSERT(be32_to_cpu(lep[i].hashval) >= be32_to_cpu(lep[i - 1].hashval));
167 		}
168 		ASSERT(count == be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
169 		ASSERT(stale == be32_to_cpu(btp->stale));
170 	}
171 }
172 #endif
173 
174 /*
175  * Given a data block and an unused entry from that block,
176  * return the bestfree entry if any that corresponds to it.
177  */
178 STATIC xfs_dir2_data_free_t *
xfs_dir2_data_freefind(xfs_dir2_data_hdr_t * hdr,xfs_dir2_data_unused_t * dup)179 xfs_dir2_data_freefind(
180 	xfs_dir2_data_hdr_t	*hdr,		/* data block */
181 	xfs_dir2_data_unused_t	*dup)		/* data unused entry */
182 {
183 	xfs_dir2_data_free_t	*dfp;		/* bestfree entry */
184 	xfs_dir2_data_aoff_t	off;		/* offset value needed */
185 #if defined(DEBUG) && defined(__KERNEL__)
186 	int			matched;	/* matched the value */
187 	int			seenzero;	/* saw a 0 bestfree entry */
188 #endif
189 
190 	off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
191 #if defined(DEBUG) && defined(__KERNEL__)
192 	/*
193 	 * Validate some consistency in the bestfree table.
194 	 * Check order, non-overlapping entries, and if we find the
195 	 * one we're looking for it has to be exact.
196 	 */
197 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
198 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
199 	for (dfp = &hdr->bestfree[0], seenzero = matched = 0;
200 	     dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT];
201 	     dfp++) {
202 		if (!dfp->offset) {
203 			ASSERT(!dfp->length);
204 			seenzero = 1;
205 			continue;
206 		}
207 		ASSERT(seenzero == 0);
208 		if (be16_to_cpu(dfp->offset) == off) {
209 			matched = 1;
210 			ASSERT(dfp->length == dup->length);
211 		} else if (off < be16_to_cpu(dfp->offset))
212 			ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
213 		else
214 			ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
215 		ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
216 		if (dfp > &hdr->bestfree[0])
217 			ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
218 	}
219 #endif
220 	/*
221 	 * If this is smaller than the smallest bestfree entry,
222 	 * it can't be there since they're sorted.
223 	 */
224 	if (be16_to_cpu(dup->length) <
225 	    be16_to_cpu(hdr->bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length))
226 		return NULL;
227 	/*
228 	 * Look at the three bestfree entries for our guy.
229 	 */
230 	for (dfp = &hdr->bestfree[0];
231 	     dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT];
232 	     dfp++) {
233 		if (!dfp->offset)
234 			return NULL;
235 		if (be16_to_cpu(dfp->offset) == off)
236 			return dfp;
237 	}
238 	/*
239 	 * Didn't find it.  This only happens if there are duplicate lengths.
240 	 */
241 	return NULL;
242 }
243 
244 /*
245  * Insert an unused-space entry into the bestfree table.
246  */
247 xfs_dir2_data_free_t *				/* entry inserted */
xfs_dir2_data_freeinsert(xfs_dir2_data_hdr_t * hdr,xfs_dir2_data_unused_t * dup,int * loghead)248 xfs_dir2_data_freeinsert(
249 	xfs_dir2_data_hdr_t	*hdr,		/* data block pointer */
250 	xfs_dir2_data_unused_t	*dup,		/* unused space */
251 	int			*loghead)	/* log the data header (out) */
252 {
253 	xfs_dir2_data_free_t	*dfp;		/* bestfree table pointer */
254 	xfs_dir2_data_free_t	new;		/* new bestfree entry */
255 
256 #ifdef __KERNEL__
257 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
258 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
259 #endif
260 	dfp = hdr->bestfree;
261 	new.length = dup->length;
262 	new.offset = cpu_to_be16((char *)dup - (char *)hdr);
263 
264 	/*
265 	 * Insert at position 0, 1, or 2; or not at all.
266 	 */
267 	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
268 		dfp[2] = dfp[1];
269 		dfp[1] = dfp[0];
270 		dfp[0] = new;
271 		*loghead = 1;
272 		return &dfp[0];
273 	}
274 	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
275 		dfp[2] = dfp[1];
276 		dfp[1] = new;
277 		*loghead = 1;
278 		return &dfp[1];
279 	}
280 	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
281 		dfp[2] = new;
282 		*loghead = 1;
283 		return &dfp[2];
284 	}
285 	return NULL;
286 }
287 
288 /*
289  * Remove a bestfree entry from the table.
290  */
291 STATIC void
xfs_dir2_data_freeremove(xfs_dir2_data_hdr_t * hdr,xfs_dir2_data_free_t * dfp,int * loghead)292 xfs_dir2_data_freeremove(
293 	xfs_dir2_data_hdr_t	*hdr,		/* data block header */
294 	xfs_dir2_data_free_t	*dfp,		/* bestfree entry pointer */
295 	int			*loghead)	/* out: log data header */
296 {
297 #ifdef __KERNEL__
298 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
299 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
300 #endif
301 	/*
302 	 * It's the first entry, slide the next 2 up.
303 	 */
304 	if (dfp == &hdr->bestfree[0]) {
305 		hdr->bestfree[0] = hdr->bestfree[1];
306 		hdr->bestfree[1] = hdr->bestfree[2];
307 	}
308 	/*
309 	 * It's the second entry, slide the 3rd entry up.
310 	 */
311 	else if (dfp == &hdr->bestfree[1])
312 		hdr->bestfree[1] = hdr->bestfree[2];
313 	/*
314 	 * Must be the last entry.
315 	 */
316 	else
317 		ASSERT(dfp == &hdr->bestfree[2]);
318 	/*
319 	 * Clear the 3rd entry, must be zero now.
320 	 */
321 	hdr->bestfree[2].length = 0;
322 	hdr->bestfree[2].offset = 0;
323 	*loghead = 1;
324 }
325 
326 /*
327  * Given a data block, reconstruct its bestfree map.
328  */
329 void
xfs_dir2_data_freescan(xfs_mount_t * mp,xfs_dir2_data_hdr_t * hdr,int * loghead)330 xfs_dir2_data_freescan(
331 	xfs_mount_t		*mp,		/* filesystem mount point */
332 	xfs_dir2_data_hdr_t	*hdr,		/* data block header */
333 	int			*loghead)	/* out: log data header */
334 {
335 	xfs_dir2_block_tail_t	*btp;		/* block tail */
336 	xfs_dir2_data_entry_t	*dep;		/* active data entry */
337 	xfs_dir2_data_unused_t	*dup;		/* unused data entry */
338 	char			*endp;		/* end of block's data */
339 	char			*p;		/* current entry pointer */
340 
341 #ifdef __KERNEL__
342 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
343 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
344 #endif
345 	/*
346 	 * Start by clearing the table.
347 	 */
348 	memset(hdr->bestfree, 0, sizeof(hdr->bestfree));
349 	*loghead = 1;
350 	/*
351 	 * Set up pointers.
352 	 */
353 	p = (char *)(hdr + 1);
354 	if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
355 		btp = xfs_dir2_block_tail_p(mp, hdr);
356 		endp = (char *)xfs_dir2_block_leaf_p(btp);
357 	} else
358 		endp = (char *)hdr + mp->m_dirblksize;
359 	/*
360 	 * Loop over the block's entries.
361 	 */
362 	while (p < endp) {
363 		dup = (xfs_dir2_data_unused_t *)p;
364 		/*
365 		 * If it's a free entry, insert it.
366 		 */
367 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
368 			ASSERT((char *)dup - (char *)hdr ==
369 			       be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
370 			xfs_dir2_data_freeinsert(hdr, dup, loghead);
371 			p += be16_to_cpu(dup->length);
372 		}
373 		/*
374 		 * For active entries, check their tags and skip them.
375 		 */
376 		else {
377 			dep = (xfs_dir2_data_entry_t *)p;
378 			ASSERT((char *)dep - (char *)hdr ==
379 			       be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
380 			p += xfs_dir2_data_entsize(dep->namelen);
381 		}
382 	}
383 }
384 
385 /*
386  * Initialize a data block at the given block number in the directory.
387  * Give back the buffer for the created block.
388  */
389 int						/* error */
xfs_dir2_data_init(xfs_da_args_t * args,xfs_dir2_db_t blkno,xfs_dabuf_t ** bpp)390 xfs_dir2_data_init(
391 	xfs_da_args_t		*args,		/* directory operation args */
392 	xfs_dir2_db_t		blkno,		/* logical dir block number */
393 	xfs_dabuf_t		**bpp)		/* output block buffer */
394 {
395 	xfs_dabuf_t		*bp;		/* block buffer */
396 	xfs_dir2_data_hdr_t	*hdr;		/* data block header */
397 	xfs_inode_t		*dp;		/* incore directory inode */
398 	xfs_dir2_data_unused_t	*dup;		/* unused entry pointer */
399 	int			error;		/* error return value */
400 	int			i;		/* bestfree index */
401 	xfs_mount_t		*mp;		/* filesystem mount point */
402 	xfs_trans_t		*tp;		/* transaction pointer */
403 	int                     t;              /* temp */
404 
405 	dp = args->dp;
406 	mp = dp->i_mount;
407 	tp = args->trans;
408 	/*
409 	 * Get the buffer set up for the block.
410 	 */
411 	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
412 		XFS_DATA_FORK);
413 	if (error) {
414 		return error;
415 	}
416 	ASSERT(bp != NULL);
417 
418 	/*
419 	 * Initialize the header.
420 	 */
421 	hdr = bp->data;
422 	hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
423 	hdr->bestfree[0].offset = cpu_to_be16(sizeof(*hdr));
424 	for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
425 		hdr->bestfree[i].length = 0;
426 		hdr->bestfree[i].offset = 0;
427 	}
428 
429 	/*
430 	 * Set up an unused entry for the block's body.
431 	 */
432 	dup = (xfs_dir2_data_unused_t *)(hdr + 1);
433 	dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
434 
435 	t = mp->m_dirblksize - (uint)sizeof(*hdr);
436 	hdr->bestfree[0].length = cpu_to_be16(t);
437 	dup->length = cpu_to_be16(t);
438 	*xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
439 	/*
440 	 * Log it and return it.
441 	 */
442 	xfs_dir2_data_log_header(tp, bp);
443 	xfs_dir2_data_log_unused(tp, bp, dup);
444 	*bpp = bp;
445 	return 0;
446 }
447 
448 /*
449  * Log an active data entry from the block.
450  */
451 void
xfs_dir2_data_log_entry(xfs_trans_t * tp,xfs_dabuf_t * bp,xfs_dir2_data_entry_t * dep)452 xfs_dir2_data_log_entry(
453 	xfs_trans_t		*tp,		/* transaction pointer */
454 	xfs_dabuf_t		*bp,		/* block buffer */
455 	xfs_dir2_data_entry_t	*dep)		/* data entry pointer */
456 {
457 	xfs_dir2_data_hdr_t	*hdr = bp->data;
458 
459 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
460 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
461 
462 	xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
463 		(uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
464 		       (char *)hdr - 1));
465 }
466 
467 /*
468  * Log a data block header.
469  */
470 void
xfs_dir2_data_log_header(xfs_trans_t * tp,xfs_dabuf_t * bp)471 xfs_dir2_data_log_header(
472 	xfs_trans_t		*tp,		/* transaction pointer */
473 	xfs_dabuf_t		*bp)		/* block buffer */
474 {
475 	xfs_dir2_data_hdr_t	*hdr = bp->data;
476 
477 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
478 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
479 
480 	xfs_da_log_buf(tp, bp, 0, sizeof(*hdr) - 1);
481 }
482 
483 /*
484  * Log a data unused entry.
485  */
486 void
xfs_dir2_data_log_unused(xfs_trans_t * tp,xfs_dabuf_t * bp,xfs_dir2_data_unused_t * dup)487 xfs_dir2_data_log_unused(
488 	xfs_trans_t		*tp,		/* transaction pointer */
489 	xfs_dabuf_t		*bp,		/* block buffer */
490 	xfs_dir2_data_unused_t	*dup)		/* data unused pointer */
491 {
492 	xfs_dir2_data_hdr_t	*hdr = bp->data;
493 
494 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
495 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
496 
497 	/*
498 	 * Log the first part of the unused entry.
499 	 */
500 	xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
501 		(uint)((char *)&dup->length + sizeof(dup->length) -
502 		       1 - (char *)hdr));
503 	/*
504 	 * Log the end (tag) of the unused entry.
505 	 */
506 	xfs_da_log_buf(tp, bp,
507 		(uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
508 		(uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
509 		       sizeof(xfs_dir2_data_off_t) - 1));
510 }
511 
512 /*
513  * Make a byte range in the data block unused.
514  * Its current contents are unimportant.
515  */
516 void
xfs_dir2_data_make_free(xfs_trans_t * tp,xfs_dabuf_t * bp,xfs_dir2_data_aoff_t offset,xfs_dir2_data_aoff_t len,int * needlogp,int * needscanp)517 xfs_dir2_data_make_free(
518 	xfs_trans_t		*tp,		/* transaction pointer */
519 	xfs_dabuf_t		*bp,		/* block buffer */
520 	xfs_dir2_data_aoff_t	offset,		/* starting byte offset */
521 	xfs_dir2_data_aoff_t	len,		/* length in bytes */
522 	int			*needlogp,	/* out: log header */
523 	int			*needscanp)	/* out: regen bestfree */
524 {
525 	xfs_dir2_data_hdr_t	*hdr;		/* data block pointer */
526 	xfs_dir2_data_free_t	*dfp;		/* bestfree pointer */
527 	char			*endptr;	/* end of data area */
528 	xfs_mount_t		*mp;		/* filesystem mount point */
529 	int			needscan;	/* need to regen bestfree */
530 	xfs_dir2_data_unused_t	*newdup;	/* new unused entry */
531 	xfs_dir2_data_unused_t	*postdup;	/* unused entry after us */
532 	xfs_dir2_data_unused_t	*prevdup;	/* unused entry before us */
533 
534 	mp = tp->t_mountp;
535 	hdr = bp->data;
536 
537 	/*
538 	 * Figure out where the end of the data area is.
539 	 */
540 	if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC))
541 		endptr = (char *)hdr + mp->m_dirblksize;
542 	else {
543 		xfs_dir2_block_tail_t	*btp;	/* block tail */
544 
545 		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
546 		btp = xfs_dir2_block_tail_p(mp, hdr);
547 		endptr = (char *)xfs_dir2_block_leaf_p(btp);
548 	}
549 	/*
550 	 * If this isn't the start of the block, then back up to
551 	 * the previous entry and see if it's free.
552 	 */
553 	if (offset > sizeof(*hdr)) {
554 		__be16			*tagp;	/* tag just before us */
555 
556 		tagp = (__be16 *)((char *)hdr + offset) - 1;
557 		prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
558 		if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
559 			prevdup = NULL;
560 	} else
561 		prevdup = NULL;
562 	/*
563 	 * If this isn't the end of the block, see if the entry after
564 	 * us is free.
565 	 */
566 	if ((char *)hdr + offset + len < endptr) {
567 		postdup =
568 			(xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
569 		if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
570 			postdup = NULL;
571 	} else
572 		postdup = NULL;
573 	ASSERT(*needscanp == 0);
574 	needscan = 0;
575 	/*
576 	 * Previous and following entries are both free,
577 	 * merge everything into a single free entry.
578 	 */
579 	if (prevdup && postdup) {
580 		xfs_dir2_data_free_t	*dfp2;	/* another bestfree pointer */
581 
582 		/*
583 		 * See if prevdup and/or postdup are in bestfree table.
584 		 */
585 		dfp = xfs_dir2_data_freefind(hdr, prevdup);
586 		dfp2 = xfs_dir2_data_freefind(hdr, postdup);
587 		/*
588 		 * We need a rescan unless there are exactly 2 free entries
589 		 * namely our two.  Then we know what's happening, otherwise
590 		 * since the third bestfree is there, there might be more
591 		 * entries.
592 		 */
593 		needscan = (hdr->bestfree[2].length != 0);
594 		/*
595 		 * Fix up the new big freespace.
596 		 */
597 		be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
598 		*xfs_dir2_data_unused_tag_p(prevdup) =
599 			cpu_to_be16((char *)prevdup - (char *)hdr);
600 		xfs_dir2_data_log_unused(tp, bp, prevdup);
601 		if (!needscan) {
602 			/*
603 			 * Has to be the case that entries 0 and 1 are
604 			 * dfp and dfp2 (don't know which is which), and
605 			 * entry 2 is empty.
606 			 * Remove entry 1 first then entry 0.
607 			 */
608 			ASSERT(dfp && dfp2);
609 			if (dfp == &hdr->bestfree[1]) {
610 				dfp = &hdr->bestfree[0];
611 				ASSERT(dfp2 == dfp);
612 				dfp2 = &hdr->bestfree[1];
613 			}
614 			xfs_dir2_data_freeremove(hdr, dfp2, needlogp);
615 			xfs_dir2_data_freeremove(hdr, dfp, needlogp);
616 			/*
617 			 * Now insert the new entry.
618 			 */
619 			dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
620 			ASSERT(dfp == &hdr->bestfree[0]);
621 			ASSERT(dfp->length == prevdup->length);
622 			ASSERT(!dfp[1].length);
623 			ASSERT(!dfp[2].length);
624 		}
625 	}
626 	/*
627 	 * The entry before us is free, merge with it.
628 	 */
629 	else if (prevdup) {
630 		dfp = xfs_dir2_data_freefind(hdr, prevdup);
631 		be16_add_cpu(&prevdup->length, len);
632 		*xfs_dir2_data_unused_tag_p(prevdup) =
633 			cpu_to_be16((char *)prevdup - (char *)hdr);
634 		xfs_dir2_data_log_unused(tp, bp, prevdup);
635 		/*
636 		 * If the previous entry was in the table, the new entry
637 		 * is longer, so it will be in the table too.  Remove
638 		 * the old one and add the new one.
639 		 */
640 		if (dfp) {
641 			xfs_dir2_data_freeremove(hdr, dfp, needlogp);
642 			xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
643 		}
644 		/*
645 		 * Otherwise we need a scan if the new entry is big enough.
646 		 */
647 		else {
648 			needscan = be16_to_cpu(prevdup->length) >
649 				   be16_to_cpu(hdr->bestfree[2].length);
650 		}
651 	}
652 	/*
653 	 * The following entry is free, merge with it.
654 	 */
655 	else if (postdup) {
656 		dfp = xfs_dir2_data_freefind(hdr, postdup);
657 		newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
658 		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
659 		newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
660 		*xfs_dir2_data_unused_tag_p(newdup) =
661 			cpu_to_be16((char *)newdup - (char *)hdr);
662 		xfs_dir2_data_log_unused(tp, bp, newdup);
663 		/*
664 		 * If the following entry was in the table, the new entry
665 		 * is longer, so it will be in the table too.  Remove
666 		 * the old one and add the new one.
667 		 */
668 		if (dfp) {
669 			xfs_dir2_data_freeremove(hdr, dfp, needlogp);
670 			xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
671 		}
672 		/*
673 		 * Otherwise we need a scan if the new entry is big enough.
674 		 */
675 		else {
676 			needscan = be16_to_cpu(newdup->length) >
677 				   be16_to_cpu(hdr->bestfree[2].length);
678 		}
679 	}
680 	/*
681 	 * Neither neighbor is free.  Make a new entry.
682 	 */
683 	else {
684 		newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
685 		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
686 		newdup->length = cpu_to_be16(len);
687 		*xfs_dir2_data_unused_tag_p(newdup) =
688 			cpu_to_be16((char *)newdup - (char *)hdr);
689 		xfs_dir2_data_log_unused(tp, bp, newdup);
690 		xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
691 	}
692 	*needscanp = needscan;
693 }
694 
695 /*
696  * Take a byte range out of an existing unused space and make it un-free.
697  */
698 void
xfs_dir2_data_use_free(xfs_trans_t * tp,xfs_dabuf_t * bp,xfs_dir2_data_unused_t * dup,xfs_dir2_data_aoff_t offset,xfs_dir2_data_aoff_t len,int * needlogp,int * needscanp)699 xfs_dir2_data_use_free(
700 	xfs_trans_t		*tp,		/* transaction pointer */
701 	xfs_dabuf_t		*bp,		/* data block buffer */
702 	xfs_dir2_data_unused_t	*dup,		/* unused entry */
703 	xfs_dir2_data_aoff_t	offset,		/* starting offset to use */
704 	xfs_dir2_data_aoff_t	len,		/* length to use */
705 	int			*needlogp,	/* out: need to log header */
706 	int			*needscanp)	/* out: need regen bestfree */
707 {
708 	xfs_dir2_data_hdr_t	*hdr;		/* data block header */
709 	xfs_dir2_data_free_t	*dfp;		/* bestfree pointer */
710 	int			matchback;	/* matches end of freespace */
711 	int			matchfront;	/* matches start of freespace */
712 	int			needscan;	/* need to regen bestfree */
713 	xfs_dir2_data_unused_t	*newdup;	/* new unused entry */
714 	xfs_dir2_data_unused_t	*newdup2;	/* another new unused entry */
715 	int			oldlen;		/* old unused entry's length */
716 
717 	hdr = bp->data;
718 	ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
719 	       hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
720 	ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
721 	ASSERT(offset >= (char *)dup - (char *)hdr);
722 	ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
723 	ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
724 	/*
725 	 * Look up the entry in the bestfree table.
726 	 */
727 	dfp = xfs_dir2_data_freefind(hdr, dup);
728 	oldlen = be16_to_cpu(dup->length);
729 	ASSERT(dfp || oldlen <= be16_to_cpu(hdr->bestfree[2].length));
730 	/*
731 	 * Check for alignment with front and back of the entry.
732 	 */
733 	matchfront = (char *)dup - (char *)hdr == offset;
734 	matchback = (char *)dup + oldlen - (char *)hdr == offset + len;
735 	ASSERT(*needscanp == 0);
736 	needscan = 0;
737 	/*
738 	 * If we matched it exactly we just need to get rid of it from
739 	 * the bestfree table.
740 	 */
741 	if (matchfront && matchback) {
742 		if (dfp) {
743 			needscan = (hdr->bestfree[2].offset != 0);
744 			if (!needscan)
745 				xfs_dir2_data_freeremove(hdr, dfp, needlogp);
746 		}
747 	}
748 	/*
749 	 * We match the first part of the entry.
750 	 * Make a new entry with the remaining freespace.
751 	 */
752 	else if (matchfront) {
753 		newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
754 		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
755 		newdup->length = cpu_to_be16(oldlen - len);
756 		*xfs_dir2_data_unused_tag_p(newdup) =
757 			cpu_to_be16((char *)newdup - (char *)hdr);
758 		xfs_dir2_data_log_unused(tp, bp, newdup);
759 		/*
760 		 * If it was in the table, remove it and add the new one.
761 		 */
762 		if (dfp) {
763 			xfs_dir2_data_freeremove(hdr, dfp, needlogp);
764 			dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
765 			ASSERT(dfp != NULL);
766 			ASSERT(dfp->length == newdup->length);
767 			ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
768 			/*
769 			 * If we got inserted at the last slot,
770 			 * that means we don't know if there was a better
771 			 * choice for the last slot, or not.  Rescan.
772 			 */
773 			needscan = dfp == &hdr->bestfree[2];
774 		}
775 	}
776 	/*
777 	 * We match the last part of the entry.
778 	 * Trim the allocated space off the tail of the entry.
779 	 */
780 	else if (matchback) {
781 		newdup = dup;
782 		newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
783 		*xfs_dir2_data_unused_tag_p(newdup) =
784 			cpu_to_be16((char *)newdup - (char *)hdr);
785 		xfs_dir2_data_log_unused(tp, bp, newdup);
786 		/*
787 		 * If it was in the table, remove it and add the new one.
788 		 */
789 		if (dfp) {
790 			xfs_dir2_data_freeremove(hdr, dfp, needlogp);
791 			dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
792 			ASSERT(dfp != NULL);
793 			ASSERT(dfp->length == newdup->length);
794 			ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
795 			/*
796 			 * If we got inserted at the last slot,
797 			 * that means we don't know if there was a better
798 			 * choice for the last slot, or not.  Rescan.
799 			 */
800 			needscan = dfp == &hdr->bestfree[2];
801 		}
802 	}
803 	/*
804 	 * Poking out the middle of an entry.
805 	 * Make two new entries.
806 	 */
807 	else {
808 		newdup = dup;
809 		newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
810 		*xfs_dir2_data_unused_tag_p(newdup) =
811 			cpu_to_be16((char *)newdup - (char *)hdr);
812 		xfs_dir2_data_log_unused(tp, bp, newdup);
813 		newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
814 		newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
815 		newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
816 		*xfs_dir2_data_unused_tag_p(newdup2) =
817 			cpu_to_be16((char *)newdup2 - (char *)hdr);
818 		xfs_dir2_data_log_unused(tp, bp, newdup2);
819 		/*
820 		 * If the old entry was in the table, we need to scan
821 		 * if the 3rd entry was valid, since these entries
822 		 * are smaller than the old one.
823 		 * If we don't need to scan that means there were 1 or 2
824 		 * entries in the table, and removing the old and adding
825 		 * the 2 new will work.
826 		 */
827 		if (dfp) {
828 			needscan = (hdr->bestfree[2].length != 0);
829 			if (!needscan) {
830 				xfs_dir2_data_freeremove(hdr, dfp, needlogp);
831 				xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
832 				xfs_dir2_data_freeinsert(hdr, newdup2,
833 							 needlogp);
834 			}
835 		}
836 	}
837 	*needscanp = needscan;
838 }
839