source: rtems/cpukit/libblock/src/blkdev-imfs.c @ 30d4124

4.11
Last change on this file since 30d4124 was 30d4124, checked in by Sebastian Huber <sebastian.huber@…>, on May 7, 2012 at 2:30:37 PM

Filesystem: PR1398: Fix lseek() mechanic

According to POSIX the lseek() function shall not, by itself, extend the
size of a file.

Remove the size field of rtems_libio_t. A file has only one size but
may have multiple open file descriptors. Thus a file size field in the
file descriptor may lead to inconsistencies.

New default handlers rtems_filesystem_default_lseek_file() and
rtems_filesystem_default_lseek_directory().

  • 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_file,
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_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
277      ctx->fd = -1;
278
279      dd->phys_dev = dd;
280      dd->size = block_count;
281      dd->media_block_size = block_size;
282      dd->ioctl = handler;
283      dd->driver_data = driver_data;
284
285      if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) != 0) {
286        dd->capabilities = 0;
287      }
288
289      sc = rtems_bdbuf_set_block_size(dd, block_size);
290      if (sc == RTEMS_SUCCESSFUL) {
291        int 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        free(ctx);
304      }
305    } else {
306      sc = RTEMS_NO_MEMORY;
307    }
308  } else {
309    sc = RTEMS_INVALID_NUMBER;
310  }
311
312  return sc;
313}
314
315rtems_status_code rtems_blkdev_create_partition(
316  const char *partition,
317  const char *device,
318  rtems_blkdev_bnum block_begin,
319  rtems_blkdev_bnum block_count
320)
321{
322  rtems_status_code sc = RTEMS_SUCCESSFUL;
323  int fd = open(device, O_RDWR);
324
325  if (fd >= 0) {
326    int rv;
327    struct stat st;
328
329    rv = fstat(fd, &st);
330    if (rv == 0 && S_ISBLK(st.st_mode)) {
331      rtems_disk_device *dd;
332
333      rv = ioctl(fd, RTEMS_BLKIO_GETDISKDEV, &dd);
334      if (rv == 0) {
335        rtems_blkdev_bnum device_block_count = rtems_disk_get_block_count(dd);
336
337        if (
338          block_begin < device_block_count
339            && block_count > 0
340            && block_count <= device_block_count - block_begin
341        ) {
342          rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
343
344          if (ctx != NULL) {
345            memcpy(&ctx->dd, dd, sizeof(ctx->dd));
346
347            ctx->dd.start = block_begin;
348            ctx->dd.size = block_count;
349            ctx->fd = fd;
350
351            rv = IMFS_make_generic_node(
352              partition,
353              S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
354              &rtems_blkdev_imfs_control,
355              ctx
356            );
357
358            if (rv != 0) {
359              free(ctx);
360              sc = RTEMS_UNSATISFIED;
361            }
362          } else {
363            sc = RTEMS_NO_MEMORY;
364          }
365        } else {
366          sc = RTEMS_INVALID_NUMBER;
367        }
368      } else {
369        sc = RTEMS_NOT_IMPLEMENTED;
370      }
371    } else {
372      sc = RTEMS_INVALID_NODE;
373    }
374
375    if (sc != RTEMS_SUCCESSFUL) {
376      close(fd);
377    }
378  } else {
379    sc = RTEMS_INVALID_ID;
380  }
381
382  return sc;
383}
Note: See TracBrowser for help on using the repository browser.