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

Generated by: LCOV version 1.14