Commit 0313dd8f authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'repair-symlink-6.10_2024-04-15' of...

Merge tag 'repair-symlink-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeA

xfs: online repair of symbolic links

The patches in this set adds the ability to repair the target buffer of
a symbolic link, using the same salvage, rebuild, and swap strategy used
everywhere else.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'repair-symlink-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: online repair of symbolic links
  xfs: pass the owner to xfs_symlink_write_target
  xfs: expose xfs_bmap_local_to_extents for online repair
parents 067d3f71 2651923d
......@@ -213,6 +213,7 @@ xfs-y += $(addprefix scrub/, \
refcount_repair.o \
repair.o \
rmap_repair.o \
symlink_repair.o \
tempfile.o \
xfblob.o \
)
......
......@@ -779,7 +779,7 @@ xfs_bmap_local_to_extents_empty(
}
STATIC int /* error */
int /* error */
xfs_bmap_local_to_extents(
xfs_trans_t *tp, /* transaction pointer */
xfs_inode_t *ip, /* incore inode pointer */
......@@ -789,7 +789,8 @@ xfs_bmap_local_to_extents(
void (*init_fn)(struct xfs_trans *tp,
struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp))
struct xfs_ifork *ifp, void *priv),
void *priv)
{
int error = 0;
int flags; /* logging flags returned */
......@@ -850,7 +851,7 @@ xfs_bmap_local_to_extents(
* log here. Note that init_fn must also set the buffer log item type
* correctly.
*/
init_fn(tp, bp, ip, ifp);
init_fn(tp, bp, ip, ifp, priv);
/* account for the change in fork size */
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
......@@ -982,8 +983,8 @@ xfs_bmap_add_attrfork_local(
if (S_ISLNK(VFS_I(ip)->i_mode))
return xfs_bmap_local_to_extents(tp, ip, 1, flags,
XFS_DATA_FORK,
xfs_symlink_local_to_remote);
XFS_DATA_FORK, xfs_symlink_local_to_remote,
NULL);
/* should only be called for types that support local format data */
ASSERT(0);
......
......@@ -179,6 +179,12 @@ unsigned int xfs_bmap_compute_attr_offset(struct xfs_mount *mp);
int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
void xfs_bmap_local_to_extents_empty(struct xfs_trans *tp,
struct xfs_inode *ip, int whichfork);
int xfs_bmap_local_to_extents(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_extlen_t total, int *logflagsp, int whichfork,
void (*init_fn)(struct xfs_trans *tp, struct xfs_buf *bp,
struct xfs_inode *ip, struct xfs_ifork *ifp,
void *priv),
void *priv);
void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork);
int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
......
......@@ -169,7 +169,8 @@ xfs_symlink_local_to_remote(
struct xfs_trans *tp,
struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp)
struct xfs_ifork *ifp,
void *priv)
{
struct xfs_mount *mp = ip->i_mount;
char *buf;
......@@ -310,6 +311,7 @@ int
xfs_symlink_write_target(
struct xfs_trans *tp,
struct xfs_inode *ip,
xfs_ino_t owner,
const char *target_path,
int pathlen,
xfs_fsblock_t fs_blocks,
......@@ -364,8 +366,7 @@ xfs_symlink_write_target(
byte_cnt = min(byte_cnt, pathlen);
buf = bp->b_addr;
buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, byte_cnt,
bp);
buf += xfs_symlink_hdr_set(mp, owner, offset, byte_cnt, bp);
memcpy(buf, cur_chunk, byte_cnt);
......
......@@ -16,12 +16,13 @@ int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
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);
struct xfs_inode *ip, struct xfs_ifork *ifp,
void *priv);
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);
xfs_ino_t owner, const char *target_path, int pathlen,
xfs_fsblock_t fs_blocks, uint resblks);
int xfs_symlink_remote_truncate(struct xfs_trans *tp, struct xfs_inode *ip);
#endif /* __XFS_SYMLINK_REMOTE_H */
......@@ -94,6 +94,7 @@ int xrep_setup_xattr(struct xfs_scrub *sc);
int xrep_setup_directory(struct xfs_scrub *sc);
int xrep_setup_parent(struct xfs_scrub *sc);
int xrep_setup_nlinks(struct xfs_scrub *sc);
int xrep_setup_symlink(struct xfs_scrub *sc, unsigned int *resblks);
/* Repair setup functions */
int xrep_setup_ag_allocbt(struct xfs_scrub *sc);
......@@ -130,6 +131,7 @@ int xrep_fscounters(struct xfs_scrub *sc);
int xrep_xattr(struct xfs_scrub *sc);
int xrep_directory(struct xfs_scrub *sc);
int xrep_parent(struct xfs_scrub *sc);
int xrep_symlink(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
int xrep_rtbitmap(struct xfs_scrub *sc);
......@@ -206,6 +208,11 @@ xrep_setup_nothing(
#define xrep_setup_inode(sc, imap) ((void)0)
static inline int xrep_setup_symlink(struct xfs_scrub *sc, unsigned int *x)
{
return 0;
}
#define xrep_revalidate_allocbt (NULL)
#define xrep_revalidate_iallocbt (NULL)
......@@ -231,6 +238,7 @@ xrep_setup_nothing(
#define xrep_xattr xrep_notsupported
#define xrep_directory xrep_notsupported
#define xrep_parent xrep_notsupported
#define xrep_symlink xrep_notsupported
#endif /* CONFIG_XFS_ONLINE_REPAIR */
......
......@@ -339,7 +339,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
.type = ST_INODE,
.setup = xchk_setup_symlink,
.scrub = xchk_symlink,
.repair = xrep_notsupported,
.repair = xrep_symlink,
},
[XFS_SCRUB_TYPE_PARENT] = { /* parent pointers */
.type = ST_INODE,
......
......@@ -10,6 +10,7 @@
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_inode.h"
#include "xfs_symlink.h"
#include "xfs_health.h"
......@@ -17,18 +18,28 @@
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/health.h"
#include "scrub/repair.h"
/* Set us up to scrub a symbolic link. */
int
xchk_setup_symlink(
struct xfs_scrub *sc)
{
unsigned int resblks = 0;
int error;
/* Allocate the buffer without the inode lock held. */
sc->buf = kvzalloc(XFS_SYMLINK_MAXLEN + 1, XCHK_GFP_FLAGS);
if (!sc->buf)
return -ENOMEM;
return xchk_setup_inode_contents(sc, 0);
if (xchk_could_repair(sc)) {
error = xrep_setup_symlink(sc, &resblks);
if (error)
return error;
}
return xchk_setup_inode_contents(sc, resblks);
}
/* Symbolic links. */
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#include "xfs_exchrange.h"
#include "xfs_exchmaps.h"
#include "xfs_defer.h"
#include "xfs_symlink_remote.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
......@@ -109,6 +110,18 @@ xrep_tempfile_create(
error = xfs_dir_init(tp, sc->tempip, dp);
if (error)
goto out_trans_cancel;
} else if (S_ISLNK(VFS_I(sc->tempip)->i_mode)) {
/*
* Initialize the temporary symlink with a meaningless target
* that won't trip the verifiers. Repair must rewrite the
* target with meaningful content before swapping with the file
* being repaired. A single-byte target will not write a
* remote target block, so the owner is irrelevant.
*/
error = xfs_symlink_write_target(tp, sc->tempip,
sc->tempip->i_ino, ".", 1, 0, 0);
if (error)
goto out_trans_cancel;
}
/*
......
......@@ -2711,6 +2711,52 @@ DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_alias);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_dentry);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_invalidate_child);
TRACE_EVENT(xrep_symlink_salvage_target,
TP_PROTO(struct xfs_inode *ip, char *target, unsigned int targetlen),
TP_ARGS(ip, target, targetlen),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(unsigned int, targetlen)
__dynamic_array(char, target, targetlen + 1)
),
TP_fast_assign(
__entry->dev = ip->i_mount->m_super->s_dev;
__entry->ino = ip->i_ino;
__entry->targetlen = targetlen;
memcpy(__get_str(target), target, targetlen);
__get_str(target)[targetlen] = 0;
),
TP_printk("dev %d:%d ip 0x%llx target '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->targetlen,
__get_str(target))
);
DECLARE_EVENT_CLASS(xrep_symlink_class,
TP_PROTO(struct xfs_inode *ip),
TP_ARGS(ip),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
),
TP_fast_assign(
__entry->dev = ip->i_mount->m_super->s_dev;
__entry->ino = ip->i_ino;
),
TP_printk("dev %d:%d ip 0x%llx",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino)
);
#define DEFINE_XREP_SYMLINK_EVENT(name) \
DEFINE_EVENT(xrep_symlink_class, name, \
TP_PROTO(struct xfs_inode *ip), \
TP_ARGS(ip))
DEFINE_XREP_SYMLINK_EVENT(xrep_symlink_rebuild);
DEFINE_XREP_SYMLINK_EVENT(xrep_symlink_reset_fork);
#endif /* IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) */
#endif /* _TRACE_XFS_SCRUB_TRACE_H */
......
......@@ -181,8 +181,8 @@ xfs_symlink(
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
resblks -= XFS_IALLOC_SPACE_RES(mp);
error = xfs_symlink_write_target(tp, ip, target_path, pathlen,
fs_blocks, resblks);
error = xfs_symlink_write_target(tp, ip, ip->i_ino, target_path,
pathlen, fs_blocks, resblks);
if (error)
goto out_trans_cancel;
resblks -= fs_blocks;
......
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