source: rtems/cpukit/libblock/src/blkdev-imfs.c @ 73c09b3b

4.11
Last change on this file since 73c09b3b was 73c09b3b, checked in by Sebastian Huber <sebastian.huber@…>, on May 30, 2012 at 11:40:34 AM

libblock: Simplify disk management

Add block_count and media_blocks_per_block to rtems_disk_device. Add
and use rtems_disk_init_phys() and rtems_disk_init_log().

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Obere Lagerstr. 30
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.com/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <sys/stat.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <string.h>
24
25#include <rtems/blkdev.h>
26#include <rtems/bdbuf.h>
27#include <rtems/imfs.h>
28
29typedef struct {
30  rtems_disk_device dd;
31  int fd;
32} rtems_blkdev_imfs_context;
33
34static ssize_t rtems_blkdev_imfs_read(
35  rtems_libio_t *iop,
36  void *buffer,
37  size_t count
38)
39{
40  int rv;
41  rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
42  rtems_disk_device *dd = &ctx->dd;
43  ssize_t remaining = (ssize_t) count;
44  off_t offset = iop->offset;
45  ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd);
46  rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size);
47  ssize_t block_offset = (ssize_t) (offset % block_size);
48  char *dst = buffer;
49
50  while (remaining > 0) {
51    rtems_bdbuf_buffer *bd;
52    rtems_status_code sc = rtems_bdbuf_read(dd, block, &bd);
53
54    if (sc == RTEMS_SUCCESSFUL) {
55      ssize_t copy = block_size - block_offset;
56
57      if (copy > remaining) {
58        copy = remaining;
59      }
60
61      memcpy(dst, (char *) bd->buffer + block_offset, (size_t) copy);
62
63      sc = rtems_bdbuf_release(bd);
64      if (sc == RTEMS_SUCCESSFUL) {
65        block_offset = 0;
66        remaining -= copy;
67        dst += copy;
68        ++block;
69      } else {
70        remaining = -1;
71      }
72    } else {
73      remaining = -1;
74    }
75  }
76
77  if (remaining >= 0) {
78    iop->offset += count;
79    rv = (ssize_t) count;
80  } else {
81    errno = EIO;
82    rv = -1;
83  }
84
85  return rv;
86}
87
88static ssize_t rtems_blkdev_imfs_write(
89  rtems_libio_t *iop,
90  const void *buffer,
91  size_t count
92)
93{
94  int rv;
95  rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
96  rtems_disk_device *dd = &ctx->dd;
97  ssize_t remaining = (ssize_t) count;
98  off_t offset = iop->offset;
99  ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd);
100  rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size);
101  ssize_t block_offset = (ssize_t) (offset % block_size);
102  const char *src = buffer;
103
104  while (remaining > 0) {
105    rtems_status_code sc;
106    rtems_bdbuf_buffer *bd;
107
108    if (block_offset == 0 && remaining >= block_size) {
109       sc = rtems_bdbuf_get(dd, block, &bd);
110    } else {
111       sc = rtems_bdbuf_read(dd, block, &bd);
112    }
113
114    if (sc == RTEMS_SUCCESSFUL) {
115      ssize_t copy = block_size - block_offset;
116
117      if (copy > remaining) {
118        copy = remaining;
119      }
120
121      memcpy((char *) bd->buffer + block_offset, src, (size_t) copy);
122
123      sc = rtems_bdbuf_release_modified(bd);
124      if (sc == RTEMS_SUCCESSFUL) {
125        block_offset = 0;
126        remaining -= copy;
127        src += copy;
128        ++block;
129      } else {
130        remaining = -1;
131      }
132    } else {
133      remaining = -1;
134    }
135  }
136
137  if (remaining >= 0) {
138    iop->offset += count;
139    rv = (ssize_t) count;
140  } else {
141    errno = EIO;
142    rv = -1;
143  }
144
145  return rv;
146}
147
148static int rtems_blkdev_imfs_ioctl(
149  rtems_libio_t *iop,
150  uint32_t request,
151  void *buffer
152)
153{
154  int rv = 0;
155
156  if (request != RTEMS_BLKIO_REQUEST) {
157    rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
158    rtems_disk_device *dd = &ctx->dd;
159
160    rv = (*dd->ioctl)(dd, request, buffer);
161  } else {
162    /*
163     * It is not allowed to directly access the driver circumventing the cache.
164     */
165    errno = EINVAL;
166    rv = -1;
167  }
168
169  return rv;
170}
171
172static int rtems_blkdev_imfs_fstat(
173  const rtems_filesystem_location_info_t *loc,
174  struct stat *buf
175)
176{
177  rtems_blkdev_imfs_context *ctx =
178    IMFS_generic_get_context_by_location(loc);
179  rtems_disk_device *dd = &ctx->dd;
180
181  buf->st_rdev = rtems_disk_get_device_identifier(dd);
182  buf->st_blksize = rtems_disk_get_block_size(dd);
183  buf->st_blocks = rtems_disk_get_block_count(dd);
184
185  return IMFS_stat(loc, buf);
186}
187
188static int rtems_blkdev_imfs_fsync_or_fdatasync(
189  rtems_libio_t *iop
190)
191{
192  int rv = 0;
193  rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
194  rtems_disk_device *dd = &ctx->dd;
195  rtems_status_code sc = rtems_bdbuf_syncdev(dd);
196
197  if (sc != RTEMS_SUCCESSFUL) {
198    errno = EIO;
199    rv = -1;
200  }
201
202  return rv;
203}
204
205static const rtems_filesystem_file_handlers_r rtems_blkdev_imfs_node = {
206  .open_h = rtems_filesystem_default_open,
207  .close_h = rtems_filesystem_default_close,
208  .read_h = rtems_blkdev_imfs_read,
209  .write_h = rtems_blkdev_imfs_write,
210  .ioctl_h = rtems_blkdev_imfs_ioctl,
211  .lseek_h = rtems_filesystem_default_lseek_file,
212  .fstat_h = rtems_blkdev_imfs_fstat,
213  .ftruncate_h = rtems_filesystem_default_ftruncate,
214  .fsync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
215  .fdatasync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
216  .fcntl_h = rtems_filesystem_default_fcntl
217};
218
219static IMFS_jnode_t *rtems_blkdev_imfs_initialize(
220  IMFS_jnode_t *node,
221  const IMFS_types_union *info
222)
223{
224  rtems_blkdev_imfs_context *ctx;
225  rtems_disk_device *dd;
226
227  node = IMFS_node_initialize_generic(node, info);
228
229  ctx = IMFS_generic_get_context_by_node(node);
230  dd = &ctx->dd;
231  dd->dev = IMFS_generic_get_device_identifier_by_node(node);
232
233  return node;
234}
235
236static IMFS_jnode_t *rtems_blkdev_imfs_destroy(IMFS_jnode_t *node)
237{
238  rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_node(node);
239  rtems_disk_device *dd = &ctx->dd;
240
241  rtems_bdbuf_syncdev(dd);
242  rtems_bdbuf_purge_dev(dd);
243
244  if (ctx->fd >= 0) {
245    close(ctx->fd);
246  } else {
247    (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
248  }
249
250  free(ctx);
251
252  return node;
253}
254
255static const IMFS_node_control rtems_blkdev_imfs_control = {
256  .imfs_type = IMFS_GENERIC,
257  .handlers = &rtems_blkdev_imfs_node,
258  .node_initialize = rtems_blkdev_imfs_initialize,
259  .node_remove = IMFS_node_remove_default,
260  .node_destroy = rtems_blkdev_imfs_destroy
261};
262
263rtems_status_code rtems_blkdev_create(
264  const char *device,
265  uint32_t block_size,
266  rtems_blkdev_bnum block_count,
267  rtems_block_device_ioctl handler,
268  void *driver_data
269)
270{
271  rtems_status_code sc = RTEMS_SUCCESSFUL;
272  rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
273
274  if (ctx != NULL) {
275    sc = rtems_disk_init_phys(
276      &ctx->dd,
277      block_size,
278      block_count,
279      handler,
280      driver_data
281    );
282
283    ctx->fd = -1;
284
285    if (sc == RTEMS_SUCCESSFUL) {
286      int rv = IMFS_make_generic_node(
287        device,
288        S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
289        &rtems_blkdev_imfs_control,
290        ctx
291      );
292
293      if (rv != 0) {
294        free(ctx);
295        sc = RTEMS_UNSATISFIED;
296      }
297    } else {
298      free(ctx);
299    }
300  } else {
301    sc = RTEMS_NO_MEMORY;
302  }
303
304  return sc;
305}
306
307rtems_status_code rtems_blkdev_create_partition(
308  const char *partition,
309  const char *device,
310  rtems_blkdev_bnum block_begin,
311  rtems_blkdev_bnum block_count
312)
313{
314  rtems_status_code sc = RTEMS_SUCCESSFUL;
315  int fd = open(device, O_RDWR);
316
317  if (fd >= 0) {
318    int rv;
319    struct stat st;
320
321    rv = fstat(fd, &st);
322    if (rv == 0 && S_ISBLK(st.st_mode)) {
323      rtems_disk_device *phys_dd;
324
325      rv = rtems_disk_fd_get_disk_device(fd, &phys_dd);
326      if (rv == 0) {
327        rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
328
329        if (ctx != NULL) {
330          sc = rtems_disk_init_log(
331            &ctx->dd,
332            phys_dd,
333            block_begin,
334            block_count
335          );
336
337          if (sc == RTEMS_SUCCESSFUL) {
338            ctx->fd = fd;
339
340            rv = IMFS_make_generic_node(
341              partition,
342              S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
343              &rtems_blkdev_imfs_control,
344              ctx
345            );
346
347            if (rv != 0) {
348              free(ctx);
349              sc = RTEMS_UNSATISFIED;
350            }
351          } else {
352            free(ctx);
353          }
354        } else {
355          sc = RTEMS_NO_MEMORY;
356        }
357      } else {
358        sc = RTEMS_NOT_IMPLEMENTED;
359      }
360    } else {
361      sc = RTEMS_INVALID_NODE;
362    }
363
364    if (sc != RTEMS_SUCCESSFUL) {
365      close(fd);
366    }
367  } else {
368    sc = RTEMS_INVALID_ID;
369  }
370
371  return sc;
372}
Note: See TracBrowser for help on using the repository browser.