@@ -887,8 +887,34 @@ read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)
887
887
return status ;
888
888
}
889
889
890
- static int
891
- read_u32_from_xdr_buf (struct xdr_buf * buf , int base , u32 * obj )
890
+ /* obj is assumed to point to allocated memory of size at least len: */
891
+ int
892
+ write_bytes_to_xdr_buf (struct xdr_buf * buf , int base , void * obj , int len )
893
+ {
894
+ struct xdr_buf subbuf ;
895
+ int this_len ;
896
+ int status ;
897
+
898
+ status = xdr_buf_subsegment (buf , & subbuf , base , len );
899
+ if (status )
900
+ goto out ;
901
+ this_len = min (len , (int )subbuf .head [0 ].iov_len );
902
+ memcpy (subbuf .head [0 ].iov_base , obj , this_len );
903
+ len -= this_len ;
904
+ obj += this_len ;
905
+ this_len = min (len , (int )subbuf .page_len );
906
+ if (this_len )
907
+ _copy_to_pages (subbuf .pages , subbuf .page_base , obj , this_len );
908
+ len -= this_len ;
909
+ obj += this_len ;
910
+ this_len = min (len , (int )subbuf .tail [0 ].iov_len );
911
+ memcpy (subbuf .tail [0 ].iov_base , obj , this_len );
912
+ out :
913
+ return status ;
914
+ }
915
+
916
+ int
917
+ xdr_decode_word (struct xdr_buf * buf , int base , u32 * obj )
892
918
{
893
919
u32 raw ;
894
920
int status ;
@@ -900,6 +926,14 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
900
926
return 0 ;
901
927
}
902
928
929
+ int
930
+ xdr_encode_word (struct xdr_buf * buf , int base , u32 obj )
931
+ {
932
+ u32 raw = htonl (obj );
933
+
934
+ return write_bytes_to_xdr_buf (buf , base , & raw , sizeof (obj ));
935
+ }
936
+
903
937
/* If the netobj starting offset bytes from the start of xdr_buf is contained
904
938
* entirely in the head or the tail, set object to point to it; otherwise
905
939
* try to find space for it at the end of the tail, copy it there, and
@@ -910,7 +944,7 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset)
910
944
u32 tail_offset = buf -> head [0 ].iov_len + buf -> page_len ;
911
945
u32 obj_end_offset ;
912
946
913
- if (read_u32_from_xdr_buf (buf , offset , & obj -> len ))
947
+ if (xdr_decode_word (buf , offset , & obj -> len ))
914
948
goto out ;
915
949
obj_end_offset = offset + 4 + obj -> len ;
916
950
@@ -943,3 +977,219 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset)
943
977
out :
944
978
return -1 ;
945
979
}
980
+
981
+ /* Returns 0 on success, or else a negative error code. */
982
+ static int
983
+ xdr_xcode_array2 (struct xdr_buf * buf , unsigned int base ,
984
+ struct xdr_array2_desc * desc , int encode )
985
+ {
986
+ char * elem = NULL , * c ;
987
+ unsigned int copied = 0 , todo , avail_here ;
988
+ struct page * * ppages = NULL ;
989
+ int err ;
990
+
991
+ if (encode ) {
992
+ if (xdr_encode_word (buf , base , desc -> array_len ) != 0 )
993
+ return - EINVAL ;
994
+ } else {
995
+ if (xdr_decode_word (buf , base , & desc -> array_len ) != 0 ||
996
+ (unsigned long ) base + 4 + desc -> array_len *
997
+ desc -> elem_size > buf -> len )
998
+ return - EINVAL ;
999
+ }
1000
+ base += 4 ;
1001
+
1002
+ if (!desc -> xcode )
1003
+ return 0 ;
1004
+
1005
+ todo = desc -> array_len * desc -> elem_size ;
1006
+
1007
+ /* process head */
1008
+ if (todo && base < buf -> head -> iov_len ) {
1009
+ c = buf -> head -> iov_base + base ;
1010
+ avail_here = min_t (unsigned int , todo ,
1011
+ buf -> head -> iov_len - base );
1012
+ todo -= avail_here ;
1013
+
1014
+ while (avail_here >= desc -> elem_size ) {
1015
+ err = desc -> xcode (desc , c );
1016
+ if (err )
1017
+ goto out ;
1018
+ c += desc -> elem_size ;
1019
+ avail_here -= desc -> elem_size ;
1020
+ }
1021
+ if (avail_here ) {
1022
+ if (!elem ) {
1023
+ elem = kmalloc (desc -> elem_size , GFP_KERNEL );
1024
+ err = - ENOMEM ;
1025
+ if (!elem )
1026
+ goto out ;
1027
+ }
1028
+ if (encode ) {
1029
+ err = desc -> xcode (desc , elem );
1030
+ if (err )
1031
+ goto out ;
1032
+ memcpy (c , elem , avail_here );
1033
+ } else
1034
+ memcpy (elem , c , avail_here );
1035
+ copied = avail_here ;
1036
+ }
1037
+ base = buf -> head -> iov_len ; /* align to start of pages */
1038
+ }
1039
+
1040
+ /* process pages array */
1041
+ base -= buf -> head -> iov_len ;
1042
+ if (todo && base < buf -> page_len ) {
1043
+ unsigned int avail_page ;
1044
+
1045
+ avail_here = min (todo , buf -> page_len - base );
1046
+ todo -= avail_here ;
1047
+
1048
+ base += buf -> page_base ;
1049
+ ppages = buf -> pages + (base >> PAGE_CACHE_SHIFT );
1050
+ base &= ~PAGE_CACHE_MASK ;
1051
+ avail_page = min_t (unsigned int , PAGE_CACHE_SIZE - base ,
1052
+ avail_here );
1053
+ c = kmap (* ppages ) + base ;
1054
+
1055
+ while (avail_here ) {
1056
+ avail_here -= avail_page ;
1057
+ if (copied || avail_page < desc -> elem_size ) {
1058
+ unsigned int l = min (avail_page ,
1059
+ desc -> elem_size - copied );
1060
+ if (!elem ) {
1061
+ elem = kmalloc (desc -> elem_size ,
1062
+ GFP_KERNEL );
1063
+ err = - ENOMEM ;
1064
+ if (!elem )
1065
+ goto out ;
1066
+ }
1067
+ if (encode ) {
1068
+ if (!copied ) {
1069
+ err = desc -> xcode (desc , elem );
1070
+ if (err )
1071
+ goto out ;
1072
+ }
1073
+ memcpy (c , elem + copied , l );
1074
+ copied += l ;
1075
+ if (copied == desc -> elem_size )
1076
+ copied = 0 ;
1077
+ } else {
1078
+ memcpy (elem + copied , c , l );
1079
+ copied += l ;
1080
+ if (copied == desc -> elem_size ) {
1081
+ err = desc -> xcode (desc , elem );
1082
+ if (err )
1083
+ goto out ;
1084
+ copied = 0 ;
1085
+ }
1086
+ }
1087
+ avail_page -= l ;
1088
+ c += l ;
1089
+ }
1090
+ while (avail_page >= desc -> elem_size ) {
1091
+ err = desc -> xcode (desc , c );
1092
+ if (err )
1093
+ goto out ;
1094
+ c += desc -> elem_size ;
1095
+ avail_page -= desc -> elem_size ;
1096
+ }
1097
+ if (avail_page ) {
1098
+ unsigned int l = min (avail_page ,
1099
+ desc -> elem_size - copied );
1100
+ if (!elem ) {
1101
+ elem = kmalloc (desc -> elem_size ,
1102
+ GFP_KERNEL );
1103
+ err = - ENOMEM ;
1104
+ if (!elem )
1105
+ goto out ;
1106
+ }
1107
+ if (encode ) {
1108
+ if (!copied ) {
1109
+ err = desc -> xcode (desc , elem );
1110
+ if (err )
1111
+ goto out ;
1112
+ }
1113
+ memcpy (c , elem + copied , l );
1114
+ copied += l ;
1115
+ if (copied == desc -> elem_size )
1116
+ copied = 0 ;
1117
+ } else {
1118
+ memcpy (elem + copied , c , l );
1119
+ copied += l ;
1120
+ if (copied == desc -> elem_size ) {
1121
+ err = desc -> xcode (desc , elem );
1122
+ if (err )
1123
+ goto out ;
1124
+ copied = 0 ;
1125
+ }
1126
+ }
1127
+ }
1128
+ if (avail_here ) {
1129
+ kunmap (* ppages );
1130
+ ppages ++ ;
1131
+ c = kmap (* ppages );
1132
+ }
1133
+
1134
+ avail_page = min (avail_here ,
1135
+ (unsigned int ) PAGE_CACHE_SIZE );
1136
+ }
1137
+ base = buf -> page_len ; /* align to start of tail */
1138
+ }
1139
+
1140
+ /* process tail */
1141
+ base -= buf -> page_len ;
1142
+ if (todo ) {
1143
+ c = buf -> tail -> iov_base + base ;
1144
+ if (copied ) {
1145
+ unsigned int l = desc -> elem_size - copied ;
1146
+
1147
+ if (encode )
1148
+ memcpy (c , elem + copied , l );
1149
+ else {
1150
+ memcpy (elem + copied , c , l );
1151
+ err = desc -> xcode (desc , elem );
1152
+ if (err )
1153
+ goto out ;
1154
+ }
1155
+ todo -= l ;
1156
+ c += l ;
1157
+ }
1158
+ while (todo ) {
1159
+ err = desc -> xcode (desc , c );
1160
+ if (err )
1161
+ goto out ;
1162
+ c += desc -> elem_size ;
1163
+ todo -= desc -> elem_size ;
1164
+ }
1165
+ }
1166
+ err = 0 ;
1167
+
1168
+ out :
1169
+ if (elem )
1170
+ kfree (elem );
1171
+ if (ppages )
1172
+ kunmap (* ppages );
1173
+ return err ;
1174
+ }
1175
+
1176
+ int
1177
+ xdr_decode_array2 (struct xdr_buf * buf , unsigned int base ,
1178
+ struct xdr_array2_desc * desc )
1179
+ {
1180
+ if (base >= buf -> len )
1181
+ return - EINVAL ;
1182
+
1183
+ return xdr_xcode_array2 (buf , base , desc , 0 );
1184
+ }
1185
+
1186
+ int
1187
+ xdr_encode_array2 (struct xdr_buf * buf , unsigned int base ,
1188
+ struct xdr_array2_desc * desc )
1189
+ {
1190
+ if ((unsigned long ) base + 4 + desc -> array_len * desc -> elem_size >
1191
+ buf -> head -> iov_len + buf -> page_len + buf -> tail -> iov_len )
1192
+ return - EINVAL ;
1193
+
1194
+ return xdr_xcode_array2 (buf , base , desc , 1 );
1195
+ }
0 commit comments