source: rtems/cpukit/libfs/src/rfs/rtems-rfs-buffer.c @ 796967c

4.115
Last change on this file since 796967c was 796967c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 16:19:49

libblock: Change bdbuf API

The functions

o rtems_bdbuf_get(),
o rtems_bdbuf_read(),
o rtems_bdbuf_syncdev(), and
o rtems_bdbuf_purge_dev(),

use now the disk device instead of the device identifier. This makes
bdbuf independent of rtems_disk_obtain() and rtems_disk_release(). It
is the responsiblity of the file system to obtain the disk device. This
also reduces the overhead to get a buffer.

The key for the AVL tree uses now the disk device instead of the device
identifier. The pointer is interpreted as an unsigned integer. This
reduces the memory overhead and makes the comparison operation a bit
faster.

Removed function rtems_bdbuf_purge_major(). This function was too
destructive and could have unpredictable side effects.

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  $Id$
9 */
10/**
11 * @file
12 *
13 * @ingroup rtems-rfs
14 *
15 * RTEMS File Systems Buffer Routines.
16 *
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <sys/stat.h>
24#include <inttypes.h>
25#include <errno.h>
26#include <fcntl.h>
27
28#include <rtems/rfs/rtems-rfs-buffer.h>
29#include <rtems/rfs/rtems-rfs-file-system.h>
30
31/**
32 * Scan the chain for a buffer that matches the block number.
33 *
34 * @param chain The chain to scan.
35 * @param count The number of items on the chain.
36 * @param block The block number to find.
37 * @return  rtems_rfs_buffer* The buffer if found else NULL.
38 */
39static rtems_rfs_buffer*
40rtems_rfs_scan_chain (rtems_chain_control*   chain,
41                      uint32_t*              count,
42                      rtems_rfs_buffer_block block)
43{
44  rtems_rfs_buffer* buffer;
45  rtems_chain_node* node;
46
47  node = rtems_chain_last (chain);
48
49  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
50    printf ("rtems-rfs: buffer-scan: count=%" PRIu32 ", block=%" PRIu32 ": ", *count, block);
51
52  while (!rtems_chain_is_head (chain, node))
53  {
54    buffer = (rtems_rfs_buffer*) node;
55
56    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
57      printf ("%" PRIuPTR " ", ((intptr_t) buffer->user));
58
59    if (((rtems_rfs_buffer_block) ((intptr_t)(buffer->user))) == block)
60    {
61      if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
62        printf (": found block=%" PRIuPTR "\n",
63                ((intptr_t)(buffer->user)));
64
65      (*count)--;
66      rtems_chain_extract (node);
67      rtems_chain_set_off_chain (node);
68      return buffer;
69    }
70    node = rtems_chain_previous (node);
71  }
72
73  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
74    printf (": not found\n");
75
76  return NULL;
77}
78
79int
80rtems_rfs_buffer_handle_request (rtems_rfs_file_system*   fs,
81                                 rtems_rfs_buffer_handle* handle,
82                                 rtems_rfs_buffer_block   block,
83                                 bool                     read)
84{
85  int rc;
86
87  /*
88   * If the handle has a buffer release it. This allows a handle to be reused
89   * without needing to close then open it again.
90   */
91  if (rtems_rfs_buffer_handle_has_block (handle))
92  {
93    /*
94     * Treat block 0 as special to handle the loading of the super block.
95     */
96    if (block && (rtems_rfs_buffer_bnum (handle) == block))
97      return 0;
98
99    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
100      printf ("rtems-rfs: buffer-request: handle has buffer: %" PRIu32 "\n",
101              rtems_rfs_buffer_bnum (handle));
102
103    rc = rtems_rfs_buffer_handle_release (fs, handle);
104    if (rc > 0)
105      return rc;
106    handle->dirty = false;
107    handle->bnum = 0;
108  }
109
110  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
111    printf ("rtems-rfs: buffer-request: block=%" PRIu32 "\n", block);
112
113  /*
114   * First check to see if the buffer has already been requested and is
115   * currently attached to a handle. If it is share the access. A buffer could
116   * be shared where different parts of the block have separate functions. An
117   * example is an inode block and the file system needs to handle 2 inodes in
118   * the same block at the same time.
119   */
120  if (fs->buffers_count)
121  {
122    /*
123     * Check the active buffer list for shared buffers.
124     */
125    handle->buffer = rtems_rfs_scan_chain (&fs->buffers,
126                                           &fs->buffers_count,
127                                           block);
128    if (rtems_rfs_buffer_handle_has_block (handle) &&
129        rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
130      printf ("rtems-rfs: buffer-request: buffer shared: refs: %d\n",
131              rtems_rfs_buffer_refs (handle) + 1);
132  }
133
134  /*
135   * If the buffer has not been found check the local cache of released
136   * buffers. There are release and released modified lists to preserve the
137   * state.
138   */
139  if (!rtems_rfs_fs_no_local_cache (fs) &&
140      !rtems_rfs_buffer_handle_has_block (handle))
141  {
142    /*
143     * Check the local cache of released buffers.
144     */
145    if (fs->release_count)
146      handle->buffer = rtems_rfs_scan_chain (&fs->release,
147                                             &fs->release_count,
148                                             block);
149
150    if (!rtems_rfs_buffer_handle_has_block (handle) &&
151        fs->release_modified_count)
152    {
153      handle->buffer = rtems_rfs_scan_chain (&fs->release_modified,
154                                             &fs->release_modified_count,
155                                             block);
156      /*
157       * If we found a buffer retain the dirty buffer state.
158       */
159      if (rtems_rfs_buffer_handle_has_block (handle))
160        rtems_rfs_buffer_mark_dirty (handle);
161    }
162  }
163
164  /*
165   * If not located we request the buffer from the I/O layer.
166   */
167  if (!rtems_rfs_buffer_handle_has_block (handle))
168  {
169    rc = rtems_rfs_buffer_io_request (fs, block, read, &handle->buffer);
170
171    rtems_chain_set_off_chain (rtems_rfs_buffer_link(handle));
172
173    if (rc > 0)
174    {
175      if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
176        printf ("rtems-rfs: buffer-request: block=%" PRIu32 ": bdbuf-%s: %d: %s\n",
177                block, read ? "read" : "get", rc, strerror (rc));
178      return rc;
179    }
180  }
181
182  /*
183   * Increase the reference count of the buffer.
184   */
185  rtems_rfs_buffer_refs_up (handle);
186  rtems_chain_append (&fs->buffers, rtems_rfs_buffer_link (handle));
187  fs->buffers_count++;
188
189  handle->buffer->user = (void*) ((intptr_t) block);
190  handle->bnum = block;
191
192  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
193    printf ("rtems-rfs: buffer-request: block=%" PRIu32 " bdbuf-%s=%" PRIu32 " refs=%d\n",
194            block, read ? "read" : "get", handle->buffer->block,
195            handle->buffer->references);
196
197  return 0;
198}
199
200int
201rtems_rfs_buffer_handle_release (rtems_rfs_file_system*   fs,
202                                 rtems_rfs_buffer_handle* handle)
203{
204  int rc = 0;
205
206  if (rtems_rfs_buffer_handle_has_block (handle))
207  {
208    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
209      printf ("rtems-rfs: buffer-release: block=%" PRIu32 " %s refs=%d %s\n",
210              rtems_rfs_buffer_bnum (handle),
211              rtems_rfs_buffer_dirty (handle) ? "(dirty)" : "",
212              rtems_rfs_buffer_refs (handle),
213              rtems_rfs_buffer_refs (handle) == 0 ? "BAD REF COUNT" : "");
214
215    if (rtems_rfs_buffer_refs (handle) > 0)
216      rtems_rfs_buffer_refs_down (handle);
217
218    if (rtems_rfs_buffer_refs (handle) == 0)
219    {
220      rtems_chain_extract (rtems_rfs_buffer_link (handle));
221      fs->buffers_count--;
222
223      if (rtems_rfs_fs_no_local_cache (fs))
224      {
225        handle->buffer->user = (void*) 0;
226        rc = rtems_rfs_buffer_io_release (handle->buffer,
227                                          rtems_rfs_buffer_dirty (handle));
228      }
229      else
230      {
231        /*
232         * If the total number of held buffers is higher than the configured
233         * value remove a buffer from the queue with the most buffers and
234         * release. The buffers are held on the queues with the newest at the
235         * head.
236         *
237         * This code stops a large series of transactions causing all the
238         * buffers in the cache being held in queues of this file system.
239         */
240        if ((fs->release_count +
241             fs->release_modified_count) >= fs->max_held_buffers)
242        {
243          rtems_rfs_buffer* buffer;
244          bool              modified;
245
246          if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
247            printf ("rtems-rfs: buffer-release: local cache overflow:"
248                    " %" PRIu32 "\n", fs->release_count + fs->release_modified_count);
249
250          if (fs->release_count > fs->release_modified_count)
251          {
252            buffer = (rtems_rfs_buffer*) rtems_chain_get (&fs->release);
253            fs->release_count--;
254            modified = false;
255          }
256          else
257          {
258            buffer =
259              (rtems_rfs_buffer*) rtems_chain_get (&fs->release_modified);
260            fs->release_modified_count--;
261            modified = true;
262          }
263          buffer->user = (void*) 0;
264          rc = rtems_rfs_buffer_io_release (buffer, modified);
265        }
266
267        if (rtems_rfs_buffer_dirty (handle))
268        {
269          rtems_chain_append (&fs->release_modified,
270                              rtems_rfs_buffer_link (handle));
271          fs->release_modified_count++;
272        }
273        else
274        {
275          rtems_chain_append (&fs->release, rtems_rfs_buffer_link (handle));
276          fs->release_count++;
277        }
278      }
279    }
280    handle->buffer = NULL;
281  }
282
283  return rc;
284}
285
286int
287rtems_rfs_buffer_open (const char* name, rtems_rfs_file_system* fs)
288{
289  struct stat st;
290#if RTEMS_RFS_USE_LIBBLOCK
291  int rv;
292#endif
293
294  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
295    printf ("rtems-rfs: buffer-open: opening: %s\n", name);
296
297  fs->device = open (name, O_RDWR);
298  if (fs->device < 0)
299  {
300    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
301      printf ("rtems-rfs: buffer-open: cannot open file\n");
302    return ENXIO;
303  }
304
305  if (fstat (fs->device, &st) < 0)
306  {
307    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
308      printf ("rtems-rfs: buffer-open: stat '%s' failed: %s\n",
309              name, strerror (errno));
310    return ENXIO;
311  }
312
313#if RTEMS_RFS_USE_LIBBLOCK
314  /*
315   * Is the device a block device ?
316   */
317  if (!S_ISBLK (st.st_mode))
318  {
319    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
320      printf ("rtems-rfs: buffer-open: '%s' is not a block device\n", name);
321    return ENXIO;
322  }
323
324  /*
325   * Check that device is registred as a block device and lock it.
326   */
327  rv = rtems_disk_fd_get_disk_device (fs->device, &fs->disk);
328  if (rv != 0)
329  {
330    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
331      printf ("rtems-rfs: buffer-open: cannot obtain the disk\n");
332    return ENXIO;
333  }
334#else
335  fs->media_size = st.st_size;
336  strcat (fs->name, name);
337#endif
338
339  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
340    printf ("rtems-rfs: buffer-open: blks=%" PRId32 ", blk-size=%" PRId32 "\n",
341            rtems_rfs_fs_media_blocks (fs),
342            rtems_rfs_fs_media_block_size (fs));
343
344  return 0;
345}
346
347int
348rtems_rfs_buffer_close (rtems_rfs_file_system* fs)
349{
350  int rc = 0;
351
352  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
353    printf ("rtems-rfs: buffer-close: closing\n");
354
355  /*
356   * Change the block size to the media device size. It will release and sync
357   * all buffers.
358   */
359  rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_media_block_size (fs));
360
361  if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
362    printf ("rtems-rfs: buffer-close: set media block size failed: %d: %s\n",
363            rc, strerror (rc));
364
365  if (close (fs->device) < 0)
366  {
367    rc = errno;
368    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
369      printf ("rtems-rfs: buffer-close: file close failed: %d: %s\n",
370              rc, strerror (rc));
371  }
372
373  return rc;
374}
375
376int
377rtems_rfs_buffer_sync (rtems_rfs_file_system* fs)
378{
379  int result = 0;
380#if RTEMS_RFS_USE_LIBBLOCK
381  rtems_status_code sc;
382#endif
383
384  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
385    printf ("rtems-rfs: buffer-sync: syncing\n");
386
387  /*
388   * @todo Split in the separate files for each type.
389   */
390#if RTEMS_RFS_USE_LIBBLOCK
391  sc = rtems_bdbuf_syncdev (rtems_rfs_fs_device (fs));
392  if (sc != RTEMS_SUCCESSFUL)
393  {
394    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
395      printf ("rtems-rfs: buffer-sync: device sync failed: %s\n",
396              rtems_status_text (sc));
397    result = EIO;
398  }
399  rtems_disk_release (fs->disk);
400#else
401  if (fsync (fs->device) < 0)
402  {
403    result = errno;
404    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
405      printf ("rtems-rfs: buffer-sync: file sync failed: %d: %s\n",
406              result, strerror (result));
407  }
408#endif
409  return result;
410}
411
412int
413rtems_rfs_buffer_setblksize (rtems_rfs_file_system* fs, size_t size)
414{
415  int rc;
416
417  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
418    printf ("rtems-rfs: buffer-setblksize: block size: %zu\n", size);
419
420  rc = rtems_rfs_buffers_release (fs);
421  if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
422    printf ("rtems-rfs: buffer-setblksize: buffer release failed: %d: %s\n",
423            rc, strerror (rc));
424
425  rc = rtems_rfs_buffer_sync (fs);
426  if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
427    printf ("rtems-rfs: buffer-setblksize: device sync failed: %d: %s\n",
428            rc, strerror (rc));
429
430#if RTEMS_RFS_USE_LIBBLOCK
431  rc = fs->disk->ioctl (fs->disk, RTEMS_BLKIO_SETBLKSIZE, &size);
432  if (rc < 0)
433    rc = errno;
434#endif
435  return rc;
436}
437
438static int
439rtems_rfs_release_chain (rtems_chain_control* chain,
440                         uint32_t*            count,
441                         bool                 modified)
442{
443  rtems_rfs_buffer* buffer;
444  int               rrc = 0;
445  int               rc;
446
447  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
448    printf ("rtems-rfs: release-chain: count=%" PRIu32 "\n", *count);
449
450  while (!rtems_chain_is_empty (chain))
451  {
452    buffer = (rtems_rfs_buffer*) rtems_chain_get (chain);
453    (*count)--;
454
455    buffer->user = (void*) 0;
456
457    rc = rtems_rfs_buffer_io_release (buffer, modified);
458    if ((rc > 0) && (rrc == 0))
459      rrc = rc;
460  }
461  return rrc;
462}
463
464int
465rtems_rfs_buffers_release (rtems_rfs_file_system* fs)
466{
467  int rrc = 0;
468  int rc;
469
470  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_RELEASE))
471    printf ("rtems-rfs: buffers-release: active:%" PRIu32 " "
472            "release:%" PRIu32 " release-modified:%" PRIu32 "\n",
473            fs->buffers_count, fs->release_count, fs->release_modified_count);
474
475  rc = rtems_rfs_release_chain (&fs->release,
476                                &fs->release_count,
477                                false);
478  if ((rc > 0) && (rrc == 0))
479    rrc = rc;
480  rc = rtems_rfs_release_chain (&fs->release_modified,
481                                &fs->release_modified_count,
482                                true);
483  if ((rc > 0) && (rrc == 0))
484    rrc = rc;
485
486  return rrc;
487}
Note: See TracBrowser for help on using the repository browser.