]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - drivers/char/tpm/tpm.c
Merge branch 'tpmdd-next-v3.6' of git://github.com/shpedoikal/linux into for-linus
[can-eth-gw-linux.git] / drivers / char / tpm / tpm.c
index b429f1ea1b976c9e0d5e267e8fe03ce47df89470..93211df52aab7cef9ad9615e42a7b9d36dea4d6f 100644 (file)
@@ -1182,17 +1182,20 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
                  size_t size, loff_t *off)
 {
        struct tpm_chip *chip = file->private_data;
-       size_t in_size = size, out_size;
+       size_t in_size = size;
+       ssize_t out_size;
 
        /* cannot perform a write until the read has cleared
-          either via tpm_read or a user_read_timer timeout */
-       while (atomic_read(&chip->data_pending) != 0)
-               msleep(TPM_TIMEOUT);
-
-       mutex_lock(&chip->buffer_mutex);
+          either via tpm_read or a user_read_timer timeout.
+          This also prevents splitted buffered writes from blocking here.
+       */
+       if (atomic_read(&chip->data_pending) != 0)
+               return -EBUSY;
 
        if (in_size > TPM_BUFSIZE)
-               in_size = TPM_BUFSIZE;
+               return -E2BIG;
+
+       mutex_lock(&chip->buffer_mutex);
 
        if (copy_from_user
            (chip->data_buffer, (void __user *) buf, in_size)) {
@@ -1202,6 +1205,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
 
        /* atomic tpm command send and result receive */
        out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
+       if (out_size < 0) {
+               mutex_unlock(&chip->buffer_mutex);
+               return out_size;
+       }
 
        atomic_set(&chip->data_pending, out_size);
        mutex_unlock(&chip->buffer_mutex);