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

4.115
Last change on this file since 3c96bee was a839d62, checked in by Sebastian Huber <sebastian.huber@…>, on 08/26/13 at 08:31:46

RFS: Use unprotected chain operations

This area is protected by the RFS file system instance lock.

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