mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read
authorLars-Peter Clausen <lars@metafoo.de>
Wed, 12 May 2010 00:10:54 +0000 (02:10 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 27 May 2010 23:37:49 +0000 (01:37 +0200)
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>
drivers/mfd/pcf50633-adc.c

index fe8f922..aed0d2a 100644 (file)
 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);