0001
0002
0003
0004
0005
0006
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_shared.h"
0010 #include "xfs_format.h"
0011 #include "xfs_log_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_dir2.h"
0016 #include "xfs_dir2_priv.h"
0017 #include "xfs_error.h"
0018 #include "xfs_trans.h"
0019 #include "xfs_buf_item.h"
0020 #include "xfs_log.h"
0021
0022 static xfs_failaddr_t xfs_dir2_data_freefind_verify(
0023 struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
0024 struct xfs_dir2_data_unused *dup,
0025 struct xfs_dir2_data_free **bf_ent);
0026
0027 struct xfs_dir2_data_free *
0028 xfs_dir2_data_bestfree_p(
0029 struct xfs_mount *mp,
0030 struct xfs_dir2_data_hdr *hdr)
0031 {
0032 if (xfs_has_crc(mp))
0033 return ((struct xfs_dir3_data_hdr *)hdr)->best_free;
0034 return hdr->bestfree;
0035 }
0036
0037
0038
0039
0040 __be16 *
0041 xfs_dir2_data_entry_tag_p(
0042 struct xfs_mount *mp,
0043 struct xfs_dir2_data_entry *dep)
0044 {
0045 return (__be16 *)((char *)dep +
0046 xfs_dir2_data_entsize(mp, dep->namelen) - sizeof(__be16));
0047 }
0048
0049 uint8_t
0050 xfs_dir2_data_get_ftype(
0051 struct xfs_mount *mp,
0052 struct xfs_dir2_data_entry *dep)
0053 {
0054 if (xfs_has_ftype(mp)) {
0055 uint8_t ftype = dep->name[dep->namelen];
0056
0057 if (likely(ftype < XFS_DIR3_FT_MAX))
0058 return ftype;
0059 }
0060
0061 return XFS_DIR3_FT_UNKNOWN;
0062 }
0063
0064 void
0065 xfs_dir2_data_put_ftype(
0066 struct xfs_mount *mp,
0067 struct xfs_dir2_data_entry *dep,
0068 uint8_t ftype)
0069 {
0070 ASSERT(ftype < XFS_DIR3_FT_MAX);
0071 ASSERT(dep->namelen != 0);
0072
0073 if (xfs_has_ftype(mp))
0074 dep->name[dep->namelen] = ftype;
0075 }
0076
0077
0078
0079
0080
0081
0082
0083 static inline unsigned int
0084 xfs_dir2_data_max_leaf_entries(
0085 struct xfs_da_geometry *geo)
0086 {
0087 return (geo->blksize - sizeof(struct xfs_dir2_block_tail) -
0088 geo->data_entry_offset) /
0089 sizeof(struct xfs_dir2_leaf_entry);
0090 }
0091
0092
0093
0094
0095
0096
0097 xfs_failaddr_t
0098 __xfs_dir3_data_check(
0099 struct xfs_inode *dp,
0100 struct xfs_buf *bp)
0101 {
0102 xfs_dir2_dataptr_t addr;
0103 xfs_dir2_data_free_t *bf;
0104 xfs_dir2_block_tail_t *btp=NULL;
0105 int count;
0106 xfs_dir2_data_hdr_t *hdr;
0107 xfs_dir2_data_free_t *dfp;
0108 int freeseen;
0109 xfs_dahash_t hash;
0110 int i;
0111 int lastfree;
0112 xfs_dir2_leaf_entry_t *lep=NULL;
0113 struct xfs_mount *mp = bp->b_mount;
0114 int stale;
0115 struct xfs_name name;
0116 unsigned int offset;
0117 unsigned int end;
0118 struct xfs_da_geometry *geo = mp->m_dir_geo;
0119
0120
0121
0122
0123 if (dp && !S_ISDIR(VFS_I(dp)->i_mode))
0124 return __this_address;
0125
0126 hdr = bp->b_addr;
0127 offset = geo->data_entry_offset;
0128
0129 switch (hdr->magic) {
0130 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
0131 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
0132 btp = xfs_dir2_block_tail_p(geo, hdr);
0133 lep = xfs_dir2_block_leaf_p(btp);
0134
0135 if (be32_to_cpu(btp->count) >=
0136 xfs_dir2_data_max_leaf_entries(geo))
0137 return __this_address;
0138 break;
0139 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
0140 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
0141 break;
0142 default:
0143 return __this_address;
0144 }
0145 end = xfs_dir3_data_end_offset(geo, hdr);
0146 if (!end)
0147 return __this_address;
0148
0149
0150
0151
0152 bf = xfs_dir2_data_bestfree_p(mp, hdr);
0153 count = lastfree = freeseen = 0;
0154 if (!bf[0].length) {
0155 if (bf[0].offset)
0156 return __this_address;
0157 freeseen |= 1 << 0;
0158 }
0159 if (!bf[1].length) {
0160 if (bf[1].offset)
0161 return __this_address;
0162 freeseen |= 1 << 1;
0163 }
0164 if (!bf[2].length) {
0165 if (bf[2].offset)
0166 return __this_address;
0167 freeseen |= 1 << 2;
0168 }
0169
0170 if (be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length))
0171 return __this_address;
0172 if (be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length))
0173 return __this_address;
0174
0175
0176
0177 while (offset < end) {
0178 struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
0179 struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
0180
0181
0182
0183
0184
0185
0186 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
0187 xfs_failaddr_t fa;
0188
0189 if (lastfree != 0)
0190 return __this_address;
0191 if (offset + be16_to_cpu(dup->length) > end)
0192 return __this_address;
0193 if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
0194 offset)
0195 return __this_address;
0196 fa = xfs_dir2_data_freefind_verify(hdr, bf, dup, &dfp);
0197 if (fa)
0198 return fa;
0199 if (dfp) {
0200 i = (int)(dfp - bf);
0201 if ((freeseen & (1 << i)) != 0)
0202 return __this_address;
0203 freeseen |= 1 << i;
0204 } else {
0205 if (be16_to_cpu(dup->length) >
0206 be16_to_cpu(bf[2].length))
0207 return __this_address;
0208 }
0209 offset += be16_to_cpu(dup->length);
0210 lastfree = 1;
0211 continue;
0212 }
0213
0214
0215
0216
0217
0218
0219 if (dep->namelen == 0)
0220 return __this_address;
0221 if (!xfs_verify_dir_ino(mp, be64_to_cpu(dep->inumber)))
0222 return __this_address;
0223 if (offset + xfs_dir2_data_entsize(mp, dep->namelen) > end)
0224 return __this_address;
0225 if (be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep)) != offset)
0226 return __this_address;
0227 if (xfs_dir2_data_get_ftype(mp, dep) >= XFS_DIR3_FT_MAX)
0228 return __this_address;
0229 count++;
0230 lastfree = 0;
0231 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0232 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
0233 addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
0234 (xfs_dir2_data_aoff_t)
0235 ((char *)dep - (char *)hdr));
0236 name.name = dep->name;
0237 name.len = dep->namelen;
0238 hash = xfs_dir2_hashname(mp, &name);
0239 for (i = 0; i < be32_to_cpu(btp->count); i++) {
0240 if (be32_to_cpu(lep[i].address) == addr &&
0241 be32_to_cpu(lep[i].hashval) == hash)
0242 break;
0243 }
0244 if (i >= be32_to_cpu(btp->count))
0245 return __this_address;
0246 }
0247 offset += xfs_dir2_data_entsize(mp, dep->namelen);
0248 }
0249
0250
0251
0252 if (freeseen != 7)
0253 return __this_address;
0254 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0255 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
0256 for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
0257 if (lep[i].address ==
0258 cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
0259 stale++;
0260 if (i > 0 && be32_to_cpu(lep[i].hashval) <
0261 be32_to_cpu(lep[i - 1].hashval))
0262 return __this_address;
0263 }
0264 if (count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale))
0265 return __this_address;
0266 if (stale != be32_to_cpu(btp->stale))
0267 return __this_address;
0268 }
0269 return NULL;
0270 }
0271
0272 #ifdef DEBUG
0273 void
0274 xfs_dir3_data_check(
0275 struct xfs_inode *dp,
0276 struct xfs_buf *bp)
0277 {
0278 xfs_failaddr_t fa;
0279
0280 fa = __xfs_dir3_data_check(dp, bp);
0281 if (!fa)
0282 return;
0283 xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount,
0284 bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__,
0285 fa);
0286 ASSERT(0);
0287 }
0288 #endif
0289
0290 static xfs_failaddr_t
0291 xfs_dir3_data_verify(
0292 struct xfs_buf *bp)
0293 {
0294 struct xfs_mount *mp = bp->b_mount;
0295 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
0296
0297 if (!xfs_verify_magic(bp, hdr3->magic))
0298 return __this_address;
0299
0300 if (xfs_has_crc(mp)) {
0301 if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
0302 return __this_address;
0303 if (be64_to_cpu(hdr3->blkno) != xfs_buf_daddr(bp))
0304 return __this_address;
0305 if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
0306 return __this_address;
0307 }
0308 return __xfs_dir3_data_check(NULL, bp);
0309 }
0310
0311
0312
0313
0314
0315
0316 static void
0317 xfs_dir3_data_reada_verify(
0318 struct xfs_buf *bp)
0319 {
0320 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
0321
0322 switch (hdr->magic) {
0323 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
0324 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
0325 bp->b_ops = &xfs_dir3_block_buf_ops;
0326 bp->b_ops->verify_read(bp);
0327 return;
0328 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
0329 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
0330 bp->b_ops = &xfs_dir3_data_buf_ops;
0331 bp->b_ops->verify_read(bp);
0332 return;
0333 default:
0334 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
0335 break;
0336 }
0337 }
0338
0339 static void
0340 xfs_dir3_data_read_verify(
0341 struct xfs_buf *bp)
0342 {
0343 struct xfs_mount *mp = bp->b_mount;
0344 xfs_failaddr_t fa;
0345
0346 if (xfs_has_crc(mp) &&
0347 !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF))
0348 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
0349 else {
0350 fa = xfs_dir3_data_verify(bp);
0351 if (fa)
0352 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0353 }
0354 }
0355
0356 static void
0357 xfs_dir3_data_write_verify(
0358 struct xfs_buf *bp)
0359 {
0360 struct xfs_mount *mp = bp->b_mount;
0361 struct xfs_buf_log_item *bip = bp->b_log_item;
0362 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
0363 xfs_failaddr_t fa;
0364
0365 fa = xfs_dir3_data_verify(bp);
0366 if (fa) {
0367 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0368 return;
0369 }
0370
0371 if (!xfs_has_crc(mp))
0372 return;
0373
0374 if (bip)
0375 hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn);
0376
0377 xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF);
0378 }
0379
0380 const struct xfs_buf_ops xfs_dir3_data_buf_ops = {
0381 .name = "xfs_dir3_data",
0382 .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC),
0383 cpu_to_be32(XFS_DIR3_DATA_MAGIC) },
0384 .verify_read = xfs_dir3_data_read_verify,
0385 .verify_write = xfs_dir3_data_write_verify,
0386 .verify_struct = xfs_dir3_data_verify,
0387 };
0388
0389 static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
0390 .name = "xfs_dir3_data_reada",
0391 .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC),
0392 cpu_to_be32(XFS_DIR3_DATA_MAGIC) },
0393 .verify_read = xfs_dir3_data_reada_verify,
0394 .verify_write = xfs_dir3_data_write_verify,
0395 };
0396
0397 static xfs_failaddr_t
0398 xfs_dir3_data_header_check(
0399 struct xfs_inode *dp,
0400 struct xfs_buf *bp)
0401 {
0402 struct xfs_mount *mp = dp->i_mount;
0403
0404 if (xfs_has_crc(mp)) {
0405 struct xfs_dir3_data_hdr *hdr3 = bp->b_addr;
0406
0407 if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
0408 return __this_address;
0409 }
0410
0411 return NULL;
0412 }
0413
0414 int
0415 xfs_dir3_data_read(
0416 struct xfs_trans *tp,
0417 struct xfs_inode *dp,
0418 xfs_dablk_t bno,
0419 unsigned int flags,
0420 struct xfs_buf **bpp)
0421 {
0422 xfs_failaddr_t fa;
0423 int err;
0424
0425 err = xfs_da_read_buf(tp, dp, bno, flags, bpp, XFS_DATA_FORK,
0426 &xfs_dir3_data_buf_ops);
0427 if (err || !*bpp)
0428 return err;
0429
0430
0431 fa = xfs_dir3_data_header_check(dp, *bpp);
0432 if (fa) {
0433 __xfs_buf_mark_corrupt(*bpp, fa);
0434 xfs_trans_brelse(tp, *bpp);
0435 *bpp = NULL;
0436 return -EFSCORRUPTED;
0437 }
0438
0439 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF);
0440 return err;
0441 }
0442
0443 int
0444 xfs_dir3_data_readahead(
0445 struct xfs_inode *dp,
0446 xfs_dablk_t bno,
0447 unsigned int flags)
0448 {
0449 return xfs_da_reada_buf(dp, bno, flags, XFS_DATA_FORK,
0450 &xfs_dir3_data_reada_buf_ops);
0451 }
0452
0453
0454
0455
0456
0457 static xfs_failaddr_t
0458 xfs_dir2_data_freefind_verify(
0459 struct xfs_dir2_data_hdr *hdr,
0460 struct xfs_dir2_data_free *bf,
0461 struct xfs_dir2_data_unused *dup,
0462 struct xfs_dir2_data_free **bf_ent)
0463 {
0464 struct xfs_dir2_data_free *dfp;
0465 xfs_dir2_data_aoff_t off;
0466 bool matched = false;
0467 bool seenzero = false;
0468
0469 *bf_ent = NULL;
0470 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
0471
0472
0473
0474
0475
0476
0477 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
0478 if (!dfp->offset) {
0479 if (dfp->length)
0480 return __this_address;
0481 seenzero = true;
0482 continue;
0483 }
0484 if (seenzero)
0485 return __this_address;
0486 if (be16_to_cpu(dfp->offset) == off) {
0487 matched = true;
0488 if (dfp->length != dup->length)
0489 return __this_address;
0490 } else if (be16_to_cpu(dfp->offset) > off) {
0491 if (off + be16_to_cpu(dup->length) >
0492 be16_to_cpu(dfp->offset))
0493 return __this_address;
0494 } else {
0495 if (be16_to_cpu(dfp->offset) +
0496 be16_to_cpu(dfp->length) > off)
0497 return __this_address;
0498 }
0499 if (!matched &&
0500 be16_to_cpu(dfp->length) < be16_to_cpu(dup->length))
0501 return __this_address;
0502 if (dfp > &bf[0] &&
0503 be16_to_cpu(dfp[-1].length) < be16_to_cpu(dfp[0].length))
0504 return __this_address;
0505 }
0506
0507
0508 *bf_ent = xfs_dir2_data_freefind(hdr, bf, dup);
0509 return NULL;
0510 }
0511
0512
0513
0514
0515
0516 xfs_dir2_data_free_t *
0517 xfs_dir2_data_freefind(
0518 struct xfs_dir2_data_hdr *hdr,
0519 struct xfs_dir2_data_free *bf,
0520 struct xfs_dir2_data_unused *dup)
0521 {
0522 xfs_dir2_data_free_t *dfp;
0523 xfs_dir2_data_aoff_t off;
0524
0525 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
0526
0527
0528
0529
0530
0531 if (be16_to_cpu(dup->length) <
0532 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
0533 return NULL;
0534
0535
0536
0537 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
0538 if (!dfp->offset)
0539 return NULL;
0540 if (be16_to_cpu(dfp->offset) == off)
0541 return dfp;
0542 }
0543
0544
0545
0546 return NULL;
0547 }
0548
0549
0550
0551
0552 xfs_dir2_data_free_t *
0553 xfs_dir2_data_freeinsert(
0554 struct xfs_dir2_data_hdr *hdr,
0555 struct xfs_dir2_data_free *dfp,
0556 struct xfs_dir2_data_unused *dup,
0557 int *loghead)
0558 {
0559 xfs_dir2_data_free_t new;
0560
0561 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0562 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0563 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0564 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0565
0566 new.length = dup->length;
0567 new.offset = cpu_to_be16((char *)dup - (char *)hdr);
0568
0569
0570
0571
0572 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
0573 dfp[2] = dfp[1];
0574 dfp[1] = dfp[0];
0575 dfp[0] = new;
0576 *loghead = 1;
0577 return &dfp[0];
0578 }
0579 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
0580 dfp[2] = dfp[1];
0581 dfp[1] = new;
0582 *loghead = 1;
0583 return &dfp[1];
0584 }
0585 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
0586 dfp[2] = new;
0587 *loghead = 1;
0588 return &dfp[2];
0589 }
0590 return NULL;
0591 }
0592
0593
0594
0595
0596 STATIC void
0597 xfs_dir2_data_freeremove(
0598 struct xfs_dir2_data_hdr *hdr,
0599 struct xfs_dir2_data_free *bf,
0600 struct xfs_dir2_data_free *dfp,
0601 int *loghead)
0602 {
0603
0604 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0605 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0606 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0607 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0608
0609
0610
0611
0612 if (dfp == &bf[0]) {
0613 bf[0] = bf[1];
0614 bf[1] = bf[2];
0615 }
0616
0617
0618
0619 else if (dfp == &bf[1])
0620 bf[1] = bf[2];
0621
0622
0623
0624 else
0625 ASSERT(dfp == &bf[2]);
0626
0627
0628
0629 bf[2].length = 0;
0630 bf[2].offset = 0;
0631 *loghead = 1;
0632 }
0633
0634
0635
0636
0637 void
0638 xfs_dir2_data_freescan(
0639 struct xfs_mount *mp,
0640 struct xfs_dir2_data_hdr *hdr,
0641 int *loghead)
0642 {
0643 struct xfs_da_geometry *geo = mp->m_dir_geo;
0644 struct xfs_dir2_data_free *bf = xfs_dir2_data_bestfree_p(mp, hdr);
0645 void *addr = hdr;
0646 unsigned int offset = geo->data_entry_offset;
0647 unsigned int end;
0648
0649 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0650 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0651 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0652 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0653
0654
0655
0656
0657 memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
0658 *loghead = 1;
0659
0660 end = xfs_dir3_data_end_offset(geo, addr);
0661 while (offset < end) {
0662 struct xfs_dir2_data_unused *dup = addr + offset;
0663 struct xfs_dir2_data_entry *dep = addr + offset;
0664
0665
0666
0667
0668 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
0669 ASSERT(offset ==
0670 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
0671 xfs_dir2_data_freeinsert(hdr, bf, dup, loghead);
0672 offset += be16_to_cpu(dup->length);
0673 continue;
0674 }
0675
0676
0677
0678
0679 ASSERT(offset ==
0680 be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep)));
0681 offset += xfs_dir2_data_entsize(mp, dep->namelen);
0682 }
0683 }
0684
0685
0686
0687
0688
0689 int
0690 xfs_dir3_data_init(
0691 struct xfs_da_args *args,
0692 xfs_dir2_db_t blkno,
0693 struct xfs_buf **bpp)
0694 {
0695 struct xfs_trans *tp = args->trans;
0696 struct xfs_inode *dp = args->dp;
0697 struct xfs_mount *mp = dp->i_mount;
0698 struct xfs_da_geometry *geo = args->geo;
0699 struct xfs_buf *bp;
0700 struct xfs_dir2_data_hdr *hdr;
0701 struct xfs_dir2_data_unused *dup;
0702 struct xfs_dir2_data_free *bf;
0703 int error;
0704 int i;
0705
0706
0707
0708
0709 error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
0710 &bp, XFS_DATA_FORK);
0711 if (error)
0712 return error;
0713 bp->b_ops = &xfs_dir3_data_buf_ops;
0714 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF);
0715
0716
0717
0718
0719 hdr = bp->b_addr;
0720 if (xfs_has_crc(mp)) {
0721 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
0722
0723 memset(hdr3, 0, sizeof(*hdr3));
0724 hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
0725 hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp));
0726 hdr3->owner = cpu_to_be64(dp->i_ino);
0727 uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
0728
0729 } else
0730 hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
0731
0732 bf = xfs_dir2_data_bestfree_p(mp, hdr);
0733 bf[0].offset = cpu_to_be16(geo->data_entry_offset);
0734 bf[0].length = cpu_to_be16(geo->blksize - geo->data_entry_offset);
0735 for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
0736 bf[i].length = 0;
0737 bf[i].offset = 0;
0738 }
0739
0740
0741
0742
0743 dup = bp->b_addr + geo->data_entry_offset;
0744 dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
0745 dup->length = bf[0].length;
0746 *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
0747
0748
0749
0750
0751 xfs_dir2_data_log_header(args, bp);
0752 xfs_dir2_data_log_unused(args, bp, dup);
0753 *bpp = bp;
0754 return 0;
0755 }
0756
0757
0758
0759
0760 void
0761 xfs_dir2_data_log_entry(
0762 struct xfs_da_args *args,
0763 struct xfs_buf *bp,
0764 xfs_dir2_data_entry_t *dep)
0765 {
0766 struct xfs_mount *mp = bp->b_mount;
0767 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
0768
0769 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0770 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0771 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0772 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0773
0774 xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr),
0775 (uint)((char *)(xfs_dir2_data_entry_tag_p(mp, dep) + 1) -
0776 (char *)hdr - 1));
0777 }
0778
0779
0780
0781
0782 void
0783 xfs_dir2_data_log_header(
0784 struct xfs_da_args *args,
0785 struct xfs_buf *bp)
0786 {
0787 #ifdef DEBUG
0788 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
0789
0790 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0791 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0792 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0793 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0794 #endif
0795
0796 xfs_trans_log_buf(args->trans, bp, 0, args->geo->data_entry_offset - 1);
0797 }
0798
0799
0800
0801
0802 void
0803 xfs_dir2_data_log_unused(
0804 struct xfs_da_args *args,
0805 struct xfs_buf *bp,
0806 xfs_dir2_data_unused_t *dup)
0807 {
0808 xfs_dir2_data_hdr_t *hdr = bp->b_addr;
0809
0810 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
0811 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
0812 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
0813 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
0814
0815
0816
0817
0818 xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr),
0819 (uint)((char *)&dup->length + sizeof(dup->length) -
0820 1 - (char *)hdr));
0821
0822
0823
0824 xfs_trans_log_buf(args->trans, bp,
0825 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
0826 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
0827 sizeof(xfs_dir2_data_off_t) - 1));
0828 }
0829
0830
0831
0832
0833
0834 void
0835 xfs_dir2_data_make_free(
0836 struct xfs_da_args *args,
0837 struct xfs_buf *bp,
0838 xfs_dir2_data_aoff_t offset,
0839 xfs_dir2_data_aoff_t len,
0840 int *needlogp,
0841 int *needscanp)
0842 {
0843 xfs_dir2_data_hdr_t *hdr;
0844 xfs_dir2_data_free_t *dfp;
0845 int needscan;
0846 xfs_dir2_data_unused_t *newdup;
0847 xfs_dir2_data_unused_t *postdup;
0848 xfs_dir2_data_unused_t *prevdup;
0849 unsigned int end;
0850 struct xfs_dir2_data_free *bf;
0851
0852 hdr = bp->b_addr;
0853
0854
0855
0856
0857 end = xfs_dir3_data_end_offset(args->geo, hdr);
0858 ASSERT(end != 0);
0859
0860
0861
0862
0863
0864 if (offset > args->geo->data_entry_offset) {
0865 __be16 *tagp;
0866
0867 tagp = (__be16 *)((char *)hdr + offset) - 1;
0868 prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
0869 if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
0870 prevdup = NULL;
0871 } else
0872 prevdup = NULL;
0873
0874
0875
0876
0877 if (offset + len < end) {
0878 postdup =
0879 (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
0880 if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
0881 postdup = NULL;
0882 } else
0883 postdup = NULL;
0884 ASSERT(*needscanp == 0);
0885 needscan = 0;
0886
0887
0888
0889
0890 bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr);
0891 if (prevdup && postdup) {
0892 xfs_dir2_data_free_t *dfp2;
0893
0894
0895
0896
0897 dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
0898 dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup);
0899
0900
0901
0902
0903
0904
0905 needscan = (bf[2].length != 0);
0906
0907
0908
0909 be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
0910 *xfs_dir2_data_unused_tag_p(prevdup) =
0911 cpu_to_be16((char *)prevdup - (char *)hdr);
0912 xfs_dir2_data_log_unused(args, bp, prevdup);
0913 if (!needscan) {
0914
0915
0916
0917
0918
0919
0920 ASSERT(dfp && dfp2);
0921 if (dfp == &bf[1]) {
0922 dfp = &bf[0];
0923 ASSERT(dfp2 == dfp);
0924 dfp2 = &bf[1];
0925 }
0926 xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp);
0927 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
0928
0929
0930
0931 dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup,
0932 needlogp);
0933 ASSERT(dfp == &bf[0]);
0934 ASSERT(dfp->length == prevdup->length);
0935 ASSERT(!dfp[1].length);
0936 ASSERT(!dfp[2].length);
0937 }
0938 }
0939
0940
0941
0942 else if (prevdup) {
0943 dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
0944 be16_add_cpu(&prevdup->length, len);
0945 *xfs_dir2_data_unused_tag_p(prevdup) =
0946 cpu_to_be16((char *)prevdup - (char *)hdr);
0947 xfs_dir2_data_log_unused(args, bp, prevdup);
0948
0949
0950
0951
0952
0953 if (dfp) {
0954 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
0955 xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp);
0956 }
0957
0958
0959
0960 else {
0961 needscan = be16_to_cpu(prevdup->length) >
0962 be16_to_cpu(bf[2].length);
0963 }
0964 }
0965
0966
0967
0968 else if (postdup) {
0969 dfp = xfs_dir2_data_freefind(hdr, bf, postdup);
0970 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
0971 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
0972 newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
0973 *xfs_dir2_data_unused_tag_p(newdup) =
0974 cpu_to_be16((char *)newdup - (char *)hdr);
0975 xfs_dir2_data_log_unused(args, bp, newdup);
0976
0977
0978
0979
0980
0981 if (dfp) {
0982 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
0983 xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
0984 }
0985
0986
0987
0988 else {
0989 needscan = be16_to_cpu(newdup->length) >
0990 be16_to_cpu(bf[2].length);
0991 }
0992 }
0993
0994
0995
0996 else {
0997 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
0998 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
0999 newdup->length = cpu_to_be16(len);
1000 *xfs_dir2_data_unused_tag_p(newdup) =
1001 cpu_to_be16((char *)newdup - (char *)hdr);
1002 xfs_dir2_data_log_unused(args, bp, newdup);
1003 xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
1004 }
1005 *needscanp = needscan;
1006 }
1007
1008
1009 static inline xfs_failaddr_t
1010 xfs_dir2_data_check_free(
1011 struct xfs_dir2_data_hdr *hdr,
1012 struct xfs_dir2_data_unused *dup,
1013 xfs_dir2_data_aoff_t offset,
1014 xfs_dir2_data_aoff_t len)
1015 {
1016 if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) &&
1017 hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) &&
1018 hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) &&
1019 hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
1020 return __this_address;
1021 if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG)
1022 return __this_address;
1023 if (offset < (char *)dup - (char *)hdr)
1024 return __this_address;
1025 if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr)
1026 return __this_address;
1027 if ((char *)dup - (char *)hdr !=
1028 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)))
1029 return __this_address;
1030 return NULL;
1031 }
1032
1033
1034 static inline xfs_failaddr_t
1035 xfs_dir2_data_check_new_free(
1036 struct xfs_dir2_data_hdr *hdr,
1037 struct xfs_dir2_data_free *dfp,
1038 struct xfs_dir2_data_unused *newdup)
1039 {
1040 if (dfp == NULL)
1041 return __this_address;
1042 if (dfp->length != newdup->length)
1043 return __this_address;
1044 if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr)
1045 return __this_address;
1046 return NULL;
1047 }
1048
1049
1050
1051
1052 int
1053 xfs_dir2_data_use_free(
1054 struct xfs_da_args *args,
1055 struct xfs_buf *bp,
1056 xfs_dir2_data_unused_t *dup,
1057 xfs_dir2_data_aoff_t offset,
1058 xfs_dir2_data_aoff_t len,
1059 int *needlogp,
1060 int *needscanp)
1061 {
1062 xfs_dir2_data_hdr_t *hdr;
1063 xfs_dir2_data_free_t *dfp;
1064 xfs_dir2_data_unused_t *newdup;
1065 xfs_dir2_data_unused_t *newdup2;
1066 struct xfs_dir2_data_free *bf;
1067 xfs_failaddr_t fa;
1068 int matchback;
1069 int matchfront;
1070 int needscan;
1071 int oldlen;
1072
1073 hdr = bp->b_addr;
1074 fa = xfs_dir2_data_check_free(hdr, dup, offset, len);
1075 if (fa)
1076 goto corrupt;
1077
1078
1079
1080 oldlen = be16_to_cpu(dup->length);
1081 bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr);
1082 dfp = xfs_dir2_data_freefind(hdr, bf, dup);
1083 ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
1084
1085
1086
1087 matchfront = (char *)dup - (char *)hdr == offset;
1088 matchback = (char *)dup + oldlen - (char *)hdr == offset + len;
1089 ASSERT(*needscanp == 0);
1090 needscan = 0;
1091
1092
1093
1094
1095 if (matchfront && matchback) {
1096 if (dfp) {
1097 needscan = (bf[2].offset != 0);
1098 if (!needscan)
1099 xfs_dir2_data_freeremove(hdr, bf, dfp,
1100 needlogp);
1101 }
1102 }
1103
1104
1105
1106
1107 else if (matchfront) {
1108 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
1109 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
1110 newdup->length = cpu_to_be16(oldlen - len);
1111 *xfs_dir2_data_unused_tag_p(newdup) =
1112 cpu_to_be16((char *)newdup - (char *)hdr);
1113 xfs_dir2_data_log_unused(args, bp, newdup);
1114
1115
1116
1117 if (dfp) {
1118 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
1119 dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
1120 needlogp);
1121 fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
1122 if (fa)
1123 goto corrupt;
1124
1125
1126
1127
1128
1129 needscan = dfp == &bf[2];
1130 }
1131 }
1132
1133
1134
1135
1136 else if (matchback) {
1137 newdup = dup;
1138 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
1139 *xfs_dir2_data_unused_tag_p(newdup) =
1140 cpu_to_be16((char *)newdup - (char *)hdr);
1141 xfs_dir2_data_log_unused(args, bp, newdup);
1142
1143
1144
1145 if (dfp) {
1146 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
1147 dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
1148 needlogp);
1149 fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
1150 if (fa)
1151 goto corrupt;
1152
1153
1154
1155
1156
1157 needscan = dfp == &bf[2];
1158 }
1159 }
1160
1161
1162
1163
1164 else {
1165 newdup = dup;
1166 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
1167 *xfs_dir2_data_unused_tag_p(newdup) =
1168 cpu_to_be16((char *)newdup - (char *)hdr);
1169 xfs_dir2_data_log_unused(args, bp, newdup);
1170 newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
1171 newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
1172 newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
1173 *xfs_dir2_data_unused_tag_p(newdup2) =
1174 cpu_to_be16((char *)newdup2 - (char *)hdr);
1175 xfs_dir2_data_log_unused(args, bp, newdup2);
1176
1177
1178
1179
1180
1181
1182
1183
1184 if (dfp) {
1185 needscan = (bf[2].length != 0);
1186 if (!needscan) {
1187 xfs_dir2_data_freeremove(hdr, bf, dfp,
1188 needlogp);
1189 xfs_dir2_data_freeinsert(hdr, bf, newdup,
1190 needlogp);
1191 xfs_dir2_data_freeinsert(hdr, bf, newdup2,
1192 needlogp);
1193 }
1194 }
1195 }
1196 *needscanp = needscan;
1197 return 0;
1198 corrupt:
1199 xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount,
1200 hdr, sizeof(*hdr), __FILE__, __LINE__, fa);
1201 return -EFSCORRUPTED;
1202 }
1203
1204
1205 unsigned int
1206 xfs_dir3_data_end_offset(
1207 struct xfs_da_geometry *geo,
1208 struct xfs_dir2_data_hdr *hdr)
1209 {
1210 void *p;
1211
1212 switch (hdr->magic) {
1213 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
1214 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
1215 p = xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr));
1216 return p - (void *)hdr;
1217 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
1218 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
1219 return geo->blksize;
1220 default:
1221 return 0;
1222 }
1223 }