4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <linux/vhost.h>
37 #include <linux/virtio_net.h>
38 #include <fuse/cuse_lowlevel.h>
42 #include <sys/eventfd.h>
44 #include <sys/types.h>
50 #include "vhost-net.h"
52 /* Line size for reading maps file. */
53 static const uint32_t BUFSIZE = PATH_MAX;
55 /* Size of prot char array in procmap. */
58 /* Number of elements in procmap struct. */
61 /* Structure containing information gathered from maps file. */
63 uint64_t va_start; /* Start virtual address in file. */
64 uint64_t len; /* Size of file. */
65 uint64_t pgoff; /* Not used. */
66 uint32_t maj; /* Not used. */
67 uint32_t min; /* Not used. */
68 uint32_t ino; /* Not used. */
69 char prot[PROT_SZ]; /* Not used. */
70 char fname[PATH_MAX]; /* File name. */
74 * Locate the file containing QEMU's memory space and
75 * map it to our address space.
78 host_memory_map(struct virtio_net *dev, struct virtio_memory *mem,
79 pid_t pid, uint64_t addr)
81 struct dirent *dptr = NULL;
82 struct procmap procmap;
86 char memfile[PATH_MAX];
87 char mapfile[PATH_MAX];
88 char procdir[PATH_MAX];
89 char resolved_path[PATH_MAX];
96 char *str, *sp, *in[PROCMAP_SZ];
99 /* Path where mem files are located. */
100 snprintf(procdir, PATH_MAX, "/proc/%u/fd/", pid);
101 /* Maps file used to locate mem file. */
102 snprintf(mapfile, PATH_MAX, "/proc/%u/maps", pid);
104 fmap = fopen(mapfile, "r");
106 RTE_LOG(ERR, VHOST_CONFIG,
107 "(%"PRIu64") Failed to open maps file for pid %d\n",
108 dev->device_fh, pid);
112 /* Read through maps file until we find out base_address. */
113 while (fgets(line, BUFSIZE, fmap) != 0) {
116 /* Split line into fields. */
117 for (i = 0; i < PROCMAP_SZ; i++) {
118 in[i] = strtok_r(str, &dlm[i], &sp);
119 if ((in[i] == NULL) || (errno != 0)) {
126 /* Convert/Copy each field as needed. */
127 procmap.va_start = strtoull(in[0], &end, 16);
128 if ((in[0] == '\0') || (end == NULL) || (*end != '\0') ||
134 procmap.len = strtoull(in[1], &end, 16);
135 if ((in[1] == '\0') || (end == NULL) || (*end != '\0') ||
141 procmap.pgoff = strtoull(in[3], &end, 16);
142 if ((in[3] == '\0') || (end == NULL) || (*end != '\0') ||
148 procmap.maj = strtoul(in[4], &end, 16);
149 if ((in[4] == '\0') || (end == NULL) || (*end != '\0') ||
155 procmap.min = strtoul(in[5], &end, 16);
156 if ((in[5] == '\0') || (end == NULL) || (*end != '\0') ||
162 procmap.ino = strtoul(in[6], &end, 16);
163 if ((in[6] == '\0') || (end == NULL) || (*end != '\0') ||
169 memcpy(&procmap.prot, in[2], PROT_SZ);
170 memcpy(&procmap.fname, in[7], PATH_MAX);
172 if (procmap.va_start == addr) {
173 procmap.len = procmap.len - procmap.va_start;
181 RTE_LOG(ERR, VHOST_CONFIG,
182 "(%"PRIu64") Failed to find memory file in pid %d maps file\n",
183 dev->device_fh, pid);
187 /* Find the guest memory file among the process fds. */
188 dp = opendir(procdir);
190 RTE_LOG(ERR, VHOST_CONFIG,
191 "(%"PRIu64") Cannot open pid %d process directory\n",
192 dev->device_fh, pid);
198 /* Read the fd directory contents. */
199 while (NULL != (dptr = readdir(dp))) {
200 snprintf(memfile, PATH_MAX, "/proc/%u/fd/%s",
202 path = realpath(memfile, resolved_path);
203 if ((path == NULL) && (strlen(resolved_path) == 0)) {
204 RTE_LOG(ERR, VHOST_CONFIG,
205 "(%"PRIu64") Failed to resolve fd directory\n",
210 if (strncmp(resolved_path, procmap.fname,
211 strnlen(procmap.fname, PATH_MAX)) == 0) {
220 RTE_LOG(ERR, VHOST_CONFIG,
221 "(%"PRIu64") Failed to find memory file for pid %d\n",
222 dev->device_fh, pid);
225 /* Open the shared memory file and map the memory into this process. */
226 fd = open(memfile, O_RDWR);
229 RTE_LOG(ERR, VHOST_CONFIG,
230 "(%"PRIu64") Failed to open %s for pid %d\n",
231 dev->device_fh, memfile, pid);
235 map = mmap(0, (size_t)procmap.len, PROT_READ|PROT_WRITE,
236 MAP_POPULATE|MAP_SHARED, fd, 0);
239 if (map == MAP_FAILED) {
240 RTE_LOG(ERR, VHOST_CONFIG,
241 "(%"PRIu64") Error mapping the file %s for pid %d\n",
242 dev->device_fh, memfile, pid);
246 /* Store the memory address and size in the device data structure */
247 mem->mapped_address = (uint64_t)(uintptr_t)map;
248 mem->mapped_size = procmap.len;
250 LOG_DEBUG(VHOST_CONFIG,
251 "(%"PRIu64") Mem File: %s->%s - Size: %llu - VA: %p\n",
253 memfile, resolved_path,
254 (unsigned long long)mem->mapped_size, map);