Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <errno.h>
36 : : #include <fcntl.h>
37 : : #include <stdio.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <sys/statvfs.h>
41 : : #include <sys/stat.h>
42 : : #include <sys/ioctl.h>
43 : : #include <linux/fs.h>
44 : : #include <string.h>
45 : :
46 : : #include "tapdisk.h"
47 : : #include "tapdisk-driver.h"
48 : : #include "tapdisk-interface.h"
49 : :
50 : : void *img;
51 : : long int disksector_size;
52 : : long int disksize;
53 : : long int diskinfo;
54 : : static int connections = 0;
55 : :
56 : : struct tdram_state {
57 : : int fd;
58 : : };
59 : :
60 : : /*Get Image size, secsize*/
61 : 0 : static int get_image_info(int fd, td_disk_info_t *info)
62 : : {
63 : : int ret;
64 : : struct stat stat;
65 : :
66 : 0 : ret = fstat(fd, &stat);
67 [ # # ]: 0 : if (ret != 0) {
68 : : DPRINTF("ERROR: fstat failed, Couldn't stat image");
69 : 0 : return -EINVAL;
70 : : }
71 : :
72 [ # # ]: 0 : if (S_ISBLK(stat.st_mode)) {
73 : : /*Accessing block device directly*/
74 : 0 : info->size = 0;
75 [ # # ]: 0 : if (ioctl(fd,BLKGETSIZE,&info->size)!=0) {
76 : : DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
77 : : return -EINVAL;
78 : : }
79 : :
80 : 0 : DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
81 : : "sector_shift [%llu]\n",
82 : : (long long unsigned)(info->size << SECTOR_SHIFT),
83 : : (long long unsigned)info->size);
84 : :
85 : : /*Get the sector size*/
86 : : #if defined(BLKSSZGET)
87 : : {
88 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
89 : 0 : ioctl(fd, BLKSSZGET, &info->sector_size);
90 : :
91 [ # # ]: 0 : if (info->sector_size != DEFAULT_SECTOR_SIZE)
92 : 0 : DPRINTF("Note: sector size is %ld (not %d)\n",
93 : : info->sector_size, DEFAULT_SECTOR_SIZE);
94 : : }
95 : : #else
96 : : info->sector_size = DEFAULT_SECTOR_SIZE;
97 : : #endif
98 : :
99 : : } else {
100 : : /*Local file? try fstat instead*/
101 : 0 : info->size = (stat.st_size >> SECTOR_SHIFT);
102 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
103 : 0 : DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
104 : : "sector_shift [%llu]\n",
105 : : (long long unsigned)(info->size << SECTOR_SHIFT),
106 : : (long long unsigned)info->size);
107 : : }
108 : :
109 [ # # ]: 0 : if (info->size == 0) {
110 : 0 : info->size =((uint64_t) MAX_RAMDISK_SIZE);
111 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
112 : : }
113 : 0 : info->info = 0;
114 : :
115 : : /*Store variables locally*/
116 : 0 : disksector_size = info->sector_size;
117 : 0 : disksize = info->size;
118 : 0 : diskinfo = info->info;
119 : 0 : DPRINTF("Image sector_size: \n\t[%lu]\n",
120 : : info->sector_size);
121 : :
122 : : return 0;
123 : : }
124 : :
125 : : /* Open the disk file and initialize ram state. */
126 : 0 : int tdram_open (td_driver_t *driver, const char *name,
127 : : struct td_vbd_encryption *encryption, td_flag_t flags)
128 : : {
129 : : char *p;
130 : : uint64_t size;
131 : 0 : int i, fd, ret = 0, count = 0, o_flags;
132 : 0 : struct tdram_state *prv = (struct tdram_state *)driver->data;
133 : :
134 : 0 : connections++;
135 : :
136 [ # # ]: 0 : if (connections > 1) {
137 : 0 : driver->info.sector_size = disksector_size;
138 : 0 : driver->info.size = disksize;
139 : 0 : driver->info.info = diskinfo;
140 : : DPRINTF("Image already open, returning parameters:\n");
141 : 0 : DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
142 : : "sector_shift [%llu]\n",
143 : : (long long unsigned)(driver->info.size << SECTOR_SHIFT),
144 : : (long long unsigned)driver->info.size);
145 : 0 : DPRINTF("Image sector_size: \n\t[%lu]\n",
146 : : driver->info.sector_size);
147 : :
148 : 0 : prv->fd = -1;
149 : 0 : goto done;
150 : : }
151 : :
152 : : /* Open the file */
153 [ # # ]: 0 : o_flags = O_DIRECT | O_LARGEFILE |
154 : : ((flags == TD_OPEN_RDONLY) ? O_RDONLY : O_RDWR);
155 : 0 : fd = open(name, o_flags);
156 : :
157 [ # # ][ # # ]: 0 : if ((fd == -1) && (errno == EINVAL)) {
158 : :
159 : : /* Maybe O_DIRECT isn't supported. */
160 : 0 : o_flags &= ~O_DIRECT;
161 : 0 : fd = open(name, o_flags);
162 [ # # ]: 0 : if (fd != -1) DPRINTF("WARNING: Accessing image without"
163 : : "O_DIRECT! (%s)\n", name);
164 : :
165 [ # # ]: 0 : } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
166 : :
167 [ # # ]: 0 : if (fd == -1) {
168 : : DPRINTF("Unable to open [%s]!\n",name);
169 : 0 : ret = 0 - errno;
170 : 0 : goto done;
171 : : }
172 : :
173 : 0 : prv->fd = fd;
174 : :
175 : 0 : ret = get_image_info(fd, &driver->info);
176 : 0 : size = MAX_RAMDISK_SIZE;
177 : :
178 [ # # ]: 0 : if (driver->info.size > size) {
179 : : DPRINTF("Disk exceeds limit, must be less than [%d]MB",
180 : : (MAX_RAMDISK_SIZE<<SECTOR_SHIFT)>>20);
181 : 0 : return -ENOMEM;
182 : : }
183 : :
184 : : /*Read the image into memory*/
185 [ # # ]: 0 : if (posix_memalign(&img, DEFAULT_SECTOR_SIZE,
186 : : driver->info.size << SECTOR_SHIFT)) {
187 : : DPRINTF("Mem malloc failed\n");
188 : 0 : return -errno;
189 : : }
190 : 0 : p = img;
191 : 0 : DPRINTF("Reading %llu bytes.......",
192 : : (long long unsigned)driver->info.size << SECTOR_SHIFT);
193 : :
194 [ # # ]: 0 : for (i = 0; i < driver->info.size; i++) {
195 : 0 : ret = read(prv->fd, p, driver->info.sector_size);
196 [ # # ]: 0 : if (ret != driver->info.sector_size) {
197 : 0 : DPRINTF("ret = %d, errno = %d\n", ret, errno);
198 : 0 : ret = 0 - errno;
199 : 0 : break;
200 : : } else {
201 : 0 : count += ret;
202 : 0 : p = img + count;
203 : : }
204 : : }
205 : : DPRINTF("[%d]\n",count);
206 [ # # ]: 0 : if (count != driver->info.size << SECTOR_SHIFT) {
207 : : ret = -1;
208 : : } else {
209 : 0 : ret = 0;
210 : : }
211 : :
212 : : done:
213 : 0 : return ret;
214 : : }
215 : :
216 : 0 : void tdram_queue_read(td_driver_t *driver, td_request_t treq)
217 : : {
218 : 0 : int size = treq.secs * driver->info.sector_size;
219 : 0 : uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
220 : :
221 : 0 : memcpy(treq.buf, img + offset, size);
222 : :
223 : 0 : td_complete_request(treq, 0);
224 : 0 : }
225 : :
226 : 0 : void tdram_queue_write(td_driver_t *driver, td_request_t treq)
227 : : {
228 : 0 : int size = treq.secs * driver->info.sector_size;
229 : 0 : uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
230 : :
231 : : /* We assume that write access is controlled
232 : : * at a higher level for multiple disks */
233 : 0 : memcpy(img + offset, treq.buf, size);
234 : :
235 : 0 : td_complete_request(treq, 0);
236 : 0 : }
237 : :
238 : 0 : int tdram_close(td_driver_t *driver)
239 : : {
240 : 0 : connections--;
241 : :
242 : 0 : return 0;
243 : : }
244 : :
245 : 0 : int tdram_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
246 : : {
247 : 0 : return TD_NO_PARENT;
248 : : }
249 : :
250 : 0 : int tdram_validate_parent(td_driver_t *driver,
251 : : td_driver_t *pdriver, td_flag_t flags)
252 : : {
253 : 0 : return -EINVAL;
254 : : }
255 : :
256 : : struct tap_disk tapdisk_ram = {
257 : : .disk_type = "tapdisk_ram",
258 : : .flags = 0,
259 : : .private_data_size = sizeof(struct tdram_state),
260 : : .td_open = tdram_open,
261 : : .td_close = tdram_close,
262 : : .td_queue_read = tdram_queue_read,
263 : : .td_queue_write = tdram_queue_write,
264 : : .td_get_parent_id = tdram_get_parent_id,
265 : : .td_validate_parent = tdram_validate_parent,
266 : : .td_debug = NULL,
267 : : };
|