linux/fs/xfs/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_ag.h"
  26#include "xfs_sb.h"
  27#include "xfs_mount.h"
  28#include "xfs_bmap_btree.h"
  29#include "xfs_inode.h"
  30#include "xfs_error.h"
  31#include "xfs_trace.h"
  32#include "xfs_symlink.h"
  33#include "xfs_cksum.h"
  34#include "xfs_trans.h"
  35#include "xfs_buf_item.h"
  36
  37
  38/*
  39 * Each contiguous block has a header, so it is not just a simple pathlen
  40 * to FSB conversion.
  41 */
  42int
  43xfs_symlink_blocks(
  44        struct xfs_mount *mp,
  45        int             pathlen)
  46{
  47        int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
  48
  49        return (pathlen + buflen - 1) / buflen;
  50}
  51
  52int
  53xfs_symlink_hdr_set(
  54        struct xfs_mount        *mp,
  55        xfs_ino_t               ino,
  56        uint32_t                offset,
  57        uint32_t                size,
  58        struct xfs_buf          *bp)
  59{
  60        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  61
  62        if (!xfs_sb_version_hascrc(&mp->m_sb))
  63                return 0;
  64
  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_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        struct xfs_mount        *mp,
  84        xfs_ino_t               ino,
  85        uint32_t                offset,
  86        uint32_t                size,
  87        struct xfs_buf          *bp)
  88{
  89        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  90
  91        if (offset != be32_to_cpu(dsl->sl_offset))
  92                return false;
  93        if (size != be32_to_cpu(dsl->sl_bytes))
  94                return false;
  95        if (ino != be64_to_cpu(dsl->sl_owner))
  96                return false;
  97
  98        /* ok */
  99        return true;
 100}
 101
 102static bool
 103xfs_symlink_verify(
 104        struct xfs_buf          *bp)
 105{
 106        struct xfs_mount        *mp = bp->b_target->bt_mount;
 107        struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 108
 109        if (!xfs_sb_version_hascrc(&mp->m_sb))
 110                return false;
 111        if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 112                return false;
 113        if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
 114                return false;
 115        if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 116                return false;
 117        if (be32_to_cpu(dsl->sl_offset) +
 118                                be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
 119                return false;
 120        if (dsl->sl_owner == 0)
 121                return false;
 122
 123        return true;
 124}
 125
 126static void
 127xfs_symlink_read_verify(
 128        struct xfs_buf  *bp)
 129{
 130        struct xfs_mount *mp = bp->b_target->bt_mount;
 131
 132        /* no verification of non-crc buffers */
 133        if (!xfs_sb_version_hascrc(&mp->m_sb))
 134                return;
 135
 136        if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
 137                                  offsetof(struct xfs_dsymlink_hdr, sl_crc)) ||
 138            !xfs_symlink_verify(bp)) {
 139                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
 140                xfs_buf_ioerror(bp, EFSCORRUPTED);
 141        }
 142}
 143
 144static void
 145xfs_symlink_write_verify(
 146        struct xfs_buf  *bp)
 147{
 148        struct xfs_mount *mp = bp->b_target->bt_mount;
 149        struct xfs_buf_log_item *bip = bp->b_fspriv;
 150
 151        /* no verification of non-crc buffers */
 152        if (!xfs_sb_version_hascrc(&mp->m_sb))
 153                return;
 154
 155        if (!xfs_symlink_verify(bp)) {
 156                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
 157                xfs_buf_ioerror(bp, EFSCORRUPTED);
 158                return;
 159        }
 160
 161        if (bip) {
 162                struct xfs_dsymlink_hdr *dsl = bp->b_addr;
 163                dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
 164        }
 165        xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
 166                         offsetof(struct xfs_dsymlink_hdr, sl_crc));
 167}
 168
 169const struct xfs_buf_ops xfs_symlink_buf_ops = {
 170        .verify_read = xfs_symlink_read_verify,
 171        .verify_write = xfs_symlink_write_verify,
 172};
 173
 174void
 175xfs_symlink_local_to_remote(
 176        struct xfs_trans        *tp,
 177        struct xfs_buf          *bp,
 178        struct xfs_inode        *ip,
 179        struct xfs_ifork        *ifp)
 180{
 181        struct xfs_mount        *mp = ip->i_mount;
 182        char                    *buf;
 183
 184        if (!xfs_sb_version_hascrc(&mp->m_sb)) {
 185                bp->b_ops = NULL;
 186                memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
 187                return;
 188        }
 189
 190        /*
 191         * As this symlink fits in an inode literal area, it must also fit in
 192         * the smallest buffer the filesystem supports.
 193         */
 194        ASSERT(BBTOB(bp->b_length) >=
 195                        ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
 196
 197        bp->b_ops = &xfs_symlink_buf_ops;
 198
 199        buf = bp->b_addr;
 200        buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
 201        memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
 202}
 203