]>
Commit | Line | Data |
---|---|---|
3b04b1f3 JR |
1 | From jlayton@redhat.com Thu Dec 11 08:49:55 2008 |
2 | From: Jeff Layton <jlayton@redhat.com> | |
3 | Date: Wed, 10 Dec 2008 06:44:29 -0500 | |
4 | Subject: cifs: fix a regression in cifs umount codepath | |
5 | To: greg@kroah.com, stable@kernel.org | |
6 | Cc: smfrench@gmail.com, shirishp@us.ibm.com, sjayaraman@suse.de | |
7 | Message-ID: <1228909469-438-1-git-send-email-jlayton@redhat.com> | |
8 | ||
9 | From: Jeff Layton <jlayton@redhat.com> | |
10 | ||
11 | backport of 469ee614aaa367d9cde01cbdd2027212f56c6cc6 upstream. | |
12 | ||
13 | Several cifs patches were added to 2.6.27.8 to fix some races in the | |
14 | mount/umount codepath. When this was done, a couple of prerequisite | |
15 | patches were missed causing a minor regression. | |
16 | ||
17 | When the last cifs mount to a server goes away, the kthread that manages | |
18 | the socket is supposed to come down. The patches that went into 2.6.27.8 | |
19 | removed the kthread_stop calls that used to take down these threads, but | |
20 | left the thread function expecting them. This made the thread stay up | |
21 | even after the last mount was gone. | |
22 | ||
23 | This patch should fix up this regression and also prevent a possible | |
24 | race where a dead task could be signalled. | |
25 | ||
26 | Signed-off-by: Jeff Layton <jlayton@redhat.com> | |
27 | Cc: Suresh Jayaraman <sjayaraman@suse.de> | |
28 | Acked-by: Steve French <smfrench@gmail.com> | |
29 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
30 | ||
31 | --- | |
32 | fs/cifs/connect.c | 36 +++++++++++++++++++++--------------- | |
33 | 1 file changed, 21 insertions(+), 15 deletions(-) | |
34 | ||
35 | --- a/fs/cifs/connect.c | |
36 | +++ b/fs/cifs/connect.c | |
37 | @@ -128,7 +128,7 @@ cifs_reconnect(struct TCP_Server_Info *s | |
38 | struct mid_q_entry *mid_entry; | |
39 | ||
40 | spin_lock(&GlobalMid_Lock); | |
41 | - if (kthread_should_stop()) { | |
42 | + if (server->tcpStatus == CifsExiting) { | |
43 | /* the demux thread will exit normally | |
44 | next time through the loop */ | |
45 | spin_unlock(&GlobalMid_Lock); | |
46 | @@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *s | |
47 | spin_unlock(&GlobalMid_Lock); | |
48 | up(&server->tcpSem); | |
49 | ||
50 | - while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { | |
51 | + while ((server->tcpStatus != CifsExiting) && | |
52 | + (server->tcpStatus != CifsGood)) { | |
53 | try_to_freeze(); | |
54 | if (server->addr.sockAddr6.sin6_family == AF_INET6) { | |
55 | rc = ipv6_connect(&server->addr.sockAddr6, | |
56 | @@ -200,7 +201,7 @@ cifs_reconnect(struct TCP_Server_Info *s | |
57 | } else { | |
58 | atomic_inc(&tcpSesReconnectCount); | |
59 | spin_lock(&GlobalMid_Lock); | |
60 | - if (!kthread_should_stop()) | |
61 | + if (server->tcpStatus != CifsExiting) | |
62 | server->tcpStatus = CifsGood; | |
63 | server->sequence_number = 0; | |
64 | spin_unlock(&GlobalMid_Lock); | |
65 | @@ -355,7 +356,7 @@ cifs_demultiplex_thread(struct TCP_Serve | |
66 | GFP_KERNEL); | |
67 | ||
68 | set_freezable(); | |
69 | - while (!kthread_should_stop()) { | |
70 | + while (server->tcpStatus != CifsExiting) { | |
71 | if (try_to_freeze()) | |
72 | continue; | |
73 | if (bigbuf == NULL) { | |
74 | @@ -396,7 +397,7 @@ incomplete_rcv: | |
75 | kernel_recvmsg(csocket, &smb_msg, | |
76 | &iov, 1, pdu_length, 0 /* BB other flags? */); | |
77 | ||
78 | - if (kthread_should_stop()) { | |
79 | + if (server->tcpStatus == CifsExiting) { | |
80 | break; | |
81 | } else if (server->tcpStatus == CifsNeedReconnect) { | |
82 | cFYI(1, ("Reconnect after server stopped responding")); | |
83 | @@ -527,7 +528,7 @@ incomplete_rcv: | |
84 | total_read += length) { | |
85 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | |
86 | pdu_length - total_read, 0); | |
87 | - if (kthread_should_stop() || | |
88 | + if ((server->tcpStatus == CifsExiting) || | |
89 | (length == -EINTR)) { | |
90 | /* then will exit */ | |
91 | reconnect = 2; | |
92 | @@ -661,14 +662,6 @@ multi_t2_fnd: | |
93 | spin_unlock(&GlobalMid_Lock); | |
94 | wake_up_all(&server->response_q); | |
95 | ||
96 | - /* don't exit until kthread_stop is called */ | |
97 | - set_current_state(TASK_UNINTERRUPTIBLE); | |
98 | - while (!kthread_should_stop()) { | |
99 | - schedule(); | |
100 | - set_current_state(TASK_UNINTERRUPTIBLE); | |
101 | - } | |
102 | - set_current_state(TASK_RUNNING); | |
103 | - | |
104 | /* check if we have blocked requests that need to free */ | |
105 | /* Note that cifs_max_pending is normally 50, but | |
106 | can be set at module install time to as little as two */ | |
107 | @@ -764,6 +757,7 @@ multi_t2_fnd: | |
108 | read_unlock(&cifs_tcp_ses_lock); | |
109 | ||
110 | kfree(server->hostname); | |
111 | + task_to_wake = xchg(&server->tsk, NULL); | |
112 | kfree(server); | |
113 | ||
114 | length = atomic_dec_return(&tcpSesAllocCount); | |
115 | @@ -771,6 +765,16 @@ multi_t2_fnd: | |
116 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, | |
117 | GFP_KERNEL); | |
118 | ||
119 | + /* if server->tsk was NULL then wait for a signal before exiting */ | |
120 | + if (!task_to_wake) { | |
121 | + set_current_state(TASK_INTERRUPTIBLE); | |
122 | + while (!signal_pending(current)) { | |
123 | + schedule(); | |
124 | + set_current_state(TASK_INTERRUPTIBLE); | |
125 | + } | |
126 | + set_current_state(TASK_RUNNING); | |
127 | + } | |
128 | + | |
129 | return 0; | |
130 | } | |
131 | ||
132 | @@ -2310,7 +2314,7 @@ cifs_mount(struct super_block *sb, struc | |
133 | /* on error free sesinfo and tcon struct if needed */ | |
134 | mount_fail_check: | |
135 | if (rc) { | |
136 | - /* If find_unc succeeded then rc == 0 so we can not end */ | |
137 | + /* If find_unc succeeded then rc == 0 so we can not end */ | |
138 | /* up accidently freeing someone elses tcon struct */ | |
139 | if (tcon) | |
140 | cifs_put_tcon(tcon); | |
141 | @@ -3715,8 +3719,10 @@ int cifs_setup_session(unsigned int xid, | |
142 | cERROR(1, ("Send error in SessSetup = %d", rc)); | |
143 | } else { | |
144 | cFYI(1, ("CIFS Session Established successfully")); | |
145 | + spin_lock(&GlobalMid_Lock); | |
146 | pSesInfo->status = CifsGood; | |
147 | pSesInfo->need_reconnect = false; | |
148 | + spin_unlock(&GlobalMid_Lock); | |
149 | } | |
150 | ||
151 | ss_err_exit: | |
152 | From 218d11a8b071b23b76c484fd5f72a4fe3306801e Mon Sep 17 00:00:00 2001 | |
153 | From: Jonathan Corbet <corbet@lwn.net> | |
154 | Date: Fri, 5 Dec 2008 16:12:48 -0700 | |
155 | Subject: Fix a race condition in FASYNC handling | |
156 | ||
157 | From: Jonathan Corbet <corbet@lwn.net> | |
158 | ||
159 | commit 218d11a8b071b23b76c484fd5f72a4fe3306801e upstream. | |
160 | ||
161 | Changeset a238b790d5f99c7832f9b73ac8847025815b85f7 (Call fasync() | |
162 | functions without the BKL) introduced a race which could leave | |
163 | file->f_flags in a state inconsistent with what the underlying | |
164 | driver/filesystem believes. Revert that change, and also fix the same | |
165 | races in ioctl_fioasync() and ioctl_fionbio(). | |
166 | ||
167 | This is a minimal, short-term fix; the real fix will not involve the | |
168 | BKL. | |
169 | ||
170 | Reported-by: Oleg Nesterov <oleg@redhat.com> | |
171 | Cc: Andi Kleen <ak@linux.intel.com> | |
172 | Cc: Al Viro <viro@zeniv.linux.org.uk> | |
173 | Signed-off-by: Jonathan Corbet <corbet@lwn.net> | |
174 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
175 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
176 | ||
177 | --- | |
178 | fs/fcntl.c | 7 +++++++ | |
179 | fs/ioctl.c | 12 ++++++++---- | |
180 | 2 files changed, 15 insertions(+), 4 deletions(-) | |
181 | ||
182 | --- a/fs/fcntl.c | |
183 | +++ b/fs/fcntl.c | |
184 | @@ -19,6 +19,7 @@ | |
185 | #include <linux/signal.h> | |
186 | #include <linux/rcupdate.h> | |
187 | #include <linux/pid_namespace.h> | |
188 | +#include <linux/smp_lock.h> | |
189 | ||
190 | #include <asm/poll.h> | |
191 | #include <asm/siginfo.h> | |
192 | @@ -175,6 +176,11 @@ static int setfl(int fd, struct file * f | |
193 | if (error) | |
194 | return error; | |
195 | ||
196 | + /* | |
197 | + * We still need a lock here for now to keep multiple FASYNC calls | |
198 | + * from racing with each other. | |
199 | + */ | |
200 | + lock_kernel(); | |
201 | if ((arg ^ filp->f_flags) & FASYNC) { | |
202 | if (filp->f_op && filp->f_op->fasync) { | |
203 | error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); | |
204 | @@ -185,6 +191,7 @@ static int setfl(int fd, struct file * f | |
205 | ||
206 | filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); | |
207 | out: | |
208 | + unlock_kernel(); | |
209 | return error; | |
210 | } | |
211 | ||
212 | --- a/fs/ioctl.c | |
213 | +++ b/fs/ioctl.c | |
214 | @@ -123,11 +123,9 @@ static int ioctl_fioasync(unsigned int f | |
215 | ||
216 | /* Did FASYNC state change ? */ | |
217 | if ((flag ^ filp->f_flags) & FASYNC) { | |
218 | - if (filp->f_op && filp->f_op->fasync) { | |
219 | - lock_kernel(); | |
220 | + if (filp->f_op && filp->f_op->fasync) | |
221 | error = filp->f_op->fasync(fd, filp, on); | |
222 | - unlock_kernel(); | |
223 | - } else | |
224 | + else | |
225 | error = -ENOTTY; | |
226 | } | |
227 | if (error) | |
228 | @@ -163,11 +161,17 @@ int do_vfs_ioctl(struct file *filp, unsi | |
229 | break; | |
230 | ||
231 | case FIONBIO: | |
232 | + /* BKL needed to avoid races tweaking f_flags */ | |
233 | + lock_kernel(); | |
234 | error = ioctl_fionbio(filp, argp); | |
235 | + unlock_kernel(); | |
236 | break; | |
237 | ||
238 | case FIOASYNC: | |
239 | + /* BKL needed to avoid races tweaking f_flags */ | |
240 | + lock_kernel(); | |
241 | error = ioctl_fioasync(fd, filp, argp); | |
242 | + unlock_kernel(); | |
243 | break; | |
244 | ||
245 | case FIOQSIZE: | |
246 | From 49c50342c728344b79c8f9e8293637fe80ef5ad5 Mon Sep 17 00:00:00 2001 | |
247 | From: Matt Mackall <mpm@selenic.com> | |
248 | Date: Tue, 9 Dec 2008 13:14:21 -0800 | |
249 | Subject: pagemap: fix 32-bit pagemap regression | |
250 | ||
251 | From: Matt Mackall <mpm@selenic.com> | |
252 | ||
253 | commit 49c50342c728344b79c8f9e8293637fe80ef5ad5 upstream. | |
254 | ||
255 | The large pages fix from bcf8039ed45 broke 32-bit pagemap by pulling the | |
256 | pagemap entry code out into a function with the wrong return type. | |
257 | Pagemap entries are 64 bits on all systems and unsigned long is only 32 | |
258 | bits on 32-bit systems. | |
259 | ||
260 | Signed-off-by: Matt Mackall <mpm@selenic.com> | |
261 | Reported-by: Doug Graham <dgraham@nortel.com> | |
262 | Cc: Alexey Dobriyan <adobriyan@gmail.com> | |
263 | Cc: Dave Hansen <dave@linux.vnet.ibm.com> | |
264 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
265 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
266 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
267 | ||
268 | --- | |
269 | fs/proc/task_mmu.c | 4 ++-- | |
270 | 1 file changed, 2 insertions(+), 2 deletions(-) | |
271 | ||
272 | --- a/fs/proc/task_mmu.c | |
273 | +++ b/fs/proc/task_mmu.c | |
274 | @@ -563,9 +563,9 @@ static u64 swap_pte_to_pagemap_entry(pte | |
275 | return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); | |
276 | } | |
277 | ||
278 | -static unsigned long pte_to_pagemap_entry(pte_t pte) | |
279 | +static u64 pte_to_pagemap_entry(pte_t pte) | |
280 | { | |
281 | - unsigned long pme = 0; | |
282 | + u64 pme = 0; | |
283 | if (is_swap_pte(pte)) | |
284 | pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte)) | |
285 | | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; | |
286 | rom ae060e0b7bc071bd73dd5319b93c3344d9e10212 Mon Sep 17 00:00:00 2001 | |
287 | From: Manfred Spraul <manfred@colorfullife.com> | |
288 | To: torvalds@linux-foundation.org | |
289 | Cc: linux-kernel@vger.kernel.org | |
290 | Cc: cebbert@redhat.com | |
291 | Cc: airlied@gmail.com | |
292 | Cc: akpm@linux-foundation.org | |
293 | Bcc: manfred@colorfullife.com | |
294 | Date: Wed, 10 Dec 2008 18:17:06 +0100 | |
295 | Subject: [PATCH] lib/idr.c: Fix bug introduced by RCU fix | |
296 | ||
297 | The last patch to lib/idr.c caused a bug if idr_get_new_above() was | |
298 | called on an empty idr: | |
299 | Usually, nodes stay on the same layer. New layers are added to the top | |
300 | of the tree. | |
301 | The exception is idr_get_new_above() on an empty tree: In this case, | |
302 | the new root node is first added on layer 0, then moved upwards. | |
303 | p->layer was not updated. | |
304 | ||
305 | As usual: You shall never rely on the source code comments, they | |
306 | will only mislead you. | |
307 | ||
308 | Signed-off-by: Manfred Spraul <manfred@colorfullife.com> | |
309 | --- | |
310 | lib/idr.c | 8 +++++++- | |
311 | 1 files changed, 7 insertions(+), 1 deletions(-) | |
312 | ||
313 | diff --git a/lib/idr.c b/lib/idr.c | |
314 | index 7a785a0..1c4f928 100644 | |
315 | --- a/lib/idr.c | |
316 | +++ b/lib/idr.c | |
317 | @@ -220,8 +220,14 @@ build_up: | |
318 | */ | |
319 | while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { | |
320 | layers++; | |
321 | - if (!p->count) | |
322 | + if (!p->count) { | |
323 | + /* special case: if the tree is currently empty, | |
324 | + * then we grow the tree by moving the top node | |
325 | + * upwards. | |
326 | + */ | |
327 | + p->layer++; | |
328 | continue; | |
329 | + } | |
330 | if (!(new = get_from_free_list(idp))) { | |
331 | /* | |
332 | * The allocation failed. If we built part of | |
333 | -- | |
334 | 1.5.6.5 | |
335 |