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

4.115
Last change on this file since 06e04f8 was 06e04f8, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/15/10 at 13:35:28

2010-06-15 Ralf Corsépius <ralf.corsepius@…>

  • libfs/src/rfs/rtems-rfs-block.c, libfs/src/rfs/rtems-rfs-buffer.c, libnetworking/nfs/bootp_subr.c: Misc. 64bit-compatibility fixes.
  • 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 <inttypes.h>
24#include <errno.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 ("%lu ", (rtems_rfs_buffer_block) ((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=%lu\n",
61                (rtems_rfs_buffer_block) ((intptr_t)(buffer->user)));
62
63      (*count)--;
64      rtems_chain_extract (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: %lu\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    rtems_chain_set_off_chain (rtems_rfs_buffer_link(handle));
170
171    if (rc > 0)
172    {
173      if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
174        printf ("rtems-rfs: buffer-request: block=%lu: bdbuf-%s: %d: %s\n",
175                block, read ? "read" : "get", rc, strerror (rc));
176      return rc;
177    }
178  }
179
180  /*
181   * Increase the reference count of the buffer.
182   */
183  rtems_rfs_buffer_refs_up (handle);
184  rtems_chain_append (&fs->buffers, rtems_rfs_buffer_link (handle));
185  fs->buffers_count++;
186 
187  handle->buffer->user = (void*) ((intptr_t) block);
188  handle->bnum = block;
189 
190  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
191    printf ("rtems-rfs: buffer-request: block=%lu bdbuf-%s=%lu refs=%d\n",
192            block, read ? "read" : "get", handle->buffer->block,
193            handle->buffer->references);
194 
195  return 0;
196}
197
198int
199rtems_rfs_buffer_handle_release (rtems_rfs_file_system*   fs,
200                                 rtems_rfs_buffer_handle* handle)
201{
202  int rc = 0;
203 
204  if (rtems_rfs_buffer_handle_has_block (handle))
205  {
206    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
207      printf ("rtems-rfs: buffer-release: block=%lu %s refs=%d %s\n",
208              rtems_rfs_buffer_bnum (handle),
209              rtems_rfs_buffer_dirty (handle) ? "(dirty)" : "",
210              rtems_rfs_buffer_refs (handle),
211              rtems_rfs_buffer_refs (handle) == 0 ? "BAD REF COUNT" : "");
212
213    if (rtems_rfs_buffer_refs (handle) > 0)
214      rtems_rfs_buffer_refs_down (handle);
215   
216    if (rtems_rfs_buffer_refs (handle) == 0)
217    {
218      rtems_chain_extract (rtems_rfs_buffer_link (handle));
219      fs->buffers_count--;
220     
221      if (rtems_rfs_fs_no_local_cache (fs))
222      {
223        handle->buffer->user = (void*) 0;
224        rc = rtems_rfs_buffer_io_release (handle->buffer,
225                                          rtems_rfs_buffer_dirty (handle));
226      }
227      else
228      {
229        /*
230         * If the total number of held buffers is higher than the configured
231         * value remove a buffer from the queue with the most buffers and
232         * release. The buffers are held on the queues with the newest at the
233         * head.
234         *
235         * This code stops a large series of transactions causing all the
236         * buffers in the cache being held in queues of this file system.
237         */
238        if ((fs->release_count +
239             fs->release_modified_count) >= fs->max_held_buffers)
240        {
241          rtems_rfs_buffer* buffer;
242          bool              modified;
243       
244          if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
245            printf ("rtems-rfs: buffer-release: local cache overflow:" \
246                    " %lu\n", fs->release_count + fs->release_modified_count);
247       
248          if (fs->release_count > fs->release_modified_count)
249          {
250            buffer = (rtems_rfs_buffer*) rtems_chain_get (&fs->release);
251            fs->release_count--;
252            modified = false;
253          }
254          else
255          {
256            buffer =
257              (rtems_rfs_buffer*) rtems_chain_get (&fs->release_modified);
258            fs->release_modified_count--;
259            modified = true;
260          }
261          buffer->user = (void*) 0;
262          rc = rtems_rfs_buffer_io_release (buffer, modified);
263        }
264     
265        if (rtems_rfs_buffer_dirty (handle))
266        {
267          rtems_chain_append (&fs->release_modified,
268                              rtems_rfs_buffer_link (handle));
269          fs->release_modified_count++;
270        }
271        else
272        {
273          rtems_chain_append (&fs->release, rtems_rfs_buffer_link (handle));
274          fs->release_count++;
275        }
276      }
277    }
278    handle->buffer = NULL;
279  }
280 
281  return rc;
282}
283
284int
285rtems_rfs_buffer_open (const char* name, rtems_rfs_file_system* fs)
286{
287  struct stat st;
288
289  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
290    printf ("rtems-rfs: buffer-open: opening: %s\n", name);
291 
292  if (stat (name, &st) < 0)
293  {
294    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
295      printf ("rtems-rfs: buffer-open: stat '%s' failed: %s\n",
296              name, strerror (errno));
297    return ENOENT;
298  }
299
300#if RTEMS_RFS_USE_LIBBLOCK
301  /*
302   * Is the device a block device ?
303   */
304  if (!S_ISBLK (st.st_mode))
305  {
306    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
307      printf ("rtems-rfs: buffer-open: '%s' is not a block device\n", name);
308    return EIO;
309  }
310
311  /*
312   * Check that device is registred as a block device and lock it.
313   */
314  fs->disk = rtems_disk_obtain (st.st_rdev);
315  if (!fs->disk)
316  {
317    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
318      printf ("rtems-rfs: buffer-open: cannot obtain the disk\n");
319    return EIO;
320  }
321#else
322  fs->device = open (name, O_RDWR);
323  if (fs->device < 0)
324  {
325    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
326      printf ("rtems-rfs: buffer-open: cannot open file\n");
327  }
328  fs->media_size = st.st_size;
329  strcat (fs->name, name);
330#endif
331
332  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
333    printf ("rtems-rfs: buffer-open: blks=%ld, blk-size=%ld\n",
334            rtems_rfs_fs_media_blocks (fs),
335            rtems_rfs_fs_media_block_size (fs));
336 
337  return 0;
338}
339
340int
341rtems_rfs_buffer_close (rtems_rfs_file_system* fs)
342{
343  int rc = 0;
344
345  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
346    printf ("rtems-rfs: buffer-close: closing\n");
347
348  /*
349   * Change the block size to the media device size. It will release and sync
350   * all buffers.
351   */
352  rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_media_block_size (fs));
353
354  if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
355    printf ("rtems-rfs: buffer-close: set media block size failed: %d: %s\n",
356            rc, strerror (rc));
357 
358#if RTEMS_RFS_USE_LIBBLOCK
359  rtems_disk_release (fs->disk);
360#else
361  if (close (fs->device) < 0)
362  {
363    rc = errno;
364    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
365      printf ("rtems-rfs: buffer-close: file close failed: %d: %s\n",
366              rc, strerror (rc));
367  }
368#endif
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=%lu\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:%lu " \
469            "release:%lu release-modified:%lu\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.