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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;

+1 −0
Original line number Diff line number Diff line
@@ -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;

+0 −13
Original line number Diff line number Diff line
@@ -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. */
+154 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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 */
Loading