source: rtems/cpukit/libblock/src/blkdev-imfs.c @ 3d60c1b

4.115
Last change on this file since 3d60c1b was 01211720, checked in by Sebastian Huber <sebastian.huber@…>, on 03/05/12 at 14:06:02

libblock: Add generic IMFS block device nodes

New functions

o rtems_blkdev_create(), and
o rtems_blkdev_create_partition().

New test libtests/block11.

  • Property mode set to 100644
File size: 8.6 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  const rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
42  const 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    rv = (ssize_t) count;
79  } else {
80    errno = EIO;
81    rv = -1;
82  }
83
84  return rv;
85}
86
87static ssize_t rtems_blkdev_imfs_write(
88  rtems_libio_t *iop,
89  const void *buffer,
90  size_t count
91)
92{
93  int rv;
94  const rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
95  const rtems_disk_device *dd = &ctx->dd;
96  ssize_t remaining = (ssize_t) count;
97  off_t offset = iop->offset;
98  ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd);
99  rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size);
100  ssize_t block_offset = (ssize_t) (offset % block_size);
101  const char *src = buffer;
102
103  while (remaining > 0) {
104    rtems_status_code sc;
105    rtems_bdbuf_buffer *bd;
106
107    if (block_offset == 0 && remaining >= block_size) {
108       sc = rtems_bdbuf_get(dd, block, &bd);
109    } else {
110       sc = rtems_bdbuf_read(dd, block, &bd);
111    }
112
113    if (sc == RTEMS_SUCCESSFUL) {
114      ssize_t copy = block_size - block_offset;
115
116      if (copy > remaining) {
117        copy = remaining;
118      }
119
120      memcpy((char *) bd->buffer + block_offset, src, (size_t) copy);
121
122      sc = rtems_bdbuf_release_modified(bd);
123      if (sc == RTEMS_SUCCESSFUL) {
124        block_offset = 0;
125        remaining -= copy;
126        src += copy;
127        ++block;
128      } else {
129        remaining = -1;
130      }
131    } else {
132      remaining = -1;
133    }
134  }
135
136  if (remaining >= 0) {
137    rv = (ssize_t) count;
138  } else {
139    errno = EIO;
140    rv = -1;
141  }
142
143  return rv;
144}
145
146static int rtems_blkdev_imfs_ioctl(
147  rtems_libio_t *iop,
148  uint32_t request,
149  void *buffer
150)
151{
152  int rv = 0;
153
154  if (request != RTEMS_BLKIO_REQUEST) {
155    rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
156    rtems_disk_device *dd = &ctx->dd;
157
158    rv = (*dd->ioctl)(dd, request, buffer);
159  } else {
160    /*
161     * It is not allowed to directly access the driver circumventing the cache.
162     */
163    errno = EINVAL;
164    rv = -1;
165  }
166
167  return rv;
168}
169
170static int rtems_blkdev_imfs_fstat(
171  const rtems_filesystem_location_info_t *loc,
172  struct stat *buf
173)
174{
175  const rtems_blkdev_imfs_context *ctx =
176    IMFS_generic_get_context_by_location(loc);
177  const rtems_disk_device *dd = &ctx->dd;
178
179  buf->st_rdev = rtems_disk_get_device_identifier(dd);
180  buf->st_blksize = rtems_disk_get_block_size(dd);
181  buf->st_blocks = rtems_disk_get_block_count(dd);
182
183  return IMFS_stat(loc, buf);
184}
185
186static int rtems_blkdev_imfs_fsync_or_fdatasync(
187  rtems_libio_t *iop
188)
189{
190  int rv = 0;
191  const rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
192  const rtems_disk_device *dd = &ctx->dd;
193  rtems_status_code sc = rtems_bdbuf_syncdev(dd);
194
195  if (sc != RTEMS_SUCCESSFUL) {
196    errno = EIO;
197    rv = -1;
198  }
199
200  return rv;
201}
202
203static const rtems_filesystem_file_handlers_r rtems_blkdev_imfs_node = {
204  .open_h = rtems_filesystem_default_open,
205  .close_h = rtems_filesystem_default_close,
206  .read_h = rtems_blkdev_imfs_read,
207  .write_h = rtems_blkdev_imfs_write,
208  .ioctl_h = rtems_blkdev_imfs_ioctl,
209  .lseek_h = rtems_filesystem_default_lseek_success,
210  .fstat_h = rtems_blkdev_imfs_fstat,
211  .ftruncate_h = rtems_filesystem_default_ftruncate,
212  .fsync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
213  .fdatasync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
214  .fcntl_h = rtems_filesystem_default_fcntl
215};
216
217static IMFS_jnode_t *rtems_blkdev_imfs_initialize(
218  IMFS_jnode_t *node,
219  const IMFS_types_union *info
220)
221{
222  rtems_blkdev_imfs_context *ctx;
223  rtems_disk_device *dd;
224
225  node = IMFS_node_initialize_generic(node, info);
226
227  ctx = IMFS_generic_get_context_by_node(node);
228  dd = &ctx->dd;
229  dd->dev = IMFS_generic_get_device_identifier_by_node(node);
230
231  return node;
232}
233
234static IMFS_jnode_t *rtems_blkdev_imfs_destroy(IMFS_jnode_t *node)
235{
236  rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_node(node);
237  rtems_disk_device *dd = &ctx->dd;
238
239  rtems_bdbuf_syncdev(dd);
240  rtems_bdbuf_purge_dev(dd);
241
242  if (ctx->fd >= 0) {
243    close(ctx->fd);
244  } else {
245    (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
246  }
247
248  free(ctx);
249
250  return node;
251}
252
253static const IMFS_node_control rtems_blkdev_imfs_control = {
254  .imfs_type = IMFS_GENERIC,
255  .handlers = &rtems_blkdev_imfs_node,
256  .node_initialize = rtems_blkdev_imfs_initialize,
257  .node_remove = IMFS_node_remove_default,
258  .node_destroy = rtems_blkdev_imfs_destroy
259};
260
261rtems_status_code rtems_blkdev_create(
262  const char *device,
263  uint32_t block_size,
264  rtems_blkdev_bnum block_count,
265  rtems_block_device_ioctl handler,
266  void *driver_data
267)
268{
269  rtems_status_code sc = RTEMS_SUCCESSFUL;
270
271  if (block_size > 0 && block_count > 0) {
272    rtems_blkdev_imfs_context *ctx = calloc(1, sizeof(*ctx));
273
274    if (ctx != NULL) {
275      rtems_disk_device *dd = &ctx->dd;
276      int rv;
277
278      ctx->fd = -1;
279
280      dd->phys_dev = dd;
281      dd->size = block_count;
282      dd->media_block_size = block_size;
283      dd->block_size = block_size;
284      dd->ioctl = handler;
285      dd->driver_data = driver_data;
286
287      if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) != 0) {
288        dd->capabilities = 0;
289      }
290
291      rv = IMFS_make_generic_node(
292        device,
293        S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
294        &rtems_blkdev_imfs_control,
295        ctx
296      );
297
298      if (rv != 0) {
299        free(ctx);
300        sc = RTEMS_UNSATISFIED;
301      }
302    } else {
303      sc = RTEMS_NO_MEMORY;
304    }
305  } else {
306    sc = RTEMS_INVALID_NUMBER;
307  }
308
309  return sc;
310}
311
312rtems_status_code rtems_blkdev_create_partition(
313  const char *partition,
314  const char *device,
315  rtems_blkdev_bnum block_begin,
316  rtems_blkdev_bnum block_count
317)
318{
319  rtems_status_code sc = RTEMS_SUCCESSFUL;
320  int fd = open(device, O_RDWR);
321
322  if (fd >= 0) {
323    int rv;
324    struct stat st;
325
326    rv = fstat(fd, &st);
327    if (rv == 0 && S_ISBLK(st.st_mode)) {
328      rtems_disk_device *dd;
329
330      rv = ioctl(fd, RTEMS_BLKIO_GETDISKDEV, &dd);
331      if (rv == 0) {
332        rtems_blkdev_bnum device_block_count = rtems_disk_get_block_count(dd);
333
334        if (
335          block_begin < device_block_count
336            && block_count > 0
337            && block_count <= device_block_count - block_begin
338        ) {
339          rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
340
341          if (ctx != NULL) {
342            memcpy(&ctx->dd, dd, sizeof(ctx->dd));
343
344            ctx->dd.start = block_begin;
345            ctx->dd.size = block_count;
346            ctx->fd = fd;
347
348            rv = IMFS_make_generic_node(
349              partition,
350              S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
351              &rtems_blkdev_imfs_control,
352              ctx
353            );
354
355            if (rv != 0) {
356              free(ctx);
357              sc = RTEMS_UNSATISFIED;
358            }
359          } else {
360            sc = RTEMS_NO_MEMORY;
361          }
362        } else {
363          sc = RTEMS_INVALID_NUMBER;
364        }
365      } else {
366        sc = RTEMS_NOT_IMPLEMENTED;
367      }
368    } else {
369      sc = RTEMS_INVALID_NODE;
370    }
371
372    if (sc != RTEMS_SUCCESSFUL) {
373      close(fd);
374    }
375  } else {
376    sc = RTEMS_INVALID_ID;
377  }
378
379  return sc;
380}
Note: See TracBrowser for help on using the repository browser.