LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_symlink_remote.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 177 206 85.9 %
Date: 2023-07-31 20:08:34 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2012-2013 Red Hat, Inc.
       5             :  * All rights reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_fs.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_shared.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_inode.h"
      15             : #include "xfs_error.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_buf_item.h"
      18             : #include "xfs_log.h"
      19             : #include "xfs_symlink_remote.h"
      20             : #include "xfs_bit.h"
      21             : #include "xfs_bmap.h"
      22             : #include "xfs_health.h"
      23             : 
      24             : /*
      25             :  * Each contiguous block has a header, so it is not just a simple pathlen
      26             :  * to FSB conversion.
      27             :  */
      28             : int
      29   276358447 : xfs_symlink_blocks(
      30             :         struct xfs_mount *mp,
      31             :         int             pathlen)
      32             : {
      33   276358447 :         int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
      34             : 
      35   276358447 :         return (pathlen + buflen - 1) / buflen;
      36             : }
      37             : 
      38             : int
      39    25547448 : xfs_symlink_hdr_set(
      40             :         struct xfs_mount        *mp,
      41             :         xfs_ino_t               ino,
      42             :         uint32_t                offset,
      43             :         uint32_t                size,
      44             :         struct xfs_buf          *bp)
      45             : {
      46    25547448 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      47             : 
      48    25547448 :         if (!xfs_has_crc(mp))
      49             :                 return 0;
      50             : 
      51    25547448 :         memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
      52    25547448 :         dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
      53    25547448 :         dsl->sl_offset = cpu_to_be32(offset);
      54    25547448 :         dsl->sl_bytes = cpu_to_be32(size);
      55    25547448 :         uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
      56    25553057 :         dsl->sl_owner = cpu_to_be64(ino);
      57    25553057 :         dsl->sl_blkno = cpu_to_be64(xfs_buf_daddr(bp));
      58    25553057 :         bp->b_ops = &xfs_symlink_buf_ops;
      59             : 
      60    25553057 :         return sizeof(struct xfs_dsymlink_hdr);
      61             : }
      62             : 
      63             : /*
      64             :  * Checking of the symlink header is split into two parts. the verifier does
      65             :  * CRC, location and bounds checking, the unpacking function checks the path
      66             :  * parameters and owner.
      67             :  */
      68             : bool
      69   244496793 : xfs_symlink_hdr_ok(
      70             :         xfs_ino_t               ino,
      71             :         uint32_t                offset,
      72             :         uint32_t                size,
      73             :         struct xfs_buf          *bp)
      74             : {
      75   244496793 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      76             : 
      77   244496793 :         if (offset != be32_to_cpu(dsl->sl_offset))
      78             :                 return false;
      79   244787532 :         if (size != be32_to_cpu(dsl->sl_bytes))
      80             :                 return false;
      81   244789284 :         if (ino != be64_to_cpu(dsl->sl_owner))
      82           0 :                 return false;
      83             : 
      84             :         /* ok */
      85             :         return true;
      86             : }
      87             : 
      88             : static xfs_failaddr_t
      89     4139868 : xfs_symlink_verify(
      90             :         struct xfs_buf          *bp)
      91             : {
      92     4139868 :         struct xfs_mount        *mp = bp->b_mount;
      93     4139868 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      94             : 
      95     4139868 :         if (!xfs_has_crc(mp))
      96           0 :                 return __this_address;
      97     4139868 :         if (!xfs_verify_magic(bp, dsl->sl_magic))
      98           0 :                 return __this_address;
      99     4139868 :         if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
     100           0 :                 return __this_address;
     101     4139868 :         if (xfs_buf_daddr(bp) != be64_to_cpu(dsl->sl_blkno))
     102           0 :                 return __this_address;
     103     4139868 :         if (be32_to_cpu(dsl->sl_offset) +
     104     4139868 :                                 be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
     105           0 :                 return __this_address;
     106     4139868 :         if (dsl->sl_owner == 0)
     107           0 :                 return __this_address;
     108     4139868 :         if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
     109           0 :                 return __this_address;
     110             : 
     111             :         return NULL;
     112             : }
     113             : 
     114             : static void
     115      138875 : xfs_symlink_read_verify(
     116             :         struct xfs_buf  *bp)
     117             : {
     118      138875 :         struct xfs_mount *mp = bp->b_mount;
     119      138875 :         xfs_failaddr_t  fa;
     120             : 
     121             :         /* no verification of non-crc buffers */
     122      138875 :         if (!xfs_has_crc(mp))
     123             :                 return;
     124             : 
     125      138875 :         if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
     126          10 :                 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
     127             :         else {
     128      138865 :                 fa = xfs_symlink_verify(bp);
     129      138865 :                 if (fa)
     130           0 :                         xfs_verifier_error(bp, -EFSCORRUPTED, fa);
     131             :         }
     132             : }
     133             : 
     134             : static void
     135     3982441 : xfs_symlink_write_verify(
     136             :         struct xfs_buf  *bp)
     137             : {
     138     3982441 :         struct xfs_mount *mp = bp->b_mount;
     139     3982441 :         struct xfs_buf_log_item *bip = bp->b_log_item;
     140     3982441 :         xfs_failaddr_t          fa;
     141             : 
     142             :         /* no verification of non-crc buffers */
     143     3982441 :         if (!xfs_has_crc(mp))
     144             :                 return;
     145             : 
     146     3982441 :         fa = xfs_symlink_verify(bp);
     147     3982441 :         if (fa) {
     148           0 :                 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
     149           0 :                 return;
     150             :         }
     151             : 
     152     3982441 :         if (bip) {
     153     3982441 :                 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
     154     3982441 :                 dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
     155             :         }
     156     3982441 :         xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
     157             : }
     158             : 
     159             : const struct xfs_buf_ops xfs_symlink_buf_ops = {
     160             :         .name = "xfs_symlink",
     161             :         .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
     162             :         .verify_read = xfs_symlink_read_verify,
     163             :         .verify_write = xfs_symlink_write_verify,
     164             :         .verify_struct = xfs_symlink_verify,
     165             : };
     166             : 
     167             : void
     168        3141 : xfs_symlink_local_to_remote(
     169             :         struct xfs_trans        *tp,
     170             :         struct xfs_buf          *bp,
     171             :         struct xfs_inode        *ip,
     172             :         struct xfs_ifork        *ifp,
     173             :         void                    *priv)
     174             : {
     175        3141 :         struct xfs_mount        *mp = ip->i_mount;
     176        3141 :         char                    *buf;
     177             : 
     178        3141 :         xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
     179             : 
     180        3141 :         if (!xfs_has_crc(mp)) {
     181           0 :                 bp->b_ops = NULL;
     182           0 :                 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
     183           0 :                 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
     184           0 :                 return;
     185             :         }
     186             : 
     187             :         /*
     188             :          * As this symlink fits in an inode literal area, it must also fit in
     189             :          * the smallest buffer the filesystem supports.
     190             :          */
     191        3141 :         ASSERT(BBTOB(bp->b_length) >=
     192             :                         ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
     193             : 
     194        3141 :         bp->b_ops = &xfs_symlink_buf_ops;
     195             : 
     196        3141 :         buf = bp->b_addr;
     197        3141 :         buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
     198        6282 :         memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
     199        3141 :         xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
     200        3141 :                                         ifp->if_bytes - 1);
     201             : }
     202             : 
     203             : /*
     204             :  * Verify the in-memory consistency of an inline symlink data fork. This
     205             :  * does not do on-disk format checks.
     206             :  */
     207             : xfs_failaddr_t
     208     5740208 : xfs_symlink_sf_verify_struct(
     209             :         void                    *sfp,
     210             :         int64_t                 size)
     211             : {
     212     5740208 :         char                    *endp = sfp + size;
     213             : 
     214             :         /*
     215             :          * Zero length symlinks should never occur in memory as they are
     216             :          * never allowed to exist on disk.
     217             :          */
     218     5740208 :         if (!size)
     219           0 :                 return __this_address;
     220             : 
     221             :         /* No negative sizes or overly long symlink targets. */
     222     5740208 :         if (size < 0 || size > XFS_SYMLINK_MAXLEN)
     223           0 :                 return __this_address;
     224             : 
     225             :         /* No NULLs in the target either. */
     226    11480416 :         if (memchr(sfp, 0, size - 1))
     227          11 :                 return __this_address;
     228             : 
     229             :         /* We /did/ null-terminate the buffer, right? */
     230     5740197 :         if (*endp != 0)
     231           0 :                 return __this_address;
     232             :         return NULL;
     233             : }
     234             : 
     235             : xfs_failaddr_t
     236     5740209 : xfs_symlink_shortform_verify(
     237             :         struct xfs_inode        *ip)
     238             : {
     239     5740209 :         struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
     240             : 
     241     5740209 :         ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
     242             : 
     243     5740209 :         return xfs_symlink_sf_verify_struct(ifp->if_u1.if_data, ifp->if_bytes);
     244             : }
     245             : 
     246             : /* Read a remote symlink target into the buffer. */
     247             : int
     248   244742298 : xfs_symlink_remote_read(
     249             :         struct xfs_inode        *ip,
     250             :         char                    *link)
     251             : {
     252   244742298 :         struct xfs_mount        *mp = ip->i_mount;
     253   244742298 :         struct xfs_bmbt_irec    mval[XFS_SYMLINK_MAPS];
     254   244742298 :         struct xfs_buf          *bp;
     255   244742298 :         xfs_daddr_t             d;
     256   244742298 :         char                    *cur_chunk;
     257   244742298 :         int                     pathlen = ip->i_disk_size;
     258   244742298 :         int                     nmaps = XFS_SYMLINK_MAPS;
     259   244742298 :         int                     byte_cnt;
     260   244742298 :         int                     n;
     261   244742298 :         int                     error = 0;
     262   244742298 :         int                     fsblocks = 0;
     263   244742298 :         int                     offset;
     264             : 
     265   244742298 :         ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
     266             : 
     267   244558505 :         fsblocks = xfs_symlink_blocks(mp, pathlen);
     268   244547569 :         error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
     269   244399632 :         if (error)
     270           0 :                 goto out;
     271             : 
     272             :         offset = 0;
     273   489151471 :         for (n = 0; n < nmaps; n++) {
     274   244392390 :                 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
     275   244420670 :                 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
     276             : 
     277   244480626 :                 error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
     278             :                                 &bp, &xfs_symlink_buf_ops);
     279   244743648 :                 if (xfs_metadata_is_sick(error))
     280          10 :                         xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
     281   244743648 :                 if (error)
     282          10 :                         return error;
     283   244743638 :                 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
     284   244743638 :                 if (pathlen < byte_cnt)
     285             :                         byte_cnt = pathlen;
     286             : 
     287   244743638 :                 cur_chunk = bp->b_addr;
     288   244743638 :                 if (xfs_has_crc(mp)) {
     289   244746578 :                         if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
     290             :                                                         byte_cnt, bp)) {
     291           0 :                                 xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
     292           0 :                                 error = -EFSCORRUPTED;
     293           0 :                                 xfs_alert(mp,
     294             : "symlink header does not match required off/len/owner (0x%x/0x%x,0x%llx)",
     295             :                                         offset, byte_cnt, ip->i_ino);
     296           0 :                                 xfs_buf_relse(bp);
     297           0 :                                 goto out;
     298             : 
     299             :                         }
     300             : 
     301   244746578 :                         cur_chunk += sizeof(struct xfs_dsymlink_hdr);
     302             :                 }
     303             : 
     304   489487276 :                 memcpy(link + offset, cur_chunk, byte_cnt);
     305             : 
     306   244743638 :                 pathlen -= byte_cnt;
     307   244743638 :                 offset += byte_cnt;
     308             : 
     309   244743638 :                 xfs_buf_relse(bp);
     310             :         }
     311   244759081 :         ASSERT(pathlen == 0);
     312             : 
     313   244759081 :         link[ip->i_disk_size] = '\0';
     314   244759081 :         error = 0;
     315             : 
     316             :  out:
     317             :         return error;
     318             : }
     319             : 
     320             : /* Write the symlink target into the inode. */
     321             : int
     322    31992676 : __xfs_symlink_write_target(
     323             :         struct xfs_trans        *tp,
     324             :         struct xfs_inode        *ip,
     325             :         xfs_ino_t               owner,
     326             :         const char              *target_path,
     327             :         int                     pathlen,
     328             :         xfs_fsblock_t           fs_blocks,
     329             :         uint                    resblks)
     330             : {
     331    31992676 :         struct xfs_bmbt_irec    mval[XFS_SYMLINK_MAPS];
     332    31992676 :         struct xfs_mount        *mp = tp->t_mountp;
     333    31992676 :         const char              *cur_chunk;
     334    31992676 :         struct xfs_buf          *bp;
     335    31992676 :         xfs_daddr_t             d;
     336    31992676 :         int                     byte_cnt;
     337    31992676 :         int                     nmaps;
     338    31992676 :         int                     offset = 0;
     339    31992676 :         int                     n;
     340    31992676 :         int                     error;
     341             : 
     342             :         /*
     343             :          * If the symlink will fit into the inode, write it inline.
     344             :          */
     345    31992676 :         if (pathlen <= xfs_inode_data_fork_size(ip)) {
     346     6435657 :                 xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
     347             : 
     348     6438158 :                 ip->i_disk_size = pathlen;
     349     6438158 :                 ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
     350     6438158 :                 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
     351     6438158 :                 return 0;
     352             :         }
     353             : 
     354    25557019 :         nmaps = XFS_SYMLINK_MAPS;
     355    25557019 :         error = xfs_bmapi_write(tp, ip, 0, fs_blocks, XFS_BMAPI_METADATA,
     356             :                         resblks, mval, &nmaps);
     357    25583511 :         if (error)
     358             :                 return error;
     359             : 
     360    25557142 :         ip->i_disk_size = pathlen;
     361    25557142 :         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
     362             : 
     363    25557142 :         cur_chunk = target_path;
     364    25557142 :         offset = 0;
     365    76790160 :         for (n = 0; n < nmaps; n++) {
     366    25627397 :                 char    *buf;
     367             : 
     368    25627397 :                 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
     369    25571941 :                 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
     370    25571871 :                 error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
     371    25571871 :                                 BTOBB(byte_cnt), 0, &bp);
     372    25592350 :                 if (error)
     373           0 :                         return error;
     374    25592350 :                 bp->b_ops = &xfs_symlink_buf_ops;
     375             : 
     376    25592350 :                 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
     377    25592350 :                 byte_cnt = min(byte_cnt, pathlen);
     378             : 
     379    25592350 :                 buf = bp->b_addr;
     380    25592350 :                 buf += xfs_symlink_hdr_set(mp, owner, offset, byte_cnt, bp);
     381             : 
     382    51138926 :                 memcpy(buf, cur_chunk, byte_cnt);
     383             : 
     384    25569463 :                 cur_chunk += byte_cnt;
     385    25569463 :                 pathlen -= byte_cnt;
     386    25569463 :                 offset += byte_cnt;
     387             : 
     388    25569463 :                 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
     389    25595879 :                 xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
     390    25595879 :                                                 (char *)bp->b_addr);
     391             :         }
     392    25605621 :         ASSERT(pathlen == 0);
     393             :         return 0;
     394             : }
     395             : 
     396             : /* Remove all the blocks from a symlink and invalidate buffers. */
     397             : int
     398    23761697 : xfs_symlink_remote_truncate(
     399             :         struct xfs_trans        *tp,
     400             :         struct xfs_inode        *ip)
     401             : {
     402    23761697 :         struct xfs_bmbt_irec    mval[XFS_SYMLINK_MAPS];
     403    23761697 :         struct xfs_mount        *mp = tp->t_mountp;
     404    23761697 :         struct xfs_buf          *bp;
     405    23761697 :         int                     nmaps = XFS_SYMLINK_MAPS;
     406    23761697 :         int                     done = 0;
     407    23761697 :         int                     i;
     408    23761697 :         int                     error;
     409             : 
     410             :         /* Read mappings and invalidate buffers. */
     411    23761697 :         error = xfs_bmapi_read(ip, 0, XFS_MAX_FILEOFF, mval, &nmaps, 0);
     412    23655094 :         if (error)
     413             :                 return error;
     414             : 
     415    47443522 :         for (i = 0; i < nmaps; i++) {
     416    94875022 :                 if (!xfs_bmap_is_real_extent(&mval[i]))
     417             :                         break;
     418             : 
     419   118169291 :                 error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
     420    23655093 :                                 XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
     421    23645539 :                                 XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0,
     422             :                                 &bp);
     423    23759277 :                 if (error)
     424           0 :                         return error;
     425             : 
     426    23759277 :                 xfs_trans_binval(tp, bp);
     427             :         }
     428             : 
     429             :         /* Unmap the remote blocks. */
     430    23785961 :         error = xfs_bunmapi(tp, ip, 0, XFS_MAX_FILEOFF, 0, nmaps, &done);
     431    23742083 :         if (error)
     432             :                 return error;
     433    23742083 :         if (!done) {
     434           0 :                 ASSERT(done);
     435           0 :                 xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
     436           0 :                 return -EFSCORRUPTED;
     437             :         }
     438             : 
     439    23742083 :         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
     440    23742083 :         return 0;
     441             : }

Generated by: LCOV version 1.14