[Ocfs2-devel] [PATCH] ocfs2: flush dentry lock drop when sync ocfs2 volume.
Tao Ma
tao.ma at oracle.com
Mon Jul 20 02:08:42 PDT 2009
In commit ea455f8ab68338ba69f5d3362b342c115bea8e13, we move the
dentry lock put process into ocfs2_wq. This is OK for most case,
but as for umount, it lead to at least 2 bugs. See
http://oss.oracle.com/bugzilla/show_bug.cgi?id=1133 and
http://oss.oracle.com/bugzilla/show_bug.cgi?id=1135. And it happens
easily if we have opened a lot of inodes.
For 1135, the reason is that during umount will call
generic_shutdown_super and it will do:
1. shrink_dcache_for_umount
2. sync_filesystem.
3. invalidate_inodes.
In shrink_dcache_for_umount, we will drop the dentry, and queue
ocfs2_wq for dentry lock put. While in invalidate_inodes we will
call invalidate_list which will iterate all the inodes for the sb.
The bad thing is that in this function it will call
cond_resched_lock(&inode_lock). So if in any case, we are scheduled
out and ocfs2_wq is scheduled and drop some inodes, the "next" in
invalidate_list will get damaged(have next->next = next). And the
invalidate_list will enter dead loop and cause very high cpu.
So the only chance that we can solve this problem is flush dentry put
in step 2 of generic_shutdown_super, that is sync_filesystem. And
this patch is just adding dentry put flush process in ocfs2_sync_fs.
Jan,
Will dentry put in sync_fs have potential dead lock with quota
lock? If yes, maybe we have to revert that commit which cause this umount
problem and find other ways instead.
Cc: Jan Kara <jack at suse.cz>
Cc: Joel Becker <joel.becker at oracle.com>
Cc: Mark Fasheh <mfasheh at suse.com>
Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
fs/ocfs2/dcache.c | 16 ++++++++++++++++
fs/ocfs2/dcache.h | 1 +
fs/ocfs2/super.c | 7 +++++++
3 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index b574431..610288a 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -316,6 +316,22 @@ static DEFINE_SPINLOCK(dentry_list_lock);
* this limit so that we don't starve other users of ocfs2_wq. */
#define DL_INODE_DROP_COUNT 64
+void ocfs2_flush_dl_inode_drop(struct ocfs2_super *osb)
+{
+ struct ocfs2_dentry_lock *dl;
+
+ spin_lock(&dentry_list_lock);
+ while (osb->dentry_lock_list) {
+ dl = osb->dentry_lock_list;
+ osb->dentry_lock_list = dl->dl_next;
+ spin_unlock(&dentry_list_lock);
+ iput(dl->dl_inode);
+ kfree(dl);
+ spin_lock(&dentry_list_lock);
+ }
+ spin_unlock(&dentry_list_lock);
+}
+
/* Drop inode references from dentry locks */
void ocfs2_drop_dl_inodes(struct work_struct *work)
{
diff --git a/fs/ocfs2/dcache.h b/fs/ocfs2/dcache.h
index faa12e7..6dcf7cd 100644
--- a/fs/ocfs2/dcache.h
+++ b/fs/ocfs2/dcache.h
@@ -62,4 +62,5 @@ void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target,
extern spinlock_t dentry_attach_lock;
+void ocfs2_flush_dl_inode_drop(struct ocfs2_super *osb);
#endif /* OCFS2_DCACHE_H */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 2b4fd69..7e80fda 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -384,6 +384,13 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait)
if (ocfs2_is_hard_readonly(osb))
return -EROFS;
+ if (osb->dentry_lock_list) {
+ if (wait)
+ ocfs2_flush_dl_inode_drop(osb);
+ else
+ queue_work(ocfs2_wq, &osb->dentry_lock_work);
+ }
+
if (wait) {
status = ocfs2_flush_truncate_log(osb);
if (status < 0)
--
1.6.2.rc2.16.gf474c
More information about the Ocfs2-devel
mailing list