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

4.104.11
Last change on this file since 5268642 was 5268642, checked in by Chris Johns <chrisj@…>, on Feb 20, 2010 at 2:27:58 AM

2010-02-20 Chris Johns <chrisj@…>

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