0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_bit.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_sb.h"
0015 #include "xfs_defer.h"
0016 #include "xfs_btree.h"
0017 #include "xfs_trans.h"
0018 #include "xfs_alloc.h"
0019 #include "xfs_rmap.h"
0020 #include "xfs_rmap_btree.h"
0021 #include "xfs_trace.h"
0022 #include "xfs_errortag.h"
0023 #include "xfs_error.h"
0024 #include "xfs_inode.h"
0025 #include "xfs_ag.h"
0026
0027 struct kmem_cache *xfs_rmap_intent_cache;
0028
0029
0030
0031
0032
0033 int
0034 xfs_rmap_lookup_le(
0035 struct xfs_btree_cur *cur,
0036 xfs_agblock_t bno,
0037 uint64_t owner,
0038 uint64_t offset,
0039 unsigned int flags,
0040 struct xfs_rmap_irec *irec,
0041 int *stat)
0042 {
0043 int get_stat = 0;
0044 int error;
0045
0046 cur->bc_rec.r.rm_startblock = bno;
0047 cur->bc_rec.r.rm_blockcount = 0;
0048 cur->bc_rec.r.rm_owner = owner;
0049 cur->bc_rec.r.rm_offset = offset;
0050 cur->bc_rec.r.rm_flags = flags;
0051
0052 error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
0053 if (error || !(*stat) || !irec)
0054 return error;
0055
0056 error = xfs_rmap_get_rec(cur, irec, &get_stat);
0057 if (error)
0058 return error;
0059 if (!get_stat)
0060 return -EFSCORRUPTED;
0061
0062 return 0;
0063 }
0064
0065
0066
0067
0068
0069 int
0070 xfs_rmap_lookup_eq(
0071 struct xfs_btree_cur *cur,
0072 xfs_agblock_t bno,
0073 xfs_extlen_t len,
0074 uint64_t owner,
0075 uint64_t offset,
0076 unsigned int flags,
0077 int *stat)
0078 {
0079 cur->bc_rec.r.rm_startblock = bno;
0080 cur->bc_rec.r.rm_blockcount = len;
0081 cur->bc_rec.r.rm_owner = owner;
0082 cur->bc_rec.r.rm_offset = offset;
0083 cur->bc_rec.r.rm_flags = flags;
0084 return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
0085 }
0086
0087
0088
0089
0090
0091
0092 STATIC int
0093 xfs_rmap_update(
0094 struct xfs_btree_cur *cur,
0095 struct xfs_rmap_irec *irec)
0096 {
0097 union xfs_btree_rec rec;
0098 int error;
0099
0100 trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
0101 irec->rm_startblock, irec->rm_blockcount,
0102 irec->rm_owner, irec->rm_offset, irec->rm_flags);
0103
0104 rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
0105 rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
0106 rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
0107 rec.rmap.rm_offset = cpu_to_be64(
0108 xfs_rmap_irec_offset_pack(irec));
0109 error = xfs_btree_update(cur, &rec);
0110 if (error)
0111 trace_xfs_rmap_update_error(cur->bc_mp,
0112 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
0113 return error;
0114 }
0115
0116 int
0117 xfs_rmap_insert(
0118 struct xfs_btree_cur *rcur,
0119 xfs_agblock_t agbno,
0120 xfs_extlen_t len,
0121 uint64_t owner,
0122 uint64_t offset,
0123 unsigned int flags)
0124 {
0125 int i;
0126 int error;
0127
0128 trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
0129 len, owner, offset, flags);
0130
0131 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
0132 if (error)
0133 goto done;
0134 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
0135 error = -EFSCORRUPTED;
0136 goto done;
0137 }
0138
0139 rcur->bc_rec.r.rm_startblock = agbno;
0140 rcur->bc_rec.r.rm_blockcount = len;
0141 rcur->bc_rec.r.rm_owner = owner;
0142 rcur->bc_rec.r.rm_offset = offset;
0143 rcur->bc_rec.r.rm_flags = flags;
0144 error = xfs_btree_insert(rcur, &i);
0145 if (error)
0146 goto done;
0147 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
0148 error = -EFSCORRUPTED;
0149 goto done;
0150 }
0151 done:
0152 if (error)
0153 trace_xfs_rmap_insert_error(rcur->bc_mp,
0154 rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
0155 return error;
0156 }
0157
0158 STATIC int
0159 xfs_rmap_delete(
0160 struct xfs_btree_cur *rcur,
0161 xfs_agblock_t agbno,
0162 xfs_extlen_t len,
0163 uint64_t owner,
0164 uint64_t offset,
0165 unsigned int flags)
0166 {
0167 int i;
0168 int error;
0169
0170 trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
0171 len, owner, offset, flags);
0172
0173 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
0174 if (error)
0175 goto done;
0176 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
0177 error = -EFSCORRUPTED;
0178 goto done;
0179 }
0180
0181 error = xfs_btree_delete(rcur, &i);
0182 if (error)
0183 goto done;
0184 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
0185 error = -EFSCORRUPTED;
0186 goto done;
0187 }
0188 done:
0189 if (error)
0190 trace_xfs_rmap_delete_error(rcur->bc_mp,
0191 rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
0192 return error;
0193 }
0194
0195
0196 int
0197 xfs_rmap_btrec_to_irec(
0198 const union xfs_btree_rec *rec,
0199 struct xfs_rmap_irec *irec)
0200 {
0201 irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
0202 irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
0203 irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
0204 return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
0205 irec);
0206 }
0207
0208
0209
0210
0211 int
0212 xfs_rmap_get_rec(
0213 struct xfs_btree_cur *cur,
0214 struct xfs_rmap_irec *irec,
0215 int *stat)
0216 {
0217 struct xfs_mount *mp = cur->bc_mp;
0218 struct xfs_perag *pag = cur->bc_ag.pag;
0219 union xfs_btree_rec *rec;
0220 int error;
0221
0222 error = xfs_btree_get_rec(cur, &rec, stat);
0223 if (error || !*stat)
0224 return error;
0225
0226 if (xfs_rmap_btrec_to_irec(rec, irec))
0227 goto out_bad_rec;
0228
0229 if (irec->rm_blockcount == 0)
0230 goto out_bad_rec;
0231 if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
0232 if (irec->rm_owner != XFS_RMAP_OWN_FS)
0233 goto out_bad_rec;
0234 if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
0235 goto out_bad_rec;
0236 } else {
0237
0238 if (!xfs_verify_agbno(pag, irec->rm_startblock))
0239 goto out_bad_rec;
0240 if (irec->rm_startblock >
0241 irec->rm_startblock + irec->rm_blockcount)
0242 goto out_bad_rec;
0243 if (!xfs_verify_agbno(pag,
0244 irec->rm_startblock + irec->rm_blockcount - 1))
0245 goto out_bad_rec;
0246 }
0247
0248 if (!(xfs_verify_ino(mp, irec->rm_owner) ||
0249 (irec->rm_owner <= XFS_RMAP_OWN_FS &&
0250 irec->rm_owner >= XFS_RMAP_OWN_MIN)))
0251 goto out_bad_rec;
0252
0253 return 0;
0254 out_bad_rec:
0255 xfs_warn(mp,
0256 "Reverse Mapping BTree record corruption in AG %d detected!",
0257 pag->pag_agno);
0258 xfs_warn(mp,
0259 "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
0260 irec->rm_owner, irec->rm_flags, irec->rm_startblock,
0261 irec->rm_blockcount);
0262 return -EFSCORRUPTED;
0263 }
0264
0265 struct xfs_find_left_neighbor_info {
0266 struct xfs_rmap_irec high;
0267 struct xfs_rmap_irec *irec;
0268 };
0269
0270
0271 STATIC int
0272 xfs_rmap_find_left_neighbor_helper(
0273 struct xfs_btree_cur *cur,
0274 const struct xfs_rmap_irec *rec,
0275 void *priv)
0276 {
0277 struct xfs_find_left_neighbor_info *info = priv;
0278
0279 trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
0280 cur->bc_ag.pag->pag_agno, rec->rm_startblock,
0281 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
0282 rec->rm_flags);
0283
0284 if (rec->rm_owner != info->high.rm_owner)
0285 return 0;
0286 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
0287 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
0288 rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
0289 return 0;
0290
0291 *info->irec = *rec;
0292 return -ECANCELED;
0293 }
0294
0295
0296
0297
0298
0299
0300 STATIC int
0301 xfs_rmap_find_left_neighbor(
0302 struct xfs_btree_cur *cur,
0303 xfs_agblock_t bno,
0304 uint64_t owner,
0305 uint64_t offset,
0306 unsigned int flags,
0307 struct xfs_rmap_irec *irec,
0308 int *stat)
0309 {
0310 struct xfs_find_left_neighbor_info info;
0311 int found = 0;
0312 int error;
0313
0314 *stat = 0;
0315 if (bno == 0)
0316 return 0;
0317 info.high.rm_startblock = bno - 1;
0318 info.high.rm_owner = owner;
0319 if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
0320 !(flags & XFS_RMAP_BMBT_BLOCK)) {
0321 if (offset == 0)
0322 return 0;
0323 info.high.rm_offset = offset - 1;
0324 } else
0325 info.high.rm_offset = 0;
0326 info.high.rm_flags = flags;
0327 info.high.rm_blockcount = 0;
0328 info.irec = irec;
0329
0330 trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
0331 cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
0350 &found);
0351 if (error)
0352 return error;
0353 if (found)
0354 error = xfs_rmap_find_left_neighbor_helper(cur, irec, &info);
0355 if (!error)
0356 error = xfs_rmap_query_range(cur, &info.high, &info.high,
0357 xfs_rmap_find_left_neighbor_helper, &info);
0358 if (error != -ECANCELED)
0359 return error;
0360
0361 *stat = 1;
0362 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
0363 cur->bc_ag.pag->pag_agno, irec->rm_startblock,
0364 irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
0365 irec->rm_flags);
0366 return 0;
0367 }
0368
0369
0370 STATIC int
0371 xfs_rmap_lookup_le_range_helper(
0372 struct xfs_btree_cur *cur,
0373 const struct xfs_rmap_irec *rec,
0374 void *priv)
0375 {
0376 struct xfs_find_left_neighbor_info *info = priv;
0377
0378 trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
0379 cur->bc_ag.pag->pag_agno, rec->rm_startblock,
0380 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
0381 rec->rm_flags);
0382
0383 if (rec->rm_owner != info->high.rm_owner)
0384 return 0;
0385 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
0386 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
0387 (rec->rm_offset > info->high.rm_offset ||
0388 rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
0389 return 0;
0390
0391 *info->irec = *rec;
0392 return -ECANCELED;
0393 }
0394
0395
0396
0397
0398
0399
0400
0401 int
0402 xfs_rmap_lookup_le_range(
0403 struct xfs_btree_cur *cur,
0404 xfs_agblock_t bno,
0405 uint64_t owner,
0406 uint64_t offset,
0407 unsigned int flags,
0408 struct xfs_rmap_irec *irec,
0409 int *stat)
0410 {
0411 struct xfs_find_left_neighbor_info info;
0412 int found = 0;
0413 int error;
0414
0415 info.high.rm_startblock = bno;
0416 info.high.rm_owner = owner;
0417 if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
0418 info.high.rm_offset = offset;
0419 else
0420 info.high.rm_offset = 0;
0421 info.high.rm_flags = flags;
0422 info.high.rm_blockcount = 0;
0423 *stat = 0;
0424 info.irec = irec;
0425
0426 trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
0427 bno, 0, owner, offset, flags);
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
0446 &found);
0447 if (error)
0448 return error;
0449 if (found)
0450 error = xfs_rmap_lookup_le_range_helper(cur, irec, &info);
0451 if (!error)
0452 error = xfs_rmap_query_range(cur, &info.high, &info.high,
0453 xfs_rmap_lookup_le_range_helper, &info);
0454 if (error != -ECANCELED)
0455 return error;
0456
0457 *stat = 1;
0458 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
0459 cur->bc_ag.pag->pag_agno, irec->rm_startblock,
0460 irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
0461 irec->rm_flags);
0462 return 0;
0463 }
0464
0465
0466
0467
0468
0469 static int
0470 xfs_rmap_free_check_owner(
0471 struct xfs_mount *mp,
0472 uint64_t ltoff,
0473 struct xfs_rmap_irec *rec,
0474 xfs_filblks_t len,
0475 uint64_t owner,
0476 uint64_t offset,
0477 unsigned int flags)
0478 {
0479 int error = 0;
0480
0481 if (owner == XFS_RMAP_OWN_UNKNOWN)
0482 return 0;
0483
0484
0485 if (XFS_IS_CORRUPT(mp,
0486 (flags & XFS_RMAP_UNWRITTEN) !=
0487 (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
0488 error = -EFSCORRUPTED;
0489 goto out;
0490 }
0491
0492
0493 if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
0494 error = -EFSCORRUPTED;
0495 goto out;
0496 }
0497
0498
0499 if (XFS_RMAP_NON_INODE_OWNER(owner))
0500 goto out;
0501
0502 if (flags & XFS_RMAP_BMBT_BLOCK) {
0503 if (XFS_IS_CORRUPT(mp,
0504 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
0505 error = -EFSCORRUPTED;
0506 goto out;
0507 }
0508 } else {
0509 if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
0510 error = -EFSCORRUPTED;
0511 goto out;
0512 }
0513 if (XFS_IS_CORRUPT(mp,
0514 offset + len > ltoff + rec->rm_blockcount)) {
0515 error = -EFSCORRUPTED;
0516 goto out;
0517 }
0518 }
0519
0520 out:
0521 return error;
0522 }
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542 STATIC int
0543 xfs_rmap_unmap(
0544 struct xfs_btree_cur *cur,
0545 xfs_agblock_t bno,
0546 xfs_extlen_t len,
0547 bool unwritten,
0548 const struct xfs_owner_info *oinfo)
0549 {
0550 struct xfs_mount *mp = cur->bc_mp;
0551 struct xfs_rmap_irec ltrec;
0552 uint64_t ltoff;
0553 int error = 0;
0554 int i;
0555 uint64_t owner;
0556 uint64_t offset;
0557 unsigned int flags;
0558 bool ignore_off;
0559
0560 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
0561 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
0562 (flags & XFS_RMAP_BMBT_BLOCK);
0563 if (unwritten)
0564 flags |= XFS_RMAP_UNWRITTEN;
0565 trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
0566 unwritten, oinfo);
0567
0568
0569
0570
0571
0572
0573 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, <rec, &i);
0574 if (error)
0575 goto out_error;
0576 if (XFS_IS_CORRUPT(mp, i != 1)) {
0577 error = -EFSCORRUPTED;
0578 goto out_error;
0579 }
0580
0581 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
0582 cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
0583 ltrec.rm_blockcount, ltrec.rm_owner,
0584 ltrec.rm_offset, ltrec.rm_flags);
0585 ltoff = ltrec.rm_offset;
0586
0587
0588
0589
0590
0591
0592
0593
0594 if (owner == XFS_RMAP_OWN_NULL) {
0595 if (XFS_IS_CORRUPT(mp,
0596 bno <
0597 ltrec.rm_startblock + ltrec.rm_blockcount)) {
0598 error = -EFSCORRUPTED;
0599 goto out_error;
0600 }
0601 goto out_done;
0602 }
0603
0604
0605
0606
0607
0608
0609
0610
0611 if (owner == XFS_RMAP_OWN_UNKNOWN &&
0612 ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
0613 struct xfs_rmap_irec rtrec;
0614
0615 error = xfs_btree_increment(cur, 0, &i);
0616 if (error)
0617 goto out_error;
0618 if (i == 0)
0619 goto out_done;
0620 error = xfs_rmap_get_rec(cur, &rtrec, &i);
0621 if (error)
0622 goto out_error;
0623 if (XFS_IS_CORRUPT(mp, i != 1)) {
0624 error = -EFSCORRUPTED;
0625 goto out_error;
0626 }
0627 if (rtrec.rm_startblock >= bno + len)
0628 goto out_done;
0629 }
0630
0631
0632 if (XFS_IS_CORRUPT(mp,
0633 ltrec.rm_startblock > bno ||
0634 ltrec.rm_startblock + ltrec.rm_blockcount <
0635 bno + len)) {
0636 error = -EFSCORRUPTED;
0637 goto out_error;
0638 }
0639
0640
0641 error = xfs_rmap_free_check_owner(mp, ltoff, <rec, len, owner,
0642 offset, flags);
0643 if (error)
0644 goto out_error;
0645
0646 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
0647
0648 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
0649 ltrec.rm_startblock, ltrec.rm_blockcount,
0650 ltrec.rm_owner, ltrec.rm_offset,
0651 ltrec.rm_flags);
0652 error = xfs_btree_delete(cur, &i);
0653 if (error)
0654 goto out_error;
0655 if (XFS_IS_CORRUPT(mp, i != 1)) {
0656 error = -EFSCORRUPTED;
0657 goto out_error;
0658 }
0659 } else if (ltrec.rm_startblock == bno) {
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670 ltrec.rm_startblock += len;
0671 ltrec.rm_blockcount -= len;
0672 if (!ignore_off)
0673 ltrec.rm_offset += len;
0674 error = xfs_rmap_update(cur, <rec);
0675 if (error)
0676 goto out_error;
0677 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688 ltrec.rm_blockcount -= len;
0689 error = xfs_rmap_update(cur, <rec);
0690 if (error)
0691 goto out_error;
0692 } else {
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706 xfs_extlen_t orig_len = ltrec.rm_blockcount;
0707
0708 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
0709 error = xfs_rmap_update(cur, <rec);
0710 if (error)
0711 goto out_error;
0712
0713 error = xfs_btree_increment(cur, 0, &i);
0714 if (error)
0715 goto out_error;
0716
0717 cur->bc_rec.r.rm_startblock = bno + len;
0718 cur->bc_rec.r.rm_blockcount = orig_len - len -
0719 ltrec.rm_blockcount;
0720 cur->bc_rec.r.rm_owner = ltrec.rm_owner;
0721 if (ignore_off)
0722 cur->bc_rec.r.rm_offset = 0;
0723 else
0724 cur->bc_rec.r.rm_offset = offset + len;
0725 cur->bc_rec.r.rm_flags = flags;
0726 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
0727 cur->bc_rec.r.rm_startblock,
0728 cur->bc_rec.r.rm_blockcount,
0729 cur->bc_rec.r.rm_owner,
0730 cur->bc_rec.r.rm_offset,
0731 cur->bc_rec.r.rm_flags);
0732 error = xfs_btree_insert(cur, &i);
0733 if (error)
0734 goto out_error;
0735 }
0736
0737 out_done:
0738 trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
0739 unwritten, oinfo);
0740 out_error:
0741 if (error)
0742 trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
0743 error, _RET_IP_);
0744 return error;
0745 }
0746
0747
0748
0749
0750 int
0751 xfs_rmap_free(
0752 struct xfs_trans *tp,
0753 struct xfs_buf *agbp,
0754 struct xfs_perag *pag,
0755 xfs_agblock_t bno,
0756 xfs_extlen_t len,
0757 const struct xfs_owner_info *oinfo)
0758 {
0759 struct xfs_mount *mp = tp->t_mountp;
0760 struct xfs_btree_cur *cur;
0761 int error;
0762
0763 if (!xfs_has_rmapbt(mp))
0764 return 0;
0765
0766 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
0767
0768 error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
0769
0770 xfs_btree_del_cursor(cur, error);
0771 return error;
0772 }
0773
0774
0775
0776
0777
0778
0779 static bool
0780 xfs_rmap_is_mergeable(
0781 struct xfs_rmap_irec *irec,
0782 uint64_t owner,
0783 unsigned int flags)
0784 {
0785 if (irec->rm_owner == XFS_RMAP_OWN_NULL)
0786 return false;
0787 if (irec->rm_owner != owner)
0788 return false;
0789 if ((flags & XFS_RMAP_UNWRITTEN) ^
0790 (irec->rm_flags & XFS_RMAP_UNWRITTEN))
0791 return false;
0792 if ((flags & XFS_RMAP_ATTR_FORK) ^
0793 (irec->rm_flags & XFS_RMAP_ATTR_FORK))
0794 return false;
0795 if ((flags & XFS_RMAP_BMBT_BLOCK) ^
0796 (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
0797 return false;
0798 return true;
0799 }
0800
0801
0802
0803
0804
0805
0806
0807 STATIC int
0808 xfs_rmap_map(
0809 struct xfs_btree_cur *cur,
0810 xfs_agblock_t bno,
0811 xfs_extlen_t len,
0812 bool unwritten,
0813 const struct xfs_owner_info *oinfo)
0814 {
0815 struct xfs_mount *mp = cur->bc_mp;
0816 struct xfs_rmap_irec ltrec;
0817 struct xfs_rmap_irec gtrec;
0818 int have_gt;
0819 int have_lt;
0820 int error = 0;
0821 int i;
0822 uint64_t owner;
0823 uint64_t offset;
0824 unsigned int flags = 0;
0825 bool ignore_off;
0826
0827 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
0828 ASSERT(owner != 0);
0829 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
0830 (flags & XFS_RMAP_BMBT_BLOCK);
0831 if (unwritten)
0832 flags |= XFS_RMAP_UNWRITTEN;
0833 trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
0834 unwritten, oinfo);
0835 ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
0836
0837
0838
0839
0840
0841
0842 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, <rec,
0843 &have_lt);
0844 if (error)
0845 goto out_error;
0846 if (have_lt) {
0847 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
0848 cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
0849 ltrec.rm_blockcount, ltrec.rm_owner,
0850 ltrec.rm_offset, ltrec.rm_flags);
0851
0852 if (!xfs_rmap_is_mergeable(<rec, owner, flags))
0853 have_lt = 0;
0854 }
0855
0856 if (XFS_IS_CORRUPT(mp,
0857 have_lt != 0 &&
0858 ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
0859 error = -EFSCORRUPTED;
0860 goto out_error;
0861 }
0862
0863
0864
0865
0866
0867
0868 error = xfs_btree_increment(cur, 0, &have_gt);
0869 if (error)
0870 goto out_error;
0871 if (have_gt) {
0872 error = xfs_rmap_get_rec(cur, >rec, &have_gt);
0873 if (error)
0874 goto out_error;
0875 if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
0876 error = -EFSCORRUPTED;
0877 goto out_error;
0878 }
0879 if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
0880 error = -EFSCORRUPTED;
0881 goto out_error;
0882 }
0883 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
0884 cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
0885 gtrec.rm_blockcount, gtrec.rm_owner,
0886 gtrec.rm_offset, gtrec.rm_flags);
0887 if (!xfs_rmap_is_mergeable(>rec, owner, flags))
0888 have_gt = 0;
0889 }
0890
0891
0892
0893
0894
0895 if (have_lt &&
0896 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
0897 (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907 ltrec.rm_blockcount += len;
0908 if (have_gt &&
0909 bno + len == gtrec.rm_startblock &&
0910 (ignore_off || offset + len == gtrec.rm_offset) &&
0911 (unsigned long)ltrec.rm_blockcount + len +
0912 gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922 ltrec.rm_blockcount += gtrec.rm_blockcount;
0923 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
0924 gtrec.rm_startblock,
0925 gtrec.rm_blockcount,
0926 gtrec.rm_owner,
0927 gtrec.rm_offset,
0928 gtrec.rm_flags);
0929 error = xfs_btree_delete(cur, &i);
0930 if (error)
0931 goto out_error;
0932 if (XFS_IS_CORRUPT(mp, i != 1)) {
0933 error = -EFSCORRUPTED;
0934 goto out_error;
0935 }
0936 }
0937
0938
0939 error = xfs_btree_decrement(cur, 0, &have_gt);
0940 if (error)
0941 goto out_error;
0942 error = xfs_rmap_update(cur, <rec);
0943 if (error)
0944 goto out_error;
0945 } else if (have_gt &&
0946 bno + len == gtrec.rm_startblock &&
0947 (ignore_off || offset + len == gtrec.rm_offset)) {
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957 gtrec.rm_startblock = bno;
0958 gtrec.rm_blockcount += len;
0959 if (!ignore_off)
0960 gtrec.rm_offset = offset;
0961 error = xfs_rmap_update(cur, >rec);
0962 if (error)
0963 goto out_error;
0964 } else {
0965
0966
0967
0968
0969 cur->bc_rec.r.rm_startblock = bno;
0970 cur->bc_rec.r.rm_blockcount = len;
0971 cur->bc_rec.r.rm_owner = owner;
0972 cur->bc_rec.r.rm_offset = offset;
0973 cur->bc_rec.r.rm_flags = flags;
0974 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
0975 owner, offset, flags);
0976 error = xfs_btree_insert(cur, &i);
0977 if (error)
0978 goto out_error;
0979 if (XFS_IS_CORRUPT(mp, i != 1)) {
0980 error = -EFSCORRUPTED;
0981 goto out_error;
0982 }
0983 }
0984
0985 trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
0986 unwritten, oinfo);
0987 out_error:
0988 if (error)
0989 trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
0990 error, _RET_IP_);
0991 return error;
0992 }
0993
0994
0995
0996
0997 int
0998 xfs_rmap_alloc(
0999 struct xfs_trans *tp,
1000 struct xfs_buf *agbp,
1001 struct xfs_perag *pag,
1002 xfs_agblock_t bno,
1003 xfs_extlen_t len,
1004 const struct xfs_owner_info *oinfo)
1005 {
1006 struct xfs_mount *mp = tp->t_mountp;
1007 struct xfs_btree_cur *cur;
1008 int error;
1009
1010 if (!xfs_has_rmapbt(mp))
1011 return 0;
1012
1013 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
1014 error = xfs_rmap_map(cur, bno, len, false, oinfo);
1015
1016 xfs_btree_del_cursor(cur, error);
1017 return error;
1018 }
1019
1020 #define RMAP_LEFT_CONTIG (1 << 0)
1021 #define RMAP_RIGHT_CONTIG (1 << 1)
1022 #define RMAP_LEFT_FILLING (1 << 2)
1023 #define RMAP_RIGHT_FILLING (1 << 3)
1024 #define RMAP_LEFT_VALID (1 << 6)
1025 #define RMAP_RIGHT_VALID (1 << 7)
1026
1027 #define LEFT r[0]
1028 #define RIGHT r[1]
1029 #define PREV r[2]
1030 #define NEW r[3]
1031
1032
1033
1034
1035
1036 STATIC int
1037 xfs_rmap_convert(
1038 struct xfs_btree_cur *cur,
1039 xfs_agblock_t bno,
1040 xfs_extlen_t len,
1041 bool unwritten,
1042 const struct xfs_owner_info *oinfo)
1043 {
1044 struct xfs_mount *mp = cur->bc_mp;
1045 struct xfs_rmap_irec r[4];
1046
1047
1048 uint64_t owner;
1049 uint64_t offset;
1050 uint64_t new_endoff;
1051 unsigned int oldext;
1052 unsigned int newext;
1053 unsigned int flags = 0;
1054 int i;
1055 int state = 0;
1056 int error;
1057
1058 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1059 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1060 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1061 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1062 new_endoff = offset + len;
1063 trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1064 unwritten, oinfo);
1065
1066
1067
1068
1069
1070
1071 error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, &PREV, &i);
1072 if (error)
1073 goto done;
1074 if (XFS_IS_CORRUPT(mp, i != 1)) {
1075 error = -EFSCORRUPTED;
1076 goto done;
1077 }
1078
1079 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
1080 cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
1081 PREV.rm_blockcount, PREV.rm_owner,
1082 PREV.rm_offset, PREV.rm_flags);
1083
1084 ASSERT(PREV.rm_offset <= offset);
1085 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1086 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1087 newext = ~oldext & XFS_RMAP_UNWRITTEN;
1088
1089
1090
1091
1092
1093 if (PREV.rm_offset == offset)
1094 state |= RMAP_LEFT_FILLING;
1095 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1096 state |= RMAP_RIGHT_FILLING;
1097
1098
1099
1100
1101
1102
1103 error = xfs_btree_decrement(cur, 0, &i);
1104 if (error)
1105 goto done;
1106 if (i) {
1107 state |= RMAP_LEFT_VALID;
1108 error = xfs_rmap_get_rec(cur, &LEFT, &i);
1109 if (error)
1110 goto done;
1111 if (XFS_IS_CORRUPT(mp, i != 1)) {
1112 error = -EFSCORRUPTED;
1113 goto done;
1114 }
1115 if (XFS_IS_CORRUPT(mp,
1116 LEFT.rm_startblock + LEFT.rm_blockcount >
1117 bno)) {
1118 error = -EFSCORRUPTED;
1119 goto done;
1120 }
1121 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
1122 cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
1123 LEFT.rm_blockcount, LEFT.rm_owner,
1124 LEFT.rm_offset, LEFT.rm_flags);
1125 if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
1126 LEFT.rm_offset + LEFT.rm_blockcount == offset &&
1127 xfs_rmap_is_mergeable(&LEFT, owner, newext))
1128 state |= RMAP_LEFT_CONTIG;
1129 }
1130
1131
1132
1133
1134
1135
1136 error = xfs_btree_increment(cur, 0, &i);
1137 if (error)
1138 goto done;
1139 if (XFS_IS_CORRUPT(mp, i != 1)) {
1140 error = -EFSCORRUPTED;
1141 goto done;
1142 }
1143 error = xfs_btree_increment(cur, 0, &i);
1144 if (error)
1145 goto done;
1146 if (i) {
1147 state |= RMAP_RIGHT_VALID;
1148 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1149 if (error)
1150 goto done;
1151 if (XFS_IS_CORRUPT(mp, i != 1)) {
1152 error = -EFSCORRUPTED;
1153 goto done;
1154 }
1155 if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1156 error = -EFSCORRUPTED;
1157 goto done;
1158 }
1159 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
1160 cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
1161 RIGHT.rm_blockcount, RIGHT.rm_owner,
1162 RIGHT.rm_offset, RIGHT.rm_flags);
1163 if (bno + len == RIGHT.rm_startblock &&
1164 offset + len == RIGHT.rm_offset &&
1165 xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1166 state |= RMAP_RIGHT_CONTIG;
1167 }
1168
1169
1170 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1171 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1172 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1173 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1174 (unsigned long)LEFT.rm_blockcount + len +
1175 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1176 state &= ~RMAP_RIGHT_CONTIG;
1177
1178 trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
1179 _RET_IP_);
1180
1181
1182 error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, NULL, &i);
1183 if (error)
1184 goto done;
1185 if (XFS_IS_CORRUPT(mp, i != 1)) {
1186 error = -EFSCORRUPTED;
1187 goto done;
1188 }
1189
1190
1191
1192
1193 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1194 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1195 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1196 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1197
1198
1199
1200
1201 error = xfs_btree_increment(cur, 0, &i);
1202 if (error)
1203 goto done;
1204 if (XFS_IS_CORRUPT(mp, i != 1)) {
1205 error = -EFSCORRUPTED;
1206 goto done;
1207 }
1208 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1209 RIGHT.rm_startblock, RIGHT.rm_blockcount,
1210 RIGHT.rm_owner, RIGHT.rm_offset,
1211 RIGHT.rm_flags);
1212 error = xfs_btree_delete(cur, &i);
1213 if (error)
1214 goto done;
1215 if (XFS_IS_CORRUPT(mp, i != 1)) {
1216 error = -EFSCORRUPTED;
1217 goto done;
1218 }
1219 error = xfs_btree_decrement(cur, 0, &i);
1220 if (error)
1221 goto done;
1222 if (XFS_IS_CORRUPT(mp, i != 1)) {
1223 error = -EFSCORRUPTED;
1224 goto done;
1225 }
1226 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1227 PREV.rm_startblock, PREV.rm_blockcount,
1228 PREV.rm_owner, PREV.rm_offset,
1229 PREV.rm_flags);
1230 error = xfs_btree_delete(cur, &i);
1231 if (error)
1232 goto done;
1233 if (XFS_IS_CORRUPT(mp, i != 1)) {
1234 error = -EFSCORRUPTED;
1235 goto done;
1236 }
1237 error = xfs_btree_decrement(cur, 0, &i);
1238 if (error)
1239 goto done;
1240 if (XFS_IS_CORRUPT(mp, i != 1)) {
1241 error = -EFSCORRUPTED;
1242 goto done;
1243 }
1244 NEW = LEFT;
1245 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1246 error = xfs_rmap_update(cur, &NEW);
1247 if (error)
1248 goto done;
1249 break;
1250
1251 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1252
1253
1254
1255
1256 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1257 PREV.rm_startblock, PREV.rm_blockcount,
1258 PREV.rm_owner, PREV.rm_offset,
1259 PREV.rm_flags);
1260 error = xfs_btree_delete(cur, &i);
1261 if (error)
1262 goto done;
1263 if (XFS_IS_CORRUPT(mp, i != 1)) {
1264 error = -EFSCORRUPTED;
1265 goto done;
1266 }
1267 error = xfs_btree_decrement(cur, 0, &i);
1268 if (error)
1269 goto done;
1270 if (XFS_IS_CORRUPT(mp, i != 1)) {
1271 error = -EFSCORRUPTED;
1272 goto done;
1273 }
1274 NEW = LEFT;
1275 NEW.rm_blockcount += PREV.rm_blockcount;
1276 error = xfs_rmap_update(cur, &NEW);
1277 if (error)
1278 goto done;
1279 break;
1280
1281 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1282
1283
1284
1285
1286 error = xfs_btree_increment(cur, 0, &i);
1287 if (error)
1288 goto done;
1289 if (XFS_IS_CORRUPT(mp, i != 1)) {
1290 error = -EFSCORRUPTED;
1291 goto done;
1292 }
1293 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1294 RIGHT.rm_startblock, RIGHT.rm_blockcount,
1295 RIGHT.rm_owner, RIGHT.rm_offset,
1296 RIGHT.rm_flags);
1297 error = xfs_btree_delete(cur, &i);
1298 if (error)
1299 goto done;
1300 if (XFS_IS_CORRUPT(mp, i != 1)) {
1301 error = -EFSCORRUPTED;
1302 goto done;
1303 }
1304 error = xfs_btree_decrement(cur, 0, &i);
1305 if (error)
1306 goto done;
1307 if (XFS_IS_CORRUPT(mp, i != 1)) {
1308 error = -EFSCORRUPTED;
1309 goto done;
1310 }
1311 NEW = PREV;
1312 NEW.rm_blockcount = len + RIGHT.rm_blockcount;
1313 NEW.rm_flags = newext;
1314 error = xfs_rmap_update(cur, &NEW);
1315 if (error)
1316 goto done;
1317 break;
1318
1319 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1320
1321
1322
1323
1324
1325 NEW = PREV;
1326 NEW.rm_flags = newext;
1327 error = xfs_rmap_update(cur, &NEW);
1328 if (error)
1329 goto done;
1330 break;
1331
1332 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1333
1334
1335
1336
1337 NEW = PREV;
1338 NEW.rm_offset += len;
1339 NEW.rm_startblock += len;
1340 NEW.rm_blockcount -= len;
1341 error = xfs_rmap_update(cur, &NEW);
1342 if (error)
1343 goto done;
1344 error = xfs_btree_decrement(cur, 0, &i);
1345 if (error)
1346 goto done;
1347 NEW = LEFT;
1348 NEW.rm_blockcount += len;
1349 error = xfs_rmap_update(cur, &NEW);
1350 if (error)
1351 goto done;
1352 break;
1353
1354 case RMAP_LEFT_FILLING:
1355
1356
1357
1358
1359 NEW = PREV;
1360 NEW.rm_startblock += len;
1361 NEW.rm_offset += len;
1362 NEW.rm_blockcount -= len;
1363 error = xfs_rmap_update(cur, &NEW);
1364 if (error)
1365 goto done;
1366 NEW.rm_startblock = bno;
1367 NEW.rm_owner = owner;
1368 NEW.rm_offset = offset;
1369 NEW.rm_blockcount = len;
1370 NEW.rm_flags = newext;
1371 cur->bc_rec.r = NEW;
1372 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1373 len, owner, offset, newext);
1374 error = xfs_btree_insert(cur, &i);
1375 if (error)
1376 goto done;
1377 if (XFS_IS_CORRUPT(mp, i != 1)) {
1378 error = -EFSCORRUPTED;
1379 goto done;
1380 }
1381 break;
1382
1383 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1384
1385
1386
1387
1388 NEW = PREV;
1389 NEW.rm_blockcount -= len;
1390 error = xfs_rmap_update(cur, &NEW);
1391 if (error)
1392 goto done;
1393 error = xfs_btree_increment(cur, 0, &i);
1394 if (error)
1395 goto done;
1396 NEW = RIGHT;
1397 NEW.rm_offset = offset;
1398 NEW.rm_startblock = bno;
1399 NEW.rm_blockcount += len;
1400 error = xfs_rmap_update(cur, &NEW);
1401 if (error)
1402 goto done;
1403 break;
1404
1405 case RMAP_RIGHT_FILLING:
1406
1407
1408
1409
1410 NEW = PREV;
1411 NEW.rm_blockcount -= len;
1412 error = xfs_rmap_update(cur, &NEW);
1413 if (error)
1414 goto done;
1415 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1416 oldext, &i);
1417 if (error)
1418 goto done;
1419 if (XFS_IS_CORRUPT(mp, i != 0)) {
1420 error = -EFSCORRUPTED;
1421 goto done;
1422 }
1423 NEW.rm_startblock = bno;
1424 NEW.rm_owner = owner;
1425 NEW.rm_offset = offset;
1426 NEW.rm_blockcount = len;
1427 NEW.rm_flags = newext;
1428 cur->bc_rec.r = NEW;
1429 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1430 len, owner, offset, newext);
1431 error = xfs_btree_insert(cur, &i);
1432 if (error)
1433 goto done;
1434 if (XFS_IS_CORRUPT(mp, i != 1)) {
1435 error = -EFSCORRUPTED;
1436 goto done;
1437 }
1438 break;
1439
1440 case 0:
1441
1442
1443
1444
1445
1446
1447 NEW.rm_startblock = bno + len;
1448 NEW.rm_owner = owner;
1449 NEW.rm_offset = new_endoff;
1450 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1451 new_endoff;
1452 NEW.rm_flags = PREV.rm_flags;
1453 error = xfs_rmap_update(cur, &NEW);
1454 if (error)
1455 goto done;
1456
1457 NEW = PREV;
1458 NEW.rm_blockcount = offset - PREV.rm_offset;
1459 cur->bc_rec.r = NEW;
1460 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
1461 NEW.rm_startblock, NEW.rm_blockcount,
1462 NEW.rm_owner, NEW.rm_offset,
1463 NEW.rm_flags);
1464 error = xfs_btree_insert(cur, &i);
1465 if (error)
1466 goto done;
1467 if (XFS_IS_CORRUPT(mp, i != 1)) {
1468 error = -EFSCORRUPTED;
1469 goto done;
1470 }
1471
1472
1473
1474
1475
1476 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1477 oldext, &i);
1478 if (error)
1479 goto done;
1480 if (XFS_IS_CORRUPT(mp, i != 0)) {
1481 error = -EFSCORRUPTED;
1482 goto done;
1483 }
1484
1485 cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1486 cur->bc_rec.r.rm_flags |= newext;
1487 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1488 owner, offset, newext);
1489 error = xfs_btree_insert(cur, &i);
1490 if (error)
1491 goto done;
1492 if (XFS_IS_CORRUPT(mp, i != 1)) {
1493 error = -EFSCORRUPTED;
1494 goto done;
1495 }
1496 break;
1497
1498 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1499 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1500 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1501 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1502 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1503 case RMAP_LEFT_CONTIG:
1504 case RMAP_RIGHT_CONTIG:
1505
1506
1507
1508 ASSERT(0);
1509 }
1510
1511 trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
1512 unwritten, oinfo);
1513 done:
1514 if (error)
1515 trace_xfs_rmap_convert_error(cur->bc_mp,
1516 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
1517 return error;
1518 }
1519
1520
1521
1522
1523
1524
1525 STATIC int
1526 xfs_rmap_convert_shared(
1527 struct xfs_btree_cur *cur,
1528 xfs_agblock_t bno,
1529 xfs_extlen_t len,
1530 bool unwritten,
1531 const struct xfs_owner_info *oinfo)
1532 {
1533 struct xfs_mount *mp = cur->bc_mp;
1534 struct xfs_rmap_irec r[4];
1535
1536
1537 uint64_t owner;
1538 uint64_t offset;
1539 uint64_t new_endoff;
1540 unsigned int oldext;
1541 unsigned int newext;
1542 unsigned int flags = 0;
1543 int i;
1544 int state = 0;
1545 int error;
1546
1547 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1548 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1549 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1550 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1551 new_endoff = offset + len;
1552 trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1553 unwritten, oinfo);
1554
1555
1556
1557
1558
1559
1560 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, oldext,
1561 &PREV, &i);
1562 if (error)
1563 goto done;
1564 if (XFS_IS_CORRUPT(mp, i != 1)) {
1565 error = -EFSCORRUPTED;
1566 goto done;
1567 }
1568
1569 ASSERT(PREV.rm_offset <= offset);
1570 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1571 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1572 newext = ~oldext & XFS_RMAP_UNWRITTEN;
1573
1574
1575
1576
1577
1578 if (PREV.rm_offset == offset)
1579 state |= RMAP_LEFT_FILLING;
1580 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1581 state |= RMAP_RIGHT_FILLING;
1582
1583
1584 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
1585 &LEFT, &i);
1586 if (error)
1587 goto done;
1588 if (i) {
1589 state |= RMAP_LEFT_VALID;
1590 if (XFS_IS_CORRUPT(mp,
1591 LEFT.rm_startblock + LEFT.rm_blockcount >
1592 bno)) {
1593 error = -EFSCORRUPTED;
1594 goto done;
1595 }
1596 if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
1597 state |= RMAP_LEFT_CONTIG;
1598 }
1599
1600
1601 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
1602 newext, &i);
1603 if (error)
1604 goto done;
1605 if (i) {
1606 state |= RMAP_RIGHT_VALID;
1607 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1608 if (error)
1609 goto done;
1610 if (XFS_IS_CORRUPT(mp, i != 1)) {
1611 error = -EFSCORRUPTED;
1612 goto done;
1613 }
1614 if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1615 error = -EFSCORRUPTED;
1616 goto done;
1617 }
1618 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
1619 cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
1620 RIGHT.rm_blockcount, RIGHT.rm_owner,
1621 RIGHT.rm_offset, RIGHT.rm_flags);
1622 if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1623 state |= RMAP_RIGHT_CONTIG;
1624 }
1625
1626
1627 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1628 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1629 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1630 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1631 (unsigned long)LEFT.rm_blockcount + len +
1632 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1633 state &= ~RMAP_RIGHT_CONTIG;
1634
1635 trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
1636 _RET_IP_);
1637
1638
1639
1640 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1641 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1642 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1643 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1644
1645
1646
1647
1648 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1649 RIGHT.rm_blockcount, RIGHT.rm_owner,
1650 RIGHT.rm_offset, RIGHT.rm_flags);
1651 if (error)
1652 goto done;
1653 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1654 PREV.rm_blockcount, PREV.rm_owner,
1655 PREV.rm_offset, PREV.rm_flags);
1656 if (error)
1657 goto done;
1658 NEW = LEFT;
1659 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1660 NEW.rm_blockcount, NEW.rm_owner,
1661 NEW.rm_offset, NEW.rm_flags, &i);
1662 if (error)
1663 goto done;
1664 if (XFS_IS_CORRUPT(mp, i != 1)) {
1665 error = -EFSCORRUPTED;
1666 goto done;
1667 }
1668 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1669 error = xfs_rmap_update(cur, &NEW);
1670 if (error)
1671 goto done;
1672 break;
1673
1674 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1675
1676
1677
1678
1679 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1680 PREV.rm_blockcount, PREV.rm_owner,
1681 PREV.rm_offset, PREV.rm_flags);
1682 if (error)
1683 goto done;
1684 NEW = LEFT;
1685 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1686 NEW.rm_blockcount, NEW.rm_owner,
1687 NEW.rm_offset, NEW.rm_flags, &i);
1688 if (error)
1689 goto done;
1690 if (XFS_IS_CORRUPT(mp, i != 1)) {
1691 error = -EFSCORRUPTED;
1692 goto done;
1693 }
1694 NEW.rm_blockcount += PREV.rm_blockcount;
1695 error = xfs_rmap_update(cur, &NEW);
1696 if (error)
1697 goto done;
1698 break;
1699
1700 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1701
1702
1703
1704
1705 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1706 RIGHT.rm_blockcount, RIGHT.rm_owner,
1707 RIGHT.rm_offset, RIGHT.rm_flags);
1708 if (error)
1709 goto done;
1710 NEW = PREV;
1711 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1712 NEW.rm_blockcount, NEW.rm_owner,
1713 NEW.rm_offset, NEW.rm_flags, &i);
1714 if (error)
1715 goto done;
1716 if (XFS_IS_CORRUPT(mp, i != 1)) {
1717 error = -EFSCORRUPTED;
1718 goto done;
1719 }
1720 NEW.rm_blockcount += RIGHT.rm_blockcount;
1721 NEW.rm_flags = RIGHT.rm_flags;
1722 error = xfs_rmap_update(cur, &NEW);
1723 if (error)
1724 goto done;
1725 break;
1726
1727 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1728
1729
1730
1731
1732
1733 NEW = PREV;
1734 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1735 NEW.rm_blockcount, NEW.rm_owner,
1736 NEW.rm_offset, NEW.rm_flags, &i);
1737 if (error)
1738 goto done;
1739 if (XFS_IS_CORRUPT(mp, i != 1)) {
1740 error = -EFSCORRUPTED;
1741 goto done;
1742 }
1743 NEW.rm_flags = newext;
1744 error = xfs_rmap_update(cur, &NEW);
1745 if (error)
1746 goto done;
1747 break;
1748
1749 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1750
1751
1752
1753
1754 NEW = PREV;
1755 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1756 NEW.rm_blockcount, NEW.rm_owner,
1757 NEW.rm_offset, NEW.rm_flags);
1758 if (error)
1759 goto done;
1760 NEW.rm_offset += len;
1761 NEW.rm_startblock += len;
1762 NEW.rm_blockcount -= len;
1763 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1764 NEW.rm_blockcount, NEW.rm_owner,
1765 NEW.rm_offset, NEW.rm_flags);
1766 if (error)
1767 goto done;
1768 NEW = LEFT;
1769 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1770 NEW.rm_blockcount, NEW.rm_owner,
1771 NEW.rm_offset, NEW.rm_flags, &i);
1772 if (error)
1773 goto done;
1774 if (XFS_IS_CORRUPT(mp, i != 1)) {
1775 error = -EFSCORRUPTED;
1776 goto done;
1777 }
1778 NEW.rm_blockcount += len;
1779 error = xfs_rmap_update(cur, &NEW);
1780 if (error)
1781 goto done;
1782 break;
1783
1784 case RMAP_LEFT_FILLING:
1785
1786
1787
1788
1789 NEW = PREV;
1790 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1791 NEW.rm_blockcount, NEW.rm_owner,
1792 NEW.rm_offset, NEW.rm_flags);
1793 if (error)
1794 goto done;
1795 NEW.rm_offset += len;
1796 NEW.rm_startblock += len;
1797 NEW.rm_blockcount -= len;
1798 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1799 NEW.rm_blockcount, NEW.rm_owner,
1800 NEW.rm_offset, NEW.rm_flags);
1801 if (error)
1802 goto done;
1803 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1804 if (error)
1805 goto done;
1806 break;
1807
1808 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1809
1810
1811
1812
1813 NEW = PREV;
1814 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1815 NEW.rm_blockcount, NEW.rm_owner,
1816 NEW.rm_offset, NEW.rm_flags, &i);
1817 if (error)
1818 goto done;
1819 if (XFS_IS_CORRUPT(mp, i != 1)) {
1820 error = -EFSCORRUPTED;
1821 goto done;
1822 }
1823 NEW.rm_blockcount = offset - NEW.rm_offset;
1824 error = xfs_rmap_update(cur, &NEW);
1825 if (error)
1826 goto done;
1827 NEW = RIGHT;
1828 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1829 NEW.rm_blockcount, NEW.rm_owner,
1830 NEW.rm_offset, NEW.rm_flags);
1831 if (error)
1832 goto done;
1833 NEW.rm_offset = offset;
1834 NEW.rm_startblock = bno;
1835 NEW.rm_blockcount += len;
1836 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1837 NEW.rm_blockcount, NEW.rm_owner,
1838 NEW.rm_offset, NEW.rm_flags);
1839 if (error)
1840 goto done;
1841 break;
1842
1843 case RMAP_RIGHT_FILLING:
1844
1845
1846
1847
1848 NEW = PREV;
1849 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1850 NEW.rm_blockcount, NEW.rm_owner,
1851 NEW.rm_offset, NEW.rm_flags, &i);
1852 if (error)
1853 goto done;
1854 if (XFS_IS_CORRUPT(mp, i != 1)) {
1855 error = -EFSCORRUPTED;
1856 goto done;
1857 }
1858 NEW.rm_blockcount -= len;
1859 error = xfs_rmap_update(cur, &NEW);
1860 if (error)
1861 goto done;
1862 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1863 if (error)
1864 goto done;
1865 break;
1866
1867 case 0:
1868
1869
1870
1871
1872
1873
1874 NEW.rm_startblock = bno + len;
1875 NEW.rm_owner = owner;
1876 NEW.rm_offset = new_endoff;
1877 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1878 new_endoff;
1879 NEW.rm_flags = PREV.rm_flags;
1880 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1881 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1882 NEW.rm_flags);
1883 if (error)
1884 goto done;
1885
1886 NEW = PREV;
1887 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1888 NEW.rm_blockcount, NEW.rm_owner,
1889 NEW.rm_offset, NEW.rm_flags, &i);
1890 if (error)
1891 goto done;
1892 if (XFS_IS_CORRUPT(mp, i != 1)) {
1893 error = -EFSCORRUPTED;
1894 goto done;
1895 }
1896 NEW.rm_blockcount = offset - NEW.rm_offset;
1897 error = xfs_rmap_update(cur, &NEW);
1898 if (error)
1899 goto done;
1900
1901 NEW.rm_startblock = bno;
1902 NEW.rm_blockcount = len;
1903 NEW.rm_owner = owner;
1904 NEW.rm_offset = offset;
1905 NEW.rm_flags = newext;
1906 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1907 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1908 NEW.rm_flags);
1909 if (error)
1910 goto done;
1911 break;
1912
1913 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1914 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1915 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1916 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1917 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1918 case RMAP_LEFT_CONTIG:
1919 case RMAP_RIGHT_CONTIG:
1920
1921
1922
1923 ASSERT(0);
1924 }
1925
1926 trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
1927 unwritten, oinfo);
1928 done:
1929 if (error)
1930 trace_xfs_rmap_convert_error(cur->bc_mp,
1931 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
1932 return error;
1933 }
1934
1935 #undef NEW
1936 #undef LEFT
1937 #undef RIGHT
1938 #undef PREV
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949 STATIC int
1950 xfs_rmap_unmap_shared(
1951 struct xfs_btree_cur *cur,
1952 xfs_agblock_t bno,
1953 xfs_extlen_t len,
1954 bool unwritten,
1955 const struct xfs_owner_info *oinfo)
1956 {
1957 struct xfs_mount *mp = cur->bc_mp;
1958 struct xfs_rmap_irec ltrec;
1959 uint64_t ltoff;
1960 int error = 0;
1961 int i;
1962 uint64_t owner;
1963 uint64_t offset;
1964 unsigned int flags;
1965
1966 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1967 if (unwritten)
1968 flags |= XFS_RMAP_UNWRITTEN;
1969 trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
1970 unwritten, oinfo);
1971
1972
1973
1974
1975
1976
1977 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
1978 <rec, &i);
1979 if (error)
1980 goto out_error;
1981 if (XFS_IS_CORRUPT(mp, i != 1)) {
1982 error = -EFSCORRUPTED;
1983 goto out_error;
1984 }
1985 ltoff = ltrec.rm_offset;
1986
1987
1988 if (XFS_IS_CORRUPT(mp,
1989 ltrec.rm_startblock > bno ||
1990 ltrec.rm_startblock + ltrec.rm_blockcount <
1991 bno + len)) {
1992 error = -EFSCORRUPTED;
1993 goto out_error;
1994 }
1995
1996
1997 if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
1998 error = -EFSCORRUPTED;
1999 goto out_error;
2000 }
2001
2002
2003 if (XFS_IS_CORRUPT(mp,
2004 (flags & XFS_RMAP_UNWRITTEN) !=
2005 (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
2006 error = -EFSCORRUPTED;
2007 goto out_error;
2008 }
2009
2010
2011 if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
2012 error = -EFSCORRUPTED;
2013 goto out_error;
2014 }
2015 if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
2016 error = -EFSCORRUPTED;
2017 goto out_error;
2018 }
2019
2020 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
2021
2022 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2023 ltrec.rm_blockcount, ltrec.rm_owner,
2024 ltrec.rm_offset, ltrec.rm_flags);
2025 if (error)
2026 goto out_error;
2027 } else if (ltrec.rm_startblock == bno) {
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2041 ltrec.rm_blockcount, ltrec.rm_owner,
2042 ltrec.rm_offset, ltrec.rm_flags);
2043 if (error)
2044 goto out_error;
2045
2046
2047 ltrec.rm_startblock += len;
2048 ltrec.rm_blockcount -= len;
2049 ltrec.rm_offset += len;
2050 error = xfs_rmap_insert(cur, ltrec.rm_startblock,
2051 ltrec.rm_blockcount, ltrec.rm_owner,
2052 ltrec.rm_offset, ltrec.rm_flags);
2053 if (error)
2054 goto out_error;
2055 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2067 ltrec.rm_blockcount, ltrec.rm_owner,
2068 ltrec.rm_offset, ltrec.rm_flags, &i);
2069 if (error)
2070 goto out_error;
2071 if (XFS_IS_CORRUPT(mp, i != 1)) {
2072 error = -EFSCORRUPTED;
2073 goto out_error;
2074 }
2075 ltrec.rm_blockcount -= len;
2076 error = xfs_rmap_update(cur, <rec);
2077 if (error)
2078 goto out_error;
2079 } else {
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092 xfs_extlen_t orig_len = ltrec.rm_blockcount;
2093
2094
2095 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2096 ltrec.rm_blockcount, ltrec.rm_owner,
2097 ltrec.rm_offset, ltrec.rm_flags, &i);
2098 if (error)
2099 goto out_error;
2100 if (XFS_IS_CORRUPT(mp, i != 1)) {
2101 error = -EFSCORRUPTED;
2102 goto out_error;
2103 }
2104 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
2105 error = xfs_rmap_update(cur, <rec);
2106 if (error)
2107 goto out_error;
2108
2109
2110 error = xfs_rmap_insert(cur, bno + len,
2111 orig_len - len - ltrec.rm_blockcount,
2112 ltrec.rm_owner, offset + len,
2113 ltrec.rm_flags);
2114 if (error)
2115 goto out_error;
2116 }
2117
2118 trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2119 unwritten, oinfo);
2120 out_error:
2121 if (error)
2122 trace_xfs_rmap_unmap_error(cur->bc_mp,
2123 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2124 return error;
2125 }
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136 STATIC int
2137 xfs_rmap_map_shared(
2138 struct xfs_btree_cur *cur,
2139 xfs_agblock_t bno,
2140 xfs_extlen_t len,
2141 bool unwritten,
2142 const struct xfs_owner_info *oinfo)
2143 {
2144 struct xfs_mount *mp = cur->bc_mp;
2145 struct xfs_rmap_irec ltrec;
2146 struct xfs_rmap_irec gtrec;
2147 int have_gt;
2148 int have_lt;
2149 int error = 0;
2150 int i;
2151 uint64_t owner;
2152 uint64_t offset;
2153 unsigned int flags = 0;
2154
2155 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2156 if (unwritten)
2157 flags |= XFS_RMAP_UNWRITTEN;
2158 trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
2159 unwritten, oinfo);
2160
2161
2162 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
2163 <rec, &have_lt);
2164 if (error)
2165 goto out_error;
2166 if (have_lt &&
2167 !xfs_rmap_is_mergeable(<rec, owner, flags))
2168 have_lt = 0;
2169
2170
2171 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
2172 flags, &have_gt);
2173 if (error)
2174 goto out_error;
2175 if (have_gt) {
2176 error = xfs_rmap_get_rec(cur, >rec, &have_gt);
2177 if (error)
2178 goto out_error;
2179 if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
2180 error = -EFSCORRUPTED;
2181 goto out_error;
2182 }
2183 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
2184 cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
2185 gtrec.rm_blockcount, gtrec.rm_owner,
2186 gtrec.rm_offset, gtrec.rm_flags);
2187
2188 if (!xfs_rmap_is_mergeable(>rec, owner, flags))
2189 have_gt = 0;
2190 }
2191
2192 if (have_lt &&
2193 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
2194 ltrec.rm_offset + ltrec.rm_blockcount == offset) {
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204 ltrec.rm_blockcount += len;
2205 if (have_gt &&
2206 bno + len == gtrec.rm_startblock &&
2207 offset + len == gtrec.rm_offset) {
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217 ltrec.rm_blockcount += gtrec.rm_blockcount;
2218 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2219 gtrec.rm_blockcount, gtrec.rm_owner,
2220 gtrec.rm_offset, gtrec.rm_flags);
2221 if (error)
2222 goto out_error;
2223 }
2224
2225
2226 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2227 ltrec.rm_blockcount, ltrec.rm_owner,
2228 ltrec.rm_offset, ltrec.rm_flags, &i);
2229 if (error)
2230 goto out_error;
2231 if (XFS_IS_CORRUPT(mp, i != 1)) {
2232 error = -EFSCORRUPTED;
2233 goto out_error;
2234 }
2235
2236 error = xfs_rmap_update(cur, <rec);
2237 if (error)
2238 goto out_error;
2239 } else if (have_gt &&
2240 bno + len == gtrec.rm_startblock &&
2241 offset + len == gtrec.rm_offset) {
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2253 gtrec.rm_blockcount, gtrec.rm_owner,
2254 gtrec.rm_offset, gtrec.rm_flags);
2255 if (error)
2256 goto out_error;
2257
2258
2259 gtrec.rm_startblock = bno;
2260 gtrec.rm_blockcount += len;
2261 gtrec.rm_offset = offset;
2262 error = xfs_rmap_insert(cur, gtrec.rm_startblock,
2263 gtrec.rm_blockcount, gtrec.rm_owner,
2264 gtrec.rm_offset, gtrec.rm_flags);
2265 if (error)
2266 goto out_error;
2267 } else {
2268
2269
2270
2271
2272 error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
2273 if (error)
2274 goto out_error;
2275 }
2276
2277 trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2278 unwritten, oinfo);
2279 out_error:
2280 if (error)
2281 trace_xfs_rmap_map_error(cur->bc_mp,
2282 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2283 return error;
2284 }
2285
2286
2287 int
2288 xfs_rmap_map_raw(
2289 struct xfs_btree_cur *cur,
2290 struct xfs_rmap_irec *rmap)
2291 {
2292 struct xfs_owner_info oinfo;
2293
2294 oinfo.oi_owner = rmap->rm_owner;
2295 oinfo.oi_offset = rmap->rm_offset;
2296 oinfo.oi_flags = 0;
2297 if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
2298 oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
2299 if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
2300 oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
2301
2302 if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
2303 return xfs_rmap_map(cur, rmap->rm_startblock,
2304 rmap->rm_blockcount,
2305 rmap->rm_flags & XFS_RMAP_UNWRITTEN,
2306 &oinfo);
2307
2308 return xfs_rmap_map_shared(cur, rmap->rm_startblock,
2309 rmap->rm_blockcount,
2310 rmap->rm_flags & XFS_RMAP_UNWRITTEN,
2311 &oinfo);
2312 }
2313
2314 struct xfs_rmap_query_range_info {
2315 xfs_rmap_query_range_fn fn;
2316 void *priv;
2317 };
2318
2319
2320 STATIC int
2321 xfs_rmap_query_range_helper(
2322 struct xfs_btree_cur *cur,
2323 const union xfs_btree_rec *rec,
2324 void *priv)
2325 {
2326 struct xfs_rmap_query_range_info *query = priv;
2327 struct xfs_rmap_irec irec;
2328 int error;
2329
2330 error = xfs_rmap_btrec_to_irec(rec, &irec);
2331 if (error)
2332 return error;
2333 return query->fn(cur, &irec, query->priv);
2334 }
2335
2336
2337 int
2338 xfs_rmap_query_range(
2339 struct xfs_btree_cur *cur,
2340 const struct xfs_rmap_irec *low_rec,
2341 const struct xfs_rmap_irec *high_rec,
2342 xfs_rmap_query_range_fn fn,
2343 void *priv)
2344 {
2345 union xfs_btree_irec low_brec;
2346 union xfs_btree_irec high_brec;
2347 struct xfs_rmap_query_range_info query;
2348
2349 low_brec.r = *low_rec;
2350 high_brec.r = *high_rec;
2351 query.priv = priv;
2352 query.fn = fn;
2353 return xfs_btree_query_range(cur, &low_brec, &high_brec,
2354 xfs_rmap_query_range_helper, &query);
2355 }
2356
2357
2358 int
2359 xfs_rmap_query_all(
2360 struct xfs_btree_cur *cur,
2361 xfs_rmap_query_range_fn fn,
2362 void *priv)
2363 {
2364 struct xfs_rmap_query_range_info query;
2365
2366 query.priv = priv;
2367 query.fn = fn;
2368 return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
2369 }
2370
2371
2372 void
2373 xfs_rmap_finish_one_cleanup(
2374 struct xfs_trans *tp,
2375 struct xfs_btree_cur *rcur,
2376 int error)
2377 {
2378 struct xfs_buf *agbp;
2379
2380 if (rcur == NULL)
2381 return;
2382 agbp = rcur->bc_ag.agbp;
2383 xfs_btree_del_cursor(rcur, error);
2384 if (error)
2385 xfs_trans_brelse(tp, agbp);
2386 }
2387
2388
2389
2390
2391
2392
2393
2394
2395 int
2396 xfs_rmap_finish_one(
2397 struct xfs_trans *tp,
2398 enum xfs_rmap_intent_type type,
2399 uint64_t owner,
2400 int whichfork,
2401 xfs_fileoff_t startoff,
2402 xfs_fsblock_t startblock,
2403 xfs_filblks_t blockcount,
2404 xfs_exntst_t state,
2405 struct xfs_btree_cur **pcur)
2406 {
2407 struct xfs_mount *mp = tp->t_mountp;
2408 struct xfs_perag *pag;
2409 struct xfs_btree_cur *rcur;
2410 struct xfs_buf *agbp = NULL;
2411 int error = 0;
2412 struct xfs_owner_info oinfo;
2413 xfs_agblock_t bno;
2414 bool unwritten;
2415
2416 pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
2417 bno = XFS_FSB_TO_AGBNO(mp, startblock);
2418
2419 trace_xfs_rmap_deferred(mp, pag->pag_agno, type, bno, owner, whichfork,
2420 startoff, blockcount, state);
2421
2422 if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) {
2423 error = -EIO;
2424 goto out_drop;
2425 }
2426
2427
2428
2429
2430
2431
2432 rcur = *pcur;
2433 if (rcur != NULL && rcur->bc_ag.pag != pag) {
2434 xfs_rmap_finish_one_cleanup(tp, rcur, 0);
2435 rcur = NULL;
2436 *pcur = NULL;
2437 }
2438 if (rcur == NULL) {
2439
2440
2441
2442
2443
2444 error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
2445 if (error)
2446 goto out_drop;
2447 if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
2448 error = -EFSCORRUPTED;
2449 goto out_drop;
2450 }
2451
2452 rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
2453 }
2454 *pcur = rcur;
2455
2456 xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff);
2457 unwritten = state == XFS_EXT_UNWRITTEN;
2458 bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock);
2459
2460 switch (type) {
2461 case XFS_RMAP_ALLOC:
2462 case XFS_RMAP_MAP:
2463 error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo);
2464 break;
2465 case XFS_RMAP_MAP_SHARED:
2466 error = xfs_rmap_map_shared(rcur, bno, blockcount, unwritten,
2467 &oinfo);
2468 break;
2469 case XFS_RMAP_FREE:
2470 case XFS_RMAP_UNMAP:
2471 error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten,
2472 &oinfo);
2473 break;
2474 case XFS_RMAP_UNMAP_SHARED:
2475 error = xfs_rmap_unmap_shared(rcur, bno, blockcount, unwritten,
2476 &oinfo);
2477 break;
2478 case XFS_RMAP_CONVERT:
2479 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
2480 &oinfo);
2481 break;
2482 case XFS_RMAP_CONVERT_SHARED:
2483 error = xfs_rmap_convert_shared(rcur, bno, blockcount,
2484 !unwritten, &oinfo);
2485 break;
2486 default:
2487 ASSERT(0);
2488 error = -EFSCORRUPTED;
2489 }
2490 out_drop:
2491 xfs_perag_put(pag);
2492 return error;
2493 }
2494
2495
2496
2497
2498 static bool
2499 xfs_rmap_update_is_needed(
2500 struct xfs_mount *mp,
2501 int whichfork)
2502 {
2503 return xfs_has_rmapbt(mp) && whichfork != XFS_COW_FORK;
2504 }
2505
2506
2507
2508
2509
2510 static void
2511 __xfs_rmap_add(
2512 struct xfs_trans *tp,
2513 enum xfs_rmap_intent_type type,
2514 uint64_t owner,
2515 int whichfork,
2516 struct xfs_bmbt_irec *bmap)
2517 {
2518 struct xfs_rmap_intent *ri;
2519
2520 trace_xfs_rmap_defer(tp->t_mountp,
2521 XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
2522 type,
2523 XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
2524 owner, whichfork,
2525 bmap->br_startoff,
2526 bmap->br_blockcount,
2527 bmap->br_state);
2528
2529 ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
2530 INIT_LIST_HEAD(&ri->ri_list);
2531 ri->ri_type = type;
2532 ri->ri_owner = owner;
2533 ri->ri_whichfork = whichfork;
2534 ri->ri_bmap = *bmap;
2535
2536 xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
2537 }
2538
2539
2540 void
2541 xfs_rmap_map_extent(
2542 struct xfs_trans *tp,
2543 struct xfs_inode *ip,
2544 int whichfork,
2545 struct xfs_bmbt_irec *PREV)
2546 {
2547 enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
2548
2549 if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2550 return;
2551
2552 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2553 type = XFS_RMAP_MAP_SHARED;
2554
2555 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
2556 }
2557
2558
2559 void
2560 xfs_rmap_unmap_extent(
2561 struct xfs_trans *tp,
2562 struct xfs_inode *ip,
2563 int whichfork,
2564 struct xfs_bmbt_irec *PREV)
2565 {
2566 enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
2567
2568 if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2569 return;
2570
2571 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2572 type = XFS_RMAP_UNMAP_SHARED;
2573
2574 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
2575 }
2576
2577
2578
2579
2580
2581
2582
2583 void
2584 xfs_rmap_convert_extent(
2585 struct xfs_mount *mp,
2586 struct xfs_trans *tp,
2587 struct xfs_inode *ip,
2588 int whichfork,
2589 struct xfs_bmbt_irec *PREV)
2590 {
2591 enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
2592
2593 if (!xfs_rmap_update_is_needed(mp, whichfork))
2594 return;
2595
2596 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2597 type = XFS_RMAP_CONVERT_SHARED;
2598
2599 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
2600 }
2601
2602
2603 void
2604 xfs_rmap_alloc_extent(
2605 struct xfs_trans *tp,
2606 xfs_agnumber_t agno,
2607 xfs_agblock_t bno,
2608 xfs_extlen_t len,
2609 uint64_t owner)
2610 {
2611 struct xfs_bmbt_irec bmap;
2612
2613 if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2614 return;
2615
2616 bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
2617 bmap.br_blockcount = len;
2618 bmap.br_startoff = 0;
2619 bmap.br_state = XFS_EXT_NORM;
2620
2621 __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
2622 }
2623
2624
2625 void
2626 xfs_rmap_free_extent(
2627 struct xfs_trans *tp,
2628 xfs_agnumber_t agno,
2629 xfs_agblock_t bno,
2630 xfs_extlen_t len,
2631 uint64_t owner)
2632 {
2633 struct xfs_bmbt_irec bmap;
2634
2635 if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2636 return;
2637
2638 bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
2639 bmap.br_blockcount = len;
2640 bmap.br_startoff = 0;
2641 bmap.br_state = XFS_EXT_NORM;
2642
2643 __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
2644 }
2645
2646
2647 int
2648 xfs_rmap_compare(
2649 const struct xfs_rmap_irec *a,
2650 const struct xfs_rmap_irec *b)
2651 {
2652 __u64 oa;
2653 __u64 ob;
2654
2655 oa = xfs_rmap_irec_offset_pack(a);
2656 ob = xfs_rmap_irec_offset_pack(b);
2657
2658 if (a->rm_startblock < b->rm_startblock)
2659 return -1;
2660 else if (a->rm_startblock > b->rm_startblock)
2661 return 1;
2662 else if (a->rm_owner < b->rm_owner)
2663 return -1;
2664 else if (a->rm_owner > b->rm_owner)
2665 return 1;
2666 else if (oa < ob)
2667 return -1;
2668 else if (oa > ob)
2669 return 1;
2670 else
2671 return 0;
2672 }
2673
2674
2675 int
2676 xfs_rmap_has_record(
2677 struct xfs_btree_cur *cur,
2678 xfs_agblock_t bno,
2679 xfs_extlen_t len,
2680 bool *exists)
2681 {
2682 union xfs_btree_irec low;
2683 union xfs_btree_irec high;
2684
2685 memset(&low, 0, sizeof(low));
2686 low.r.rm_startblock = bno;
2687 memset(&high, 0xFF, sizeof(high));
2688 high.r.rm_startblock = bno + len - 1;
2689
2690 return xfs_btree_has_record(cur, &low, &high, exists);
2691 }
2692
2693
2694
2695
2696
2697
2698
2699
2700 int
2701 xfs_rmap_record_exists(
2702 struct xfs_btree_cur *cur,
2703 xfs_agblock_t bno,
2704 xfs_extlen_t len,
2705 const struct xfs_owner_info *oinfo,
2706 bool *has_rmap)
2707 {
2708 uint64_t owner;
2709 uint64_t offset;
2710 unsigned int flags;
2711 int has_record;
2712 struct xfs_rmap_irec irec;
2713 int error;
2714
2715 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2716 ASSERT(XFS_RMAP_NON_INODE_OWNER(owner) ||
2717 (flags & XFS_RMAP_BMBT_BLOCK));
2718
2719 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &irec,
2720 &has_record);
2721 if (error)
2722 return error;
2723 if (!has_record) {
2724 *has_rmap = false;
2725 return 0;
2726 }
2727
2728 *has_rmap = (irec.rm_owner == owner && irec.rm_startblock <= bno &&
2729 irec.rm_startblock + irec.rm_blockcount >= bno + len);
2730 return 0;
2731 }
2732
2733 struct xfs_rmap_key_state {
2734 uint64_t owner;
2735 uint64_t offset;
2736 unsigned int flags;
2737 };
2738
2739
2740 STATIC int
2741 xfs_rmap_has_other_keys_helper(
2742 struct xfs_btree_cur *cur,
2743 const struct xfs_rmap_irec *rec,
2744 void *priv)
2745 {
2746 struct xfs_rmap_key_state *rks = priv;
2747
2748 if (rks->owner == rec->rm_owner && rks->offset == rec->rm_offset &&
2749 ((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) == rks->flags)
2750 return 0;
2751 return -ECANCELED;
2752 }
2753
2754
2755
2756
2757
2758 int
2759 xfs_rmap_has_other_keys(
2760 struct xfs_btree_cur *cur,
2761 xfs_agblock_t bno,
2762 xfs_extlen_t len,
2763 const struct xfs_owner_info *oinfo,
2764 bool *has_rmap)
2765 {
2766 struct xfs_rmap_irec low = {0};
2767 struct xfs_rmap_irec high;
2768 struct xfs_rmap_key_state rks;
2769 int error;
2770
2771 xfs_owner_info_unpack(oinfo, &rks.owner, &rks.offset, &rks.flags);
2772 *has_rmap = false;
2773
2774 low.rm_startblock = bno;
2775 memset(&high, 0xFF, sizeof(high));
2776 high.rm_startblock = bno + len - 1;
2777
2778 error = xfs_rmap_query_range(cur, &low, &high,
2779 xfs_rmap_has_other_keys_helper, &rks);
2780 if (error == -ECANCELED) {
2781 *has_rmap = true;
2782 return 0;
2783 }
2784
2785 return error;
2786 }
2787
2788 const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
2789 .oi_owner = XFS_RMAP_OWN_NULL,
2790 };
2791 const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = {
2792 .oi_owner = XFS_RMAP_OWN_UNKNOWN,
2793 };
2794 const struct xfs_owner_info XFS_RMAP_OINFO_FS = {
2795 .oi_owner = XFS_RMAP_OWN_FS,
2796 };
2797 const struct xfs_owner_info XFS_RMAP_OINFO_LOG = {
2798 .oi_owner = XFS_RMAP_OWN_LOG,
2799 };
2800 const struct xfs_owner_info XFS_RMAP_OINFO_AG = {
2801 .oi_owner = XFS_RMAP_OWN_AG,
2802 };
2803 const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = {
2804 .oi_owner = XFS_RMAP_OWN_INOBT,
2805 };
2806 const struct xfs_owner_info XFS_RMAP_OINFO_INODES = {
2807 .oi_owner = XFS_RMAP_OWN_INODES,
2808 };
2809 const struct xfs_owner_info XFS_RMAP_OINFO_REFC = {
2810 .oi_owner = XFS_RMAP_OWN_REFC,
2811 };
2812 const struct xfs_owner_info XFS_RMAP_OINFO_COW = {
2813 .oi_owner = XFS_RMAP_OWN_COW,
2814 };
2815
2816 int __init
2817 xfs_rmap_intent_init_cache(void)
2818 {
2819 xfs_rmap_intent_cache = kmem_cache_create("xfs_rmap_intent",
2820 sizeof(struct xfs_rmap_intent),
2821 0, 0, NULL);
2822
2823 return xfs_rmap_intent_cache != NULL ? 0 : -ENOMEM;
2824 }
2825
2826 void
2827 xfs_rmap_intent_destroy_cache(void)
2828 {
2829 kmem_cache_destroy(xfs_rmap_intent_cache);
2830 xfs_rmap_intent_cache = NULL;
2831 }