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

4.115
Last change on this file since 36f3207 was 36f3207, checked in by Alex Ivanov <alexivanov97@…>, on 12/28/12 at 13:49:39

libfs: Doxygen Enhancement Task #3

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