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

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

gradually introduce async ports, initial phase

The initial phase is to reimplement the traditional async client connections as an untyped fallback port. This creates the possibility to introduce ports typed by interface type gradually in later changesets.

  • Property mode set to 100644
File size: 7.0 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 <unistd.h>
43#include <async.h>
44#include <as.h>
45#include <bd_srv.h>
46#include <fibril_synch.h>
47#include <loc.h>
48#include <sys/types.h>
49#include <sys/typefmt.h>
50#include <errno.h>
51#include <stdbool.h>
52#include <task.h>
53#include <macros.h>
54
55#define NAME "file_bd"
56
57#define DEFAULT_BLOCK_SIZE 512
58
59static size_t block_size;
60static aoff64_t num_blocks;
61static FILE *img;
62
63static service_id_t service_id;
64static bd_srvs_t bd_srvs;
65static fibril_mutex_t dev_lock;
66
67static void print_usage(void);
68static int file_bd_init(const char *fname);
69static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
70
71static int file_bd_open(bd_srvs_t *, bd_srv_t *);
72static int file_bd_close(bd_srv_t *);
73static int file_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
74static int file_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
75static int file_bd_get_block_size(bd_srv_t *, size_t *);
76static int file_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
77
78static bd_ops_t file_bd_ops = {
79 .open = file_bd_open,
80 .close = file_bd_close,
81 .read_blocks = file_bd_read_blocks,
82 .write_blocks = file_bd_write_blocks,
83 .get_block_size = file_bd_get_block_size,
84 .get_num_blocks = file_bd_get_num_blocks
85};
86
87int main(int argc, char **argv)
88{
89 int rc;
90 char *image_name;
91 char *device_name;
92
93 printf(NAME ": File-backed block device driver\n");
94
95 block_size = DEFAULT_BLOCK_SIZE;
96
97 ++argv; --argc;
98 while (*argv != NULL && (*argv)[0] == '-') {
99 /* Option */
100 if (str_cmp(*argv, "-b") == 0) {
101 if (argc < 2) {
102 printf("Argument missing.\n");
103 print_usage();
104 return -1;
105 }
106
107 rc = str_size_t(argv[1], NULL, 10, true, &block_size);
108 if (rc != EOK || block_size == 0) {
109 printf("Invalid block size '%s'.\n", argv[1]);
110 print_usage();
111 return -1;
112 }
113 ++argv; --argc;
114 } else {
115 printf("Invalid option '%s'.\n", *argv);
116 print_usage();
117 return -1;
118 }
119 ++argv; --argc;
120 }
121
122 if (argc < 2) {
123 printf("Missing arguments.\n");
124 print_usage();
125 return -1;
126 }
127
128 image_name = argv[0];
129 device_name = argv[1];
130
131 if (file_bd_init(image_name) != EOK)
132 return -1;
133
134 rc = loc_service_register(device_name, &service_id);
135 if (rc != EOK) {
136 printf("%s: Unable to register device '%s'.\n",
137 NAME, device_name);
138 return rc;
139 }
140
141 printf("%s: Accepting connections\n", NAME);
142 task_retval(0);
143 async_manager();
144
145 /* Not reached */
146 return 0;
147}
148
149static void print_usage(void)
150{
151 printf("Usage: " NAME " [-b <block_size>] <image_file> <device_name>\n");
152}
153
154static int file_bd_init(const char *fname)
155{
156 bd_srvs_init(&bd_srvs);
157 bd_srvs.ops = &file_bd_ops;
158
159 async_set_fallback_port_handler(file_bd_connection, NULL);
160 int rc = loc_server_register(NAME);
161 if (rc != EOK) {
162 printf("%s: Unable to register driver.\n", NAME);
163 return rc;
164 }
165
166 img = fopen(fname, "rb+");
167 if (img == NULL)
168 return EINVAL;
169
170 if (fseek(img, 0, SEEK_END) != 0) {
171 fclose(img);
172 return EIO;
173 }
174
175 off64_t img_size = ftell(img);
176 if (img_size < 0) {
177 fclose(img);
178 return EIO;
179 }
180
181 num_blocks = img_size / block_size;
182
183 fibril_mutex_initialize(&dev_lock);
184
185 return EOK;
186}
187
188static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
189{
190 bd_conn(iid, icall, &bd_srvs);
191}
192
193/** Open device. */
194static int file_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
195{
196 return EOK;
197}
198
199/** Close device. */
200static int file_bd_close(bd_srv_t *bd)
201{
202 return EOK;
203}
204
205/** Read blocks from the device. */
206static int file_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
207 size_t size)
208{
209 size_t n_rd;
210 int rc;
211
212 if (size < cnt * block_size)
213 return EINVAL;
214
215 /* Check whether access is within device address bounds. */
216 if (ba + cnt > num_blocks) {
217 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
218 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
219 num_blocks - 1);
220 return ELIMIT;
221 }
222
223 fibril_mutex_lock(&dev_lock);
224
225 clearerr(img);
226 rc = fseek(img, ba * block_size, SEEK_SET);
227 if (rc < 0) {
228 fibril_mutex_unlock(&dev_lock);
229 return EIO;
230 }
231
232 n_rd = fread(buf, block_size, cnt, img);
233
234 if (ferror(img)) {
235 fibril_mutex_unlock(&dev_lock);
236 return EIO; /* Read error */
237 }
238
239 fibril_mutex_unlock(&dev_lock);
240
241 if (n_rd < cnt)
242 return EINVAL; /* Read beyond end of device */
243
244 return EOK;
245}
246
247/** Write blocks to the device. */
248static int file_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
249 const void *buf, size_t size)
250{
251 size_t n_wr;
252 int rc;
253
254 if (size < cnt * block_size)
255 return EINVAL;
256
257 /* Check whether access is within device address bounds. */
258 if (ba + cnt > num_blocks) {
259 printf(NAME ": Accessed blocks %" PRIuOFF64 "-%" PRIuOFF64 ", while "
260 "max block number is %" PRIuOFF64 ".\n", ba, ba + cnt - 1,
261 num_blocks - 1);
262 return ELIMIT;
263 }
264
265 fibril_mutex_lock(&dev_lock);
266
267 clearerr(img);
268 rc = fseek(img, ba * block_size, SEEK_SET);
269 if (rc < 0) {
270 fibril_mutex_unlock(&dev_lock);
271 return EIO;
272 }
273
274 n_wr = fwrite(buf, block_size, cnt, img);
275
276 if (ferror(img) || n_wr < cnt) {
277 fibril_mutex_unlock(&dev_lock);
278 return EIO; /* Write error */
279 }
280
281 if (fflush(img) != 0) {
282 fibril_mutex_unlock(&dev_lock);
283 return EIO;
284 }
285
286 fibril_mutex_unlock(&dev_lock);
287
288 return EOK;
289}
290
291/** Get device block size. */
292static int file_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
293{
294 *rsize = block_size;
295 return EOK;
296}
297
298/** Get number of blocks on device. */
299static int file_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
300{
301 *rnb = num_blocks;
302 return EOK;
303}
304
305/**
306 * @}
307 */
Note: See TracBrowser for help on using the repository browser.