Skip to content

Commit

Permalink
mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lars-Peter Clausen authored and Samuel Ortiz committed May 27, 2010
1 parent 0aeee5d commit 6438a69
Showing 1 changed file with 15 additions and 24 deletions.
39 changes: 15 additions & 24 deletions drivers/mfd/pcf50633-adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -109,39 +109,30 @@ 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);
}

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);

Expand Down

0 comments on commit 6438a69

Please sign in to comment.