forked from Minki/linux
239880ef64
xfs_trans.h has a dependency on xfs_log.h for a couple of structures. Most code that does transactions doesn't need to know anything about the log, but this dependency means that they have to include xfs_log.h. Decouple the xfs_trans.h and xfs_log.h header files and clean up the includes to be in dependency order. In doing this, remove the direct include of xfs_trans_reserve.h from xfs_trans.h so that we remove the dependency between xfs_trans.h and xfs_mount.h. Hence the xfs_trans.h include can be moved to the indicate the actual dependencies other header files have on it. Note that these are kernel only header files, so this does not translate to any userspace changes at all. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
203 lines
4.9 KiB
C
203 lines
4.9 KiB
C
/*
|
|
* Copyright (c) 2000-2006 Silicon Graphics, Inc.
|
|
* Copyright (c) 2012-2013 Red Hat, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include "xfs.h"
|
|
#include "xfs_fs.h"
|
|
#include "xfs_format.h"
|
|
#include "xfs_log_format.h"
|
|
#include "xfs_shared.h"
|
|
#include "xfs_trans_resv.h"
|
|
#include "xfs_ag.h"
|
|
#include "xfs_sb.h"
|
|
#include "xfs_mount.h"
|
|
#include "xfs_bmap_btree.h"
|
|
#include "xfs_inode.h"
|
|
#include "xfs_error.h"
|
|
#include "xfs_trace.h"
|
|
#include "xfs_symlink.h"
|
|
#include "xfs_cksum.h"
|
|
#include "xfs_trans.h"
|
|
#include "xfs_buf_item.h"
|
|
|
|
|
|
/*
|
|
* Each contiguous block has a header, so it is not just a simple pathlen
|
|
* to FSB conversion.
|
|
*/
|
|
int
|
|
xfs_symlink_blocks(
|
|
struct xfs_mount *mp,
|
|
int pathlen)
|
|
{
|
|
int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
|
|
|
|
return (pathlen + buflen - 1) / buflen;
|
|
}
|
|
|
|
int
|
|
xfs_symlink_hdr_set(
|
|
struct xfs_mount *mp,
|
|
xfs_ino_t ino,
|
|
uint32_t offset,
|
|
uint32_t size,
|
|
struct xfs_buf *bp)
|
|
{
|
|
struct xfs_dsymlink_hdr *dsl = bp->b_addr;
|
|
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
return 0;
|
|
|
|
dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
|
|
dsl->sl_offset = cpu_to_be32(offset);
|
|
dsl->sl_bytes = cpu_to_be32(size);
|
|
uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
|
|
dsl->sl_owner = cpu_to_be64(ino);
|
|
dsl->sl_blkno = cpu_to_be64(bp->b_bn);
|
|
bp->b_ops = &xfs_symlink_buf_ops;
|
|
|
|
return sizeof(struct xfs_dsymlink_hdr);
|
|
}
|
|
|
|
/*
|
|
* Checking of the symlink header is split into two parts. the verifier does
|
|
* CRC, location and bounds checking, the unpacking function checks the path
|
|
* parameters and owner.
|
|
*/
|
|
bool
|
|
xfs_symlink_hdr_ok(
|
|
struct xfs_mount *mp,
|
|
xfs_ino_t ino,
|
|
uint32_t offset,
|
|
uint32_t size,
|
|
struct xfs_buf *bp)
|
|
{
|
|
struct xfs_dsymlink_hdr *dsl = bp->b_addr;
|
|
|
|
if (offset != be32_to_cpu(dsl->sl_offset))
|
|
return false;
|
|
if (size != be32_to_cpu(dsl->sl_bytes))
|
|
return false;
|
|
if (ino != be64_to_cpu(dsl->sl_owner))
|
|
return false;
|
|
|
|
/* ok */
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
xfs_symlink_verify(
|
|
struct xfs_buf *bp)
|
|
{
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
struct xfs_dsymlink_hdr *dsl = bp->b_addr;
|
|
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
return false;
|
|
if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
|
|
return false;
|
|
if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
|
|
return false;
|
|
if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
|
|
return false;
|
|
if (be32_to_cpu(dsl->sl_offset) +
|
|
be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
|
|
return false;
|
|
if (dsl->sl_owner == 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
xfs_symlink_read_verify(
|
|
struct xfs_buf *bp)
|
|
{
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
|
/* no verification of non-crc buffers */
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
return;
|
|
|
|
if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
|
|
offsetof(struct xfs_dsymlink_hdr, sl_crc)) ||
|
|
!xfs_symlink_verify(bp)) {
|
|
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
}
|
|
}
|
|
|
|
static void
|
|
xfs_symlink_write_verify(
|
|
struct xfs_buf *bp)
|
|
{
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
struct xfs_buf_log_item *bip = bp->b_fspriv;
|
|
|
|
/* no verification of non-crc buffers */
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
return;
|
|
|
|
if (!xfs_symlink_verify(bp)) {
|
|
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
return;
|
|
}
|
|
|
|
if (bip) {
|
|
struct xfs_dsymlink_hdr *dsl = bp->b_addr;
|
|
dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
|
|
}
|
|
xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
|
|
offsetof(struct xfs_dsymlink_hdr, sl_crc));
|
|
}
|
|
|
|
const struct xfs_buf_ops xfs_symlink_buf_ops = {
|
|
.verify_read = xfs_symlink_read_verify,
|
|
.verify_write = xfs_symlink_write_verify,
|
|
};
|
|
|
|
void
|
|
xfs_symlink_local_to_remote(
|
|
struct xfs_trans *tp,
|
|
struct xfs_buf *bp,
|
|
struct xfs_inode *ip,
|
|
struct xfs_ifork *ifp)
|
|
{
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
char *buf;
|
|
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb)) {
|
|
bp->b_ops = NULL;
|
|
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* As this symlink fits in an inode literal area, it must also fit in
|
|
* the smallest buffer the filesystem supports.
|
|
*/
|
|
ASSERT(BBTOB(bp->b_length) >=
|
|
ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
|
|
|
|
bp->b_ops = &xfs_symlink_buf_ops;
|
|
|
|
buf = bp->b_addr;
|
|
buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
|
|
memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
|
|
}
|