fs9p.cc (11793:ef606668d247) fs9p.cc (12076:d6fa15da87cd)
1/*
1/*
2 * Copyright (c) 2014-2015 ARM Limited
2 * Copyright (c) 2014-2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andreas Sandberg
38 */
39
40#include "dev/virtio/fs9p.hh"
41
42#include <fcntl.h>
43#include <netdb.h>
44#include <netinet/in.h>
45#include <sys/socket.h>
46#include <sys/types.h>
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andreas Sandberg
38 */
39
40#include "dev/virtio/fs9p.hh"
41
42#include <fcntl.h>
43#include <netdb.h>
44#include <netinet/in.h>
45#include <sys/socket.h>
46#include <sys/types.h>
47#include <sys/un.h>
47#include <unistd.h>
48
48#include <unistd.h>
49
50#include <fstream>
51
52#include "base/output.hh"
49#include "debug/VIO9P.hh"
50#include "debug/VIO9PData.hh"
51#include "params/VirtIO9PBase.hh"
52#include "params/VirtIO9PDiod.hh"
53#include "params/VirtIO9PProxy.hh"
54#include "params/VirtIO9PSocket.hh"
55#include "sim/system.hh"
56
57struct P9MsgInfo {
58 P9MsgInfo(P9MsgType _type, std::string _name)
59 : type(_type), name(_name) {}
60
61 P9MsgType type;
62 std::string name;
63};
64
65typedef std::map<P9MsgType, P9MsgInfo> P9MsgInfoMap;
66
67#define P9MSG(type, name) \
68 { (type), P9MsgInfo((type), "T" # name ) }, \
69 { (type + 1), P9MsgInfo((type + 1), "R" # name ) }
70
71static const P9MsgInfoMap p9_msg_info {
72 P9MSG(6, LERROR),
73 P9MSG(8, STATFS),
74 P9MSG(12, LOPEN),
75 P9MSG(14, LCREATE),
76 P9MSG(16, SYMLINK),
77 P9MSG(18, MKNOD),
78 P9MSG(20, RENAME),
79 P9MSG(22, READLINK),
80 P9MSG(24, GETATTR),
81 P9MSG(26, SETATTR),
82 P9MSG(30, XATTRWALK),
83 P9MSG(32, XATTRCREATE),
84 P9MSG(40, READDIR),
85 P9MSG(50, FSYNC),
86 P9MSG(52, LOCK),
87 P9MSG(54, GETLOCK),
88 P9MSG(70, LINK),
89 P9MSG(72, MKDIR),
90 P9MSG(74, RENAMEAT),
91 P9MSG(76, UNLINKAT),
92 P9MSG(100, VERSION),
93 P9MSG(102, AUTH),
94 P9MSG(104, ATTACH),
95 P9MSG(106, ERROR),
96 P9MSG(108, FLUSH),
97 P9MSG(110, WALK),
98 P9MSG(112, OPEN),
99 P9MSG(114, CREATE),
100 P9MSG(116, READ),
101 P9MSG(118, WRITE),
102 P9MSG(120, CLUNK),
103 P9MSG(122, REMOVE),
104 P9MSG(124, STAT),
105 P9MSG(126, WSTAT),
106};
107
108#undef P9MSG
109
110VirtIO9PBase::VirtIO9PBase(Params *params)
111 : VirtIODeviceBase(params, ID_9P,
112 sizeof(Config) + params->tag.size(),
113 F_MOUNT_TAG),
114 queue(params->system->physProxy, params->queueSize, *this)
115{
116 config.reset((Config *)
117 operator new(configSize));
118 config->len = htov_legacy(params->tag.size());
119 memcpy(config->tag, params->tag.c_str(), params->tag.size());
120
121 registerQueue(queue);
122}
123
124
125VirtIO9PBase::~VirtIO9PBase()
126{
127}
128
129void
130VirtIO9PBase::readConfig(PacketPtr pkt, Addr cfgOffset)
131{
132 readConfigBlob(pkt, cfgOffset, (uint8_t *)config.get());
133}
134
135void
136VirtIO9PBase::FSQueue::onNotifyDescriptor(VirtDescriptor *desc)
137{
138 DPRINTF(VIO9P, "Got input data descriptor (len: %i)\n", desc->size());
139 DPRINTF(VIO9P, "\tPending transactions: %i\n", parent.pendingTransactions.size());
140
141 P9MsgHeader header;
142 desc->chainRead(0, (uint8_t *)&header, sizeof(header));
143 header = p9toh(header);
144
145 uint8_t data[header.len - sizeof(header)];
146 desc->chainRead(sizeof(header), data, sizeof(data));
147
148 // Keep track of pending transactions
149 parent.pendingTransactions[header.tag] = desc;
150
151 DPRINTF(VIO9P, "recvTMsg\n");
152 parent.dumpMsg(header, data, sizeof(data));
153
154 // Notify device of message
155 parent.recvTMsg(header, data, sizeof(data));
156}
157
158void
159VirtIO9PBase::sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
160{
161 DPRINTF(VIO9P, "Sending RMsg\n");
162 dumpMsg(header, data, size);
163 DPRINTF(VIO9P, "\tPending transactions: %i\n", pendingTransactions.size());
164 assert(header.len >= sizeof(header));
165
166 VirtDescriptor *main_desc(pendingTransactions[header.tag]);
167 pendingTransactions.erase(header.tag);
168
169 // Find the first output descriptor
170 VirtDescriptor *out_desc(main_desc);
171 while (out_desc && !out_desc->isOutgoing())
172 out_desc = out_desc->next();
173 if (!out_desc)
174 panic("sendRMsg: Framing error, no output descriptor.\n");
175
176 P9MsgHeader header_out(htop9(header));
177 header_out.len = htop9(sizeof(P9MsgHeader) + size);
178
179 out_desc->chainWrite(0, (uint8_t *)&header_out, sizeof(header_out));
180 out_desc->chainWrite(sizeof(header_out), data, size);
181
182 queue.produceDescriptor(main_desc, sizeof(P9MsgHeader) + size);
183 kick();
184}
185
186void
187VirtIO9PBase::dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
188{
189#ifndef NDEBUG
190 if (!DTRACE(VIO9P))
191 return;
192
193 const P9MsgInfoMap::const_iterator it_msg(p9_msg_info.find(header.type));
194 if (it_msg != p9_msg_info.cend()) {
195 const P9MsgInfo &info(it_msg->second);
196 DPRINTF(VIO9P, "P9Msg[len = %i, type = %s (%i), tag = %i]\n",
197 header.len, info.name, header.type, header.tag);
198 } else {
199 DPRINTF(VIO9P, "P9Msg[len = %i, type = Unknown (%i), tag = %i]\n",
200 header.len, header.type, header.tag);
201 }
202 DDUMP(VIO9PData, data, size);
203#endif
204}
205
206
207VirtIO9PProxy::VirtIO9PProxy(Params *params)
208 : VirtIO9PBase(params), deviceUsed(false)
209{
210}
211
212VirtIO9PProxy::~VirtIO9PProxy()
213{
214}
215
216
217void
218VirtIO9PProxy::serialize(CheckpointOut &cp) const
219{
220 if (deviceUsed) {
221 warn("Serializing VirtIO9Base device after device has been used. It is "
222 "likely that state will be lost, and that the device will cease "
223 "to work!");
224 }
225 SERIALIZE_SCALAR(deviceUsed);
226
227 VirtIO9PBase::serialize(cp);
228}
229
230void
231VirtIO9PProxy::unserialize(CheckpointIn &cp)
232{
233 UNSERIALIZE_SCALAR(deviceUsed);
234
235 if (deviceUsed) {
236 warn("Unserializing VirtIO9Base device after device has been used. It is "
237 "likely that state has been lost, and that the device will cease "
238 "to work!");
239 }
240 VirtIO9PBase::unserialize(cp);
241}
242
243
244void
245VirtIO9PProxy::recvTMsg(const P9MsgHeader &header,
246 const uint8_t *data, size_t size)
247{
248 deviceUsed = true;
249 assert(header.len == sizeof(header) + size);
250 // While technically not needed, we send the packet as one
251 // contiguous segment to make some packet dissectors happy.
252 uint8_t out[header.len];
253 P9MsgHeader header_out(htop9(header));
254 memcpy(out, (uint8_t *)&header_out, sizeof(header_out));
255 memcpy(out + sizeof(header_out), data, size);
256 writeAll(out, sizeof(header_out) + size);
257}
258
259void
260VirtIO9PProxy::serverDataReady()
261{
262 P9MsgHeader header;
263 readAll((uint8_t *)&header, sizeof(header));
264 header = p9toh(header);
265
266 const ssize_t payload_len(header.len - sizeof(header));
267 if (payload_len < 0)
268 panic("Payload length is negative!\n");
269 uint8_t data[payload_len];
270 readAll(data, payload_len);
271
272 sendRMsg(header, data, payload_len);
273}
274
275
276void
277VirtIO9PProxy::readAll(uint8_t *data, size_t len)
278{
279 while (len) {
280 ssize_t ret;
281 while ((ret = read(data, len)) == -EAGAIN)
282 ;
283 if (ret < 0)
284 panic("readAll: Read failed: %i\n", -ret);
285
286 len -= ret;
287 data += ret;
288 }
289}
290
291void
292VirtIO9PProxy::writeAll(const uint8_t *data, size_t len)
293{
294 while (len) {
295 ssize_t ret;
296 while ((ret = write(data, len)) == -EAGAIN)
297 ;
298 if (ret < 0)
299 panic("writeAll: write failed: %i\n", -ret);
300
301 len -= ret;
302 data += ret;
303 }
304}
305
306
307
308VirtIO9PDiod::VirtIO9PDiod(Params *params)
309 : VirtIO9PProxy(params),
310 fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1)
311{
312}
313
314VirtIO9PDiod::~VirtIO9PDiod()
315{
316}
317
318void
319VirtIO9PDiod::startup()
320{
321 startDiod();
322 dataEvent.reset(new DiodDataEvent(*this, fd_from_diod, POLLIN));
323 pollQueue.schedule(dataEvent.get());
324}
325
326void
327VirtIO9PDiod::startDiod()
328{
329 const Params *p(dynamic_cast<const Params *>(params()));
330 int pipe_rfd[2];
331 int pipe_wfd[2];
332 const int DIOD_RFD = 3;
333 const int DIOD_WFD = 4;
334
335 const char *diod(p->diod.c_str());
336
53#include "debug/VIO9P.hh"
54#include "debug/VIO9PData.hh"
55#include "params/VirtIO9PBase.hh"
56#include "params/VirtIO9PDiod.hh"
57#include "params/VirtIO9PProxy.hh"
58#include "params/VirtIO9PSocket.hh"
59#include "sim/system.hh"
60
61struct P9MsgInfo {
62 P9MsgInfo(P9MsgType _type, std::string _name)
63 : type(_type), name(_name) {}
64
65 P9MsgType type;
66 std::string name;
67};
68
69typedef std::map<P9MsgType, P9MsgInfo> P9MsgInfoMap;
70
71#define P9MSG(type, name) \
72 { (type), P9MsgInfo((type), "T" # name ) }, \
73 { (type + 1), P9MsgInfo((type + 1), "R" # name ) }
74
75static const P9MsgInfoMap p9_msg_info {
76 P9MSG(6, LERROR),
77 P9MSG(8, STATFS),
78 P9MSG(12, LOPEN),
79 P9MSG(14, LCREATE),
80 P9MSG(16, SYMLINK),
81 P9MSG(18, MKNOD),
82 P9MSG(20, RENAME),
83 P9MSG(22, READLINK),
84 P9MSG(24, GETATTR),
85 P9MSG(26, SETATTR),
86 P9MSG(30, XATTRWALK),
87 P9MSG(32, XATTRCREATE),
88 P9MSG(40, READDIR),
89 P9MSG(50, FSYNC),
90 P9MSG(52, LOCK),
91 P9MSG(54, GETLOCK),
92 P9MSG(70, LINK),
93 P9MSG(72, MKDIR),
94 P9MSG(74, RENAMEAT),
95 P9MSG(76, UNLINKAT),
96 P9MSG(100, VERSION),
97 P9MSG(102, AUTH),
98 P9MSG(104, ATTACH),
99 P9MSG(106, ERROR),
100 P9MSG(108, FLUSH),
101 P9MSG(110, WALK),
102 P9MSG(112, OPEN),
103 P9MSG(114, CREATE),
104 P9MSG(116, READ),
105 P9MSG(118, WRITE),
106 P9MSG(120, CLUNK),
107 P9MSG(122, REMOVE),
108 P9MSG(124, STAT),
109 P9MSG(126, WSTAT),
110};
111
112#undef P9MSG
113
114VirtIO9PBase::VirtIO9PBase(Params *params)
115 : VirtIODeviceBase(params, ID_9P,
116 sizeof(Config) + params->tag.size(),
117 F_MOUNT_TAG),
118 queue(params->system->physProxy, params->queueSize, *this)
119{
120 config.reset((Config *)
121 operator new(configSize));
122 config->len = htov_legacy(params->tag.size());
123 memcpy(config->tag, params->tag.c_str(), params->tag.size());
124
125 registerQueue(queue);
126}
127
128
129VirtIO9PBase::~VirtIO9PBase()
130{
131}
132
133void
134VirtIO9PBase::readConfig(PacketPtr pkt, Addr cfgOffset)
135{
136 readConfigBlob(pkt, cfgOffset, (uint8_t *)config.get());
137}
138
139void
140VirtIO9PBase::FSQueue::onNotifyDescriptor(VirtDescriptor *desc)
141{
142 DPRINTF(VIO9P, "Got input data descriptor (len: %i)\n", desc->size());
143 DPRINTF(VIO9P, "\tPending transactions: %i\n", parent.pendingTransactions.size());
144
145 P9MsgHeader header;
146 desc->chainRead(0, (uint8_t *)&header, sizeof(header));
147 header = p9toh(header);
148
149 uint8_t data[header.len - sizeof(header)];
150 desc->chainRead(sizeof(header), data, sizeof(data));
151
152 // Keep track of pending transactions
153 parent.pendingTransactions[header.tag] = desc;
154
155 DPRINTF(VIO9P, "recvTMsg\n");
156 parent.dumpMsg(header, data, sizeof(data));
157
158 // Notify device of message
159 parent.recvTMsg(header, data, sizeof(data));
160}
161
162void
163VirtIO9PBase::sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
164{
165 DPRINTF(VIO9P, "Sending RMsg\n");
166 dumpMsg(header, data, size);
167 DPRINTF(VIO9P, "\tPending transactions: %i\n", pendingTransactions.size());
168 assert(header.len >= sizeof(header));
169
170 VirtDescriptor *main_desc(pendingTransactions[header.tag]);
171 pendingTransactions.erase(header.tag);
172
173 // Find the first output descriptor
174 VirtDescriptor *out_desc(main_desc);
175 while (out_desc && !out_desc->isOutgoing())
176 out_desc = out_desc->next();
177 if (!out_desc)
178 panic("sendRMsg: Framing error, no output descriptor.\n");
179
180 P9MsgHeader header_out(htop9(header));
181 header_out.len = htop9(sizeof(P9MsgHeader) + size);
182
183 out_desc->chainWrite(0, (uint8_t *)&header_out, sizeof(header_out));
184 out_desc->chainWrite(sizeof(header_out), data, size);
185
186 queue.produceDescriptor(main_desc, sizeof(P9MsgHeader) + size);
187 kick();
188}
189
190void
191VirtIO9PBase::dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
192{
193#ifndef NDEBUG
194 if (!DTRACE(VIO9P))
195 return;
196
197 const P9MsgInfoMap::const_iterator it_msg(p9_msg_info.find(header.type));
198 if (it_msg != p9_msg_info.cend()) {
199 const P9MsgInfo &info(it_msg->second);
200 DPRINTF(VIO9P, "P9Msg[len = %i, type = %s (%i), tag = %i]\n",
201 header.len, info.name, header.type, header.tag);
202 } else {
203 DPRINTF(VIO9P, "P9Msg[len = %i, type = Unknown (%i), tag = %i]\n",
204 header.len, header.type, header.tag);
205 }
206 DDUMP(VIO9PData, data, size);
207#endif
208}
209
210
211VirtIO9PProxy::VirtIO9PProxy(Params *params)
212 : VirtIO9PBase(params), deviceUsed(false)
213{
214}
215
216VirtIO9PProxy::~VirtIO9PProxy()
217{
218}
219
220
221void
222VirtIO9PProxy::serialize(CheckpointOut &cp) const
223{
224 if (deviceUsed) {
225 warn("Serializing VirtIO9Base device after device has been used. It is "
226 "likely that state will be lost, and that the device will cease "
227 "to work!");
228 }
229 SERIALIZE_SCALAR(deviceUsed);
230
231 VirtIO9PBase::serialize(cp);
232}
233
234void
235VirtIO9PProxy::unserialize(CheckpointIn &cp)
236{
237 UNSERIALIZE_SCALAR(deviceUsed);
238
239 if (deviceUsed) {
240 warn("Unserializing VirtIO9Base device after device has been used. It is "
241 "likely that state has been lost, and that the device will cease "
242 "to work!");
243 }
244 VirtIO9PBase::unserialize(cp);
245}
246
247
248void
249VirtIO9PProxy::recvTMsg(const P9MsgHeader &header,
250 const uint8_t *data, size_t size)
251{
252 deviceUsed = true;
253 assert(header.len == sizeof(header) + size);
254 // While technically not needed, we send the packet as one
255 // contiguous segment to make some packet dissectors happy.
256 uint8_t out[header.len];
257 P9MsgHeader header_out(htop9(header));
258 memcpy(out, (uint8_t *)&header_out, sizeof(header_out));
259 memcpy(out + sizeof(header_out), data, size);
260 writeAll(out, sizeof(header_out) + size);
261}
262
263void
264VirtIO9PProxy::serverDataReady()
265{
266 P9MsgHeader header;
267 readAll((uint8_t *)&header, sizeof(header));
268 header = p9toh(header);
269
270 const ssize_t payload_len(header.len - sizeof(header));
271 if (payload_len < 0)
272 panic("Payload length is negative!\n");
273 uint8_t data[payload_len];
274 readAll(data, payload_len);
275
276 sendRMsg(header, data, payload_len);
277}
278
279
280void
281VirtIO9PProxy::readAll(uint8_t *data, size_t len)
282{
283 while (len) {
284 ssize_t ret;
285 while ((ret = read(data, len)) == -EAGAIN)
286 ;
287 if (ret < 0)
288 panic("readAll: Read failed: %i\n", -ret);
289
290 len -= ret;
291 data += ret;
292 }
293}
294
295void
296VirtIO9PProxy::writeAll(const uint8_t *data, size_t len)
297{
298 while (len) {
299 ssize_t ret;
300 while ((ret = write(data, len)) == -EAGAIN)
301 ;
302 if (ret < 0)
303 panic("writeAll: write failed: %i\n", -ret);
304
305 len -= ret;
306 data += ret;
307 }
308}
309
310
311
312VirtIO9PDiod::VirtIO9PDiod(Params *params)
313 : VirtIO9PProxy(params),
314 fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1)
315{
316}
317
318VirtIO9PDiod::~VirtIO9PDiod()
319{
320}
321
322void
323VirtIO9PDiod::startup()
324{
325 startDiod();
326 dataEvent.reset(new DiodDataEvent(*this, fd_from_diod, POLLIN));
327 pollQueue.schedule(dataEvent.get());
328}
329
330void
331VirtIO9PDiod::startDiod()
332{
333 const Params *p(dynamic_cast<const Params *>(params()));
334 int pipe_rfd[2];
335 int pipe_wfd[2];
336 const int DIOD_RFD = 3;
337 const int DIOD_WFD = 4;
338
339 const char *diod(p->diod.c_str());
340
341 DPRINTF(VIO9P, "Using diod at %s \n", p->diod.c_str());
342
337 if (pipe(pipe_rfd) == -1 || pipe(pipe_wfd) == -1)
338 panic("Failed to create DIOD pipes: %i\n", errno);
339
340 fd_to_diod = pipe_rfd[1];
341 fd_from_diod = pipe_wfd[0];
342
343 diod_pid = fork();
344 if (diod_pid == -1) {
345 panic("Fork failed: %i\n", errno);
346 } else if (diod_pid == 0) {
347 close(STDIN_FILENO);
348
349 if (dup2(pipe_rfd[0], DIOD_RFD) == -1 ||
350 dup2(pipe_wfd[1], DIOD_WFD) == -1) {
351
352 panic("Failed to setup read/write pipes: %i\n",
353 errno);
354 }
355
343 if (pipe(pipe_rfd) == -1 || pipe(pipe_wfd) == -1)
344 panic("Failed to create DIOD pipes: %i\n", errno);
345
346 fd_to_diod = pipe_rfd[1];
347 fd_from_diod = pipe_wfd[0];
348
349 diod_pid = fork();
350 if (diod_pid == -1) {
351 panic("Fork failed: %i\n", errno);
352 } else if (diod_pid == 0) {
353 close(STDIN_FILENO);
354
355 if (dup2(pipe_rfd[0], DIOD_RFD) == -1 ||
356 dup2(pipe_wfd[1], DIOD_WFD) == -1) {
357
358 panic("Failed to setup read/write pipes: %i\n",
359 errno);
360 }
361
362 // Create Unix domain socket
363 int socket_id = socket(AF_UNIX, SOCK_STREAM, 0);
364 if (socket_id == -1) {
365 panic("Socket creation failed %i \n", errno);
366 }
367 // Bind the socket to a path which will not be read
368 struct sockaddr_un socket_address;
369 memset(&socket_address, 0, sizeof(struct sockaddr_un));
370 socket_address.sun_family = AF_UNIX;
371
372 const std::string socket_path = simout.resolve(p->socketPath);
373 fatal_if(!OutputDirectory::isAbsolute(socket_path), "Please make the" \
374 " output directory an absolute path, else diod will fail!\n");
375
376 // Prevent overflow in strcpy
377 fatal_if(sizeof(socket_address.sun_path) <= socket_path.length(),
378 "Incorrect length of socket path");
379 strncpy(socket_address.sun_path, socket_path.c_str(),
380 sizeof(socket_address.sun_path));
381
382 if (bind(socket_id, (struct sockaddr*) &socket_address,
383 sizeof(struct sockaddr_un)) == -1){
384 perror("Socket binding");
385 panic("Socket binding to %i failed - most likely the output dir" \
386 " and hence unused socket already exists \n", socket_id);
387 }
388
356 execlp(diod, diod,
357 "-f", // start in foreground
358 "-r", "3", // setup read FD
359 "-w", "4", // setup write FD
360 "-e", p->root.c_str(), // path to export
361 "-n", // disable security
362 "-S", // squash all users
389 execlp(diod, diod,
390 "-f", // start in foreground
391 "-r", "3", // setup read FD
392 "-w", "4", // setup write FD
393 "-e", p->root.c_str(), // path to export
394 "-n", // disable security
395 "-S", // squash all users
396 "-l", socket_path.c_str(), // pass the socket
363 (char *)NULL);
397 (char *)NULL);
364 panic("Failed to execute diod: %i\n", errno);
398 perror("Starting DIOD");
399 panic("Failed to execute diod to %s: %i\n",socket_path, errno);
365 } else {
366 close(pipe_rfd[0]);
367 close(pipe_wfd[1]);
368 }
369
370#undef DIOD_RFD
371#undef DIOD_WFD
372}
373
374ssize_t
375VirtIO9PDiod::read(uint8_t *data, size_t len)
376{
377 assert(fd_from_diod != -1);
378 const int ret(::read(fd_from_diod, (void *)data, len));
379 return ret < 0 ? -errno : ret;
380}
381
382ssize_t
383VirtIO9PDiod::write(const uint8_t *data, size_t len)
384{
385 assert(fd_to_diod != -1);
386 const int ret(::write(fd_to_diod, (const void *)data, len));
387 return ret < 0 ? -errno : ret;
388}
389
390void
391VirtIO9PDiod::DiodDataEvent::process(int revent)
392{
393 parent.serverDataReady();
394}
395
396VirtIO9PDiod *
397VirtIO9PDiodParams::create()
398{
399 return new VirtIO9PDiod(this);
400}
401
402
403
404
405VirtIO9PSocket::VirtIO9PSocket(Params *params)
406 : VirtIO9PProxy(params), fdSocket(-1)
407{
408}
409
410VirtIO9PSocket::~VirtIO9PSocket()
411{
412}
413
414void
415VirtIO9PSocket::startup()
416{
417 connectSocket();
418 dataEvent.reset(new SocketDataEvent(*this, fdSocket, POLLIN));
419 pollQueue.schedule(dataEvent.get());
420}
421
422void
423VirtIO9PSocket::connectSocket()
424{
425 const Params &p(dynamic_cast<const Params &>(*params()));
426
427 int ret;
428 struct addrinfo hints, *result;
429 memset(&hints, 0, sizeof(hints));
430 hints.ai_family = AF_UNSPEC;
431 hints.ai_socktype = SOCK_STREAM;
432 hints.ai_flags = 0;
433 hints.ai_protocol = 0;
434
435 if ((ret = getaddrinfo(p.server.c_str(), p.port.c_str(),
436 &hints, &result)) != 0)
437 panic("getaddrinfo: %s\n", gai_strerror(ret));
438
439 DPRINTF(VIO9P, "Connecting to 9p server '%s'.\n", p.server);
440 for (struct addrinfo *rp = result; rp; rp = rp->ai_next) {
441 fdSocket = socket(rp->ai_family, rp->ai_socktype,
442 rp->ai_protocol);
443 if (fdSocket == -1) {
444 continue;
445 } else if (connect(fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) {
446 break;
447 } else {
448 close(fdSocket);
449 fdSocket = -1;
450 }
451 }
452
453 freeaddrinfo(result);
454
455 if (fdSocket == -1)
456 panic("Failed to connect to 9p server (%s:%s)", p.server, p.port);
457}
458
459void
460VirtIO9PSocket::socketDisconnect()
461{
462 panic("9P Socket disconnected!\n");
463}
464
465ssize_t
466VirtIO9PSocket::read(uint8_t *data, size_t len)
467{
468 assert(fdSocket != -1);
469 int ret;
470
471 ret = ::recv(fdSocket, (void *)data, len, 0);
472 if (ret == 0)
473 socketDisconnect();
474
475 return ret < 0 ? -errno : ret;
476}
477
478ssize_t
479VirtIO9PSocket::write(const uint8_t *data, size_t len)
480{
481 assert(fdSocket != -1);
482 int ret(::send(fdSocket, (const void *)data, len, 0));
483 return ret < 0 ? -errno : ret;
484}
485
486void
487VirtIO9PSocket::SocketDataEvent::process(int revent)
488{
489 parent.serverDataReady();
490}
491
492
493VirtIO9PSocket *
494VirtIO9PSocketParams::create()
495{
496 return new VirtIO9PSocket(this);
497}
400 } else {
401 close(pipe_rfd[0]);
402 close(pipe_wfd[1]);
403 }
404
405#undef DIOD_RFD
406#undef DIOD_WFD
407}
408
409ssize_t
410VirtIO9PDiod::read(uint8_t *data, size_t len)
411{
412 assert(fd_from_diod != -1);
413 const int ret(::read(fd_from_diod, (void *)data, len));
414 return ret < 0 ? -errno : ret;
415}
416
417ssize_t
418VirtIO9PDiod::write(const uint8_t *data, size_t len)
419{
420 assert(fd_to_diod != -1);
421 const int ret(::write(fd_to_diod, (const void *)data, len));
422 return ret < 0 ? -errno : ret;
423}
424
425void
426VirtIO9PDiod::DiodDataEvent::process(int revent)
427{
428 parent.serverDataReady();
429}
430
431VirtIO9PDiod *
432VirtIO9PDiodParams::create()
433{
434 return new VirtIO9PDiod(this);
435}
436
437
438
439
440VirtIO9PSocket::VirtIO9PSocket(Params *params)
441 : VirtIO9PProxy(params), fdSocket(-1)
442{
443}
444
445VirtIO9PSocket::~VirtIO9PSocket()
446{
447}
448
449void
450VirtIO9PSocket::startup()
451{
452 connectSocket();
453 dataEvent.reset(new SocketDataEvent(*this, fdSocket, POLLIN));
454 pollQueue.schedule(dataEvent.get());
455}
456
457void
458VirtIO9PSocket::connectSocket()
459{
460 const Params &p(dynamic_cast<const Params &>(*params()));
461
462 int ret;
463 struct addrinfo hints, *result;
464 memset(&hints, 0, sizeof(hints));
465 hints.ai_family = AF_UNSPEC;
466 hints.ai_socktype = SOCK_STREAM;
467 hints.ai_flags = 0;
468 hints.ai_protocol = 0;
469
470 if ((ret = getaddrinfo(p.server.c_str(), p.port.c_str(),
471 &hints, &result)) != 0)
472 panic("getaddrinfo: %s\n", gai_strerror(ret));
473
474 DPRINTF(VIO9P, "Connecting to 9p server '%s'.\n", p.server);
475 for (struct addrinfo *rp = result; rp; rp = rp->ai_next) {
476 fdSocket = socket(rp->ai_family, rp->ai_socktype,
477 rp->ai_protocol);
478 if (fdSocket == -1) {
479 continue;
480 } else if (connect(fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) {
481 break;
482 } else {
483 close(fdSocket);
484 fdSocket = -1;
485 }
486 }
487
488 freeaddrinfo(result);
489
490 if (fdSocket == -1)
491 panic("Failed to connect to 9p server (%s:%s)", p.server, p.port);
492}
493
494void
495VirtIO9PSocket::socketDisconnect()
496{
497 panic("9P Socket disconnected!\n");
498}
499
500ssize_t
501VirtIO9PSocket::read(uint8_t *data, size_t len)
502{
503 assert(fdSocket != -1);
504 int ret;
505
506 ret = ::recv(fdSocket, (void *)data, len, 0);
507 if (ret == 0)
508 socketDisconnect();
509
510 return ret < 0 ? -errno : ret;
511}
512
513ssize_t
514VirtIO9PSocket::write(const uint8_t *data, size_t len)
515{
516 assert(fdSocket != -1);
517 int ret(::send(fdSocket, (const void *)data, len, 0));
518 return ret < 0 ? -errno : ret;
519}
520
521void
522VirtIO9PSocket::SocketDataEvent::process(int revent)
523{
524 parent.serverDataReady();
525}
526
527
528VirtIO9PSocket *
529VirtIO9PSocketParams::create()
530{
531 return new VirtIO9PSocket(this);
532}