@@ -54,6 +54,39 @@ struct pvcalls_fedata {
54
54
struct semaphore socket_lock ;
55
55
};
56
56
57
+ struct pvcalls_ioworker {
58
+ struct work_struct register_work ;
59
+ struct workqueue_struct * wq ;
60
+ };
61
+
62
+ struct sock_mapping {
63
+ struct list_head list ;
64
+ struct pvcalls_fedata * fedata ;
65
+ struct socket * sock ;
66
+ uint64_t id ;
67
+ grant_ref_t ref ;
68
+ struct pvcalls_data_intf * ring ;
69
+ void * bytes ;
70
+ struct pvcalls_data data ;
71
+ uint32_t ring_order ;
72
+ int irq ;
73
+ atomic_t read ;
74
+ atomic_t write ;
75
+ atomic_t io ;
76
+ atomic_t release ;
77
+ void (* saved_data_ready )(struct sock * sk );
78
+ struct pvcalls_ioworker ioworker ;
79
+ };
80
+
81
+ static irqreturn_t pvcalls_back_conn_event (int irq , void * sock_map );
82
+ static int pvcalls_back_release_active (struct xenbus_device * dev ,
83
+ struct pvcalls_fedata * fedata ,
84
+ struct sock_mapping * map );
85
+
86
+ static void pvcalls_back_ioworker (struct work_struct * work )
87
+ {
88
+ }
89
+
57
90
static int pvcalls_back_socket (struct xenbus_device * dev ,
58
91
struct xen_pvcalls_request * req )
59
92
{
@@ -82,8 +115,149 @@ static int pvcalls_back_socket(struct xenbus_device *dev,
82
115
return 0 ;
83
116
}
84
117
118
+ static void pvcalls_sk_state_change (struct sock * sock )
119
+ {
120
+ struct sock_mapping * map = sock -> sk_user_data ;
121
+ struct pvcalls_data_intf * intf ;
122
+
123
+ if (map == NULL )
124
+ return ;
125
+
126
+ intf = map -> ring ;
127
+ intf -> in_error = - ENOTCONN ;
128
+ notify_remote_via_irq (map -> irq );
129
+ }
130
+
131
+ static void pvcalls_sk_data_ready (struct sock * sock )
132
+ {
133
+ }
134
+
135
+ static struct sock_mapping * pvcalls_new_active_socket (
136
+ struct pvcalls_fedata * fedata ,
137
+ uint64_t id ,
138
+ grant_ref_t ref ,
139
+ uint32_t evtchn ,
140
+ struct socket * sock )
141
+ {
142
+ int ret ;
143
+ struct sock_mapping * map ;
144
+ void * page ;
145
+
146
+ map = kzalloc (sizeof (* map ), GFP_KERNEL );
147
+ if (map == NULL )
148
+ return NULL ;
149
+
150
+ map -> fedata = fedata ;
151
+ map -> sock = sock ;
152
+ map -> id = id ;
153
+ map -> ref = ref ;
154
+
155
+ ret = xenbus_map_ring_valloc (fedata -> dev , & ref , 1 , & page );
156
+ if (ret < 0 )
157
+ goto out ;
158
+ map -> ring = page ;
159
+ map -> ring_order = map -> ring -> ring_order ;
160
+ /* first read the order, then map the data ring */
161
+ virt_rmb ();
162
+ if (map -> ring_order > MAX_RING_ORDER ) {
163
+ pr_warn ("%s frontend requested ring_order %u, which is > MAX (%u)\n" ,
164
+ __func__ , map -> ring_order , MAX_RING_ORDER );
165
+ goto out ;
166
+ }
167
+ ret = xenbus_map_ring_valloc (fedata -> dev , map -> ring -> ref ,
168
+ (1 << map -> ring_order ), & page );
169
+ if (ret < 0 )
170
+ goto out ;
171
+ map -> bytes = page ;
172
+
173
+ ret = bind_interdomain_evtchn_to_irqhandler (fedata -> dev -> otherend_id ,
174
+ evtchn ,
175
+ pvcalls_back_conn_event ,
176
+ 0 ,
177
+ "pvcalls-backend" ,
178
+ map );
179
+ if (ret < 0 )
180
+ goto out ;
181
+ map -> irq = ret ;
182
+
183
+ map -> data .in = map -> bytes ;
184
+ map -> data .out = map -> bytes + XEN_FLEX_RING_SIZE (map -> ring_order );
185
+
186
+ map -> ioworker .wq = alloc_workqueue ("pvcalls_io" , WQ_UNBOUND , 1 );
187
+ if (!map -> ioworker .wq )
188
+ goto out ;
189
+ atomic_set (& map -> io , 1 );
190
+ INIT_WORK (& map -> ioworker .register_work , pvcalls_back_ioworker );
191
+
192
+ down (& fedata -> socket_lock );
193
+ list_add_tail (& map -> list , & fedata -> socket_mappings );
194
+ up (& fedata -> socket_lock );
195
+
196
+ write_lock_bh (& map -> sock -> sk -> sk_callback_lock );
197
+ map -> saved_data_ready = map -> sock -> sk -> sk_data_ready ;
198
+ map -> sock -> sk -> sk_user_data = map ;
199
+ map -> sock -> sk -> sk_data_ready = pvcalls_sk_data_ready ;
200
+ map -> sock -> sk -> sk_state_change = pvcalls_sk_state_change ;
201
+ write_unlock_bh (& map -> sock -> sk -> sk_callback_lock );
202
+
203
+ return map ;
204
+ out :
205
+ down (& fedata -> socket_lock );
206
+ list_del (& map -> list );
207
+ pvcalls_back_release_active (fedata -> dev , fedata , map );
208
+ up (& fedata -> socket_lock );
209
+ return NULL ;
210
+ }
211
+
85
212
static int pvcalls_back_connect (struct xenbus_device * dev ,
86
213
struct xen_pvcalls_request * req )
214
+ {
215
+ struct pvcalls_fedata * fedata ;
216
+ int ret = - EINVAL ;
217
+ struct socket * sock ;
218
+ struct sock_mapping * map ;
219
+ struct xen_pvcalls_response * rsp ;
220
+ struct sockaddr * sa = (struct sockaddr * )& req -> u .connect .addr ;
221
+
222
+ fedata = dev_get_drvdata (& dev -> dev );
223
+
224
+ if (req -> u .connect .len < sizeof (sa -> sa_family ) ||
225
+ req -> u .connect .len > sizeof (req -> u .connect .addr ) ||
226
+ sa -> sa_family != AF_INET )
227
+ goto out ;
228
+
229
+ ret = sock_create (AF_INET , SOCK_STREAM , 0 , & sock );
230
+ if (ret < 0 )
231
+ goto out ;
232
+ ret = inet_stream_connect (sock , sa , req -> u .connect .len , 0 );
233
+ if (ret < 0 ) {
234
+ sock_release (sock );
235
+ goto out ;
236
+ }
237
+
238
+ map = pvcalls_new_active_socket (fedata ,
239
+ req -> u .connect .id ,
240
+ req -> u .connect .ref ,
241
+ req -> u .connect .evtchn ,
242
+ sock );
243
+ if (!map ) {
244
+ ret = - EFAULT ;
245
+ sock_release (map -> sock );
246
+ }
247
+
248
+ out :
249
+ rsp = RING_GET_RESPONSE (& fedata -> ring , fedata -> ring .rsp_prod_pvt ++ );
250
+ rsp -> req_id = req -> req_id ;
251
+ rsp -> cmd = req -> cmd ;
252
+ rsp -> u .connect .id = req -> u .connect .id ;
253
+ rsp -> ret = ret ;
254
+
255
+ return 0 ;
256
+ }
257
+
258
+ static int pvcalls_back_release_active (struct xenbus_device * dev ,
259
+ struct pvcalls_fedata * fedata ,
260
+ struct sock_mapping * map )
87
261
{
88
262
return 0 ;
89
263
}
@@ -206,6 +380,11 @@ static irqreturn_t pvcalls_back_event(int irq, void *dev_id)
206
380
return IRQ_HANDLED ;
207
381
}
208
382
383
+ static irqreturn_t pvcalls_back_conn_event (int irq , void * sock_map )
384
+ {
385
+ return IRQ_HANDLED ;
386
+ }
387
+
209
388
static int backend_connect (struct xenbus_device * dev )
210
389
{
211
390
int err , evtchn ;
0 commit comments