When kmod_dup_request_announce() announces the completion of a request_module() call to duplicate waiters, it queues a work item to invoke kmod_dup_request_complete(), and only that function calls complete_all(). This adds an arbitrary delay that is unnecessary and provides little benefit. Call complete_all() directly from kmod_dup_request_announce() instead.
Unified · Split
| @@ -48,7 +48,6 @@ struct kmod_dup_req { · 47 unmodified lines | |||
| 48 | struct list_head list; | 48 | struct list_head list; |
| 49 | char name[MODULE_NAME_LEN]; | 49 | char name[MODULE_NAME_LEN]; |
| 50 | struct completion first_req_done; | 50 | struct completion first_req_done; |
| 51 | struct work_struct complete_work; | ||
| 52 | struct delayed_work delete_work; | 51 | struct delayed_work delete_work; |
| 53 | int dup_ret; | 52 | int dup_ret; |
| 54 | }; | 53 | }; |
| @@ -93,29 +92,6 @@ static void kmod_dup_request_delete(struct work_struct *work) · 38 unmodified lines | |||
| 93 | kfree(kmod_req); | 92 | kfree(kmod_req); |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | static void kmod_dup_request_complete(struct work_struct *work) | ||
| 97 | { | ||
| 98 | struct kmod_dup_req *kmod_req; | ||
| 99 | |||
| 100 | kmod_req = container_of(work, struct kmod_dup_req, complete_work); | ||
| 101 | |||
| 102 | /* | ||
| 103 | * This will ensure that the kernel will let all the waiters get | ||
| 104 | * informed its time to check the return value. It's time to | ||
| 105 | * go home. | ||
| 106 | */ | ||
| 107 | complete_all(&kmod_req->first_req_done); | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Now that we have allowed prior request_module() calls to go on | ||
| 111 | * with life, let's schedule deleting this entry. We don't have | ||
| 112 | * to do it right away, but we *eventually* want to do it so to not | ||
| 113 | * let this linger forever as this is just a boot optimization for | ||
| 114 | * possible abuses of vmalloc() incurred by finit_module() thrashing. | ||
| 115 | */ | ||
| 116 | queue_delayed_work(system_dfl_wq, &kmod_req->delete_work, 60 * HZ); | ||
| 117 | } | ||
| 118 | |||
| 119 | bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret) | 95 | bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret) |
| 120 | { | 96 | { |
| 121 | struct kmod_dup_req *kmod_req, *new_kmod_req; | 97 | struct kmod_dup_req *kmod_req, *new_kmod_req; |
| @@ -130,7 +106,6 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret) · 8 unmodified lines | |||
| 130 | return false; | 106 | return false; |
| 131 | 107 | ||
| 132 | strscpy(new_kmod_req->name, module_name); | 108 | strscpy(new_kmod_req->name, module_name); |
| 133 | INIT_WORK(&new_kmod_req->complete_work, kmod_dup_request_complete); | ||
| 134 | INIT_DELAYED_WORK(&new_kmod_req->delete_work, kmod_dup_request_delete); | 109 | INIT_DELAYED_WORK(&new_kmod_req->delete_work, kmod_dup_request_delete); |
| 135 | init_completion(&new_kmod_req->first_req_done); | 110 | init_completion(&new_kmod_req->first_req_done); |
| 136 | 111 | ||
| @@ -230,17 +205,17 @@ void kmod_dup_request_announce(char *module_name, int ret) · 93 unmodified lines | |||
| 230 | 205 | ||
| 231 | kmod_req->dup_ret = ret; | 206 | kmod_req->dup_ret = ret; |
| 232 | 207 | ||
| 208 | /* Inform all duplicate waiters to check the return value. */ | ||
| 209 | complete_all(&kmod_req->first_req_done); | ||
| 210 | |||
| 233 | /* | 211 | /* |
| 234 | * If we complete() here we may allow duplicate threads | 212 | * Now that we have allowed prior request_module() calls to go on |
| 235 | * to continue before the first one that submitted the | 213 | * with life, let's schedule deleting this entry. We don't have |
| 236 | * request. We're in no rush also, given that each and | 214 | * to do it right away, but we *eventually* want to do it so to not |
| 237 | * every bounce back to userspace is slow we avoid that | 215 | * let this linger forever as this is just a boot optimization for |
| 238 | * with a slight delay here. So queueue up the completion | 216 | * possible abuses of vmalloc() incurred by finit_module() thrashing. |
| 239 | * and let duplicates suffer, just wait a tad bit longer. | ||
| 240 | * There is no rush. But we also don't want to hold the | ||
| 241 | * caller up forever or introduce any boot delays. | ||
| 242 | */ | 217 | */ |
| 243 | queue_work(system_dfl_wq, &kmod_req->complete_work); | 218 | queue_delayed_work(system_dfl_wq, &kmod_req->delete_work, 60 * HZ); |
| 244 | 219 | ||
| 245 | out: | 220 | out: |
| 246 | mutex_unlock(&kmod_dup_mutex); | 221 | mutex_unlock(&kmod_dup_mutex); |