]> Pileus Git - ~andy/linux/blobdiff - drivers/iio/kfifo_buf.c
iio:accel:kxsd9 fix missing mutex unlock
[~andy/linux] / drivers / iio / kfifo_buf.c
index 538d4616e48ff33a5b5ad84e5dcc0ac7b6e390f4..95c6fc81c2c78f2d57598995753e342302c3cb3a 100644 (file)
@@ -12,6 +12,7 @@
 struct iio_kfifo {
        struct iio_buffer buffer;
        struct kfifo kf;
+       struct mutex user_lock;
        int update_needed;
 };
 
@@ -32,13 +33,18 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
        int ret = 0;
        struct iio_kfifo *buf = iio_to_kfifo(r);
 
-       if (!buf->update_needed)
-               goto error_ret;
-       kfifo_free(&buf->kf);
-       ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
+       mutex_lock(&buf->user_lock);
+       if (buf->update_needed) {
+               kfifo_free(&buf->kf);
+               ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
                                   buf->buffer.length);
+               buf->update_needed = false;
+       } else {
+               kfifo_reset_out(&buf->kf);
+       }
        r->stufftoread = false;
-error_ret:
+       mutex_unlock(&buf->user_lock);
+
        return ret;
 }
 
@@ -114,12 +120,13 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
        int ret, copied;
        struct iio_kfifo *kf = iio_to_kfifo(r);
 
-       if (n < r->bytes_per_datum || r->bytes_per_datum == 0)
-               return -EINVAL;
+       if (mutex_lock_interruptible(&kf->user_lock))
+               return -ERESTARTSYS;
 
-       ret = kfifo_to_user(&kf->kf, buf, n, &copied);
-       if (ret < 0)
-               return ret;
+       if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf))
+               ret = -EINVAL;
+       else
+               ret = kfifo_to_user(&kf->kf, buf, n, &copied);
 
        if (kfifo_is_empty(&kf->kf))
                r->stufftoread = false;
@@ -127,9 +134,22 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
        if (!kfifo_is_empty(&kf->kf))
                r->stufftoread = true;
 
+       mutex_unlock(&kf->user_lock);
+       if (ret < 0)
+               return ret;
+
        return copied;
 }
 
+static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
+{
+       struct iio_kfifo *kf = iio_to_kfifo(buffer);
+
+       mutex_destroy(&kf->user_lock);
+       kfifo_free(&kf->kf);
+       kfree(kf);
+}
+
 static const struct iio_buffer_access_funcs kfifo_access_funcs = {
        .store_to = &iio_store_to_kfifo,
        .read_first_n = &iio_read_first_n_kfifo,
@@ -138,6 +158,7 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = {
        .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
        .get_length = &iio_get_length_kfifo,
        .set_length = &iio_set_length_kfifo,
+       .release = &iio_kfifo_buffer_release,
 };
 
 struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
@@ -152,13 +173,14 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
        kf->buffer.attrs = &iio_kfifo_attribute_group;
        kf->buffer.access = &kfifo_access_funcs;
        kf->buffer.length = 2;
+       mutex_init(&kf->user_lock);
        return &kf->buffer;
 }
 EXPORT_SYMBOL(iio_kfifo_allocate);
 
 void iio_kfifo_free(struct iio_buffer *r)
 {
-       kfree(iio_to_kfifo(r));
+       iio_buffer_put(r);
 }
 EXPORT_SYMBOL(iio_kfifo_free);