Commit 62bbf50b authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: move dirent update hooks to xfs_dir2.c



Move the directory entry update hook code to xfs_dir2 so that it is
mostly consolidated with the higher level directory functions.  Retain
the exports so that online fsck can still send notifications through the
hooks.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 28d0d813
Loading
Loading
Loading
Loading
+104 −0
Original line number Diff line number Diff line
@@ -762,6 +762,81 @@ xfs_dir2_compname(
	return xfs_da_compname(args, name, len);
}

#ifdef CONFIG_XFS_LIVE_HOOKS
/*
 * Use a static key here to reduce the overhead of directory live update hooks.
 * If the compiler supports jump labels, the static branch will be replaced by
 * a nop sled when there are no hook users.  Online fsck is currently the only
 * caller, so this is a reasonable tradeoff.
 *
 * Note: Patching the kernel code requires taking the cpu hotplug lock.  Other
 * parts of the kernel allocate memory with that lock held, which means that
 * XFS callers cannot hold any locks that might be used by memory reclaim or
 * writeback when calling the static_branch_{inc,dec} functions.
 */
DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_dir_hooks_switch);

void
xfs_dir_hook_disable(void)
{
	xfs_hooks_switch_off(&xfs_dir_hooks_switch);
}

void
xfs_dir_hook_enable(void)
{
	xfs_hooks_switch_on(&xfs_dir_hooks_switch);
}

/* Call hooks for a directory update relating to a child dirent update. */
inline void
xfs_dir_update_hook(
	struct xfs_inode		*dp,
	struct xfs_inode		*ip,
	int				delta,
	const struct xfs_name		*name)
{
	if (xfs_hooks_switched_on(&xfs_dir_hooks_switch)) {
		struct xfs_dir_update_params	p = {
			.dp		= dp,
			.ip		= ip,
			.delta		= delta,
			.name		= name,
		};
		struct xfs_mount	*mp = ip->i_mount;

		xfs_hooks_call(&mp->m_dir_update_hooks, 0, &p);
	}
}

/* Call the specified function during a directory update. */
int
xfs_dir_hook_add(
	struct xfs_mount	*mp,
	struct xfs_dir_hook	*hook)
{
	return xfs_hooks_add(&mp->m_dir_update_hooks, &hook->dirent_hook);
}

/* Stop calling the specified function during a directory update. */
void
xfs_dir_hook_del(
	struct xfs_mount	*mp,
	struct xfs_dir_hook	*hook)
{
	xfs_hooks_del(&mp->m_dir_update_hooks, &hook->dirent_hook);
}

/* Configure directory update hook functions. */
void
xfs_dir_hook_setup(
	struct xfs_dir_hook	*hook,
	notifier_fn_t		mod_fn)
{
	xfs_hook_setup(&hook->dirent_hook, mod_fn);
}
#endif /* CONFIG_XFS_LIVE_HOOKS */

/*
 * Given a directory @dp, a newly allocated inode @ip, and a @name, link @ip
 * into @dp under the given @name.  If @ip is a directory, it will be
@@ -809,6 +884,7 @@ xfs_dir_create_child(
			return error;
	}

	xfs_dir_update_hook(dp, ip, 1, name);
	return 0;
}

@@ -873,6 +949,7 @@ xfs_dir_add_child(
			return error;
	}

	xfs_dir_update_hook(dp, ip, 1, name);
	return 0;
}

@@ -954,6 +1031,7 @@ xfs_dir_remove_child(
			return error;
	}

	xfs_dir_update_hook(dp, ip, -1, name);
	return 0;
}

@@ -1079,6 +1157,18 @@ xfs_dir_exchange_children(
			return error;
	}

	/*
	 * Inform our hook clients that we've finished an exchange operation as
	 * follows: removed the source and target files from their directories;
	 * added the target to the source directory; and added the source to
	 * the target directory.  All inodes are locked, so it's ok to model a
	 * rename this way so long as we say we deleted entries before we add
	 * new ones.
	 */
	xfs_dir_update_hook(dp1, ip1, -1, name1);
	xfs_dir_update_hook(dp2, ip2, -1, name2);
	xfs_dir_update_hook(dp1, ip2, 1, name1);
	xfs_dir_update_hook(dp2, ip1, 1, name2);
	return 0;
}

@@ -1305,5 +1395,19 @@ xfs_dir_rename_children(
			return error;
	}

	/*
	 * Inform our hook clients that we've finished a rename operation as
	 * follows: removed the source and target files from their directories;
	 * that we've added the source to the target directory; and finally
	 * that we've added the whiteout, if there was one.  All inodes are
	 * locked, so it's ok to model a rename this way so long as we say we
	 * deleted entries before we add new ones.
	 */
	if (target_ip)
		xfs_dir_update_hook(target_dp, target_ip, -1, target_name);
	xfs_dir_update_hook(src_dp, src_ip, -1, src_name);
	xfs_dir_update_hook(target_dp, src_ip, 1, target_name);
	if (du_wip->ip)
		xfs_dir_update_hook(src_dp, du_wip->ip, 1, src_name);
	return 0;
}
+25 −0
Original line number Diff line number Diff line
@@ -309,6 +309,31 @@ static inline unsigned char xfs_ascii_ci_xfrm(unsigned char c)
	return c;
}

struct xfs_dir_update_params {
	const struct xfs_inode	*dp;
	const struct xfs_inode	*ip;
	const struct xfs_name	*name;
	int			delta;
};

#ifdef CONFIG_XFS_LIVE_HOOKS
void xfs_dir_update_hook(struct xfs_inode *dp, struct xfs_inode *ip,
		int delta, const struct xfs_name *name);

struct xfs_dir_hook {
	struct xfs_hook		dirent_hook;
};

void xfs_dir_hook_disable(void);
void xfs_dir_hook_enable(void);

int xfs_dir_hook_add(struct xfs_mount *mp, struct xfs_dir_hook *hook);
void xfs_dir_hook_del(struct xfs_mount *mp, struct xfs_dir_hook *hook);
void xfs_dir_hook_setup(struct xfs_dir_hook *hook, notifier_fn_t mod_fn);
#else
# define xfs_dir_update_hook(dp, ip, delta, name)	((void)0)
#endif /* CONFIG_XFS_LIVE_HOOKS */

struct xfs_parent_args;

struct xfs_dir_update {
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_dir2_priv.h"
#include "xfs_dir2.h"
#include "xfs_attr.h"
#include "xfs_reflink.h"
#include "xfs_ag.h"
+0 −117
Original line number Diff line number Diff line
@@ -600,81 +600,6 @@ xfs_icreate(
	return 0;
}

#ifdef CONFIG_XFS_LIVE_HOOKS
/*
 * Use a static key here to reduce the overhead of directory live update hooks.
 * If the compiler supports jump labels, the static branch will be replaced by
 * a nop sled when there are no hook users.  Online fsck is currently the only
 * caller, so this is a reasonable tradeoff.
 *
 * Note: Patching the kernel code requires taking the cpu hotplug lock.  Other
 * parts of the kernel allocate memory with that lock held, which means that
 * XFS callers cannot hold any locks that might be used by memory reclaim or
 * writeback when calling the static_branch_{inc,dec} functions.
 */
DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_dir_hooks_switch);

void
xfs_dir_hook_disable(void)
{
	xfs_hooks_switch_off(&xfs_dir_hooks_switch);
}

void
xfs_dir_hook_enable(void)
{
	xfs_hooks_switch_on(&xfs_dir_hooks_switch);
}

/* Call hooks for a directory update relating to a child dirent update. */
inline void
xfs_dir_update_hook(
	struct xfs_inode		*dp,
	struct xfs_inode		*ip,
	int				delta,
	const struct xfs_name		*name)
{
	if (xfs_hooks_switched_on(&xfs_dir_hooks_switch)) {
		struct xfs_dir_update_params	p = {
			.dp		= dp,
			.ip		= ip,
			.delta		= delta,
			.name		= name,
		};
		struct xfs_mount	*mp = ip->i_mount;

		xfs_hooks_call(&mp->m_dir_update_hooks, 0, &p);
	}
}

/* Call the specified function during a directory update. */
int
xfs_dir_hook_add(
	struct xfs_mount	*mp,
	struct xfs_dir_hook	*hook)
{
	return xfs_hooks_add(&mp->m_dir_update_hooks, &hook->dirent_hook);
}

/* Stop calling the specified function during a directory update. */
void
xfs_dir_hook_del(
	struct xfs_mount	*mp,
	struct xfs_dir_hook	*hook)
{
	xfs_hooks_del(&mp->m_dir_update_hooks, &hook->dirent_hook);
}

/* Configure directory update hook functions. */
void
xfs_dir_hook_setup(
	struct xfs_dir_hook	*hook,
	notifier_fn_t		mod_fn)
{
	xfs_hook_setup(&hook->dirent_hook, mod_fn);
}
#endif /* CONFIG_XFS_LIVE_HOOKS */

/* Return dquots for the ids that will be assigned to a new file. */
int
xfs_icreate_dqalloc(
@@ -798,12 +723,6 @@ xfs_create(
	if (error)
		goto out_trans_cancel;

	/*
	 * Create ip with a reference from dp, and add '.' and '..' references
	 * if it's a directory.
	 */
	xfs_dir_update_hook(dp, du.ip, 1, name);

	/*
	 * If this is a synchronous mount, make sure that the
	 * create transaction goes to disk before returning to
@@ -1025,8 +944,6 @@ xfs_link(
	if (error)
		goto error_return;

	xfs_dir_update_hook(tdp, sip, 1, target_name);

	/*
	 * If this is a synchronous mount, make sure that the
	 * link transaction goes to disk before returning to
@@ -2094,12 +2011,6 @@ xfs_remove(
	if (error)
		goto out_trans_cancel;

	/*
	 * Drop the link from dp to ip, and if ip was a directory, remove the
	 * '.' and '..' references since we freed the directory.
	 */
	xfs_dir_update_hook(dp, ip, -1, name);

	/*
	 * If this is a synchronous mount, make sure that the
	 * remove transaction goes to disk before returning to
@@ -2256,19 +2167,6 @@ xfs_cross_rename(
	if (error)
		goto out_trans_abort;

	/*
	 * Inform our hook clients that we've finished an exchange operation as
	 * follows: removed the source and target files from their directories;
	 * added the target to the source directory; and added the source to
	 * the target directory.  All inodes are locked, so it's ok to model a
	 * rename this way so long as we say we deleted entries before we add
	 * new ones.
	 */
	xfs_dir_update_hook(dp1, ip1, -1, name1);
	xfs_dir_update_hook(dp2, ip2, -1, name2);
	xfs_dir_update_hook(dp1, ip2, 1, name1);
	xfs_dir_update_hook(dp2, ip1, 1, name2);

	return xfs_finish_rename(tp);

out_trans_abort:
@@ -2550,21 +2448,6 @@ xfs_rename(
		VFS_I(du_wip.ip)->i_state &= ~I_LINKABLE;
	}

	/*
	 * Inform our hook clients that we've finished a rename operation as
	 * follows: removed the source and target files from their directories;
	 * that we've added the source to the target directory; and finally
	 * that we've added the whiteout, if there was one.  All inodes are
	 * locked, so it's ok to model a rename this way so long as we say we
	 * deleted entries before we add new ones.
	 */
	if (target_ip)
		xfs_dir_update_hook(target_dp, target_ip, -1, target_name);
	xfs_dir_update_hook(src_dp, src_ip, -1, src_name);
	xfs_dir_update_hook(target_dp, src_ip, 1, target_name);
	if (du_wip.ip)
		xfs_dir_update_hook(src_dp, du_wip.ip, 1, src_name);

	error = xfs_finish_rename(tp);
	nospace_error = 0;
	goto out_unlock;
+0 −25
Original line number Diff line number Diff line
@@ -632,31 +632,6 @@ void xfs_inode_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
		xfs_filblks_t *dblocks, xfs_filblks_t *rblocks);
unsigned int xfs_inode_alloc_unitsize(struct xfs_inode *ip);

struct xfs_dir_update_params {
	const struct xfs_inode	*dp;
	const struct xfs_inode	*ip;
	const struct xfs_name	*name;
	int			delta;
};

#ifdef CONFIG_XFS_LIVE_HOOKS
void xfs_dir_update_hook(struct xfs_inode *dp, struct xfs_inode *ip,
		int delta, const struct xfs_name *name);

struct xfs_dir_hook {
	struct xfs_hook		dirent_hook;
};

void xfs_dir_hook_disable(void);
void xfs_dir_hook_enable(void);

int xfs_dir_hook_add(struct xfs_mount *mp, struct xfs_dir_hook *hook);
void xfs_dir_hook_del(struct xfs_mount *mp, struct xfs_dir_hook *hook);
void xfs_dir_hook_setup(struct xfs_dir_hook *hook, notifier_fn_t mod_fn);
#else
# define xfs_dir_update_hook(dp, ip, delta, name)	((void)0)
#endif /* CONFIG_XFS_LIVE_HOOKS */

int xfs_icreate_dqalloc(const struct xfs_icreate_args *args,
		struct xfs_dquot **udqpp, struct xfs_dquot **gdqpp,
		struct xfs_dquot **pdqpp);
Loading