]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.fixes/bug-531716_ocfs2-SLE11-dentry_lock_drop_flush.diff
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / bug-531716_ocfs2-SLE11-dentry_lock_drop_flush.diff
1 From: Jan Kara <jack@suse.cz>
2 Subject: ocfs2: Fix deadlock on umount
3 References: bnc#531716
4 Patch-mainline: 2.6.32
5
6 In patch patches.fixes/ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch
7 we moved the dentry lock put process into ocfs2_wq. This causes problems during
8 umount because ocfs2_wq can drop references to inodes while they are being
9 invalidated by invalidate_inodes() causing all sorts of nasty things
10 (invalidate_inodes() ending in an infinite loop, "Busy inodes after umount"
11 messages etc.).
12
13 We fix the problem by stopping ocfs2_wq from doing any further releasing of
14 inode references on the superblock being unmounted, wait until it finishes
15 the current round of releasing and finally cleaning up all the references in
16 dentry_lock_list from ocfs2_put_super().
17
18 The issue was tracked down by Tao Ma <tao.ma@oracle.com>.
19
20 Signed-off-by: Jan Kara <jack@suse.cz>
21 Signed-off-by: Joel Becker <joel.becker@oracle.com>
22
23 diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/ocfs2/dcache.c linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/dcache.c
24 --- linux-2.6.27-SLE11_BRANCH/fs/ocfs2/dcache.c 2009-08-18 15:39:32.000000000 +0200
25 +++ linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/dcache.c 2009-08-18 15:44:51.000000000 +0200
26 @@ -295,22 +295,19 @@ out_attach:
27 return ret;
28 }
29
30 -static DEFINE_SPINLOCK(dentry_list_lock);
31 +DEFINE_SPINLOCK(dentry_list_lock);
32
33 /* We limit the number of dentry locks to drop in one go. We have
34 * this limit so that we don't starve other users of ocfs2_wq. */
35 #define DL_INODE_DROP_COUNT 64
36
37 /* Drop inode references from dentry locks */
38 -void ocfs2_drop_dl_inodes(struct work_struct *work)
39 +static void __ocfs2_drop_dl_inodes(struct ocfs2_super *osb, int drop_count)
40 {
41 - struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
42 - dentry_lock_work);
43 struct ocfs2_dentry_lock *dl;
44 - int drop_count = DL_INODE_DROP_COUNT;
45
46 spin_lock(&dentry_list_lock);
47 - while (osb->dentry_lock_list && drop_count--) {
48 + while (osb->dentry_lock_list && (drop_count < 0 || drop_count--)) {
49 dl = osb->dentry_lock_list;
50 osb->dentry_lock_list = dl->dl_next;
51 spin_unlock(&dentry_list_lock);
52 @@ -318,11 +315,32 @@ void ocfs2_drop_dl_inodes(struct work_st
53 kfree(dl);
54 spin_lock(&dentry_list_lock);
55 }
56 - if (osb->dentry_lock_list)
57 + spin_unlock(&dentry_list_lock);
58 +}
59 +
60 +void ocfs2_drop_dl_inodes(struct work_struct *work)
61 +{
62 + struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
63 + dentry_lock_work);
64 +
65 + __ocfs2_drop_dl_inodes(osb, DL_INODE_DROP_COUNT);
66 + /*
67 + * Don't queue dropping if umount is in progress. We flush the
68 + * list in ocfs2_dismount_volume
69 + */
70 + spin_lock(&dentry_list_lock);
71 + if (osb->dentry_lock_list &&
72 + !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
73 queue_work(ocfs2_wq, &osb->dentry_lock_work);
74 spin_unlock(&dentry_list_lock);
75 }
76
77 +/* Flush the whole work queue */
78 +void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb)
79 +{
80 + __ocfs2_drop_dl_inodes(osb, -1);
81 +}
82 +
83 /*
84 * ocfs2_dentry_iput() and friends.
85 *
86 @@ -353,7 +371,8 @@ static void ocfs2_drop_dentry_lock(struc
87 /* We leave dropping of inode reference to ocfs2_wq as that can
88 * possibly lead to inode deletion which gets tricky */
89 spin_lock(&dentry_list_lock);
90 - if (!osb->dentry_lock_list)
91 + if (!osb->dentry_lock_list &&
92 + !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
93 queue_work(ocfs2_wq, &osb->dentry_lock_work);
94 dl->dl_next = osb->dentry_lock_list;
95 osb->dentry_lock_list = dl;
96 diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/ocfs2/dcache.h linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/dcache.h
97 --- linux-2.6.27-SLE11_BRANCH/fs/ocfs2/dcache.h 2009-08-18 15:39:32.000000000 +0200
98 +++ linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/dcache.h 2009-08-18 15:44:51.000000000 +0200
99 @@ -49,10 +49,13 @@ struct ocfs2_dentry_lock {
100 int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode,
101 u64 parent_blkno);
102
103 +extern spinlock_t dentry_list_lock;
104 +
105 void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
106 struct ocfs2_dentry_lock *dl);
107
108 void ocfs2_drop_dl_inodes(struct work_struct *work);
109 +void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb);
110
111 struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
112 int skip_unhashed);
113 diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/ocfs2/ocfs2.h linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/ocfs2.h
114 --- linux-2.6.27-SLE11_BRANCH/fs/ocfs2/ocfs2.h 2009-08-18 15:39:32.000000000 +0200
115 +++ linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/ocfs2.h 2009-08-18 15:44:51.000000000 +0200
116 @@ -201,10 +201,12 @@ enum ocfs2_mount_options
117 OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */
118 };
119
120 -#define OCFS2_OSB_SOFT_RO 0x0001
121 -#define OCFS2_OSB_HARD_RO 0x0002
122 -#define OCFS2_OSB_ERROR_FS 0x0004
123 -#define OCFS2_DEFAULT_ATIME_QUANTUM 60
124 +#define OCFS2_OSB_SOFT_RO 0x0001
125 +#define OCFS2_OSB_HARD_RO 0x0002
126 +#define OCFS2_OSB_ERROR_FS 0x0004
127 +#define OCFS2_OSB_DROP_DENTRY_LOCK_IMMED 0x0008
128 +
129 +#define OCFS2_DEFAULT_ATIME_QUANTUM 60
130
131 struct ocfs2_journal;
132 struct ocfs2_slot_info;
133 @@ -400,6 +402,18 @@ static inline void ocfs2_set_osb_flag(st
134 spin_unlock(&osb->osb_lock);
135 }
136
137 +
138 +static inline unsigned long ocfs2_test_osb_flag(struct ocfs2_super *osb,
139 + unsigned long flag)
140 +{
141 + unsigned long ret;
142 +
143 + spin_lock(&osb->osb_lock);
144 + ret = osb->osb_flags & flag;
145 + spin_unlock(&osb->osb_lock);
146 + return ret;
147 +}
148 +
149 static inline void ocfs2_set_ro_flag(struct ocfs2_super *osb,
150 int hard)
151 {
152 diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/ocfs2/super.c linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/super.c
153 --- linux-2.6.27-SLE11_BRANCH/fs/ocfs2/super.c 2009-08-18 15:39:33.000000000 +0200
154 +++ linux-2.6.27-SLE11_BRANCH-1-dentry_lock_drop//fs/ocfs2/super.c 2009-08-18 15:46:56.000000000 +0200
155 @@ -1014,14 +1014,27 @@ static int ocfs2_get_sb(struct file_syst
156 mnt);
157 }
158
159 +static void ocfs2_kill_sb(struct super_block *sb)
160 +{
161 + struct ocfs2_super *osb = OCFS2_SB(sb);
162 +
163 + /* Prevent further queueing of inode drop events */
164 + spin_lock(&dentry_list_lock);
165 + ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED);
166 + spin_unlock(&dentry_list_lock);
167 + /* Wait for work to finish and/or remove it */
168 + cancel_work_sync(&osb->dentry_lock_work);
169 +
170 + kill_block_super(sb);
171 +}
172 +
173 static struct file_system_type ocfs2_fs_type = {
174 .owner = THIS_MODULE,
175 .name = "ocfs2",
176 .get_sb = ocfs2_get_sb, /* is this called when we mount
177 * the fs? */
178 - .kill_sb = kill_block_super, /* set to the generic one
179 - * right now, but do we
180 - * need to change that? */
181 + .kill_sb = ocfs2_kill_sb,
182 +
183 .fs_flags = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
184 .next = NULL
185 };
186 @@ -1621,6 +1634,12 @@ static void ocfs2_dismount_volume(struct
187 osb = OCFS2_SB(sb);
188 BUG_ON(!osb);
189
190 + /*
191 + * Flush inode dropping work queue so that deletes are
192 + * performed while the filesystem is still working
193 + */
194 + ocfs2_drop_all_dl_inodes(osb);
195 +
196 ocfs2_disable_quotas(osb);
197
198 ocfs2_shutdown_local_alloc(osb);