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_bit.h"
0014 #include "xfs_mount.h"
0015 #include "xfs_defer.h"
0016 #include "xfs_da_format.h"
0017 #include "xfs_da_btree.h"
0018 #include "xfs_inode.h"
0019 #include "xfs_trans.h"
0020 #include "xfs_bmap.h"
0021 #include "xfs_attr.h"
0022 #include "xfs_attr_remote.h"
0023 #include "xfs_trace.h"
0024 #include "xfs_error.h"
0025
0026 #define ATTR_RMTVALUE_MAPSIZE 1
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 int
0050 xfs_attr3_rmt_blocks(
0051 struct xfs_mount *mp,
0052 int attrlen)
0053 {
0054 if (xfs_has_crc(mp)) {
0055 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
0056 return (attrlen + buflen - 1) / buflen;
0057 }
0058 return XFS_B_TO_FSB(mp, attrlen);
0059 }
0060
0061
0062
0063
0064
0065
0066 static xfs_failaddr_t
0067 xfs_attr3_rmt_hdr_ok(
0068 void *ptr,
0069 xfs_ino_t ino,
0070 uint32_t offset,
0071 uint32_t size,
0072 xfs_daddr_t bno)
0073 {
0074 struct xfs_attr3_rmt_hdr *rmt = ptr;
0075
0076 if (bno != be64_to_cpu(rmt->rm_blkno))
0077 return __this_address;
0078 if (offset != be32_to_cpu(rmt->rm_offset))
0079 return __this_address;
0080 if (size != be32_to_cpu(rmt->rm_bytes))
0081 return __this_address;
0082 if (ino != be64_to_cpu(rmt->rm_owner))
0083 return __this_address;
0084
0085
0086 return NULL;
0087 }
0088
0089 static xfs_failaddr_t
0090 xfs_attr3_rmt_verify(
0091 struct xfs_mount *mp,
0092 struct xfs_buf *bp,
0093 void *ptr,
0094 int fsbsize,
0095 xfs_daddr_t bno)
0096 {
0097 struct xfs_attr3_rmt_hdr *rmt = ptr;
0098
0099 if (!xfs_verify_magic(bp, rmt->rm_magic))
0100 return __this_address;
0101 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
0102 return __this_address;
0103 if (be64_to_cpu(rmt->rm_blkno) != bno)
0104 return __this_address;
0105 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
0106 return __this_address;
0107 if (be32_to_cpu(rmt->rm_offset) +
0108 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
0109 return __this_address;
0110 if (rmt->rm_owner == 0)
0111 return __this_address;
0112
0113 return NULL;
0114 }
0115
0116 static int
0117 __xfs_attr3_rmt_read_verify(
0118 struct xfs_buf *bp,
0119 bool check_crc,
0120 xfs_failaddr_t *failaddr)
0121 {
0122 struct xfs_mount *mp = bp->b_mount;
0123 char *ptr;
0124 int len;
0125 xfs_daddr_t bno;
0126 int blksize = mp->m_attr_geo->blksize;
0127
0128
0129 if (!xfs_has_crc(mp))
0130 return 0;
0131
0132 ptr = bp->b_addr;
0133 bno = xfs_buf_daddr(bp);
0134 len = BBTOB(bp->b_length);
0135 ASSERT(len >= blksize);
0136
0137 while (len > 0) {
0138 if (check_crc &&
0139 !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
0140 *failaddr = __this_address;
0141 return -EFSBADCRC;
0142 }
0143 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
0144 if (*failaddr)
0145 return -EFSCORRUPTED;
0146 len -= blksize;
0147 ptr += blksize;
0148 bno += BTOBB(blksize);
0149 }
0150
0151 if (len != 0) {
0152 *failaddr = __this_address;
0153 return -EFSCORRUPTED;
0154 }
0155
0156 return 0;
0157 }
0158
0159 static void
0160 xfs_attr3_rmt_read_verify(
0161 struct xfs_buf *bp)
0162 {
0163 xfs_failaddr_t fa;
0164 int error;
0165
0166 error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
0167 if (error)
0168 xfs_verifier_error(bp, error, fa);
0169 }
0170
0171 static xfs_failaddr_t
0172 xfs_attr3_rmt_verify_struct(
0173 struct xfs_buf *bp)
0174 {
0175 xfs_failaddr_t fa;
0176 int error;
0177
0178 error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
0179 return error ? fa : NULL;
0180 }
0181
0182 static void
0183 xfs_attr3_rmt_write_verify(
0184 struct xfs_buf *bp)
0185 {
0186 struct xfs_mount *mp = bp->b_mount;
0187 xfs_failaddr_t fa;
0188 int blksize = mp->m_attr_geo->blksize;
0189 char *ptr;
0190 int len;
0191 xfs_daddr_t bno;
0192
0193
0194 if (!xfs_has_crc(mp))
0195 return;
0196
0197 ptr = bp->b_addr;
0198 bno = xfs_buf_daddr(bp);
0199 len = BBTOB(bp->b_length);
0200 ASSERT(len >= blksize);
0201
0202 while (len > 0) {
0203 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
0204
0205 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
0206 if (fa) {
0207 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0208 return;
0209 }
0210
0211
0212
0213
0214
0215 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
0216 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
0217 return;
0218 }
0219 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
0220
0221 len -= blksize;
0222 ptr += blksize;
0223 bno += BTOBB(blksize);
0224 }
0225
0226 if (len != 0)
0227 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
0228 }
0229
0230 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
0231 .name = "xfs_attr3_rmt",
0232 .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
0233 .verify_read = xfs_attr3_rmt_read_verify,
0234 .verify_write = xfs_attr3_rmt_write_verify,
0235 .verify_struct = xfs_attr3_rmt_verify_struct,
0236 };
0237
0238 STATIC int
0239 xfs_attr3_rmt_hdr_set(
0240 struct xfs_mount *mp,
0241 void *ptr,
0242 xfs_ino_t ino,
0243 uint32_t offset,
0244 uint32_t size,
0245 xfs_daddr_t bno)
0246 {
0247 struct xfs_attr3_rmt_hdr *rmt = ptr;
0248
0249 if (!xfs_has_crc(mp))
0250 return 0;
0251
0252 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
0253 rmt->rm_offset = cpu_to_be32(offset);
0254 rmt->rm_bytes = cpu_to_be32(size);
0255 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
0256 rmt->rm_owner = cpu_to_be64(ino);
0257 rmt->rm_blkno = cpu_to_be64(bno);
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
0270
0271 return sizeof(struct xfs_attr3_rmt_hdr);
0272 }
0273
0274
0275
0276
0277 STATIC int
0278 xfs_attr_rmtval_copyout(
0279 struct xfs_mount *mp,
0280 struct xfs_buf *bp,
0281 xfs_ino_t ino,
0282 int *offset,
0283 int *valuelen,
0284 uint8_t **dst)
0285 {
0286 char *src = bp->b_addr;
0287 xfs_daddr_t bno = xfs_buf_daddr(bp);
0288 int len = BBTOB(bp->b_length);
0289 int blksize = mp->m_attr_geo->blksize;
0290
0291 ASSERT(len >= blksize);
0292
0293 while (len > 0 && *valuelen > 0) {
0294 int hdr_size = 0;
0295 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
0296
0297 byte_cnt = min(*valuelen, byte_cnt);
0298
0299 if (xfs_has_crc(mp)) {
0300 if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
0301 byte_cnt, bno)) {
0302 xfs_alert(mp,
0303 "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
0304 bno, *offset, byte_cnt, ino);
0305 return -EFSCORRUPTED;
0306 }
0307 hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
0308 }
0309
0310 memcpy(*dst, src + hdr_size, byte_cnt);
0311
0312
0313 len -= blksize;
0314 src += blksize;
0315 bno += BTOBB(blksize);
0316
0317
0318 *valuelen -= byte_cnt;
0319 *dst += byte_cnt;
0320 *offset += byte_cnt;
0321 }
0322 return 0;
0323 }
0324
0325 STATIC void
0326 xfs_attr_rmtval_copyin(
0327 struct xfs_mount *mp,
0328 struct xfs_buf *bp,
0329 xfs_ino_t ino,
0330 int *offset,
0331 int *valuelen,
0332 uint8_t **src)
0333 {
0334 char *dst = bp->b_addr;
0335 xfs_daddr_t bno = xfs_buf_daddr(bp);
0336 int len = BBTOB(bp->b_length);
0337 int blksize = mp->m_attr_geo->blksize;
0338
0339 ASSERT(len >= blksize);
0340
0341 while (len > 0 && *valuelen > 0) {
0342 int hdr_size;
0343 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
0344
0345 byte_cnt = min(*valuelen, byte_cnt);
0346 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
0347 byte_cnt, bno);
0348
0349 memcpy(dst + hdr_size, *src, byte_cnt);
0350
0351
0352
0353
0354
0355 if (byte_cnt + hdr_size < blksize) {
0356 ASSERT(*valuelen - byte_cnt == 0);
0357 ASSERT(len == blksize);
0358 memset(dst + hdr_size + byte_cnt, 0,
0359 blksize - hdr_size - byte_cnt);
0360 }
0361
0362
0363 len -= blksize;
0364 dst += blksize;
0365 bno += BTOBB(blksize);
0366
0367
0368 *valuelen -= byte_cnt;
0369 *src += byte_cnt;
0370 *offset += byte_cnt;
0371 }
0372 }
0373
0374
0375
0376
0377
0378
0379
0380 int
0381 xfs_attr_rmtval_get(
0382 struct xfs_da_args *args)
0383 {
0384 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];
0385 struct xfs_mount *mp = args->dp->i_mount;
0386 struct xfs_buf *bp;
0387 xfs_dablk_t lblkno = args->rmtblkno;
0388 uint8_t *dst = args->value;
0389 int valuelen;
0390 int nmap;
0391 int error;
0392 int blkcnt = args->rmtblkcnt;
0393 int i;
0394 int offset = 0;
0395
0396 trace_xfs_attr_rmtval_get(args);
0397
0398 ASSERT(args->valuelen != 0);
0399 ASSERT(args->rmtvaluelen == args->valuelen);
0400
0401 valuelen = args->rmtvaluelen;
0402 while (valuelen > 0) {
0403 nmap = ATTR_RMTVALUE_MAPSIZE;
0404 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
0405 blkcnt, map, &nmap,
0406 XFS_BMAPI_ATTRFORK);
0407 if (error)
0408 return error;
0409 ASSERT(nmap >= 1);
0410
0411 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
0412 xfs_daddr_t dblkno;
0413 int dblkcnt;
0414
0415 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
0416 (map[i].br_startblock != HOLESTARTBLOCK));
0417 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
0418 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
0419 error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
0420 0, &bp, &xfs_attr3_rmt_buf_ops);
0421 if (error)
0422 return error;
0423
0424 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
0425 &offset, &valuelen,
0426 &dst);
0427 xfs_buf_relse(bp);
0428 if (error)
0429 return error;
0430
0431
0432 lblkno += map[i].br_blockcount;
0433 blkcnt -= map[i].br_blockcount;
0434 }
0435 }
0436 ASSERT(valuelen == 0);
0437 return 0;
0438 }
0439
0440
0441
0442
0443
0444 int
0445 xfs_attr_rmt_find_hole(
0446 struct xfs_da_args *args)
0447 {
0448 struct xfs_inode *dp = args->dp;
0449 struct xfs_mount *mp = dp->i_mount;
0450 int error;
0451 int blkcnt;
0452 xfs_fileoff_t lfileoff = 0;
0453
0454
0455
0456
0457
0458
0459 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
0460 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
0461 XFS_ATTR_FORK);
0462 if (error)
0463 return error;
0464
0465 args->rmtblkno = (xfs_dablk_t)lfileoff;
0466 args->rmtblkcnt = blkcnt;
0467
0468 return 0;
0469 }
0470
0471 int
0472 xfs_attr_rmtval_set_value(
0473 struct xfs_da_args *args)
0474 {
0475 struct xfs_inode *dp = args->dp;
0476 struct xfs_mount *mp = dp->i_mount;
0477 struct xfs_bmbt_irec map;
0478 xfs_dablk_t lblkno;
0479 uint8_t *src = args->value;
0480 int blkcnt;
0481 int valuelen;
0482 int nmap;
0483 int error;
0484 int offset = 0;
0485
0486
0487
0488
0489
0490
0491
0492 lblkno = args->rmtblkno;
0493 blkcnt = args->rmtblkcnt;
0494 valuelen = args->rmtvaluelen;
0495 while (valuelen > 0) {
0496 struct xfs_buf *bp;
0497 xfs_daddr_t dblkno;
0498 int dblkcnt;
0499
0500 ASSERT(blkcnt > 0);
0501
0502 nmap = 1;
0503 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
0504 blkcnt, &map, &nmap,
0505 XFS_BMAPI_ATTRFORK);
0506 if (error)
0507 return error;
0508 ASSERT(nmap == 1);
0509 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
0510 (map.br_startblock != HOLESTARTBLOCK));
0511
0512 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
0513 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
0514
0515 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
0516 if (error)
0517 return error;
0518 bp->b_ops = &xfs_attr3_rmt_buf_ops;
0519
0520 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
0521 &valuelen, &src);
0522
0523 error = xfs_bwrite(bp);
0524 xfs_buf_relse(bp);
0525 if (error)
0526 return error;
0527
0528
0529
0530 lblkno += map.br_blockcount;
0531 blkcnt -= map.br_blockcount;
0532 }
0533 ASSERT(valuelen == 0);
0534 return 0;
0535 }
0536
0537
0538 int
0539 xfs_attr_rmtval_stale(
0540 struct xfs_inode *ip,
0541 struct xfs_bmbt_irec *map,
0542 xfs_buf_flags_t incore_flags)
0543 {
0544 struct xfs_mount *mp = ip->i_mount;
0545 struct xfs_buf *bp;
0546 int error;
0547
0548 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
0549
0550 if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
0551 XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
0552 return -EFSCORRUPTED;
0553
0554 error = xfs_buf_incore(mp->m_ddev_targp,
0555 XFS_FSB_TO_DADDR(mp, map->br_startblock),
0556 XFS_FSB_TO_BB(mp, map->br_blockcount),
0557 incore_flags, &bp);
0558 if (error) {
0559 if (error == -ENOENT)
0560 return 0;
0561 return error;
0562 }
0563
0564 xfs_buf_stale(bp);
0565 xfs_buf_relse(bp);
0566 return 0;
0567 }
0568
0569
0570
0571
0572
0573
0574 int
0575 xfs_attr_rmtval_find_space(
0576 struct xfs_attr_intent *attr)
0577 {
0578 struct xfs_da_args *args = attr->xattri_da_args;
0579 struct xfs_bmbt_irec *map = &attr->xattri_map;
0580 int error;
0581
0582 attr->xattri_lblkno = 0;
0583 attr->xattri_blkcnt = 0;
0584 args->rmtblkcnt = 0;
0585 args->rmtblkno = 0;
0586 memset(map, 0, sizeof(struct xfs_bmbt_irec));
0587
0588 error = xfs_attr_rmt_find_hole(args);
0589 if (error)
0590 return error;
0591
0592 attr->xattri_blkcnt = args->rmtblkcnt;
0593 attr->xattri_lblkno = args->rmtblkno;
0594
0595 return 0;
0596 }
0597
0598
0599
0600
0601
0602
0603
0604 int
0605 xfs_attr_rmtval_set_blk(
0606 struct xfs_attr_intent *attr)
0607 {
0608 struct xfs_da_args *args = attr->xattri_da_args;
0609 struct xfs_inode *dp = args->dp;
0610 struct xfs_bmbt_irec *map = &attr->xattri_map;
0611 int nmap;
0612 int error;
0613
0614 nmap = 1;
0615 error = xfs_bmapi_write(args->trans, dp,
0616 (xfs_fileoff_t)attr->xattri_lblkno,
0617 attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
0618 map, &nmap);
0619 if (error)
0620 return error;
0621
0622 ASSERT(nmap == 1);
0623 ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
0624 (map->br_startblock != HOLESTARTBLOCK));
0625
0626
0627 attr->xattri_lblkno += map->br_blockcount;
0628 attr->xattri_blkcnt -= map->br_blockcount;
0629
0630 return 0;
0631 }
0632
0633
0634
0635
0636
0637 int
0638 xfs_attr_rmtval_invalidate(
0639 struct xfs_da_args *args)
0640 {
0641 xfs_dablk_t lblkno;
0642 int blkcnt;
0643 int error;
0644
0645
0646
0647
0648 lblkno = args->rmtblkno;
0649 blkcnt = args->rmtblkcnt;
0650 while (blkcnt > 0) {
0651 struct xfs_bmbt_irec map;
0652 int nmap;
0653
0654
0655
0656
0657 nmap = 1;
0658 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
0659 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
0660 if (error)
0661 return error;
0662 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
0663 return -EFSCORRUPTED;
0664 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
0665 if (error)
0666 return error;
0667
0668 lblkno += map.br_blockcount;
0669 blkcnt -= map.br_blockcount;
0670 }
0671 return 0;
0672 }
0673
0674
0675
0676
0677
0678
0679
0680 int
0681 xfs_attr_rmtval_remove(
0682 struct xfs_attr_intent *attr)
0683 {
0684 struct xfs_da_args *args = attr->xattri_da_args;
0685 int error, done;
0686
0687
0688
0689
0690 error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
0691 args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
0692 if (error)
0693 return error;
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 if (!done) {
0704 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
0705 args->dp);
0706 return -EAGAIN;
0707 }
0708
0709 args->rmtblkno = 0;
0710 args->rmtblkcnt = 0;
0711 return 0;
0712 }