Contents of /trunk/kernel-alx/patches-4.9/0126-4.9.27-all-fixes.patch
Parent Directory | Revision Log
Revision 2956 -
(show annotations)
(download)
Mon Jul 24 12:03:46 2017 UTC (7 years, 2 months ago) by niro
File size: 29538 byte(s)
Mon Jul 24 12:03:46 2017 UTC (7 years, 2 months ago) by niro
File size: 29538 byte(s)
-added patches-4.9
1 | diff --git a/Makefile b/Makefile |
2 | index c09679c1a70d..35d6b4e76264 100644 |
3 | --- a/Makefile |
4 | +++ b/Makefile |
5 | @@ -1,6 +1,6 @@ |
6 | VERSION = 4 |
7 | PATCHLEVEL = 9 |
8 | -SUBLEVEL = 26 |
9 | +SUBLEVEL = 27 |
10 | EXTRAVERSION = |
11 | NAME = Roaring Lionus |
12 | |
13 | diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c |
14 | index 3a9149cf0110..d0ac2d56520f 100644 |
15 | --- a/drivers/char/tpm/tpm-interface.c |
16 | +++ b/drivers/char/tpm/tpm-interface.c |
17 | @@ -489,8 +489,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) |
18 | int tpm_get_timeouts(struct tpm_chip *chip) |
19 | { |
20 | struct tpm_cmd_t tpm_cmd; |
21 | - unsigned long new_timeout[4]; |
22 | - unsigned long old_timeout[4]; |
23 | + unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4]; |
24 | struct duration_t *duration_cap; |
25 | ssize_t rc; |
26 | |
27 | @@ -542,11 +541,15 @@ int tpm_get_timeouts(struct tpm_chip *chip) |
28 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) |
29 | return -EINVAL; |
30 | |
31 | - old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); |
32 | - old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); |
33 | - old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); |
34 | - old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); |
35 | - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); |
36 | + timeout_old[0] = jiffies_to_usecs(chip->timeout_a); |
37 | + timeout_old[1] = jiffies_to_usecs(chip->timeout_b); |
38 | + timeout_old[2] = jiffies_to_usecs(chip->timeout_c); |
39 | + timeout_old[3] = jiffies_to_usecs(chip->timeout_d); |
40 | + timeout_chip[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); |
41 | + timeout_chip[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); |
42 | + timeout_chip[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); |
43 | + timeout_chip[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); |
44 | + memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff)); |
45 | |
46 | /* |
47 | * Provide ability for vendor overrides of timeout values in case |
48 | @@ -554,16 +557,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) |
49 | */ |
50 | if (chip->ops->update_timeouts != NULL) |
51 | chip->timeout_adjusted = |
52 | - chip->ops->update_timeouts(chip, new_timeout); |
53 | + chip->ops->update_timeouts(chip, timeout_eff); |
54 | |
55 | if (!chip->timeout_adjusted) { |
56 | - /* Don't overwrite default if value is 0 */ |
57 | - if (new_timeout[0] != 0 && new_timeout[0] < 1000) { |
58 | - int i; |
59 | + /* Restore default if chip reported 0 */ |
60 | + int i; |
61 | |
62 | + for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) { |
63 | + if (timeout_eff[i]) |
64 | + continue; |
65 | + |
66 | + timeout_eff[i] = timeout_old[i]; |
67 | + chip->timeout_adjusted = true; |
68 | + } |
69 | + |
70 | + if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) { |
71 | /* timeouts in msec rather usec */ |
72 | - for (i = 0; i != ARRAY_SIZE(new_timeout); i++) |
73 | - new_timeout[i] *= 1000; |
74 | + for (i = 0; i != ARRAY_SIZE(timeout_eff); i++) |
75 | + timeout_eff[i] *= 1000; |
76 | chip->timeout_adjusted = true; |
77 | } |
78 | } |
79 | @@ -572,16 +583,16 @@ int tpm_get_timeouts(struct tpm_chip *chip) |
80 | if (chip->timeout_adjusted) { |
81 | dev_info(&chip->dev, |
82 | HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", |
83 | - old_timeout[0], new_timeout[0], |
84 | - old_timeout[1], new_timeout[1], |
85 | - old_timeout[2], new_timeout[2], |
86 | - old_timeout[3], new_timeout[3]); |
87 | + timeout_chip[0], timeout_eff[0], |
88 | + timeout_chip[1], timeout_eff[1], |
89 | + timeout_chip[2], timeout_eff[2], |
90 | + timeout_chip[3], timeout_eff[3]); |
91 | } |
92 | |
93 | - chip->timeout_a = usecs_to_jiffies(new_timeout[0]); |
94 | - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); |
95 | - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); |
96 | - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); |
97 | + chip->timeout_a = usecs_to_jiffies(timeout_eff[0]); |
98 | + chip->timeout_b = usecs_to_jiffies(timeout_eff[1]); |
99 | + chip->timeout_c = usecs_to_jiffies(timeout_eff[2]); |
100 | + chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); |
101 | |
102 | duration: |
103 | tpm_cmd.header.in = tpm_getcap_header; |
104 | diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c |
105 | index 43146162c122..b99c1df48156 100644 |
106 | --- a/drivers/hwmon/it87.c |
107 | +++ b/drivers/hwmon/it87.c |
108 | @@ -3115,7 +3115,7 @@ static int __init sm_it87_init(void) |
109 | { |
110 | int sioaddr[2] = { REG_2E, REG_4E }; |
111 | struct it87_sio_data sio_data; |
112 | - unsigned short isa_address; |
113 | + unsigned short isa_address[2]; |
114 | bool found = false; |
115 | int i, err; |
116 | |
117 | @@ -3125,15 +3125,29 @@ static int __init sm_it87_init(void) |
118 | |
119 | for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { |
120 | memset(&sio_data, 0, sizeof(struct it87_sio_data)); |
121 | - isa_address = 0; |
122 | - err = it87_find(sioaddr[i], &isa_address, &sio_data); |
123 | - if (err || isa_address == 0) |
124 | + isa_address[i] = 0; |
125 | + err = it87_find(sioaddr[i], &isa_address[i], &sio_data); |
126 | + if (err || isa_address[i] == 0) |
127 | continue; |
128 | + /* |
129 | + * Don't register second chip if its ISA address matches |
130 | + * the first chip's ISA address. |
131 | + */ |
132 | + if (i && isa_address[i] == isa_address[0]) |
133 | + break; |
134 | |
135 | - err = it87_device_add(i, isa_address, &sio_data); |
136 | + err = it87_device_add(i, isa_address[i], &sio_data); |
137 | if (err) |
138 | goto exit_dev_unregister; |
139 | + |
140 | found = true; |
141 | + |
142 | + /* |
143 | + * IT8705F may respond on both SIO addresses. |
144 | + * Stop probing after finding one. |
145 | + */ |
146 | + if (sio_data.type == it87) |
147 | + break; |
148 | } |
149 | |
150 | if (!found) { |
151 | diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c |
152 | index 966eb4b61aed..a68c650aad11 100644 |
153 | --- a/drivers/md/dm-ioctl.c |
154 | +++ b/drivers/md/dm-ioctl.c |
155 | @@ -1847,7 +1847,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
156 | if (r) |
157 | goto out; |
158 | |
159 | - param->data_size = sizeof(*param); |
160 | + param->data_size = offsetof(struct dm_ioctl, data); |
161 | r = fn(param, input_param_size); |
162 | |
163 | if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) && |
164 | diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c |
165 | index 3f218f5cf29b..c5ab1b0037fc 100644 |
166 | --- a/drivers/scsi/storvsc_drv.c |
167 | +++ b/drivers/scsi/storvsc_drv.c |
168 | @@ -400,8 +400,6 @@ MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels") |
169 | */ |
170 | static int storvsc_timeout = 180; |
171 | |
172 | -static int msft_blist_flags = BLIST_TRY_VPD_PAGES; |
173 | - |
174 | #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) |
175 | static struct scsi_transport_template *fc_transport_template; |
176 | #endif |
177 | @@ -1283,6 +1281,22 @@ static int storvsc_do_io(struct hv_device *device, |
178 | return ret; |
179 | } |
180 | |
181 | +static int storvsc_device_alloc(struct scsi_device *sdevice) |
182 | +{ |
183 | + /* |
184 | + * Set blist flag to permit the reading of the VPD pages even when |
185 | + * the target may claim SPC-2 compliance. MSFT targets currently |
186 | + * claim SPC-2 compliance while they implement post SPC-2 features. |
187 | + * With this flag we can correctly handle WRITE_SAME_16 issues. |
188 | + * |
189 | + * Hypervisor reports SCSI_UNKNOWN type for DVD ROM device but |
190 | + * still supports REPORT LUN. |
191 | + */ |
192 | + sdevice->sdev_bflags = BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES; |
193 | + |
194 | + return 0; |
195 | +} |
196 | + |
197 | static int storvsc_device_configure(struct scsi_device *sdevice) |
198 | { |
199 | |
200 | @@ -1298,14 +1312,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice) |
201 | sdevice->no_write_same = 1; |
202 | |
203 | /* |
204 | - * Add blist flags to permit the reading of the VPD pages even when |
205 | - * the target may claim SPC-2 compliance. MSFT targets currently |
206 | - * claim SPC-2 compliance while they implement post SPC-2 features. |
207 | - * With this patch we can correctly handle WRITE_SAME_16 issues. |
208 | - */ |
209 | - sdevice->sdev_bflags |= msft_blist_flags; |
210 | - |
211 | - /* |
212 | * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 |
213 | * if the device is a MSFT virtual device. If the host is |
214 | * WIN10 or newer, allow write_same. |
215 | @@ -1569,6 +1575,7 @@ static struct scsi_host_template scsi_driver = { |
216 | .eh_host_reset_handler = storvsc_host_reset_handler, |
217 | .proc_name = "storvsc_host", |
218 | .eh_timed_out = storvsc_eh_timed_out, |
219 | + .slave_alloc = storvsc_device_alloc, |
220 | .slave_configure = storvsc_device_configure, |
221 | .cmd_per_lun = 255, |
222 | .this_id = -1, |
223 | diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c |
224 | index 6e3e63675e56..22d32d295c5b 100644 |
225 | --- a/drivers/tty/serial/8250/8250_pci.c |
226 | +++ b/drivers/tty/serial/8250/8250_pci.c |
227 | @@ -5621,17 +5621,15 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev) |
228 | static void serial8250_io_resume(struct pci_dev *dev) |
229 | { |
230 | struct serial_private *priv = pci_get_drvdata(dev); |
231 | - const struct pciserial_board *board; |
232 | + struct serial_private *new; |
233 | |
234 | if (!priv) |
235 | return; |
236 | |
237 | - board = priv->board; |
238 | - kfree(priv); |
239 | - priv = pciserial_init_ports(dev, board); |
240 | - |
241 | - if (!IS_ERR(priv)) { |
242 | - pci_set_drvdata(dev, priv); |
243 | + new = pciserial_init_ports(dev, priv->board); |
244 | + if (!IS_ERR(new)) { |
245 | + pci_set_drvdata(dev, new); |
246 | + kfree(priv); |
247 | } |
248 | } |
249 | |
250 | diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c |
251 | index 1e643c718917..18dc18f8af2c 100644 |
252 | --- a/fs/ceph/addr.c |
253 | +++ b/fs/ceph/addr.c |
254 | @@ -315,7 +315,32 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) |
255 | struct page **pages; |
256 | pgoff_t next_index; |
257 | int nr_pages = 0; |
258 | - int ret; |
259 | + int got = 0; |
260 | + int ret = 0; |
261 | + |
262 | + if (!current->journal_info) { |
263 | + /* caller of readpages does not hold buffer and read caps |
264 | + * (fadvise, madvise and readahead cases) */ |
265 | + int want = CEPH_CAP_FILE_CACHE; |
266 | + ret = ceph_try_get_caps(ci, CEPH_CAP_FILE_RD, want, &got); |
267 | + if (ret < 0) { |
268 | + dout("start_read %p, error getting cap\n", inode); |
269 | + } else if (!(got & want)) { |
270 | + dout("start_read %p, no cache cap\n", inode); |
271 | + ret = 0; |
272 | + } |
273 | + if (ret <= 0) { |
274 | + if (got) |
275 | + ceph_put_cap_refs(ci, got); |
276 | + while (!list_empty(page_list)) { |
277 | + page = list_entry(page_list->prev, |
278 | + struct page, lru); |
279 | + list_del(&page->lru); |
280 | + put_page(page); |
281 | + } |
282 | + return ret; |
283 | + } |
284 | + } |
285 | |
286 | off = (u64) page_offset(page); |
287 | |
288 | @@ -338,15 +363,18 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) |
289 | CEPH_OSD_FLAG_READ, NULL, |
290 | ci->i_truncate_seq, ci->i_truncate_size, |
291 | false); |
292 | - if (IS_ERR(req)) |
293 | - return PTR_ERR(req); |
294 | + if (IS_ERR(req)) { |
295 | + ret = PTR_ERR(req); |
296 | + goto out; |
297 | + } |
298 | |
299 | /* build page vector */ |
300 | nr_pages = calc_pages_for(0, len); |
301 | pages = kmalloc(sizeof(*pages) * nr_pages, GFP_KERNEL); |
302 | - ret = -ENOMEM; |
303 | - if (!pages) |
304 | - goto out; |
305 | + if (!pages) { |
306 | + ret = -ENOMEM; |
307 | + goto out_put; |
308 | + } |
309 | for (i = 0; i < nr_pages; ++i) { |
310 | page = list_entry(page_list->prev, struct page, lru); |
311 | BUG_ON(PageLocked(page)); |
312 | @@ -379,6 +407,12 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) |
313 | if (ret < 0) |
314 | goto out_pages; |
315 | ceph_osdc_put_request(req); |
316 | + |
317 | + /* After adding locked pages to page cache, the inode holds cache cap. |
318 | + * So we can drop our cap refs. */ |
319 | + if (got) |
320 | + ceph_put_cap_refs(ci, got); |
321 | + |
322 | return nr_pages; |
323 | |
324 | out_pages: |
325 | @@ -387,8 +421,11 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) |
326 | unlock_page(pages[i]); |
327 | } |
328 | ceph_put_page_vector(pages, nr_pages, false); |
329 | -out: |
330 | +out_put: |
331 | ceph_osdc_put_request(req); |
332 | +out: |
333 | + if (got) |
334 | + ceph_put_cap_refs(ci, got); |
335 | return ret; |
336 | } |
337 | |
338 | @@ -425,7 +462,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, |
339 | rc = start_read(inode, page_list, max); |
340 | if (rc < 0) |
341 | goto out; |
342 | - BUG_ON(rc == 0); |
343 | } |
344 | out: |
345 | ceph_fscache_readpages_cancel(inode, page_list); |
346 | @@ -1372,9 +1408,11 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
347 | inode, off, (size_t)PAGE_SIZE, ceph_cap_string(got)); |
348 | |
349 | if ((got & (CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO)) || |
350 | - ci->i_inline_version == CEPH_INLINE_NONE) |
351 | + ci->i_inline_version == CEPH_INLINE_NONE) { |
352 | + current->journal_info = vma->vm_file; |
353 | ret = filemap_fault(vma, vmf); |
354 | - else |
355 | + current->journal_info = NULL; |
356 | + } else |
357 | ret = -EAGAIN; |
358 | |
359 | dout("filemap_fault %p %llu~%zd dropping cap refs on %s ret %d\n", |
360 | diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c |
361 | index f3f21105b860..03951f90ecf7 100644 |
362 | --- a/fs/ceph/caps.c |
363 | +++ b/fs/ceph/caps.c |
364 | @@ -2479,6 +2479,27 @@ static void check_max_size(struct inode *inode, loff_t endoff) |
365 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); |
366 | } |
367 | |
368 | +int ceph_try_get_caps(struct ceph_inode_info *ci, int need, int want, int *got) |
369 | +{ |
370 | + int ret, err = 0; |
371 | + |
372 | + BUG_ON(need & ~CEPH_CAP_FILE_RD); |
373 | + BUG_ON(want & ~(CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)); |
374 | + ret = ceph_pool_perm_check(ci, need); |
375 | + if (ret < 0) |
376 | + return ret; |
377 | + |
378 | + ret = try_get_cap_refs(ci, need, want, 0, true, got, &err); |
379 | + if (ret) { |
380 | + if (err == -EAGAIN) { |
381 | + ret = 0; |
382 | + } else if (err < 0) { |
383 | + ret = err; |
384 | + } |
385 | + } |
386 | + return ret; |
387 | +} |
388 | + |
389 | /* |
390 | * Wait for caps, and take cap references. If we can't get a WR cap |
391 | * due to a small max_size, make sure we check_max_size (and possibly |
392 | diff --git a/fs/ceph/file.c b/fs/ceph/file.c |
393 | index f995e3528a33..ca3f630db90f 100644 |
394 | --- a/fs/ceph/file.c |
395 | +++ b/fs/ceph/file.c |
396 | @@ -1249,8 +1249,9 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) |
397 | dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", |
398 | inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, |
399 | ceph_cap_string(got)); |
400 | - |
401 | + current->journal_info = filp; |
402 | ret = generic_file_read_iter(iocb, to); |
403 | + current->journal_info = NULL; |
404 | } |
405 | dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n", |
406 | inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); |
407 | diff --git a/fs/ceph/super.h b/fs/ceph/super.h |
408 | index 3e3fa9163059..622d5dd9f616 100644 |
409 | --- a/fs/ceph/super.h |
410 | +++ b/fs/ceph/super.h |
411 | @@ -905,6 +905,8 @@ extern int ceph_encode_dentry_release(void **p, struct dentry *dn, |
412 | |
413 | extern int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, |
414 | loff_t endoff, int *got, struct page **pinned_page); |
415 | +extern int ceph_try_get_caps(struct ceph_inode_info *ci, |
416 | + int need, int want, int *got); |
417 | |
418 | /* for counting open files by mode */ |
419 | extern void __ceph_get_fmode(struct ceph_inode_info *ci, int mode); |
420 | diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h |
421 | index 94661cf77ae8..b3830f7ab260 100644 |
422 | --- a/fs/cifs/cifsglob.h |
423 | +++ b/fs/cifs/cifsglob.h |
424 | @@ -241,6 +241,7 @@ struct smb_version_operations { |
425 | /* verify the message */ |
426 | int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); |
427 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); |
428 | + int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *); |
429 | void (*downgrade_oplock)(struct TCP_Server_Info *, |
430 | struct cifsInodeInfo *, bool); |
431 | /* process transaction2 response */ |
432 | @@ -1314,12 +1315,19 @@ struct mid_q_entry { |
433 | void *callback_data; /* general purpose pointer for callback */ |
434 | void *resp_buf; /* pointer to received SMB header */ |
435 | int mid_state; /* wish this were enum but can not pass to wait_event */ |
436 | + unsigned int mid_flags; |
437 | __le16 command; /* smb command code */ |
438 | bool large_buf:1; /* if valid response, is pointer to large buf */ |
439 | bool multiRsp:1; /* multiple trans2 responses for one request */ |
440 | bool multiEnd:1; /* both received */ |
441 | }; |
442 | |
443 | +struct close_cancelled_open { |
444 | + struct cifs_fid fid; |
445 | + struct cifs_tcon *tcon; |
446 | + struct work_struct work; |
447 | +}; |
448 | + |
449 | /* Make code in transport.c a little cleaner by moving |
450 | update of optional stats into function below */ |
451 | #ifdef CONFIG_CIFS_STATS2 |
452 | @@ -1451,6 +1459,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, |
453 | #define MID_RESPONSE_MALFORMED 0x10 |
454 | #define MID_SHUTDOWN 0x20 |
455 | |
456 | +/* Flags */ |
457 | +#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ |
458 | + |
459 | /* Types of response buffer returned from SendReceive2 */ |
460 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ |
461 | #define CIFS_SMALL_BUFFER 1 |
462 | diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c |
463 | index e3fed9249a04..586fdac05ec2 100644 |
464 | --- a/fs/cifs/cifssmb.c |
465 | +++ b/fs/cifs/cifssmb.c |
466 | @@ -1423,6 +1423,8 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) |
467 | |
468 | length = discard_remaining_data(server); |
469 | dequeue_mid(mid, rdata->result); |
470 | + mid->resp_buf = server->smallbuf; |
471 | + server->smallbuf = NULL; |
472 | return length; |
473 | } |
474 | |
475 | @@ -1534,6 +1536,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) |
476 | return cifs_readv_discard(server, mid); |
477 | |
478 | dequeue_mid(mid, false); |
479 | + mid->resp_buf = server->smallbuf; |
480 | + server->smallbuf = NULL; |
481 | return length; |
482 | } |
483 | |
484 | diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c |
485 | index 893be0722643..b8015de88e8c 100644 |
486 | --- a/fs/cifs/connect.c |
487 | +++ b/fs/cifs/connect.c |
488 | @@ -882,10 +882,19 @@ cifs_demultiplex_thread(void *p) |
489 | |
490 | server->lstrp = jiffies; |
491 | if (mid_entry != NULL) { |
492 | + if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && |
493 | + mid_entry->mid_state == MID_RESPONSE_RECEIVED && |
494 | + server->ops->handle_cancelled_mid) |
495 | + server->ops->handle_cancelled_mid( |
496 | + mid_entry->resp_buf, |
497 | + server); |
498 | + |
499 | if (!mid_entry->multiRsp || mid_entry->multiEnd) |
500 | mid_entry->callback(mid_entry); |
501 | - } else if (!server->ops->is_oplock_break || |
502 | - !server->ops->is_oplock_break(buf, server)) { |
503 | + } else if (server->ops->is_oplock_break && |
504 | + server->ops->is_oplock_break(buf, server)) { |
505 | + cifs_dbg(FYI, "Received oplock break\n"); |
506 | + } else { |
507 | cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", |
508 | atomic_read(&midCount)); |
509 | cifs_dump_mem("Received Data is: ", buf, |
510 | diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c |
511 | index 3d383489b9cf..97307808ae42 100644 |
512 | --- a/fs/cifs/smb2misc.c |
513 | +++ b/fs/cifs/smb2misc.c |
514 | @@ -654,3 +654,47 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) |
515 | cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); |
516 | return false; |
517 | } |
518 | + |
519 | +void |
520 | +smb2_cancelled_close_fid(struct work_struct *work) |
521 | +{ |
522 | + struct close_cancelled_open *cancelled = container_of(work, |
523 | + struct close_cancelled_open, work); |
524 | + |
525 | + cifs_dbg(VFS, "Close unmatched open\n"); |
526 | + |
527 | + SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, |
528 | + cancelled->fid.volatile_fid); |
529 | + cifs_put_tcon(cancelled->tcon); |
530 | + kfree(cancelled); |
531 | +} |
532 | + |
533 | +int |
534 | +smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) |
535 | +{ |
536 | + struct smb2_hdr *hdr = (struct smb2_hdr *)buffer; |
537 | + struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; |
538 | + struct cifs_tcon *tcon; |
539 | + struct close_cancelled_open *cancelled; |
540 | + |
541 | + if (hdr->Command != SMB2_CREATE || hdr->Status != STATUS_SUCCESS) |
542 | + return 0; |
543 | + |
544 | + cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL); |
545 | + if (!cancelled) |
546 | + return -ENOMEM; |
547 | + |
548 | + tcon = smb2_find_smb_tcon(server, hdr->SessionId, hdr->TreeId); |
549 | + if (!tcon) { |
550 | + kfree(cancelled); |
551 | + return -ENOENT; |
552 | + } |
553 | + |
554 | + cancelled->fid.persistent_fid = rsp->PersistentFileId; |
555 | + cancelled->fid.volatile_fid = rsp->VolatileFileId; |
556 | + cancelled->tcon = tcon; |
557 | + INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); |
558 | + queue_work(cifsiod_wq, &cancelled->work); |
559 | + |
560 | + return 0; |
561 | +} |
562 | diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c |
563 | index 5d456ebb3813..007abf7195af 100644 |
564 | --- a/fs/cifs/smb2ops.c |
565 | +++ b/fs/cifs/smb2ops.c |
566 | @@ -1565,6 +1565,7 @@ struct smb_version_operations smb20_operations = { |
567 | .clear_stats = smb2_clear_stats, |
568 | .print_stats = smb2_print_stats, |
569 | .is_oplock_break = smb2_is_valid_oplock_break, |
570 | + .handle_cancelled_mid = smb2_handle_cancelled_mid, |
571 | .downgrade_oplock = smb2_downgrade_oplock, |
572 | .need_neg = smb2_need_neg, |
573 | .negotiate = smb2_negotiate, |
574 | @@ -1645,6 +1646,7 @@ struct smb_version_operations smb21_operations = { |
575 | .clear_stats = smb2_clear_stats, |
576 | .print_stats = smb2_print_stats, |
577 | .is_oplock_break = smb2_is_valid_oplock_break, |
578 | + .handle_cancelled_mid = smb2_handle_cancelled_mid, |
579 | .downgrade_oplock = smb2_downgrade_oplock, |
580 | .need_neg = smb2_need_neg, |
581 | .negotiate = smb2_negotiate, |
582 | @@ -1727,6 +1729,7 @@ struct smb_version_operations smb30_operations = { |
583 | .print_stats = smb2_print_stats, |
584 | .dump_share_caps = smb2_dump_share_caps, |
585 | .is_oplock_break = smb2_is_valid_oplock_break, |
586 | + .handle_cancelled_mid = smb2_handle_cancelled_mid, |
587 | .downgrade_oplock = smb2_downgrade_oplock, |
588 | .need_neg = smb2_need_neg, |
589 | .negotiate = smb2_negotiate, |
590 | @@ -1815,6 +1818,7 @@ struct smb_version_operations smb311_operations = { |
591 | .print_stats = smb2_print_stats, |
592 | .dump_share_caps = smb2_dump_share_caps, |
593 | .is_oplock_break = smb2_is_valid_oplock_break, |
594 | + .handle_cancelled_mid = smb2_handle_cancelled_mid, |
595 | .downgrade_oplock = smb2_downgrade_oplock, |
596 | .need_neg = smb2_need_neg, |
597 | .negotiate = smb2_negotiate, |
598 | diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h |
599 | index f2d511a6971b..04ef6e914597 100644 |
600 | --- a/fs/cifs/smb2proto.h |
601 | +++ b/fs/cifs/smb2proto.h |
602 | @@ -48,6 +48,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, |
603 | struct smb_rqst *rqst); |
604 | extern struct mid_q_entry *smb2_setup_async_request( |
605 | struct TCP_Server_Info *server, struct smb_rqst *rqst); |
606 | +extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, |
607 | + __u64 ses_id); |
608 | +extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, |
609 | + __u64 ses_id, __u32 tid); |
610 | extern int smb2_calc_signature(struct smb_rqst *rqst, |
611 | struct TCP_Server_Info *server); |
612 | extern int smb3_calc_signature(struct smb_rqst *rqst, |
613 | @@ -158,6 +162,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, |
614 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, |
615 | const u64 persistent_fid, const u64 volatile_fid, |
616 | const __u8 oplock_level); |
617 | +extern int smb2_handle_cancelled_mid(char *buffer, |
618 | + struct TCP_Server_Info *server); |
619 | +void smb2_cancelled_close_fid(struct work_struct *work); |
620 | extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, |
621 | u64 persistent_file_id, u64 volatile_file_id, |
622 | struct kstatfs *FSData); |
623 | diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c |
624 | index bc9a7b634643..390b0d0198f8 100644 |
625 | --- a/fs/cifs/smb2transport.c |
626 | +++ b/fs/cifs/smb2transport.c |
627 | @@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) |
628 | } |
629 | |
630 | static struct cifs_ses * |
631 | -smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) |
632 | +smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) |
633 | { |
634 | struct cifs_ses *ses; |
635 | |
636 | - spin_lock(&cifs_tcp_ses_lock); |
637 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
638 | - if (ses->Suid != smb2hdr->SessionId) |
639 | + if (ses->Suid != ses_id) |
640 | continue; |
641 | - spin_unlock(&cifs_tcp_ses_lock); |
642 | return ses; |
643 | } |
644 | + |
645 | + return NULL; |
646 | +} |
647 | + |
648 | +struct cifs_ses * |
649 | +smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) |
650 | +{ |
651 | + struct cifs_ses *ses; |
652 | + |
653 | + spin_lock(&cifs_tcp_ses_lock); |
654 | + ses = smb2_find_smb_ses_unlocked(server, ses_id); |
655 | spin_unlock(&cifs_tcp_ses_lock); |
656 | |
657 | + return ses; |
658 | +} |
659 | + |
660 | +static struct cifs_tcon * |
661 | +smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) |
662 | +{ |
663 | + struct cifs_tcon *tcon; |
664 | + |
665 | + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { |
666 | + if (tcon->tid != tid) |
667 | + continue; |
668 | + ++tcon->tc_count; |
669 | + return tcon; |
670 | + } |
671 | + |
672 | return NULL; |
673 | } |
674 | |
675 | +/* |
676 | + * Obtain tcon corresponding to the tid in the given |
677 | + * cifs_ses |
678 | + */ |
679 | + |
680 | +struct cifs_tcon * |
681 | +smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) |
682 | +{ |
683 | + struct cifs_ses *ses; |
684 | + struct cifs_tcon *tcon; |
685 | + |
686 | + spin_lock(&cifs_tcp_ses_lock); |
687 | + ses = smb2_find_smb_ses_unlocked(server, ses_id); |
688 | + if (!ses) { |
689 | + spin_unlock(&cifs_tcp_ses_lock); |
690 | + return NULL; |
691 | + } |
692 | + tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); |
693 | + spin_unlock(&cifs_tcp_ses_lock); |
694 | + |
695 | + return tcon; |
696 | +} |
697 | |
698 | int |
699 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
700 | @@ -142,7 +188,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
701 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
702 | struct cifs_ses *ses; |
703 | |
704 | - ses = smb2_find_smb_ses(smb2_pdu, server); |
705 | + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); |
706 | if (!ses) { |
707 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); |
708 | return 0; |
709 | @@ -359,7 +405,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
710 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
711 | struct cifs_ses *ses; |
712 | |
713 | - ses = smb2_find_smb_ses(smb2_pdu, server); |
714 | + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); |
715 | if (!ses) { |
716 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); |
717 | return 0; |
718 | diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c |
719 | index 206a597b2293..cc26d4138d70 100644 |
720 | --- a/fs/cifs/transport.c |
721 | +++ b/fs/cifs/transport.c |
722 | @@ -727,9 +727,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, |
723 | |
724 | rc = wait_for_response(ses->server, midQ); |
725 | if (rc != 0) { |
726 | + cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); |
727 | send_cancel(ses->server, buf, midQ); |
728 | spin_lock(&GlobalMid_Lock); |
729 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { |
730 | + midQ->mid_flags |= MID_WAIT_CANCELLED; |
731 | midQ->callback = DeleteMidQEntry; |
732 | spin_unlock(&GlobalMid_Lock); |
733 | cifs_small_buf_release(buf); |
734 | diff --git a/fs/timerfd.c b/fs/timerfd.c |
735 | index 9ae4abb4110b..ab8dd1538381 100644 |
736 | --- a/fs/timerfd.c |
737 | +++ b/fs/timerfd.c |
738 | @@ -40,6 +40,7 @@ struct timerfd_ctx { |
739 | short unsigned settime_flags; /* to show in fdinfo */ |
740 | struct rcu_head rcu; |
741 | struct list_head clist; |
742 | + spinlock_t cancel_lock; |
743 | bool might_cancel; |
744 | }; |
745 | |
746 | @@ -112,7 +113,7 @@ void timerfd_clock_was_set(void) |
747 | rcu_read_unlock(); |
748 | } |
749 | |
750 | -static void timerfd_remove_cancel(struct timerfd_ctx *ctx) |
751 | +static void __timerfd_remove_cancel(struct timerfd_ctx *ctx) |
752 | { |
753 | if (ctx->might_cancel) { |
754 | ctx->might_cancel = false; |
755 | @@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx) |
756 | } |
757 | } |
758 | |
759 | +static void timerfd_remove_cancel(struct timerfd_ctx *ctx) |
760 | +{ |
761 | + spin_lock(&ctx->cancel_lock); |
762 | + __timerfd_remove_cancel(ctx); |
763 | + spin_unlock(&ctx->cancel_lock); |
764 | +} |
765 | + |
766 | static bool timerfd_canceled(struct timerfd_ctx *ctx) |
767 | { |
768 | if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) |
769 | @@ -132,6 +140,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx) |
770 | |
771 | static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) |
772 | { |
773 | + spin_lock(&ctx->cancel_lock); |
774 | if ((ctx->clockid == CLOCK_REALTIME || |
775 | ctx->clockid == CLOCK_REALTIME_ALARM) && |
776 | (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) { |
777 | @@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) |
778 | list_add_rcu(&ctx->clist, &cancel_list); |
779 | spin_unlock(&cancel_lock); |
780 | } |
781 | - } else if (ctx->might_cancel) { |
782 | - timerfd_remove_cancel(ctx); |
783 | + } else { |
784 | + __timerfd_remove_cancel(ctx); |
785 | } |
786 | + spin_unlock(&ctx->cancel_lock); |
787 | } |
788 | |
789 | static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) |
790 | @@ -400,6 +410,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) |
791 | return -ENOMEM; |
792 | |
793 | init_waitqueue_head(&ctx->wqh); |
794 | + spin_lock_init(&ctx->cancel_lock); |
795 | ctx->clockid = clockid; |
796 | |
797 | if (isalarm(ctx)) |
798 | diff --git a/kernel/cpu.c b/kernel/cpu.c |
799 | index 217fd2e7f435..99c6c568bc55 100644 |
800 | --- a/kernel/cpu.c |
801 | +++ b/kernel/cpu.c |
802 | @@ -1441,14 +1441,12 @@ static void cpuhp_store_callbacks(enum cpuhp_state state, |
803 | /* (Un)Install the callbacks for further cpu hotplug operations */ |
804 | struct cpuhp_step *sp; |
805 | |
806 | - mutex_lock(&cpuhp_state_mutex); |
807 | sp = cpuhp_get_step(state); |
808 | sp->startup.single = startup; |
809 | sp->teardown.single = teardown; |
810 | sp->name = name; |
811 | sp->multi_instance = multi_instance; |
812 | INIT_HLIST_HEAD(&sp->list); |
813 | - mutex_unlock(&cpuhp_state_mutex); |
814 | } |
815 | |
816 | static void *cpuhp_get_teardown_cb(enum cpuhp_state state) |
817 | @@ -1518,16 +1516,13 @@ static int cpuhp_reserve_state(enum cpuhp_state state) |
818 | { |
819 | enum cpuhp_state i; |
820 | |
821 | - mutex_lock(&cpuhp_state_mutex); |
822 | for (i = CPUHP_AP_ONLINE_DYN; i <= CPUHP_AP_ONLINE_DYN_END; i++) { |
823 | if (cpuhp_ap_states[i].name) |
824 | continue; |
825 | |
826 | cpuhp_ap_states[i].name = "Reserved"; |
827 | - mutex_unlock(&cpuhp_state_mutex); |
828 | return i; |
829 | } |
830 | - mutex_unlock(&cpuhp_state_mutex); |
831 | WARN(1, "No more dynamic states available for CPU hotplug\n"); |
832 | return -ENOSPC; |
833 | } |
834 | @@ -1544,6 +1539,7 @@ int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, |
835 | return -EINVAL; |
836 | |
837 | get_online_cpus(); |
838 | + mutex_lock(&cpuhp_state_mutex); |
839 | |
840 | if (!invoke || !sp->startup.multi) |
841 | goto add_node; |
842 | @@ -1568,11 +1564,10 @@ int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, |
843 | } |
844 | add_node: |
845 | ret = 0; |
846 | - mutex_lock(&cpuhp_state_mutex); |
847 | hlist_add_head(node, &sp->list); |
848 | - mutex_unlock(&cpuhp_state_mutex); |
849 | |
850 | err: |
851 | + mutex_unlock(&cpuhp_state_mutex); |
852 | put_online_cpus(); |
853 | return ret; |
854 | } |
855 | @@ -1601,6 +1596,7 @@ int __cpuhp_setup_state(enum cpuhp_state state, |
856 | return -EINVAL; |
857 | |
858 | get_online_cpus(); |
859 | + mutex_lock(&cpuhp_state_mutex); |
860 | |
861 | /* currently assignments for the ONLINE state are possible */ |
862 | if (state == CPUHP_AP_ONLINE_DYN) { |
863 | @@ -1636,6 +1632,8 @@ int __cpuhp_setup_state(enum cpuhp_state state, |
864 | } |
865 | } |
866 | out: |
867 | + mutex_unlock(&cpuhp_state_mutex); |
868 | + |
869 | put_online_cpus(); |
870 | if (!ret && dyn_state) |
871 | return state; |
872 | @@ -1655,6 +1653,8 @@ int __cpuhp_state_remove_instance(enum cpuhp_state state, |
873 | return -EINVAL; |
874 | |
875 | get_online_cpus(); |
876 | + mutex_lock(&cpuhp_state_mutex); |
877 | + |
878 | if (!invoke || !cpuhp_get_teardown_cb(state)) |
879 | goto remove; |
880 | /* |
881 | @@ -1671,7 +1671,6 @@ int __cpuhp_state_remove_instance(enum cpuhp_state state, |
882 | } |
883 | |
884 | remove: |
885 | - mutex_lock(&cpuhp_state_mutex); |
886 | hlist_del(node); |
887 | mutex_unlock(&cpuhp_state_mutex); |
888 | put_online_cpus(); |
889 | @@ -1696,6 +1695,7 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) |
890 | BUG_ON(cpuhp_cb_check(state)); |
891 | |
892 | get_online_cpus(); |
893 | + mutex_lock(&cpuhp_state_mutex); |
894 | |
895 | if (sp->multi_instance) { |
896 | WARN(!hlist_empty(&sp->list), |
897 | @@ -1721,6 +1721,7 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) |
898 | } |
899 | remove: |
900 | cpuhp_store_callbacks(state, NULL, NULL, NULL, false); |
901 | + mutex_unlock(&cpuhp_state_mutex); |
902 | put_online_cpus(); |
903 | } |
904 | EXPORT_SYMBOL(__cpuhp_remove_state); |