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: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
28d0d81344
commit
62bbf50bea
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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 @@ retry:
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -200,8 +200,6 @@ xfs_symlink(
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
xfs_dir_update_hook(dp, du.ip, 1, link_name);
|
||||
|
||||
/*
|
||||
* If this is a synchronous mount, make sure that the
|
||||
* symlink transaction goes to disk before returning to
|
||||
|
Loading…
Reference in New Issue
Block a user