Commit e6469b22 authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'symlink-cleanups-6.9_2024-02-23' of...

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: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan 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
parents 6723ca99 b8102b61
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "xfs_iomap.h" #include "xfs_iomap.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_bmap_item.h" #include "xfs_bmap_item.h"
#include "xfs_symlink_remote.h"
struct kmem_cache *xfs_bmap_intent_cache; struct kmem_cache *xfs_bmap_intent_cache;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "xfs_types.h" #include "xfs_types.h"
#include "xfs_errortag.h" #include "xfs_errortag.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_symlink_remote.h"
struct kmem_cache *xfs_ifork_cache; struct kmem_cache *xfs_ifork_cache;
......
...@@ -182,19 +182,6 @@ void xfs_log_get_max_trans_res(struct xfs_mount *mp, ...@@ -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_CHG 0x2 /* inode field change timestamp */
#define XFS_ICHGTIME_CREATE 0x4 /* inode create 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. */ /* Computed inode geometry for the filesystem. */
struct xfs_ino_geometry { struct xfs_ino_geometry {
/* Maximum inode count in this filesystem. */ /* Maximum inode count in this filesystem. */
......
...@@ -16,7 +16,10 @@ ...@@ -16,7 +16,10 @@
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_log.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 * Each contiguous block has a header, so it is not just a simple pathlen
...@@ -227,3 +230,153 @@ xfs_symlink_shortform_verify( ...@@ -227,3 +230,153 @@ xfs_symlink_shortform_verify(
return __this_address; return __this_address;
return NULL; 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;
}
// 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 @@ ...@@ -37,6 +37,7 @@
#include "xfs_attr_leaf.h" #include "xfs_attr_leaf.h"
#include "xfs_log_priv.h" #include "xfs_log_priv.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_symlink_remote.h"
#include "scrub/xfs_scrub.h" #include "scrub/xfs_scrub.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_symlink.h" #include "xfs_symlink.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_symlink_remote.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/health.h" #include "scrub/health.h"
...@@ -67,7 +68,7 @@ xchk_symlink( ...@@ -67,7 +68,7 @@ xchk_symlink(
} }
/* Remote symlink; must read the contents. */ /* 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)) if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
return error; return error;
if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len) if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len)
......
...@@ -24,80 +24,7 @@ ...@@ -24,80 +24,7 @@
#include "xfs_ialloc.h" #include "xfs_ialloc.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_symlink_remote.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;
}
int int
xfs_readlink( xfs_readlink(
...@@ -140,7 +67,7 @@ xfs_readlink( ...@@ -140,7 +67,7 @@ xfs_readlink(
memcpy(link, ip->i_df.if_data, pathlen + 1); memcpy(link, ip->i_df.if_data, pathlen + 1);
error = 0; error = 0;
} else { } else {
error = xfs_readlink_bmap_ilocked(ip, link); error = xfs_symlink_remote_read(ip, link);
} }
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
...@@ -166,15 +93,7 @@ xfs_symlink( ...@@ -166,15 +93,7 @@ xfs_symlink(
int error = 0; int error = 0;
int pathlen; int pathlen;
bool unlock_dp_on_error = false; bool unlock_dp_on_error = false;
xfs_fileoff_t first_fsb;
xfs_filblks_t fs_blocks; 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; prid_t prid;
struct xfs_dquot *udqp = NULL; struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *gdqp = NULL;
...@@ -262,62 +181,11 @@ xfs_symlink( ...@@ -262,62 +181,11 @@ xfs_symlink(
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
resblks -= XFS_IALLOC_SPACE_RES(mp); resblks -= XFS_IALLOC_SPACE_RES(mp);
/* error = xfs_symlink_write_target(tp, ip, target_path, pathlen,
* If the symlink will fit into the inode, write it inline. fs_blocks, resblks);
*/ if (error)
if (pathlen <= xfs_inode_data_fork_size(ip)) { goto out_trans_cancel;
xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen); resblks -= fs_blocks;
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);
}
i_size_write(VFS_I(ip), ip->i_disk_size); i_size_write(VFS_I(ip), ip->i_disk_size);
/* /*
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
int xfs_symlink(struct mnt_idmap *idmap, struct xfs_inode *dp, int xfs_symlink(struct mnt_idmap *idmap, struct xfs_inode *dp,
struct xfs_name *link_name, const char *target_path, struct xfs_name *link_name, const char *target_path,
umode_t mode, struct xfs_inode **ipp); 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_readlink(struct xfs_inode *ip, char *link);
int xfs_inactive_symlink(struct xfs_inode *ip); int xfs_inactive_symlink(struct xfs_inode *ip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment