mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ocfs2: cache the mount context for dentry lock callbacks
ocfs2_drop_dentry_lock() drops the inode reference before releasing the
DENTRY lock. This lets inode eviction release the local inode and open
locks before a remote unlink can proceed past the DENTRY lock.
A DLM callback can still arrive before the DENTRY lock has been dropped.
ocfs2_get_dentry_osb() obtains the mount context through dl_inode->i_sb,
which can access a freed inode when the downconvert thread drops the
last inode reference in its post-unlock callback:
Downconvert thread DLM callback thread
------------------ -------------------
ocfs2_process_blocked_lock()
ocfs2_dentry_post_unlock()
ocfs2_dentry_lock_put()
ocfs2_drop_dentry_lock()
iput(dl->dl_inode)
[inode reclaimed after RCU]
ocfs2_blocking_ast()
ocfs2_get_dentry_osb()
dl->dl_inode->i_sb
ocfs2_simple_drop_lockres()
Store the mount context in the DENTRY lock resource's l_priv field and use
the default mount-context lookup. Recover the containing dentry lock with
container_of(), as already done for refcount locks, and remove
ocfs2_get_dentry_osb(). ocfs2_dismount_volume() shuts down the DLM before
freeing the mount context, so callbacks can use it without accessing the
inode. Preserve the existing iput-before-unlock order to avoid delaying
local inode and open lock release until after the DENTRY lock is released.
Link: https://lore.kernel.org/pm-ocfs2-objects-candidate-0012-v9-eeb9084fb29577971229@gmail.com
Fixes: 8ed6b23709 ("ocfs2: revert iput deferring code in ocfs2_drop_dentry_lock")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Assisted-by: LLM
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Jia-Ju Bai <baijiaju1990@gmail.com>
Cc: <jjzuming@gmail.com>
Cc: <stable@vger.kernel.org>
This commit is contained in:
parent
a25c02af29
commit
5b4696e0bf
|
|
@ -17,9 +17,8 @@ struct ocfs2_dentry_lock {
|
|||
u64 dl_parent_blkno;
|
||||
|
||||
/*
|
||||
* The ocfs2_dentry_lock keeps an inode reference until
|
||||
* dl_lockres has been destroyed. This is usually done in
|
||||
* ->d_iput() anyway, so there should be minimal impact.
|
||||
* The inode reference is dropped before dl_lockres is unlocked.
|
||||
* Callbacks must not use it to find the mount context during teardown.
|
||||
*/
|
||||
struct inode *dl_inode;
|
||||
struct ocfs2_lock_res dl_lockres;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ struct ocfs2_mask_waiter {
|
|||
#endif
|
||||
};
|
||||
|
||||
static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
|
||||
static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
|
||||
static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
|
||||
static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres);
|
||||
|
|
@ -258,7 +257,6 @@ static const struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = {
|
|||
};
|
||||
|
||||
static const struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
|
||||
.get_osb = ocfs2_get_dentry_osb,
|
||||
.post_unlock = ocfs2_dentry_post_unlock,
|
||||
.downconvert_worker = ocfs2_dentry_convert_worker,
|
||||
.flags = 0,
|
||||
|
|
@ -309,7 +307,7 @@ static inline struct ocfs2_dentry_lock *ocfs2_lock_res_dl(struct ocfs2_lock_res
|
|||
{
|
||||
BUG_ON(lockres->l_type != OCFS2_LOCK_TYPE_DENTRY);
|
||||
|
||||
return (struct ocfs2_dentry_lock *)lockres->l_priv;
|
||||
return container_of(lockres, struct ocfs2_dentry_lock, dl_lockres);
|
||||
}
|
||||
|
||||
static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_res *lockres)
|
||||
|
|
@ -610,13 +608,6 @@ static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres)
|
|||
return be64_to_cpu(inode_blkno_be);
|
||||
}
|
||||
|
||||
static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
struct ocfs2_dentry_lock *dl = lockres->l_priv;
|
||||
|
||||
return OCFS2_SB(dl->dl_inode->i_sb);
|
||||
}
|
||||
|
||||
void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
|
||||
u64 parent, struct inode *inode)
|
||||
{
|
||||
|
|
@ -624,6 +615,7 @@ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
|
|||
u64 inode_blkno = OCFS2_I(inode)->ip_blkno;
|
||||
__be64 inode_blkno_be = cpu_to_be64(inode_blkno);
|
||||
struct ocfs2_lock_res *lockres = &dl->dl_lockres;
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
|
||||
ocfs2_lock_res_init_once(lockres);
|
||||
|
||||
|
|
@ -652,9 +644,9 @@ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
|
|||
memcpy(&lockres->l_name[OCFS2_DENTRY_LOCK_INO_START], &inode_blkno_be,
|
||||
sizeof(__be64));
|
||||
|
||||
ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres,
|
||||
ocfs2_lock_res_init_common(osb, lockres,
|
||||
OCFS2_LOCK_TYPE_DENTRY, &ocfs2_dentry_lops,
|
||||
dl);
|
||||
osb);
|
||||
}
|
||||
|
||||
static void ocfs2_super_lock_res_init(struct ocfs2_lock_res *res,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user