Commit ea455f8a authored by Jan Kara's avatar Jan Kara Committed by Mark Fasheh

ocfs2: Push out dropping of dentry lock to ocfs2_wq

Dropping of last reference to dentry lock is a complicated operation involving
dropping of reference to inode. This can get complicated and quota code in
particular needs to obtain some quota locks which leads to potential deadlock.
Thus we defer dropping of inode reference to ocfs2_wq.
Signed-off-by: default avatarJan Kara <>
Signed-off-by: default avatarMark Fasheh <>
parent 27421e21
......@@ -38,6 +38,7 @@
#include "dlmglue.h"
#include "file.h"
#include "inode.h"
#include "super.h"
static int ocfs2_dentry_revalidate(struct dentry *dentry,
......@@ -294,6 +295,34 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
return ret;
static DEFINE_SPINLOCK(dentry_list_lock);
/* We limit the number of dentry locks to drop in one go. We have
* this limit so that we don't starve other users of ocfs2_wq. */
/* Drop inode references from dentry locks */
void ocfs2_drop_dl_inodes(struct work_struct *work)
struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
struct ocfs2_dentry_lock *dl;
int drop_count = DL_INODE_DROP_COUNT;
while (osb->dentry_lock_list && drop_count--) {
dl = osb->dentry_lock_list;
osb->dentry_lock_list = dl->dl_next;
if (osb->dentry_lock_list)
queue_work(ocfs2_wq, &osb->dentry_lock_work);
* ocfs2_dentry_iput() and friends.
......@@ -318,16 +347,23 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb,
struct ocfs2_dentry_lock *dl)
ocfs2_simple_drop_lockres(osb, &dl->dl_lockres);
/* We leave dropping of inode reference to ocfs2_wq as that can
* possibly lead to inode deletion which gets tricky */
if (!osb->dentry_lock_list)
queue_work(ocfs2_wq, &osb->dentry_lock_work);
dl->dl_next = osb->dentry_lock_list;
osb->dentry_lock_list = dl;
void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
struct ocfs2_dentry_lock *dl)
int unlock = 0;
int unlock;
BUG_ON(dl->dl_count == 0);
......@@ -29,8 +29,13 @@
extern struct dentry_operations ocfs2_dentry_ops;
struct ocfs2_dentry_lock {
/* Use count of dentry lock */
unsigned int dl_count;
u64 dl_parent_blkno;
union {
/* Linked list of dentry locks to release */
struct ocfs2_dentry_lock *dl_next;
u64 dl_parent_blkno;
* The ocfs2_dentry_lock keeps an inode reference until
......@@ -47,6 +52,8 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode,
void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
struct ocfs2_dentry_lock *dl);
void ocfs2_drop_dl_inodes(struct work_struct *work);
struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
int skip_unhashed);
......@@ -210,6 +210,7 @@ struct ocfs2_journal;
struct ocfs2_slot_info;
struct ocfs2_recovery_map;
struct ocfs2_quota_recovery;
struct ocfs2_dentry_lock;
struct ocfs2_super
struct task_struct *commit_task;
......@@ -325,6 +326,11 @@ struct ocfs2_super
struct list_head blocked_lock_list;
unsigned long blocked_lock_count;
/* List of dentry locks to release. Anyone can add locks to
* the list, ocfs2_wq processes the list */
struct ocfs2_dentry_lock *dentry_lock_list;
struct work_struct dentry_lock_work;
wait_queue_head_t osb_mount_event;
/* Truncate log info */
......@@ -1887,6 +1887,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery);
journal->j_state = OCFS2_JOURNAL_FREE;
INIT_WORK(&osb->dentry_lock_work, ocfs2_drop_dl_inodes);
osb->dentry_lock_list = NULL;
/* get some pseudo constants for clustersize bits */
osb->s_clustersize_bits =
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