linux/fs/xfs/libxfs/xfs_symlink_remote.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
   3 * Copyright (c) 2012-2013 Red Hat, Inc.
   4 * All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it would be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write the Free Software Foundation,
  17 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18 */
  19#include "xfs.h"
  20#include "xfs_fs.h"
  21#include "xfs_format.h"
  22#include "xfs_log_format.h"
  23#include "xfs_shared.h"
  24#include "xfs_trans_resv.h"
  25#include "xfs_mount.h"
  26#include "xfs_bmap_btree.h"
  27#include "xfs_inode.h"
  28#include "xfs_error.h"
  29#include "xfs_trace.h"
  30#include "xfs_symlink.h"
  31#include "xfs_cksum.h"
  32#include "xfs_trans.h"
  33#include "xfs_buf_item.h"
  34#include "xfs_log.h"
  35
  36
  37/*
  38 * Each contiguous block has a header, so it is not just a simple pathlen
  39 * to FSB conversion.
  40 */
  41int
  42xfs_symlink_blocks(
  43        struct xfs_mount *mp,
  44        int             pathlen)
  45{
  46        int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
  47
  48        return (pathlen + buflen - 1) / buflen;
  49}
  50
  51int
  52xfs_symlink_hdr_set(
  53        struct xfs_mount        *mp,
  54        xfs_ino_t               ino,
  55        uint32_t                offset,
  56        uint32_t                size,
  57        struct xfs_buf          *bp)
  58{
  59        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  60
  61        if (!xfs_sb_version_hascrc(&mp->m_sb))
  62                return 0;
  63
  64        memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
  65        dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
  66        dsl->sl_offset = cpu_to_be32(offset);
  67        dsl->sl_bytes = cpu_to_be32(size);
  68        uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
  69        dsl->sl_owner = cpu_to_be64(ino);
  70        dsl->sl_blkno = cpu_to_be64(bp->b_bn);
  71        bp->b_ops = &xfs_symlink_buf_ops;
  72
  73        return sizeof(struct xfs_dsymlink_hdr);
  74}
  75
  76/*
  77 * Checking of the symlink header is split into two parts. the verifier does
  78 * CRC, location and bounds checking, the unpacking function checks the path
  79 * parameters and owner.
  80 */
  81bool
  82xfs_symlink_hdr_ok(
  83        xfs_ino_t               ino,
  84        uint32_t                offset,
  85        uint32_t                size,
  86        struct xfs_buf          *bp)
  87{
  88        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  89
  90        if (offset != be32_to_cpu(dsl->sl_offset))
  91                return false;
  92        if (size != be32_to_cpu(dsl->sl_bytes))
  93                return false;
  94        if (ino != be64_to_cpu(dsl->sl_owner))
  95                return false;
  96
  97        /* ok */
  98        return true;
  99}
 100
 101static bool
 102xfs_symlink_verify(
 103        struct xfs_buf          *bp)
 104{
 105        struct xfs_mount        *mp = bp->b_target->bt_mount;
 106        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 107
 108        if (!xfs_sb_version_hascrc(&mp->m_sb))
 109                return false;
 110        if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 111                return false;
 112        if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 113                return false;
 114        if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 115                return false;
 116        if (be32_to_cpu(dsl->sl_offset) +
 117                                be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
 118                return false;
 119        if (dsl->sl_owner == 0)
 120                return false;
 121        if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
 122                return false;
 123
 124        return true;
 125}
 126
 127static void
 128xfs_symlink_read_verify(
 129        struct xfs_buf  *bp)
 130{
 131        struct xfs_mount *mp = bp->b_target->bt_mount;
 132
 133        /* no verification of non-crc buffers */
 134        if (!xfs_sb_version_hascrc(&mp->m_sb))
 135                return;
 136
 137        if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
 138                xfs_buf_ioerror(bp, -EFSBADCRC);
 139        else if (!xfs_symlink_verify(bp))
 140                xfs_buf_ioerror(bp, -EFSCORRUPTED);
 141
 142        if (bp->b_error)
 143                xfs_verifier_error(bp);
 144}
 145
 146static void
 147xfs_symlink_write_verify(
 148        struct xfs_buf  *bp)
 149{
 150        struct xfs_mount *mp = bp->b_target->bt_mount;
 151        struct xfs_buf_log_item *bip = bp->b_fspriv;
 152
 153        /* no verification of non-crc buffers */
 154        if (!xfs_sb_version_hascrc(&mp->m_sb))
 155                return;
 156
 157        if (!xfs_symlink_verify(bp)) {
 158                xfs_buf_ioerror(bp, -EFSCORRUPTED);
 159                xfs_verifier_error(bp);
 160                return;
 161        }
 162
 163        if (bip) {
 164                struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 165                dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
 166        }
 167        xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
 168}
 169
 170const struct xfs_buf_ops xfs_symlink_buf_ops = {
 171        .name = "xfs_symlink",
 172        .verify_read = xfs_symlink_read_verify,
 173        .verify_write = xfs_symlink_write_verify,
 174};
 175
 176void
 177xfs_symlink_local_to_remote(
 178        struct xfs_trans        *tp,
 179        struct xfs_buf          *bp,
 180        struct xfs_inode        *ip,
 181        struct xfs_ifork        *ifp)
 182{
 183        struct xfs_mount        *mp = ip->i_mount;
 184        char                    *buf;
 185
 186        xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
 187
 188        if (!xfs_sb_version_hascrc(&mp->m_sb)) {
 189                bp->b_ops = NULL;
 190                memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
 191                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
 192                return;
 193        }
 194
 195        /*
 196         * As this symlink fits in an inode literal area, it must also fit in
 197         * the smallest buffer the filesystem supports.
 198         */
 199        ASSERT(BBTOB(bp->b_length) >=
 200                        ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
 201
 202        bp->b_ops = &xfs_symlink_buf_ops;
 203
 204        buf = bp->b_addr;
 205        buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
 206        memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
 207        xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
 208                                        ifp->if_bytes - 1);
 209}
 210