Skip to content

Commit 5db4d28

Browse files
sstabelliniBoris Ostrovsky
authored andcommitted
xen/pvcalls: implement connect command
Allocate a socket. Keep track of socket <-> ring mappings with a new data structure, called sock_mapping. Implement the connect command by calling inet_stream_connect, and mapping the new indexes page and data ring. Allocate a workqueue and a work_struct, called ioworker, to perform reads and writes to the socket. When an active socket is closed (sk_state_change), set in_error to -ENOTCONN and notify the other end, as specified by the protocol. sk_data_ready and pvcalls_back_ioworker will be implemented later. [ boris: fixed whitespaces ] Signed-off-by: Stefano Stabellini <[email protected]> Reviewed-by: Juergen Gross <[email protected]> CC: [email protected] CC: [email protected] Signed-off-by: Boris Ostrovsky <[email protected]>
1 parent fb02987 commit 5db4d28

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

drivers/xen/pvcalls-back.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,39 @@ struct pvcalls_fedata {
5454
struct semaphore socket_lock;
5555
};
5656

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+
5790
static int pvcalls_back_socket(struct xenbus_device *dev,
5891
struct xen_pvcalls_request *req)
5992
{
@@ -82,8 +115,149 @@ static int pvcalls_back_socket(struct xenbus_device *dev,
82115
return 0;
83116
}
84117

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+
85212
static int pvcalls_back_connect(struct xenbus_device *dev,
86213
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)
87261
{
88262
return 0;
89263
}
@@ -206,6 +380,11 @@ static irqreturn_t pvcalls_back_event(int irq, void *dev_id)
206380
return IRQ_HANDLED;
207381
}
208382

383+
static irqreturn_t pvcalls_back_conn_event(int irq, void *sock_map)
384+
{
385+
return IRQ_HANDLED;
386+
}
387+
209388
static int backend_connect(struct xenbus_device *dev)
210389
{
211390
int err, evtchn;

0 commit comments

Comments
 (0)