]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_dir2_data.c
xfs: add buffer types to directory and attribute buffers
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_dir2_data.c
CommitLineData
2bd0ea18 1/*
da23017d 2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
693fc8f6 3 * Copyright (c) 2013 Red Hat, Inc.
da23017d 4 * All Rights Reserved.
5000d01d 5 *
da23017d
NS
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
2bd0ea18 8 * published by the Free Software Foundation.
5000d01d 9 *
da23017d
NS
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
5000d01d 14 *
da23017d
NS
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
18 */
19
2bd0ea18
NS
20#include <xfs.h>
21
2bd0ea18
NS
22/*
23 * Check the consistency of the data block.
24 * The input can also be a block-format directory.
a2ceac1f 25 * Return 0 is the buffer is good, otherwise an error.
2bd0ea18 26 */
a2ceac1f 27int
90ea28c3 28__xfs_dir3_data_check(
a2ceac1f
DC
29 struct xfs_inode *dp, /* incore inode pointer */
30 struct xfs_buf *bp) /* data block's buffer */
2bd0ea18
NS
31{
32 xfs_dir2_dataptr_t addr; /* addr for leaf lookup */
33 xfs_dir2_data_free_t *bf; /* bestfree table */
0e266570 34 xfs_dir2_block_tail_t *btp=NULL; /* block tail */
2bd0ea18 35 int count; /* count of entries found */
a2ceac1f 36 xfs_dir2_data_hdr_t *hdr; /* data block header */
2bd0ea18
NS
37 xfs_dir2_data_entry_t *dep; /* data entry */
38 xfs_dir2_data_free_t *dfp; /* bestfree entry */
39 xfs_dir2_data_unused_t *dup; /* unused entry */
40 char *endp; /* end of useful data */
41 int freeseen; /* mask of bestfrees seen */
42 xfs_dahash_t hash; /* hash of current name */
43 int i; /* leaf index */
44 int lastfree; /* last entry was unused */
0e266570 45 xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */
2bd0ea18
NS
46 xfs_mount_t *mp; /* filesystem mount point */
47 char *p; /* current data position */
48 int stale; /* count of stale leaves */
5e656dbb 49 struct xfs_name name;
2bd0ea18 50
a2ceac1f
DC
51 mp = bp->b_target->bt_mount;
52 hdr = bp->b_addr;
693fc8f6
DC
53 bf = xfs_dir3_data_bestfree_p(hdr);
54 p = (char *)xfs_dir3_data_entry_p(hdr);
a2ceac1f
DC
55
56 switch (be32_to_cpu(hdr->magic)) {
57 case XFS_DIR2_BLOCK_MAGIC:
693fc8f6 58 case XFS_DIR3_BLOCK_MAGIC:
a2ceac1f 59 btp = xfs_dir2_block_tail_p(mp, hdr);
5e656dbb 60 lep = xfs_dir2_block_leaf_p(btp);
2bd0ea18 61 endp = (char *)lep;
a2ceac1f
DC
62 break;
63 case XFS_DIR2_DATA_MAGIC:
90ea28c3 64 case XFS_DIR3_DATA_MAGIC:
a2ceac1f
DC
65 endp = (char *)hdr + mp->m_dirblksize;
66 break;
67 default:
68 XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
69 return EFSCORRUPTED;
70 }
71
2bd0ea18
NS
72 count = lastfree = freeseen = 0;
73 /*
74 * Account for zero bestfree entries.
75 */
46eca962 76 if (!bf[0].length) {
a2ceac1f 77 XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
2bd0ea18
NS
78 freeseen |= 1 << 0;
79 }
46eca962 80 if (!bf[1].length) {
a2ceac1f 81 XFS_WANT_CORRUPTED_RETURN(!bf[1].offset);
2bd0ea18
NS
82 freeseen |= 1 << 1;
83 }
46eca962 84 if (!bf[2].length) {
a2ceac1f 85 XFS_WANT_CORRUPTED_RETURN(!bf[2].offset);
2bd0ea18
NS
86 freeseen |= 1 << 2;
87 }
a2ceac1f
DC
88
89 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[0].length) >=
90 be16_to_cpu(bf[1].length));
91 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[1].length) >=
92 be16_to_cpu(bf[2].length));
2bd0ea18
NS
93 /*
94 * Loop over the data/unused entries.
95 */
96 while (p < endp) {
97 dup = (xfs_dir2_data_unused_t *)p;
98 /*
99 * If it's unused, look for the space in the bestfree table.
5000d01d 100 * If we find it, account for that, else make sure it
2bd0ea18
NS
101 * doesn't need to be there.
102 */
5e656dbb 103 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
a2ceac1f
DC
104 XFS_WANT_CORRUPTED_RETURN(lastfree == 0);
105 XFS_WANT_CORRUPTED_RETURN(
106 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
107 (char *)dup - (char *)hdr);
108 dfp = xfs_dir2_data_freefind(hdr, dup);
2bd0ea18
NS
109 if (dfp) {
110 i = (int)(dfp - bf);
a2ceac1f
DC
111 XFS_WANT_CORRUPTED_RETURN(
112 (freeseen & (1 << i)) == 0);
2bd0ea18 113 freeseen |= 1 << i;
5e656dbb 114 } else {
a2ceac1f
DC
115 XFS_WANT_CORRUPTED_RETURN(
116 be16_to_cpu(dup->length) <=
117 be16_to_cpu(bf[2].length));
5e656dbb
BN
118 }
119 p += be16_to_cpu(dup->length);
2bd0ea18
NS
120 lastfree = 1;
121 continue;
122 }
123 /*
124 * It's a real entry. Validate the fields.
5000d01d 125 * If this is a block directory then make sure it's
2bd0ea18
NS
126 * in the leaf section of the block.
127 * The linear search is crude but this is DEBUG code.
128 */
129 dep = (xfs_dir2_data_entry_t *)p;
a2ceac1f
DC
130 XFS_WANT_CORRUPTED_RETURN(dep->namelen != 0);
131 XFS_WANT_CORRUPTED_RETURN(
132 !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
133 XFS_WANT_CORRUPTED_RETURN(
134 be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
135 (char *)dep - (char *)hdr);
2bd0ea18
NS
136 count++;
137 lastfree = 0;
693fc8f6
DC
138 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
139 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
5e656dbb 140 addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
2bd0ea18 141 (xfs_dir2_data_aoff_t)
a2ceac1f 142 ((char *)dep - (char *)hdr));
5e656dbb
BN
143 name.name = dep->name;
144 name.len = dep->namelen;
145 hash = mp->m_dirnameops->hashname(&name);
146 for (i = 0; i < be32_to_cpu(btp->count); i++) {
147 if (be32_to_cpu(lep[i].address) == addr &&
148 be32_to_cpu(lep[i].hashval) == hash)
2bd0ea18
NS
149 break;
150 }
a2ceac1f 151 XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
2bd0ea18 152 }
5e656dbb 153 p += xfs_dir2_data_entsize(dep->namelen);
2bd0ea18
NS
154 }
155 /*
156 * Need to have seen all the entries and all the bestfree slots.
157 */
a2ceac1f 158 XFS_WANT_CORRUPTED_RETURN(freeseen == 7);
693fc8f6
DC
159 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
160 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
5e656dbb 161 for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
a2ceac1f
DC
162 if (lep[i].address ==
163 cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
2bd0ea18
NS
164 stale++;
165 if (i > 0)
a2ceac1f
DC
166 XFS_WANT_CORRUPTED_RETURN(
167 be32_to_cpu(lep[i].hashval) >=
168 be32_to_cpu(lep[i - 1].hashval));
2bd0ea18 169 }
a2ceac1f
DC
170 XFS_WANT_CORRUPTED_RETURN(count ==
171 be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
172 XFS_WANT_CORRUPTED_RETURN(stale == be32_to_cpu(btp->stale));
173 }
174 return 0;
175}
176
90ea28c3
DC
177static bool
178xfs_dir3_data_verify(
a2ceac1f
DC
179 struct xfs_buf *bp)
180{
181 struct xfs_mount *mp = bp->b_target->bt_mount;
90ea28c3 182 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
a2ceac1f 183
90ea28c3
DC
184 if (xfs_sb_version_hascrc(&mp->m_sb)) {
185 if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
186 return false;
187 if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
188 return false;
189 if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
190 return false;
191 } else {
192 if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC))
193 return false;
a2ceac1f 194 }
90ea28c3
DC
195 if (__xfs_dir3_data_check(NULL, bp))
196 return false;
197 return true;
a2ceac1f
DC
198}
199
200/*
201 * Readahead of the first block of the directory when it is opened is completely
202 * oblivious to the format of the directory. Hence we can either get a block
203 * format buffer or a data format buffer on readahead.
204 */
205static void
90ea28c3 206xfs_dir3_data_reada_verify(
a2ceac1f
DC
207 struct xfs_buf *bp)
208{
209 struct xfs_mount *mp = bp->b_target->bt_mount;
210 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
211
212 switch (be32_to_cpu(hdr->magic)) {
213 case XFS_DIR2_BLOCK_MAGIC:
693fc8f6
DC
214 case XFS_DIR3_BLOCK_MAGIC:
215 bp->b_ops = &xfs_dir3_block_buf_ops;
a2ceac1f
DC
216 bp->b_ops->verify_read(bp);
217 return;
218 case XFS_DIR2_DATA_MAGIC:
90ea28c3
DC
219 case XFS_DIR3_DATA_MAGIC:
220 xfs_dir3_data_verify(bp);
a2ceac1f
DC
221 return;
222 default:
223 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
224 xfs_buf_ioerror(bp, EFSCORRUPTED);
225 break;
2bd0ea18
NS
226 }
227}
a2ceac1f
DC
228
229static void
90ea28c3 230xfs_dir3_data_read_verify(
a2ceac1f
DC
231 struct xfs_buf *bp)
232{
90ea28c3
DC
233 struct xfs_mount *mp = bp->b_target->bt_mount;
234
235 if ((xfs_sb_version_hascrc(&mp->m_sb) &&
236 !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
237 XFS_DIR3_DATA_CRC_OFF)) ||
238 !xfs_dir3_data_verify(bp)) {
239 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
240 xfs_buf_ioerror(bp, EFSCORRUPTED);
241 }
a2ceac1f
DC
242}
243
244static void
90ea28c3 245xfs_dir3_data_write_verify(
a2ceac1f
DC
246 struct xfs_buf *bp)
247{
90ea28c3
DC
248 struct xfs_mount *mp = bp->b_target->bt_mount;
249 struct xfs_buf_log_item *bip = bp->b_fspriv;
250 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
251
252 if (!xfs_dir3_data_verify(bp)) {
253 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
254 xfs_buf_ioerror(bp, EFSCORRUPTED);
255 return;
256 }
257
258 if (!xfs_sb_version_hascrc(&mp->m_sb))
259 return;
260
261 if (bip)
262 hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn);
263
264 xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_DATA_CRC_OFF);
a2ceac1f
DC
265}
266
90ea28c3
DC
267const struct xfs_buf_ops xfs_dir3_data_buf_ops = {
268 .verify_read = xfs_dir3_data_read_verify,
269 .verify_write = xfs_dir3_data_write_verify,
a2ceac1f
DC
270};
271
90ea28c3
DC
272static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
273 .verify_read = xfs_dir3_data_reada_verify,
274 .verify_write = xfs_dir3_data_write_verify,
a2ceac1f
DC
275};
276
277
278int
90ea28c3 279xfs_dir3_data_read(
a2ceac1f
DC
280 struct xfs_trans *tp,
281 struct xfs_inode *dp,
282 xfs_dablk_t bno,
283 xfs_daddr_t mapped_bno,
284 struct xfs_buf **bpp)
285{
8b4dc4a9
DC
286 int err;
287
288 err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
90ea28c3 289 XFS_DATA_FORK, &xfs_dir3_data_buf_ops);
8b4dc4a9
DC
290 if (!err && tp)
291 xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_DATA_BUF);
292 return err;
a2ceac1f
DC
293}
294
295int
90ea28c3 296xfs_dir3_data_readahead(
a2ceac1f
DC
297 struct xfs_trans *tp,
298 struct xfs_inode *dp,
299 xfs_dablk_t bno,
300 xfs_daddr_t mapped_bno)
301{
302 return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
90ea28c3 303 XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops);
a2ceac1f 304}
2bd0ea18
NS
305
306/*
307 * Given a data block and an unused entry from that block,
308 * return the bestfree entry if any that corresponds to it.
309 */
310xfs_dir2_data_free_t *
311xfs_dir2_data_freefind(
a2ceac1f 312 xfs_dir2_data_hdr_t *hdr, /* data block */
2bd0ea18
NS
313 xfs_dir2_data_unused_t *dup) /* data unused entry */
314{
315 xfs_dir2_data_free_t *dfp; /* bestfree entry */
316 xfs_dir2_data_aoff_t off; /* offset value needed */
693fc8f6 317 struct xfs_dir2_data_free *bf;
2bd0ea18
NS
318#if defined(DEBUG) && defined(__KERNEL__)
319 int matched; /* matched the value */
320 int seenzero; /* saw a 0 bestfree entry */
321#endif
322
a2ceac1f 323 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
693fc8f6
DC
324 bf = xfs_dir3_data_bestfree_p(hdr);
325
2bd0ea18
NS
326#if defined(DEBUG) && defined(__KERNEL__)
327 /*
328 * Validate some consistency in the bestfree table.
329 * Check order, non-overlapping entries, and if we find the
330 * one we're looking for it has to be exact.
331 */
a2ceac1f 332 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 333 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
334 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
335 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
336 for (dfp = &bf[0], seenzero = matched = 0;
337 dfp < &bf[XFS_DIR2_DATA_FD_COUNT];
2bd0ea18 338 dfp++) {
46eca962
NS
339 if (!dfp->offset) {
340 ASSERT(!dfp->length);
2bd0ea18
NS
341 seenzero = 1;
342 continue;
343 }
344 ASSERT(seenzero == 0);
5e656dbb 345 if (be16_to_cpu(dfp->offset) == off) {
2bd0ea18 346 matched = 1;
5e656dbb
BN
347 ASSERT(dfp->length == dup->length);
348 } else if (off < be16_to_cpu(dfp->offset))
349 ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
2bd0ea18 350 else
5e656dbb
BN
351 ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
352 ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
693fc8f6 353 if (dfp > &bf[0])
5e656dbb 354 ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
2bd0ea18
NS
355 }
356#endif
357 /*
358 * If this is smaller than the smallest bestfree entry,
359 * it can't be there since they're sorted.
360 */
5e656dbb 361 if (be16_to_cpu(dup->length) <
693fc8f6 362 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
2bd0ea18
NS
363 return NULL;
364 /*
365 * Look at the three bestfree entries for our guy.
366 */
693fc8f6 367 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
46eca962 368 if (!dfp->offset)
2bd0ea18 369 return NULL;
5e656dbb 370 if (be16_to_cpu(dfp->offset) == off)
2bd0ea18
NS
371 return dfp;
372 }
373 /*
374 * Didn't find it. This only happens if there are duplicate lengths.
375 */
376 return NULL;
377}
378
379/*
380 * Insert an unused-space entry into the bestfree table.
381 */
382xfs_dir2_data_free_t * /* entry inserted */
383xfs_dir2_data_freeinsert(
a2ceac1f 384 xfs_dir2_data_hdr_t *hdr, /* data block pointer */
2bd0ea18
NS
385 xfs_dir2_data_unused_t *dup, /* unused space */
386 int *loghead) /* log the data header (out) */
387{
388 xfs_dir2_data_free_t *dfp; /* bestfree table pointer */
389 xfs_dir2_data_free_t new; /* new bestfree entry */
390
a2ceac1f 391 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
693fc8f6
DC
392 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
393 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
394 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
395
396 dfp = xfs_dir3_data_bestfree_p(hdr);
5e656dbb 397 new.length = dup->length;
a2ceac1f
DC
398 new.offset = cpu_to_be16((char *)dup - (char *)hdr);
399
2bd0ea18
NS
400 /*
401 * Insert at position 0, 1, or 2; or not at all.
402 */
5e656dbb 403 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
2bd0ea18
NS
404 dfp[2] = dfp[1];
405 dfp[1] = dfp[0];
406 dfp[0] = new;
407 *loghead = 1;
408 return &dfp[0];
409 }
5e656dbb 410 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
2bd0ea18
NS
411 dfp[2] = dfp[1];
412 dfp[1] = new;
413 *loghead = 1;
414 return &dfp[1];
415 }
5e656dbb 416 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
2bd0ea18
NS
417 dfp[2] = new;
418 *loghead = 1;
419 return &dfp[2];
420 }
421 return NULL;
422}
423
424/*
425 * Remove a bestfree entry from the table.
426 */
5e656dbb 427STATIC void
2bd0ea18 428xfs_dir2_data_freeremove(
a2ceac1f 429 xfs_dir2_data_hdr_t *hdr, /* data block header */
2bd0ea18
NS
430 xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */
431 int *loghead) /* out: log data header */
432{
693fc8f6
DC
433 struct xfs_dir2_data_free *bf;
434
a2ceac1f 435 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
693fc8f6
DC
436 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
437 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
438 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
439
2bd0ea18
NS
440 /*
441 * It's the first entry, slide the next 2 up.
442 */
693fc8f6
DC
443 bf = xfs_dir3_data_bestfree_p(hdr);
444 if (dfp == &bf[0]) {
445 bf[0] = bf[1];
446 bf[1] = bf[2];
2bd0ea18
NS
447 }
448 /*
449 * It's the second entry, slide the 3rd entry up.
450 */
693fc8f6
DC
451 else if (dfp == &bf[1])
452 bf[1] = bf[2];
2bd0ea18
NS
453 /*
454 * Must be the last entry.
455 */
456 else
693fc8f6 457 ASSERT(dfp == &bf[2]);
2bd0ea18
NS
458 /*
459 * Clear the 3rd entry, must be zero now.
460 */
693fc8f6
DC
461 bf[2].length = 0;
462 bf[2].offset = 0;
2bd0ea18
NS
463 *loghead = 1;
464}
465
466/*
467 * Given a data block, reconstruct its bestfree map.
468 */
469void
470xfs_dir2_data_freescan(
471 xfs_mount_t *mp, /* filesystem mount point */
a2ceac1f 472 xfs_dir2_data_hdr_t *hdr, /* data block header */
5e656dbb 473 int *loghead) /* out: log data header */
2bd0ea18
NS
474{
475 xfs_dir2_block_tail_t *btp; /* block tail */
476 xfs_dir2_data_entry_t *dep; /* active data entry */
477 xfs_dir2_data_unused_t *dup; /* unused data entry */
693fc8f6 478 struct xfs_dir2_data_free *bf;
2bd0ea18
NS
479 char *endp; /* end of block's data */
480 char *p; /* current entry pointer */
481
a2ceac1f 482 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 483 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
484 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
485 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
486
2bd0ea18
NS
487 /*
488 * Start by clearing the table.
489 */
693fc8f6
DC
490 bf = xfs_dir3_data_bestfree_p(hdr);
491 memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
2bd0ea18
NS
492 *loghead = 1;
493 /*
494 * Set up pointers.
495 */
693fc8f6
DC
496 p = (char *)xfs_dir3_data_entry_p(hdr);
497 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
498 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
a2ceac1f 499 btp = xfs_dir2_block_tail_p(mp, hdr);
5e656dbb 500 endp = (char *)xfs_dir2_block_leaf_p(btp);
2bd0ea18 501 } else
a2ceac1f 502 endp = (char *)hdr + mp->m_dirblksize;
2bd0ea18
NS
503 /*
504 * Loop over the block's entries.
505 */
506 while (p < endp) {
507 dup = (xfs_dir2_data_unused_t *)p;
508 /*
509 * If it's a free entry, insert it.
510 */
5e656dbb 511 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
a2ceac1f 512 ASSERT((char *)dup - (char *)hdr ==
5e656dbb 513 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
a2ceac1f 514 xfs_dir2_data_freeinsert(hdr, dup, loghead);
5e656dbb 515 p += be16_to_cpu(dup->length);
2bd0ea18
NS
516 }
517 /*
518 * For active entries, check their tags and skip them.
519 */
520 else {
521 dep = (xfs_dir2_data_entry_t *)p;
a2ceac1f 522 ASSERT((char *)dep - (char *)hdr ==
5e656dbb
BN
523 be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
524 p += xfs_dir2_data_entsize(dep->namelen);
2bd0ea18
NS
525 }
526 }
527}
528
529/*
530 * Initialize a data block at the given block number in the directory.
531 * Give back the buffer for the created block.
532 */
533int /* error */
693fc8f6 534xfs_dir3_data_init(
2bd0ea18
NS
535 xfs_da_args_t *args, /* directory operation args */
536 xfs_dir2_db_t blkno, /* logical dir block number */
a2ceac1f 537 struct xfs_buf **bpp) /* output block buffer */
2bd0ea18 538{
a2ceac1f
DC
539 struct xfs_buf *bp; /* block buffer */
540 xfs_dir2_data_hdr_t *hdr; /* data block header */
2bd0ea18
NS
541 xfs_inode_t *dp; /* incore directory inode */
542 xfs_dir2_data_unused_t *dup; /* unused entry pointer */
693fc8f6 543 struct xfs_dir2_data_free *bf;
2bd0ea18
NS
544 int error; /* error return value */
545 int i; /* bestfree index */
546 xfs_mount_t *mp; /* filesystem mount point */
547 xfs_trans_t *tp; /* transaction pointer */
dfc130f3 548 int t; /* temp */
2bd0ea18
NS
549
550 dp = args->dp;
551 mp = dp->i_mount;
552 tp = args->trans;
553 /*
554 * Get the buffer set up for the block.
555 */
5e656dbb 556 error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
2bd0ea18 557 XFS_DATA_FORK);
a2ceac1f 558 if (error)
2bd0ea18 559 return error;
90ea28c3 560 bp->b_ops = &xfs_dir3_data_buf_ops;
8b4dc4a9 561 xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_DATA_BUF);
a2ceac1f 562
2bd0ea18
NS
563 /*
564 * Initialize the header.
565 */
a2ceac1f 566 hdr = bp->b_addr;
693fc8f6
DC
567 if (xfs_sb_version_hascrc(&mp->m_sb)) {
568 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
569
570 memset(hdr3, 0, sizeof(*hdr3));
571 hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
572 hdr3->blkno = cpu_to_be64(bp->b_bn);
573 hdr3->owner = cpu_to_be64(dp->i_ino);
574 uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
575
576 } else
577 hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
578
579 bf = xfs_dir3_data_bestfree_p(hdr);
580 bf[0].offset = cpu_to_be16(xfs_dir3_data_entry_offset(hdr));
2bd0ea18 581 for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
693fc8f6
DC
582 bf[i].length = 0;
583 bf[i].offset = 0;
5000d01d 584 }
a2ceac1f 585
2bd0ea18
NS
586 /*
587 * Set up an unused entry for the block's body.
588 */
693fc8f6 589 dup = xfs_dir3_data_unused_p(hdr);
5e656dbb 590 dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
5000d01d 591
693fc8f6
DC
592 t = mp->m_dirblksize - (uint)xfs_dir3_data_entry_offset(hdr);
593 bf[0].length = cpu_to_be16(t);
5e656dbb 594 dup->length = cpu_to_be16(t);
a2ceac1f 595 *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
2bd0ea18
NS
596 /*
597 * Log it and return it.
598 */
599 xfs_dir2_data_log_header(tp, bp);
600 xfs_dir2_data_log_unused(tp, bp, dup);
601 *bpp = bp;
602 return 0;
603}
604
605/*
606 * Log an active data entry from the block.
607 */
608void
609xfs_dir2_data_log_entry(
a2ceac1f
DC
610 struct xfs_trans *tp,
611 struct xfs_buf *bp,
2bd0ea18
NS
612 xfs_dir2_data_entry_t *dep) /* data entry pointer */
613{
a2ceac1f
DC
614 xfs_dir2_data_hdr_t *hdr = bp->b_addr;
615
616 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 617 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
618 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
619 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
2bd0ea18 620
a2ceac1f 621 xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
5e656dbb 622 (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
a2ceac1f 623 (char *)hdr - 1));
2bd0ea18
NS
624}
625
626/*
627 * Log a data block header.
628 */
629void
630xfs_dir2_data_log_header(
a2ceac1f
DC
631 struct xfs_trans *tp,
632 struct xfs_buf *bp)
2bd0ea18 633{
a2ceac1f
DC
634 xfs_dir2_data_hdr_t *hdr = bp->b_addr;
635
636 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 637 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
638 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
639 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
2bd0ea18 640
693fc8f6 641 xfs_trans_log_buf(tp, bp, 0, xfs_dir3_data_entry_offset(hdr) - 1);
2bd0ea18
NS
642}
643
644/*
645 * Log a data unused entry.
646 */
647void
648xfs_dir2_data_log_unused(
a2ceac1f
DC
649 struct xfs_trans *tp,
650 struct xfs_buf *bp,
2bd0ea18
NS
651 xfs_dir2_data_unused_t *dup) /* data unused pointer */
652{
a2ceac1f
DC
653 xfs_dir2_data_hdr_t *hdr = bp->b_addr;
654
655 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 656 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
657 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
658 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
2bd0ea18 659
2bd0ea18
NS
660 /*
661 * Log the first part of the unused entry.
662 */
a2ceac1f 663 xfs_trans_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
2bd0ea18 664 (uint)((char *)&dup->length + sizeof(dup->length) -
a2ceac1f 665 1 - (char *)hdr));
2bd0ea18
NS
666 /*
667 * Log the end (tag) of the unused entry.
668 */
a2ceac1f
DC
669 xfs_trans_log_buf(tp, bp,
670 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
671 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
2bd0ea18
NS
672 sizeof(xfs_dir2_data_off_t) - 1));
673}
674
675/*
676 * Make a byte range in the data block unused.
677 * Its current contents are unimportant.
678 */
679void
680xfs_dir2_data_make_free(
a2ceac1f
DC
681 struct xfs_trans *tp,
682 struct xfs_buf *bp,
2bd0ea18
NS
683 xfs_dir2_data_aoff_t offset, /* starting byte offset */
684 xfs_dir2_data_aoff_t len, /* length in bytes */
685 int *needlogp, /* out: log header */
686 int *needscanp) /* out: regen bestfree */
687{
a2ceac1f 688 xfs_dir2_data_hdr_t *hdr; /* data block pointer */
2bd0ea18
NS
689 xfs_dir2_data_free_t *dfp; /* bestfree pointer */
690 char *endptr; /* end of data area */
691 xfs_mount_t *mp; /* filesystem mount point */
692 int needscan; /* need to regen bestfree */
693 xfs_dir2_data_unused_t *newdup; /* new unused entry */
694 xfs_dir2_data_unused_t *postdup; /* unused entry after us */
695 xfs_dir2_data_unused_t *prevdup; /* unused entry before us */
693fc8f6 696 struct xfs_dir2_data_free *bf;
2bd0ea18
NS
697
698 mp = tp->t_mountp;
a2ceac1f
DC
699 hdr = bp->b_addr;
700
2bd0ea18
NS
701 /*
702 * Figure out where the end of the data area is.
703 */
90ea28c3
DC
704 if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
705 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC))
a2ceac1f 706 endptr = (char *)hdr + mp->m_dirblksize;
2bd0ea18
NS
707 else {
708 xfs_dir2_block_tail_t *btp; /* block tail */
709
693fc8f6
DC
710 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
711 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
a2ceac1f 712 btp = xfs_dir2_block_tail_p(mp, hdr);
5e656dbb 713 endptr = (char *)xfs_dir2_block_leaf_p(btp);
2bd0ea18
NS
714 }
715 /*
5000d01d 716 * If this isn't the start of the block, then back up to
2bd0ea18
NS
717 * the previous entry and see if it's free.
718 */
693fc8f6 719 if (offset > xfs_dir3_data_entry_offset(hdr)) {
5e656dbb 720 __be16 *tagp; /* tag just before us */
2bd0ea18 721
a2ceac1f
DC
722 tagp = (__be16 *)((char *)hdr + offset) - 1;
723 prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
5e656dbb 724 if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
2bd0ea18
NS
725 prevdup = NULL;
726 } else
727 prevdup = NULL;
728 /*
729 * If this isn't the end of the block, see if the entry after
730 * us is free.
731 */
a2ceac1f 732 if ((char *)hdr + offset + len < endptr) {
2bd0ea18 733 postdup =
a2ceac1f 734 (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
5e656dbb 735 if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
2bd0ea18
NS
736 postdup = NULL;
737 } else
738 postdup = NULL;
739 ASSERT(*needscanp == 0);
740 needscan = 0;
741 /*
5000d01d 742 * Previous and following entries are both free,
2bd0ea18
NS
743 * merge everything into a single free entry.
744 */
693fc8f6 745 bf = xfs_dir3_data_bestfree_p(hdr);
2bd0ea18
NS
746 if (prevdup && postdup) {
747 xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */
748
749 /*
750 * See if prevdup and/or postdup are in bestfree table.
751 */
a2ceac1f
DC
752 dfp = xfs_dir2_data_freefind(hdr, prevdup);
753 dfp2 = xfs_dir2_data_freefind(hdr, postdup);
2bd0ea18
NS
754 /*
755 * We need a rescan unless there are exactly 2 free entries
756 * namely our two. Then we know what's happening, otherwise
757 * since the third bestfree is there, there might be more
758 * entries.
759 */
693fc8f6 760 needscan = (bf[2].length != 0);
2bd0ea18
NS
761 /*
762 * Fix up the new big freespace.
763 */
5e656dbb
BN
764 be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
765 *xfs_dir2_data_unused_tag_p(prevdup) =
a2ceac1f 766 cpu_to_be16((char *)prevdup - (char *)hdr);
2bd0ea18
NS
767 xfs_dir2_data_log_unused(tp, bp, prevdup);
768 if (!needscan) {
769 /*
5000d01d 770 * Has to be the case that entries 0 and 1 are
2bd0ea18
NS
771 * dfp and dfp2 (don't know which is which), and
772 * entry 2 is empty.
773 * Remove entry 1 first then entry 0.
774 */
775 ASSERT(dfp && dfp2);
693fc8f6
DC
776 if (dfp == &bf[1]) {
777 dfp = &bf[0];
2bd0ea18 778 ASSERT(dfp2 == dfp);
693fc8f6 779 dfp2 = &bf[1];
2bd0ea18 780 }
a2ceac1f
DC
781 xfs_dir2_data_freeremove(hdr, dfp2, needlogp);
782 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
2bd0ea18
NS
783 /*
784 * Now insert the new entry.
785 */
a2ceac1f 786 dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
693fc8f6 787 ASSERT(dfp == &bf[0]);
5e656dbb 788 ASSERT(dfp->length == prevdup->length);
46eca962
NS
789 ASSERT(!dfp[1].length);
790 ASSERT(!dfp[2].length);
2bd0ea18
NS
791 }
792 }
793 /*
794 * The entry before us is free, merge with it.
795 */
796 else if (prevdup) {
a2ceac1f 797 dfp = xfs_dir2_data_freefind(hdr, prevdup);
5e656dbb
BN
798 be16_add_cpu(&prevdup->length, len);
799 *xfs_dir2_data_unused_tag_p(prevdup) =
a2ceac1f 800 cpu_to_be16((char *)prevdup - (char *)hdr);
2bd0ea18
NS
801 xfs_dir2_data_log_unused(tp, bp, prevdup);
802 /*
803 * If the previous entry was in the table, the new entry
804 * is longer, so it will be in the table too. Remove
805 * the old one and add the new one.
806 */
807 if (dfp) {
a2ceac1f
DC
808 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
809 xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
2bd0ea18
NS
810 }
811 /*
812 * Otherwise we need a scan if the new entry is big enough.
813 */
5e656dbb
BN
814 else {
815 needscan = be16_to_cpu(prevdup->length) >
693fc8f6 816 be16_to_cpu(bf[2].length);
5e656dbb 817 }
2bd0ea18
NS
818 }
819 /*
820 * The following entry is free, merge with it.
821 */
822 else if (postdup) {
a2ceac1f
DC
823 dfp = xfs_dir2_data_freefind(hdr, postdup);
824 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
5e656dbb
BN
825 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
826 newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
827 *xfs_dir2_data_unused_tag_p(newdup) =
a2ceac1f 828 cpu_to_be16((char *)newdup - (char *)hdr);
2bd0ea18
NS
829 xfs_dir2_data_log_unused(tp, bp, newdup);
830 /*
831 * If the following entry was in the table, the new entry
832 * is longer, so it will be in the table too. Remove
833 * the old one and add the new one.
834 */
835 if (dfp) {
a2ceac1f
DC
836 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
837 xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
2bd0ea18
NS
838 }
839 /*
840 * Otherwise we need a scan if the new entry is big enough.
841 */
5e656dbb
BN
842 else {
843 needscan = be16_to_cpu(newdup->length) >
693fc8f6 844 be16_to_cpu(bf[2].length);
5e656dbb 845 }
2bd0ea18
NS
846 }
847 /*
848 * Neither neighbor is free. Make a new entry.
849 */
850 else {
a2ceac1f 851 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
5e656dbb
BN
852 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
853 newdup->length = cpu_to_be16(len);
854 *xfs_dir2_data_unused_tag_p(newdup) =
a2ceac1f 855 cpu_to_be16((char *)newdup - (char *)hdr);
2bd0ea18 856 xfs_dir2_data_log_unused(tp, bp, newdup);
a2ceac1f 857 xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
2bd0ea18
NS
858 }
859 *needscanp = needscan;
860}
861
862/*
863 * Take a byte range out of an existing unused space and make it un-free.
864 */
865void
866xfs_dir2_data_use_free(
a2ceac1f
DC
867 struct xfs_trans *tp,
868 struct xfs_buf *bp,
2bd0ea18
NS
869 xfs_dir2_data_unused_t *dup, /* unused entry */
870 xfs_dir2_data_aoff_t offset, /* starting offset to use */
871 xfs_dir2_data_aoff_t len, /* length to use */
872 int *needlogp, /* out: need to log header */
873 int *needscanp) /* out: need regen bestfree */
874{
a2ceac1f 875 xfs_dir2_data_hdr_t *hdr; /* data block header */
2bd0ea18
NS
876 xfs_dir2_data_free_t *dfp; /* bestfree pointer */
877 int matchback; /* matches end of freespace */
878 int matchfront; /* matches start of freespace */
879 int needscan; /* need to regen bestfree */
880 xfs_dir2_data_unused_t *newdup; /* new unused entry */
881 xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
882 int oldlen; /* old unused entry's length */
693fc8f6 883 struct xfs_dir2_data_free *bf;
2bd0ea18 884
a2ceac1f
DC
885 hdr = bp->b_addr;
886 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
90ea28c3 887 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
693fc8f6
DC
888 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
889 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
5e656dbb 890 ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
a2ceac1f
DC
891 ASSERT(offset >= (char *)dup - (char *)hdr);
892 ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
893 ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
2bd0ea18
NS
894 /*
895 * Look up the entry in the bestfree table.
896 */
a2ceac1f 897 dfp = xfs_dir2_data_freefind(hdr, dup);
5e656dbb 898 oldlen = be16_to_cpu(dup->length);
693fc8f6
DC
899 bf = xfs_dir3_data_bestfree_p(hdr);
900 ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
2bd0ea18
NS
901 /*
902 * Check for alignment with front and back of the entry.
903 */
a2ceac1f
DC
904 matchfront = (char *)dup - (char *)hdr == offset;
905 matchback = (char *)dup + oldlen - (char *)hdr == offset + len;
2bd0ea18
NS
906 ASSERT(*needscanp == 0);
907 needscan = 0;
908 /*
909 * If we matched it exactly we just need to get rid of it from
910 * the bestfree table.
911 */
912 if (matchfront && matchback) {
913 if (dfp) {
693fc8f6 914 needscan = (bf[2].offset != 0);
2bd0ea18 915 if (!needscan)
a2ceac1f 916 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
2bd0ea18
NS
917 }
918 }
919 /*
920 * We match the first part of the entry.
921 * Make a new entry with the remaining freespace.
922 */
923 else if (matchfront) {
a2ceac1f 924 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
5e656dbb
BN
925 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
926 newdup->length = cpu_to_be16(oldlen - len);
927 *xfs_dir2_data_unused_tag_p(newdup) =
a2ceac1f 928 cpu_to_be16((char *)newdup - (char *)hdr);
2bd0ea18
NS
929 xfs_dir2_data_log_unused(tp, bp, newdup);
930 /*
931 * If it was in the table, remove it and add the new one.
932 */
933 if (dfp) {
a2ceac1f
DC
934 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
935 dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
2bd0ea18 936 ASSERT(dfp != NULL);
5e656dbb 937 ASSERT(dfp->length == newdup->length);
a2ceac1f 938 ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
2bd0ea18
NS
939 /*
940 * If we got inserted at the last slot,
941 * that means we don't know if there was a better
942 * choice for the last slot, or not. Rescan.
943 */
693fc8f6 944 needscan = dfp == &bf[2];
2bd0ea18
NS
945 }
946 }
947 /*
948 * We match the last part of the entry.
949 * Trim the allocated space off the tail of the entry.
950 */
951 else if (matchback) {
952 newdup = dup;
a2ceac1f 953 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
5e656dbb 954 *xfs_dir2_data_unused_tag_p(newdup) =
a2ceac1f 955 cpu_to_be16((char *)newdup - (char *)hdr);
2bd0ea18
NS
956 xfs_dir2_data_log_unused(tp, bp, newdup);
957 /*
958 * If it was in the table, remove it and add the new one.
959 */
960 if (dfp) {
a2ceac1f
DC
961 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
962 dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
2bd0ea18 963 ASSERT(dfp != NULL);
5e656dbb 964 ASSERT(dfp->length == newdup->length);
a2ceac1f 965 ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
2bd0ea18
NS
966 /*
967 * If we got inserted at the last slot,
968 * that means we don't know if there was a better
969 * choice for the last slot, or not. Rescan.
970 */
693fc8f6 971 needscan = dfp == &bf[2];
2bd0ea18
NS
972 }
973 }
974 /*
975 * Poking out the middle of an entry.
976 * Make two new entries.
977 */
978 else {
979 newdup = dup;
a2ceac1f 980 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
5e656dbb 981 *xfs_dir2_data_unused_tag_p(newdup) =
a2ceac1f 982 cpu_to_be16((char *)newdup - (char *)hdr);
2bd0ea18 983 xfs_dir2_data_log_unused(tp, bp, newdup);
a2ceac1f 984 newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
5e656dbb
BN
985 newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
986 newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
987 *xfs_dir2_data_unused_tag_p(newdup2) =
a2ceac1f 988 cpu_to_be16((char *)newdup2 - (char *)hdr);
2bd0ea18
NS
989 xfs_dir2_data_log_unused(tp, bp, newdup2);
990 /*
991 * If the old entry was in the table, we need to scan
992 * if the 3rd entry was valid, since these entries
993 * are smaller than the old one.
994 * If we don't need to scan that means there were 1 or 2
995 * entries in the table, and removing the old and adding
996 * the 2 new will work.
997 */
998 if (dfp) {
693fc8f6 999 needscan = (bf[2].length != 0);
2bd0ea18 1000 if (!needscan) {
a2ceac1f
DC
1001 xfs_dir2_data_freeremove(hdr, dfp, needlogp);
1002 xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
1003 xfs_dir2_data_freeinsert(hdr, newdup2,
1004 needlogp);
2bd0ea18
NS
1005 }
1006 }
1007 }
1008 *needscanp = needscan;
1009}