LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_attr_remote.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 275 316 87.0 %
Date: 2023-07-31 20:08:17 Functions: 17 18 94.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2013 Red Hat, Inc.
       5             :  * All Rights Reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_fs.h"
       9             : #include "xfs_shared.h"
      10             : #include "xfs_format.h"
      11             : #include "xfs_log_format.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_bit.h"
      14             : #include "xfs_mount.h"
      15             : #include "xfs_defer.h"
      16             : #include "xfs_da_format.h"
      17             : #include "xfs_da_btree.h"
      18             : #include "xfs_inode.h"
      19             : #include "xfs_trans.h"
      20             : #include "xfs_bmap.h"
      21             : #include "xfs_attr.h"
      22             : #include "xfs_attr_remote.h"
      23             : #include "xfs_trace.h"
      24             : #include "xfs_error.h"
      25             : 
      26             : #define ATTR_RMTVALUE_MAPSIZE   1       /* # of map entries at once */
      27             : 
      28             : /*
      29             :  * Remote Attribute Values
      30             :  * =======================
      31             :  *
      32             :  * Remote extended attribute values are conceptually simple -- they're written
      33             :  * to data blocks mapped by an inode's attribute fork, and they have an upper
      34             :  * size limit of 64k.  Setting a value does not involve the XFS log.
      35             :  *
      36             :  * However, on a v5 filesystem, maximally sized remote attr values require one
      37             :  * block more than 64k worth of space to hold both the remote attribute value
      38             :  * header (64 bytes).  On a 4k block filesystem this results in a 68k buffer;
      39             :  * on a 64k block filesystem, this would be a 128k buffer.  Note that the log
      40             :  * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
      41             :  * Therefore, we /must/ ensure that remote attribute value buffers never touch
      42             :  * the logging system and therefore never have a log item.
      43             :  */
      44             : 
      45             : /*
      46             :  * Each contiguous block has a header, so it is not just a simple attribute
      47             :  * length to FSB conversion.
      48             :  */
      49             : int
      50    32735388 : xfs_attr3_rmt_blocks(
      51             :         struct xfs_mount *mp,
      52             :         int             attrlen)
      53             : {
      54    32735388 :         if (xfs_has_crc(mp)) {
      55    32735388 :                 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
      56    32735388 :                 return (attrlen + buflen - 1) / buflen;
      57             :         }
      58           0 :         return XFS_B_TO_FSB(mp, attrlen);
      59             : }
      60             : 
      61             : /*
      62             :  * Checking of the remote attribute header is split into two parts. The verifier
      63             :  * does CRC, location and bounds checking, the unpacking function checks the
      64             :  * attribute parameters and owner.
      65             :  */
      66             : static xfs_failaddr_t
      67        2927 : xfs_attr3_rmt_hdr_ok(
      68             :         void                    *ptr,
      69             :         xfs_ino_t               ino,
      70             :         uint32_t                offset,
      71             :         uint32_t                size,
      72             :         xfs_daddr_t             bno)
      73             : {
      74        2927 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
      75             : 
      76        2927 :         if (bno != be64_to_cpu(rmt->rm_blkno))
      77           0 :                 return __this_address;
      78        5854 :         if (offset != be32_to_cpu(rmt->rm_offset))
      79           0 :                 return __this_address;
      80        5854 :         if (size != be32_to_cpu(rmt->rm_bytes))
      81           0 :                 return __this_address;
      82        2927 :         if (ino != be64_to_cpu(rmt->rm_owner))
      83           0 :                 return __this_address;
      84             : 
      85             :         /* ok */
      86             :         return NULL;
      87             : }
      88             : 
      89             : static xfs_failaddr_t
      90        3730 : xfs_attr3_rmt_verify(
      91             :         struct xfs_mount        *mp,
      92             :         struct xfs_buf          *bp,
      93             :         void                    *ptr,
      94             :         int                     fsbsize,
      95             :         xfs_daddr_t             bno)
      96             : {
      97        3730 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
      98             : 
      99        3730 :         if (!xfs_verify_magic(bp, rmt->rm_magic))
     100           0 :                 return __this_address;
     101        3730 :         if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
     102           0 :                 return __this_address;
     103        3730 :         if (be64_to_cpu(rmt->rm_blkno) != bno)
     104           0 :                 return __this_address;
     105        3730 :         if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
     106           0 :                 return __this_address;
     107        7460 :         if (be32_to_cpu(rmt->rm_offset) +
     108        3730 :                                 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
     109           0 :                 return __this_address;
     110        3730 :         if (rmt->rm_owner == 0)
     111           0 :                 return __this_address;
     112             : 
     113             :         return NULL;
     114             : }
     115             : 
     116             : static int
     117          40 : __xfs_attr3_rmt_read_verify(
     118             :         struct xfs_buf  *bp,
     119             :         bool            check_crc,
     120             :         xfs_failaddr_t  *failaddr)
     121             : {
     122          40 :         struct xfs_mount *mp = bp->b_mount;
     123          40 :         char            *ptr;
     124          40 :         int             len;
     125          40 :         xfs_daddr_t     bno;
     126          40 :         int             blksize = mp->m_attr_geo->blksize;
     127             : 
     128             :         /* no verification of non-crc buffers */
     129          40 :         if (!xfs_has_crc(mp))
     130             :                 return 0;
     131             : 
     132          40 :         ptr = bp->b_addr;
     133          40 :         bno = xfs_buf_daddr(bp);
     134          40 :         len = BBTOB(bp->b_length);
     135          40 :         ASSERT(len >= blksize);
     136             : 
     137         272 :         while (len > 0) {
     138         464 :                 if (check_crc &&
     139         232 :                     !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
     140           0 :                         *failaddr = __this_address;
     141           0 :                         return -EFSBADCRC;
     142             :                 }
     143         232 :                 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
     144         232 :                 if (*failaddr)
     145             :                         return -EFSCORRUPTED;
     146         232 :                 len -= blksize;
     147         232 :                 ptr += blksize;
     148         232 :                 bno += BTOBB(blksize);
     149             :         }
     150             : 
     151          40 :         if (len != 0) {
     152           0 :                 *failaddr = __this_address;
     153           0 :                 return -EFSCORRUPTED;
     154             :         }
     155             : 
     156             :         return 0;
     157             : }
     158             : 
     159             : static void
     160          40 : xfs_attr3_rmt_read_verify(
     161             :         struct xfs_buf  *bp)
     162             : {
     163          40 :         xfs_failaddr_t  fa;
     164          40 :         int             error;
     165             : 
     166          40 :         error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
     167          40 :         if (error)
     168           0 :                 xfs_verifier_error(bp, error, fa);
     169          40 : }
     170             : 
     171             : static xfs_failaddr_t
     172           0 : xfs_attr3_rmt_verify_struct(
     173             :         struct xfs_buf  *bp)
     174             : {
     175           0 :         xfs_failaddr_t  fa;
     176           0 :         int             error;
     177             : 
     178           0 :         error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
     179           0 :         return error ? fa : NULL;
     180             : }
     181             : 
     182             : static void
     183         452 : xfs_attr3_rmt_write_verify(
     184             :         struct xfs_buf  *bp)
     185             : {
     186         452 :         struct xfs_mount *mp = bp->b_mount;
     187         452 :         xfs_failaddr_t  fa;
     188         452 :         int             blksize = mp->m_attr_geo->blksize;
     189         452 :         char            *ptr;
     190         452 :         int             len;
     191         452 :         xfs_daddr_t     bno;
     192             : 
     193             :         /* no verification of non-crc buffers */
     194         452 :         if (!xfs_has_crc(mp))
     195             :                 return;
     196             : 
     197         452 :         ptr = bp->b_addr;
     198         452 :         bno = xfs_buf_daddr(bp);
     199         452 :         len = BBTOB(bp->b_length);
     200         452 :         ASSERT(len >= blksize);
     201             : 
     202        3950 :         while (len > 0) {
     203        3498 :                 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
     204             : 
     205        3498 :                 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
     206        3498 :                 if (fa) {
     207           0 :                         xfs_verifier_error(bp, -EFSCORRUPTED, fa);
     208           0 :                         return;
     209             :                 }
     210             : 
     211             :                 /*
     212             :                  * Ensure we aren't writing bogus LSNs to disk. See
     213             :                  * xfs_attr3_rmt_hdr_set() for the explanation.
     214             :                  */
     215        3498 :                 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
     216           0 :                         xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
     217           0 :                         return;
     218             :                 }
     219        3498 :                 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
     220             : 
     221        3498 :                 len -= blksize;
     222        3498 :                 ptr += blksize;
     223        3498 :                 bno += BTOBB(blksize);
     224             :         }
     225             : 
     226         452 :         if (len != 0)
     227           0 :                 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
     228             : }
     229             : 
     230             : const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
     231             :         .name = "xfs_attr3_rmt",
     232             :         .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
     233             :         .verify_read = xfs_attr3_rmt_read_verify,
     234             :         .verify_write = xfs_attr3_rmt_write_verify,
     235             :         .verify_struct = xfs_attr3_rmt_verify_struct,
     236             : };
     237             : 
     238             : STATIC int
     239        3498 : xfs_attr3_rmt_hdr_set(
     240             :         struct xfs_mount        *mp,
     241             :         void                    *ptr,
     242             :         xfs_ino_t               ino,
     243             :         uint32_t                offset,
     244             :         uint32_t                size,
     245             :         xfs_daddr_t             bno)
     246             : {
     247        3498 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
     248             : 
     249        3498 :         if (!xfs_has_crc(mp))
     250             :                 return 0;
     251             : 
     252        3498 :         rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
     253        3498 :         rmt->rm_offset = cpu_to_be32(offset);
     254        3498 :         rmt->rm_bytes = cpu_to_be32(size);
     255        3498 :         uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
     256        3498 :         rmt->rm_owner = cpu_to_be64(ino);
     257        3498 :         rmt->rm_blkno = cpu_to_be64(bno);
     258             : 
     259             :         /*
     260             :          * Remote attribute blocks are written synchronously, so we don't
     261             :          * have an LSN that we can stamp in them that makes any sense to log
     262             :          * recovery. To ensure that log recovery handles overwrites of these
     263             :          * blocks sanely (i.e. once they've been freed and reallocated as some
     264             :          * other type of metadata) we need to ensure that the LSN has a value
     265             :          * that tells log recovery to ignore the LSN and overwrite the buffer
     266             :          * with whatever is in it's log. To do this, we use the magic
     267             :          * NULLCOMMITLSN to indicate that the LSN is invalid.
     268             :          */
     269        3498 :         rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
     270             : 
     271        3498 :         return sizeof(struct xfs_attr3_rmt_hdr);
     272             : }
     273             : 
     274             : /*
     275             :  * Helper functions to copy attribute data in and out of the one disk extents
     276             :  */
     277             : STATIC int
     278         221 : xfs_attr_rmtval_copyout(
     279             :         struct xfs_mount *mp,
     280             :         struct xfs_buf  *bp,
     281             :         xfs_ino_t       ino,
     282             :         int             *offset,
     283             :         int             *valuelen,
     284             :         uint8_t         **dst)
     285             : {
     286         221 :         char            *src = bp->b_addr;
     287         221 :         xfs_daddr_t     bno = xfs_buf_daddr(bp);
     288         221 :         int             len = BBTOB(bp->b_length);
     289         221 :         int             blksize = mp->m_attr_geo->blksize;
     290             : 
     291         221 :         ASSERT(len >= blksize);
     292             : 
     293        3148 :         while (len > 0 && *valuelen > 0) {
     294        2927 :                 int hdr_size = 0;
     295        2927 :                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
     296             : 
     297        2927 :                 byte_cnt = min(*valuelen, byte_cnt);
     298             : 
     299        2927 :                 if (xfs_has_crc(mp)) {
     300        2927 :                         if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
     301             :                                                   byte_cnt, bno)) {
     302           0 :                                 xfs_alert(mp,
     303             : "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
     304             :                                         bno, *offset, byte_cnt, ino);
     305           0 :                                 return -EFSCORRUPTED;
     306             :                         }
     307             :                         hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
     308             :                 }
     309             : 
     310        5854 :                 memcpy(*dst, src + hdr_size, byte_cnt);
     311             : 
     312             :                 /* roll buffer forwards */
     313        2927 :                 len -= blksize;
     314        2927 :                 src += blksize;
     315        2927 :                 bno += BTOBB(blksize);
     316             : 
     317             :                 /* roll attribute data forwards */
     318        2927 :                 *valuelen -= byte_cnt;
     319        2927 :                 *dst += byte_cnt;
     320        2927 :                 *offset += byte_cnt;
     321             :         }
     322             :         return 0;
     323             : }
     324             : 
     325             : STATIC void
     326         452 : xfs_attr_rmtval_copyin(
     327             :         struct xfs_mount *mp,
     328             :         struct xfs_buf  *bp,
     329             :         xfs_ino_t       ino,
     330             :         int             *offset,
     331             :         int             *valuelen,
     332             :         uint8_t         **src)
     333             : {
     334         452 :         char            *dst = bp->b_addr;
     335         452 :         xfs_daddr_t     bno = xfs_buf_daddr(bp);
     336         452 :         int             len = BBTOB(bp->b_length);
     337         452 :         int             blksize = mp->m_attr_geo->blksize;
     338             : 
     339         452 :         ASSERT(len >= blksize);
     340             : 
     341        3950 :         while (len > 0 && *valuelen > 0) {
     342        3498 :                 int hdr_size;
     343        3498 :                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
     344             : 
     345        3498 :                 byte_cnt = min(*valuelen, byte_cnt);
     346        3498 :                 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
     347             :                                                  byte_cnt, bno);
     348             : 
     349        6996 :                 memcpy(dst + hdr_size, *src, byte_cnt);
     350             : 
     351             :                 /*
     352             :                  * If this is the last block, zero the remainder of it.
     353             :                  * Check that we are actually the last block, too.
     354             :                  */
     355        3498 :                 if (byte_cnt + hdr_size < blksize) {
     356         452 :                         ASSERT(*valuelen - byte_cnt == 0);
     357         452 :                         ASSERT(len == blksize);
     358         904 :                         memset(dst + hdr_size + byte_cnt, 0,
     359             :                                         blksize - hdr_size - byte_cnt);
     360             :                 }
     361             : 
     362             :                 /* roll buffer forwards */
     363        3498 :                 len -= blksize;
     364        3498 :                 dst += blksize;
     365        3498 :                 bno += BTOBB(blksize);
     366             : 
     367             :                 /* roll attribute data forwards */
     368        3498 :                 *valuelen -= byte_cnt;
     369        3498 :                 *src += byte_cnt;
     370        3498 :                 *offset += byte_cnt;
     371             :         }
     372         452 : }
     373             : 
     374             : /*
     375             :  * Read the value associated with an attribute from the out-of-line buffer
     376             :  * that we stored it in.
     377             :  *
     378             :  * Returns 0 on successful retrieval, otherwise an error.
     379             :  */
     380             : int
     381         221 : xfs_attr_rmtval_get(
     382             :         struct xfs_da_args      *args)
     383             : {
     384         221 :         struct xfs_bmbt_irec    map[ATTR_RMTVALUE_MAPSIZE];
     385         221 :         struct xfs_mount        *mp = args->dp->i_mount;
     386         221 :         struct xfs_buf          *bp;
     387         221 :         xfs_dablk_t             lblkno = args->rmtblkno;
     388         221 :         uint8_t                 *dst = args->value;
     389         221 :         int                     valuelen;
     390         221 :         int                     nmap;
     391         221 :         int                     error;
     392         221 :         int                     blkcnt = args->rmtblkcnt;
     393         221 :         int                     i;
     394         221 :         int                     offset = 0;
     395             : 
     396         221 :         trace_xfs_attr_rmtval_get(args);
     397             : 
     398         221 :         ASSERT(args->valuelen != 0);
     399         221 :         ASSERT(args->rmtvaluelen == args->valuelen);
     400             : 
     401         221 :         valuelen = args->rmtvaluelen;
     402         442 :         while (valuelen > 0) {
     403         221 :                 nmap = ATTR_RMTVALUE_MAPSIZE;
     404         221 :                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
     405             :                                        blkcnt, map, &nmap,
     406             :                                        XFS_BMAPI_ATTRFORK);
     407         221 :                 if (error)
     408           0 :                         return error;
     409         221 :                 ASSERT(nmap >= 1);
     410             : 
     411         442 :                 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
     412         221 :                         xfs_daddr_t     dblkno;
     413         221 :                         int             dblkcnt;
     414             : 
     415         221 :                         ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
     416             :                                (map[i].br_startblock != HOLESTARTBLOCK));
     417         221 :                         dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
     418         221 :                         dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
     419         221 :                         error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
     420             :                                         0, &bp, &xfs_attr3_rmt_buf_ops);
     421         221 :                         if (error)
     422           0 :                                 return error;
     423             : 
     424         221 :                         error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
     425             :                                                         &offset, &valuelen,
     426             :                                                         &dst);
     427         221 :                         xfs_buf_relse(bp);
     428         221 :                         if (error)
     429           0 :                                 return error;
     430             : 
     431             :                         /* roll attribute extent map forwards */
     432         221 :                         lblkno += map[i].br_blockcount;
     433         221 :                         blkcnt -= map[i].br_blockcount;
     434             :                 }
     435             :         }
     436         221 :         ASSERT(valuelen == 0);
     437             :         return 0;
     438             : }
     439             : 
     440             : /*
     441             :  * Find a "hole" in the attribute address space large enough for us to drop the
     442             :  * new attributes value into
     443             :  */
     444             : int
     445         452 : xfs_attr_rmt_find_hole(
     446             :         struct xfs_da_args      *args)
     447             : {
     448         452 :         struct xfs_inode        *dp = args->dp;
     449         452 :         struct xfs_mount        *mp = dp->i_mount;
     450         452 :         int                     error;
     451         452 :         int                     blkcnt;
     452         452 :         xfs_fileoff_t           lfileoff = 0;
     453             : 
     454             :         /*
     455             :          * Because CRC enable attributes have headers, we can't just do a
     456             :          * straight byte to FSB conversion and have to take the header space
     457             :          * into account.
     458             :          */
     459         452 :         blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
     460         452 :         error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
     461             :                                                    XFS_ATTR_FORK);
     462         452 :         if (error)
     463             :                 return error;
     464             : 
     465         452 :         args->rmtblkno = (xfs_dablk_t)lfileoff;
     466         452 :         args->rmtblkcnt = blkcnt;
     467             : 
     468         452 :         return 0;
     469             : }
     470             : 
     471             : int
     472         452 : xfs_attr_rmtval_set_value(
     473             :         struct xfs_da_args      *args)
     474             : {
     475         452 :         struct xfs_inode        *dp = args->dp;
     476         452 :         struct xfs_mount        *mp = dp->i_mount;
     477         452 :         struct xfs_bmbt_irec    map;
     478         452 :         xfs_dablk_t             lblkno;
     479         452 :         uint8_t                 *src = args->value;
     480         452 :         int                     blkcnt;
     481         452 :         int                     valuelen;
     482         452 :         int                     nmap;
     483         452 :         int                     error;
     484         452 :         int                     offset = 0;
     485             : 
     486             :         /*
     487             :          * Roll through the "value", copying the attribute value to the
     488             :          * already-allocated blocks.  Blocks are written synchronously
     489             :          * so that we can know they are all on disk before we turn off
     490             :          * the INCOMPLETE flag.
     491             :          */
     492         452 :         lblkno = args->rmtblkno;
     493         452 :         blkcnt = args->rmtblkcnt;
     494         452 :         valuelen = args->rmtvaluelen;
     495         904 :         while (valuelen > 0) {
     496         452 :                 struct xfs_buf  *bp;
     497         452 :                 xfs_daddr_t     dblkno;
     498         452 :                 int             dblkcnt;
     499             : 
     500         452 :                 ASSERT(blkcnt > 0);
     501             : 
     502         452 :                 nmap = 1;
     503         452 :                 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
     504             :                                        blkcnt, &map, &nmap,
     505             :                                        XFS_BMAPI_ATTRFORK);
     506         452 :                 if (error)
     507           0 :                         return error;
     508         452 :                 ASSERT(nmap == 1);
     509         452 :                 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
     510             :                        (map.br_startblock != HOLESTARTBLOCK));
     511             : 
     512         452 :                 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
     513         452 :                 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
     514             : 
     515         452 :                 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
     516         452 :                 if (error)
     517           0 :                         return error;
     518         452 :                 bp->b_ops = &xfs_attr3_rmt_buf_ops;
     519             : 
     520         452 :                 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
     521             :                                        &valuelen, &src);
     522             : 
     523         452 :                 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
     524         452 :                 xfs_buf_relse(bp);
     525         452 :                 if (error)
     526           0 :                         return error;
     527             : 
     528             : 
     529             :                 /* roll attribute extent map forwards */
     530         452 :                 lblkno += map.br_blockcount;
     531         452 :                 blkcnt -= map.br_blockcount;
     532             :         }
     533         452 :         ASSERT(valuelen == 0);
     534             :         return 0;
     535             : }
     536             : 
     537             : /* Mark stale any incore buffers for the remote value. */
     538             : int
     539         424 : xfs_attr_rmtval_stale(
     540             :         struct xfs_inode        *ip,
     541             :         struct xfs_bmbt_irec    *map,
     542             :         xfs_buf_flags_t         incore_flags)
     543             : {
     544         424 :         struct xfs_mount        *mp = ip->i_mount;
     545         424 :         struct xfs_buf          *bp;
     546         424 :         int                     error;
     547             : 
     548         424 :         ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
     549             : 
     550         424 :         if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
     551         424 :             XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
     552           0 :                 return -EFSCORRUPTED;
     553             : 
     554        1272 :         error = xfs_buf_incore(mp->m_ddev_targp,
     555         424 :                         XFS_FSB_TO_DADDR(mp, map->br_startblock),
     556         424 :                         XFS_FSB_TO_BB(mp, map->br_blockcount),
     557             :                         incore_flags, &bp);
     558         424 :         if (error) {
     559         410 :                 if (error == -ENOENT)
     560             :                         return 0;
     561           0 :                 return error;
     562             :         }
     563             : 
     564          14 :         xfs_buf_stale(bp);
     565          14 :         xfs_buf_relse(bp);
     566          14 :         return 0;
     567             : }
     568             : 
     569             : /*
     570             :  * Find a hole for the attr and store it in the delayed attr context.  This
     571             :  * initializes the context to roll through allocating an attr extent for a
     572             :  * delayed attr operation
     573             :  */
     574             : int
     575         452 : xfs_attr_rmtval_find_space(
     576             :         struct xfs_attr_intent          *attr)
     577             : {
     578         452 :         struct xfs_da_args              *args = attr->xattri_da_args;
     579         452 :         struct xfs_bmbt_irec            *map = &attr->xattri_map;
     580         452 :         int                             error;
     581             : 
     582         452 :         attr->xattri_lblkno = 0;
     583         452 :         attr->xattri_blkcnt = 0;
     584         452 :         args->rmtblkcnt = 0;
     585         452 :         args->rmtblkno = 0;
     586         452 :         memset(map, 0, sizeof(struct xfs_bmbt_irec));
     587             : 
     588         452 :         error = xfs_attr_rmt_find_hole(args);
     589         452 :         if (error)
     590             :                 return error;
     591             : 
     592         452 :         attr->xattri_blkcnt = args->rmtblkcnt;
     593         452 :         attr->xattri_lblkno = args->rmtblkno;
     594             : 
     595         452 :         return 0;
     596             : }
     597             : 
     598             : /*
     599             :  * Write one block of the value associated with an attribute into the
     600             :  * out-of-line buffer that we have defined for it. This is similar to a subset
     601             :  * of xfs_attr_rmtval_set, but records the current block to the delayed attr
     602             :  * context, and leaves transaction handling to the caller.
     603             :  */
     604             : int
     605         452 : xfs_attr_rmtval_set_blk(
     606             :         struct xfs_attr_intent          *attr)
     607             : {
     608         452 :         struct xfs_da_args              *args = attr->xattri_da_args;
     609         452 :         struct xfs_inode                *dp = args->dp;
     610         452 :         struct xfs_bmbt_irec            *map = &attr->xattri_map;
     611         452 :         int nmap;
     612         452 :         int error;
     613             : 
     614         452 :         nmap = 1;
     615         452 :         error = xfs_bmapi_write(args->trans, dp,
     616         452 :                         (xfs_fileoff_t)attr->xattri_lblkno,
     617         452 :                         attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
     618             :                         map, &nmap);
     619         452 :         if (error)
     620             :                 return error;
     621             : 
     622         452 :         ASSERT(nmap == 1);
     623         452 :         ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
     624             :                (map->br_startblock != HOLESTARTBLOCK));
     625             : 
     626             :         /* roll attribute extent map forwards */
     627         452 :         attr->xattri_lblkno += map->br_blockcount;
     628         452 :         attr->xattri_blkcnt -= map->br_blockcount;
     629             : 
     630         452 :         return 0;
     631             : }
     632             : 
     633             : /*
     634             :  * Remove the value associated with an attribute by deleting the
     635             :  * out-of-line buffer that it is stored on.
     636             :  */
     637             : int
     638          16 : xfs_attr_rmtval_invalidate(
     639             :         struct xfs_da_args      *args)
     640             : {
     641          16 :         xfs_dablk_t             lblkno;
     642          16 :         int                     blkcnt;
     643          16 :         int                     error;
     644             : 
     645             :         /*
     646             :          * Roll through the "value", invalidating the attribute value's blocks.
     647             :          */
     648          16 :         lblkno = args->rmtblkno;
     649          16 :         blkcnt = args->rmtblkcnt;
     650          32 :         while (blkcnt > 0) {
     651          16 :                 struct xfs_bmbt_irec    map;
     652          16 :                 int                     nmap;
     653             : 
     654             :                 /*
     655             :                  * Try to remember where we decided to put the value.
     656             :                  */
     657          16 :                 nmap = 1;
     658          16 :                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
     659             :                                        blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
     660          16 :                 if (error)
     661           0 :                         return error;
     662          16 :                 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
     663           0 :                         return -EFSCORRUPTED;
     664          16 :                 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
     665          16 :                 if (error)
     666           0 :                         return error;
     667             : 
     668          16 :                 lblkno += map.br_blockcount;
     669          16 :                 blkcnt -= map.br_blockcount;
     670             :         }
     671             :         return 0;
     672             : }
     673             : 
     674             : /*
     675             :  * Remove the value associated with an attribute by deleting the out-of-line
     676             :  * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the
     677             :  * transaction and re-call the function.  Callers should keep calling this
     678             :  * routine until it returns something other than -EAGAIN.
     679             :  */
     680             : int
     681          16 : xfs_attr_rmtval_remove(
     682             :         struct xfs_attr_intent          *attr)
     683             : {
     684          16 :         struct xfs_da_args              *args = attr->xattri_da_args;
     685          16 :         int                             error, done;
     686             : 
     687             :         /*
     688             :          * Unmap value blocks for this attr.
     689             :          */
     690          16 :         error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
     691          16 :                             args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
     692          16 :         if (error)
     693             :                 return error;
     694             : 
     695             :         /*
     696             :          * We don't need an explicit state here to pick up where we left off. We
     697             :          * can figure it out using the !done return code. The actual value of
     698             :          * attr->xattri_dela_state may be some value reminiscent of the calling
     699             :          * function, but it's value is irrelevant with in the context of this
     700             :          * function. Once we are done here, the next state is set as needed by
     701             :          * the parent
     702             :          */
     703          16 :         if (!done) {
     704           0 :                 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
     705             :                                                     args->dp);
     706           0 :                 return -EAGAIN;
     707             :         }
     708             : 
     709          16 :         args->rmtblkno = 0;
     710          16 :         args->rmtblkcnt = 0;
     711          16 :         return 0;
     712             : }

Generated by: LCOV version 1.14