linux/fs/xfs/libxfs/xfs_attr_remote.c
<<
>>
Prefs
   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        void                    *ptr,
  72        xfs_ino_t               ino,
  73        uint32_t                offset,
  74        uint32_t                size,
  75        xfs_daddr_t             bno)
  76{
  77        struct xfs_attr3_rmt_hdr *rmt = ptr;
  78
  79        if (bno != be64_to_cpu(rmt->rm_blkno))
  80                return false;
  81        if (offset != be32_to_cpu(rmt->rm_offset))
  82                return false;
  83        if (size != be32_to_cpu(rmt->rm_bytes))
  84                return false;
  85        if (ino != be64_to_cpu(rmt->rm_owner))
  86                return false;
  87
  88        /* ok */
  89        return true;
  90}
  91
  92static bool
  93xfs_attr3_rmt_verify(
  94        struct xfs_mount        *mp,
  95        void                    *ptr,
  96        int                     fsbsize,
  97        xfs_daddr_t             bno)
  98{
  99        struct xfs_attr3_rmt_hdr *rmt = ptr;
 100
 101        if (!xfs_sb_version_hascrc(&mp->m_sb))
 102                return false;
 103        if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 104                return false;
 105        if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
 106                return false;
 107        if (be64_to_cpu(rmt->rm_blkno) != bno)
 108                return false;
 109        if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
 110                return false;
 111        if (be32_to_cpu(rmt->rm_offset) +
 112                                be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
 113                return false;
 114        if (rmt->rm_owner == 0)
 115                return false;
 116
 117        return true;
 118}
 119
 120static void
 121xfs_attr3_rmt_read_verify(
 122        struct xfs_buf  *bp)
 123{
 124        struct xfs_mount *mp = bp->b_target->bt_mount;
 125        char            *ptr;
 126        int             len;
 127        xfs_daddr_t     bno;
 128        int             blksize = mp->m_attr_geo->blksize;
 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 >= blksize);
 138
 139        while (len > 0) {
 140                if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
 141                        xfs_buf_ioerror(bp, -EFSBADCRC);
 142                        break;
 143                }
 144                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
 145                        xfs_buf_ioerror(bp, -EFSCORRUPTED);
 146                        break;
 147                }
 148                len -= blksize;
 149                ptr += blksize;
 150                bno += BTOBB(blksize);
 151        }
 152
 153        if (bp->b_error)
 154                xfs_verifier_error(bp);
 155        else
 156                ASSERT(len == 0);
 157}
 158
 159static void
 160xfs_attr3_rmt_write_verify(
 161        struct xfs_buf  *bp)
 162{
 163        struct xfs_mount *mp = bp->b_target->bt_mount;
 164        struct xfs_buf_log_item *bip = bp->b_fspriv;
 165        char            *ptr;
 166        int             len;
 167        xfs_daddr_t     bno;
 168        int             blksize = mp->m_attr_geo->blksize;
 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 >= blksize);
 178
 179        while (len > 0) {
 180                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, 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, blksize, XFS_ATTR3_RMT_CRC_OFF);
 192
 193                len -= blksize;
 194                ptr += blksize;
 195                bno += BTOBB(blksize);
 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        int             blksize = mp->m_attr_geo->blksize;
 245
 246        ASSERT(len >= blksize);
 247
 248        while (len > 0 && *valuelen > 0) {
 249                int hdr_size = 0;
 250                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
 251
 252                byte_cnt = min(*valuelen, byte_cnt);
 253
 254                if (xfs_sb_version_hascrc(&mp->m_sb)) {
 255                        if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
 256                                                  byte_cnt, bno)) {
 257                                xfs_alert(mp,
 258"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
 259                                        bno, *offset, byte_cnt, ino);
 260                                return -EFSCORRUPTED;
 261                        }
 262                        hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
 263                }
 264
 265                memcpy(*dst, src + hdr_size, byte_cnt);
 266
 267                /* roll buffer forwards */
 268                len -= blksize;
 269                src += blksize;
 270                bno += BTOBB(blksize);
 271
 272                /* roll attribute data forwards */
 273                *valuelen -= byte_cnt;
 274                *dst += byte_cnt;
 275                *offset += byte_cnt;
 276        }
 277        return 0;
 278}
 279
 280STATIC void
 281xfs_attr_rmtval_copyin(
 282        struct xfs_mount *mp,
 283        struct xfs_buf  *bp,
 284        xfs_ino_t       ino,
 285        int             *offset,
 286        int             *valuelen,
 287        __uint8_t       **src)
 288{
 289        char            *dst = bp->b_addr;
 290        xfs_daddr_t     bno = bp->b_bn;
 291        int             len = BBTOB(bp->b_length);
 292        int             blksize = mp->m_attr_geo->blksize;
 293
 294        ASSERT(len >= blksize);
 295
 296        while (len > 0 && *valuelen > 0) {
 297                int hdr_size;
 298                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
 299
 300                byte_cnt = min(*valuelen, byte_cnt);
 301                hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
 302                                                 byte_cnt, bno);
 303
 304                memcpy(dst + hdr_size, *src, byte_cnt);
 305
 306                /*
 307                 * If this is the last block, zero the remainder of it.
 308                 * Check that we are actually the last block, too.
 309                 */
 310                if (byte_cnt + hdr_size < blksize) {
 311                        ASSERT(*valuelen - byte_cnt == 0);
 312                        ASSERT(len == blksize);
 313                        memset(dst + hdr_size + byte_cnt, 0,
 314                                        blksize - hdr_size - byte_cnt);
 315                }
 316
 317                /* roll buffer forwards */
 318                len -= blksize;
 319                dst += blksize;
 320                bno += BTOBB(blksize);
 321
 322                /* roll attribute data forwards */
 323                *valuelen -= byte_cnt;
 324                *src += byte_cnt;
 325                *offset += byte_cnt;
 326        }
 327}
 328
 329/*
 330 * Read the value associated with an attribute from the out-of-line buffer
 331 * that we stored it in.
 332 */
 333int
 334xfs_attr_rmtval_get(
 335        struct xfs_da_args      *args)
 336{
 337        struct xfs_bmbt_irec    map[ATTR_RMTVALUE_MAPSIZE];
 338        struct xfs_mount        *mp = args->dp->i_mount;
 339        struct xfs_buf          *bp;
 340        xfs_dablk_t             lblkno = args->rmtblkno;
 341        __uint8_t               *dst = args->value;
 342        int                     valuelen;
 343        int                     nmap;
 344        int                     error;
 345        int                     blkcnt = args->rmtblkcnt;
 346        int                     i;
 347        int                     offset = 0;
 348
 349        trace_xfs_attr_rmtval_get(args);
 350
 351        ASSERT(!(args->flags & ATTR_KERNOVAL));
 352        ASSERT(args->rmtvaluelen == args->valuelen);
 353
 354        valuelen = args->rmtvaluelen;
 355        while (valuelen > 0) {
 356                nmap = ATTR_RMTVALUE_MAPSIZE;
 357                error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
 358                                       blkcnt, map, &nmap,
 359                                       XFS_BMAPI_ATTRFORK);
 360                if (error)
 361                        return error;
 362                ASSERT(nmap >= 1);
 363
 364                for (i = 0; (i < nmap) && (valuelen > 0); i++) {
 365                        xfs_daddr_t     dblkno;
 366                        int             dblkcnt;
 367
 368                        ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
 369                               (map[i].br_startblock != HOLESTARTBLOCK));
 370                        dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
 371                        dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
 372                        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
 373                                                   dblkno, dblkcnt, 0, &bp,
 374                                                   &xfs_attr3_rmt_buf_ops);
 375                        if (error)
 376                                return error;
 377
 378                        error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
 379                                                        &offset, &valuelen,
 380                                                        &dst);
 381                        xfs_buf_relse(bp);
 382                        if (error)
 383                                return error;
 384
 385                        /* roll attribute extent map forwards */
 386                        lblkno += map[i].br_blockcount;
 387                        blkcnt -= map[i].br_blockcount;
 388                }
 389        }
 390        ASSERT(valuelen == 0);
 391        return 0;
 392}
 393
 394/*
 395 * Write the value associated with an attribute into the out-of-line buffer
 396 * that we have defined for it.
 397 */
 398int
 399xfs_attr_rmtval_set(
 400        struct xfs_da_args      *args)
 401{
 402        struct xfs_inode        *dp = args->dp;
 403        struct xfs_mount        *mp = dp->i_mount;
 404        struct xfs_bmbt_irec    map;
 405        xfs_dablk_t             lblkno;
 406        xfs_fileoff_t           lfileoff = 0;
 407        __uint8_t               *src = args->value;
 408        int                     blkcnt;
 409        int                     valuelen;
 410        int                     nmap;
 411        int                     error;
 412        int                     offset = 0;
 413
 414        trace_xfs_attr_rmtval_set(args);
 415
 416        /*
 417         * Find a "hole" in the attribute address space large enough for
 418         * us to drop the new attribute's value into. Because CRC enable
 419         * attributes have headers, we can't just do a straight byte to FSB
 420         * conversion and have to take the header space into account.
 421         */
 422        blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
 423        error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
 424                                                   XFS_ATTR_FORK);
 425        if (error)
 426                return error;
 427
 428        args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
 429        args->rmtblkcnt = blkcnt;
 430
 431        /*
 432         * Roll through the "value", allocating blocks on disk as required.
 433         */
 434        while (blkcnt > 0) {
 435                int     committed;
 436
 437                /*
 438                 * Allocate a single extent, up to the size of the value.
 439                 */
 440                xfs_bmap_init(args->flist, args->firstblock);
 441                nmap = 1;
 442                error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
 443                                  blkcnt,
 444                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
 445                                  args->firstblock, args->total, &map, &nmap,
 446                                  args->flist);
 447                if (!error) {
 448                        error = xfs_bmap_finish(&args->trans, args->flist,
 449                                                &committed);
 450                }
 451                if (error) {
 452                        ASSERT(committed);
 453                        args->trans = NULL;
 454                        xfs_bmap_cancel(args->flist);
 455                        return error;
 456                }
 457
 458                /*
 459                 * bmap_finish() may have committed the last trans and started
 460                 * a new one.  We need the inode to be in all transactions.
 461                 */
 462                if (committed)
 463                        xfs_trans_ijoin(args->trans, dp, 0);
 464
 465                ASSERT(nmap == 1);
 466                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 467                       (map.br_startblock != HOLESTARTBLOCK));
 468                lblkno += map.br_blockcount;
 469                blkcnt -= map.br_blockcount;
 470
 471                /*
 472                 * Start the next trans in the chain.
 473                 */
 474                error = xfs_trans_roll(&args->trans, dp);
 475                if (error)
 476                        return error;
 477        }
 478
 479        /*
 480         * Roll through the "value", copying the attribute value to the
 481         * already-allocated blocks.  Blocks are written synchronously
 482         * so that we can know they are all on disk before we turn off
 483         * the INCOMPLETE flag.
 484         */
 485        lblkno = args->rmtblkno;
 486        blkcnt = args->rmtblkcnt;
 487        valuelen = args->rmtvaluelen;
 488        while (valuelen > 0) {
 489                struct xfs_buf  *bp;
 490                xfs_daddr_t     dblkno;
 491                int             dblkcnt;
 492
 493                ASSERT(blkcnt > 0);
 494
 495                xfs_bmap_init(args->flist, args->firstblock);
 496                nmap = 1;
 497                error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
 498                                       blkcnt, &map, &nmap,
 499                                       XFS_BMAPI_ATTRFORK);
 500                if (error)
 501                        return error;
 502                ASSERT(nmap == 1);
 503                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 504                       (map.br_startblock != HOLESTARTBLOCK));
 505
 506                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
 507                dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
 508
 509                bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
 510                if (!bp)
 511                        return -ENOMEM;
 512                bp->b_ops = &xfs_attr3_rmt_buf_ops;
 513
 514                xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
 515                                       &valuelen, &src);
 516
 517                error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
 518                xfs_buf_relse(bp);
 519                if (error)
 520                        return error;
 521
 522
 523                /* roll attribute extent map forwards */
 524                lblkno += map.br_blockcount;
 525                blkcnt -= map.br_blockcount;
 526        }
 527        ASSERT(valuelen == 0);
 528        return 0;
 529}
 530
 531/*
 532 * Remove the value associated with an attribute by deleting the
 533 * out-of-line buffer that it is stored on.
 534 */
 535int
 536xfs_attr_rmtval_remove(
 537        struct xfs_da_args      *args)
 538{
 539        struct xfs_mount        *mp = args->dp->i_mount;
 540        xfs_dablk_t             lblkno;
 541        int                     blkcnt;
 542        int                     error;
 543        int                     done;
 544
 545        trace_xfs_attr_rmtval_remove(args);
 546
 547        /*
 548         * Roll through the "value", invalidating the attribute value's blocks.
 549         */
 550        lblkno = args->rmtblkno;
 551        blkcnt = args->rmtblkcnt;
 552        while (blkcnt > 0) {
 553                struct xfs_bmbt_irec    map;
 554                struct xfs_buf          *bp;
 555                xfs_daddr_t             dblkno;
 556                int                     dblkcnt;
 557                int                     nmap;
 558
 559                /*
 560                 * Try to remember where we decided to put the value.
 561                 */
 562                nmap = 1;
 563                error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
 564                                       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
 565                if (error)
 566                        return error;
 567                ASSERT(nmap == 1);
 568                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 569                       (map.br_startblock != HOLESTARTBLOCK));
 570
 571                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
 572                dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
 573
 574                /*
 575                 * If the "remote" value is in the cache, remove it.
 576                 */
 577                bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
 578                if (bp) {
 579                        xfs_buf_stale(bp);
 580                        xfs_buf_relse(bp);
 581                        bp = NULL;
 582                }
 583
 584                lblkno += map.br_blockcount;
 585                blkcnt -= map.br_blockcount;
 586        }
 587
 588        /*
 589         * Keep de-allocating extents until the remote-value region is gone.
 590         */
 591        lblkno = args->rmtblkno;
 592        blkcnt = args->rmtblkcnt;
 593        done = 0;
 594        while (!done) {
 595                int committed;
 596
 597                xfs_bmap_init(args->flist, args->firstblock);
 598                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
 599                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
 600                                    1, args->firstblock, args->flist,
 601                                    &done);
 602                if (!error) {
 603                        error = xfs_bmap_finish(&args->trans, args->flist,
 604                                                &committed);
 605                }
 606                if (error) {
 607                        ASSERT(committed);
 608                        args->trans = NULL;
 609                        xfs_bmap_cancel(args->flist);
 610                        return error;
 611                }
 612
 613                /*
 614                 * bmap_finish() may have committed the last trans and started
 615                 * a new one.  We need the inode to be in all transactions.
 616                 */
 617                if (committed)
 618                        xfs_trans_ijoin(args->trans, args->dp, 0);
 619
 620                /*
 621                 * Close out trans and start the next one in the chain.
 622                 */
 623                error = xfs_trans_roll(&args->trans, args->dp);
 624                if (error)
 625                        return error;
 626        }
 627        return 0;
 628}
 629