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.

at v3.15 626 lines 15 kB view raw
1/* 2 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 3 * Copyright (c) 2013 Red Hat, Inc. 4 * All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it would be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19#include "xfs.h" 20#include "xfs_fs.h" 21#include "xfs_shared.h" 22#include "xfs_format.h" 23#include "xfs_log_format.h" 24#include "xfs_trans_resv.h" 25#include "xfs_bit.h" 26#include "xfs_sb.h" 27#include "xfs_ag.h" 28#include "xfs_mount.h" 29#include "xfs_da_format.h" 30#include "xfs_da_btree.h" 31#include "xfs_inode.h" 32#include "xfs_alloc.h" 33#include "xfs_trans.h" 34#include "xfs_inode_item.h" 35#include "xfs_bmap.h" 36#include "xfs_bmap_util.h" 37#include "xfs_attr.h" 38#include "xfs_attr_leaf.h" 39#include "xfs_attr_remote.h" 40#include "xfs_trans_space.h" 41#include "xfs_trace.h" 42#include "xfs_cksum.h" 43#include "xfs_buf_item.h" 44#include "xfs_error.h" 45 46#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ 47 48/* 49 * Each contiguous block has a header, so it is not just a simple attribute 50 * length to FSB conversion. 51 */ 52int 53xfs_attr3_rmt_blocks( 54 struct xfs_mount *mp, 55 int attrlen) 56{ 57 if (xfs_sb_version_hascrc(&mp->m_sb)) { 58 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); 59 return (attrlen + buflen - 1) / buflen; 60 } 61 return XFS_B_TO_FSB(mp, attrlen); 62} 63 64/* 65 * Checking of the remote attribute header is split into two parts. The verifier 66 * does CRC, location and bounds checking, the unpacking function checks the 67 * attribute parameters and owner. 68 */ 69static bool 70xfs_attr3_rmt_hdr_ok( 71 struct xfs_mount *mp, 72 void *ptr, 73 xfs_ino_t ino, 74 uint32_t offset, 75 uint32_t size, 76 xfs_daddr_t bno) 77{ 78 struct xfs_attr3_rmt_hdr *rmt = ptr; 79 80 if (bno != be64_to_cpu(rmt->rm_blkno)) 81 return false; 82 if (offset != be32_to_cpu(rmt->rm_offset)) 83 return false; 84 if (size != be32_to_cpu(rmt->rm_bytes)) 85 return false; 86 if (ino != be64_to_cpu(rmt->rm_owner)) 87 return false; 88 89 /* ok */ 90 return true; 91} 92 93static bool 94xfs_attr3_rmt_verify( 95 struct xfs_mount *mp, 96 void *ptr, 97 int fsbsize, 98 xfs_daddr_t bno) 99{ 100 struct xfs_attr3_rmt_hdr *rmt = ptr; 101 102 if (!xfs_sb_version_hascrc(&mp->m_sb)) 103 return false; 104 if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) 105 return false; 106 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid)) 107 return false; 108 if (be64_to_cpu(rmt->rm_blkno) != bno) 109 return false; 110 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) 111 return false; 112 if (be32_to_cpu(rmt->rm_offset) + 113 be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX) 114 return false; 115 if (rmt->rm_owner == 0) 116 return false; 117 118 return true; 119} 120 121static void 122xfs_attr3_rmt_read_verify( 123 struct xfs_buf *bp) 124{ 125 struct xfs_mount *mp = bp->b_target->bt_mount; 126 char *ptr; 127 int len; 128 xfs_daddr_t bno; 129 130 /* no verification of non-crc buffers */ 131 if (!xfs_sb_version_hascrc(&mp->m_sb)) 132 return; 133 134 ptr = bp->b_addr; 135 bno = bp->b_bn; 136 len = BBTOB(bp->b_length); 137 ASSERT(len >= XFS_LBSIZE(mp)); 138 139 while (len > 0) { 140 if (!xfs_verify_cksum(ptr, XFS_LBSIZE(mp), 141 XFS_ATTR3_RMT_CRC_OFF)) { 142 xfs_buf_ioerror(bp, EFSBADCRC); 143 break; 144 } 145 if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) { 146 xfs_buf_ioerror(bp, EFSCORRUPTED); 147 break; 148 } 149 len -= XFS_LBSIZE(mp); 150 ptr += XFS_LBSIZE(mp); 151 bno += mp->m_bsize; 152 } 153 154 if (bp->b_error) 155 xfs_verifier_error(bp); 156 else 157 ASSERT(len == 0); 158} 159 160static void 161xfs_attr3_rmt_write_verify( 162 struct xfs_buf *bp) 163{ 164 struct xfs_mount *mp = bp->b_target->bt_mount; 165 struct xfs_buf_log_item *bip = bp->b_fspriv; 166 char *ptr; 167 int len; 168 xfs_daddr_t bno; 169 170 /* no verification of non-crc buffers */ 171 if (!xfs_sb_version_hascrc(&mp->m_sb)) 172 return; 173 174 ptr = bp->b_addr; 175 bno = bp->b_bn; 176 len = BBTOB(bp->b_length); 177 ASSERT(len >= XFS_LBSIZE(mp)); 178 179 while (len > 0) { 180 if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) { 181 xfs_buf_ioerror(bp, EFSCORRUPTED); 182 xfs_verifier_error(bp); 183 return; 184 } 185 if (bip) { 186 struct xfs_attr3_rmt_hdr *rmt; 187 188 rmt = (struct xfs_attr3_rmt_hdr *)ptr; 189 rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn); 190 } 191 xfs_update_cksum(ptr, XFS_LBSIZE(mp), XFS_ATTR3_RMT_CRC_OFF); 192 193 len -= XFS_LBSIZE(mp); 194 ptr += XFS_LBSIZE(mp); 195 bno += mp->m_bsize; 196 } 197 ASSERT(len == 0); 198} 199 200const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { 201 .verify_read = xfs_attr3_rmt_read_verify, 202 .verify_write = xfs_attr3_rmt_write_verify, 203}; 204 205STATIC int 206xfs_attr3_rmt_hdr_set( 207 struct xfs_mount *mp, 208 void *ptr, 209 xfs_ino_t ino, 210 uint32_t offset, 211 uint32_t size, 212 xfs_daddr_t bno) 213{ 214 struct xfs_attr3_rmt_hdr *rmt = ptr; 215 216 if (!xfs_sb_version_hascrc(&mp->m_sb)) 217 return 0; 218 219 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); 220 rmt->rm_offset = cpu_to_be32(offset); 221 rmt->rm_bytes = cpu_to_be32(size); 222 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid); 223 rmt->rm_owner = cpu_to_be64(ino); 224 rmt->rm_blkno = cpu_to_be64(bno); 225 226 return sizeof(struct xfs_attr3_rmt_hdr); 227} 228 229/* 230 * Helper functions to copy attribute data in and out of the one disk extents 231 */ 232STATIC int 233xfs_attr_rmtval_copyout( 234 struct xfs_mount *mp, 235 struct xfs_buf *bp, 236 xfs_ino_t ino, 237 int *offset, 238 int *valuelen, 239 __uint8_t **dst) 240{ 241 char *src = bp->b_addr; 242 xfs_daddr_t bno = bp->b_bn; 243 int len = BBTOB(bp->b_length); 244 245 ASSERT(len >= XFS_LBSIZE(mp)); 246 247 while (len > 0 && *valuelen > 0) { 248 int hdr_size = 0; 249 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp)); 250 251 byte_cnt = min(*valuelen, byte_cnt); 252 253 if (xfs_sb_version_hascrc(&mp->m_sb)) { 254 if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset, 255 byte_cnt, bno)) { 256 xfs_alert(mp, 257"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", 258 bno, *offset, byte_cnt, ino); 259 return EFSCORRUPTED; 260 } 261 hdr_size = sizeof(struct xfs_attr3_rmt_hdr); 262 } 263 264 memcpy(*dst, src + hdr_size, byte_cnt); 265 266 /* roll buffer forwards */ 267 len -= XFS_LBSIZE(mp); 268 src += XFS_LBSIZE(mp); 269 bno += mp->m_bsize; 270 271 /* roll attribute data forwards */ 272 *valuelen -= byte_cnt; 273 *dst += byte_cnt; 274 *offset += byte_cnt; 275 } 276 return 0; 277} 278 279STATIC void 280xfs_attr_rmtval_copyin( 281 struct xfs_mount *mp, 282 struct xfs_buf *bp, 283 xfs_ino_t ino, 284 int *offset, 285 int *valuelen, 286 __uint8_t **src) 287{ 288 char *dst = bp->b_addr; 289 xfs_daddr_t bno = bp->b_bn; 290 int len = BBTOB(bp->b_length); 291 292 ASSERT(len >= XFS_LBSIZE(mp)); 293 294 while (len > 0 && *valuelen > 0) { 295 int hdr_size; 296 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp)); 297 298 byte_cnt = min(*valuelen, byte_cnt); 299 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, 300 byte_cnt, bno); 301 302 memcpy(dst + hdr_size, *src, byte_cnt); 303 304 /* 305 * If this is the last block, zero the remainder of it. 306 * Check that we are actually the last block, too. 307 */ 308 if (byte_cnt + hdr_size < XFS_LBSIZE(mp)) { 309 ASSERT(*valuelen - byte_cnt == 0); 310 ASSERT(len == XFS_LBSIZE(mp)); 311 memset(dst + hdr_size + byte_cnt, 0, 312 XFS_LBSIZE(mp) - hdr_size - byte_cnt); 313 } 314 315 /* roll buffer forwards */ 316 len -= XFS_LBSIZE(mp); 317 dst += XFS_LBSIZE(mp); 318 bno += mp->m_bsize; 319 320 /* roll attribute data forwards */ 321 *valuelen -= byte_cnt; 322 *src += byte_cnt; 323 *offset += byte_cnt; 324 } 325} 326 327/* 328 * Read the value associated with an attribute from the out-of-line buffer 329 * that we stored it in. 330 */ 331int 332xfs_attr_rmtval_get( 333 struct xfs_da_args *args) 334{ 335 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; 336 struct xfs_mount *mp = args->dp->i_mount; 337 struct xfs_buf *bp; 338 xfs_dablk_t lblkno = args->rmtblkno; 339 __uint8_t *dst = args->value; 340 int valuelen; 341 int nmap; 342 int error; 343 int blkcnt = args->rmtblkcnt; 344 int i; 345 int offset = 0; 346 347 trace_xfs_attr_rmtval_get(args); 348 349 ASSERT(!(args->flags & ATTR_KERNOVAL)); 350 ASSERT(args->rmtvaluelen == args->valuelen); 351 352 valuelen = args->rmtvaluelen; 353 while (valuelen > 0) { 354 nmap = ATTR_RMTVALUE_MAPSIZE; 355 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 356 blkcnt, map, &nmap, 357 XFS_BMAPI_ATTRFORK); 358 if (error) 359 return error; 360 ASSERT(nmap >= 1); 361 362 for (i = 0; (i < nmap) && (valuelen > 0); i++) { 363 xfs_daddr_t dblkno; 364 int dblkcnt; 365 366 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && 367 (map[i].br_startblock != HOLESTARTBLOCK)); 368 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); 369 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 370 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, 371 dblkno, dblkcnt, 0, &bp, 372 &xfs_attr3_rmt_buf_ops); 373 if (error) 374 return error; 375 376 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, 377 &offset, &valuelen, 378 &dst); 379 xfs_buf_relse(bp); 380 if (error) 381 return error; 382 383 /* roll attribute extent map forwards */ 384 lblkno += map[i].br_blockcount; 385 blkcnt -= map[i].br_blockcount; 386 } 387 } 388 ASSERT(valuelen == 0); 389 return 0; 390} 391 392/* 393 * Write the value associated with an attribute into the out-of-line buffer 394 * that we have defined for it. 395 */ 396int 397xfs_attr_rmtval_set( 398 struct xfs_da_args *args) 399{ 400 struct xfs_inode *dp = args->dp; 401 struct xfs_mount *mp = dp->i_mount; 402 struct xfs_bmbt_irec map; 403 xfs_dablk_t lblkno; 404 xfs_fileoff_t lfileoff = 0; 405 __uint8_t *src = args->value; 406 int blkcnt; 407 int valuelen; 408 int nmap; 409 int error; 410 int offset = 0; 411 412 trace_xfs_attr_rmtval_set(args); 413 414 /* 415 * Find a "hole" in the attribute address space large enough for 416 * us to drop the new attribute's value into. Because CRC enable 417 * attributes have headers, we can't just do a straight byte to FSB 418 * conversion and have to take the header space into account. 419 */ 420 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); 421 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 422 XFS_ATTR_FORK); 423 if (error) 424 return error; 425 426 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; 427 args->rmtblkcnt = blkcnt; 428 429 /* 430 * Roll through the "value", allocating blocks on disk as required. 431 */ 432 while (blkcnt > 0) { 433 int committed; 434 435 /* 436 * Allocate a single extent, up to the size of the value. 437 */ 438 xfs_bmap_init(args->flist, args->firstblock); 439 nmap = 1; 440 error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, 441 blkcnt, 442 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 443 args->firstblock, args->total, &map, &nmap, 444 args->flist); 445 if (!error) { 446 error = xfs_bmap_finish(&args->trans, args->flist, 447 &committed); 448 } 449 if (error) { 450 ASSERT(committed); 451 args->trans = NULL; 452 xfs_bmap_cancel(args->flist); 453 return(error); 454 } 455 456 /* 457 * bmap_finish() may have committed the last trans and started 458 * a new one. We need the inode to be in all transactions. 459 */ 460 if (committed) 461 xfs_trans_ijoin(args->trans, dp, 0); 462 463 ASSERT(nmap == 1); 464 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 465 (map.br_startblock != HOLESTARTBLOCK)); 466 lblkno += map.br_blockcount; 467 blkcnt -= map.br_blockcount; 468 469 /* 470 * Start the next trans in the chain. 471 */ 472 error = xfs_trans_roll(&args->trans, dp); 473 if (error) 474 return (error); 475 } 476 477 /* 478 * Roll through the "value", copying the attribute value to the 479 * already-allocated blocks. Blocks are written synchronously 480 * so that we can know they are all on disk before we turn off 481 * the INCOMPLETE flag. 482 */ 483 lblkno = args->rmtblkno; 484 blkcnt = args->rmtblkcnt; 485 valuelen = args->rmtvaluelen; 486 while (valuelen > 0) { 487 struct xfs_buf *bp; 488 xfs_daddr_t dblkno; 489 int dblkcnt; 490 491 ASSERT(blkcnt > 0); 492 493 xfs_bmap_init(args->flist, args->firstblock); 494 nmap = 1; 495 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, 496 blkcnt, &map, &nmap, 497 XFS_BMAPI_ATTRFORK); 498 if (error) 499 return(error); 500 ASSERT(nmap == 1); 501 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 502 (map.br_startblock != HOLESTARTBLOCK)); 503 504 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 505 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 506 507 bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0); 508 if (!bp) 509 return ENOMEM; 510 bp->b_ops = &xfs_attr3_rmt_buf_ops; 511 512 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, 513 &valuelen, &src); 514 515 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ 516 xfs_buf_relse(bp); 517 if (error) 518 return error; 519 520 521 /* roll attribute extent map forwards */ 522 lblkno += map.br_blockcount; 523 blkcnt -= map.br_blockcount; 524 } 525 ASSERT(valuelen == 0); 526 return 0; 527} 528 529/* 530 * Remove the value associated with an attribute by deleting the 531 * out-of-line buffer that it is stored on. 532 */ 533int 534xfs_attr_rmtval_remove( 535 struct xfs_da_args *args) 536{ 537 struct xfs_mount *mp = args->dp->i_mount; 538 xfs_dablk_t lblkno; 539 int blkcnt; 540 int error; 541 int done; 542 543 trace_xfs_attr_rmtval_remove(args); 544 545 /* 546 * Roll through the "value", invalidating the attribute value's blocks. 547 */ 548 lblkno = args->rmtblkno; 549 blkcnt = args->rmtblkcnt; 550 while (blkcnt > 0) { 551 struct xfs_bmbt_irec map; 552 struct xfs_buf *bp; 553 xfs_daddr_t dblkno; 554 int dblkcnt; 555 int nmap; 556 557 /* 558 * Try to remember where we decided to put the value. 559 */ 560 nmap = 1; 561 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 562 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); 563 if (error) 564 return(error); 565 ASSERT(nmap == 1); 566 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 567 (map.br_startblock != HOLESTARTBLOCK)); 568 569 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 570 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 571 572 /* 573 * If the "remote" value is in the cache, remove it. 574 */ 575 bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); 576 if (bp) { 577 xfs_buf_stale(bp); 578 xfs_buf_relse(bp); 579 bp = NULL; 580 } 581 582 lblkno += map.br_blockcount; 583 blkcnt -= map.br_blockcount; 584 } 585 586 /* 587 * Keep de-allocating extents until the remote-value region is gone. 588 */ 589 lblkno = args->rmtblkno; 590 blkcnt = args->rmtblkcnt; 591 done = 0; 592 while (!done) { 593 int committed; 594 595 xfs_bmap_init(args->flist, args->firstblock); 596 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, 597 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 598 1, args->firstblock, args->flist, 599 &done); 600 if (!error) { 601 error = xfs_bmap_finish(&args->trans, args->flist, 602 &committed); 603 } 604 if (error) { 605 ASSERT(committed); 606 args->trans = NULL; 607 xfs_bmap_cancel(args->flist); 608 return error; 609 } 610 611 /* 612 * bmap_finish() may have committed the last trans and started 613 * a new one. We need the inode to be in all transactions. 614 */ 615 if (committed) 616 xfs_trans_ijoin(args->trans, args->dp, 0); 617 618 /* 619 * Close out trans and start the next one in the chain. 620 */ 621 error = xfs_trans_roll(&args->trans, args->dp); 622 if (error) 623 return (error); 624 } 625 return(0); 626}