diff options
Diffstat (limited to 'kernel/relay.c')
-rw-r--r-- | kernel/relay.c | 175 |
1 files changed, 91 insertions, 84 deletions
diff --git a/kernel/relay.c b/kernel/relay.c index fefe2b2a7277..33345e73485c 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
@@ -866,131 +866,138 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf, | |||
866 | } | 866 | } |
867 | 867 | ||
868 | /** | 868 | /** |
869 | * relay_file_read - read file op for relay files | 869 | * subbuf_read_actor - read up to one subbuf's worth of data |
870 | * @filp: the file | ||
871 | * @buffer: the userspace buffer | ||
872 | * @count: number of bytes to read | ||
873 | * @ppos: position to read from | ||
874 | * | ||
875 | * Reads count bytes or the number of bytes available in the | ||
876 | * current sub-buffer being read, whichever is smaller. | ||
877 | */ | 870 | */ |
878 | static ssize_t relay_file_read(struct file *filp, | 871 | static int subbuf_read_actor(size_t read_start, |
879 | char __user *buffer, | 872 | struct rchan_buf *buf, |
880 | size_t count, | 873 | size_t avail, |
881 | loff_t *ppos) | 874 | read_descriptor_t *desc, |
875 | read_actor_t actor) | ||
882 | { | 876 | { |
883 | struct rchan_buf *buf = filp->private_data; | ||
884 | struct inode *inode = filp->f_dentry->d_inode; | ||
885 | size_t read_start, avail; | ||
886 | ssize_t ret = 0; | ||
887 | void *from; | 877 | void *from; |
888 | 878 | int ret = 0; | |
889 | mutex_lock(&inode->i_mutex); | ||
890 | if(!relay_file_read_avail(buf, *ppos)) | ||
891 | goto out; | ||
892 | |||
893 | read_start = relay_file_read_start_pos(*ppos, buf); | ||
894 | avail = relay_file_read_subbuf_avail(read_start, buf); | ||
895 | if (!avail) | ||
896 | goto out; | ||
897 | 879 | ||
898 | from = buf->start + read_start; | 880 | from = buf->start + read_start; |
899 | ret = count = min(count, avail); | 881 | ret = avail; |
900 | if (copy_to_user(buffer, from, count)) { | 882 | if (copy_to_user(desc->arg.data, from, avail)) { |
901 | ret = -EFAULT; | 883 | desc->error = -EFAULT; |
902 | goto out; | 884 | ret = 0; |
903 | } | 885 | } |
904 | relay_file_read_consume(buf, read_start, count); | 886 | desc->arg.data += ret; |
905 | *ppos = relay_file_read_end_pos(buf, read_start, count); | 887 | desc->written += ret; |
906 | out: | 888 | desc->count -= ret; |
907 | mutex_unlock(&inode->i_mutex); | 889 | |
908 | return ret; | 890 | return ret; |
909 | } | 891 | } |
910 | 892 | ||
911 | static ssize_t relay_file_sendsubbuf(struct file *filp, loff_t *ppos, | 893 | /** |
912 | size_t count, read_actor_t actor, | 894 | * subbuf_send_actor - send up to one subbuf's worth of data |
913 | void *target) | 895 | */ |
896 | static int subbuf_send_actor(size_t read_start, | ||
897 | struct rchan_buf *buf, | ||
898 | size_t avail, | ||
899 | read_descriptor_t *desc, | ||
900 | read_actor_t actor) | ||
914 | { | 901 | { |
915 | struct rchan_buf *buf = filp->private_data; | ||
916 | read_descriptor_t desc; | ||
917 | size_t read_start, avail; | ||
918 | unsigned long pidx, poff; | 902 | unsigned long pidx, poff; |
919 | unsigned int subbuf_pages; | 903 | unsigned int subbuf_pages; |
920 | ssize_t ret = 0; | 904 | int ret = 0; |
921 | |||
922 | if (!relay_file_read_avail(buf, *ppos)) | ||
923 | return 0; | ||
924 | |||
925 | read_start = relay_file_read_start_pos(*ppos, buf); | ||
926 | avail = relay_file_read_subbuf_avail(read_start, buf); | ||
927 | if (!avail) | ||
928 | return 0; | ||
929 | |||
930 | count = min(count, avail); | ||
931 | |||
932 | desc.written = 0; | ||
933 | desc.count = count; | ||
934 | desc.arg.data = target; | ||
935 | desc.error = 0; | ||
936 | 905 | ||
937 | subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT; | 906 | subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT; |
938 | pidx = (read_start / PAGE_SIZE) % subbuf_pages; | 907 | pidx = (read_start / PAGE_SIZE) % subbuf_pages; |
939 | poff = read_start & ~PAGE_MASK; | 908 | poff = read_start & ~PAGE_MASK; |
940 | while (count) { | 909 | while (avail) { |
941 | struct page *p = buf->page_array[pidx]; | 910 | struct page *p = buf->page_array[pidx]; |
942 | unsigned int len; | 911 | unsigned int len; |
943 | 912 | ||
944 | len = PAGE_SIZE - poff; | 913 | len = PAGE_SIZE - poff; |
945 | if (len > count) | 914 | if (len > avail) |
946 | len = count; | 915 | len = avail; |
947 | 916 | ||
948 | len = actor(&desc, p, poff, len); | 917 | len = actor(desc, p, poff, len); |
949 | 918 | if (desc->error) | |
950 | if (desc.error) { | ||
951 | if (!ret) | ||
952 | ret = desc.error; | ||
953 | break; | 919 | break; |
954 | } | ||
955 | 920 | ||
956 | count -= len; | 921 | avail -= len; |
957 | ret += len; | 922 | ret += len; |
958 | poff = 0; | 923 | poff = 0; |
959 | pidx = (pidx + 1) % subbuf_pages; | 924 | pidx = (pidx + 1) % subbuf_pages; |
960 | } | 925 | } |
961 | 926 | ||
962 | if (ret > 0) { | ||
963 | relay_file_read_consume(buf, read_start, ret); | ||
964 | *ppos = relay_file_read_end_pos(buf, read_start, ret); | ||
965 | } | ||
966 | |||
967 | return ret; | 927 | return ret; |
968 | } | 928 | } |
969 | 929 | ||
970 | static ssize_t relay_file_sendfile(struct file *filp, loff_t *ppos, | 930 | typedef int (*subbuf_actor_t) (size_t read_start, |
971 | size_t count, read_actor_t actor, | 931 | struct rchan_buf *buf, |
972 | void *target) | 932 | size_t avail, |
933 | read_descriptor_t *desc, | ||
934 | read_actor_t actor); | ||
935 | |||
936 | /** | ||
937 | * relay_file_read_subbufs - read count bytes, bridging subbuf boundaries | ||
938 | */ | ||
939 | static inline ssize_t relay_file_read_subbufs(struct file *filp, | ||
940 | loff_t *ppos, | ||
941 | size_t count, | ||
942 | subbuf_actor_t subbuf_actor, | ||
943 | read_actor_t actor, | ||
944 | void *target) | ||
973 | { | 945 | { |
974 | ssize_t sent = 0, ret = 0; | 946 | struct rchan_buf *buf = filp->private_data; |
947 | size_t read_start, avail; | ||
948 | read_descriptor_t desc; | ||
949 | int ret; | ||
975 | 950 | ||
976 | if (!count) | 951 | if (!count) |
977 | return 0; | 952 | return 0; |
978 | 953 | ||
979 | mutex_lock(&filp->f_dentry->d_inode->i_mutex); | 954 | desc.written = 0; |
955 | desc.count = count; | ||
956 | desc.arg.data = target; | ||
957 | desc.error = 0; | ||
980 | 958 | ||
959 | mutex_lock(&filp->f_dentry->d_inode->i_mutex); | ||
981 | do { | 960 | do { |
982 | ret = relay_file_sendsubbuf(filp, ppos, count, actor, target); | 961 | if (!relay_file_read_avail(buf, *ppos)) |
983 | if (ret < 0) { | 962 | break; |
984 | if (!sent) | 963 | |
985 | sent = ret; | 964 | read_start = relay_file_read_start_pos(*ppos, buf); |
965 | avail = relay_file_read_subbuf_avail(read_start, buf); | ||
966 | if (!avail) | ||
986 | break; | 967 | break; |
987 | } | ||
988 | count -= ret; | ||
989 | sent += ret; | ||
990 | } while (count && ret); | ||
991 | 968 | ||
969 | avail = min(desc.count, avail); | ||
970 | ret = subbuf_actor(read_start, buf, avail, &desc, actor); | ||
971 | if (desc.error < 0) | ||
972 | break; | ||
973 | |||
974 | if (ret) { | ||
975 | relay_file_read_consume(buf, read_start, ret); | ||
976 | *ppos = relay_file_read_end_pos(buf, read_start, ret); | ||
977 | } | ||
978 | } while (desc.count && ret); | ||
992 | mutex_unlock(&filp->f_dentry->d_inode->i_mutex); | 979 | mutex_unlock(&filp->f_dentry->d_inode->i_mutex); |
993 | return sent; | 980 | |
981 | return desc.written; | ||
982 | } | ||
983 | |||
984 | static ssize_t relay_file_read(struct file *filp, | ||
985 | char __user *buffer, | ||
986 | size_t count, | ||
987 | loff_t *ppos) | ||
988 | { | ||
989 | return relay_file_read_subbufs(filp, ppos, count, subbuf_read_actor, | ||
990 | NULL, buffer); | ||
991 | } | ||
992 | |||
993 | static ssize_t relay_file_sendfile(struct file *filp, | ||
994 | loff_t *ppos, | ||
995 | size_t count, | ||
996 | read_actor_t actor, | ||
997 | void *target) | ||
998 | { | ||
999 | return relay_file_read_subbufs(filp, ppos, count, subbuf_send_actor, | ||
1000 | actor, target); | ||
994 | } | 1001 | } |
995 | 1002 | ||
996 | struct file_operations relay_file_operations = { | 1003 | struct file_operations relay_file_operations = { |