732 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.4 * Copyright (c) 2013 Red Hat, Inc.5 * All Rights Reserved.6 */7#include "xfs.h"8#include "xfs_fs.h"9#include "xfs_shared.h"10#include "xfs_format.h"11#include "xfs_log_format.h"12#include "xfs_trans_resv.h"13#include "xfs_bit.h"14#include "xfs_mount.h"15#include "xfs_defer.h"16#include "xfs_da_format.h"17#include "xfs_da_btree.h"18#include "xfs_inode.h"19#include "xfs_trans.h"20#include "xfs_bmap.h"21#include "xfs_attr.h"22#include "xfs_attr_remote.h"23#include "xfs_trace.h"24#include "xfs_error.h"25#include "xfs_health.h"26 27#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */28 29/*30 * Remote Attribute Values31 * =======================32 *33 * Remote extended attribute values are conceptually simple -- they're written34 * to data blocks mapped by an inode's attribute fork, and they have an upper35 * size limit of 64k. Setting a value does not involve the XFS log.36 *37 * However, on a v5 filesystem, maximally sized remote attr values require one38 * block more than 64k worth of space to hold both the remote attribute value39 * header (64 bytes). On a 4k block filesystem this results in a 68k buffer;40 * on a 64k block filesystem, this would be a 128k buffer. Note that the log41 * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).42 * Therefore, we /must/ ensure that remote attribute value buffers never touch43 * the logging system and therefore never have a log item.44 */45 46/* How many bytes can be stored in a remote value buffer? */47inline unsigned int48xfs_attr3_rmt_buf_space(49 struct xfs_mount *mp)50{51 unsigned int blocksize = mp->m_attr_geo->blksize;52 53 if (xfs_has_crc(mp))54 return blocksize - sizeof(struct xfs_attr3_rmt_hdr);55 56 return blocksize;57}58 59/* Compute number of fsblocks needed to store a remote attr value */60unsigned int61xfs_attr3_rmt_blocks(62 struct xfs_mount *mp,63 unsigned int attrlen)64{65 /*66 * Each contiguous block has a header, so it is not just a simple67 * attribute length to FSB conversion.68 */69 if (xfs_has_crc(mp))70 return howmany(attrlen, xfs_attr3_rmt_buf_space(mp));71 72 return XFS_B_TO_FSB(mp, attrlen);73}74 75/*76 * Checking of the remote attribute header is split into two parts. The verifier77 * does CRC, location and bounds checking, the unpacking function checks the78 * attribute parameters and owner.79 */80static xfs_failaddr_t81xfs_attr3_rmt_hdr_ok(82 void *ptr,83 xfs_ino_t ino,84 uint32_t offset,85 uint32_t size,86 xfs_daddr_t bno)87{88 struct xfs_attr3_rmt_hdr *rmt = ptr;89 90 if (bno != be64_to_cpu(rmt->rm_blkno))91 return __this_address;92 if (offset != be32_to_cpu(rmt->rm_offset))93 return __this_address;94 if (size != be32_to_cpu(rmt->rm_bytes))95 return __this_address;96 if (ino != be64_to_cpu(rmt->rm_owner))97 return __this_address;98 99 /* ok */100 return NULL;101}102 103static xfs_failaddr_t104xfs_attr3_rmt_verify(105 struct xfs_mount *mp,106 struct xfs_buf *bp,107 void *ptr,108 xfs_daddr_t bno)109{110 struct xfs_attr3_rmt_hdr *rmt = ptr;111 112 if (!xfs_verify_magic(bp, rmt->rm_magic))113 return __this_address;114 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))115 return __this_address;116 if (be64_to_cpu(rmt->rm_blkno) != bno)117 return __this_address;118 if (be32_to_cpu(rmt->rm_bytes) > mp->m_attr_geo->blksize - sizeof(*rmt))119 return __this_address;120 if (be32_to_cpu(rmt->rm_offset) +121 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)122 return __this_address;123 if (rmt->rm_owner == 0)124 return __this_address;125 126 return NULL;127}128 129static int130__xfs_attr3_rmt_read_verify(131 struct xfs_buf *bp,132 bool check_crc,133 xfs_failaddr_t *failaddr)134{135 struct xfs_mount *mp = bp->b_mount;136 char *ptr;137 unsigned int len;138 xfs_daddr_t bno;139 unsigned int blksize = mp->m_attr_geo->blksize;140 141 /* no verification of non-crc buffers */142 if (!xfs_has_crc(mp))143 return 0;144 145 ptr = bp->b_addr;146 bno = xfs_buf_daddr(bp);147 len = BBTOB(bp->b_length);148 ASSERT(len >= blksize);149 150 while (len > 0) {151 if (check_crc &&152 !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {153 *failaddr = __this_address;154 return -EFSBADCRC;155 }156 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, bno);157 if (*failaddr)158 return -EFSCORRUPTED;159 len -= blksize;160 ptr += blksize;161 bno += BTOBB(blksize);162 }163 164 if (len != 0) {165 *failaddr = __this_address;166 return -EFSCORRUPTED;167 }168 169 return 0;170}171 172static void173xfs_attr3_rmt_read_verify(174 struct xfs_buf *bp)175{176 xfs_failaddr_t fa;177 int error;178 179 error = __xfs_attr3_rmt_read_verify(bp, true, &fa);180 if (error)181 xfs_verifier_error(bp, error, fa);182}183 184static xfs_failaddr_t185xfs_attr3_rmt_verify_struct(186 struct xfs_buf *bp)187{188 xfs_failaddr_t fa;189 int error;190 191 error = __xfs_attr3_rmt_read_verify(bp, false, &fa);192 return error ? fa : NULL;193}194 195static void196xfs_attr3_rmt_write_verify(197 struct xfs_buf *bp)198{199 struct xfs_mount *mp = bp->b_mount;200 xfs_failaddr_t fa;201 unsigned int blksize = mp->m_attr_geo->blksize;202 char *ptr;203 int len;204 xfs_daddr_t bno;205 206 /* no verification of non-crc buffers */207 if (!xfs_has_crc(mp))208 return;209 210 ptr = bp->b_addr;211 bno = xfs_buf_daddr(bp);212 len = BBTOB(bp->b_length);213 ASSERT(len >= blksize);214 215 while (len > 0) {216 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;217 218 fa = xfs_attr3_rmt_verify(mp, bp, ptr, bno);219 if (fa) {220 xfs_verifier_error(bp, -EFSCORRUPTED, fa);221 return;222 }223 224 /*225 * Ensure we aren't writing bogus LSNs to disk. See226 * xfs_attr3_rmt_hdr_set() for the explanation.227 */228 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {229 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);230 return;231 }232 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);233 234 len -= blksize;235 ptr += blksize;236 bno += BTOBB(blksize);237 }238 239 if (len != 0)240 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);241}242 243const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {244 .name = "xfs_attr3_rmt",245 .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },246 .verify_read = xfs_attr3_rmt_read_verify,247 .verify_write = xfs_attr3_rmt_write_verify,248 .verify_struct = xfs_attr3_rmt_verify_struct,249};250 251STATIC int252xfs_attr3_rmt_hdr_set(253 struct xfs_mount *mp,254 void *ptr,255 xfs_ino_t ino,256 uint32_t offset,257 uint32_t size,258 xfs_daddr_t bno)259{260 struct xfs_attr3_rmt_hdr *rmt = ptr;261 262 if (!xfs_has_crc(mp))263 return 0;264 265 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);266 rmt->rm_offset = cpu_to_be32(offset);267 rmt->rm_bytes = cpu_to_be32(size);268 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);269 rmt->rm_owner = cpu_to_be64(ino);270 rmt->rm_blkno = cpu_to_be64(bno);271 272 /*273 * Remote attribute blocks are written synchronously, so we don't274 * have an LSN that we can stamp in them that makes any sense to log275 * recovery. To ensure that log recovery handles overwrites of these276 * blocks sanely (i.e. once they've been freed and reallocated as some277 * other type of metadata) we need to ensure that the LSN has a value278 * that tells log recovery to ignore the LSN and overwrite the buffer279 * with whatever is in it's log. To do this, we use the magic280 * NULLCOMMITLSN to indicate that the LSN is invalid.281 */282 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);283 284 return sizeof(struct xfs_attr3_rmt_hdr);285}286 287/*288 * Helper functions to copy attribute data in and out of the one disk extents289 */290STATIC int291xfs_attr_rmtval_copyout(292 struct xfs_mount *mp,293 struct xfs_buf *bp,294 struct xfs_inode *dp,295 xfs_ino_t owner,296 unsigned int *offset,297 unsigned int *valuelen,298 uint8_t **dst)299{300 char *src = bp->b_addr;301 xfs_daddr_t bno = xfs_buf_daddr(bp);302 unsigned int len = BBTOB(bp->b_length);303 unsigned int blksize = mp->m_attr_geo->blksize;304 305 ASSERT(len >= blksize);306 307 while (len > 0 && *valuelen > 0) {308 unsigned int hdr_size = 0;309 unsigned int byte_cnt = xfs_attr3_rmt_buf_space(mp);310 311 byte_cnt = min(*valuelen, byte_cnt);312 313 if (xfs_has_crc(mp)) {314 if (xfs_attr3_rmt_hdr_ok(src, owner, *offset,315 byte_cnt, bno)) {316 xfs_alert(mp,317"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",318 bno, *offset, byte_cnt, owner);319 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);320 return -EFSCORRUPTED;321 }322 hdr_size = sizeof(struct xfs_attr3_rmt_hdr);323 }324 325 memcpy(*dst, src + hdr_size, byte_cnt);326 327 /* roll buffer forwards */328 len -= blksize;329 src += blksize;330 bno += BTOBB(blksize);331 332 /* roll attribute data forwards */333 *valuelen -= byte_cnt;334 *dst += byte_cnt;335 *offset += byte_cnt;336 }337 return 0;338}339 340STATIC void341xfs_attr_rmtval_copyin(342 struct xfs_mount *mp,343 struct xfs_buf *bp,344 xfs_ino_t ino,345 unsigned int *offset,346 unsigned int *valuelen,347 uint8_t **src)348{349 char *dst = bp->b_addr;350 xfs_daddr_t bno = xfs_buf_daddr(bp);351 unsigned int len = BBTOB(bp->b_length);352 unsigned int blksize = mp->m_attr_geo->blksize;353 354 ASSERT(len >= blksize);355 356 while (len > 0 && *valuelen > 0) {357 unsigned int hdr_size;358 unsigned int byte_cnt = xfs_attr3_rmt_buf_space(mp);359 360 byte_cnt = min(*valuelen, byte_cnt);361 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,362 byte_cnt, bno);363 364 memcpy(dst + hdr_size, *src, byte_cnt);365 366 /*367 * If this is the last block, zero the remainder of it.368 * Check that we are actually the last block, too.369 */370 if (byte_cnt + hdr_size < blksize) {371 ASSERT(*valuelen - byte_cnt == 0);372 ASSERT(len == blksize);373 memset(dst + hdr_size + byte_cnt, 0,374 blksize - hdr_size - byte_cnt);375 }376 377 /* roll buffer forwards */378 len -= blksize;379 dst += blksize;380 bno += BTOBB(blksize);381 382 /* roll attribute data forwards */383 *valuelen -= byte_cnt;384 *src += byte_cnt;385 *offset += byte_cnt;386 }387}388 389/*390 * Read the value associated with an attribute from the out-of-line buffer391 * that we stored it in.392 *393 * Returns 0 on successful retrieval, otherwise an error.394 */395int396xfs_attr_rmtval_get(397 struct xfs_da_args *args)398{399 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];400 struct xfs_mount *mp = args->dp->i_mount;401 struct xfs_buf *bp;402 xfs_dablk_t lblkno = args->rmtblkno;403 uint8_t *dst = args->value;404 unsigned int valuelen;405 int nmap;406 int error;407 unsigned int blkcnt = args->rmtblkcnt;408 int i;409 unsigned int offset = 0;410 411 trace_xfs_attr_rmtval_get(args);412 413 ASSERT(args->valuelen != 0);414 ASSERT(args->rmtvaluelen == args->valuelen);415 416 valuelen = args->rmtvaluelen;417 while (valuelen > 0) {418 nmap = ATTR_RMTVALUE_MAPSIZE;419 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,420 blkcnt, map, &nmap,421 XFS_BMAPI_ATTRFORK);422 if (error)423 return error;424 ASSERT(nmap >= 1);425 426 for (i = 0; (i < nmap) && (valuelen > 0); i++) {427 xfs_daddr_t dblkno;428 int dblkcnt;429 430 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&431 (map[i].br_startblock != HOLESTARTBLOCK));432 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);433 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);434 error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,435 0, &bp, &xfs_attr3_rmt_buf_ops);436 if (xfs_metadata_is_sick(error))437 xfs_dirattr_mark_sick(args->dp, XFS_ATTR_FORK);438 if (error)439 return error;440 441 error = xfs_attr_rmtval_copyout(mp, bp, args->dp,442 args->owner, &offset, &valuelen, &dst);443 xfs_buf_relse(bp);444 if (error)445 return error;446 447 /* roll attribute extent map forwards */448 lblkno += map[i].br_blockcount;449 blkcnt -= map[i].br_blockcount;450 }451 }452 ASSERT(valuelen == 0);453 return 0;454}455 456/*457 * Find a "hole" in the attribute address space large enough for us to drop the458 * new attributes value into459 */460int461xfs_attr_rmt_find_hole(462 struct xfs_da_args *args)463{464 struct xfs_inode *dp = args->dp;465 struct xfs_mount *mp = dp->i_mount;466 int error;467 unsigned int blkcnt;468 xfs_fileoff_t lfileoff = 0;469 470 /*471 * Because CRC enable attributes have headers, we can't just do a472 * straight byte to FSB conversion and have to take the header space473 * into account.474 */475 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);476 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,477 XFS_ATTR_FORK);478 if (error)479 return error;480 481 args->rmtblkno = (xfs_dablk_t)lfileoff;482 args->rmtblkcnt = blkcnt;483 484 return 0;485}486 487int488xfs_attr_rmtval_set_value(489 struct xfs_da_args *args)490{491 struct xfs_inode *dp = args->dp;492 struct xfs_mount *mp = dp->i_mount;493 struct xfs_bmbt_irec map;494 xfs_dablk_t lblkno;495 uint8_t *src = args->value;496 unsigned int blkcnt;497 unsigned int valuelen;498 int nmap;499 int error;500 unsigned int offset = 0;501 502 /*503 * Roll through the "value", copying the attribute value to the504 * already-allocated blocks. Blocks are written synchronously505 * so that we can know they are all on disk before we turn off506 * the INCOMPLETE flag.507 */508 lblkno = args->rmtblkno;509 blkcnt = args->rmtblkcnt;510 valuelen = args->rmtvaluelen;511 while (valuelen > 0) {512 struct xfs_buf *bp;513 xfs_daddr_t dblkno;514 int dblkcnt;515 516 ASSERT(blkcnt > 0);517 518 nmap = 1;519 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,520 blkcnt, &map, &nmap,521 XFS_BMAPI_ATTRFORK);522 if (error)523 return error;524 ASSERT(nmap == 1);525 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&526 (map.br_startblock != HOLESTARTBLOCK));527 528 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),529 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);530 531 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);532 if (error)533 return error;534 bp->b_ops = &xfs_attr3_rmt_buf_ops;535 536 xfs_attr_rmtval_copyin(mp, bp, args->owner, &offset, &valuelen,537 &src);538 539 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */540 xfs_buf_relse(bp);541 if (error)542 return error;543 544 545 /* roll attribute extent map forwards */546 lblkno += map.br_blockcount;547 blkcnt -= map.br_blockcount;548 }549 ASSERT(valuelen == 0);550 return 0;551}552 553/* Mark stale any incore buffers for the remote value. */554int555xfs_attr_rmtval_stale(556 struct xfs_inode *ip,557 struct xfs_bmbt_irec *map,558 xfs_buf_flags_t incore_flags)559{560 struct xfs_mount *mp = ip->i_mount;561 struct xfs_buf *bp;562 int error;563 564 xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);565 566 if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||567 XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK)) {568 xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);569 return -EFSCORRUPTED;570 }571 572 error = xfs_buf_incore(mp->m_ddev_targp,573 XFS_FSB_TO_DADDR(mp, map->br_startblock),574 XFS_FSB_TO_BB(mp, map->br_blockcount),575 incore_flags, &bp);576 if (error) {577 if (error == -ENOENT)578 return 0;579 return error;580 }581 582 xfs_buf_stale(bp);583 xfs_buf_relse(bp);584 return 0;585}586 587/*588 * Find a hole for the attr and store it in the delayed attr context. This589 * initializes the context to roll through allocating an attr extent for a590 * delayed attr operation591 */592int593xfs_attr_rmtval_find_space(594 struct xfs_attr_intent *attr)595{596 struct xfs_da_args *args = attr->xattri_da_args;597 struct xfs_bmbt_irec *map = &attr->xattri_map;598 int error;599 600 attr->xattri_lblkno = 0;601 attr->xattri_blkcnt = 0;602 args->rmtblkcnt = 0;603 args->rmtblkno = 0;604 memset(map, 0, sizeof(struct xfs_bmbt_irec));605 606 error = xfs_attr_rmt_find_hole(args);607 if (error)608 return error;609 610 attr->xattri_blkcnt = args->rmtblkcnt;611 attr->xattri_lblkno = args->rmtblkno;612 613 return 0;614}615 616/*617 * Write one block of the value associated with an attribute into the618 * out-of-line buffer that we have defined for it. This is similar to a subset619 * of xfs_attr_rmtval_set, but records the current block to the delayed attr620 * context, and leaves transaction handling to the caller.621 */622int623xfs_attr_rmtval_set_blk(624 struct xfs_attr_intent *attr)625{626 struct xfs_da_args *args = attr->xattri_da_args;627 struct xfs_inode *dp = args->dp;628 struct xfs_bmbt_irec *map = &attr->xattri_map;629 int nmap;630 int error;631 632 nmap = 1;633 error = xfs_bmapi_write(args->trans, dp,634 (xfs_fileoff_t)attr->xattri_lblkno,635 attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,636 map, &nmap);637 if (error)638 return error;639 640 ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&641 (map->br_startblock != HOLESTARTBLOCK));642 643 /* roll attribute extent map forwards */644 attr->xattri_lblkno += map->br_blockcount;645 attr->xattri_blkcnt -= map->br_blockcount;646 647 return 0;648}649 650/*651 * Remove the value associated with an attribute by deleting the652 * out-of-line buffer that it is stored on.653 */654int655xfs_attr_rmtval_invalidate(656 struct xfs_da_args *args)657{658 xfs_dablk_t lblkno;659 unsigned int blkcnt;660 int error;661 662 /*663 * Roll through the "value", invalidating the attribute value's blocks.664 */665 lblkno = args->rmtblkno;666 blkcnt = args->rmtblkcnt;667 while (blkcnt > 0) {668 struct xfs_bmbt_irec map;669 int nmap;670 671 /*672 * Try to remember where we decided to put the value.673 */674 nmap = 1;675 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,676 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);677 if (error)678 return error;679 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1)) {680 xfs_bmap_mark_sick(args->dp, XFS_ATTR_FORK);681 return -EFSCORRUPTED;682 }683 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);684 if (error)685 return error;686 687 lblkno += map.br_blockcount;688 blkcnt -= map.br_blockcount;689 }690 return 0;691}692 693/*694 * Remove the value associated with an attribute by deleting the out-of-line695 * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the696 * transaction and re-call the function. Callers should keep calling this697 * routine until it returns something other than -EAGAIN.698 */699int700xfs_attr_rmtval_remove(701 struct xfs_attr_intent *attr)702{703 struct xfs_da_args *args = attr->xattri_da_args;704 int error, done;705 706 /*707 * Unmap value blocks for this attr.708 */709 error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,710 args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);711 if (error)712 return error;713 714 /*715 * We don't need an explicit state here to pick up where we left off. We716 * can figure it out using the !done return code. The actual value of717 * attr->xattri_dela_state may be some value reminiscent of the calling718 * function, but it's value is irrelevant with in the context of this719 * function. Once we are done here, the next state is set as needed by720 * the parent721 */722 if (!done) {723 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,724 args->dp);725 return -EAGAIN;726 }727 728 args->rmtblkno = 0;729 args->rmtblkcnt = 0;730 return 0;731}732