]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.fixes/ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch
1 From: Jan Kara <jack@suse.cz>
2 Date: Mon, 12 Jan 2009 23:20:31 +0100
3 Subject: [PATCH] ocfs2: Push out dropping of dentry lock to ocfs2_wq
4 Patch-mainline: 2.6.29
5
6 Dropping of last reference to dentry lock is a complicated operation involving
7 dropping of reference to inode. This can get complicated and quota code in
8 particular needs to obtain some quota locks which leads to potential deadlock.
9 Thus we defer dropping of inode reference to ocfs2_wq.
10
11 Signed-off-by: Jan Kara <jack@suse.cz>
12 Signed-off-by: Mark Fasheh <mfasheh@suse.com>
13 ---
14 fs/ocfs2/dcache.c | 42 +++++++++++++++++++++++++++++++++++++++---
15 fs/ocfs2/dcache.h | 9 ++++++++-
16 fs/ocfs2/ocfs2.h | 6 ++++++
17 fs/ocfs2/super.c | 3 +++
18 4 files changed, 56 insertions(+), 4 deletions(-)
19
20 --- a/fs/ocfs2/dcache.c
21 +++ b/fs/ocfs2/dcache.c
22 @@ -38,6 +38,7 @@
23 #include "dlmglue.h"
24 #include "file.h"
25 #include "inode.h"
26 +#include "super.h"
27
28
29 static int ocfs2_dentry_revalidate(struct dentry *dentry,
30 @@ -294,6 +295,34 @@ out_attach:
31 return ret;
32 }
33
34 +static DEFINE_SPINLOCK(dentry_list_lock);
35 +
36 +/* We limit the number of dentry locks to drop in one go. We have
37 + * this limit so that we don't starve other users of ocfs2_wq. */
38 +#define DL_INODE_DROP_COUNT 64
39 +
40 +/* Drop inode references from dentry locks */
41 +void ocfs2_drop_dl_inodes(struct work_struct *work)
42 +{
43 + struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
44 + dentry_lock_work);
45 + struct ocfs2_dentry_lock *dl;
46 + int drop_count = DL_INODE_DROP_COUNT;
47 +
48 + spin_lock(&dentry_list_lock);
49 + while (osb->dentry_lock_list && drop_count--) {
50 + dl = osb->dentry_lock_list;
51 + osb->dentry_lock_list = dl->dl_next;
52 + spin_unlock(&dentry_list_lock);
53 + iput(dl->dl_inode);
54 + kfree(dl);
55 + spin_lock(&dentry_list_lock);
56 + }
57 + if (osb->dentry_lock_list)
58 + queue_work(ocfs2_wq, &osb->dentry_lock_work);
59 + spin_unlock(&dentry_list_lock);
60 +}
61 +
62 /*
63 * ocfs2_dentry_iput() and friends.
64 *
65 @@ -318,16 +347,23 @@ out_attach:
66 static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb,
67 struct ocfs2_dentry_lock *dl)
68 {
69 - iput(dl->dl_inode);
70 ocfs2_simple_drop_lockres(osb, &dl->dl_lockres);
71 ocfs2_lock_res_free(&dl->dl_lockres);
72 - kfree(dl);
73 +
74 + /* We leave dropping of inode reference to ocfs2_wq as that can
75 + * possibly lead to inode deletion which gets tricky */
76 + spin_lock(&dentry_list_lock);
77 + if (!osb->dentry_lock_list)
78 + queue_work(ocfs2_wq, &osb->dentry_lock_work);
79 + dl->dl_next = osb->dentry_lock_list;
80 + osb->dentry_lock_list = dl;
81 + spin_unlock(&dentry_list_lock);
82 }
83
84 void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
85 struct ocfs2_dentry_lock *dl)
86 {
87 - int unlock = 0;
88 + int unlock;
89
90 BUG_ON(dl->dl_count == 0);
91
92 --- a/fs/ocfs2/dcache.h
93 +++ b/fs/ocfs2/dcache.h
94 @@ -29,8 +29,13 @@
95 extern struct dentry_operations ocfs2_dentry_ops;
96
97 struct ocfs2_dentry_lock {
98 + /* Use count of dentry lock */
99 unsigned int dl_count;
100 - u64 dl_parent_blkno;
101 + union {
102 + /* Linked list of dentry locks to release */
103 + struct ocfs2_dentry_lock *dl_next;
104 + u64 dl_parent_blkno;
105 + };
106
107 /*
108 * The ocfs2_dentry_lock keeps an inode reference until
109 @@ -47,6 +52,8 @@ int ocfs2_dentry_attach_lock(struct dent
110 void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
111 struct ocfs2_dentry_lock *dl);
112
113 +void ocfs2_drop_dl_inodes(struct work_struct *work);
114 +
115 struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
116 int skip_unhashed);
117
118 --- a/fs/ocfs2/ocfs2.h
119 +++ b/fs/ocfs2/ocfs2.h
120 @@ -210,6 +210,7 @@ struct ocfs2_journal;
121 struct ocfs2_slot_info;
122 struct ocfs2_recovery_map;
123 struct ocfs2_quota_recovery;
124 +struct ocfs2_dentry_lock;
125 struct ocfs2_super
126 {
127 struct task_struct *commit_task;
128 @@ -325,6 +326,11 @@ struct ocfs2_super
129 struct list_head blocked_lock_list;
130 unsigned long blocked_lock_count;
131
132 + /* List of dentry locks to release. Anyone can add locks to
133 + * the list, ocfs2_wq processes the list */
134 + struct ocfs2_dentry_lock *dentry_lock_list;
135 + struct work_struct dentry_lock_work;
136 +
137 wait_queue_head_t osb_mount_event;
138
139 /* Truncate log info */
140 --- a/fs/ocfs2/super.c
141 +++ b/fs/ocfs2/super.c
142 @@ -1888,6 +1888,9 @@ static int ocfs2_initialize_super(struct
143 INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery);
144 journal->j_state = OCFS2_JOURNAL_FREE;
145
146 + INIT_WORK(&osb->dentry_lock_work, ocfs2_drop_dl_inodes);
147 + osb->dentry_lock_list = NULL;
148 +
149 /* get some pseudo constants for clustersize bits */
150 osb->s_clustersize_bits =
151 le32_to_cpu(di->id2.i_super.s_clustersize_bits);