source: mainline/uspace/srv/bd/file_bd/file_bd.c@ e7c6250

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e7c6250 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2009 Jiri Svoboda
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
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - 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 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bd
30 * @{
31 */
32
33/**
34 * @file
35 * @brief File-backed block device driver
36 *
37 * Allows accessing a file as a block device. Useful for, e.g., mounting
38 * a disk image.
39 */
40
41#include <stdio.h>
42#include <async.h>
43#include <as.h>
44#include <bd_srv.h>
45#include <fibril_synch.h>
46#include <loc.h>
47#include <stddef.h>
48#include <stdint.h>
49#include <errno.h>
50#include <str_error.h>
51#include <stdbool.h>
52#include <task.h>
53#include <macros.h>
54#include <str.h>
55
56#define NAME "file_bd"
57
58#define DEFAULT_BLOCK_SIZE 512
59
60static size_t block_size;
61static aoff64_t num_blocks;
62static FILE *img;
63
64static service_id_t service_id;
65static bd_srvs_t bd_srvs;
66static fibril_mutex_t dev_lock;
67
68static void print_usage(void);
69static errno_t file_bd_init(const char *fname);
70static void file_bd_connection(ipc_call_t *icall, void *);
71
72static errno_t file_bd_open(bd_srvs_t *, bd_srv_t *);
73static errno_t file_bd_close(bd_srv_t *);
74static errno_t file_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
75static errno_t file_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
76static errno_t file_bd_get_block_size(bd_srv_t *, size_t *);
77static errno_t file_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
78
79static bd_ops_t file_bd_ops = {
80 .open = file_bd_open,
81 .close = file_bd_close,
82 .read_blocks = file_bd_read_blocks,
83 .write_blocks = file_bd_write_blocks,
84 .get_block_size = file_bd_get_block_size,
85 .get_num_blocks = file_bd_get_num_blocks
86};
87
88int main(int argc, char **argv)
89{
90 errno_t rc;
91 char *image_name;
92 char *device_name;
93 category_id_t disk_cat;
94
95 printf(NAME ": File-backed block device driver\n");
96
97 block_size = DEFAULT_BLOCK_SIZE;
98
99 ++argv;
100 --argc;
101 while (*argv != NULL && (*argv)[0] == '-') {
102 /* Option */
103 if (str_cmp(*argv, "-b") == 0) {
104 if (argc < 2) {
105 printf("Argument missing.\n");
106 print_usage();
107 return -1;
108 }
109
110 rc = str_size_t(argv[1], NULL, 10, true, &block_size);
111 if (rc != EOK || block_size == 0) {
112 printf("Invalid block size '%s'.\n", argv[1]);
113 print_usage();
114 return -1;
115 }
116 ++argv;
117 --argc;
118 } else {
119 printf("Invalid option '%s'.\n", *argv);
120 print_usage();
121 return -1;
122 }
123 ++argv;
124 --argc;
125 }
126
127 if (argc < 2) {
128 printf("Missing arguments.\n");
129 print_usage();
130 return -1;
131 }
132
133 image_name = argv[0];
134 device_name = argv[1];
135
136 if (file_bd_init(image_name) != EOK)
137 return -1;
138
139 rc = loc_service_register(device_name, &service_id);
140 if (rc != EOK) {
141 printf("%s: Unable to register device '%s': %s.\n",
142 NAME, device_name, str_error(rc));
143 return rc;
144 }
145
146 rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
147 if (rc != EOK) {
148 printf("%s: Failed resolving category 'disk': %s\n", NAME, str_error(rc));
149 return rc;
150 }
151
152 rc = loc_service_add_to_cat(service_id, disk_cat);
153 if (rc != EOK) {
154 printf("%s: Failed adding %s to category: %s",
155 NAME, device_name, str_error(rc));
156 return rc;
157 }
158
159 printf("%s: Accepting connections\n", NAME);
160 task_retval(0);
161 async_manager();
162
163 /* Not reached */
164 return 0;
165}
166
167static void print_usage(void)
168{
169 printf("Usage: " NAME " [-b <block_size>] <image_file> <device_name>\n");
170}
171
172static errno_t file_bd_init(const char *fname)
173{
174 bd_srvs_init(&bd_srvs);
175 bd_srvs.ops = &file_bd_ops;
176
177 async_set_fallback_port_handler(file_bd_connection, NULL);
178 errno_t rc = loc_server_register(NAME);
179 if (rc != EOK) {
180 printf("%s: Unable to register driver.\n", NAME);
181 return rc;
182 }
183
184 img = fopen(fname, "rb+");
185 if (img == NULL)
186 return EINVAL;
187
188 if (fseek(img, 0, SEEK_END) != 0) {
189 fclose(img);
190 return EIO;
191 }
192
193 off64_t img_size = ftell(img);
194 if (img_size < 0) {
195 fclose(img);
196 return EIO;
197 }
198
199 num_blocks = img_size / block_size;
200
201 fibril_mutex_initialize(&dev_lock);
202
203 return EOK;
204}
205
206static void file_bd_connection(ipc_call_t *icall, void *arg)
207{
208 bd_conn(icall, &bd_srvs);
209}
210
211/** Open device. */
212static errno_t file_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
213{
214 return EOK;
215}
216
217/** Close device. */
218static errno_t file_bd_close(bd_srv_t *bd)
219{
220 return EOK;
221}
222
223/** Read blocks from the device. */
224static errno_t file_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
225 size_t size)
226{
227 size_t n_rd;
228
229 if (size < cnt * block_size)
230 return EINVAL;
231
232 /* Check whether access is within device address bounds. */
233 if (ba + cnt > num_blocks) {
234 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
235 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
236 num_blocks - 1);
237 return ELIMIT;
238 }
239
240 fibril_mutex_lock(&dev_lock);
241
242 clearerr(img);
243 if (fseek(img, ba * block_size, SEEK_SET) < 0) {
244 fibril_mutex_unlock(&dev_lock);
245 return EIO;
246 }
247
248 n_rd = fread(buf, block_size, cnt, img);
249
250 if (ferror(img)) {
251 fibril_mutex_unlock(&dev_lock);
252 return EIO; /* Read error */
253 }
254
255 fibril_mutex_unlock(&dev_lock);
256
257 if (n_rd < cnt)
258 return EINVAL; /* Read beyond end of device */
259
260 return EOK;
261}
262
263/** Write blocks to the device. */
264static errno_t file_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
265 const void *buf, size_t size)
266{
267 size_t n_wr;
268
269 if (size < cnt * block_size)
270 return EINVAL;
271
272 /* Check whether access is within device address bounds. */
273 if (ba + cnt > num_blocks) {
274 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
275 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
276 num_blocks - 1);
277 return ELIMIT;
278 }
279
280 fibril_mutex_lock(&dev_lock);
281
282 clearerr(img);
283 if (fseek(img, ba * block_size, SEEK_SET) < 0) {
284 fibril_mutex_unlock(&dev_lock);
285 return EIO;
286 }
287
288 n_wr = fwrite(buf, block_size, cnt, img);
289
290 if (ferror(img) || n_wr < cnt) {
291 fibril_mutex_unlock(&dev_lock);
292 return EIO; /* Write error */
293 }
294
295 if (fflush(img) != 0) {
296 fibril_mutex_unlock(&dev_lock);
297 return EIO;
298 }
299
300 fibril_mutex_unlock(&dev_lock);
301
302 return EOK;
303}
304
305/** Get device block size. */
306static errno_t file_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
307{
308 *rsize = block_size;
309 return EOK;
310}
311
312/** Get number of blocks on device. */
313static errno_t file_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
314{
315 *rnb = num_blocks;
316 return EOK;
317}
318
319/**
320 * @}
321 */
Note: See TracBrowser for help on using the repository browser.