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 : :
45 : : #include "tapdisk.h"
46 : : #include "tapdisk-driver.h"
47 : : #include "tapdisk-interface.h"
48 : : #include "block-aio.h"
49 : :
50 : :
51 : :
52 : : /*Get Image size, secsize*/
53 : 0 : static int tdaio_get_image_info(int fd, td_disk_info_t *info)
54 : : {
55 : : int ret;
56 : : unsigned long long bytes;
57 : : struct stat stat;
58 : :
59 : 0 : ret = fstat(fd, &stat);
60 [ # # ]: 0 : if (ret != 0) {
61 : : DPRINTF("ERROR: fstat failed, Couldn't stat image");
62 : 0 : return -EINVAL;
63 : : }
64 : :
65 [ # # ]: 0 : if (S_ISBLK(stat.st_mode)) {
66 : : /*Accessing block device directly*/
67 : 0 : info->size = 0;
68 [ # # ]: 0 : if (ioctl(fd,BLKGETSIZE64,&bytes)==0) {
69 : 0 : info->size = bytes >> SECTOR_SHIFT;
70 [ # # ]: 0 : } else if (ioctl(fd,BLKGETSIZE,&info->size)!=0) {
71 : : DPRINTF("ERR: BLKGETSIZE and BLKGETSIZE64 failed, couldn't stat image");
72 : : return -EINVAL;
73 : : }
74 : :
75 : 0 : DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
76 : : "sector_shift [%llu]\n",
77 : : (long long unsigned)(info->size << SECTOR_SHIFT),
78 : : (long long unsigned)info->size);
79 : :
80 : : /*Get the sector size*/
81 : : #if defined(BLKSSZGET)
82 : : {
83 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
84 : 0 : ioctl(fd, BLKSSZGET, &info->sector_size);
85 : :
86 [ # # ]: 0 : if (info->sector_size != DEFAULT_SECTOR_SIZE)
87 : 0 : DPRINTF("Note: sector size is %ld (not %d)\n",
88 : : info->sector_size, DEFAULT_SECTOR_SIZE);
89 : : }
90 : : #else
91 : : info->sector_size = DEFAULT_SECTOR_SIZE;
92 : : #endif
93 : :
94 : : } else {
95 : : /*Local file? try fstat instead*/
96 : 0 : info->size = (stat.st_size >> SECTOR_SHIFT);
97 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
98 : 0 : DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
99 : : "sector_shift [%llu]\n",
100 : : (long long unsigned)(info->size << SECTOR_SHIFT),
101 : : (long long unsigned)info->size);
102 : : }
103 : :
104 [ # # ]: 0 : if (info->size == 0) {
105 : 0 : info->size =((uint64_t) 16836057);
106 : 0 : info->sector_size = DEFAULT_SECTOR_SIZE;
107 : : }
108 : 0 : info->info = 0;
109 : :
110 : 0 : return 0;
111 : : }
112 : :
113 : : /* Open the disk file and initialize aio state. */
114 : 0 : int tdaio_open(td_driver_t *driver, const char *name,
115 : : struct td_vbd_encryption *encryption, td_flag_t flags)
116 : : {
117 : : int i, fd, ret, o_flags;
118 : : struct tdaio_state *prv;
119 : :
120 : 0 : ret = 0;
121 : 0 : prv = (struct tdaio_state *)driver->data;
122 : :
123 : : DPRINTF("block-aio open('%s')", name);
124 : :
125 : : memset(prv, 0, sizeof(struct tdaio_state));
126 : :
127 : 0 : prv->aio_free_count = MAX_AIO_REQS;
128 [ # # ]: 0 : for (i = 0; i < MAX_AIO_REQS; i++)
129 : 0 : prv->aio_free_list[i] = &prv->aio_requests[i];
130 : :
131 : : /* Open the file */
132 [ # # ]: 0 : o_flags = O_DIRECT | O_LARGEFILE |
133 : 0 : ((flags & TD_OPEN_RDONLY) ? O_RDONLY : O_RDWR);
134 : 0 : fd = open(name, o_flags);
135 : :
136 [ # # ][ # # ]: 0 : if ( (fd == -1) && (errno == EINVAL) ) {
137 : :
138 : : /* Maybe O_DIRECT isn't supported. */
139 : 0 : o_flags &= ~O_DIRECT;
140 : 0 : fd = open(name, o_flags);
141 [ # # ]: 0 : if (fd != -1) DPRINTF("WARNING: Accessing image without"
142 : : "O_DIRECT! (%s)\n", name);
143 : :
144 [ # # ]: 0 : } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
145 : :
146 [ # # ]: 0 : if (fd == -1) {
147 : 0 : DPRINTF("Unable to open [%s] (%d)!\n", name, 0 - errno);
148 : 0 : ret = 0 - errno;
149 : 0 : goto done;
150 : : }
151 : :
152 : 0 : ret = tdaio_get_image_info(fd, &driver->info);
153 [ # # ]: 0 : if (ret) {
154 : 0 : close(fd);
155 : 0 : goto done;
156 : : }
157 : :
158 : 0 : prv->fd = fd;
159 : :
160 : : done:
161 : 0 : return ret;
162 : : }
163 : :
164 : 0 : void tdaio_complete(void *arg, struct tiocb *tiocb, int err)
165 : : {
166 : 0 : struct aio_request *aio = (struct aio_request *)arg;
167 : 0 : struct tdaio_state *prv = aio->state;
168 : :
169 : 0 : td_complete_request(aio->treq, err);
170 : 0 : prv->aio_free_list[prv->aio_free_count++] = aio;
171 : 0 : }
172 : :
173 : 0 : void tdaio_queue_read(td_driver_t *driver, td_request_t treq)
174 : : {
175 : : int size;
176 : : uint64_t offset;
177 : : struct aio_request *aio;
178 : : struct tdaio_state *prv;
179 : :
180 : 0 : prv = (struct tdaio_state *)driver->data;
181 : 0 : size = treq.secs * SECTOR_SIZE;
182 : 0 : offset = treq.sec * (uint64_t)SECTOR_SIZE;
183 : :
184 [ # # ]: 0 : if (prv->aio_free_count == 0)
185 : : goto fail;
186 : :
187 : 0 : aio = prv->aio_free_list[--prv->aio_free_count];
188 : 0 : aio->treq = treq;
189 : 0 : aio->state = prv;
190 : :
191 : 0 : td_prep_read(driver, &aio->tiocb, prv->fd, treq.buf,
192 : : size, offset, tdaio_complete, aio);
193 : 0 : td_queue_tiocb(driver, &aio->tiocb);
194 : :
195 : 0 : return;
196 : :
197 : : fail:
198 : 0 : td_complete_request(treq, -EBUSY);
199 : : }
200 : :
201 : 0 : void tdaio_queue_write(td_driver_t *driver, td_request_t treq)
202 : : {
203 : : int size;
204 : : uint64_t offset;
205 : : struct aio_request *aio;
206 : : struct tdaio_state *prv;
207 : :
208 : 0 : prv = (struct tdaio_state *)driver->data;
209 : 0 : size = treq.secs * driver->info.sector_size;
210 : 0 : offset = treq.sec * (uint64_t)driver->info.sector_size;
211 : :
212 [ # # ]: 0 : if (prv->aio_free_count == 0)
213 : : goto fail;
214 : :
215 : 0 : aio = prv->aio_free_list[--prv->aio_free_count];
216 : 0 : aio->treq = treq;
217 : 0 : aio->state = prv;
218 : :
219 : 0 : td_prep_write(driver, &aio->tiocb, prv->fd, treq.buf,
220 : : size, offset, tdaio_complete, aio);
221 : 0 : td_queue_tiocb(driver, &aio->tiocb);
222 : :
223 : 0 : return;
224 : :
225 : : fail:
226 : 0 : td_complete_request(treq, -EBUSY);
227 : : }
228 : :
229 : 0 : int tdaio_close(td_driver_t *driver)
230 : : {
231 : 0 : struct tdaio_state *prv = (struct tdaio_state *)driver->data;
232 : :
233 : 0 : close(prv->fd);
234 : :
235 : 0 : return 0;
236 : : }
237 : :
238 : 0 : int tdaio_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
239 : : {
240 : 0 : return TD_NO_PARENT;
241 : : }
242 : :
243 : 0 : int tdaio_validate_parent(td_driver_t *driver,
244 : : td_driver_t *pdriver, td_flag_t flags)
245 : : {
246 : 0 : return -EINVAL;
247 : : }
248 : :
249 : 0 : void tdaio_stats(td_driver_t *driver, td_stats_t *st)
250 : : {
251 : 0 : struct tdaio_state *prv = (struct tdaio_state *)driver->data;
252 : : int n_pending;
253 : :
254 : 0 : n_pending = MAX_AIO_REQS - prv->aio_free_count;
255 : :
256 : 0 : tapdisk_stats_field(st, "reqs", "{");
257 : 0 : tapdisk_stats_field(st, "max", "lu", MAX_AIO_REQS);
258 : 0 : tapdisk_stats_field(st, "pending", "d", n_pending);
259 : 0 : tapdisk_stats_leave(st, '}');
260 : 0 : }
261 : :
262 : : struct tap_disk tapdisk_aio = {
263 : : .disk_type = "tapdisk_aio",
264 : : .flags = 0,
265 : : .private_data_size = sizeof(struct tdaio_state),
266 : : .td_open = tdaio_open,
267 : : .td_close = tdaio_close,
268 : : .td_queue_read = tdaio_queue_read,
269 : : .td_queue_write = tdaio_queue_write,
270 : : .td_get_parent_id = tdaio_get_parent_id,
271 : : .td_validate_parent = tdaio_validate_parent,
272 : : .td_debug = NULL,
273 : : .td_stats = tdaio_stats,
274 : : };
|