diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2010-05-12 04:10:54 +0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2010-05-28 03:37:49 +0400 |
commit | 6438a694b670cd188c2fd2f75e0cd6b0ae21bea9 (patch) | |
tree | dd53c02d505042d8ff6cedbd48f7f84a49d8878f /drivers/mfd/pcf50633-adc.c | |
parent | 0aeee5d4f6aa9bd28373907727937b7935d0434c (diff) | |
download | linux-6438a694b670cd188c2fd2f75e0cd6b0ae21bea9.tar.xz |
mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read
Currently it's not guaranteed that request struct is not already freed when
reading from it. Fix this by moving synced request related fields from the
pcf50633_adc_request struct to its own struct and store it on the functions
stack.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/pcf50633-adc.c')
-rw-r--r-- | drivers/mfd/pcf50633-adc.c | 39 |
1 files changed, 15 insertions, 24 deletions
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index fe8f922f6654..aed0d2a9b032 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -30,13 +30,13 @@ struct pcf50633_adc_request { int mux; int avg; - int result; void (*callback)(struct pcf50633 *, void *, int); void *callback_param; +}; - /* Used in case of sync requests */ +struct pcf50633_adc_sync_request { + int result; struct completion completion; - }; #define PCF50633_MAX_ADC_FIFO_DEPTH 8 @@ -109,10 +109,10 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) return 0; } -static void -pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) +static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, + int result) { - struct pcf50633_adc_request *req = param; + struct pcf50633_adc_sync_request *req = param; req->result = result; complete(&req->completion); @@ -120,28 +120,19 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) { - struct pcf50633_adc_request *req; - int err; + struct pcf50633_adc_sync_request req; + int ret; - /* req is freed when the result is ready, in interrupt handler */ - req = kzalloc(sizeof(*req), GFP_KERNEL); - if (!req) - return -ENOMEM; - - req->mux = mux; - req->avg = avg; - req->callback = pcf50633_adc_sync_read_callback; - req->callback_param = req; + init_completion(&req.completion); - init_completion(&req->completion); - err = adc_enqueue_request(pcf, req); - if (err) - return err; + ret = pcf50633_adc_async_read(pcf, mux, avg, + pcf50633_adc_sync_read_callback, &req); + if (ret) + return ret; - wait_for_completion(&req->completion); + wait_for_completion(&req.completion); - /* FIXME by this time req might be already freed */ - return req->result; + return req.result; } EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); |