diff options
author | Cornelia Huck <cohuck@redhat.com> | 2019-01-31 07:53:14 -0500 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2019-03-06 11:19:57 -0500 |
commit | ab7a2375fb8e83f8744c34442f476fa5a9df5e35 (patch) | |
tree | 58698720fc0a7a79f4fdefaae195aabf57a83dba | |
parent | 971bedca26e037ee961e090c84c2640563836d3e (diff) |
virtio: hint if callbacks surprisingly might sleep
A virtio transport is free to implement some of the callbacks in
virtio_config_ops in a matter that they cannot be called from
atomic context (e.g. virtio-ccw, which maps a lot of the callbacks
to channel I/O, which is an inherently asynchronous mechanism).
This can be very surprising for developers using the much more
common virtio-pci transport, just to find out that things break
when used on s390.
The documentation for virtio_config_ops now contains a comment
explaining this, but it makes sense to add a might_sleep() annotation
to various wrapper functions in the virtio core to avoid surprises
later.
Note that annotations are NOT added to two classes of calls:
- direct calls from device drivers (all current callers should be
fine, however)
- calls which clearly won't be made from atomic context (such as
those ultimately coming in via the driver core)
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | drivers/virtio/virtio.c | 2 | ||||
-rw-r--r-- | include/linux/virtio_config.h | 13 |
2 files changed, 15 insertions, 0 deletions
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 59e36ef4920f..98b30f54342c 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c | |||
@@ -161,6 +161,7 @@ EXPORT_SYMBOL_GPL(virtio_config_enable); | |||
161 | 161 | ||
162 | void virtio_add_status(struct virtio_device *dev, unsigned int status) | 162 | void virtio_add_status(struct virtio_device *dev, unsigned int status) |
163 | { | 163 | { |
164 | might_sleep(); | ||
164 | dev->config->set_status(dev, dev->config->get_status(dev) | status); | 165 | dev->config->set_status(dev, dev->config->get_status(dev) | status); |
165 | } | 166 | } |
166 | EXPORT_SYMBOL_GPL(virtio_add_status); | 167 | EXPORT_SYMBOL_GPL(virtio_add_status); |
@@ -170,6 +171,7 @@ int virtio_finalize_features(struct virtio_device *dev) | |||
170 | int ret = dev->config->finalize_features(dev); | 171 | int ret = dev->config->finalize_features(dev); |
171 | unsigned status; | 172 | unsigned status; |
172 | 173 | ||
174 | might_sleep(); | ||
173 | if (ret) | 175 | if (ret) |
174 | return ret; | 176 | return ret; |
175 | 177 | ||
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 987b6491b946..bb4cc4910750 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h | |||
@@ -290,6 +290,7 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) | |||
290 | /* Config space accessors. */ | 290 | /* Config space accessors. */ |
291 | #define virtio_cread(vdev, structname, member, ptr) \ | 291 | #define virtio_cread(vdev, structname, member, ptr) \ |
292 | do { \ | 292 | do { \ |
293 | might_sleep(); \ | ||
293 | /* Must match the member's type, and be integer */ \ | 294 | /* Must match the member's type, and be integer */ \ |
294 | if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ | 295 | if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ |
295 | (*ptr) = 1; \ | 296 | (*ptr) = 1; \ |
@@ -319,6 +320,7 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) | |||
319 | /* Config space accessors. */ | 320 | /* Config space accessors. */ |
320 | #define virtio_cwrite(vdev, structname, member, ptr) \ | 321 | #define virtio_cwrite(vdev, structname, member, ptr) \ |
321 | do { \ | 322 | do { \ |
323 | might_sleep(); \ | ||
322 | /* Must match the member's type, and be integer */ \ | 324 | /* Must match the member's type, and be integer */ \ |
323 | if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ | 325 | if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ |
324 | BUG_ON((*ptr) == 1); \ | 326 | BUG_ON((*ptr) == 1); \ |
@@ -358,6 +360,7 @@ static inline void __virtio_cread_many(struct virtio_device *vdev, | |||
358 | vdev->config->generation(vdev) : 0; | 360 | vdev->config->generation(vdev) : 0; |
359 | int i; | 361 | int i; |
360 | 362 | ||
363 | might_sleep(); | ||
361 | do { | 364 | do { |
362 | old = gen; | 365 | old = gen; |
363 | 366 | ||
@@ -380,6 +383,8 @@ static inline void virtio_cread_bytes(struct virtio_device *vdev, | |||
380 | static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) | 383 | static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) |
381 | { | 384 | { |
382 | u8 ret; | 385 | u8 ret; |
386 | |||
387 | might_sleep(); | ||
383 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); | 388 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); |
384 | return ret; | 389 | return ret; |
385 | } | 390 | } |
@@ -387,6 +392,7 @@ static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) | |||
387 | static inline void virtio_cwrite8(struct virtio_device *vdev, | 392 | static inline void virtio_cwrite8(struct virtio_device *vdev, |
388 | unsigned int offset, u8 val) | 393 | unsigned int offset, u8 val) |
389 | { | 394 | { |
395 | might_sleep(); | ||
390 | vdev->config->set(vdev, offset, &val, sizeof(val)); | 396 | vdev->config->set(vdev, offset, &val, sizeof(val)); |
391 | } | 397 | } |
392 | 398 | ||
@@ -394,6 +400,8 @@ static inline u16 virtio_cread16(struct virtio_device *vdev, | |||
394 | unsigned int offset) | 400 | unsigned int offset) |
395 | { | 401 | { |
396 | u16 ret; | 402 | u16 ret; |
403 | |||
404 | might_sleep(); | ||
397 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); | 405 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); |
398 | return virtio16_to_cpu(vdev, (__force __virtio16)ret); | 406 | return virtio16_to_cpu(vdev, (__force __virtio16)ret); |
399 | } | 407 | } |
@@ -401,6 +409,7 @@ static inline u16 virtio_cread16(struct virtio_device *vdev, | |||
401 | static inline void virtio_cwrite16(struct virtio_device *vdev, | 409 | static inline void virtio_cwrite16(struct virtio_device *vdev, |
402 | unsigned int offset, u16 val) | 410 | unsigned int offset, u16 val) |
403 | { | 411 | { |
412 | might_sleep(); | ||
404 | val = (__force u16)cpu_to_virtio16(vdev, val); | 413 | val = (__force u16)cpu_to_virtio16(vdev, val); |
405 | vdev->config->set(vdev, offset, &val, sizeof(val)); | 414 | vdev->config->set(vdev, offset, &val, sizeof(val)); |
406 | } | 415 | } |
@@ -409,6 +418,8 @@ static inline u32 virtio_cread32(struct virtio_device *vdev, | |||
409 | unsigned int offset) | 418 | unsigned int offset) |
410 | { | 419 | { |
411 | u32 ret; | 420 | u32 ret; |
421 | |||
422 | might_sleep(); | ||
412 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); | 423 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); |
413 | return virtio32_to_cpu(vdev, (__force __virtio32)ret); | 424 | return virtio32_to_cpu(vdev, (__force __virtio32)ret); |
414 | } | 425 | } |
@@ -416,6 +427,7 @@ static inline u32 virtio_cread32(struct virtio_device *vdev, | |||
416 | static inline void virtio_cwrite32(struct virtio_device *vdev, | 427 | static inline void virtio_cwrite32(struct virtio_device *vdev, |
417 | unsigned int offset, u32 val) | 428 | unsigned int offset, u32 val) |
418 | { | 429 | { |
430 | might_sleep(); | ||
419 | val = (__force u32)cpu_to_virtio32(vdev, val); | 431 | val = (__force u32)cpu_to_virtio32(vdev, val); |
420 | vdev->config->set(vdev, offset, &val, sizeof(val)); | 432 | vdev->config->set(vdev, offset, &val, sizeof(val)); |
421 | } | 433 | } |
@@ -431,6 +443,7 @@ static inline u64 virtio_cread64(struct virtio_device *vdev, | |||
431 | static inline void virtio_cwrite64(struct virtio_device *vdev, | 443 | static inline void virtio_cwrite64(struct virtio_device *vdev, |
432 | unsigned int offset, u64 val) | 444 | unsigned int offset, u64 val) |
433 | { | 445 | { |
446 | might_sleep(); | ||
434 | val = (__force u64)cpu_to_virtio64(vdev, val); | 447 | val = (__force u64)cpu_to_virtio64(vdev, val); |
435 | vdev->config->set(vdev, offset, &val, sizeof(val)); | 448 | vdev->config->set(vdev, offset, &val, sizeof(val)); |
436 | } | 449 | } |