Ejemplo n.º 1
0
/*---------------------------------------------------------------------------*/
static struct file *
find_file(const char *name)
{
  int i;
  struct file_header hdr;
  coffee_page_t page;
  
  /* First check if the file metadata is cached. */
  for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) {
    if(FILE_FREE(&coffee_files[i])) {
      continue;
    }

    read_header(&hdr, coffee_files[i].page);
    if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr) && strcmp(name, hdr.name) == 0) {
      return &coffee_files[i];
    }
  }
  
  /* Scan the flash memory sequentially otherwise. */
  for(page = 0; page < COFFEE_PAGE_COUNT; page = next_file(page, &hdr)) {
    read_header(&hdr, page);
    if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr) && strcmp(name, hdr.name) == 0) {
      return load_file(page, &hdr);
    }
  }

  return NULL;
}
Ejemplo n.º 2
0
/*---------------------------------------------------------------------------*/
int
cfs_readdir(struct cfs_dir *dir, struct cfs_dirent *record)
{
  struct file_header hdr;
  coffee_page_t page;

  memcpy(&page, dir->dummy_space, sizeof(coffee_page_t));

  while(page < COFFEE_PAGE_COUNT) {
    read_header(&hdr, page);
    if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) {
      coffee_page_t next_page;
      memcpy(record->name, hdr.name, sizeof(record->name));
      record->name[sizeof(record->name) - 1] = '\0';
      record->size = file_end(page);

      next_page = next_file(page, &hdr);
      memcpy(dir->dummy_space, &next_page, sizeof(coffee_page_t));
      return 0;
    }
    page = next_file(page, &hdr);
  }

  return -1;
}
Ejemplo n.º 3
0
/*---------------------------------------------------------------------------*/
static void
read_header(struct file_header *hdr, coffee_page_t page)
{
  COFFEE_READ(hdr, sizeof(*hdr), page * COFFEE_PAGE_SIZE);
#if DEBUG
  if(HDR_ACTIVE(*hdr) && !HDR_VALID(*hdr)) {
    PRINTF("Invalid header at page %u!\n", (unsigned)page);
  }
#endif
}
Ejemplo n.º 4
0
/*---------------------------------------------------------------------------*/
static int
remove_by_page(coffee_page_t page, int remove_log, int close_fds,
               int gc_allowed)
{
  struct file_header hdr;
  int i;

  read_header(&hdr, page);
  if(!HDR_ACTIVE(hdr)) {
    return -1;
  }

  if(remove_log && HDR_MODIFIED(hdr)) {
    if(remove_by_page(hdr.log_page, !REMOVE_LOG, !CLOSE_FDS, !ALLOW_GC) < 0) {
      return -1;
    }
  }

  hdr.flags |= HDR_FLAG_OBSOLETE;
  write_header(&hdr, page);

  *gc_wait = 0;

  /* Close all file descriptors that reference the removed file. */
  if(close_fds) {
    for(i = 0; i < COFFEE_FD_SET_SIZE; i++) {
      if(coffee_fd_set[i].file != NULL && coffee_fd_set[i].file->page == page) {
	coffee_fd_set[i].flags = COFFEE_FD_FREE;
      }
    }
  }

  for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) {
    if(coffee_files[i].page == page) {
      coffee_files[i].page = INVALID_PAGE;
      coffee_files[i].references = 0;
      coffee_files[i].max_pages = 0;
    }
  }

#if !COFFEE_EXTENDED_WEAR_LEVELLING
  if(gc_allowed) {
    collect_garbage(GC_RELUCTANT);
  }
#endif

  return 0;
}
/*---------------------------------------------------------------------------*/
int
cfs_readdir(struct cfs_dir *dir, struct cfs_dirent *record)
{
    struct file_header hdr;
    coffee_page_t page;

    for(page = *(coffee_page_t *)dir->dummy_space; page < COFFEE_PAGE_COUNT;) {
        watchdog_periodic();
        read_header(&hdr, page);
        if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) {
            memcpy(record->name, hdr.name, sizeof(record->name));
            record->name[sizeof(record->name) - 1] = '\0';
            record->size = file_end(page);
            *(coffee_page_t *)dir->dummy_space = next_file(page, &hdr);
            return 0;
        }
        page = next_file(page, &hdr);
    }

    return -1;
}
Ejemplo n.º 6
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
get_sector_status(uint16_t sector, struct sector_status *stats)
{
  static coffee_page_t skip_pages;
  static char last_pages_are_active;
  struct file_header hdr;
  coffee_page_t active, obsolete, free;
  coffee_page_t sector_start, sector_end;
  coffee_page_t page;

  memset(stats, 0, sizeof(*stats));
  active = obsolete = free = 0;

  /*
   * get_sector_status() is an iterative function using local static 
   * state. It therefore requires that the caller starts iterating from 
   * sector 0 in order to reset the internal state.
   */
  if(sector == 0) {
    skip_pages = 0;
    last_pages_are_active = 0;
  }

  sector_start = sector * COFFEE_PAGES_PER_SECTOR;
  sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;

  /*
   * Account for pages belonging to a file starting in a previous 
   * segment that extends into this segment. If the whole segment is 
   * covered, we do not need to continue counting pages in this iteration.
   */
  if(last_pages_are_active) {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->active = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return 0;
    }
    active = skip_pages;
  } else {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->obsolete = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return skip_pages >= COFFEE_PAGES_PER_SECTOR ? 0 : skip_pages;
    }
    obsolete = skip_pages;
  }

  /* Determine the amount of pages of each type that have not been 
     accounted for yet in the current sector. */
  for(page = sector_start + skip_pages; page < sector_end;) {
    read_header(&hdr, page);
    last_pages_are_active = 0;
    if(HDR_ACTIVE(hdr)) {
      last_pages_are_active = 1;
      page += hdr.max_pages;
      active += hdr.max_pages;
    } else if(HDR_ISOLATED(hdr)) {
      page++;
      obsolete++;
    } else if(HDR_OBSOLETE(hdr)) {
      page += hdr.max_pages;
      obsolete += hdr.max_pages;
    } else {
      free = sector_end - page;
      break;
    }
  }

  /*
   * Determine the amount of pages in the following sectors that
   * should be remembered for the next iteration. This is necessary 
   * because no page except the first of a file contains information 
   * about what type of page it is. A side effect of remembering this
   * amount is that there is no need to read in the headers of each 
   * of these pages from the storage.
   */
  skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR;
  if(skip_pages > 0) {
    if(last_pages_are_active) {
      active = COFFEE_PAGES_PER_SECTOR - obsolete;
    } else {
      obsolete = COFFEE_PAGES_PER_SECTOR - active;
    }
  }

  stats->active = active;
  stats->obsolete = obsolete;
  stats->free = free;

  /*
   * To avoid unnecessary page isolation, we notify the caller that 
   * "skip_pages" pages should be isolated only if the current file extent 
   * ends in the next sector. If the file extent ends in a more distant 
   * sector, however, the garbage collection can free the next sector 
   * immediately without requiring page isolation. 
   */
  return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ?
	0 : skip_pages;
}
Ejemplo n.º 7
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
get_sector_status(uint16_t sector, struct sector_status *stats)
{
  static coffee_page_t skip_pages;
  static char last_pages_are_active;
  struct file_header hdr;
  coffee_page_t active, obsolete, free;
  coffee_page_t sector_start, sector_end;
  coffee_page_t page;

  memset(stats, 0, sizeof(*stats));
  active = obsolete = free = 0;

  if(sector == 0) {
    skip_pages = 0;
    last_pages_are_active = 0;
  }

  sector_start = sector * COFFEE_PAGES_PER_SECTOR;
  sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;

  if(last_pages_are_active) {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->active = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return 0;
    }
    active = skip_pages;
  } else {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->obsolete = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return skip_pages >= COFFEE_PAGES_PER_SECTOR ? 0 : skip_pages;
    }
    obsolete = skip_pages;
  }

  for(page = sector_start + skip_pages; page < sector_end;) {
    read_header(&hdr, page);
    last_pages_are_active = 0;
    if(HDR_ACTIVE(hdr)) {
      last_pages_are_active = 1;
      page += hdr.max_pages;
      active += hdr.max_pages;
    } else if(HDR_ISOLATED(hdr)) {
      page++;
      obsolete++;
    } else if(HDR_OBSOLETE(hdr)) {
      page += hdr.max_pages;
      obsolete += hdr.max_pages;
    } else {
      free = sector_end - page;
      break;
    }
  }

  skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR;
  if(skip_pages > 0) {
    if(last_pages_are_active) {
      active = COFFEE_PAGES_PER_SECTOR - obsolete;
    } else {
      obsolete = COFFEE_PAGES_PER_SECTOR - active;
    }
  }

  stats->active = active;
  stats->obsolete = obsolete;
  stats->free = free;

  return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ?
	0 : skip_pages;
}