int
rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
{
  int rc = 0;
  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle));
  return rc;
}
Esempio n. 2
0
int
rtems_rfs_buffer_handle_request (rtems_rfs_file_system*   fs,
                                 rtems_rfs_buffer_handle* handle,
                                 rtems_rfs_buffer_block   block,
                                 bool                     read)
{
  int rc;

  /*
   * If the handle has a buffer release it. This allows a handle to be reused
   * without needing to close then open it again.
   */
  if (rtems_rfs_buffer_handle_has_block (handle))
  {
    /*
     * Treat block 0 as special to handle the loading of the super block.
     */
    if (block && (rtems_rfs_buffer_bnum (handle) == block))
      return 0;

    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
      printf ("rtems-rfs: buffer-request: handle has buffer: %" PRIu32 "\n",
              rtems_rfs_buffer_bnum (handle));

    rc = rtems_rfs_buffer_handle_release (fs, handle);
    if (rc > 0)
      return rc;
    handle->dirty = false;
    handle->bnum = 0;
  }

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
    printf ("rtems-rfs: buffer-request: block=%" PRIu32 "\n", block);

  /*
   * First check to see if the buffer has already been requested and is
   * currently attached to a handle. If it is share the access. A buffer could
   * be shared where different parts of the block have separate functions. An
   * example is an inode block and the file system needs to handle 2 inodes in
   * the same block at the same time.
   */
  if (fs->buffers_count)
  {
    /*
     * Check the active buffer list for shared buffers.
     */
    handle->buffer = rtems_rfs_scan_chain (&fs->buffers,
                                           &fs->buffers_count,
                                           block);
    if (rtems_rfs_buffer_handle_has_block (handle) &&
        rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
      printf ("rtems-rfs: buffer-request: buffer shared: refs: %d\n",
              rtems_rfs_buffer_refs (handle) + 1);
  }

  /*
   * If the buffer has not been found check the local cache of released
   * buffers. There are release and released modified lists to preserve the
   * state.
   */
  if (!rtems_rfs_fs_no_local_cache (fs) &&
      !rtems_rfs_buffer_handle_has_block (handle))
  {
    /*
     * Check the local cache of released buffers.
     */
    if (fs->release_count)
      handle->buffer = rtems_rfs_scan_chain (&fs->release,
                                             &fs->release_count,
                                             block);

    if (!rtems_rfs_buffer_handle_has_block (handle) &&
        fs->release_modified_count)
    {
      handle->buffer = rtems_rfs_scan_chain (&fs->release_modified,
                                             &fs->release_modified_count,
                                             block);
      /*
       * If we found a buffer retain the dirty buffer state.
       */
      if (rtems_rfs_buffer_handle_has_block (handle))
        rtems_rfs_buffer_mark_dirty (handle);
    }
  }

  /*
   * If not located we request the buffer from the I/O layer.
   */
  if (!rtems_rfs_buffer_handle_has_block (handle))
  {
    rc = rtems_rfs_buffer_io_request (fs, block, read, &handle->buffer);

    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
        printf ("rtems-rfs: buffer-request: block=%" PRIu32 ": bdbuf-%s: %d: %s\n",
                block, read ? "read" : "get", rc, strerror (rc));
      return rc;
    }

    rtems_chain_set_off_chain (rtems_rfs_buffer_link(handle));
  }

  /*
   * Increase the reference count of the buffer.
   */
  rtems_rfs_buffer_refs_up (handle);
  rtems_chain_append (&fs->buffers, rtems_rfs_buffer_link (handle));
  fs->buffers_count++;

  handle->buffer->user = (void*) ((intptr_t) block);
  handle->bnum = block;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
    printf ("rtems-rfs: buffer-request: block=%" PRIu32 " bdbuf-%s=%" PRIu32 " refs=%d\n",
            block, read ? "read" : "get", handle->buffer->block,
            handle->buffer->references);

  return 0;
}
Esempio n. 3
0
int
rtems_rfs_buffer_handle_release (rtems_rfs_file_system*   fs,
                                 rtems_rfs_buffer_handle* handle)
{
  int rc = 0;

  if (rtems_rfs_buffer_handle_has_block (handle))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
      printf ("rtems-rfs: buffer-release: block=%" PRIu32 " %s refs=%d %s\n",
              rtems_rfs_buffer_bnum (handle),
              rtems_rfs_buffer_dirty (handle) ? "(dirty)" : "",
              rtems_rfs_buffer_refs (handle),
              rtems_rfs_buffer_refs (handle) == 0 ? "BAD REF COUNT" : "");

    if (rtems_rfs_buffer_refs (handle) > 0)
      rtems_rfs_buffer_refs_down (handle);

    if (rtems_rfs_buffer_refs (handle) == 0)
    {
      rtems_chain_extract (rtems_rfs_buffer_link (handle));
      fs->buffers_count--;

      if (rtems_rfs_fs_no_local_cache (fs))
      {
        handle->buffer->user = (void*) 0;
        rc = rtems_rfs_buffer_io_release (handle->buffer,
                                          rtems_rfs_buffer_dirty (handle));
      }
      else
      {
        /*
         * If the total number of held buffers is higher than the configured
         * value remove a buffer from the queue with the most buffers and
         * release. The buffers are held on the queues with the newest at the
         * head.
         *
         * This code stops a large series of transactions causing all the
         * buffers in the cache being held in queues of this file system.
         */
        if ((fs->release_count +
             fs->release_modified_count) >= fs->max_held_buffers)
        {
          rtems_rfs_buffer* buffer;
          bool              modified;

          if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
            printf ("rtems-rfs: buffer-release: local cache overflow:"
                    " %" PRIu32 "\n", fs->release_count + fs->release_modified_count);

          if (fs->release_count > fs->release_modified_count)
          {
            buffer = (rtems_rfs_buffer*) rtems_chain_get (&fs->release);
            fs->release_count--;
            modified = false;
          }
          else
          {
            buffer =
              (rtems_rfs_buffer*) rtems_chain_get (&fs->release_modified);
            fs->release_modified_count--;
            modified = true;
          }
          buffer->user = (void*) 0;
          rc = rtems_rfs_buffer_io_release (buffer, modified);
        }

        if (rtems_rfs_buffer_dirty (handle))
        {
          rtems_chain_append (&fs->release_modified,
                              rtems_rfs_buffer_link (handle));
          fs->release_modified_count++;
        }
        else
        {
          rtems_chain_append (&fs->release, rtems_rfs_buffer_link (handle));
          fs->release_count++;
        }
      }
    }
    handle->buffer = NULL;
  }

  return rc;
}
int
rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
                     rtems_rfs_pos          pos,
                     rtems_rfs_pos*         new_pos)
{
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos);
  
  /*
   * This call only sets the position if it is in a valid part of the file. The
   * user can request past the end of the file then write to extend the
   * file. The lseek entry states:
   *
   *    "Although lseek() may position the file offset beyond the end of the
   *     file, this function does not itself extend the size of the file."
   *
   * This means the file needs to set the file size to the pos only when a
   * write occurs.
   */
  if (pos < rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
                                            handle->shared))
  {
    rtems_rfs_file_set_bpos (handle, pos);
    
    /*
     * If the file has a block check if it maps to the current position and it
     * does not release it. That will force us to get the block at the new
     * position when the I/O starts.
     */
    if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
    {
      rtems_rfs_buffer_block block;
      int                    rc;
      
      rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                     rtems_rfs_file_map (handle),
                                     rtems_rfs_file_bpos (handle),
                                     &block);
      if (rc > 0)
        return rc;
      if (rtems_rfs_buffer_bnum (&handle->buffer) != block)
      {        
        rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                              rtems_rfs_file_buffer (handle));
        if (rc > 0)
          return rc;
      }
    }
  }
  else
  {
    /*
     * The seek is outside the current file so release any buffer. A write will
     * extend the file.
     */
    int rc = rtems_rfs_file_io_release (handle);
    if (rc > 0)
      return rc;
  }
  
  *new_pos = pos;
  return 0;
}
int
rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
                       size_t                 size,
                       bool                   read)
{
  bool atime;
  bool mtime;
  bool length;
  int  rc = 0;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
            read ? "read" : "write", size);
  
  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    if (!read)
      rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle));
    if (rc > 0)
    {
      printf (
        "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
        read ? "read" : "write", size, rc, strerror (rc));
      
      return rc;
    }
  }

  /*
   * Update the handle's position. Only a block size can be handled at a time
   * so no special maths is needed. If the offset is bigger than the block size
   * increase the block number and adjust the offset.
   *
   * If we are the last block and the position is past the current size update
   * the size with the new length. The map holds the block count.
   */
  handle->bpos.boff += size;

  if (handle->bpos.boff >=
      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
  {
    handle->bpos.bno++;
    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
  }

  length = false;
  mtime = false;
  
  if (!read &&
      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
                                    rtems_rfs_file_bpos (handle)))
  {
    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
                                         handle->bpos.boff);
    length = true;
    mtime = true;
  }
  
  atime  = rtems_rfs_file_update_atime (handle);
  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
  length = rtems_rfs_file_update_length (handle) && length;
  
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
            handle->bpos.bno, handle->bpos.boff,
            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
  
  if (atime || mtime)
  {
    time_t now = time (NULL);
    if (read && atime)
      handle->shared->atime = now;
    if (!read && mtime)
      handle->shared->mtime = now;
  }
  if (length)
  {
    handle->shared->size.count =
      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
    handle->shared->size.offset =
      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  }
  
  return rc;
}
int
rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
                         size_t*                available,
                         bool                   read)
{
  size_t size;
  
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
  
  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    rtems_rfs_buffer_block block;
    bool                   request_read;
    int                    rc;
     
    request_read = read;
    
    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                   rtems_rfs_file_map (handle),
                                   rtems_rfs_file_bpos (handle),
                                   &block);
    if (rc > 0)
    {
      /*
       * Has the read reached the EOF ?
       */
      if (read && (rc == ENXIO))
      {
        *available = 0;
        return 0;
      }
      
      if (rc != ENXIO)
        return rc;

      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
        printf ("rtems-rfs: file-io: start: grow\n");
      
      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
                                     rtems_rfs_file_map (handle),
                                     1, &block);
      if (rc > 0)
        return rc;

      request_read = false;
    }
    else
    {
      /*
       * If this is a write check if the write starts within a block or the
       * amount of data is less than a block size. If it is read the block
       * rather than getting a block to fill.
       */
      if (!read &&
          (rtems_rfs_file_block_offset (handle) ||
           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
        request_read = true;
    }
    
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
      printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
              block, request_read ? "yes" : "no");
    
    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle),
                                          block, request_read);
    if (rc > 0)
      return rc;
  }
  
  if (read
      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  else
    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
  
  *available = size - rtems_rfs_file_block_offset (handle);

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
            *available, size);
    
  return 0;
}