Changeset 575:4ece9d9962f1

Show
Ignore:
Timestamp:
06/03/08 08:53:55 (7 months ago)
Author:
Maxime Petazzoni <maxime.petazzoni@…>
Children:
576:59253836afad, 581:2d38c2b64075
Branch:
default
Message:

Merge _fs.[ch] and defrag.[ch] into fs.[ch] since the separation is not actually required.

Location:
nxos/base
Files:
4 removed
2 modified

Legend:

Unmodified
Added
Removed
  • nxos/base/fs.c

    r551 r575  
    1 /* Copyright (C) 2008 the NxOS developers 
     1/* Copyright (c) 2008 the NxOS developers 
    22 * 
    33 * See AUTHORS for a full list of the developers. 
     
    1515#include "base/util.h" 
    1616#include "base/fs.h" 
    17 #include "base/_fs.h" 
    1817#include "base/drivers/_efc.h" 
    1918 
    20 #include "base/display.h" 
    21  
    22 extern fs_file_t fdset[FS_MAX_OPENED_FILES]; 
     19/** Magic marker. */ 
     20#define FS_FILE_ORIGIN_MARKER 0x42 
     21 
     22/** File metadata size, in U32s. */ 
     23#define FS_FILE_METADATA_SIZE 10 
     24 
     25/** File metadata size, in bytes. */ 
     26#define FS_FILE_METADATA_BYTES (FS_FILE_METADATA_SIZE * sizeof(U32)) 
     27 
     28#define FS_FILE_ORIGIN_MASK 0xFF000000 
     29#define FS_FILE_PERMS_MASK 0x00F00000 
     30#define FS_FILE_SIZE_MASK 0x000FFFFF 
     31 
     32#define FS_FILE_PERM_MASK_READWRITE (1 << 0) 
     33#define FS_FILE_PERM_MASK_EXECUTABLE (1 << 1) 
     34 
     35#define FS_FILENAME_OFFSET 2 
     36 
     37/** U32 <-> char conversion union for filenames. */ 
     38union U32tochar { 
     39  char chars[FS_FILENAME_LENGTH]; 
     40  U32 integers[FS_FILENAME_SIZE]; 
     41}; 
     42 
     43/** FD-set. */ 
     44static fs_file_t fdset[FS_MAX_OPENED_FILES]; 
     45 
     46/* Returns a file info structure given its file descriptor, 
     47 * or NULL if the fd is invalid. 
     48 */ 
     49static fs_file_t *nx_fs_get_file(fs_fd_t fd) { 
     50  NX_ASSERT(fd < FS_MAX_OPENED_FILES); 
     51 
     52  if (!fdset[fd].used) { 
     53    return NULL; 
     54  } 
     55 
     56  return &(fdset[fd]); 
     57} 
     58 
     59/* Determines if the given page contains a file origin marker. 
     60 */ 
     61inline static bool nx_fs_page_has_magic(U32 page) { 
     62  return ((FLASH_BASE_PTR[page*EFC_PAGE_WORDS] & FS_FILE_ORIGIN_MASK) >> 24) 
     63    == FS_FILE_ORIGIN_MARKER; 
     64} 
     65 
     66/* Returns the number of pages used by a file, given its size. 
     67 */ 
     68static U32 nx_fs_get_file_page_count(size_t size) { 
     69  U32 pages; 
     70 
     71  /* Compute page occupation. */ 
     72  size += FS_FILE_METADATA_BYTES; 
     73  pages = size / EFC_PAGE_BYTES; 
     74  if (size % EFC_PAGE_BYTES) { 
     75    pages++; 
     76  } 
     77 
     78  return pages; 
     79} 
     80 
     81inline static size_t nx_fs_get_file_size_from_metadata(volatile U32 *metadata) { 
     82  return *metadata & FS_FILE_SIZE_MASK; 
     83} 
     84 
     85static fs_perm_t nx_fs_get_file_perms_from_metadata(volatile U32 *metadata) { 
     86  U8 perms = (*metadata & FS_FILE_PERMS_MASK) >> 20; 
     87 
     88  if (perms & FS_FILE_PERM_MASK_READWRITE) { 
     89    return FS_PERM_READWRITE; 
     90  } else if (perms & FS_FILE_PERM_MASK_EXECUTABLE) { 
     91    return FS_PERM_EXECUTABLE; 
     92  } 
     93 
     94  /* Defaults to read-only. */ 
     95  return FS_PERM_READONLY; 
     96} 
     97 
     98/* Find a file's origin on the file system by its name. 
     99 */ 
     100static fs_err_t nx_fs_find_file_origin(char *name, U32 *origin) { 
     101  U32 i; 
     102 
     103  for (i=FS_PAGE_START; i<FS_PAGE_END; i++) { 
     104    if (nx_fs_page_has_magic(i)) { 
     105      volatile U32 *metadata = &(FLASH_BASE_PTR[i*EFC_PAGE_WORDS]); 
     106      union U32tochar nameconv; 
     107 
     108      memcpy(nameconv.integers, 
     109             (void *)(metadata + FS_FILENAME_OFFSET), 
     110             FS_FILENAME_LENGTH); 
     111 
     112      if (streq(nameconv.chars, name)) { 
     113        *origin = i; 
     114        return FS_ERR_NO_ERROR; 
     115      } 
     116 
     117      /* Otherwise jump over the file and continue searching. */ 
     118      else { 
     119        i += nx_fs_get_file_page_count( 
     120          nx_fs_get_file_size_from_metadata(metadata)) - 1; 
     121      } 
     122    } 
     123  } 
     124 
     125  return FS_ERR_FILE_NOT_FOUND; 
     126} 
     127 
     128/* Finds the last file origin on the flash. 
     129 */ 
     130static fs_err_t nx_fs_find_last_origin(U32 *origin) { 
     131  U32 candidate = 0, i; 
     132 
     133  for (i=FS_PAGE_START; i<FS_PAGE_END; i++) { 
     134    if (nx_fs_page_has_magic(i)) { 
     135      volatile U32 *metadata = &(FLASH_BASE_PTR[i*EFC_PAGE_WORDS]); 
     136 
     137      candidate = i; 
     138      i += nx_fs_get_file_page_count( 
     139        nx_fs_get_file_size_from_metadata(metadata)) - 1; 
     140    } 
     141  } 
     142 
     143  if (candidate) { 
     144    *origin = candidate; 
     145    return FS_ERR_NO_ERROR; 
     146  } 
     147 
     148  return FS_ERR_FILE_NOT_FOUND; 
     149} 
     150 
     151static fs_err_t nx_fs_find_next_origin(U32 start, U32 *origin) { 
     152  U32 i; 
     153 
     154  for (i=start; i<FS_PAGE_END; i++) { 
     155    if (nx_fs_page_has_magic(i)) { 
     156      *origin = i; 
     157      return FS_ERR_NO_ERROR; 
     158    } 
     159  } 
     160 
     161  return FS_ERR_FILE_NOT_FOUND; 
     162} 
     163 
     164/* Serialize a file's metadata using the provided values and returns 
     165 * the resulting U32s, ready to be stored on flash. 
     166 */ 
     167static void nx_fs_create_metadata(fs_perm_t perms, char *name, size_t size, 
     168                                  U32 *metadata) { 
     169  union U32tochar nameconv; 
     170 
     171  memset(metadata, 0, FS_FILE_METADATA_BYTES); 
     172 
     173  memset(nameconv.chars, 0, 32); 
     174  memcpy(nameconv.chars, name, MIN(strlen(name), 31)); 
     175 
     176  /* Magic marker. */ 
     177  metadata[0] = (FS_FILE_ORIGIN_MARKER << 24); 
     178 
     179  /* File permissions. */ 
     180  switch (perms) { 
     181    case FS_PERM_READWRITE: 
     182      metadata[0] += (FS_FILE_PERM_MASK_READWRITE << 20); 
     183      break; 
     184    case FS_PERM_EXECUTABLE: 
     185      metadata[0] += (FS_FILE_PERM_MASK_EXECUTABLE << 20); 
     186      break; 
     187    default: 
     188      break; 
     189  } 
     190 
     191  /* File size. */ 
     192  metadata[0] += (size & FS_FILE_SIZE_MASK); 
     193 
     194  /* Insert here in metadata[1] what would be relevant (future). */ 
     195 
     196  /* File name. */ 
     197  memcpy(metadata + FS_FILENAME_OFFSET, nameconv.integers, FS_FILENAME_LENGTH); 
     198} 
     199 
     200/* Move a @a len long flash region starting at page @a source to @a dest. 
     201 * Since pages are moved one after another, regions may overlap if the 
     202 * destination is lower in the flash than the source, but not the other 
     203 * way around. Note that this is asserted anyway to avoid data loss. 
     204 * It is the responsibility of the caller to clean up the remaining 
     205 * source region of any data he doesn't want to leave there (file origin 
     206 * markers for example). 
     207 * 
     208 * @param source The source page number. 
     209 * @param dest The destination page number. 
     210 * @param len The region length. 
     211 */ 
     212static fs_err_t nx_fs_move_region(U32 source, U32 dest, U32 len) { 
     213  U32 data; 
     214 
     215  NX_ASSERT(source < EFC_PAGES); 
     216  NX_ASSERT(dest < EFC_PAGES); 
     217  NX_ASSERT(len < EFC_PAGES); 
     218  NX_ASSERT(dest - source <= len); 
     219 
     220  while (len--) { 
     221    data = FLASH_BASE_PTR[source*EFC_PAGE_WORDS]; 
     222    if (!nx__efc_write_page(&data, dest)) { 
     223      return FS_ERR_FLASH_ERROR; 
     224    } 
     225 
     226    /* TODO: erase the source page ? */ 
     227 
     228    source++; 
     229    dest++; 
     230  } 
     231 
     232  return FS_ERR_NO_ERROR; 
     233} 
     234 
     235/* Relocate the given file to @a origin. 
     236 */ 
     237static fs_err_t nx_fs_relocate_to_page(fs_file_t *file, U32 origin) { 
     238  U32 page_data[EFC_PAGE_WORDS], null_data[EFC_PAGE_WORDS] = {0}; 
     239  U32 diff, i; 
     240  size_t size; 
     241 
     242  diff = origin - file->origin; 
     243 
     244  /* Move the file's data. */ 
     245  size = nx_fs_get_file_page_count(file->size); 
     246 
     247  /* TODO: use nx_fs_move_region? */ 
     248  for (i=file->origin; i<size; i++) { 
     249    nx__efc_read_page(i, page_data); 
     250    /* TODO: figure out if we want to erase the source page now or later. */ 
     251    if (!nx__efc_write_page(page_data, i + diff) 
     252      || !nx__efc_write_page(null_data, i)) { 
     253      return FS_ERR_FLASH_ERROR; 
     254    } 
     255  } 
     256 
     257  file->origin = origin; 
     258  file->rbuf.page += diff; 
     259  file->wbuf.page += diff; 
     260 
     261  return FS_ERR_NO_ERROR; 
     262} 
     263 
     264static fs_err_t nx_fs_relocate(fs_file_t *file) { 
     265  U32 origin, start; 
     266  size_t size; 
     267 
     268  size = nx_fs_get_file_page_count(file->size); 
     269 
     270  /* First, look at the end of the flash for free space. */ 
     271  if (nx_fs_find_last_origin(&origin) == FS_ERR_NO_ERROR) { 
     272    origin += nx_fs_get_file_page_count( 
     273                nx_fs_get_file_size_from_metadata( 
     274                  &(FLASH_BASE_PTR[origin*EFC_PAGE_WORDS]))); 
     275 
     276    if (size < FS_PAGE_END - origin) { 
     277      return nx_fs_relocate_to_page(file, origin); 
     278    } 
     279  } 
     280 
     281  start = FS_PAGE_START; 
     282  while (nx_fs_find_next_origin(start, &origin) != FS_ERR_FILE_NOT_FOUND) { 
     283    if (size < origin - start || (origin == file->origin && file->origin - start > 0)) { 
     284      return nx_fs_relocate_to_page(file, origin); 
     285    } 
     286 
     287    start = origin + nx_fs_get_file_page_count( 
     288                nx_fs_get_file_size_from_metadata( 
     289                  &(FLASH_BASE_PTR[origin*EFC_PAGE_WORDS]))); 
     290  } 
     291 
     292  return FS_ERR_NO_SPACE_LEFT_ON_DEVICE; 
     293} 
    23294 
    24295/* Initialize the file system, most importantly check for file system 
     
    34305  fs_file_t *file; 
    35306 
    36   file = nx__fs_get_file(fd); 
     307  file = nx_fs_get_file(fd); 
    37308  NX_ASSERT(file != NULL); 
    38309 
    39310  file->origin = origin; 
    40   file->size = nx__fs_get_file_size_from_metadata(metadata); 
    41   file->perms = nx__fs_get_file_perms_from_metadata(metadata); 
     311  file->size = nx_fs_get_file_size_from_metadata(metadata); 
     312  file->perms = nx_fs_get_file_perms_from_metadata(metadata); 
    42313 
    43314  file->rbuf.page = file->rbuf.pos = 0; 
     
    54325  fs_err_t err; 
    55326 
    56   err = nx__fs_find_file_origin(name, &origin); 
     327  err = nx_fs_find_file_origin(name, &origin); 
    57328  if (err != FS_ERR_NO_ERROR) { 
    58329    return err; 
     
    69340 
    70341  /* Check that a file by that name does not already exists. */ 
    71   err = nx__fs_find_file_origin(name, &origin); 
     342  err = nx_fs_find_file_origin(name, &origin); 
    72343  if (err != FS_ERR_FILE_NOT_FOUND) { 
    73344    return FS_ERR_FILE_ALREADY_EXISTS; 
     
    75346 
    76347  /* Find an origin page. */ 
    77   if (nx__fs_find_last_origin(&origin) == FS_ERR_NO_ERROR) { 
    78     origin += nx__fs_get_file_page_count( 
    79                 nx__fs_get_file_size_from_metadata( 
     348  if (nx_fs_find_last_origin(&origin) == FS_ERR_NO_ERROR) { 
     349    origin += nx_fs_get_file_page_count( 
     350                nx_fs_get_file_size_from_metadata( 
    80351                  &(FLASH_BASE_PTR[origin*EFC_PAGE_WORDS]))); 
    81352  } else { 
     
    90361 
    91362  /* Bootstrap the metadata to the flash page. */ 
    92   nx__fs_create_metadata(FS_PERM_READWRITE, name, 0, metadata); 
     363  nx_fs_create_metadata(FS_PERM_READWRITE, name, 0, metadata); 
    93364 
    94365  /* Write metadata to flash. */ 
     
    157428      /* Put writing position at the end of the file. */ 
    158429      file->wbuf.page = file->origin 
    159         + nx__fs_get_file_page_count(file->size) - 1; 
     430        + nx_fs_get_file_page_count(file->size) - 1; 
    160431      nx__efc_read_page(file->wbuf.page, file->wbuf.data.raw); 
    161432      file->wbuf.pos = (FS_FILE_METADATA_BYTES + file->size) % EFC_PAGE_BYTES; 
     
    185456  fs_file_t *file; 
    186457 
    187   file = nx__fs_get_file(fd); 
     458  file = nx_fs_get_file(fd); 
    188459  if (!file) { 
    189460    return -1; 
     
    197468  fs_file_t *file; 
    198469 
    199   file = nx__fs_get_file(fd); 
     470  file = nx_fs_get_file(fd); 
    200471  if (!file) { 
    201472    return FS_ERR_INVALID_FD; 
     
    227498  U32 pages; 
    228499 
    229   file = nx__fs_get_file(fd); 
     500  file = nx_fs_get_file(fd); 
    230501  if (!file) { 
    231502    return FS_ERR_INVALID_FD; 
    232503  } 
    233504 
    234   pages = nx__fs_get_file_page_count(file->size) - 1; 
     505  pages = nx_fs_get_file_page_count(file->size) - 1; 
    235506 
    236507  /* Check that the page we will be writing to is available, 
     
    240511  if (file->wbuf.pos == 0 && 
    241512    file->wbuf.page > file->origin + pages && 
    242     nx__fs_page_has_magic(file->wbuf.page)) { 
     513    nx_fs_page_has_magic(file->wbuf.page)) { 
    243514    /* If the page we want to use is not available relocate the file. */ 
    244     err = nx__fs_relocate(file); 
     515    err = nx_fs_relocate(file); 
    245516    if (err != FS_ERR_NO_ERROR) { 
    246517      return err; 
     
    279550  fs_file_t *file; 
    280551 
    281   file = nx__fs_get_file(fd); 
     552  file = nx_fs_get_file(fd); 
    282553  if (!file) { 
    283554    return FS_ERR_INVALID_FD; 
     
    304575  fs_err_t err; 
    305576 
    306   file = nx__fs_get_file(fd); 
     577  file = nx_fs_get_file(fd); 
    307578  if (!file) { 
    308579    return FS_ERR_INVALID_FD; 
     
    316587  /* Update the file's metadata. */ 
    317588  nx__efc_read_page(file->origin, firstpage); 
    318   nx__fs_create_metadata(file->perms, file->name, file->size, firstpage); 
     589  nx_fs_create_metadata(file->perms, file->name, file->size, firstpage); 
    319590  if (!nx__efc_write_page(firstpage, file->origin)) { 
    320591    return FS_ERR_FLASH_ERROR; 
     
    328599  fs_file_t *file; 
    329600 
    330   file = nx__fs_get_file(fd); 
     601  file = nx_fs_get_file(fd); 
    331602  if (!file) { 
    332603    return FS_ERR_INVALID_FD; 
     
    339610  fs_file_t *file; 
    340611 
    341   file = nx__fs_get_file(fd); 
     612  file = nx_fs_get_file(fd); 
    342613  if (!file) { 
    343614    return FS_ERR_INVALID_FD; 
     
    355626  U32 erase[EFC_PAGE_WORDS] = {0}; 
    356627 
    357   file = nx__fs_get_file(fd); 
     628  file = nx_fs_get_file(fd); 
    358629  if (!file) { 
    359630    return FS_ERR_INVALID_FD; 
     
    361632 
    362633  /* Remove file marker and potential in-file marker-alike. */ 
    363   end = file->origin + nx__fs_get_file_page_count(file->size); 
     634  end = file->origin + nx_fs_get_file_page_count(file->size); 
    364635  for (page = file->origin; page < end; page++) { 
    365     if (nx__fs_page_has_magic(page)) { 
     636    if (nx_fs_page_has_magic(page)) { 
    366637      /* Erase marker. */ 
    367638      if (!nx__efc_write_page(erase, page)) { 
     
    378649 */ 
    379650fs_err_t nx_fs_seek(fs_fd_t fd, size_t position) { 
    380         fs_file_t *file; 
    381         U32 page; 
     651  fs_file_t *file; 
     652  U32 page; 
    382653  U32 pos; 
    383654 
    384         file = nx__fs_get_file(fd); 
    385         if (!file) { 
    386                 return FS_ERR_INVALID_FD; 
    387         } 
    388          
    389         if (position > file->size) { 
    390                 return FS_ERR_INCORRECT_SEEK; 
    391         } 
    392          
     655  file = nx_fs_get_file(fd); 
     656  if (!file) { 
     657    return FS_ERR_INVALID_FD; 
     658  } 
     659 
     660  if (position > file->size) { 
     661    return FS_ERR_INCORRECT_SEEK; 
     662  } 
     663 
    393664  position += FS_FILE_METADATA_BYTES; 
    394665 
     
    421692  } 
    422693} 
     694 
     695/** Defrag functions. */ 
     696 
     697fs_err_t nx_fs_defrag_simple(void) { 
     698  return FS_ERR_NO_ERROR; 
     699} 
     700 
     701fs_err_t nx_fs_defrag_for_file_by_name(char *name) { 
     702  U32 origin; 
     703  fs_err_t err; 
     704 
     705  err = nx_fs_find_file_origin(name, &origin); 
     706  if (err == FS_ERR_NO_ERROR) { 
     707    return nx_fs_defrag_for_file_by_origin(origin); 
     708  } 
     709 
     710  /* Fall back to simple defrag. */ 
     711  return nx_fs_defrag_simple(); 
     712} 
     713 
     714fs_err_t nx_fs_defrag_for_file_by_origin(U32 origin) { 
     715  nx_fs_move_region(origin, 1, 1); // TBR 
     716 
     717  return FS_ERR_NO_ERROR; 
     718} 
     719 
     720fs_err_t nx_fs_defrag_best_overall(void) { 
     721  return FS_ERR_NO_ERROR; 
     722} 
     723 
  • nxos/base/fs.h

    r551 r575  
    55 */ 
    66 
    7 /* Copyright (C) 2008 the NxOS developers 
     7/* Copyright (c) 2008 the NxOS developers 
    88 * 
    99 * See AUTHORS for a full list of the developers. 
     
    2424/** @defgroup fs Flash file system */ 
    2525/*@{*/ 
     26 
     27/** File-system first page number. */ 
     28#define FS_PAGE_START 128 
     29 
     30/** File-system last page number. */ 
     31#define FS_PAGE_END 1024 
    2632 
    2733/** Maximum number of files that can be stored by the filesystem. 
     
    184190                          U32 *wasted); 
    185191 
     192/** Perform a simple defragmentation of the flash filesystem. 
     193 * 
     194 * This type of defragmentation only tries to collate files towards 
     195 * the beginning of the flash medium, maximizing free space at the end of 
     196 * the flash. 
     197 * 
     198 * @return A @a fs_err_t describing the outcome of the operation. 
     199 */ 
     200fs_err_t nx_fs_defrag_simple(void); 
     201 
     202/** Perform a simple, file oriented defragmentation of the flash. 
     203 * 
     204 * This defragmentation type is similar to the simple one, but 
     205 * with the objective of making subsequent writes to the given file 
     206 * (by its name) faster by putting it at the end of the flash medium. 
     207 * 
     208 * @return A @a fs_err_t describing the outcome of the operation. 
     209 */ 
     210fs_err_t nx_fs_defrag_for_file_by_name(char *name); 
     211 
     212/** Same as @a nx_defrag_for_file_by_name but takes a file origin 
     213 * instead. This function is called by @a nx_defrag_for_file_by_name 
     214 * once it has found the requested file's origin. 
     215 * 
     216 * @return A @a fs_err_t describing the outcome of the operation. 
     217 */ 
     218fs_err_t nx_fs_defrag_for_file_by_origin(U32 origin); 
     219 
     220/** Tries to optimize the placement of the files on the filesystem 
     221 * to make write operations faster for all files by putting as much 
     222 * space as possible between each file and thus avoid a costy file 
     223 * relocation. 
     224 * 
     225 * @return A @a fs_err_t describing the outcome of the operation. 
     226 */ 
     227fs_err_t nx_fs_defrag_best_overall(void); 
     228 
    186229/*@}*/ 
    187230/*@}*/