Changeset 575:4ece9d9962f1
- Timestamp:
- 06/03/08 08:53:55 (7 months ago)
- Children:
- 576:59253836afad, 581:2d38c2b64075
- Branch:
- default
- Location:
- nxos/base
- Files:
-
- 4 removed
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
nxos/base/fs.c
r551 r575 1 /* Copyright ( C) 2008 the NxOS developers1 /* Copyright (c) 2008 the NxOS developers 2 2 * 3 3 * See AUTHORS for a full list of the developers. … … 15 15 #include "base/util.h" 16 16 #include "base/fs.h" 17 #include "base/_fs.h"18 17 #include "base/drivers/_efc.h" 19 18 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. */ 38 union U32tochar { 39 char chars[FS_FILENAME_LENGTH]; 40 U32 integers[FS_FILENAME_SIZE]; 41 }; 42 43 /** FD-set. */ 44 static 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 */ 49 static 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 */ 61 inline 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 */ 68 static 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 81 inline static size_t nx_fs_get_file_size_from_metadata(volatile U32 *metadata) { 82 return *metadata & FS_FILE_SIZE_MASK; 83 } 84 85 static 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 */ 100 static 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 */ 130 static 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 151 static 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 */ 167 static 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 */ 212 static 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 */ 237 static 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 264 static 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 } 23 294 24 295 /* Initialize the file system, most importantly check for file system … … 34 305 fs_file_t *file; 35 306 36 file = nx_ _fs_get_file(fd);307 file = nx_fs_get_file(fd); 37 308 NX_ASSERT(file != NULL); 38 309 39 310 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); 42 313 43 314 file->rbuf.page = file->rbuf.pos = 0; … … 54 325 fs_err_t err; 55 326 56 err = nx_ _fs_find_file_origin(name, &origin);327 err = nx_fs_find_file_origin(name, &origin); 57 328 if (err != FS_ERR_NO_ERROR) { 58 329 return err; … … 69 340 70 341 /* 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); 72 343 if (err != FS_ERR_FILE_NOT_FOUND) { 73 344 return FS_ERR_FILE_ALREADY_EXISTS; … … 75 346 76 347 /* 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( 80 351 &(FLASH_BASE_PTR[origin*EFC_PAGE_WORDS]))); 81 352 } else { … … 90 361 91 362 /* 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); 93 364 94 365 /* Write metadata to flash. */ … … 157 428 /* Put writing position at the end of the file. */ 158 429 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; 160 431 nx__efc_read_page(file->wbuf.page, file->wbuf.data.raw); 161 432 file->wbuf.pos = (FS_FILE_METADATA_BYTES + file->size) % EFC_PAGE_BYTES; … … 185 456 fs_file_t *file; 186 457 187 file = nx_ _fs_get_file(fd);458 file = nx_fs_get_file(fd); 188 459 if (!file) { 189 460 return -1; … … 197 468 fs_file_t *file; 198 469 199 file = nx_ _fs_get_file(fd);470 file = nx_fs_get_file(fd); 200 471 if (!file) { 201 472 return FS_ERR_INVALID_FD; … … 227 498 U32 pages; 228 499 229 file = nx_ _fs_get_file(fd);500 file = nx_fs_get_file(fd); 230 501 if (!file) { 231 502 return FS_ERR_INVALID_FD; 232 503 } 233 504 234 pages = nx_ _fs_get_file_page_count(file->size) - 1;505 pages = nx_fs_get_file_page_count(file->size) - 1; 235 506 236 507 /* Check that the page we will be writing to is available, … … 240 511 if (file->wbuf.pos == 0 && 241 512 file->wbuf.page > file->origin + pages && 242 nx_ _fs_page_has_magic(file->wbuf.page)) {513 nx_fs_page_has_magic(file->wbuf.page)) { 243 514 /* 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); 245 516 if (err != FS_ERR_NO_ERROR) { 246 517 return err; … … 279 550 fs_file_t *file; 280 551 281 file = nx_ _fs_get_file(fd);552 file = nx_fs_get_file(fd); 282 553 if (!file) { 283 554 return FS_ERR_INVALID_FD; … … 304 575 fs_err_t err; 305 576 306 file = nx_ _fs_get_file(fd);577 file = nx_fs_get_file(fd); 307 578 if (!file) { 308 579 return FS_ERR_INVALID_FD; … … 316 587 /* Update the file's metadata. */ 317 588 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); 319 590 if (!nx__efc_write_page(firstpage, file->origin)) { 320 591 return FS_ERR_FLASH_ERROR; … … 328 599 fs_file_t *file; 329 600 330 file = nx_ _fs_get_file(fd);601 file = nx_fs_get_file(fd); 331 602 if (!file) { 332 603 return FS_ERR_INVALID_FD; … … 339 610 fs_file_t *file; 340 611 341 file = nx_ _fs_get_file(fd);612 file = nx_fs_get_file(fd); 342 613 if (!file) { 343 614 return FS_ERR_INVALID_FD; … … 355 626 U32 erase[EFC_PAGE_WORDS] = {0}; 356 627 357 file = nx_ _fs_get_file(fd);628 file = nx_fs_get_file(fd); 358 629 if (!file) { 359 630 return FS_ERR_INVALID_FD; … … 361 632 362 633 /* 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); 364 635 for (page = file->origin; page < end; page++) { 365 if (nx_ _fs_page_has_magic(page)) {636 if (nx_fs_page_has_magic(page)) { 366 637 /* Erase marker. */ 367 638 if (!nx__efc_write_page(erase, page)) { … … 378 649 */ 379 650 fs_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; 382 653 U32 pos; 383 654 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 393 664 position += FS_FILE_METADATA_BYTES; 394 665 … … 421 692 } 422 693 } 694 695 /** Defrag functions. */ 696 697 fs_err_t nx_fs_defrag_simple(void) { 698 return FS_ERR_NO_ERROR; 699 } 700 701 fs_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 714 fs_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 720 fs_err_t nx_fs_defrag_best_overall(void) { 721 return FS_ERR_NO_ERROR; 722 } 723 -
nxos/base/fs.h
r551 r575 5 5 */ 6 6 7 /* Copyright ( C) 2008 the NxOS developers7 /* Copyright (c) 2008 the NxOS developers 8 8 * 9 9 * See AUTHORS for a full list of the developers. … … 24 24 /** @defgroup fs Flash file system */ 25 25 /*@{*/ 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 26 32 27 33 /** Maximum number of files that can be stored by the filesystem. … … 184 190 U32 *wasted); 185 191 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 */ 200 fs_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 */ 210 fs_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 */ 218 fs_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 */ 227 fs_err_t nx_fs_defrag_best_overall(void); 228 186 229 /*@}*/ 187 230 /*@}*/
