Check-in [a0c8ed4b7d]

Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:a0c8ed4b7dc5fa1d6fbe81917e96b26e1b8962f7
Date: 2010-03-10 16:43:06
User: stephan
Edited Comment:woohoo! next-free-inode lookups are now O(1) (plus read/modify/write ops on up to two linked neighbors). The inode free-list had to be doubly-linked, whereas the block list is single-linked, because inodes can be opened by numeric ID (whereas blocks are doled out linearly) and that hoses a single-linked list.
Original Comment:woohoo! next-free-inode lookups are not O(1) (plus read/modify/write ops on up to two linked neighbors). The inode free-list had to be doubly-linked, whereas the block list is single-linked, because inodes can be opened by numeric ID (whereas blocks are doled out linearly) and that hoses a single-linked list.
Tags And Properties
Changes
hide diffs unified diffs patch

Changes to include/wh/whio/whio_epfs.h

Old (532372e7a87a80d1) New (bf853fe24bc90198)
1 #ifndef WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED 1 #ifndef WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED
2 #define WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED 2 #define WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED
3 #include "whio_dev.h" /* core whio_dev API. */ 3 #include "whio_dev.h" /* core whio_dev API. */
4 #include "whio_encode.h" /* for whio_sizeof_encoded_xxx */ 4 #include "whio_encode.h" /* for whio_sizeof_encoded_xxx */
5 #include "whio_epfs_config.h" /* EPFS compile-time config options. */ 5 #include "whio_epfs_config.h" /* EPFS compile-time config options. */
35 hidden lines
41 - Optimized for low memory usage: normal use cases need to allocate 41 - Optimized for low memory usage: normal use cases need to allocate
42 less than 1k of dynamic memory at runtime. Clients may provide it with 42 less than 1k of dynamic memory at runtime. Clients may provide it with
43 their own memory buffer, from which it will "allocate" any memory it 43 their own memory buffer, from which it will "allocate" any memory it
44 needs. (See whio_epfs_mempool_setup().) 44 needs. (See whio_epfs_mempool_setup().)
45 45
> 46 - As of 20100310, the last of the most performance-significant
> 47 algorithms (finding the next free block and inode) are O(1), plus a
> 48 possible extra write or two to re-link the free-list. The library
> 49 overall now performs quite well.
> 50
46 - Fairly well documented. 51 - Fairly well documented.
47 52
48 - The EFS container file is endian/platform-neutral. Clients can store 53 - The EFS container file is endian/platform-neutral. Clients can store
49 arbitrary binary data in pseudofiles, and that data may or may not be 54 arbitrary binary data in pseudofiles, and that data may or may not be
50 endian/platform-dependent. 55 endian/platform-dependent.
30 hidden lines
81 features can theoretically be added on top of it, however. 86 features can theoretically be added on top of it, however.
82 87
83 - An EFS can add data blocks on demand, but cannot currently be 88 - An EFS can add data blocks on demand, but cannot currently be
84 shrunk. It needs a vaccuum-like feature. 89 shrunk. It needs a vaccuum-like feature.
85 90
86 - Certain routines (e.g. finding the next free data block or <
87 inode entry) are linear in nature, and may require a significant <
88 amount of reading from storage. Internal optimizations cut this <
89 down considerably (orders of magnitude) for the average cases, <
90 but some use cases will perform poorly. <
91 91
92 92
93 @section page_whio_epfs_main_whefs whio_epfs vs. whefs 93 @section page_whio_epfs_main_whefs whio_epfs vs. whefs
94 94
95 whio_epfs is a spin-off/refactoring of the whefs project: 95 whio_epfs is a spin-off/refactoring of the whefs project:
461 hidden lines
557 client use. 557 client use.
558 */ 558 */
559 uint32_t cflags; 559 uint32_t cflags;
560 560
561 /** 561 /**
562 Used only be free inodes, to link to the next free inode. | 562 Used only by free inodes, to link to the next free inode.
563 */ 563 */
564 whio_epfs_id_t nextFree; 564 whio_epfs_id_t nextFree;
> 565 /**
> 566 Used only by free inodes, to link to the previous free inode.
> 567
> 568 inodes must be dual-linked, unlike blocks, because the ability
> 569 to open them directly by id confuses a single-link list and
> 570 can cause it to have cycles.
> 571 */
> 572 whio_epfs_id_t prevFree;
565 }; 573 };
566 /** Convenience typedef. */ 574 /** Convenience typedef. */
567 typedef struct whio_epfs_inode whio_epfs_inode; 575 typedef struct whio_epfs_inode whio_epfs_inode;
568 576
569 /** An empty whio_epfs_inode initialization object. */ 577 /** An empty whio_epfs_inode initialization object. */
2 hidden lines
572 0/*firstBlock*/, \ 580 0/*firstBlock*/, \
573 0/*mtime*/, \ 581 0/*mtime*/, \
574 0/*size*/, \ 582 0/*size*/, \
575 0/*flags*/, \ 583 0/*flags*/, \
576 0/*cflags*/, \ 584 0/*cflags*/, \
577 0/*nextFree*/ \ | 585 0/*nextFree*/, \
578 } | 586 0/*prevFree*/ \
| 587 }
579 /** An empty whio_epfs_inode initialization object. */ 588 /** An empty whio_epfs_inode initialization object. */
580 extern const whio_epfs_inode whio_epfs_inode_empty; 589 extern const whio_epfs_inode whio_epfs_inode_empty;
581 590
582 /** 591 /**
583 Container for managing an on-storage chain of whio_epfs_block 592 Container for managing an on-storage chain of whio_epfs_block
291 hidden lines
875 , 884 ,
876 /** 885 /**
877 Encoded size of whio_epfs_hints. 886 Encoded size of whio_epfs_hints.
878 */ 887 */
879 whio_epfs_sizeof_hints = 1/*tag byte*/ 888 whio_epfs_sizeof_hints = 1/*tag byte*/
880 + (5 * whio_epfs_sizeof_id) /* whio_epfs_hints:: | 889 + (5 * whio_epfs_sizeof_id) /* whio_epfs::whio_epfs_hints::(
881 nextFreeInode, |
882 maxEverUsedInode, 890 maxEverUsedInode,
> 891 freeInodeList,
883 freeBlockList, 892 freeBlockList,
884 maxEverUsedBlock, 893 maxEverUsedBlock,
885 blockCount) */ 894 blockCount) */
886 , 895 ,
887 /** 896 /**
888 Encoded size of whio_epfs_inode. 897 Encoded size of whio_epfs_inode.
889 */ 898 */
890 whio_epfs_sizeof_inode = 1/*tag byte*/ 899 whio_epfs_sizeof_inode = 1/*tag byte*/
891 + whio_epfs_sizeof_id/*id*/ 900 + whio_epfs_sizeof_id/*id*/
892 + whio_sizeof_encoded_uint32/*cflags*/ <
893 + whio_sizeof_encoded_uint8/*flags*/ 901 + whio_sizeof_encoded_uint8/*flags*/
894 + whio_sizeof_encoded_uint32/*mtime*/ | 902 + whio_epfs_sizeof_id/*nextFree*/
| 903 + whio_epfs_sizeof_id/*prevFree*/
895 + whio_epfs_sizeof_id/*firstBlock*/ 904 + whio_epfs_sizeof_id/*firstBlock*/
> 905 + whio_sizeof_encoded_uint32/*cflags*/
896 + whio_sizeof_encoded_size_t/*size*/ 906 + whio_sizeof_encoded_size_t/*size*/
897 + whio_epfs_sizeof_id/*nextFree*/ | 907 + whio_sizeof_encoded_uint32/*mtime*/
898 , 908 ,
899 /** 909 /**
900 Encoded size of whio_epfs_block. This is independent of 910 Encoded size of whio_epfs_block. This is independent of
901 whio_epfs_fsopt::blockSize. 911 whio_epfs_fsopt::blockSize.
902 */ 912 */
291 hidden lines
1194 by client code. Some of these are persistant (stored 1204 by client code. Some of these are persistant (stored
1195 in an EFS container), some are transient. 1205 in an EFS container), some are transient.
1196 */ 1206 */
1197 struct whio_epfs_hints 1207 struct whio_epfs_hints
1198 { 1208 {
1199 /** <
1200 Starting point when looking for the next free inode. <
1201 */ <
1202 whio_epfs_id_t nextFreeInode; <
1203 1209
1204 /** 1210 /**
1205 This stores the highest used inode ID. This is simply 1211 This stores the highest used inode ID. This is simply
1206 a slight performance optimization so that we can abort 1212 a slight performance optimization so that we can abort
1207 certain read-the-next-inode loops earlier than we 1213 certain read-the-next-inode loops earlier than we
1208 normally would. 1214 normally would.
1209 */ 1215 */
1210 whio_epfs_id_t maxEverUsedInode; 1216 whio_epfs_id_t maxEverUsedInode;
> 1217 /**
> 1218 ID of the first free block, or 0 if there are none.
> 1219 */
> 1220 whio_epfs_id_t freeInodeList;
1211 1221
1212 /** 1222 /**
1213 ID of the first free block, or 0 if there are none. 1223 ID of the first free block, or 0 if there are none.
1214 */ 1224 */
1215 whio_epfs_id_t freeBlockList; 1225 whio_epfs_id_t freeBlockList;
66 hidden lines
1282 0/*err*/, \ 1292 0/*err*/, \
1283 {/*offsets*/0}, \ 1293 {/*offsets*/0}, \
1284 {/*sizes*/0}, \ 1294 {/*sizes*/0}, \
1285 whio_epfs_handle_list_empty_m, \ 1295 whio_epfs_handle_list_empty_m, \
1286 whio_client_data_empty_m,\ 1296 whio_client_data_empty_m,\
1287 {/*hints*/1U/*nextFreeInode*/,\ | 1297 {/*hints*/\
1288 0U/*maxEverUsedInode*/,\ | 1298 0U/*maxEverUsedInode*/, \
1289 0U/*freeBlockList*/,\ | 1299 0U/*freeInodeList*/, \
1290 0U/*blockCount*/,\ | 1300 0U/*freeBlockList*/, \
| 1301 0U/*blockCount*/, \
1291 0U/*maxEverUsedBlock*/, \ 1302 0U/*maxEverUsedBlock*/, \
1292 NULL/*allocStamp*/,\ 1303 NULL/*allocStamp*/,\
1293 -1/*storageLockingMode*/,\ 1304 -1/*storageLockingMode*/,\
1294 }, \ 1305 }, \
1295 {/*pool*/ \ 1306 {/*pool*/ \
481 hidden lines
1777 1788
1778 1789
1779 /** 1790 /**
1780 Please read all of these docs before using this function... 1791 Please read all of these docs before using this function...
1781 1792
1782 First: highly experimental! (But it seems to work.) | 1793 First: HIGHLY EXPERIMENTAL! It normally seems to work, but once
| 1794 in a while i'm getting memory corruption in objects allocated
| 1795 through the custom allocator, normally via the block array
| 1796 reallocations (which hints at a bug in the realloc impl).
| 1797
| 1798 Until the above warning is gone, please do not use this
| 1799 function or the related functionality built on top of it
| 1800 (e.g. whio_epfs_setup_opt::memory).
1783 1801
1784 This function tries to set up a memory pool for fs' own use, so 1802 This function tries to set up a memory pool for fs' own use, so
1785 that fs does not have to use malloc()/realloc() as much. This 1803 that fs does not have to use malloc()/realloc() as much. This
1786 reduces calls into the OS and helps provide good locality of 1804 reduces calls into the OS and helps provide good locality of
1787 reference for various fs-internal objects (which tend to 1805 reference for various fs-internal objects (which tend to
186 hidden lines
1974 /** 1992 /**
1975 If fs is opened for read/write then this flushes the storage 1993 If fs is opened for read/write then this flushes the storage
1976 and returns a storage-dependent non-zero value on error. If fs 1994 and returns a storage-dependent non-zero value on error. If fs
1977 is read-only then whio_rc.AccessError is returned. If !fs then 1995 is read-only then whio_rc.AccessError is returned. If !fs then
1978 whio_rc.ArgError is returned. 1996 whio_rc.ArgError is returned.
> 1997
> 1998 This routine is used to ensure that any persistent fs-internal
> 1999 metadata is flushed to storage. Do not call it too often,
> 2000 though, as it can be relatively slow.
1979 2001
1980 Returns 0 on success. 2002 Returns 0 on success.
1981 */ 2003 */
1982 int whio_epfs_flush( whio_epfs * fs ); 2004 int whio_epfs_flush( whio_epfs * fs );
1983 2005
540 hidden lines
2524 #ifdef __cplusplus 2546 #ifdef __cplusplus
2525 } /* extern "C" */ 2547 } /* extern "C" */
2526 #endif 2548 #endif
2527 2549
2528 #endif /* WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED */ 2550 #endif /* WANDERINGHORSE_NET_WHIO_EPFS_H_INCLUDED */

Changes to pfs/EPFSApp.c

Old (1f409f52b343cd4b) New (a038bdeeb642979c)
1 /** 1 /**
2 This file is intended to be #include'd by the whio_epfs tools 2 This file is intended to be #include'd by the whio_epfs tools
3 code. It is a small framework providing the basic shared 3 code. It is a small framework providing the basic shared
4 functionality used by those apps: 4 functionality used by those apps:
5 5
22 hidden lines
28 enum { 28 enum {
29 /** 29 /**
30 Statically-assigned size of whio_epfs memory pool for EPFS. 30 Statically-assigned size of whio_epfs memory pool for EPFS.
31 */ 31 */
32 AllocatorSize = 32 AllocatorSize =
33 //4000 // only a very large EFS with lots of opened records, or large pseudofiles with small block sizes, would need this much. | 33 4000 // only a very large EFS with lots of opened records, or large pseudofiles with small block sizes, would need this much.
34 //2000 // has worked for me so far (famous last words) 34 //2000 // has worked for me so far (famous last words)
35 //500 // works for small use cases on 32-bit, but not 64-bit. Good for testing allocation failure. 35 //500 // works for small use cases on 32-bit, but not 64-bit. Good for testing allocation failure.
36 0 // uses stdlib allocators | 36 //0 // uses stdlib allocators
37 , 37 ,
38 /** 38 /**
39 Statically-assigned size of whio_alloc() memory pool. 39 Statically-assigned size of whio_alloc() memory pool.
40 40
41 Due to static destruction ordering and our use of atexit(), we have 41 Due to static destruction ordering and our use of atexit(), we have
1085 hidden lines
1127 return whio_rc.OK; 1127 return whio_rc.OK;
1128 } 1128 }
1129 1129
1130 1130
1131 #endif /* WANDERINGHORSE_NET_WHIO_EPFSAPP_C_INCLUDED */ 1131 #endif /* WANDERINGHORSE_NET_WHIO_EPFSAPP_C_INCLUDED */

Changes to pfs/block.c

Old (eb21a33dd6a91117) New (1e84b7cb082f26a7)
1 /************************************************************************ 1 /************************************************************************
2 FAR FROM COMPLETE. 2 FAR FROM COMPLETE.
3 3
4 This is a work-in-progress, porting over parts of the whefs API into 4 This is a work-in-progress, porting over parts of the whefs API into
5 the whio API... 5 the whio API...
3 hidden lines
9 License: Public Domain 9 License: Public Domain
10 ************************************************************************/ 10 ************************************************************************/
11 #if 1 11 #if 1
12 #define MARKER(X) 12 #define MARKER(X)
13 #else 13 #else
14 #define MARKER(X) printf X | 14 #define MARKER(X) printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); printf X
15 #define WHIO_DEBUG_ENABLED 1 15 #define WHIO_DEBUG_ENABLED 1
16 #endif 16 #endif
17 17
18 #include <wh/whio/whio_devs.h> 18 #include <wh/whio/whio_devs.h>
19 #include <wh/whio/whio_encode.h> 19 #include <wh/whio/whio_encode.h>
468 hidden lines
488 do 488 do
489 { 489 {
490 id = fs->hints.maxEverUsedBlock+1; 490 id = fs->hints.maxEverUsedBlock+1;
491 rc = whio_epfs_block_read( fs, id, &bl ); 491 rc = whio_epfs_block_read( fs, id, &bl );
492 if( 0 == rc ) 492 if( 0 == rc )
493 { /* block exists */ | 493 { /* block exists? */
| 494 if( whio_epfs_block_is_used(&bl) )
| 495 {
| 496 assert(0 && "next-free-inode got a used inode!");
| 497 }
| 498 return whio_rc.InternalError;
494 } 499 }
495 else 500 else
496 { 501 {
497 /** Create the block... */ | 502 /** Try to create the block... */
498 bl = whio_epfs_block_empty; 503 bl = whio_epfs_block_empty;
499 bl.id = id; 504 bl.id = id;
> 505 #if 0
> 506 rc = whio_epfs_block_set_used( fs, &bl, markAsUsed )
> 507 /* might update fs->hints.freeBlockList */
> 508 ;
> 509 if( rc ) return rc;
> 510 #endif
500 rc = whio_epfs_block_flush( fs, &bl ); 511 rc = whio_epfs_block_flush( fs, &bl );
501 if( rc ) return rc; 512 if( rc ) return rc;
502 rc = whio_epfs_block_wipe_data( fs, &bl, 0 ); 513 rc = whio_epfs_block_wipe_data( fs, &bl, 0 );
503 if( rc ) return rc; 514 if( rc ) return rc;
504 } 515 }
317 hidden lines
822 return rc; 833 return rc;
823 } 834 }
824 } 835 }
825 836
826 #undef MARKER 837 #undef MARKER

Changes to pfs/handle.c

Old (e1a224989e2bab1d) New (3ea415da23ddacdc)
1 //#define WHIO_DEBUG_ENABLED 1 1 //#define WHIO_DEBUG_ENABLED 1
2 #include "whio_epfs_internal.h" 2 #include "whio_epfs_internal.h"
3 #include <stdlib.h> // malloc() and friends. 3 #include <stdlib.h> // malloc() and friends.
4 #include <string.h> // memmove() and friends 4 #include <string.h> // memmove() and friends
5 #include <assert.h> 5 #include <assert.h>
369 hidden lines
375 CLEANUP; 375 CLEANUP;
376 return whio_rc.AccessError;//need new error code for this??? 376 return whio_rc.AccessError;//need new error code for this???
377 } 377 }
378 if( ! wasUsed ) 378 if( ! wasUsed )
379 { 379 {
380 whio_epfs_inode_set_used( &oni, true ); | 380 whio_epfs_inode_set_used( fs, &oni, true );
381 rc = whio_epfs_inode_flush( fs, &oni ); 381 rc = whio_epfs_inode_flush( fs, &oni );
382 if( rc ) 382 if( rc )
383 { 383 {
384 /* 384 /*
385 FIXME: need to unlock here on error. 385 FIXME: need to unlock here on error.
75 hidden lines
461 #undef XXX 461 #undef XXX
462 return rc; 462 return rc;
463 } 463 }
464 464
465 #undef TRY_SORTED_HANDLE_LIST 465 #undef TRY_SORTED_HANDLE_LIST

Changes to pfs/inode.c

Old (ee3c237647709ee6) New (0032a6a00366197d)
1 /************************************************************************ 1 /************************************************************************
2 This file contains most of the inode-specific whio_epfs routines. 2 This file contains most of the inode-specific whio_epfs routines.
3 3
4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) 4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
5 5
8 hidden lines
14 #include <wh/whio/whio_encode.h> 14 #include <wh/whio/whio_encode.h>
15 #include <assert.h> 15 #include <assert.h>
16 #include <time.h> // time(), gmtime(), mktime() 16 #include <time.h> // time(), gmtime(), mktime()
17 17
18 #include "whio_epfs_internal.h" 18 #include "whio_epfs_internal.h"
19 #define MARKER printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); printf | 19 #if 1
| 20 #define MARKER(X)
| 21 #else
| 22 #define MARKER(X) printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); printf X
| 23 #endif
20 24
21 bool whio_epfs_inode_is_used( whio_epfs_inode const * ino ) 25 bool whio_epfs_inode_is_used( whio_epfs_inode const * ino )
22 { 26 {
23 return ino && (ino->flags & WHIO_EPFS_FLAG_IS_USED); 27 return ino && (ino->flags & WHIO_EPFS_FLAG_IS_USED);
24 } 28 }
> 29 /**
> 30 Updates fs->hints.freeInodeList to remove ino.
25 31
26 int whio_epfs_inode_set_used( whio_epfs_inode * ino, bool u ) | 32 ino and its neighbors are flushed.
| 33
| 34 Returns 0 on success. On error the free list may be
| 35 in an undefined state.
| 36 */
| 37 static int whio_epfs_inode_from_freelist( whio_epfs * fs,
| 38 whio_epfs_inode * ino )
| 39 {
| 40 whio_epfs_inode on = whio_epfs_inode_empty;
| 41 int rc = 0;
| 42 int i = 0;
| 43 if( !ino->nextFree && !ino->prevFree )
| 44 {
| 45 if( fs->hints.freeInodeList == ino->id )
| 46 {
| 47 fs->hints.freeInodeList = 0;
| 48 }
| 49 return 0;
| 50 }
| 51 for( ; i < 2; ++i )
| 52 {
| 53 whio_epfs_id_t nid = (0==i) ? ino->prevFree : ino->nextFree;
| 54 if( ! nid ) continue;
| 55 rc = whio_epfs_inode_read( fs, nid, &on );
| 56 if( rc ) break;
| 57 if( 0 == i )
| 58 { /* we're on the left. */
| 59 on.nextFree = ino->nextFree;
| 60 }
| 61 else
| 62 { /* we're on the right */
| 63 on.prevFree = ino->prevFree;
| 64 }
| 65 rc = whio_epfs_inode_flush( fs, &on );
| 66 if( rc ) break;
| 67 }
| 68 if( !rc )
| 69 {
| 70 if( fs->hints.freeInodeList == ino->id )
| 71 {
| 72 fs->hints.freeInodeList = ino->prevFree ? ino->prevFree : ino->nextFree;
| 73 }
| 74
| 75 MARKER(("Removed inode #%"WHIO_EPFS_ID_T_PFMT" from free-list. "
| 76 "fs->hints.freeInodeList=%"WHIO_EPFS_ID_T_PFMT"\n",
| 77 ino->id, fs->hints.freeInodeList ));
| 78 ino->nextFree = ino->prevFree = 0;
| 79 rc = whio_epfs_inode_flush( fs, ino );
| 80 }
| 81 return rc;
| 82 }
| 83
| 84 /**
| 85 Updates fs->hints.freeInodeList to insert ino
| 86 as the first free item. This modifies ino->nextFree
| 87 and ino->prevFree.
| 88
| 89 ino and its neighbors are flushed.
| 90
| 91 Returns 0 on success. On error the free list may be
| 92 in an undefined state.
| 93 */
| 94 static int whio_epfs_inode_to_freelist( whio_epfs * fs, whio_epfs_inode * ino )
| 95 {
| 96
| 97 int rc = 0;
| 98 if( fs->hints.freeInodeList == ino->id ) return rc;
| 99 else if( fs->hints.freeInodeList )
| 100 {
| 101 whio_epfs_inode on = whio_epfs_inode_empty;
| 102 rc = whio_epfs_inode_read( fs, fs->hints.freeInodeList, &on );
| 103 if( rc ) return rc;
| 104 on.prevFree = ino->id;
| 105 rc = whio_epfs_inode_flush( fs, &on );
| 106 if( rc ) return rc;
| 107 ino->nextFree = on.id;
| 108 }
| 109 ino->prevFree = 0;
| 110 rc = whio_epfs_inode_flush( fs, ino );
| 111 if( !rc )
| 112 {
| 113 fs->hints.freeInodeList = ino->id;
| 114 }
| 115 return rc;
| 116 }
| 117
| 118 int whio_epfs_inode_set_used( whio_epfs * fs, whio_epfs_inode * ino, bool u )
27 { 119 {
28 if( ! ino ) return whio_rc.ArgError; 120 if( ! ino ) return whio_rc.ArgError;
29 else 121 else
30 { 122 {
31 if(u) 123 if(u)
32 { 124 {
33 ino->flags|=WHIO_EPFS_FLAG_IS_USED; | 125 if( !(ino->flags & WHIO_EPFS_FLAG_IS_USED) )
34 if( ! ino->mtime ) |
35 { 126 {
36 whio_epfs_inode_touch( ino, -1 ); | 127 whio_epfs_inode_from_freelist( fs, ino );
| 128 ino->flags|=WHIO_EPFS_FLAG_IS_USED;
| 129 MARKER(("Setting inode #%"WHIO_EPFS_ID_T_PFMT" as used. "
| 130 "freeInodeList=%"WHIO_EPFS_ID_T_PFMT"\n",
| 131 ino->id, fs->hints.freeInodeList ));
| 132 if( ! ino->mtime )
| 133 {
| 134 whio_epfs_inode_touch( ino, -1 );
| 135 }
37 } 136 }
38 } 137 }
39 else 138 else
40 { 139 {
41 whio_epfs_id_t id = ino->id; | 140 if( ino->flags & WHIO_EPFS_FLAG_IS_USED )
42 *ino = whio_epfs_inode_empty; | 141 {
43 ino->id = id; | 142 whio_epfs_id_t id = ino->id;
| 143 *ino = whio_epfs_inode_empty;
| 144 ino->id = id;
| 145 whio_epfs_inode_to_freelist( fs, ino );
| 146 }
44 } 147 }
45 return whio_rc.OK; 148 return whio_rc.OK;
46 } 149 }
47 } 150 }
48 151
3 hidden lines
52 { 155 {
53 if( ! ino || ! dest ) return 0; 156 if( ! ino || ! dest ) return 0;
54 *(dest++) = whio_epfs_inode_tag_char; 157 *(dest++) = whio_epfs_inode_tag_char;
55 dest += whio_epfs_encode_id( dest, ino->id ); 158 dest += whio_epfs_encode_id( dest, ino->id );
56 dest += whio_encode_uint8( dest, ino->flags ); 159 dest += whio_encode_uint8( dest, ino->flags );
57 dest += whio_epfs_encode_id( dest, ino->firstBlock ); <
58 dest += whio_epfs_encode_id( dest, ino->nextFree ); 160 dest += whio_epfs_encode_id( dest, ino->nextFree );
> 161 dest += whio_epfs_encode_id( dest, ino->prevFree );
> 162 dest += whio_epfs_encode_id( dest, ino->firstBlock );
59 dest += whio_encode_uint32( dest, ino->cflags ); 163 dest += whio_encode_uint32( dest, ino->cflags );
60 dest += whio_encode_size_t( dest, ino->size ); 164 dest += whio_encode_size_t( dest, ino->size );
61 dest += whio_encode_uint32( dest, ino->mtime ); 165 dest += whio_encode_uint32( dest, ino->mtime );
62 return whio_epfs_sizeof_inode; 166 return whio_epfs_sizeof_inode;
63 } 167 }
13 hidden lines
77 181
78 rc = whio_decode_uint8( at, &ino->flags ); 182 rc = whio_decode_uint8( at, &ino->flags );
79 if( rc ) return rc; 183 if( rc ) return rc;
80 at += whio_sizeof_encoded_uint8; 184 at += whio_sizeof_encoded_uint8;
81 185
82 rc = whio_epfs_decode_id( at, &ino->firstBlock ); | 186 rc = whio_epfs_decode_id( at, &ino->nextFree );
| 187 if( rc ) return rc;
| 188 at += whio_epfs_sizeof_id;
| 189
| 190 rc = whio_epfs_decode_id( at, &ino->prevFree );
83 if( rc ) return rc; 191 if( rc ) return rc;
84 at += whio_epfs_sizeof_id; 192 at += whio_epfs_sizeof_id;
85 193
86 rc = whio_epfs_decode_id( at, &ino->nextFree ); | 194 rc = whio_epfs_decode_id( at, &ino->firstBlock );
87 if( rc ) return rc; 195 if( rc ) return rc;
88 at += whio_epfs_sizeof_id; 196 at += whio_epfs_sizeof_id;
89 197
90 rc = whio_decode_uint32( at, &ino->cflags ); 198 rc = whio_decode_uint32( at, &ino->cflags );
91 if( rc ) return rc; 199 if( rc ) return rc;
52 hidden lines
144 } 252 }
145 253
146 int whio_epfs_inode_next_free( whio_epfs * fs, whio_epfs_inode * dest, bool markAsUsed ) 254 int whio_epfs_inode_next_free( whio_epfs * fs, whio_epfs_inode * dest, bool markAsUsed )
147 { 255 {
148 if( ! fs || ! dest ) return whio_rc.ArgError; 256 if( ! fs || ! dest ) return whio_rc.ArgError;
149 whio_epfs_id_t id = fs->hints.nextFreeInode; | 257 else if( markAsUsed && !whio_epfs_is_rw(fs) )
150 if( ! (id+1) ) |
151 { 258 {
152 WHIO_DEBUG("Search for next free inode would overflow counter!\n"); | 259 return whio_rc.AccessError;
153 return whio_rc.RangeError; |
154 } 260 }
155 else if( id >= fs->fsopt.inodeCount ) <
156 { <
157 /** <
158 Re-set the counter to try to see if we can find any <
159 orphaned inodes in here... <
160 */ <
161 id = fs->hints.nextFreeInode = 1; <
162 } <
163 else if( ! id ) <
164 { <
165 /* inode ID 0 is reserved for not-an-inode. */ <
166 id = fs->hints.nextFreeInode = 1; <
167 } <
168 if( id >= fs->fsopt.inodeCount ) return whio_rc.RangeError; <
169 int rc = 0; 261 int rc = 0;
> 262 /**
> 263 This impl would be guaranteed O(1), but the ability to open an
> 264 arbitrary inode number means that our free-list can get
> 265 confused. So we have a potential linear component.
> 266 */
170 whio_epfs_inode ino = whio_epfs_inode_empty; 267 whio_epfs_inode ino = whio_epfs_inode_empty;
171 //whio_epfs_id_t origin = id; | 268 whio_epfs_id_t id = fs->hints.freeInodeList;
172 for( ; id <= fs->fsopt.inodeCount; ++id ) | 269 while(id)
173 { 270 {
174 rc = whio_epfs_inode_read( fs, id, &ino ); 271 rc = whio_epfs_inode_read( fs, id, &ino );
175 if( rc ) return rc; 272 if( rc ) return rc;
176 if( whio_epfs_inode_is_used( &ino ) ) continue; | 273 if( whio_epfs_inode_is_used( &ino ) )
177 if( markAsUsed ) |
178 { 274 {
179 whio_epfs_inode_set_used( &ino, true ); | 275 MARKER(("Is-free check of inode #%"WHIO_EPFS_ID_T_PFMT" failed.\n",ino.id));
180 rc = whio_epfs_inode_flush( fs, &ino ); | 276 if( ino.nextFree )
181 if( rc ) return rc; |
182 #if 0 //WHIO_EPFS_CONFIG_AUTO_FLUSH_HINTS |
183 // done in whio_epfs_inode_read/flush() |
184 int8_t changes = 0; |
185 if( origin >= id ) |
186 { 277 {
187 fs->hints.nextFreeInode = id + 1; | 278 MARKER(("Trying ino.nextFree #%"WHIO_EPFS_ID_T_PFMT".\n",ino.nextFree));
188 ++changes; | 279 if( fs->hints.freeInodeList == ino.id )
| 280 {
| 281 fs->hints.freeInodeList = ino.nextFree;
| 282 }
| 283 id = ino.nextFree;
| 284 continue;
189 } 285 }
190 if( id > fs->hints.maxEverUsedInode ) <
191 { <
192 fs->hints.maxEverUsedInode = id; <
193 ++changes; <
194 } <
195 if( changes ) <
196 { <
197 rc = whio_epfs_hints_write( fs ); <
198 if( rc ) return rc; <
199 } <
200 #endif <
201 } 286 }
> 287 break;
> 288 }
> 289 if( ! id )
> 290 { /* assume we are full */
> 291 return whio_rc.DeviceFullError;
> 292 }
> 293 if( markAsUsed )
> 294 {
> 295 rc = whio_epfs_inode_set_used( fs, &ino, true );
> 296 //if(!rc) rc = whio_epfs_inode_flush( fs, &ino );
> 297 if(!rc) rc = whio_epfs_hints_write( fs );
> 298 }
> 299 if( ! rc )
> 300 {
202 *dest = ino; 301 *dest = ino;
203 return whio_rc.OK; <
204 } 302 }
205 rc = whio_rc.DeviceFullError; <
206 return rc; 303 return rc;
207 } 304 }
208 305
209 306
210 int whio_epfs_inode_flush( whio_epfs * fs, 307 int whio_epfs_inode_flush( whio_epfs * fs,
19 hidden lines
230 if( ino->id > fs->hints.maxEverUsedInode ) 327 if( ino->id > fs->hints.maxEverUsedInode )
231 { 328 {
232 fs->hints.maxEverUsedInode = ino->id; 329 fs->hints.maxEverUsedInode = ino->id;
233 ++changes; 330 ++changes;
234 } 331 }
235 } <
236 else if( fs->hints.nextFreeInode > ino->id ) <
237 { <
238 fs->hints.nextFreeInode = ino->id; <
239 ++changes; <
240 } 332 }
241 #if WHIO_EPFS_CONFIG_AUTO_FLUSH_HINTS 333 #if WHIO_EPFS_CONFIG_AUTO_FLUSH_HINTS
242 if( changes ) 334 if( changes )
243 { 335 {
244 int rc = whio_epfs_hints_write( fs ); 336 int rc = whio_epfs_hints_write( fs );
32 hidden lines
277 if( fs->hints.maxEverUsedInode < ino.id ) 369 if( fs->hints.maxEverUsedInode < ino.id )
278 { 370 {
279 fs->hints.maxEverUsedInode = ino.id; 371 fs->hints.maxEverUsedInode = ino.id;
280 ++changes; 372 ++changes;
281 } 373 }
282 } <
283 else if( fs->hints.nextFreeInode > ino.id ) <
284 { <
285 fs->hints.nextFreeInode = ino.id; <
286 ++changes; <
287 } 374 }
288 #if WHIO_EPFS_CONFIG_AUTO_FLUSH_HINTS 375 #if WHIO_EPFS_CONFIG_AUTO_FLUSH_HINTS
289 if( changes && whio_epfs_is_rw(fs) ) 376 if( changes && whio_epfs_is_rw(fs) )
290 { 377 {
291 rc = whio_epfs_hints_write( fs ); 378 rc = whio_epfs_hints_write( fs );
153 hidden lines
445 } 532 }
446 return rc; 533 return rc;
447 } 534 }
448 535
449 #undef MARKER 536 #undef MARKER

Changes to pfs/ls.c

Old (9bf1654b37254e30) New (c9e8d146738a5388)
1 /************************************************************************ 1 /************************************************************************
2 An "ls"-like program for use with whio_epfs. 2 An "ls"-like program for use with whio_epfs.
3 3
4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) 4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
5 5
208 hidden lines
214 ); 214 );
215 if( EPFSApp.verbose ) 215 if( EPFSApp.verbose )
216 { 216 {
217 printf("\t[inodes=%"WHIO_EPFS_ID_T_PFMT"] [maxEverUsedInodeID==%"WHIO_EPFS_ID_T_PFMT"]\n" 217 printf("\t[inodes=%"WHIO_EPFS_ID_T_PFMT"] [maxEverUsedInodeID==%"WHIO_EPFS_ID_T_PFMT"]\n"
218 "\t[blockSize=%"WHIO_SIZE_T_PFMT"] [blocksInFS=%"WHIO_EPFS_ID_T_PFMT"] [maxBlocks=%"WHIO_EPFS_ID_T_PFMT"] [maxEverUsedBlockID==%"WHIO_EPFS_ID_T_PFMT"]\n" 218 "\t[blockSize=%"WHIO_SIZE_T_PFMT"] [blocksInFS=%"WHIO_EPFS_ID_T_PFMT"] [maxBlocks=%"WHIO_EPFS_ID_T_PFMT"] [maxEverUsedBlockID==%"WHIO_EPFS_ID_T_PFMT"]\n"
219 "\t[freeBlockList=%"WHIO_SIZE_T_PFMT"]" | 219 "\t[freeBlockList=%"WHIO_SIZE_T_PFMT"] [freeInodeList=%"WHIO_SIZE_T_PFMT"]"
220 "\n", 220 "\n",
221 fopt->inodeCount, EPFSApp.fs->hints.maxEverUsedInode, 221 fopt->inodeCount, EPFSApp.fs->hints.maxEverUsedInode,
222 fopt->blockSize, EPFSApp.fs->hints.blockCount, fopt->maxBlocks, EPFSApp.fs->hints.maxEverUsedBlock, 222 fopt->blockSize, EPFSApp.fs->hints.blockCount, fopt->maxBlocks, EPFSApp.fs->hints.maxEverUsedBlock,
223 EPFSApp.fs->hints.freeBlockList | 223 EPFSApp.fs->hints.freeBlockList, EPFSApp.fs->hints.freeInodeList
224 ); 224 );
225 } 225 }
226 226
227 //printf("Magic bytes: "); ls_dump_core_magic(); 227 //printf("Magic bytes: "); ls_dump_core_magic();
228 printf("Inode #\t Size\t "); 228 printf("Inode #\t Size\t ");
26 hidden lines
255 info.blockCount ); 255 info.blockCount );
256 } 256 }
257 puts("."); 257 puts(".");
258 } 258 }
259 259
260 if( EPFSApp.verbose && AppLs.showBlocks ) <
261 { <
262 puts("\nData block free-list: "); <
263 whio_epfs_id_t f = EPFSApp.fs->hints.freeBlockList; <
264 if( !f ) <
265 { <
266 puts("No explicit unused blocks."); <
267 } <
268 else <
269 while( f ) <
270 { <
271 whio_epfs_block bl = whio_epfs_block_empty; <
272 rc = whio_epfs_block_read( EPFSApp.fs, f, &bl ); <
273 if( rc ) <
274 { <
275 APPERR("Error reading block #%"WHIO_EPFS_ID_T_PFMT"!\n",f); <
276 break; <
277 } <
278 printf("%"WHIO_EPFS_ID_T_PFMT"->%"WHIO_EPFS_ID_T_PFMT"%s", <
279 bl.id, bl.nextFree, <
280 (bl.nextFree ? ", " : "") <
281 ); <
282 f = bl.nextFree; <
283 } <
284 putchar('\n'); <
285 } <
286 if( rc ) 260 if( rc )
287 { 261 {
288 APPERR("Got error code %d while looping over inodes!\n", rc ); 262 APPERR("Got error code %d while looping over inodes!\n", rc );
289 } 263 }
290 return rc; 264 return rc;
8 hidden lines
299 o->inodeCount, 273 o->inodeCount,
300 EPFSApp.fsName 274 EPFSApp.fsName
301 ); 275 );
302 return 0; 276 return 0;
303 } 277 }
> 278
> 279 static int ls_dump_freelists_command()
> 280 {
> 281 int rc = 0;
> 282 int i = 0;
> 283 int span = 4;
> 284 {
> 285 puts("Data block free-list: (Block ID->Next free ID)\n");
> 286 whio_epfs_id_t f = EPFSApp.fs->hints.freeBlockList;
> 287 if( !f )
> 288 {
> 289 puts("No explicit unused blocks.");
> 290 }
> 291 else
> 292 {
> 293 putchar('\t');
> 294 while( f )
> 295 {
> 296 whio_epfs_block bl = whio_epfs_block_empty;
> 297 rc = whio_epfs_block_read( EPFSApp.fs, f, &bl );
> 298 if( rc )
> 299 {
> 300 APPERR("Error reading block #%"WHIO_EPFS_ID_T_PFMT"!\n",f);
> 301 return rc;
> 302 }
> 303 printf("(%"WHIO_EPFS_ID_T_PFMT"->%"WHIO_EPFS_ID_T_PFMT")%s",
> 304 bl.id, bl.nextFree,
> 305 (bl.nextFree ? ", " : "")
> 306 );
> 307 f = bl.nextFree;
> 308 if( i == (span-1) )
> 309 {
> 310 i = 0;
> 311 printf("\n%s",(f ? "\t" : ""));
> 312 }
> 313 else ++i;
> 314 }
> 315 }
> 316 putchar('\n');
> 317 }
> 318 putchar('\n');
> 319 {
> 320 i = 0;
> 321 puts("Inode free-list: (Previous Free<- Inode ID -> Next Free)\n");
> 322 whio_epfs_id_t f = EPFSApp.fs->hints.freeInodeList;
> 323 if( !f )
> 324 {
> 325 puts("No explicit unused inodes.");
> 326 }
> 327 else
> 328 {
> 329 putchar('\t');
> 330 while( f )
> 331 {
> 332 whio_epfs_inode ino = whio_epfs_inode_empty;
> 333 rc = whio_epfs_inode_read( EPFSApp.fs, f, &ino );
> 334 if( rc )
> 335 {
> 336 APPERR("Error reading inode #%"WHIO_EPFS_ID_T_PFMT"!\n",f);
> 337 break;
> 338 }
> 339 printf("(%"WHIO_EPFS_ID_T_PFMT"<-%"WHIO_EPFS_ID_T_PFMT"->%"WHIO_EPFS_ID_T_PFMT")%s",
> 340 ino.prevFree, ino.id, ino.nextFree,
> 341 (ino.nextFree ? ", " : "")
> 342 );
> 343 f = ino.nextFree;
> 344 if( i == (span-1) )
> 345 {
> 346 i = 0;
> 347 printf("\n%s",(f ? "\t" : ""));
> 348 }
> 349 else ++i;
> 350 }
> 351 }
> 352 putchar('\n');
> 353 }
> 354 putchar('\n');
> 355 return 0;
> 356 }
> 357
304 358
305 /** 359 /**
306 Proxy for a function pointer, to work around not being able to legally 360 Proxy for a function pointer, to work around not being able to legally
307 convert a (void const *) to a (ls_command_f). 361 convert a (void const *) to a (ls_command_f).
308 */ 362 */
17 hidden lines
326 } 380 }
327 381
328 static const ls_command_f_pedantic_kludge ls_cmd_dump_options_code = {ls_dump_options_code}; 382 static const ls_command_f_pedantic_kludge ls_cmd_dump_options_code = {ls_dump_options_code};
329 static const ls_command_f_pedantic_kludge ls_cmd_dump_inodes = {ls_dump_inodes}; 383 static const ls_command_f_pedantic_kludge ls_cmd_dump_inodes = {ls_dump_inodes};
330 static const ls_command_f_pedantic_kludge ls_cmd_dump_mkfs_command = {ls_dump_mkfs_command}; 384 static const ls_command_f_pedantic_kludge ls_cmd_dump_mkfs_command = {ls_dump_mkfs_command};
> 385 static const ls_command_f_pedantic_kludge ls_cmd_dump_freelists_command = {ls_dump_freelists_command};
331 #if 0 386 #if 0
332 static const ls_command_f_pedantic_kludge ls_cmd_dump_blocks = {ls_dump_blocks}; 387 static const ls_command_f_pedantic_kludge ls_cmd_dump_blocks = {ls_dump_blocks};
333 static const ls_command_f_pedantic_kludge ls_cmd_dump_blocks_table = {ls_dump_blocks_table}; 388 static const ls_command_f_pedantic_kludge ls_cmd_dump_blocks_table = {ls_dump_blocks_table};
334 static const ls_command_f_pedantic_kludge ls_cmd_dump_stats = {ls_dump_stats}; 389 static const ls_command_f_pedantic_kludge ls_cmd_dump_stats = {ls_dump_stats};
335 #endif 390 #endif
29 hidden lines
365 {"g", ArgTypeBool, &AppLs.gmtTime, 420 {"g", ArgTypeBool, &AppLs.gmtTime,
366 "Same as --gmt.", NULL, NULL }, 421 "Same as --gmt.", NULL, NULL },
367 {"time-format", ArgTypeCString, &AppLs.tmfmt, 422 {"time-format", ArgTypeCString, &AppLs.tmfmt,
368 "Sets the time field output format, in a format supported by strftime(3).", 423 "Sets the time field output format, in a format supported by strftime(3).",
369 NULL, NULL }, 424 NULL, NULL },
> 425 {"list", ArgTypeIgnore, NULL,
> 426 "Forces the listing of inodes even if another option (e.g. --freelist) would normally supress the inode list.",
> 427 ls_arg_push_cb, &ls_cmd_dump_inodes },
> 428 {"l", ArgTypeIgnore, NULL,
> 429 "Same as --list.",
> 430 ls_arg_push_cb, &ls_cmd_dump_inodes },
> 431 {"freelist", ArgTypeIgnore, 0,
> 432 "Displays the EFS \"free lists\".",
> 433 ls_arg_push_cb, &ls_cmd_dump_freelists_command },
> 434 {"F", ArgTypeIgnore, 0,
> 435 "Same as --freelist.",
> 436 ls_arg_push_cb, &ls_cmd_dump_freelists_command },
370 {"dump-mkfs-command", ArgTypeIgnore, 0, 437 {"dump-mkfs-command", ArgTypeIgnore, 0,
371 "Dumps the EFS options as arguments for passing to whio-epfs-mkfs.", 438 "Dumps the EFS options as arguments for passing to whio-epfs-mkfs.",
372 ls_arg_push_cb, &ls_cmd_dump_mkfs_command }, 439 ls_arg_push_cb, &ls_cmd_dump_mkfs_command },
373 {"dump-lib-magic", ArgTypeIgnore, 0, 440 {"dump-lib-magic", ArgTypeIgnore, 0,
374 "Dumps the library's file format version number. This can be used without specifying an EFS.", 441 "Dumps the library's file format version number. This can be used without specifying an EFS.",
75 hidden lines
450 } 517 }
451 } 518 }
452 EPFSApp_verbose_error_code( rc ); 519 EPFSApp_verbose_error_code( rc );
453 return rc; 520 return rc;
454 } 521 }

Changes to pfs/pfs.c

Old (f2648eead089b3f3) New (17e2c59903607ab5)
1 /************************************************************************ 1 /************************************************************************
2 This is a work-in-progress, porting over parts of the whefs API into 2 This is a work-in-progress, porting over parts of the whefs API into
3 the whio API... 3 the whio API...
4 4
5 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) 5 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
51 hidden lines
57 /** Tag marking the beginning of EFS label storage. */ 57 /** Tag marking the beginning of EFS label storage. */
58 static const unsigned char whio_epfs_label_tag_char = 'L'; 58 static const unsigned char whio_epfs_label_tag_char = 'L';
59 59
60 int whio_epfs_flush( whio_epfs * fs ) 60 int whio_epfs_flush( whio_epfs * fs )
61 { 61 {
62 return (fs && fs->dev) | 62 if(!fs || !fs->dev ) return whio_rc.ArgError;
63 ? (whio_epfs_is_rw(fs) | 63 else if( !whio_epfs_is_rw(fs) ) return whio_rc.AccessError;
64 ? fs->dev->api->flush( fs->dev ) | 64 else
65 : whio_rc.AccessError) | 65 {
66 : whio_rc.ArgError; | 66 /* FIXME? put this somewhere else? */
| 67 int rc = whio_epfs_hints_write(fs);
| 68 if(! rc )
| 69 {
| 70 rc = fs->dev->api->flush( fs->dev );
| 71 }
| 72 return rc;
| 73 }
| 74
67 } 75 }
68 76
69 whio_epfs_fsopt const * whio_epfs_options(whio_epfs const * fs) 77 whio_epfs_fsopt const * whio_epfs_options(whio_epfs const * fs)
70 { 78 {
71 return fs 79 return fs
150 hidden lines
222 int whio_epfs_close( whio_epfs *fs ) 230 int whio_epfs_close( whio_epfs *fs )
223 { 231 {
224 if( !fs ) return whio_rc.ArgError; 232 if( !fs ) return whio_rc.ArgError;
225 if( !fs->err && fs->dev && whio_epfs_is_rw(fs) ) 233 if( !fs->err && fs->dev && whio_epfs_is_rw(fs) )
226 { 234 {
227 whio_epfs_hints_write(fs); | 235 whio_epfs_flush(fs);
228 } 236 }
229 if( fs->client.dtor ) 237 if( fs->client.dtor )
230 { 238 {
231 /** 239 /**
232 Reminder: we have to close this early in case the client 240 Reminder: we have to close this early in case the client
339 hidden lines
572 memset(buf, 0, Len); 580 memset(buf, 0, Len);
573 unsigned char * dest = buf; 581 unsigned char * dest = buf;
574 *(dest++) = whio_epfs_hints_tag_char; 582 *(dest++) = whio_epfs_hints_tag_char;
575 whio_size_t sz = 1; 583 whio_size_t sz = 1;
576 whio_size_t rc = 0; 584 whio_size_t rc = 0;
577 rc = whio_epfs_encode_id( dest, fs->hints.nextFreeInode ); <
578 dest += rc; <
579 sz += rc; <
580 585
581 rc = whio_epfs_encode_id( dest, fs->hints.maxEverUsedInode ); 586 rc = whio_epfs_encode_id( dest, fs->hints.maxEverUsedInode );
582 dest += rc; 587 dest += rc;
583 sz += rc; 588 sz += rc;
584 589
585 #if 0 | 590 rc = whio_epfs_encode_id( dest, fs->hints.maxEverUsedBlock );
586 rc = whio_epfs_encode_id( dest, fs->hints.nextFreeBlock ); |
587 dest += rc; 591 dest += rc;
588 sz += rc; 592 sz += rc;
589 #endif | 593
590 rc = whio_epfs_encode_id( dest, fs->hints.maxEverUsedBlock ); | 594 rc = whio_epfs_encode_id( dest, fs->hints.freeInodeList );
591 dest += rc; 595 dest += rc;
592 sz += rc; 596 sz += rc;
593 597
594 rc = whio_epfs_encode_id( dest, fs->hints.freeBlockList ); 598 rc = whio_epfs_encode_id( dest, fs->hints.freeBlockList );
595 dest += rc; 599 dest += rc;
34 hidden lines
630 return whio_rc.ConsistencyError; 634 return whio_rc.ConsistencyError;
631 } 635 }
632 unsigned char * at = buf+1; 636 unsigned char * at = buf+1;
633 int rc = 0; 637 int rc = 0;
634 638
635 rc = whio_epfs_decode_id( at, &fs->hints.nextFreeInode ); <
636 at += whio_epfs_sizeof_id; <
637 if( rc ) return rc; <
638 <
639 rc = whio_epfs_decode_id( at, &fs->hints.maxEverUsedInode ); 639 rc = whio_epfs_decode_id( at, &fs->hints.maxEverUsedInode );
640 at += whio_epfs_sizeof_id; 640 at += whio_epfs_sizeof_id;
641 if( rc ) return rc; 641 if( rc ) return rc;
642 642
643 #if 0 | 643 rc = whio_epfs_decode_id( at, &fs->hints.maxEverUsedBlock );
644 rc = whio_epfs_decode_id( at, &fs->hints.nextFreeBlock ); |
645 at += whio_epfs_sizeof_id; 644 at += whio_epfs_sizeof_id;
646 if( rc ) return rc; 645 if( rc ) return rc;
647 #endif <
648 646
649 rc = whio_epfs_decode_id( at, &fs->hints.maxEverUsedBlock ); | 647 rc = whio_epfs_decode_id( at, &fs->hints.freeInodeList );
650 at += whio_epfs_sizeof_id; 648 at += whio_epfs_sizeof_id;
651 if( rc ) return rc; 649 if( rc ) return rc;
652 650
653 rc = whio_epfs_decode_id( at, &fs->hints.freeBlockList ); 651 rc = whio_epfs_decode_id( at, &fs->hints.freeBlockList );
654 at += whio_epfs_sizeof_id; 652 at += whio_epfs_sizeof_id;
7 hidden lines
662 660
663 static int whio_epfs_inodes_table_write( whio_epfs * fs ) 661 static int whio_epfs_inodes_table_write( whio_epfs * fs )
664 { 662 {
665 whio_epfs_inode ino = whio_epfs_inode_empty; 663 whio_epfs_inode ino = whio_epfs_inode_empty;
666 int rc = 0; 664 int rc = 0;
667 whio_size_t i; | 665 whio_size_t i = 1;
668 for( i = 1; (!rc) && (i <= fs->fsopt.inodeCount); ++i ) | 666 fs->hints.freeInodeList = i;
| 667 for( ; (!rc) && (i <= fs->fsopt.inodeCount); ++i )
669 { 668 {
670 ino.id = i; 669 ino.id = i;
671 ino.nextFree = (i < fs->fsopt.inodeCount) ? (i+1) : 0; 670 ino.nextFree = (i < fs->fsopt.inodeCount) ? (i+1) : 0;
> 671 ino.prevFree = i-1;
672 rc = whio_epfs_inode_flush( fs, &ino ); 672 rc = whio_epfs_inode_flush( fs, &ino );
673 } 673 }
674 return rc; 674 return rc;
675 } 675 }
676 676
130 hidden lines
807 CHECKRC; 807 CHECKRC;
808 #undef CHECKRC 808 #undef CHECKRC
809 #undef RERR 809 #undef RERR
810 if( ownsFS ) *fs_ = fs; 810 if( ownsFS ) *fs_ = fs;
811 whio_epfs_apply_sopt( fs, sopt )/*ignoring error code - not critical.*/; 811 whio_epfs_apply_sopt( fs, sopt )/*ignoring error code - not critical.*/;
> 812 whio_epfs_flush(fs);
812 return rc; 813 return rc;
813 } 814 }
814 815
815 int whio_epfs_mkfs2( whio_epfs ** fs_, whio_dev * store, whio_epfs_fsopt const * opt, bool takeStore ) 816 int whio_epfs_mkfs2( whio_epfs ** fs_, whio_dev * store, whio_epfs_fsopt const * opt, bool takeStore )
816 { 817 {
228 hidden lines
1045 whio_epfs_inode ino = whio_epfs_inode_empty; 1046 whio_epfs_inode ino = whio_epfs_inode_empty;
1046 int rc = whio_epfs_inode_read( fs, inodeID, &ino ); 1047 int rc = whio_epfs_inode_read( fs, inodeID, &ino );
1047 if( rc ) return rc; 1048 if( rc ) return rc;
1048 if( ! whio_epfs_inode_is_used(&ino) ) return whio_rc.RangeError; 1049 if( ! whio_epfs_inode_is_used(&ino) ) return whio_rc.RangeError;
1049 whio_epfs_id_t firstBlock = ino.firstBlock; 1050 whio_epfs_id_t firstBlock = ino.firstBlock;
1050 whio_epfs_inode_set_used( &ino, false ); <
1051 rc = whio_epfs_inode_flush( fs, &ino ); <
1052 if( rc ) return rc; <
1053 if( firstBlock ) 1051 if( firstBlock )
1054 { 1052 {
1055 whio_epfs_block bl = whio_epfs_block_empty; 1053 whio_epfs_block bl = whio_epfs_block_empty;
1056 rc = whio_epfs_block_read( fs, firstBlock, &bl ); 1054 rc = whio_epfs_block_read( fs, firstBlock, &bl );
1057 if( rc ) return rc; 1055 if( rc ) return rc;
4 hidden lines
1062 1060
1063 We could fix such cases later if we stored the inode 1061 We could fix such cases later if we stored the inode
1064 ID in the block. 1062 ID in the block.
1065 */ 1063 */
1066 } 1064 }
> 1065 if( 0 == rc )
> 1066 {
> 1067 whio_epfs_inode_set_used( fs, &ino, false );
> 1068 rc = whio_epfs_inode_flush( fs, &ino );
> 1069 if( rc ) return rc;
> 1070 }
> 1071 /* FIXME? move this somewhere else? */
> 1072 rc = whio_epfs_hints_write( fs );
> 1073
1067 return rc; 1074 return rc;
1068 } 1075 }
1069 1076
1070 int whio_epfs_parse_id( char const * inp, bool allowExtraChars, whio_epfs_id_t * tgt ) 1077 int whio_epfs_parse_id( char const * inp, bool allowExtraChars, whio_epfs_id_t * tgt )
1071 //int whio_epfs_parse_id( char const * inp, whio_epfs_id_t * tgt, char const ** end ) 1078 //int whio_epfs_parse_id( char const * inp, whio_epfs_id_t * tgt, char const ** end )
59 hidden lines
1131 return rc; 1138 return rc;
1132 } 1139 }
1133 1140
1134 1141
1135 #undef MARKER 1142 #undef MARKER

Changes to pfs/test.c

Old (4afcd569975d14f4) New (ec49c1ff60aa1564)
1 /************************************************************************ 1 /************************************************************************
2 FAR FROM COMPLETE. 2 FAR FROM COMPLETE.
3 3
4 This is a work-in-progress, porting over parts of the whefs API into 4 This is a work-in-progress, porting over parts of the whefs API into
5 the whio API... 5 the whio API...
48 hidden lines
54 @endcode 54 @endcode
55 55
56 The address 0x4000300020003 is apparently bogus, but i don't know where it's coming from. 56 The address 0x4000300020003 is apparently bogus, but i don't know where it's coming from.
57 */ 57 */
58 enum { AllocatorSize = 58 enum { AllocatorSize =
59 //5000 only a very large EFS with lots of opened records would need this much | 59 5000 //only a very large EFS with lots of opened records would need this much
60 //2000 60 //2000
61 //500 // works for small use cases on 32-bit, but not 64-bit. 61 //500 // works for small use cases on 32-bit, but not 64-bit.
62 0 // uses stdlib allocators | 62 //0 // uses stdlib allocators
63 }; 63 };
64 static struct Application 64 static struct Application
65 { 65 {
66 whio_stream * cout; 66 whio_stream * cout;
67 unsigned char buffer[AllocatorSize ? AllocatorSize : 1]; 67 unsigned char buffer[AllocatorSize ? AllocatorSize : 1];
449 hidden lines
517 SO(ThisApp.buffer); 517 SO(ThisApp.buffer);
518 #undef SO 518 #undef SO
519 MARKER("Done. rc=%d\n",rc); 519 MARKER("Done. rc=%d\n",rc);
520 return rc; 520 return rc;
521 } 521 }

Changes to pfs/touch.c

Old (65b86d820e03e9aa) New (2b41841b6e151714)
1 /************************************************************************ 1 /************************************************************************
2 A "touch"-like program for use with whio_epfs. 2 A "touch"-like program for use with whio_epfs.
3 3
4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) 4 Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
5 5
80 hidden lines
86 APPERR("--no-create is in effect, so unused inode #%"WHIO_EPFS_ID_T_PFMT" cannot be touched.\n", 86 APPERR("--no-create is in effect, so unused inode #%"WHIO_EPFS_ID_T_PFMT" cannot be touched.\n",
87 ino->id ); 87 ino->id );
88 return whio_rc.AccessError; 88 return whio_rc.AccessError;
89 } 89 }
90 // Create a zero-byte entry, like Unix touch. 90 // Create a zero-byte entry, like Unix touch.
91 whio_epfs_inode_set_used( ino, true ); | 91 whio_epfs_inode_set_used( EPFSApp.fs, ino, true );
92 } 92 }
93 rc = whio_epfs_inode_touch( ino, AppTouch.mtime ); 93 rc = whio_epfs_inode_touch( ino, AppTouch.mtime );
94 if( !rc ) 94 if( !rc )
95 { 95 {
96 rc = whio_epfs_inode_flush( EPFSApp.fs, ino ); 96 rc = whio_epfs_inode_flush( EPFSApp.fs, ino );
190 hidden lines
287 return rc; 287 return rc;
288 } 288 }
289 289
290 #undef TOUCH_DEFAULT_STRPFMT 290 #undef TOUCH_DEFAULT_STRPFMT
291 #undef TOUCH_DEFAULT_STRPFMT_HUMAN 291 #undef TOUCH_DEFAULT_STRPFMT_HUMAN

Changes to pfs/whio_epfs_internal.h

Old (43ec21d3d412a462) New (59f4708000a3b808)
1 #ifndef WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED 1 #ifndef WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED
2 #define WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED 2 #define WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED
3 3
4 /** @file whio_epfs_internal.h 4 /** @file whio_epfs_internal.h
5 5
52 hidden lines
58 58
59 Sets or unsets the is-used flag for ino. Returns 0 on success, 59 Sets or unsets the is-used flag for ino. Returns 0 on success,
60 but it can only fail if !ino. If !u then ino is zeroed out 60 but it can only fail if !ino. If !u then ino is zeroed out
61 except for its id. 61 except for its id.
62 62
63 If (u && !ino->mtime) then whio_epfs_inode_touch(ino) is also | 63 If (u && !ino->mtime) then whio_epfs_inode_touch(ino) is also
64 called. | 64 called.
65 65
66 Does not flush the inode to storage. | 66 This function may have to flush ino to storage in order to update
| 67 the free-inode list.
| 68
| 69 Returns 0 on success. If an error comes from the free-list handling
| 70 part then the state of the free list is undefined and we're in all
| 71 sorts of crap from then on out. Possibly. Our we might just get
| 72 device-full errors when trying to allocate new inodes even though
| 73 there are free items.
67 */ 74 */
68 int whio_epfs_inode_set_used( whio_epfs_inode * ino, bool u ); | 75 int whio_epfs_inode_set_used( whio_epfs * fs, whio_epfs_inode * ino, bool u );
69 76
70 /** @internal 77 /** @internal
71 78
72 Encodes ino to dest, which must be at least 79 Encodes ino to dest, which must be at least
73 whio_epfs_sizeof_inode bytes long. Returns 80 whio_epfs_sizeof_inode bytes long. Returns
71 hidden lines
145 whio_client_data * whio_epfs_client_data( whio_epfs * fs ); 152 whio_client_data * whio_epfs_client_data( whio_epfs * fs );
146 153
147 /** @internal 154 /** @internal
148 155
149 Searches the inode table for the next free element. On success 156 Searches the inode table for the next free element. On success
150 it returns 0 and dest is populated with the inode data. If | 157 it returns 0 and dest is populated with a copy of the inode
151 markAsUsed is true then the record is marked as used and | 158 data. If markAsUsed is true then the record is marked as used
152 flushed to disk, otherwise the same record might be returned | 159 and flushed to disk, otherwise the same record might be
153 again on the next call to this function. | 160 returned again on the next call to this function.
154 161
155 Error conditions include: 162 Error conditions include:
156 163
157 - !fs or !dest (whio_rc.ArgError). 164 - !fs or !dest (whio_rc.ArgError).
158 - No more free inodes (whio_rc.DeviceFullError). 165 - No more free inodes (whio_rc.DeviceFullError).
159 - Any potential errors via reading or writing the inode. 166 - Any potential errors via reading or writing the inode.
160 - There's a whio_rc.RangeError for one theoretically impossible case. | 167 - There's a whio_rc.RangeError for one theoretically impossible case.\
| 168 - markAsUsed is true but fs is opened for read-only more: whio_rc.AccessError.
161 169
162 In principal this is an O(N) operation | 170
163 (N=fs->fsopt.inodeCount), but a cached number | 171 As of 20100310, this is a essentially an O(1) operation if we
164 (fs->hints.nextFreeInode) allow us to cut this down to O(1) | 172 discount the i/o it must potentially do to update the inode
165 for many cases, and O(N) worst-case, and be O(N) with a | 173 free-list. If markAsUsed is true it must read, at most, 2
166 somewhat smaller N for some high-use cases (where | 174 additional inodes, update their free-list links, and flush
167 inodes are often unlinked and later re-used). | 175 them. The ids (and therefore on-storage positions) of all
| 176 inodes involved are known in advance, so this routine has to
| 177 do no search-related i/o. Note that such re-linking pays no
| 178 attention whatsoever to whether an inode or its neighbors are
| 179 opened (and therefore have their inode state cached somewhere
| 180 in memory). If the API is used properly then by the time an
| 181 inode can be opened, all links to/from the inode and the
| 182 free-list are severed.
168 */ 183 */
169 int whio_epfs_inode_next_free( whio_epfs * fs, whio_epfs_inode * dest, bool markAsUsed ); 184 int whio_epfs_inode_next_free( whio_epfs * fs, whio_epfs_inode * dest, bool markAsUsed );
170 185
171 /** @internal 186 /** @internal
172 187
865 hidden lines
1038 #ifdef __cplusplus 1053 #ifdef __cplusplus
1039 } /* extern "C" */ 1054 } /* extern "C" */
1040 #endif 1055 #endif
1041 1056
1042 #endif /* WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED */ 1057 #endif /* WANDERINGHORSE_NET_WHIO_EPFS_INTERNAL_H_INCLUDED */