source: rtems/cpukit/libblock/src/blkdev-imfs.c @ 53da07e

4.11
Last change on this file since 53da07e was 53da07e, checked in by Sebastian Huber <sebastian.huber@…>, on May 14, 2012 at 1:21:30 PM

Filesystem: PR1255: Move offset update to handlers

It is now the responsibility of the read() and write() handler to update
the offset field of the IO descriptor (rtems_libio_t). This change
makes it possible to protect the IO descriptor from concurrent access by
per file locks.

  • Property mode set to 100644
File size: 8.7 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    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  const rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
96  const 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  const rtems_blkdev_imfs_context *ctx =
178    IMFS_generic_get_context_by_location(loc);
179  const 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  const rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
194  const 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
273  if (block_count > 0) {
274    rtems_blkdev_imfs_context *ctx = calloc(1, sizeof(*ctx));
275
276    if (ctx != NULL) {
277      rtems_disk_device *dd = &ctx->dd;
278
279      ctx->fd = -1;
280
281      dd->phys_dev = dd;
282      dd->size = block_count;
283      dd->media_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      sc = rtems_bdbuf_set_block_size(dd, block_size);
292      if (sc == RTEMS_SUCCESSFUL) {
293        int rv = IMFS_make_generic_node(
294          device,
295          S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
296          &rtems_blkdev_imfs_control,
297          ctx
298        );
299
300        if (rv != 0) {
301          free(ctx);
302          sc = RTEMS_UNSATISFIED;
303        }
304      } else {
305        free(ctx);
306      }
307    } else {
308      sc = RTEMS_NO_MEMORY;
309    }
310  } else {
311    sc = RTEMS_INVALID_NUMBER;
312  }
313
314  return sc;
315}
316
317rtems_status_code rtems_blkdev_create_partition(
318  const char *partition,
319  const char *device,
320  rtems_blkdev_bnum block_begin,
321  rtems_blkdev_bnum block_count
322)
323{
324  rtems_status_code sc = RTEMS_SUCCESSFUL;
325  int fd = open(device, O_RDWR);
326
327  if (fd >= 0) {
328    int rv;
329    struct stat st;
330
331    rv = fstat(fd, &st);
332    if (rv == 0 && S_ISBLK(st.st_mode)) {
333      rtems_disk_device *dd;
334
335      rv = ioctl(fd, RTEMS_BLKIO_GETDISKDEV, &dd);
336      if (rv == 0) {
337        rtems_blkdev_bnum device_block_count = rtems_disk_get_block_count(dd);
338
339        if (
340          block_begin < device_block_count
341            && block_count > 0
342            && block_count <= device_block_count - block_begin
343        ) {
344          rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
345
346          if (ctx != NULL) {
347            memcpy(&ctx->dd, dd, sizeof(ctx->dd));
348
349            ctx->dd.start = block_begin;
350            ctx->dd.size = block_count;
351            ctx->fd = fd;
352
353            rv = IMFS_make_generic_node(
354              partition,
355              S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
356              &rtems_blkdev_imfs_control,
357              ctx
358            );
359
360            if (rv != 0) {
361              free(ctx);
362              sc = RTEMS_UNSATISFIED;
363            }
364          } else {
365            sc = RTEMS_NO_MEMORY;
366          }
367        } else {
368          sc = RTEMS_INVALID_NUMBER;
369        }
370      } else {
371        sc = RTEMS_NOT_IMPLEMENTED;
372      }
373    } else {
374      sc = RTEMS_INVALID_NODE;
375    }
376
377    if (sc != RTEMS_SUCCESSFUL) {
378      close(fd);
379    }
380  } else {
381    sc = RTEMS_INVALID_ID;
382  }
383
384  return sc;
385}
Note: See TracBrowser for help on using the repository browser.