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