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