source: mainline/uspace/srv/bd/file_bd/file_bd.c@ 1ee00b7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1ee00b7 was 1ee00b7, checked in by Jiri Svoboda <jiri@…>, 16 years ago

Revamp block device interface: (1) block size is fixed, determined by BDD. (2) block address is 64-bit, (3) allow reading/writing more blocks at a time.

  • Property mode set to 100644
File size: 5.3 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 <ipc/ipc.h>
44#include <ipc/bd.h>
45#include <async.h>
46#include <as.h>
47#include <fibril_sync.h>
48#include <devmap.h>
49#include <sys/types.h>
50#include <errno.h>
51#include <bool.h>
52#include <task.h>
53#include <macros.h>
54
55#define NAME "file_bd"
56
57static const size_t block_size = 512;
58static FILE *img;
59
60static dev_handle_t dev_handle;
61static fibril_mutex_t dev_lock;
62
63static int file_bd_init(const char *fname);
64static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
65static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf);
66static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
67
68int main(int argc, char **argv)
69{
70 int rc;
71
72 printf(NAME ": File-backed block device driver\n");
73
74 if (argc != 3) {
75 printf("Expected two arguments (image name, device name).\n");
76 return -1;
77 }
78
79 if (file_bd_init(argv[1]) != EOK)
80 return -1;
81
82 rc = devmap_device_register(argv[2], &dev_handle);
83 if (rc != EOK) {
84 devmap_hangup_phone(DEVMAP_DRIVER);
85 printf(NAME ": Unable to register device %s.\n",
86 argv[2]);
87 return rc;
88 }
89
90 printf(NAME ": Accepting connections\n");
91 task_retval(0);
92 async_manager();
93
94 /* Not reached */
95 return 0;
96}
97
98static int file_bd_init(const char *fname)
99{
100 int rc;
101
102 rc = devmap_driver_register(NAME, file_bd_connection);
103 if (rc < 0) {
104 printf(NAME ": Unable to register driver.\n");
105 return rc;
106 }
107
108 img = fopen(fname, "rb+");
109 if (img == NULL)
110 return EINVAL;
111
112 fibril_mutex_initialize(&dev_lock);
113
114 return EOK;
115}
116
117static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
118{
119 void *fs_va = NULL;
120 ipc_callid_t callid;
121 ipc_call_t call;
122 ipcarg_t method;
123 size_t comm_size;
124 int flags;
125 int retval;
126 uint64_t ba;
127 size_t cnt;
128
129 /* Answer the IPC_M_CONNECT_ME_TO call. */
130 ipc_answer_0(iid, EOK);
131
132 if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
133 ipc_answer_0(callid, EHANGUP);
134 return;
135 }
136
137 fs_va = as_get_mappable_page(comm_size);
138 if (fs_va == NULL) {
139 ipc_answer_0(callid, EHANGUP);
140 return;
141 }
142
143 (void) ipc_share_out_finalize(callid, fs_va);
144
145 while (1) {
146 callid = async_get_call(&call);
147 method = IPC_GET_METHOD(call);
148 switch (method) {
149 case IPC_M_PHONE_HUNGUP:
150 /* The other side has hung up. */
151 ipc_answer_0(callid, EOK);
152 return;
153 case BD_READ_BLOCKS:
154 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
155 IPC_GET_ARG2(call));
156 cnt = IPC_GET_ARG3(call);
157 if (cnt * block_size > comm_size) {
158 retval = ELIMIT;
159 break;
160 }
161 retval = file_bd_read_blocks(ba, cnt, fs_va);
162 break;
163 case BD_WRITE_BLOCKS:
164 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
165 IPC_GET_ARG2(call));
166 cnt = IPC_GET_ARG3(call);
167 if (cnt * block_size > comm_size) {
168 retval = ELIMIT;
169 break;
170 }
171 retval = file_bd_write_blocks(ba, cnt, fs_va);
172 break;
173 case BD_GET_BLOCK_SIZE:
174 ipc_answer_1(callid, EOK, block_size);
175 continue;
176 default:
177 retval = EINVAL;
178 break;
179 }
180 ipc_answer_0(callid, retval);
181 }
182}
183
184/** Read blocks from the device. */
185static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf)
186{
187 size_t n_rd;
188
189 fibril_mutex_lock(&dev_lock);
190
191 fseek(img, ba * block_size, SEEK_SET);
192 n_rd = fread(buf, block_size, cnt, img);
193
194 if (ferror(img)) {
195 fibril_mutex_unlock(&dev_lock);
196 return EIO; /* Read error */
197 }
198
199 fibril_mutex_unlock(&dev_lock);
200
201 if (n_rd < cnt)
202 return EINVAL; /* Read beyond end of device */
203
204 return EOK;
205}
206
207/** Write blocks to the device. */
208static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
209{
210 size_t n_wr;
211
212 fibril_mutex_lock(&dev_lock);
213
214 fseek(img, ba * block_size, SEEK_SET);
215 n_wr = fread(buf, block_size, cnt, img);
216
217 if (ferror(img) || n_wr < cnt) {
218 fibril_mutex_unlock(&dev_lock);
219 return EIO; /* Write error */
220 }
221
222 fibril_mutex_unlock(&dev_lock);
223
224 return EOK;
225}
226
227/**
228 * @}
229 */
Note: See TracBrowser for help on using the repository browser.