1 /*
2 * Copyright (c) 2008, 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 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #ifdef MEMSHR
32 #include <memshr.h>
33 #endif
34
35 #include "tapdisk-image.h"
36 #include "tapdisk-driver.h"
37 #include "tapdisk-server.h"
38
39 #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
40
41 td_image_t *
tapdisk_image_allocate(const char * file,int type,int storage,td_flag_t flags,void * private)42 tapdisk_image_allocate(const char *file, int type, int storage,
43 td_flag_t flags, void *private)
44 {
45 int err;
46 td_image_t *image;
47
48 image = calloc(1, sizeof(td_image_t));
49 if (!image)
50 return NULL;
51
52 err = tapdisk_namedup(&image->name, file);
53 if (err) {
54 free(image);
55 return NULL;
56 }
57
58 image->type = type;
59 image->flags = flags;
60 image->storage = storage;
61 image->private = private;
62 #ifdef MEMSHR
63 image->memshr_id = memshr_vbd_image_get(file);
64 #endif
65 INIT_LIST_HEAD(&image->next);
66
67 return image;
68 }
69
70 void
tapdisk_image_free(td_image_t * image)71 tapdisk_image_free(td_image_t *image)
72 {
73 if (!image)
74 return;
75
76 list_del(&image->next);
77
78 #ifdef MEMSHR
79 memshr_vbd_image_put(image->memshr_id);
80 #endif
81 free(image->name);
82 tapdisk_driver_free(image->driver);
83 free(image);
84 }
85
86 int
tapdisk_image_check_td_request(td_image_t * image,td_request_t treq)87 tapdisk_image_check_td_request(td_image_t *image, td_request_t treq)
88 {
89 int rdonly;
90 td_driver_t *driver;
91 td_disk_info_t *info;
92
93 driver = image->driver;
94 if (!driver)
95 return -ENODEV;
96
97 info = &driver->info;
98 rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
99
100 if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE)
101 goto fail;
102
103 if (treq.op == TD_OP_WRITE && rdonly)
104 goto fail;
105
106 if (treq.secs <= 0 || treq.sec + treq.secs > info->size)
107 goto fail;
108
109 return 0;
110
111 fail:
112 ERR(-EINVAL, "bad td request on %s (%s, %"PRIu64"): %d at %"PRIu64,
113 image->name, (rdonly ? "ro" : "rw"), info->size, treq.op,
114 treq.sec + treq.secs);
115 return -EINVAL;
116
117 }
118
119 int
tapdisk_image_check_ring_request(td_image_t * image,blkif_request_t * req)120 tapdisk_image_check_ring_request(td_image_t *image, blkif_request_t *req)
121 {
122 td_driver_t *driver;
123 td_disk_info_t *info;
124 int i, psize, rdonly;
125 uint64_t nsects, total;
126
127 driver = image->driver;
128 if (!driver)
129 return -ENODEV;
130
131 nsects = 0;
132 total = 0;
133 info = &driver->info;
134
135 rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
136
137 if (req->operation != BLKIF_OP_READ &&
138 req->operation != BLKIF_OP_WRITE)
139 goto fail;
140
141 if (req->operation == BLKIF_OP_WRITE && rdonly)
142 goto fail;
143
144 if (!req->nr_segments || req->nr_segments > MAX_SEGMENTS_PER_REQ)
145 goto fail;
146
147 total = 0;
148 psize = getpagesize();
149
150 for (i = 0; i < req->nr_segments; i++) {
151 nsects = req->seg[i].last_sect - req->seg[i].first_sect + 1;
152
153 if (req->seg[i].last_sect >= psize >> 9 || nsects <= 0)
154 goto fail;
155
156 total += nsects;
157 }
158
159 if (req->sector_number + nsects > info->size)
160 goto fail;
161
162 return 0;
163
164 fail:
165 ERR(-EINVAL, "bad request on %s (%s, %"PRIu64"): id: %"PRIu64": %d at %"PRIu64,
166 image->name, (rdonly ? "ro" : "rw"), info->size, req->id,
167 req->operation, req->sector_number + total);
168 return -EINVAL;
169 }
170