gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
fs9p.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015 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>
47 #include <unistd.h>
48 
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 
57 struct P9MsgInfo {
58  P9MsgInfo(P9MsgType _type, std::string _name)
59  : type(_type), name(_name) {}
60 
62  std::string name;
63 };
64 
65 typedef 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 
71 static 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 
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 
122 }
123 
124 
126 {
127 }
128 
129 void
131 {
132  readConfigBlob(pkt, cfgOffset, (uint8_t *)config.get());
133 }
134 
135 void
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 
158 void
159 VirtIO9PBase::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 
186 void
187 VirtIO9PBase::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 
208  : VirtIO9PBase(params), deviceUsed(false)
209 {
210 }
211 
213 {
214 }
215 
216 
217 void
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  }
226 
228 }
229 
230 void
232 {
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  }
241 }
242 
243 
244 void
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 
259 void
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 
276 void
277 VirtIO9PProxy::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 
291 void
292 VirtIO9PProxy::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 
309  : VirtIO9PProxy(params),
310  fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1)
311 {
312 }
313 
315 {
316 }
317 
318 void
320 {
321  startDiod();
322  dataEvent.reset(new DiodDataEvent(*this, fd_from_diod, POLLIN));
324 }
325 
326 void
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 
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 
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
363  (char *)NULL);
364  panic("Failed to execute diod: %i\n", 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 
374 ssize_t
375 VirtIO9PDiod::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 
382 ssize_t
383 VirtIO9PDiod::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 
390 void
392 {
394 }
395 
396 VirtIO9PDiod *
397 VirtIO9PDiodParams::create()
398 {
399  return new VirtIO9PDiod(this);
400 }
401 
402 
403 
404 
406  : VirtIO9PProxy(params), fdSocket(-1)
407 {
408 }
409 
411 {
412 }
413 
414 void
416 {
417  connectSocket();
418  dataEvent.reset(new SocketDataEvent(*this, fdSocket, POLLIN));
420 }
421 
422 void
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 
459 void
461 {
462  panic("9P Socket disconnected!\n");
463 }
464 
465 ssize_t
466 VirtIO9PSocket::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)
474 
475  return ret < 0 ? -errno : ret;
476 }
477 
478 ssize_t
479 VirtIO9PSocket::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 
486 void
488 {
490 }
491 
492 
494 VirtIO9PSocketParams::create()
495 {
496  return new VirtIO9PSocket(this);
497 }
#define DPRINTF(x,...)
Definition: trace.hh:212
void startup()
startup() is the final initialization call before simulation.
Definition: fs9p.cc:319
ssize_t read(uint8_t *data, size_t len)
Read data from the server behind the proxy.
Definition: fs9p.cc:375
This class implements a VirtIO transport layer for the 9p network file system.
Definition: fs9p.hh:109
Base class for all VirtIO-based devices.
Definition: base.hh:570
ssize_t read(uint8_t *data, size_t len)
Read data from the server behind the proxy.
Definition: fs9p.cc:466
VirtIO9PSocket & parent
Definition: fs9p.hh:374
VirtIO 9p proxy that communicates with a 9p server over tcp sockets.
Definition: fs9p.hh:341
virtual ~VirtIO9PProxy()
Definition: fs9p.cc:212
PollQueue pollQueue
Definition: pollevent.cc:55
#define panic(...)
Definition: misc.hh:153
void socketDisconnect()
9p server disconnect notification
Definition: fs9p.cc:460
std::unique_ptr< DiodDataEvent > dataEvent
Definition: fs9p.hh:329
virtual ssize_t read(uint8_t *data, size_t len)=0
Read data from the server behind the proxy.
void process(int revent)
Definition: fs9p.cc:487
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: fs9p.cc:218
#define DDUMP(x, data, count)
Definition: trace.hh:211
const Params * params() const
Definition: sim_object.hh:111
uint8_t P9MsgType
Definition: fs9p.hh:50
std::map< P9Tag, VirtDescriptor * > pendingTransactions
Map between 9p transaction tags and descriptors where they appeared.
Definition: fs9p.hh:201
std::string name
Definition: fs9p.cc:62
T p9toh(T v)
Convert p9 byte order (LE) to host byte order.
Definition: fs9p.hh:66
int fd_to_diod
fd for data pipe going to diod (write end)
Definition: fs9p.hh:325
void readConfig(PacketPtr pkt, Addr cfgOffset)
Read from the configuration space of a device.
Definition: fs9p.cc:130
void sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
Send a 9p RPC message reply.
Definition: fs9p.cc:159
virtual void recvTMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)=0
Handle incoming 9p RPC message.
std::map< P9MsgType, P9MsgInfo > P9MsgInfoMap
Definition: fs9p.cc:65
virtual ssize_t write(const uint8_t *data, size_t len)=0
Write data to the server behind the proxy.
#define P9MSG(type, name)
Definition: fs9p.cc:67
int fd_from_diod
fd for data pipe coming from diod (read end)
Definition: fs9p.hh:327
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: base.cc:341
const char data[]
Definition: circlebuf.cc:43
void schedule(PollEvent *event)
Definition: pollevent.cc:159
static const P9MsgInfoMap p9_msg_info
Definition: fs9p.cc:71
#define warn(...)
Definition: misc.hh:219
void produceDescriptor(VirtDescriptor *desc, uint32_t len)
Send a descriptor chain to the guest.
Definition: base.cc:290
void writeAll(const uint8_t *data, size_t len)
Convenience function that writes exactly len bytes.
Definition: fs9p.cc:292
std::unique_ptr< SocketDataEvent > dataEvent
Definition: fs9p.hh:380
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
VirtIO9PBase & parent
Definition: fs9p.hh:159
system
Definition: isa.cc:226
virtual ~VirtIO9PSocket()
Definition: fs9p.cc:410
T htov_legacy(T v)
Convert host endianness to legacy VirtIO endianness.
Definition: base.hh:76
P9Tag tag
Message tag.
Definition: fs9p.hh:61
#define DTRACE(x)
Definition: trace.hh:210
void startup()
startup() is the final initialization call before simulation.
Definition: fs9p.cc:415
VirtIO9PDiod(Params *params)
Definition: fs9p.cc:308
void serverDataReady()
Notification of pending data from server.
Definition: fs9p.cc:260
VirtIO9PSocket(Params *params)
Definition: fs9p.cc:405
void chainRead(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor chain.
Definition: base.cc:168
void kick()
Inform the guest of available buffers.
Definition: base.hh:620
uint32_t len
Length including header.
Definition: fs9p.hh:57
void chainWrite(size_t offset, const uint8_t *src, size_t size)
Write to a descriptor chain.
Definition: base.cc:191
void process(int revent)
Definition: fs9p.cc:391
bool deviceUsed
Bool to track if the device has been used or not.
Definition: fs9p.hh:282
void onNotifyDescriptor(VirtDescriptor *desc)
Notify queue of pending incoming descriptor.
Definition: fs9p.cc:136
VirtIO descriptor (chain) wrapper.
Definition: base.hh:136
ssize_t write(const uint8_t *data, size_t len)
Write data to the server behind the proxy.
Definition: fs9p.cc:383
FSQueue queue
Definition: fs9p.hh:162
P9MsgInfo(P9MsgType _type, std::string _name)
Definition: fs9p.cc:58
void recvTMsg(const P9MsgHeader &header, const uint8_t *data, size_t size) override
Handle incoming 9p RPC message.
Definition: fs9p.cc:245
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
VirtIO9PDiod & parent
Definition: fs9p.hh:321
virtual ~VirtIO9PDiod()
Definition: fs9p.cc:314
VirtIO9PBaseParams Params
Definition: fs9p.hh:112
size_t size() const
Retrieve the size of this descriptor.
Definition: base.hh:231
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
void startDiod()
Start diod and setup the communication pipes.
Definition: fs9p.cc:327
virtual ~VirtIO9PBase()
Definition: fs9p.cc:125
VirtDescriptor * next() const
Get the pointer to the next descriptor in a chain.
Definition: base.cc:134
void registerQueue(VirtQueue &queue)
Register a new VirtQueue with the device model.
Definition: base.cc:477
int size()
Definition: pagetable.hh:146
void readAll(uint8_t *data, size_t len)
Convenience function that reads exactly len bytes.
Definition: fs9p.cc:277
T htop9(T v)
Convert host byte order to p9 byte order (LE)
Definition: fs9p.hh:70
std::ostream CheckpointOut
Definition: serialize.hh:67
VirtIO 9p configuration structure.
Definition: fs9p.hh:125
P9MsgType type
Definition: fs9p.cc:61
VirtIO9PBase(Params *params)
Definition: fs9p.cc:110
Bitfield< 18, 16 > len
Definition: miscregs.hh:1626
int diod_pid
PID of diod process.
Definition: fs9p.hh:332
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: fs9p.cc:231
bool isOutgoing() const
Check if this is a write-only descriptor (outgoing data).
Definition: base.hh:250
void connectSocket()
Try to resolve the server name and connect to the 9p server.
Definition: fs9p.cc:423
void dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
Dump a 9p RPC message on the debug output.
Definition: fs9p.cc:187
VirtIO 9p proxy that communicates with the diod 9p server using pipes.
Definition: fs9p.hh:291
Bitfield< 0 > p
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: base.cc:351
std::unique_ptr< Config > config
Currently active configuration (host byte order)
Definition: fs9p.hh:131
P9MsgType type
Message type.
Definition: fs9p.hh:59
void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
Read configuration data from a device structure.
Definition: base.cc:420
VirtIO9PProxy(Params *params)
Definition: fs9p.cc:207
int fdSocket
Socket connected to the 9p server.
Definition: fs9p.hh:378
const size_t configSize
Size of the device's configuration space.
Definition: base.hh:850
VirtIO 9p proxy base class.
Definition: fs9p.hh:212
ssize_t write(const uint8_t *data, size_t len)
Write data to the server behind the proxy.
Definition: fs9p.cc:479

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6