linux/fs/xfs/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_types.h"
  22#include "xfs_bit.h"
  23#include "xfs_log.h"
  24#include "xfs_trans.h"
  25#include "xfs_sb.h"
  26#include "xfs_ag.h"
  27#include "xfs_mount.h"
  28#include "xfs_error.h"
  29#include "xfs_da_btree.h"
  30#include "xfs_bmap_btree.h"
  31#include "xfs_dinode.h"
  32#include "xfs_inode.h"
  33#include "xfs_alloc.h"
  34#include "xfs_inode_item.h"
  35#include "xfs_bmap.h"
  36#include "xfs_attr.h"
  37#include "xfs_attr_leaf.h"
  38#include "xfs_attr_remote.h"
  39#include "xfs_trans_space.h"
  40#include "xfs_trace.h"
  41#include "xfs_cksum.h"
  42#include "xfs_buf_item.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        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;
  89}
  90
  91static bool
  92xfs_attr3_rmt_verify(
  93        struct xfs_mount        *mp,
  94        void                    *ptr,
  95        int                     fsbsize,
  96        xfs_daddr_t             bno)
  97{
  98        struct xfs_attr3_rmt_hdr *rmt = ptr;
  99
 100        if (!xfs_sb_version_hascrc(&mp->m_sb))
 101                return false;
 102        if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 103                return false;
 104        if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
 105                return false;
 106        if (be64_to_cpu(rmt->rm_blkno) != bno)
 107                return false;
 108        if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
 109                return false;
 110        if (be32_to_cpu(rmt->rm_offset) +
 111                                be32_to_cpu(rmt->rm_bytes) >= XATTR_SIZE_MAX)
 112                return false;
 113        if (rmt->rm_owner == 0)
 114                return false;
 115
 116        return true;
 117}
 118
 119static void
 120xfs_attr3_rmt_read_verify(
 121        struct xfs_buf  *bp)
 122{
 123        struct xfs_mount *mp = bp->b_target->bt_mount;
 124        char            *ptr;
 125        int             len;
 126        bool            corrupt = false;
 127        xfs_daddr_t     bno;
 128
 129        /* no verification of non-crc buffers */
 130        if (!xfs_sb_version_hascrc(&mp->m_sb))
 131                return;
 132
 133        ptr = bp->b_addr;
 134        bno = bp->b_bn;
 135        len = BBTOB(bp->b_length);
 136        ASSERT(len >= XFS_LBSIZE(mp));
 137
 138        while (len > 0) {
 139                if (!xfs_verify_cksum(ptr, XFS_LBSIZE(mp),
 140                                      XFS_ATTR3_RMT_CRC_OFF)) {
 141                        corrupt = true;
 142                        break;
 143                }
 144                if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) {
 145                        corrupt = true;
 146                        break;
 147                }
 148                len -= XFS_LBSIZE(mp);
 149                ptr += XFS_LBSIZE(mp);
 150                bno += mp->m_bsize;
 151        }
 152
 153        if (corrupt) {
 154                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
 155                xfs_buf_ioerror(bp, EFSCORRUPTED);
 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_CORRUPTION_ERROR(__func__,
 182                                            XFS_ERRLEVEL_LOW, mp, bp->b_addr);
 183                        xfs_buf_ioerror(bp, EFSCORRUPTED);
 184                        return;
 185                }
 186                if (bip) {
 187                        struct xfs_attr3_rmt_hdr *rmt;
 188
 189                        rmt = (struct xfs_attr3_rmt_hdr *)ptr;
 190                        rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
 191                }
 192                xfs_update_cksum(ptr, XFS_LBSIZE(mp), XFS_ATTR3_RMT_CRC_OFF);
 193
 194                len -= XFS_LBSIZE(mp);
 195                ptr += XFS_LBSIZE(mp);
 196                bno += mp->m_bsize;
 197        }
 198        ASSERT(len == 0);
 199}
 200
 201const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
 202        .verify_read = xfs_attr3_rmt_read_verify,
 203        .verify_write = xfs_attr3_rmt_write_verify,
 204};
 205
 206STATIC int
 207xfs_attr3_rmt_hdr_set(
 208        struct xfs_mount        *mp,
 209        void                    *ptr,
 210        xfs_ino_t               ino,
 211        uint32_t                offset,
 212        uint32_t                size,
 213        xfs_daddr_t             bno)
 214{
 215        struct xfs_attr3_rmt_hdr *rmt = ptr;
 216
 217        if (!xfs_sb_version_hascrc(&mp->m_sb))
 218                return 0;
 219
 220        rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 221        rmt->rm_offset = cpu_to_be32(offset);
 222        rmt->rm_bytes = cpu_to_be32(size);
 223        uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
 224        rmt->rm_owner = cpu_to_be64(ino);
 225        rmt->rm_blkno = cpu_to_be64(bno);
 226
 227        return sizeof(struct xfs_attr3_rmt_hdr);
 228}
 229
 230/*
 231 * Helper functions to copy attribute data in and out of the one disk extents
 232 */
 233STATIC int
 234xfs_attr_rmtval_copyout(
 235        struct xfs_mount *mp,
 236        struct xfs_buf  *bp,
 237        xfs_ino_t       ino,
 238        int             *offset,
 239        int             *valuelen,
 240        char            **dst)
 241{
 242        char            *src = bp->b_addr;
 243        xfs_daddr_t     bno = bp->b_bn;
 244        int             len = BBTOB(bp->b_length);
 245
 246        ASSERT(len >= XFS_LBSIZE(mp));
 247
 248        while (len > 0 && *valuelen > 0) {
 249                int hdr_size = 0;
 250                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
 251
 252                byte_cnt = min_t(int, *valuelen, byte_cnt);
 253
 254                if (xfs_sb_version_hascrc(&mp->m_sb)) {
 255                        if (!xfs_attr3_rmt_hdr_ok(mp, 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 -= XFS_LBSIZE(mp);
 269                src += XFS_LBSIZE(mp);
 270                bno += mp->m_bsize;
 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        char            **src)
 288{
 289        char            *dst = bp->b_addr;
 290        xfs_daddr_t     bno = bp->b_bn;
 291        int             len = BBTOB(bp->b_length);
 292
 293        ASSERT(len >= XFS_LBSIZE(mp));
 294
 295        while (len > 0 && *valuelen > 0) {
 296                int hdr_size;
 297                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
 298
 299                byte_cnt = min(*valuelen, byte_cnt);
 300                hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
 301                                                 byte_cnt, bno);
 302
 303                memcpy(dst + hdr_size, *src, byte_cnt);
 304
 305                /*
 306                 * If this is the last block, zero the remainder of it.
 307                 * Check that we are actually the last block, too.
 308                 */
 309                if (byte_cnt + hdr_size < XFS_LBSIZE(mp)) {
 310                        ASSERT(*valuelen - byte_cnt == 0);
 311                        ASSERT(len == XFS_LBSIZE(mp));
 312                        memset(dst + hdr_size + byte_cnt, 0,
 313                                        XFS_LBSIZE(mp) - hdr_size - byte_cnt);
 314                }
 315
 316                /* roll buffer forwards */
 317                len -= XFS_LBSIZE(mp);
 318                dst += XFS_LBSIZE(mp);
 319                bno += mp->m_bsize;
 320
 321                /* roll attribute data forwards */
 322                *valuelen -= byte_cnt;
 323                *src += byte_cnt;
 324                *offset += byte_cnt;
 325        }
 326}
 327
 328/*
 329 * Read the value associated with an attribute from the out-of-line buffer
 330 * that we stored it in.
 331 */
 332int
 333xfs_attr_rmtval_get(
 334        struct xfs_da_args      *args)
 335{
 336        struct xfs_bmbt_irec    map[ATTR_RMTVALUE_MAPSIZE];
 337        struct xfs_mount        *mp = args->dp->i_mount;
 338        struct xfs_buf          *bp;
 339        xfs_dablk_t             lblkno = args->rmtblkno;
 340        char                    *dst = args->value;
 341        int                     valuelen = args->valuelen;
 342        int                     nmap;
 343        int                     error;
 344        int                     blkcnt = args->rmtblkcnt;
 345        int                     i;
 346        int                     offset = 0;
 347
 348        trace_xfs_attr_rmtval_get(args);
 349
 350        ASSERT(!(args->flags & ATTR_KERNOVAL));
 351
 352        while (valuelen > 0) {
 353                nmap = ATTR_RMTVALUE_MAPSIZE;
 354                error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
 355                                       blkcnt, map, &nmap,
 356                                       XFS_BMAPI_ATTRFORK);
 357                if (error)
 358                        return error;
 359                ASSERT(nmap >= 1);
 360
 361                for (i = 0; (i < nmap) && (valuelen > 0); i++) {
 362                        xfs_daddr_t     dblkno;
 363                        int             dblkcnt;
 364
 365                        ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
 366                               (map[i].br_startblock != HOLESTARTBLOCK));
 367                        dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
 368                        dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
 369                        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
 370                                                   dblkno, dblkcnt, 0, &bp,
 371                                                   &xfs_attr3_rmt_buf_ops);
 372                        if (error)
 373                                return error;
 374
 375                        error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
 376                                                        &offset, &valuelen,
 377                                                        &dst);
 378                        xfs_buf_relse(bp);
 379                        if (error)
 380                                return error;
 381
 382                        /* roll attribute extent map forwards */
 383                        lblkno += map[i].br_blockcount;
 384                        blkcnt -= map[i].br_blockcount;
 385                }
 386        }
 387        ASSERT(valuelen == 0);
 388        return 0;
 389}
 390
 391/*
 392 * Write the value associated with an attribute into the out-of-line buffer
 393 * that we have defined for it.
 394 */
 395int
 396xfs_attr_rmtval_set(
 397        struct xfs_da_args      *args)
 398{
 399        struct xfs_inode        *dp = args->dp;
 400        struct xfs_mount        *mp = dp->i_mount;
 401        struct xfs_bmbt_irec    map;
 402        xfs_dablk_t             lblkno;
 403        xfs_fileoff_t           lfileoff = 0;
 404        char                    *src = args->value;
 405        int                     blkcnt;
 406        int                     valuelen;
 407        int                     nmap;
 408        int                     error;
 409        int                     offset = 0;
 410
 411        trace_xfs_attr_rmtval_set(args);
 412
 413        /*
 414         * Find a "hole" in the attribute address space large enough for
 415         * us to drop the new attribute's value into. Because CRC enable
 416         * attributes have headers, we can't just do a straight byte to FSB
 417         * conversion and have to take the header space into account.
 418         */
 419        blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen);
 420        error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
 421                                                   XFS_ATTR_FORK);
 422        if (error)
 423                return error;
 424
 425        args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
 426        args->rmtblkcnt = blkcnt;
 427
 428        /*
 429         * Roll through the "value", allocating blocks on disk as required.
 430         */
 431        while (blkcnt > 0) {
 432                int     committed;
 433
 434                /*
 435                 * Allocate a single extent, up to the size of the value.
 436                 */
 437                xfs_bmap_init(args->flist, args->firstblock);
 438                nmap = 1;
 439                error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
 440                                  blkcnt,
 441                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
 442                                  args->firstblock, args->total, &map, &nmap,
 443                                  args->flist);
 444                if (!error) {
 445                        error = xfs_bmap_finish(&args->trans, args->flist,
 446                                                &committed);
 447                }
 448                if (error) {
 449                        ASSERT(committed);
 450                        args->trans = NULL;
 451                        xfs_bmap_cancel(args->flist);
 452                        return(error);
 453                }
 454
 455                /*
 456                 * bmap_finish() may have committed the last trans and started
 457                 * a new one.  We need the inode to be in all transactions.
 458                 */
 459                if (committed)
 460                        xfs_trans_ijoin(args->trans, dp, 0);
 461
 462                ASSERT(nmap == 1);
 463                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 464                       (map.br_startblock != HOLESTARTBLOCK));
 465                lblkno += map.br_blockcount;
 466                blkcnt -= map.br_blockcount;
 467
 468                /*
 469                 * Start the next trans in the chain.
 470                 */
 471                error = xfs_trans_roll(&args->trans, dp);
 472                if (error)
 473                        return (error);
 474        }
 475
 476        /*
 477         * Roll through the "value", copying the attribute value to the
 478         * already-allocated blocks.  Blocks are written synchronously
 479         * so that we can know they are all on disk before we turn off
 480         * the INCOMPLETE flag.
 481         */
 482        lblkno = args->rmtblkno;
 483        blkcnt = args->rmtblkcnt;
 484        valuelen = args->valuelen;
 485        while (valuelen > 0) {
 486                struct xfs_buf  *bp;
 487                xfs_daddr_t     dblkno;
 488                int             dblkcnt;
 489
 490                ASSERT(blkcnt > 0);
 491
 492                xfs_bmap_init(args->flist, args->firstblock);
 493                nmap = 1;
 494                error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
 495                                       blkcnt, &map, &nmap,
 496                                       XFS_BMAPI_ATTRFORK);
 497                if (error)
 498                        return(error);
 499                ASSERT(nmap == 1);
 500                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 501                       (map.br_startblock != HOLESTARTBLOCK));
 502
 503                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
 504                dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
 505
 506                bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
 507                if (!bp)
 508                        return ENOMEM;
 509                bp->b_ops = &xfs_attr3_rmt_buf_ops;
 510
 511                xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
 512                                       &valuelen, &src);
 513
 514                error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
 515                xfs_buf_relse(bp);
 516                if (error)
 517                        return error;
 518
 519
 520                /* roll attribute extent map forwards */
 521                lblkno += map.br_blockcount;
 522                blkcnt -= map.br_blockcount;
 523        }
 524        ASSERT(valuelen == 0);
 525        return 0;
 526}
 527
 528/*
 529 * Remove the value associated with an attribute by deleting the
 530 * out-of-line buffer that it is stored on.
 531 */
 532int
 533xfs_attr_rmtval_remove(
 534        struct xfs_da_args      *args)
 535{
 536        struct xfs_mount        *mp = args->dp->i_mount;
 537        xfs_dablk_t             lblkno;
 538        int                     blkcnt;
 539        int                     error;
 540        int                     done;
 541
 542        trace_xfs_attr_rmtval_remove(args);
 543
 544        /*
 545         * Roll through the "value", invalidating the attribute value's blocks.
 546         * Note that args->rmtblkcnt is the minimum number of data blocks we'll
 547         * see for a CRC enabled remote attribute. Each extent will have a
 548         * header, and so we may have more blocks than we realise here.  If we
 549         * fail to map the blocks correctly, we'll have problems with the buffer
 550         * lookups.
 551         */
 552        lblkno = args->rmtblkno;
 553        blkcnt = args->rmtblkcnt;
 554        while (blkcnt > 0) {
 555                struct xfs_bmbt_irec    map;
 556                struct xfs_buf          *bp;
 557                xfs_daddr_t             dblkno;
 558                int                     dblkcnt;
 559                int                     nmap;
 560
 561                /*
 562                 * Try to remember where we decided to put the value.
 563                 */
 564                nmap = 1;
 565                error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
 566                                       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
 567                if (error)
 568                        return(error);
 569                ASSERT(nmap == 1);
 570                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
 571                       (map.br_startblock != HOLESTARTBLOCK));
 572
 573                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
 574                dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
 575
 576                /*
 577                 * If the "remote" value is in the cache, remove it.
 578                 */
 579                bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
 580                if (bp) {
 581                        xfs_buf_stale(bp);
 582                        xfs_buf_relse(bp);
 583                        bp = NULL;
 584                }
 585
 586                lblkno += map.br_blockcount;
 587                blkcnt -= map.br_blockcount;
 588        }
 589
 590        /*
 591         * Keep de-allocating extents until the remote-value region is gone.
 592         */
 593        lblkno = args->rmtblkno;
 594        blkcnt = args->rmtblkcnt;
 595        done = 0;
 596        while (!done) {
 597                int committed;
 598
 599                xfs_bmap_init(args->flist, args->firstblock);
 600                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
 601                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
 602                                    1, args->firstblock, args->flist,
 603                                    &done);
 604                if (!error) {
 605                        error = xfs_bmap_finish(&args->trans, args->flist,
 606                                                &committed);
 607                }
 608                if (error) {
 609                        ASSERT(committed);
 610                        args->trans = NULL;
 611                        xfs_bmap_cancel(args->flist);
 612                        return error;
 613                }
 614
 615                /*
 616                 * bmap_finish() may have committed the last trans and started
 617                 * a new one.  We need the inode to be in all transactions.
 618                 */
 619                if (committed)
 620                        xfs_trans_ijoin(args->trans, args->dp, 0);
 621
 622                /*
 623                 * Close out trans and start the next one in the chain.
 624                 */
 625                error = xfs_trans_roll(&args->trans, args->dp);
 626                if (error)
 627                        return (error);
 628        }
 629        return(0);
 630}
 631
 632
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.