xfs: clean up symbolic link code [v29.3 18/18]
This series cleans up a few bits of the symbolic link code as needed for future projects. Online repair requires the ability to commit fixed fork-based filesystem metadata such as directories, xattrs, and symbolic links atomically, so we need to rearrange the symlink code before we land the atomic extent swapping. Accomplish this by moving the remote symlink target block code and declarations to xfs_symlink_remote.[ch]. This has been running on the djcloud for months with no problems. Enjoy! Signed-off-by: Darrick J. Wong <djwong@kernel.org> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQ2qTKExjcn+O1o2YRKO3ySh0YRpgUCZdlBYwAKCRBKO3ySh0YR ppvvAP0S+kTZ96zROb68pfy4xo5X0mcFvtuHQo4mc4Mu6UZf0AD+Lr/Xdnj/J9k1 8FEV933MFzWHINeeGUpaN8zgZBCvKA0= =Lgry -----END PGP SIGNATURE----- Merge tag 'symlink-cleanups-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.9-mergeC xfs: clean up symbolic link code This series cleans up a few bits of the symbolic link code as needed for future projects. Online repair requires the ability to commit fixed fork-based filesystem metadata such as directories, xattrs, and symbolic links atomically, so we need to rearrange the symlink code before we land the atomic extent swapping. Accomplish this by moving the remote symlink target block code and declarations to xfs_symlink_remote.[ch]. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org> * tag 'symlink-cleanups-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: move symlink target write function to libxfs xfs: move remote symlink target read function to libxfs xfs: move xfs_symlink_remote.c declarations to xfs_symlink_remote.h
This commit is contained in:
commit
e6469b22bd
@ -38,6 +38,7 @@
|
||||
#include "xfs_iomap.h"
|
||||
#include "xfs_health.h"
|
||||
#include "xfs_bmap_item.h"
|
||||
#include "xfs_symlink_remote.h"
|
||||
|
||||
struct kmem_cache *xfs_bmap_intent_cache;
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "xfs_types.h"
|
||||
#include "xfs_errortag.h"
|
||||
#include "xfs_health.h"
|
||||
#include "xfs_symlink_remote.h"
|
||||
|
||||
struct kmem_cache *xfs_ifork_cache;
|
||||
|
||||
|
||||
@ -182,19 +182,6 @@ void xfs_log_get_max_trans_res(struct xfs_mount *mp,
|
||||
#define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */
|
||||
#define XFS_ICHGTIME_CREATE 0x4 /* inode create timestamp */
|
||||
|
||||
|
||||
/*
|
||||
* Symlink decoding/encoding functions
|
||||
*/
|
||||
int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
|
||||
int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
|
||||
uint32_t size, struct xfs_buf *bp);
|
||||
bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset,
|
||||
uint32_t size, struct xfs_buf *bp);
|
||||
void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
|
||||
struct xfs_inode *ip, struct xfs_ifork *ifp);
|
||||
xfs_failaddr_t xfs_symlink_shortform_verify(void *sfp, int64_t size);
|
||||
|
||||
/* Computed inode geometry for the filesystem. */
|
||||
struct xfs_ino_geometry {
|
||||
/* Maximum inode count in this filesystem. */
|
||||
|
||||
@ -16,7 +16,10 @@
|
||||
#include "xfs_trans.h"
|
||||
#include "xfs_buf_item.h"
|
||||
#include "xfs_log.h"
|
||||
|
||||
#include "xfs_symlink_remote.h"
|
||||
#include "xfs_bit.h"
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_health.h"
|
||||
|
||||
/*
|
||||
* Each contiguous block has a header, so it is not just a simple pathlen
|
||||
@ -227,3 +230,153 @@ xfs_symlink_shortform_verify(
|
||||
return __this_address;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read a remote symlink target into the buffer. */
|
||||
int
|
||||
xfs_symlink_remote_read(
|
||||
struct xfs_inode *ip,
|
||||
char *link)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
|
||||
struct xfs_buf *bp;
|
||||
xfs_daddr_t d;
|
||||
char *cur_chunk;
|
||||
int pathlen = ip->i_disk_size;
|
||||
int nmaps = XFS_SYMLINK_MAPS;
|
||||
int byte_cnt;
|
||||
int n;
|
||||
int error = 0;
|
||||
int fsblocks = 0;
|
||||
int offset;
|
||||
|
||||
xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
|
||||
|
||||
fsblocks = xfs_symlink_blocks(mp, pathlen);
|
||||
error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
offset = 0;
|
||||
for (n = 0; n < nmaps; n++) {
|
||||
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
|
||||
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
|
||||
|
||||
error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
|
||||
&bp, &xfs_symlink_buf_ops);
|
||||
if (xfs_metadata_is_sick(error))
|
||||
xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
|
||||
if (error)
|
||||
return error;
|
||||
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
|
||||
if (pathlen < byte_cnt)
|
||||
byte_cnt = pathlen;
|
||||
|
||||
cur_chunk = bp->b_addr;
|
||||
if (xfs_has_crc(mp)) {
|
||||
if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
|
||||
byte_cnt, bp)) {
|
||||
xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
|
||||
error = -EFSCORRUPTED;
|
||||
xfs_alert(mp,
|
||||
"symlink header does not match required off/len/owner (0x%x/0x%x,0x%llx)",
|
||||
offset, byte_cnt, ip->i_ino);
|
||||
xfs_buf_relse(bp);
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
cur_chunk += sizeof(struct xfs_dsymlink_hdr);
|
||||
}
|
||||
|
||||
memcpy(link + offset, cur_chunk, byte_cnt);
|
||||
|
||||
pathlen -= byte_cnt;
|
||||
offset += byte_cnt;
|
||||
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
ASSERT(pathlen == 0);
|
||||
|
||||
link[ip->i_disk_size] = '\0';
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Write the symlink target into the inode. */
|
||||
int
|
||||
xfs_symlink_write_target(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_inode *ip,
|
||||
const char *target_path,
|
||||
int pathlen,
|
||||
xfs_fsblock_t fs_blocks,
|
||||
uint resblks)
|
||||
{
|
||||
struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
|
||||
struct xfs_mount *mp = tp->t_mountp;
|
||||
const char *cur_chunk;
|
||||
struct xfs_buf *bp;
|
||||
xfs_daddr_t d;
|
||||
int byte_cnt;
|
||||
int nmaps;
|
||||
int offset = 0;
|
||||
int n;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* If the symlink will fit into the inode, write it inline.
|
||||
*/
|
||||
if (pathlen <= xfs_inode_data_fork_size(ip)) {
|
||||
xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
|
||||
|
||||
ip->i_disk_size = pathlen;
|
||||
ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nmaps = XFS_SYMLINK_MAPS;
|
||||
error = xfs_bmapi_write(tp, ip, 0, fs_blocks, XFS_BMAPI_METADATA,
|
||||
resblks, mval, &nmaps);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ip->i_disk_size = pathlen;
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
||||
|
||||
cur_chunk = target_path;
|
||||
offset = 0;
|
||||
for (n = 0; n < nmaps; n++) {
|
||||
char *buf;
|
||||
|
||||
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
|
||||
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
|
||||
error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
|
||||
BTOBB(byte_cnt), 0, &bp);
|
||||
if (error)
|
||||
return error;
|
||||
bp->b_ops = &xfs_symlink_buf_ops;
|
||||
|
||||
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
|
||||
byte_cnt = min(byte_cnt, pathlen);
|
||||
|
||||
buf = bp->b_addr;
|
||||
buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, byte_cnt,
|
||||
bp);
|
||||
|
||||
memcpy(buf, cur_chunk, byte_cnt);
|
||||
|
||||
cur_chunk += byte_cnt;
|
||||
pathlen -= byte_cnt;
|
||||
offset += byte_cnt;
|
||||
|
||||
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
|
||||
xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
|
||||
(char *)bp->b_addr);
|
||||
}
|
||||
ASSERT(pathlen == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
26
fs/xfs/libxfs/xfs_symlink_remote.h
Normal file
26
fs/xfs/libxfs/xfs_symlink_remote.h
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||
* Copyright (c) 2013 Red Hat, Inc.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
#ifndef __XFS_SYMLINK_REMOTE_H
|
||||
#define __XFS_SYMLINK_REMOTE_H
|
||||
|
||||
/*
|
||||
* Symlink decoding/encoding functions
|
||||
*/
|
||||
int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
|
||||
int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
|
||||
uint32_t size, struct xfs_buf *bp);
|
||||
bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset,
|
||||
uint32_t size, struct xfs_buf *bp);
|
||||
void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
|
||||
struct xfs_inode *ip, struct xfs_ifork *ifp);
|
||||
xfs_failaddr_t xfs_symlink_shortform_verify(void *sfp, int64_t size);
|
||||
int xfs_symlink_remote_read(struct xfs_inode *ip, char *link);
|
||||
int xfs_symlink_write_target(struct xfs_trans *tp, struct xfs_inode *ip,
|
||||
const char *target_path, int pathlen, xfs_fsblock_t fs_blocks,
|
||||
uint resblks);
|
||||
|
||||
#endif /* __XFS_SYMLINK_REMOTE_H */
|
||||
@ -37,6 +37,7 @@
|
||||
#include "xfs_attr_leaf.h"
|
||||
#include "xfs_log_priv.h"
|
||||
#include "xfs_health.h"
|
||||
#include "xfs_symlink_remote.h"
|
||||
#include "scrub/xfs_scrub.h"
|
||||
#include "scrub/scrub.h"
|
||||
#include "scrub/common.h"
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include "xfs_inode.h"
|
||||
#include "xfs_symlink.h"
|
||||
#include "xfs_health.h"
|
||||
#include "xfs_symlink_remote.h"
|
||||
#include "scrub/scrub.h"
|
||||
#include "scrub/common.h"
|
||||
#include "scrub/health.h"
|
||||
@ -67,7 +68,7 @@ xchk_symlink(
|
||||
}
|
||||
|
||||
/* Remote symlink; must read the contents. */
|
||||
error = xfs_readlink_bmap_ilocked(sc->ip, sc->buf);
|
||||
error = xfs_symlink_remote_read(sc->ip, sc->buf);
|
||||
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
|
||||
return error;
|
||||
if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len)
|
||||
|
||||
@ -24,80 +24,7 @@
|
||||
#include "xfs_ialloc.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_health.h"
|
||||
|
||||
/* ----- Kernel only functions below ----- */
|
||||
int
|
||||
xfs_readlink_bmap_ilocked(
|
||||
struct xfs_inode *ip,
|
||||
char *link)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
|
||||
struct xfs_buf *bp;
|
||||
xfs_daddr_t d;
|
||||
char *cur_chunk;
|
||||
int pathlen = ip->i_disk_size;
|
||||
int nmaps = XFS_SYMLINK_MAPS;
|
||||
int byte_cnt;
|
||||
int n;
|
||||
int error = 0;
|
||||
int fsblocks = 0;
|
||||
int offset;
|
||||
|
||||
xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
|
||||
|
||||
fsblocks = xfs_symlink_blocks(mp, pathlen);
|
||||
error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
offset = 0;
|
||||
for (n = 0; n < nmaps; n++) {
|
||||
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
|
||||
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
|
||||
|
||||
error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
|
||||
&bp, &xfs_symlink_buf_ops);
|
||||
if (xfs_metadata_is_sick(error))
|
||||
xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
|
||||
if (error)
|
||||
return error;
|
||||
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
|
||||
if (pathlen < byte_cnt)
|
||||
byte_cnt = pathlen;
|
||||
|
||||
cur_chunk = bp->b_addr;
|
||||
if (xfs_has_crc(mp)) {
|
||||
if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
|
||||
byte_cnt, bp)) {
|
||||
xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
|
||||
error = -EFSCORRUPTED;
|
||||
xfs_alert(mp,
|
||||
"symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)",
|
||||
offset, byte_cnt, ip->i_ino);
|
||||
xfs_buf_relse(bp);
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
cur_chunk += sizeof(struct xfs_dsymlink_hdr);
|
||||
}
|
||||
|
||||
memcpy(link + offset, cur_chunk, byte_cnt);
|
||||
|
||||
pathlen -= byte_cnt;
|
||||
offset += byte_cnt;
|
||||
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
ASSERT(pathlen == 0);
|
||||
|
||||
link[ip->i_disk_size] = '\0';
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
#include "xfs_symlink_remote.h"
|
||||
|
||||
int
|
||||
xfs_readlink(
|
||||
@ -140,7 +67,7 @@ xfs_readlink(
|
||||
memcpy(link, ip->i_df.if_data, pathlen + 1);
|
||||
error = 0;
|
||||
} else {
|
||||
error = xfs_readlink_bmap_ilocked(ip, link);
|
||||
error = xfs_symlink_remote_read(ip, link);
|
||||
}
|
||||
|
||||
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
||||
@ -166,15 +93,7 @@ xfs_symlink(
|
||||
int error = 0;
|
||||
int pathlen;
|
||||
bool unlock_dp_on_error = false;
|
||||
xfs_fileoff_t first_fsb;
|
||||
xfs_filblks_t fs_blocks;
|
||||
int nmaps;
|
||||
struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
|
||||
xfs_daddr_t d;
|
||||
const char *cur_chunk;
|
||||
int byte_cnt;
|
||||
int n;
|
||||
struct xfs_buf *bp;
|
||||
prid_t prid;
|
||||
struct xfs_dquot *udqp = NULL;
|
||||
struct xfs_dquot *gdqp = NULL;
|
||||
@ -262,62 +181,11 @@ xfs_symlink(
|
||||
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
|
||||
|
||||
resblks -= XFS_IALLOC_SPACE_RES(mp);
|
||||
/*
|
||||
* If the symlink will fit into the inode, write it inline.
|
||||
*/
|
||||
if (pathlen <= xfs_inode_data_fork_size(ip)) {
|
||||
xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
|
||||
|
||||
ip->i_disk_size = pathlen;
|
||||
ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
|
||||
} else {
|
||||
int offset;
|
||||
|
||||
first_fsb = 0;
|
||||
nmaps = XFS_SYMLINK_MAPS;
|
||||
|
||||
error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
|
||||
XFS_BMAPI_METADATA, resblks, mval, &nmaps);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
resblks -= fs_blocks;
|
||||
ip->i_disk_size = pathlen;
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
||||
|
||||
cur_chunk = target_path;
|
||||
offset = 0;
|
||||
for (n = 0; n < nmaps; n++) {
|
||||
char *buf;
|
||||
|
||||
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
|
||||
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
|
||||
error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
|
||||
BTOBB(byte_cnt), 0, &bp);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
bp->b_ops = &xfs_symlink_buf_ops;
|
||||
|
||||
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
|
||||
byte_cnt = min(byte_cnt, pathlen);
|
||||
|
||||
buf = bp->b_addr;
|
||||
buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
|
||||
byte_cnt, bp);
|
||||
|
||||
memcpy(buf, cur_chunk, byte_cnt);
|
||||
|
||||
cur_chunk += byte_cnt;
|
||||
pathlen -= byte_cnt;
|
||||
offset += byte_cnt;
|
||||
|
||||
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
|
||||
xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
|
||||
(char *)bp->b_addr);
|
||||
}
|
||||
ASSERT(pathlen == 0);
|
||||
}
|
||||
error = xfs_symlink_write_target(tp, ip, target_path, pathlen,
|
||||
fs_blocks, resblks);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
resblks -= fs_blocks;
|
||||
i_size_write(VFS_I(ip), ip->i_disk_size);
|
||||
|
||||
/*
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
int xfs_symlink(struct mnt_idmap *idmap, struct xfs_inode *dp,
|
||||
struct xfs_name *link_name, const char *target_path,
|
||||
umode_t mode, struct xfs_inode **ipp);
|
||||
int xfs_readlink_bmap_ilocked(struct xfs_inode *ip, char *link);
|
||||
int xfs_readlink(struct xfs_inode *ip, char *link);
|
||||
int xfs_inactive_symlink(struct xfs_inode *ip);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user