Annotation of /trunk/kernel-alx/patches-4.9/0126-4.9.27-all-fixes.patch
Parent Directory | Revision Log
Revision 2956 -
(hide 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 | niro | 2956 | 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); |