source: mainline/uspace/lib/libblock/libblock.c@ 6284978

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6284978 was 6284978, checked in by Jakub Jermar <jakub@…>, 18 years ago

Separate the block_init() phase from reading of the boot block.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2008 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libblock
31 * @{
32 */
33/**
34 * @file
35 * @brief
36 */
37
38#include "libblock.h"
39#include "../../srv/vfs/vfs.h"
40#include "../../srv/rd/rd.h"
41#include <ipc/devmap.h>
42#include <ipc/services.h>
43#include <errno.h>
44#include <sys/mman.h>
45#include <async.h>
46#include <ipc/ipc.h>
47#include <as.h>
48#include <assert.h>
49#include <futex.h>
50#include <libadt/list.h>
51
52/** Lock protecting the device connection list */
53static futex_t dcl_lock = FUTEX_INITIALIZER;
54/** Device connection list head. */
55static LIST_INITIALIZE(dcl_head);
56
57typedef struct {
58 link_t link;
59 int dev_handle;
60 int dev_phone;
61 void *com_area;
62 size_t com_size;
63 void *bb_buf;
64 off_t bb_off;
65 size_t bb_size;
66} devcon_t;
67
68static devcon_t *devcon_search(dev_handle_t dev_handle)
69{
70 link_t *cur;
71
72 futex_down(&dcl_lock);
73 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
74 devcon_t *devcon = list_get_instance(cur, devcon_t, link);
75 if (devcon->dev_handle == dev_handle) {
76 futex_up(&dcl_lock);
77 return devcon;
78 }
79 }
80 futex_up(&dcl_lock);
81 return NULL;
82}
83
84static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area,
85 size_t com_size)
86{
87 link_t *cur;
88 devcon_t *devcon;
89
90 devcon = malloc(sizeof(devcon_t));
91 if (!devcon)
92 return ENOMEM;
93
94 link_initialize(&devcon->link);
95 devcon->dev_handle = dev_handle;
96 devcon->dev_phone = dev_phone;
97 devcon->com_area = com_area;
98 devcon->com_size = com_size;
99 devcon->bb_buf = NULL;
100 devcon->bb_off = 0;
101 devcon->bb_size = 0;
102
103 futex_down(&dcl_lock);
104 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
105 devcon_t *d = list_get_instance(cur, devcon_t, link);
106 if (d->dev_handle == dev_handle) {
107 futex_up(&dcl_lock);
108 free(devcon);
109 return EEXIST;
110 }
111 }
112 list_append(&devcon->link, &dcl_head);
113 futex_up(&dcl_lock);
114 return EOK;
115}
116
117static void devcon_remove(devcon_t *devcon)
118{
119 futex_down(&dcl_lock);
120 list_remove(&devcon->link);
121 futex_up(&dcl_lock);
122}
123
124int block_init(dev_handle_t dev_handle, size_t com_size)
125{
126 int rc;
127 int dev_phone;
128 void *com_area;
129
130 com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
131 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
132 if (!com_area) {
133 return ENOMEM;
134 }
135 dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
136 DEVMAP_CONNECT_TO_DEVICE, dev_handle);
137
138 if (dev_phone < 0) {
139 munmap(com_area, com_size);
140 return dev_phone;
141 }
142
143 rc = ipc_share_out_start(dev_phone, com_area,
144 AS_AREA_READ | AS_AREA_WRITE);
145 if (rc != EOK) {
146 munmap(com_area, com_size);
147 ipc_hangup(dev_phone);
148 return rc;
149 }
150
151 rc = devcon_add(dev_handle, dev_phone, com_area, com_size);
152 if (rc != EOK) {
153 munmap(com_area, com_size);
154 ipc_hangup(dev_phone);
155 return rc;
156 }
157
158 return EOK;
159}
160
161void block_fini(dev_handle_t dev_handle)
162{
163 devcon_t *devcon = devcon_search(dev_handle);
164 assert(devcon);
165
166 devcon_remove(devcon);
167
168 if (devcon->bb_buf)
169 free(devcon->bb_buf);
170 munmap(devcon->com_area, devcon->com_size);
171 ipc_hangup(devcon->dev_phone);
172
173 free(devcon);
174}
175
176int block_bb_read(dev_handle_t dev_handle, off_t off, size_t size)
177{
178 void *bb_buf;
179
180 devcon_t *devcon = devcon_search(dev_handle);
181 if (!devcon)
182 return ENOENT;
183 if (devcon->bb_buf)
184 return EEXIST;
185 bb_buf = malloc(size);
186 if (!bb_buf)
187 return ENOMEM;
188
189 off_t bufpos = 0;
190 size_t buflen = 0;
191 if (!block_read(dev_handle, &bufpos, &buflen, &off,
192 bb_buf, size, size)) {
193 free(bb_buf);
194 return EIO; /* XXX real error code */
195 }
196 devcon->bb_buf = bb_buf;
197 devcon->bb_off = off;
198 devcon->bb_size = size;
199
200 return EOK;
201}
202
203void *block_bb_get(dev_handle_t dev_handle)
204{
205 devcon_t *devcon = devcon_search(dev_handle);
206 assert(devcon);
207 return devcon->bb_buf;
208}
209
210/** Read data from a block device.
211 *
212 * @param dev_handle Device handle of the block device.
213 * @param bufpos Pointer to the first unread valid offset within the
214 * communication buffer.
215 * @param buflen Pointer to the number of unread bytes that are ready in
216 * the communication buffer.
217 * @param pos Device position to be read.
218 * @param dst Destination buffer.
219 * @param size Size of the destination buffer.
220 * @param block_size Block size to be used for the transfer.
221 *
222 * @return True on success, false on failure.
223 */
224bool
225block_read(int dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, void *dst,
226 size_t size, size_t block_size)
227{
228 off_t offset = 0;
229 size_t left = size;
230 devcon_t *devcon = devcon_search(dev_handle);
231 assert(devcon);
232
233 while (left > 0) {
234 size_t rd;
235
236 if (*bufpos + left < *buflen)
237 rd = left;
238 else
239 rd = *buflen - *bufpos;
240
241 if (rd > 0) {
242 /*
243 * Copy the contents of the communication buffer to the
244 * destination buffer.
245 */
246 memcpy(dst + offset, devcon->com_area + *bufpos, rd);
247 offset += rd;
248 *bufpos += rd;
249 *pos += rd;
250 left -= rd;
251 }
252
253 if (*bufpos == *buflen) {
254 /* Refill the communication buffer with a new block. */
255 ipcarg_t retval;
256 int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK,
257 *pos / block_size, block_size, &retval);
258 if ((rc != EOK) || (retval != EOK))
259 return false;
260
261 *bufpos = 0;
262 *buflen = block_size;
263 }
264 }
265
266 return true;
267}
268
269block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
270{
271 /* FIXME */
272 block_t *b;
273 off_t bufpos = 0;
274 size_t buflen = 0;
275 off_t pos = offset * bs;
276
277 b = malloc(sizeof(block_t));
278 if (!b)
279 return NULL;
280
281 b->data = malloc(bs);
282 if (!b->data) {
283 free(b);
284 return NULL;
285 }
286 b->size = bs;
287
288 if (!block_read(dev_handle, &bufpos, &buflen, &pos, b->data,
289 bs, bs)) {
290 free(b->data);
291 free(b);
292 return NULL;
293 }
294
295 return b;
296}
297
298void block_put(block_t *block)
299{
300 /* FIXME */
301 free(block->data);
302 free(block);
303}
304
305/** @}
306 */
Note: See TracBrowser for help on using the repository browser.