Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-linus-v3.10-rc4-crc-xattr-fixes' of git://oss.sgi.com/xfs/xfs

Pull xfs extended attribute fixes for CRCs from Ben Myers:
"Here are several fixes that are relevant on CRC enabled XFS
filesystems. They are followed by a rework of the remote attribute
code so that each block of the attribute contains a header with a CRC.

Previously there was a CRC header per extent in the remote attribute
code, but this was untenable because it was not possible to know how
many extents would be allocated for the attribute until after the
allocation has completed, due to the fragmentation of free space.
This became complicated because the size of the headers needs to be
added to the length of the payload to get the overall length required
for the allocation. With a header per block, things are less
complicated at the cost of a little space.

I would have preferred to defer this and the rest of the CRC queue to
3.11 to mitigate risk for existing non-crc users in 3.10. Doing so
would require setting a feature bit for the on-disk changes, and so I
have been pressured into sending this pull request by Eric Sandeen and
David Chinner from Red Hat. I'll send another pull request or two
with the rest of the CRC queue next week.

- Remove assert on count of remote attribute CRC headers
- Fix the number of blocks read in for remote attributes
- Zero remote attribute tails properly
- Fix mapping of remote attribute buffers to have correct length
- initialize temp leaf properly in xfs_attr3_leaf_unbalance, and
xfs_attr3_leaf_compact
- Rework remote atttributes to have a header per block"

* tag 'for-linus-v3.10-rc4-crc-xattr-fixes' of git://oss.sgi.com/xfs/xfs:
xfs: rework remote attr CRCs
xfs: fully initialise temp leaf in xfs_attr3_leaf_compact
xfs: fully initialise temp leaf in xfs_attr3_leaf_unbalance
xfs: correctly map remote attr buffers during removal
xfs: remote attribute tail zeroing does too much
xfs: remote attribute read too short
xfs: remote attribute allocation may be contiguous

+307 -183
+47 -24
fs/xfs/xfs_attr_leaf.c
··· 1412 1412 name_rmt->valuelen = 0; 1413 1413 name_rmt->valueblk = 0; 1414 1414 args->rmtblkno = 1; 1415 - args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); 1415 + args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); 1416 1416 } 1417 1417 xfs_trans_log_buf(args->trans, bp, 1418 1418 XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), ··· 1445 1445 STATIC void 1446 1446 xfs_attr3_leaf_compact( 1447 1447 struct xfs_da_args *args, 1448 - struct xfs_attr3_icleaf_hdr *ichdr_d, 1448 + struct xfs_attr3_icleaf_hdr *ichdr_dst, 1449 1449 struct xfs_buf *bp) 1450 1450 { 1451 - xfs_attr_leafblock_t *leaf_s, *leaf_d; 1452 - struct xfs_attr3_icleaf_hdr ichdr_s; 1451 + struct xfs_attr_leafblock *leaf_src; 1452 + struct xfs_attr_leafblock *leaf_dst; 1453 + struct xfs_attr3_icleaf_hdr ichdr_src; 1453 1454 struct xfs_trans *trans = args->trans; 1454 1455 struct xfs_mount *mp = trans->t_mountp; 1455 1456 char *tmpbuffer; ··· 1458 1457 trace_xfs_attr_leaf_compact(args); 1459 1458 1460 1459 tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); 1461 - ASSERT(tmpbuffer != NULL); 1462 1460 memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp)); 1463 1461 memset(bp->b_addr, 0, XFS_LBSIZE(mp)); 1462 + leaf_src = (xfs_attr_leafblock_t *)tmpbuffer; 1463 + leaf_dst = bp->b_addr; 1464 1464 1465 1465 /* 1466 - * Copy basic information 1466 + * Copy the on-disk header back into the destination buffer to ensure 1467 + * all the information in the header that is not part of the incore 1468 + * header structure is preserved. 1467 1469 */ 1468 - leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; 1469 - leaf_d = bp->b_addr; 1470 - ichdr_s = *ichdr_d; /* struct copy */ 1471 - ichdr_d->firstused = XFS_LBSIZE(mp); 1472 - ichdr_d->usedbytes = 0; 1473 - ichdr_d->count = 0; 1474 - ichdr_d->holes = 0; 1475 - ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_s); 1476 - ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base; 1470 + memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src)); 1471 + 1472 + /* Initialise the incore headers */ 1473 + ichdr_src = *ichdr_dst; /* struct copy */ 1474 + ichdr_dst->firstused = XFS_LBSIZE(mp); 1475 + ichdr_dst->usedbytes = 0; 1476 + ichdr_dst->count = 0; 1477 + ichdr_dst->holes = 0; 1478 + ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src); 1479 + ichdr_dst->freemap[0].size = ichdr_dst->firstused - 1480 + ichdr_dst->freemap[0].base; 1481 + 1482 + 1483 + /* write the header back to initialise the underlying buffer */ 1484 + xfs_attr3_leaf_hdr_to_disk(leaf_dst, ichdr_dst); 1477 1485 1478 1486 /* 1479 1487 * Copy all entry's in the same (sorted) order, 1480 1488 * but allocate name/value pairs packed and in sequence. 1481 1489 */ 1482 - xfs_attr3_leaf_moveents(leaf_s, &ichdr_s, 0, leaf_d, ichdr_d, 0, 1483 - ichdr_s.count, mp); 1490 + xfs_attr3_leaf_moveents(leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0, 1491 + ichdr_src.count, mp); 1484 1492 /* 1485 1493 * this logs the entire buffer, but the caller must write the header 1486 1494 * back to the buffer when it is finished modifying it. ··· 2191 2181 struct xfs_attr_leafblock *tmp_leaf; 2192 2182 struct xfs_attr3_icleaf_hdr tmphdr; 2193 2183 2194 - tmp_leaf = kmem_alloc(state->blocksize, KM_SLEEP); 2195 - memset(tmp_leaf, 0, state->blocksize); 2196 - memset(&tmphdr, 0, sizeof(tmphdr)); 2184 + tmp_leaf = kmem_zalloc(state->blocksize, KM_SLEEP); 2197 2185 2186 + /* 2187 + * Copy the header into the temp leaf so that all the stuff 2188 + * not in the incore header is present and gets copied back in 2189 + * once we've moved all the entries. 2190 + */ 2191 + memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf)); 2192 + 2193 + memset(&tmphdr, 0, sizeof(tmphdr)); 2198 2194 tmphdr.magic = savehdr.magic; 2199 2195 tmphdr.forw = savehdr.forw; 2200 2196 tmphdr.back = savehdr.back; 2201 2197 tmphdr.firstused = state->blocksize; 2198 + 2199 + /* write the header to the temp buffer to initialise it */ 2200 + xfs_attr3_leaf_hdr_to_disk(tmp_leaf, &tmphdr); 2201 + 2202 2202 if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, 2203 2203 drop_blk->bp, &drophdr)) { 2204 2204 xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0, ··· 2354 2334 args->index = probe; 2355 2335 args->valuelen = be32_to_cpu(name_rmt->valuelen); 2356 2336 args->rmtblkno = be32_to_cpu(name_rmt->valueblk); 2357 - args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, 2358 - args->valuelen); 2337 + args->rmtblkcnt = xfs_attr3_rmt_blocks( 2338 + args->dp->i_mount, 2339 + args->valuelen); 2359 2340 return XFS_ERROR(EEXIST); 2360 2341 } 2361 2342 } ··· 2407 2386 ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0); 2408 2387 valuelen = be32_to_cpu(name_rmt->valuelen); 2409 2388 args->rmtblkno = be32_to_cpu(name_rmt->valueblk); 2410 - args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen); 2389 + args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount, 2390 + valuelen); 2411 2391 if (args->flags & ATTR_KERNOVAL) { 2412 2392 args->valuelen = valuelen; 2413 2393 return 0; ··· 2734 2712 args.valuelen = valuelen; 2735 2713 args.value = kmem_alloc(valuelen, KM_SLEEP | KM_NOFS); 2736 2714 args.rmtblkno = be32_to_cpu(name_rmt->valueblk); 2737 - args.rmtblkcnt = XFS_B_TO_FSB(args.dp->i_mount, valuelen); 2715 + args.rmtblkcnt = xfs_attr3_rmt_blocks( 2716 + args.dp->i_mount, valuelen); 2738 2717 retval = xfs_attr_rmtval_get(&args); 2739 2718 if (retval) 2740 2719 return retval;
+249 -159
fs/xfs/xfs_attr_remote.c
··· 47 47 * Each contiguous block has a header, so it is not just a simple attribute 48 48 * length to FSB conversion. 49 49 */ 50 - static int 50 + int 51 51 xfs_attr3_rmt_blocks( 52 52 struct xfs_mount *mp, 53 53 int attrlen) 54 54 { 55 - int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, 56 - mp->m_sb.sb_blocksize); 57 - return (attrlen + buflen - 1) / buflen; 55 + if (xfs_sb_version_hascrc(&mp->m_sb)) { 56 + int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); 57 + return (attrlen + buflen - 1) / buflen; 58 + } 59 + return XFS_B_TO_FSB(mp, attrlen); 60 + } 61 + 62 + /* 63 + * Checking of the remote attribute header is split into two parts. The verifier 64 + * does CRC, location and bounds checking, the unpacking function checks the 65 + * attribute parameters and owner. 66 + */ 67 + static bool 68 + xfs_attr3_rmt_hdr_ok( 69 + struct xfs_mount *mp, 70 + void *ptr, 71 + xfs_ino_t ino, 72 + uint32_t offset, 73 + uint32_t size, 74 + xfs_daddr_t bno) 75 + { 76 + struct xfs_attr3_rmt_hdr *rmt = ptr; 77 + 78 + if (bno != be64_to_cpu(rmt->rm_blkno)) 79 + return false; 80 + if (offset != be32_to_cpu(rmt->rm_offset)) 81 + return false; 82 + if (size != be32_to_cpu(rmt->rm_bytes)) 83 + return false; 84 + if (ino != be64_to_cpu(rmt->rm_owner)) 85 + return false; 86 + 87 + /* ok */ 88 + return true; 58 89 } 59 90 60 91 static bool 61 92 xfs_attr3_rmt_verify( 62 - struct xfs_buf *bp) 93 + struct xfs_mount *mp, 94 + void *ptr, 95 + int fsbsize, 96 + xfs_daddr_t bno) 63 97 { 64 - struct xfs_mount *mp = bp->b_target->bt_mount; 65 - struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; 98 + struct xfs_attr3_rmt_hdr *rmt = ptr; 66 99 67 100 if (!xfs_sb_version_hascrc(&mp->m_sb)) 68 101 return false; ··· 103 70 return false; 104 71 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid)) 105 72 return false; 106 - if (bp->b_bn != be64_to_cpu(rmt->rm_blkno)) 73 + if (be64_to_cpu(rmt->rm_blkno) != bno) 74 + return false; 75 + if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) 107 76 return false; 108 77 if (be32_to_cpu(rmt->rm_offset) + 109 78 be32_to_cpu(rmt->rm_bytes) >= XATTR_SIZE_MAX) ··· 121 86 struct xfs_buf *bp) 122 87 { 123 88 struct xfs_mount *mp = bp->b_target->bt_mount; 89 + char *ptr; 90 + int len; 91 + bool corrupt = false; 92 + xfs_daddr_t bno; 124 93 125 94 /* no verification of non-crc buffers */ 126 95 if (!xfs_sb_version_hascrc(&mp->m_sb)) 127 96 return; 128 97 129 - if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), 130 - XFS_ATTR3_RMT_CRC_OFF) || 131 - !xfs_attr3_rmt_verify(bp)) { 98 + ptr = bp->b_addr; 99 + bno = bp->b_bn; 100 + len = BBTOB(bp->b_length); 101 + ASSERT(len >= XFS_LBSIZE(mp)); 102 + 103 + while (len > 0) { 104 + if (!xfs_verify_cksum(ptr, XFS_LBSIZE(mp), 105 + XFS_ATTR3_RMT_CRC_OFF)) { 106 + corrupt = true; 107 + break; 108 + } 109 + if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) { 110 + corrupt = true; 111 + break; 112 + } 113 + len -= XFS_LBSIZE(mp); 114 + ptr += XFS_LBSIZE(mp); 115 + bno += mp->m_bsize; 116 + } 117 + 118 + if (corrupt) { 132 119 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); 133 120 xfs_buf_ioerror(bp, EFSCORRUPTED); 134 - } 121 + } else 122 + ASSERT(len == 0); 135 123 } 136 124 137 125 static void ··· 163 105 { 164 106 struct xfs_mount *mp = bp->b_target->bt_mount; 165 107 struct xfs_buf_log_item *bip = bp->b_fspriv; 108 + char *ptr; 109 + int len; 110 + xfs_daddr_t bno; 166 111 167 112 /* no verification of non-crc buffers */ 168 113 if (!xfs_sb_version_hascrc(&mp->m_sb)) 169 114 return; 170 115 171 - if (!xfs_attr3_rmt_verify(bp)) { 172 - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); 173 - xfs_buf_ioerror(bp, EFSCORRUPTED); 174 - return; 175 - } 116 + ptr = bp->b_addr; 117 + bno = bp->b_bn; 118 + len = BBTOB(bp->b_length); 119 + ASSERT(len >= XFS_LBSIZE(mp)); 176 120 177 - if (bip) { 178 - struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; 179 - rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn); 121 + while (len > 0) { 122 + if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) { 123 + XFS_CORRUPTION_ERROR(__func__, 124 + XFS_ERRLEVEL_LOW, mp, bp->b_addr); 125 + xfs_buf_ioerror(bp, EFSCORRUPTED); 126 + return; 127 + } 128 + if (bip) { 129 + struct xfs_attr3_rmt_hdr *rmt; 130 + 131 + rmt = (struct xfs_attr3_rmt_hdr *)ptr; 132 + rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn); 133 + } 134 + xfs_update_cksum(ptr, XFS_LBSIZE(mp), XFS_ATTR3_RMT_CRC_OFF); 135 + 136 + len -= XFS_LBSIZE(mp); 137 + ptr += XFS_LBSIZE(mp); 138 + bno += mp->m_bsize; 180 139 } 181 - xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), 182 - XFS_ATTR3_RMT_CRC_OFF); 140 + ASSERT(len == 0); 183 141 } 184 142 185 143 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { ··· 203 129 .verify_write = xfs_attr3_rmt_write_verify, 204 130 }; 205 131 206 - static int 132 + STATIC int 207 133 xfs_attr3_rmt_hdr_set( 208 134 struct xfs_mount *mp, 135 + void *ptr, 209 136 xfs_ino_t ino, 210 137 uint32_t offset, 211 138 uint32_t size, 212 - struct xfs_buf *bp) 139 + xfs_daddr_t bno) 213 140 { 214 - struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; 141 + struct xfs_attr3_rmt_hdr *rmt = ptr; 215 142 216 143 if (!xfs_sb_version_hascrc(&mp->m_sb)) 217 144 return 0; ··· 222 147 rmt->rm_bytes = cpu_to_be32(size); 223 148 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid); 224 149 rmt->rm_owner = cpu_to_be64(ino); 225 - rmt->rm_blkno = cpu_to_be64(bp->b_bn); 226 - bp->b_ops = &xfs_attr3_rmt_buf_ops; 150 + rmt->rm_blkno = cpu_to_be64(bno); 227 151 228 152 return sizeof(struct xfs_attr3_rmt_hdr); 229 153 } 230 154 231 155 /* 232 - * Checking of the remote attribute header is split into two parts. the verifier 233 - * does CRC, location and bounds checking, the unpacking function checks the 234 - * attribute parameters and owner. 156 + * Helper functions to copy attribute data in and out of the one disk extents 235 157 */ 236 - static bool 237 - xfs_attr3_rmt_hdr_ok( 238 - struct xfs_mount *mp, 239 - xfs_ino_t ino, 240 - uint32_t offset, 241 - uint32_t size, 242 - struct xfs_buf *bp) 158 + STATIC int 159 + xfs_attr_rmtval_copyout( 160 + struct xfs_mount *mp, 161 + struct xfs_buf *bp, 162 + xfs_ino_t ino, 163 + int *offset, 164 + int *valuelen, 165 + char **dst) 243 166 { 244 - struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; 167 + char *src = bp->b_addr; 168 + xfs_daddr_t bno = bp->b_bn; 169 + int len = BBTOB(bp->b_length); 245 170 246 - if (offset != be32_to_cpu(rmt->rm_offset)) 247 - return false; 248 - if (size != be32_to_cpu(rmt->rm_bytes)) 249 - return false; 250 - if (ino != be64_to_cpu(rmt->rm_owner)) 251 - return false; 171 + ASSERT(len >= XFS_LBSIZE(mp)); 252 172 253 - /* ok */ 254 - return true; 173 + while (len > 0 && *valuelen > 0) { 174 + int hdr_size = 0; 175 + int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp)); 176 + 177 + byte_cnt = min_t(int, *valuelen, byte_cnt); 178 + 179 + if (xfs_sb_version_hascrc(&mp->m_sb)) { 180 + if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset, 181 + byte_cnt, bno)) { 182 + xfs_alert(mp, 183 + "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", 184 + bno, *offset, byte_cnt, ino); 185 + return EFSCORRUPTED; 186 + } 187 + hdr_size = sizeof(struct xfs_attr3_rmt_hdr); 188 + } 189 + 190 + memcpy(*dst, src + hdr_size, byte_cnt); 191 + 192 + /* roll buffer forwards */ 193 + len -= XFS_LBSIZE(mp); 194 + src += XFS_LBSIZE(mp); 195 + bno += mp->m_bsize; 196 + 197 + /* roll attribute data forwards */ 198 + *valuelen -= byte_cnt; 199 + *dst += byte_cnt; 200 + *offset += byte_cnt; 201 + } 202 + return 0; 203 + } 204 + 205 + STATIC void 206 + xfs_attr_rmtval_copyin( 207 + struct xfs_mount *mp, 208 + struct xfs_buf *bp, 209 + xfs_ino_t ino, 210 + int *offset, 211 + int *valuelen, 212 + char **src) 213 + { 214 + char *dst = bp->b_addr; 215 + xfs_daddr_t bno = bp->b_bn; 216 + int len = BBTOB(bp->b_length); 217 + 218 + ASSERT(len >= XFS_LBSIZE(mp)); 219 + 220 + while (len > 0 && *valuelen > 0) { 221 + int hdr_size; 222 + int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp)); 223 + 224 + byte_cnt = min(*valuelen, byte_cnt); 225 + hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, 226 + byte_cnt, bno); 227 + 228 + memcpy(dst + hdr_size, *src, byte_cnt); 229 + 230 + /* 231 + * If this is the last block, zero the remainder of it. 232 + * Check that we are actually the last block, too. 233 + */ 234 + if (byte_cnt + hdr_size < XFS_LBSIZE(mp)) { 235 + ASSERT(*valuelen - byte_cnt == 0); 236 + ASSERT(len == XFS_LBSIZE(mp)); 237 + memset(dst + hdr_size + byte_cnt, 0, 238 + XFS_LBSIZE(mp) - hdr_size - byte_cnt); 239 + } 240 + 241 + /* roll buffer forwards */ 242 + len -= XFS_LBSIZE(mp); 243 + dst += XFS_LBSIZE(mp); 244 + bno += mp->m_bsize; 245 + 246 + /* roll attribute data forwards */ 247 + *valuelen -= byte_cnt; 248 + *src += byte_cnt; 249 + *offset += byte_cnt; 250 + } 255 251 } 256 252 257 253 /* ··· 336 190 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; 337 191 struct xfs_mount *mp = args->dp->i_mount; 338 192 struct xfs_buf *bp; 339 - xfs_daddr_t dblkno; 340 193 xfs_dablk_t lblkno = args->rmtblkno; 341 - void *dst = args->value; 194 + char *dst = args->value; 342 195 int valuelen = args->valuelen; 343 196 int nmap; 344 197 int error; 345 - int blkcnt; 198 + int blkcnt = args->rmtblkcnt; 346 199 int i; 347 200 int offset = 0; 348 201 ··· 352 207 while (valuelen > 0) { 353 208 nmap = ATTR_RMTVALUE_MAPSIZE; 354 209 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 355 - args->rmtblkcnt, map, &nmap, 210 + blkcnt, map, &nmap, 356 211 XFS_BMAPI_ATTRFORK); 357 212 if (error) 358 213 return error; 359 214 ASSERT(nmap >= 1); 360 215 361 216 for (i = 0; (i < nmap) && (valuelen > 0); i++) { 362 - int byte_cnt; 363 - char *src; 217 + xfs_daddr_t dblkno; 218 + int dblkcnt; 364 219 365 220 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && 366 221 (map[i].br_startblock != HOLESTARTBLOCK)); 367 222 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); 368 - blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 223 + dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 369 224 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, 370 - dblkno, blkcnt, 0, &bp, 225 + dblkno, dblkcnt, 0, &bp, 371 226 &xfs_attr3_rmt_buf_ops); 372 227 if (error) 373 228 return error; 374 229 375 - byte_cnt = min_t(int, valuelen, BBTOB(bp->b_length)); 376 - byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt); 377 - 378 - src = bp->b_addr; 379 - if (xfs_sb_version_hascrc(&mp->m_sb)) { 380 - if (!xfs_attr3_rmt_hdr_ok(mp, args->dp->i_ino, 381 - offset, byte_cnt, bp)) { 382 - xfs_alert(mp, 383 - "remote attribute header does not match required off/len/owner (0x%x/Ox%x,0x%llx)", 384 - offset, byte_cnt, args->dp->i_ino); 385 - xfs_buf_relse(bp); 386 - return EFSCORRUPTED; 387 - 388 - } 389 - 390 - src += sizeof(struct xfs_attr3_rmt_hdr); 391 - } 392 - 393 - memcpy(dst, src, byte_cnt); 230 + error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, 231 + &offset, &valuelen, 232 + &dst); 394 233 xfs_buf_relse(bp); 234 + if (error) 235 + return error; 395 236 396 - offset += byte_cnt; 397 - dst += byte_cnt; 398 - valuelen -= byte_cnt; 399 - 237 + /* roll attribute extent map forwards */ 400 238 lblkno += map[i].br_blockcount; 239 + blkcnt -= map[i].br_blockcount; 401 240 } 402 241 } 403 242 ASSERT(valuelen == 0); ··· 399 270 struct xfs_inode *dp = args->dp; 400 271 struct xfs_mount *mp = dp->i_mount; 401 272 struct xfs_bmbt_irec map; 402 - struct xfs_buf *bp; 403 - xfs_daddr_t dblkno; 404 273 xfs_dablk_t lblkno; 405 274 xfs_fileoff_t lfileoff = 0; 406 - void *src = args->value; 275 + char *src = args->value; 407 276 int blkcnt; 408 277 int valuelen; 409 278 int nmap; 410 279 int error; 411 - int hdrcnt = 0; 412 - bool crcs = xfs_sb_version_hascrc(&mp->m_sb); 413 280 int offset = 0; 414 281 415 282 trace_xfs_attr_rmtval_set(args); ··· 414 289 * Find a "hole" in the attribute address space large enough for 415 290 * us to drop the new attribute's value into. Because CRC enable 416 291 * attributes have headers, we can't just do a straight byte to FSB 417 - * conversion. We calculate the worst case block count in this case 418 - * and we may not need that many, so we have to handle this when 419 - * allocating the blocks below. 292 + * conversion and have to take the header space into account. 420 293 */ 421 - if (!crcs) 422 - blkcnt = XFS_B_TO_FSB(mp, args->valuelen); 423 - else 424 - blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); 425 - 294 + blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); 426 295 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 427 296 XFS_ATTR_FORK); 428 297 if (error) 429 298 return error; 430 - 431 - /* Start with the attribute data. We'll allocate the rest afterwards. */ 432 - if (crcs) 433 - blkcnt = XFS_B_TO_FSB(mp, args->valuelen); 434 299 435 300 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; 436 301 args->rmtblkcnt = blkcnt; ··· 464 349 (map.br_startblock != HOLESTARTBLOCK)); 465 350 lblkno += map.br_blockcount; 466 351 blkcnt -= map.br_blockcount; 467 - hdrcnt++; 468 - 469 - /* 470 - * If we have enough blocks for the attribute data, calculate 471 - * how many extra blocks we need for headers. We might run 472 - * through this multiple times in the case that the additional 473 - * headers in the blocks needed for the data fragments spills 474 - * into requiring more blocks. e.g. for 512 byte blocks, we'll 475 - * spill for another block every 9 headers we require in this 476 - * loop. 477 - */ 478 - if (crcs && blkcnt == 0) { 479 - int total_len; 480 - 481 - total_len = args->valuelen + 482 - hdrcnt * sizeof(struct xfs_attr3_rmt_hdr); 483 - blkcnt = XFS_B_TO_FSB(mp, total_len); 484 - blkcnt -= args->rmtblkcnt; 485 - args->rmtblkcnt += blkcnt; 486 - } 487 352 488 353 /* 489 354 * Start the next trans in the chain. ··· 480 385 * the INCOMPLETE flag. 481 386 */ 482 387 lblkno = args->rmtblkno; 388 + blkcnt = args->rmtblkcnt; 483 389 valuelen = args->valuelen; 484 390 while (valuelen > 0) { 485 - int byte_cnt; 486 - char *buf; 391 + struct xfs_buf *bp; 392 + xfs_daddr_t dblkno; 393 + int dblkcnt; 487 394 488 - /* 489 - * Try to remember where we decided to put the value. 490 - */ 395 + ASSERT(blkcnt > 0); 396 + 491 397 xfs_bmap_init(args->flist, args->firstblock); 492 398 nmap = 1; 493 399 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, 494 - args->rmtblkcnt, &map, &nmap, 400 + blkcnt, &map, &nmap, 495 401 XFS_BMAPI_ATTRFORK); 496 402 if (error) 497 403 return(error); ··· 501 405 (map.br_startblock != HOLESTARTBLOCK)); 502 406 503 407 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 504 - blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 408 + dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 505 409 506 - bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); 410 + bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0); 507 411 if (!bp) 508 412 return ENOMEM; 509 413 bp->b_ops = &xfs_attr3_rmt_buf_ops; 510 414 511 - byte_cnt = BBTOB(bp->b_length); 512 - byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt); 513 - if (valuelen < byte_cnt) 514 - byte_cnt = valuelen; 515 - 516 - buf = bp->b_addr; 517 - buf += xfs_attr3_rmt_hdr_set(mp, dp->i_ino, offset, 518 - byte_cnt, bp); 519 - memcpy(buf, src, byte_cnt); 520 - 521 - if (byte_cnt < BBTOB(bp->b_length)) 522 - xfs_buf_zero(bp, byte_cnt, 523 - BBTOB(bp->b_length) - byte_cnt); 415 + xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, 416 + &valuelen, &src); 524 417 525 418 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ 526 419 xfs_buf_relse(bp); 527 420 if (error) 528 421 return error; 529 422 530 - src += byte_cnt; 531 - valuelen -= byte_cnt; 532 - offset += byte_cnt; 533 - hdrcnt--; 534 423 424 + /* roll attribute extent map forwards */ 535 425 lblkno += map.br_blockcount; 426 + blkcnt -= map.br_blockcount; 536 427 } 537 428 ASSERT(valuelen == 0); 538 - ASSERT(hdrcnt == 0); 539 429 return 0; 540 430 } 541 431 ··· 530 448 * out-of-line buffer that it is stored on. 531 449 */ 532 450 int 533 - xfs_attr_rmtval_remove(xfs_da_args_t *args) 451 + xfs_attr_rmtval_remove( 452 + struct xfs_da_args *args) 534 453 { 535 - xfs_mount_t *mp; 536 - xfs_bmbt_irec_t map; 537 - xfs_buf_t *bp; 538 - xfs_daddr_t dblkno; 539 - xfs_dablk_t lblkno; 540 - int valuelen, blkcnt, nmap, error, done, committed; 454 + struct xfs_mount *mp = args->dp->i_mount; 455 + xfs_dablk_t lblkno; 456 + int blkcnt; 457 + int error; 458 + int done; 541 459 542 460 trace_xfs_attr_rmtval_remove(args); 543 461 544 - mp = args->dp->i_mount; 545 - 546 462 /* 547 - * Roll through the "value", invalidating the attribute value's 548 - * blocks. 463 + * Roll through the "value", invalidating the attribute value's blocks. 464 + * Note that args->rmtblkcnt is the minimum number of data blocks we'll 465 + * see for a CRC enabled remote attribute. Each extent will have a 466 + * header, and so we may have more blocks than we realise here. If we 467 + * fail to map the blocks correctly, we'll have problems with the buffer 468 + * lookups. 549 469 */ 550 470 lblkno = args->rmtblkno; 551 - valuelen = args->rmtblkcnt; 552 - while (valuelen > 0) { 471 + blkcnt = args->rmtblkcnt; 472 + while (blkcnt > 0) { 473 + struct xfs_bmbt_irec map; 474 + struct xfs_buf *bp; 475 + xfs_daddr_t dblkno; 476 + int dblkcnt; 477 + int nmap; 478 + 553 479 /* 554 480 * Try to remember where we decided to put the value. 555 481 */ 556 482 nmap = 1; 557 483 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 558 - args->rmtblkcnt, &map, &nmap, 559 - XFS_BMAPI_ATTRFORK); 484 + blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); 560 485 if (error) 561 486 return(error); 562 487 ASSERT(nmap == 1); ··· 571 482 (map.br_startblock != HOLESTARTBLOCK)); 572 483 573 484 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 574 - blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 485 + dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 575 486 576 487 /* 577 488 * If the "remote" value is in the cache, remove it. 578 489 */ 579 - bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK); 490 + bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); 580 491 if (bp) { 581 492 xfs_buf_stale(bp); 582 493 xfs_buf_relse(bp); 583 494 bp = NULL; 584 495 } 585 496 586 - valuelen -= map.br_blockcount; 587 - 588 497 lblkno += map.br_blockcount; 498 + blkcnt -= map.br_blockcount; 589 499 } 590 500 591 501 /* ··· 594 506 blkcnt = args->rmtblkcnt; 595 507 done = 0; 596 508 while (!done) { 509 + int committed; 510 + 597 511 xfs_bmap_init(args->flist, args->firstblock); 598 512 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, 599 513 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
+10
fs/xfs/xfs_attr_remote.h
··· 20 20 21 21 #define XFS_ATTR3_RMT_MAGIC 0x5841524d /* XARM */ 22 22 23 + /* 24 + * There is one of these headers per filesystem block in a remote attribute. 25 + * This is done to ensure there is a 1:1 mapping between the attribute value 26 + * length and the number of blocks needed to store the attribute. This makes the 27 + * verification of a buffer a little more complex, but greatly simplifies the 28 + * allocation, reading and writing of these attributes as we don't have to guess 29 + * the number of blocks needed to store the attribute data. 30 + */ 23 31 struct xfs_attr3_rmt_hdr { 24 32 __be32 rm_magic; 25 33 __be32 rm_offset; ··· 46 38 sizeof(struct xfs_attr3_rmt_hdr) : 0)) 47 39 48 40 extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; 41 + 42 + int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen); 49 43 50 44 int xfs_attr_rmtval_get(struct xfs_da_args *args); 51 45 int xfs_attr_rmtval_set(struct xfs_da_args *args);
+1
fs/xfs/xfs_buf.c
··· 513 513 xfs_alert(btp->bt_mount, 514 514 "%s: Block out of range: block 0x%llx, EOFS 0x%llx ", 515 515 __func__, blkno, eofs); 516 + WARN_ON(1); 516 517 return NULL; 517 518 } 518 519