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_mount.h"
  27#include "xfs_da_format.h"
  28#include "xfs_da_btree.h"
  29#include "xfs_inode.h"
  30#include "xfs_alloc.h"
  31#include "xfs_trans.h"
  32#include "xfs_inode_item.h"
  33#include "xfs_bmap.h"
  34#include "xfs_bmap_util.h"
  35#include "xfs_attr.h"
  36#include "xfs_attr_leaf.h"
  37#include "xfs_attr_remote.h"
  38#include "xfs_trans_space.h"
  39#include "xfs_trace.h"
  40#include "xfs_cksum.h"
  41#include "xfs_buf_item.h"
  42#include "xfs_error.h"
  43
  44#define ATTR_RMTVALUE_MAPSIZE   1       /* # of map entries at once */
  45
  46/*
  47 * Each contiguous block has a header, so it is not just a simple attribute
  48 * length to FSB conversion.
  49 */
  50int
  51xfs_attr3_rmt_blocks(
  52        struct xfs_mount *mp,
  53        int             attrlen)
  54{
  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 */
  67static bool
  68xfs_attr3_rmt_hdr_ok(
  69        void                    *ptr,
  70        xfs_ino_t               ino,
  71        uint32_t                offset,
  72        uint32_t                size,
  73        xfs_daddr_t             bno)
  74{
  75        struct xfs_attr3_rmt_hdr *rmt = ptr;
  76
  77        if (bno != be64_to_cpu(rmt->rm_blkno))
  78                return false;
  79        if (offset != be32_to_cpu(rmt->rm_offset))
  80                return false;
  81        if (size != be32_to_cpu(rmt->rm_bytes))
  82                return false;
  83        if (ino != be64_to_cpu(rmt->rm_owner))
  84                return false;
  85
  86        /* ok */
  87        return true;
  88}
  89
  90static bool
  91xfs_attr3_rmt_verify(
  92        struct xfs_mount        *mp,
  93        void                    *ptr,
  94        int                     fsbsize,
  95        xfs_daddr_t             bno)
  96{
  97        struct xfs_attr3_rmt_hdr *rmt = ptr;
  98
  99        if (!xfs_sb_version_hascrc(&mp->m_sb))
 100                return false;
 101        if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 102                return false;
 103        if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
 104                return false;
 105        if (be64_to_cpu(rmt->rm_blkno) != bno)
 106                return false;
 107        if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
 108                return false;
 109        if (be32_to_cpu(rmt->rm_offset) +
 110                                be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
 111                return false;
 112        if (rmt->rm_owner == 0)
 113                return false;
 114
 115        return true;
 116}
 117
 118static void
 119xfs_attr3_rmt_read_verify(
 120        struct xfs_buf  *bp)
 121{
 122        struct xfs_mount *mp = bp->b_target->bt_mount;
 123        char            *ptr;
 124        int             len;
 125        xfs_daddr_t     bno;
 126        int             blksize = mp->m_attr_geo->blksize;
 127
 128        /* no verification of non-crc buffers */
 129        if (!xfs_sb_version_hascrc(&mp->m_sb))
 130                return;
 131
 132        ptr = bp->b_addr;
 133        bno = bp->b_bn;
 134        len = BBTOB(bp->b_length);
 135        ASSERT(len >= blksize);
 136
 137        while (len > 0) {
 138                if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
 139                        xfs_buf_ioerror(bp, -EFSBADCRC);
 140                        break;
 141                }
 142                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
 143                        xfs_buf_ioerror(bp, -EFSCORRUPTED);
 144                        break;
 145                }
 146                len -= blksize;
 147                ptr += blksize;
 148                bno += BTOBB(blksize);
 149        }
 150
 151        if (bp->b_error)
 152                xfs_verifier_error(bp);
 153        else
 154                ASSERT(len == 0);
 155}
 156
 157static void
 158xfs_attr3_rmt_write_verify(
 159        struct xfs_buf  *bp)
 160{
 161        struct xfs_mount *mp = bp->b_target->bt_mount;
 162        struct xfs_buf_log_item *bip = bp->b_fspriv;
 163        char            *ptr;
 164        int             len;
 165        xfs_daddr_t     bno;
 166        int             blksize = mp->m_attr_geo->blksize;
 167
 168        /* no verification of non-crc buffers */
 169        if (!xfs_sb_version_hascrc(&mp->m_sb))
 170                return;
 171
 172        ptr = bp->b_addr;
 173        bno = bp->b_bn;
 174        len = BBTOB(bp->b_length);
 175        ASSERT(len >= blksize);
 176
 177        while (len > 0) {
 178                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
 179                        xfs_buf_ioerror(bp, -EFSCORRUPTED);
 180                        xfs_verifier_error(bp);
 181                        return;
 182                }
 183                if (bip) {
 184                        struct xfs_attr3_rmt_hdr *rmt;
 185
 186                        rmt = (struct xfs_attr3_rmt_hdr *)ptr;
 187                        rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
 188                }
 189                xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
 190
 191                len -= blksize;
 192                ptr += blksize;
 193                bno += BTOBB(blksize);
 194        }
 195        ASSERT(len == 0);
 196}
 197
 198const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
 199        .verify_read = xfs_attr3_rmt_read_verify,
 200        .verify_write = xfs_attr3_rmt_write_verify,
 201};
 202
 203STATIC int
 204xfs_attr3_rmt_hdr_set(
 205        struct xfs_mount        *mp,
 206        void                    *ptr,
 207        xfs_ino_t               ino,
 208        uint32_t                offset,
 209        uint32_t                size,
 210        xfs_daddr_t             bno)
 211{
 212        struct xfs_attr3_rmt_hdr *rmt = ptr;
 213
 214        if (!xfs_sb_version_hascrc(&mp->m_sb))
 215                return 0;
 216
 217        rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 218        rmt->rm_offset = cpu_to_be32(offset);
 219        rmt->rm_bytes = cpu_to_be32(size);
 220        uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
 221        rmt->rm_owner = cpu_to_be64(ino);
 222        rmt->rm_blkno = cpu_to_be64(bno);
 223
 224        return sizeof(struct xfs_attr3_rmt_hdr);
 225}
 226
 227/*
 228 * Helper functions to copy attribute data in and out of the one disk extents
 229 */
 230STATIC int
 231xfs_attr_rmtval_copyout(
 232        struct xfs_mount *mp,
 233        struct xfs_buf  *bp,
 234        xfs_ino_t       ino,
 235        int             *offset,
 236        int             *valuelen,
 237        __uint8_t       **dst)
 238{
 239        char            *src = bp->b_addr;
 240        xfs_daddr_t     bno = bp->b_bn;
 241        int             len = BBTOB(bp->b_length);
 242        int             blksize = mp->m_attr_geo->blksize;
 243
 244        ASSERT(len >= blksize);
 245
 246        while (len > 0 && *valuelen > 0) {
 247                int hdr_size = 0;
 248                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
 249
 250                byte_cnt = min(*valuelen, byte_cnt);
 251
 252                if (xfs_sb_version_hascrc(&mp->m_sb)) {
 253                        if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
 254                                                  byte_cnt, bno)) {
 255                                xfs_alert(mp,
 256"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
 257                                        bno, *offset, byte_cnt, ino);
 258                                return -EFSCORRUPTED;
 259                        }
 260                        hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
 261                }
 262
 263                memcpy(*dst, src + hdr_size, byte_cnt);
 264
 265                /* roll buffer forwards */
 266                len -= blksize;
 267                src += blksize;
 268                bno += BTOBB(blksize);
 269
 270                /* roll attribute data forwards */
 271                *valuelen -= byte_cnt;
 272                *dst += byte_cnt;
 273                *offset += byte_cnt;
 274        }
 275        return 0;
 276}
 277
 278STATIC void
 279xfs_attr_rmtval_copyin(
 280        struct xfs_mount *mp,
 281        struct xfs_buf  *bp,
 282        xfs_ino_t       ino,
 283        int             *offset,
 284        int             *valuelen,
 285        __uint8_t       **src)
 286{
 287        char            *dst = bp->b_addr;
 288        xfs_daddr_t     bno = bp->b_bn;
 289        int             len = BBTOB(bp->b_length);
 290        int             blksize = mp->m_attr_geo->blksize;
 291
 292        ASSERT(len >= blksize);
 293
 294        while (len > 0 && *valuelen > 0) {
 295                int hdr_size;
 296                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
 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 < blksize) {
 309                        ASSERT(*valuelen - byte_cnt == 0);
 310                        ASSERT(len == blksize);
 311                        memset(dst + hdr_size + byte_cnt, 0,
 312                                        blksize - hdr_size - byte_cnt);
 313                }
 314
 315                /* roll buffer forwards */
 316                len -= blksize;
 317                dst += blksize;
 318                bno += BTOBB(blksize);
 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}
 627