diff options
author | Alexander Usyskin <alexander.usyskin@intel.com> | 2017-03-20 09:04:06 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-08 11:38:25 -0400 |
commit | 58cde1a64c5e140e6ba498aaa406e063957e35df (patch) | |
tree | 716a3eb5e6214680435fc3d7030e91eab5dcb447 /drivers/misc/mei/main.c | |
parent | dd04eecc41ae7cf139593b400e74defad62cec54 (diff) |
mei: implement fsync
When write() returns successfully, it is only assumed that a message
was successfully queued. Add fsync syscall implementation to help
user-space ensure that all data is written.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei/main.c')
-rw-r--r-- | drivers/misc/mei/main.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 9802c5930c10..e825f013e54e 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -586,6 +586,77 @@ out: | |||
586 | } | 586 | } |
587 | 587 | ||
588 | /** | 588 | /** |
589 | * mei_cl_is_write_queued - check if the client has pending writes. | ||
590 | * | ||
591 | * @cl: writing host client | ||
592 | * | ||
593 | * Return: true if client is writing, false otherwise. | ||
594 | */ | ||
595 | static bool mei_cl_is_write_queued(struct mei_cl *cl) | ||
596 | { | ||
597 | struct mei_device *dev = cl->dev; | ||
598 | struct mei_cl_cb *cb; | ||
599 | |||
600 | list_for_each_entry(cb, &dev->write_list, list) | ||
601 | if (cb->cl == cl) | ||
602 | return true; | ||
603 | list_for_each_entry(cb, &dev->write_waiting_list, list) | ||
604 | if (cb->cl == cl) | ||
605 | return true; | ||
606 | return false; | ||
607 | } | ||
608 | |||
609 | /** | ||
610 | * mei_fsync - the fsync handler | ||
611 | * | ||
612 | * @fp: pointer to file structure | ||
613 | * @start: unused | ||
614 | * @end: unused | ||
615 | * @datasync: unused | ||
616 | * | ||
617 | * Return: 0 on success, -ENODEV if client is not connected | ||
618 | */ | ||
619 | static int mei_fsync(struct file *fp, loff_t start, loff_t end, int datasync) | ||
620 | { | ||
621 | struct mei_cl *cl = fp->private_data; | ||
622 | struct mei_device *dev; | ||
623 | int rets; | ||
624 | |||
625 | if (WARN_ON(!cl || !cl->dev)) | ||
626 | return -ENODEV; | ||
627 | |||
628 | dev = cl->dev; | ||
629 | |||
630 | mutex_lock(&dev->device_lock); | ||
631 | |||
632 | if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) { | ||
633 | rets = -ENODEV; | ||
634 | goto out; | ||
635 | } | ||
636 | |||
637 | while (mei_cl_is_write_queued(cl)) { | ||
638 | mutex_unlock(&dev->device_lock); | ||
639 | rets = wait_event_interruptible(cl->tx_wait, | ||
640 | cl->writing_state == MEI_WRITE_COMPLETE || | ||
641 | !mei_cl_is_connected(cl)); | ||
642 | mutex_lock(&dev->device_lock); | ||
643 | if (rets) { | ||
644 | if (signal_pending(current)) | ||
645 | rets = -EINTR; | ||
646 | goto out; | ||
647 | } | ||
648 | if (!mei_cl_is_connected(cl)) { | ||
649 | rets = -ENODEV; | ||
650 | goto out; | ||
651 | } | ||
652 | } | ||
653 | rets = 0; | ||
654 | out: | ||
655 | mutex_unlock(&dev->device_lock); | ||
656 | return rets; | ||
657 | } | ||
658 | |||
659 | /** | ||
589 | * mei_fasync - asynchronous io support | 660 | * mei_fasync - asynchronous io support |
590 | * | 661 | * |
591 | * @fd: file descriptor | 662 | * @fd: file descriptor |
@@ -700,6 +771,7 @@ static const struct file_operations mei_fops = { | |||
700 | .release = mei_release, | 771 | .release = mei_release, |
701 | .write = mei_write, | 772 | .write = mei_write, |
702 | .poll = mei_poll, | 773 | .poll = mei_poll, |
774 | .fsync = mei_fsync, | ||
703 | .fasync = mei_fasync, | 775 | .fasync = mei_fasync, |
704 | .llseek = no_llseek | 776 | .llseek = no_llseek |
705 | }; | 777 | }; |