diff options
author | Ming Lei <ming.lei@canonical.com> | 2012-10-09 00:01:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-22 11:37:17 -0400 |
commit | 253c9240ee09fd2a05d315ea44ac037a893d8981 (patch) | |
tree | 51694cfbb6d5f4c74e32eb19eb0ee6f5f48e0bb4 /drivers/base | |
parent | 373304fe10fc46e68815c7116709ad292695dfd1 (diff) |
firmware loader: fix one reqeust_firmware race
Several loading requests may be pending on one same
firmware buf, and this patch moves fw_map_pages_buf()
before complete_all(&fw_buf->completion) and let all
requests see the mapped 'buf->data' once the loading
is completed.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/firmware_class.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index d06a8d0534bf..f2882511a9c1 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -423,6 +423,18 @@ static void firmware_free_data(const struct firmware *fw) | |||
423 | #ifndef PAGE_KERNEL_RO | 423 | #ifndef PAGE_KERNEL_RO |
424 | #define PAGE_KERNEL_RO PAGE_KERNEL | 424 | #define PAGE_KERNEL_RO PAGE_KERNEL |
425 | #endif | 425 | #endif |
426 | |||
427 | /* one pages buffer should be mapped/unmapped only once */ | ||
428 | static int fw_map_pages_buf(struct firmware_buf *buf) | ||
429 | { | ||
430 | if (buf->data) | ||
431 | vunmap(buf->data); | ||
432 | buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); | ||
433 | if (!buf->data) | ||
434 | return -ENOMEM; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
426 | /** | 438 | /** |
427 | * firmware_loading_store - set value in the 'loading' control file | 439 | * firmware_loading_store - set value in the 'loading' control file |
428 | * @dev: device pointer | 440 | * @dev: device pointer |
@@ -467,6 +479,14 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
467 | if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { | 479 | if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { |
468 | set_bit(FW_STATUS_DONE, &fw_buf->status); | 480 | set_bit(FW_STATUS_DONE, &fw_buf->status); |
469 | clear_bit(FW_STATUS_LOADING, &fw_buf->status); | 481 | clear_bit(FW_STATUS_LOADING, &fw_buf->status); |
482 | |||
483 | /* | ||
484 | * Several loading requests may be pending on | ||
485 | * one same firmware buf, so let all requests | ||
486 | * see the mapped 'buf->data' once the loading | ||
487 | * is completed. | ||
488 | * */ | ||
489 | fw_map_pages_buf(fw_buf); | ||
470 | complete_all(&fw_buf->completion); | 490 | complete_all(&fw_buf->completion); |
471 | break; | 491 | break; |
472 | } | 492 | } |
@@ -670,15 +690,6 @@ exit: | |||
670 | return fw_priv; | 690 | return fw_priv; |
671 | } | 691 | } |
672 | 692 | ||
673 | /* one pages buffer is mapped/unmapped only once */ | ||
674 | static int fw_map_pages_buf(struct firmware_buf *buf) | ||
675 | { | ||
676 | buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); | ||
677 | if (!buf->data) | ||
678 | return -ENOMEM; | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | /* store the pages buffer info firmware from buf */ | 693 | /* store the pages buffer info firmware from buf */ |
683 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) | 694 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) |
684 | { | 695 | { |
@@ -884,9 +895,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | |||
884 | if (!retval && f_dev->parent) | 895 | if (!retval && f_dev->parent) |
885 | fw_add_devm_name(f_dev->parent, buf->fw_id); | 896 | fw_add_devm_name(f_dev->parent, buf->fw_id); |
886 | 897 | ||
887 | if (!retval) | ||
888 | retval = fw_map_pages_buf(buf); | ||
889 | |||
890 | /* | 898 | /* |
891 | * After caching firmware image is started, let it piggyback | 899 | * After caching firmware image is started, let it piggyback |
892 | * on request firmware. | 900 | * on request firmware. |