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-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 274 315 87.0 %
Date: 2023-07-31 20:08:22 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    44990208 : xfs_attr3_rmt_blocks(
      51             :         struct xfs_mount *mp,
      52             :         int             attrlen)
      53             : {
      54    44990208 :         if (xfs_has_crc(mp)) {
      55    44990208 :                 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
      56    44990208 :                 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       11869 : 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       11869 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
      75             : 
      76       11869 :         if (bno != be64_to_cpu(rmt->rm_blkno))
      77           0 :                 return __this_address;
      78       11869 :         if (offset != be32_to_cpu(rmt->rm_offset))
      79           0 :                 return __this_address;
      80       11869 :         if (size != be32_to_cpu(rmt->rm_bytes))
      81           0 :                 return __this_address;
      82       11869 :         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       33741 : 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       33741 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
      98             : 
      99       33741 :         if (!xfs_verify_magic(bp, rmt->rm_magic))
     100           0 :                 return __this_address;
     101       33741 :         if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
     102           0 :                 return __this_address;
     103       33741 :         if (be64_to_cpu(rmt->rm_blkno) != bno)
     104           0 :                 return __this_address;
     105       33741 :         if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
     106           0 :                 return __this_address;
     107       33741 :         if (be32_to_cpu(rmt->rm_offset) +
     108             :                                 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
     109           0 :                 return __this_address;
     110       33741 :         if (rmt->rm_owner == 0)
     111           0 :                 return __this_address;
     112             : 
     113             :         return NULL;
     114             : }
     115             : 
     116             : static int
     117         264 : __xfs_attr3_rmt_read_verify(
     118             :         struct xfs_buf  *bp,
     119             :         bool            check_crc,
     120             :         xfs_failaddr_t  *failaddr)
     121             : {
     122         264 :         struct xfs_mount *mp = bp->b_mount;
     123         264 :         char            *ptr;
     124         264 :         int             len;
     125         264 :         xfs_daddr_t     bno;
     126         264 :         int             blksize = mp->m_attr_geo->blksize;
     127             : 
     128             :         /* no verification of non-crc buffers */
     129         264 :         if (!xfs_has_crc(mp))
     130             :                 return 0;
     131             : 
     132         264 :         ptr = bp->b_addr;
     133         264 :         bno = xfs_buf_daddr(bp);
     134         264 :         len = BBTOB(bp->b_length);
     135         264 :         ASSERT(len >= blksize);
     136             : 
     137        3640 :         while (len > 0) {
     138        6752 :                 if (check_crc &&
     139        3376 :                     !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
     140           0 :                         *failaddr = __this_address;
     141           0 :                         return -EFSBADCRC;
     142             :                 }
     143        3376 :                 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
     144        3376 :                 if (*failaddr)
     145             :                         return -EFSCORRUPTED;
     146        3376 :                 len -= blksize;
     147        3376 :                 ptr += blksize;
     148        3376 :                 bno += BTOBB(blksize);
     149             :         }
     150             : 
     151         264 :         if (len != 0) {
     152           0 :                 *failaddr = __this_address;
     153           0 :                 return -EFSCORRUPTED;
     154             :         }
     155             : 
     156             :         return 0;
     157             : }
     158             : 
     159             : static void
     160         264 : xfs_attr3_rmt_read_verify(
     161             :         struct xfs_buf  *bp)
     162             : {
     163         264 :         xfs_failaddr_t  fa;
     164         264 :         int             error;
     165             : 
     166         264 :         error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
     167         264 :         if (error)
     168           0 :                 xfs_verifier_error(bp, error, fa);
     169         264 : }
     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        2836 : xfs_attr3_rmt_write_verify(
     184             :         struct xfs_buf  *bp)
     185             : {
     186        2836 :         struct xfs_mount *mp = bp->b_mount;
     187        2836 :         xfs_failaddr_t  fa;
     188        2836 :         int             blksize = mp->m_attr_geo->blksize;
     189        2836 :         char            *ptr;
     190        2836 :         int             len;
     191        2836 :         xfs_daddr_t     bno;
     192             : 
     193             :         /* no verification of non-crc buffers */
     194        2836 :         if (!xfs_has_crc(mp))
     195             :                 return;
     196             : 
     197        2836 :         ptr = bp->b_addr;
     198        2836 :         bno = xfs_buf_daddr(bp);
     199        2836 :         len = BBTOB(bp->b_length);
     200        2836 :         ASSERT(len >= blksize);
     201             : 
     202       33201 :         while (len > 0) {
     203       30365 :                 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
     204             : 
     205       30365 :                 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
     206       30365 :                 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       30365 :                 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
     216           0 :                         xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
     217           0 :                         return;
     218             :                 }
     219       30365 :                 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
     220             : 
     221       30365 :                 len -= blksize;
     222       30365 :                 ptr += blksize;
     223       30365 :                 bno += BTOBB(blksize);
     224             :         }
     225             : 
     226        2836 :         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       30365 : 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       30365 :         struct xfs_attr3_rmt_hdr *rmt = ptr;
     248             : 
     249       30365 :         if (!xfs_has_crc(mp))
     250             :                 return 0;
     251             : 
     252       30365 :         rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
     253       30365 :         rmt->rm_offset = cpu_to_be32(offset);
     254       30365 :         rmt->rm_bytes = cpu_to_be32(size);
     255       30365 :         uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
     256       30365 :         rmt->rm_owner = cpu_to_be64(ino);
     257       30365 :         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       30365 :         rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
     270             : 
     271       30365 :         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         784 : 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         784 :         char            *src = bp->b_addr;
     287         784 :         xfs_daddr_t     bno = xfs_buf_daddr(bp);
     288         784 :         int             len = BBTOB(bp->b_length);
     289         784 :         int             blksize = mp->m_attr_geo->blksize;
     290             : 
     291         784 :         ASSERT(len >= blksize);
     292             : 
     293       12653 :         while (len > 0 && *valuelen > 0) {
     294       11869 :                 int hdr_size = 0;
     295       11869 :                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
     296             : 
     297       11869 :                 byte_cnt = min(*valuelen, byte_cnt);
     298             : 
     299       11869 :                 if (xfs_has_crc(mp)) {
     300       11869 :                         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       23738 :                 memcpy(*dst, src + hdr_size, byte_cnt);
     311             : 
     312             :                 /* roll buffer forwards */
     313       11869 :                 len -= blksize;
     314       11869 :                 src += blksize;
     315       11869 :                 bno += BTOBB(blksize);
     316             : 
     317             :                 /* roll attribute data forwards */
     318       11869 :                 *valuelen -= byte_cnt;
     319       11869 :                 *dst += byte_cnt;
     320       11869 :                 *offset += byte_cnt;
     321             :         }
     322             :         return 0;
     323             : }
     324             : 
     325             : STATIC void
     326        2836 : 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        2836 :         char            *dst = bp->b_addr;
     335        2836 :         xfs_daddr_t     bno = xfs_buf_daddr(bp);
     336        2836 :         int             len = BBTOB(bp->b_length);
     337        2836 :         int             blksize = mp->m_attr_geo->blksize;
     338             : 
     339        2836 :         ASSERT(len >= blksize);
     340             : 
     341       33201 :         while (len > 0 && *valuelen > 0) {
     342       30365 :                 int hdr_size;
     343       30365 :                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
     344             : 
     345       30365 :                 byte_cnt = min(*valuelen, byte_cnt);
     346       30365 :                 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
     347             :                                                  byte_cnt, bno);
     348             : 
     349       60730 :                 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       30365 :                 if (byte_cnt + hdr_size < blksize) {
     356        2836 :                         ASSERT(*valuelen - byte_cnt == 0);
     357        2836 :                         ASSERT(len == blksize);
     358        5672 :                         memset(dst + hdr_size + byte_cnt, 0,
     359             :                                         blksize - hdr_size - byte_cnt);
     360             :                 }
     361             : 
     362             :                 /* roll buffer forwards */
     363       30365 :                 len -= blksize;
     364       30365 :                 dst += blksize;
     365       30365 :                 bno += BTOBB(blksize);
     366             : 
     367             :                 /* roll attribute data forwards */
     368       30365 :                 *valuelen -= byte_cnt;
     369       30365 :                 *src += byte_cnt;
     370       30365 :                 *offset += byte_cnt;
     371             :         }
     372        2836 : }
     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         784 : xfs_attr_rmtval_get(
     382             :         struct xfs_da_args      *args)
     383             : {
     384         784 :         struct xfs_bmbt_irec    map[ATTR_RMTVALUE_MAPSIZE];
     385         784 :         struct xfs_mount        *mp = args->dp->i_mount;
     386         784 :         struct xfs_buf          *bp;
     387         784 :         xfs_dablk_t             lblkno = args->rmtblkno;
     388         784 :         uint8_t                 *dst = args->value;
     389         784 :         int                     valuelen;
     390         784 :         int                     nmap;
     391         784 :         int                     error;
     392         784 :         int                     blkcnt = args->rmtblkcnt;
     393         784 :         int                     i;
     394         784 :         int                     offset = 0;
     395             : 
     396         784 :         trace_xfs_attr_rmtval_get(args);
     397             : 
     398         784 :         ASSERT(args->valuelen != 0);
     399         784 :         ASSERT(args->rmtvaluelen == args->valuelen);
     400             : 
     401         784 :         valuelen = args->rmtvaluelen;
     402        1568 :         while (valuelen > 0) {
     403         784 :                 nmap = ATTR_RMTVALUE_MAPSIZE;
     404         784 :                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
     405             :                                        blkcnt, map, &nmap,
     406             :                                        XFS_BMAPI_ATTRFORK);
     407         784 :                 if (error)
     408           0 :                         return error;
     409         784 :                 ASSERT(nmap >= 1);
     410             : 
     411        1568 :                 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
     412         784 :                         xfs_daddr_t     dblkno;
     413         784 :                         int             dblkcnt;
     414             : 
     415         784 :                         ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
     416             :                                (map[i].br_startblock != HOLESTARTBLOCK));
     417         784 :                         dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
     418         784 :                         dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
     419         784 :                         error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
     420             :                                         0, &bp, &xfs_attr3_rmt_buf_ops);
     421         784 :                         if (error)
     422           0 :                                 return error;
     423             : 
     424         784 :                         error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
     425             :                                                         &offset, &valuelen,
     426             :                                                         &dst);
     427         784 :                         xfs_buf_relse(bp);
     428         784 :                         if (error)
     429           0 :                                 return error;
     430             : 
     431             :                         /* roll attribute extent map forwards */
     432         784 :                         lblkno += map[i].br_blockcount;
     433         784 :                         blkcnt -= map[i].br_blockcount;
     434             :                 }
     435             :         }
     436         784 :         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        2836 : xfs_attr_rmt_find_hole(
     446             :         struct xfs_da_args      *args)
     447             : {
     448        2836 :         struct xfs_inode        *dp = args->dp;
     449        2836 :         struct xfs_mount        *mp = dp->i_mount;
     450        2836 :         int                     error;
     451        2836 :         int                     blkcnt;
     452        2836 :         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        2836 :         blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
     460        2836 :         error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
     461             :                                                    XFS_ATTR_FORK);
     462        2836 :         if (error)
     463             :                 return error;
     464             : 
     465        2836 :         args->rmtblkno = (xfs_dablk_t)lfileoff;
     466        2836 :         args->rmtblkcnt = blkcnt;
     467             : 
     468        2836 :         return 0;
     469             : }
     470             : 
     471             : int
     472        2836 : xfs_attr_rmtval_set_value(
     473             :         struct xfs_da_args      *args)
     474             : {
     475        2836 :         struct xfs_inode        *dp = args->dp;
     476        2836 :         struct xfs_mount        *mp = dp->i_mount;
     477        2836 :         struct xfs_bmbt_irec    map;
     478        2836 :         xfs_dablk_t             lblkno;
     479        2836 :         uint8_t                 *src = args->value;
     480        2836 :         int                     blkcnt;
     481        2836 :         int                     valuelen;
     482        2836 :         int                     nmap;
     483        2836 :         int                     error;
     484        2836 :         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        2836 :         lblkno = args->rmtblkno;
     493        2836 :         blkcnt = args->rmtblkcnt;
     494        2836 :         valuelen = args->rmtvaluelen;
     495        5672 :         while (valuelen > 0) {
     496        2836 :                 struct xfs_buf  *bp;
     497        2836 :                 xfs_daddr_t     dblkno;
     498        2836 :                 int             dblkcnt;
     499             : 
     500        2836 :                 ASSERT(blkcnt > 0);
     501             : 
     502        2836 :                 nmap = 1;
     503        2836 :                 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
     504             :                                        blkcnt, &map, &nmap,
     505             :                                        XFS_BMAPI_ATTRFORK);
     506        2836 :                 if (error)
     507           0 :                         return error;
     508        2836 :                 ASSERT(nmap == 1);
     509        2836 :                 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
     510             :                        (map.br_startblock != HOLESTARTBLOCK));
     511             : 
     512        2836 :                 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
     513        2836 :                 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
     514             : 
     515        2836 :                 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
     516        2836 :                 if (error)
     517           0 :                         return error;
     518        2836 :                 bp->b_ops = &xfs_attr3_rmt_buf_ops;
     519             : 
     520        2836 :                 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
     521             :                                        &valuelen, &src);
     522             : 
     523        2836 :                 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
     524        2836 :                 xfs_buf_relse(bp);
     525        2836 :                 if (error)
     526           0 :                         return error;
     527             : 
     528             : 
     529             :                 /* roll attribute extent map forwards */
     530        2836 :                 lblkno += map.br_blockcount;
     531        2836 :                 blkcnt -= map.br_blockcount;
     532             :         }
     533        2836 :         ASSERT(valuelen == 0);
     534             :         return 0;
     535             : }
     536             : 
     537             : /* Mark stale any incore buffers for the remote value. */
     538             : int
     539        2633 : xfs_attr_rmtval_stale(
     540             :         struct xfs_inode        *ip,
     541             :         struct xfs_bmbt_irec    *map,
     542             :         xfs_buf_flags_t         incore_flags)
     543             : {
     544        2633 :         struct xfs_mount        *mp = ip->i_mount;
     545        2633 :         struct xfs_buf          *bp;
     546        2633 :         int                     error;
     547             : 
     548        2633 :         ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
     549             : 
     550        2633 :         if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
     551        2633 :             XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
     552           0 :                 return -EFSCORRUPTED;
     553             : 
     554        7899 :         error = xfs_buf_incore(mp->m_ddev_targp,
     555        2633 :                         XFS_FSB_TO_DADDR(mp, map->br_startblock),
     556        2633 :                         XFS_FSB_TO_BB(mp, map->br_blockcount),
     557             :                         incore_flags, &bp);
     558        2633 :         if (error) {
     559        2255 :                 if (error == -ENOENT)
     560             :                         return 0;
     561           0 :                 return error;
     562             :         }
     563             : 
     564         378 :         xfs_buf_stale(bp);
     565         378 :         xfs_buf_relse(bp);
     566         378 :         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        2836 : xfs_attr_rmtval_find_space(
     576             :         struct xfs_attr_intent          *attr)
     577             : {
     578        2836 :         struct xfs_da_args              *args = attr->xattri_da_args;
     579        2836 :         struct xfs_bmbt_irec            *map = &attr->xattri_map;
     580        2836 :         int                             error;
     581             : 
     582        2836 :         attr->xattri_lblkno = 0;
     583        2836 :         attr->xattri_blkcnt = 0;
     584        2836 :         args->rmtblkcnt = 0;
     585        2836 :         args->rmtblkno = 0;
     586        2836 :         memset(map, 0, sizeof(struct xfs_bmbt_irec));
     587             : 
     588        2836 :         error = xfs_attr_rmt_find_hole(args);
     589        2836 :         if (error)
     590             :                 return error;
     591             : 
     592        2836 :         attr->xattri_blkcnt = args->rmtblkcnt;
     593        2836 :         attr->xattri_lblkno = args->rmtblkno;
     594             : 
     595        2836 :         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        2836 : xfs_attr_rmtval_set_blk(
     606             :         struct xfs_attr_intent          *attr)
     607             : {
     608        2836 :         struct xfs_da_args              *args = attr->xattri_da_args;
     609        2836 :         struct xfs_inode                *dp = args->dp;
     610        2836 :         struct xfs_bmbt_irec            *map = &attr->xattri_map;
     611        2836 :         int nmap;
     612        2836 :         int error;
     613             : 
     614        2836 :         nmap = 1;
     615        2836 :         error = xfs_bmapi_write(args->trans, dp,
     616        2836 :                         (xfs_fileoff_t)attr->xattri_lblkno,
     617        2836 :                         attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
     618             :                         map, &nmap);
     619        2836 :         if (error)
     620             :                 return error;
     621             : 
     622        2836 :         ASSERT(nmap == 1);
     623        2836 :         ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
     624             :                (map->br_startblock != HOLESTARTBLOCK));
     625             : 
     626             :         /* roll attribute extent map forwards */
     627        2836 :         attr->xattri_lblkno += map->br_blockcount;
     628        2836 :         attr->xattri_blkcnt -= map->br_blockcount;
     629             : 
     630        2836 :         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          88 : xfs_attr_rmtval_invalidate(
     639             :         struct xfs_da_args      *args)
     640             : {
     641          88 :         xfs_dablk_t             lblkno;
     642          88 :         int                     blkcnt;
     643          88 :         int                     error;
     644             : 
     645             :         /*
     646             :          * Roll through the "value", invalidating the attribute value's blocks.
     647             :          */
     648          88 :         lblkno = args->rmtblkno;
     649          88 :         blkcnt = args->rmtblkcnt;
     650         176 :         while (blkcnt > 0) {
     651          88 :                 struct xfs_bmbt_irec    map;
     652          88 :                 int                     nmap;
     653             : 
     654             :                 /*
     655             :                  * Try to remember where we decided to put the value.
     656             :                  */
     657          88 :                 nmap = 1;
     658          88 :                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
     659             :                                        blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
     660          88 :                 if (error)
     661           0 :                         return error;
     662          88 :                 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
     663           0 :                         return -EFSCORRUPTED;
     664          88 :                 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
     665          88 :                 if (error)
     666           0 :                         return error;
     667             : 
     668          88 :                 lblkno += map.br_blockcount;
     669          88 :                 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          88 : xfs_attr_rmtval_remove(
     682             :         struct xfs_attr_intent          *attr)
     683             : {
     684          88 :         struct xfs_da_args              *args = attr->xattri_da_args;
     685          88 :         int                             error, done;
     686             : 
     687             :         /*
     688             :          * Unmap value blocks for this attr.
     689             :          */
     690          88 :         error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
     691          88 :                             args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
     692          88 :         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          88 :         if (!done) {
     704           0 :                 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
     705             :                                                     args->dp);
     706           0 :                 return -EAGAIN;
     707             :         }
     708             : 
     709          88 :         args->rmtblkno = 0;
     710          88 :         args->rmtblkcnt = 0;
     711          88 :         return 0;
     712             : }

Generated by: LCOV version 1.14