diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-08 17:14:10 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-01-17 14:35:36 -0500 |
commit | a931c76b3a46d1884e985a3bfc82b947521dab97 (patch) | |
tree | 1141cf9a9a8c123bde3d76d147ee1e910c7c6045 /firmware/include | |
parent | 0056ea8a256af0e2daaf451af43c00708a31d4df (diff) | |
download | rockbox-a931c76b3a46d1884e985a3bfc82b947521dab97.tar.gz rockbox-a931c76b3a46d1884e985a3bfc82b947521dab97.zip |
Do some debug and preparatory work for ramcache and playlist
The file system rework introduced incompatibility between dircache
and the tagcache ramcache and playlist dircache path caching. This
update makes changes to filesystem code to reintegrate all that.
It also fixes a couple bugs that were found when vetting all the
code. The filestream cache was being reset without regard to
the stream even if it was shared in write mode (made work of
.playlist_control). Better handling of unmounting gives files a
better go at force-closing them without risk to disk integrity.
Did some miscellaneous pedantic changes. Improved efficiency of
testing a file's existence (a little) since the path parser will
be shared between file code and parsing for the sake of finding
dircache references, not duplicated as before.
This commit doesn't reenable said items just for the sake of
keeping changes separate and related.
Plan for the next is to enable dircache again for the playlists
(easy peasy) and reenable tagcache ramcache but *without* the
dircache path caching because it's rather substantial to change
in itself. The ramcache will still function without dircache.
Change-Id: I7e2a9910b866251fa8333e1275f72fcfc8425d2d
Diffstat (limited to 'firmware/include')
-rw-r--r-- | firmware/include/dircache.h | 40 | ||||
-rw-r--r-- | firmware/include/dircache_redirect.h | 19 | ||||
-rw-r--r-- | firmware/include/file_internal.h | 91 | ||||
-rw-r--r-- | firmware/include/fileobj_mgr.h | 5 |
4 files changed, 104 insertions, 51 deletions
diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index 7e8c764e7f..d73c6f6e81 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h | |||
@@ -57,6 +57,15 @@ | |||
57 | figure pessimistic */ | 57 | figure pessimistic */ |
58 | typedef uint32_t dc_serial_t; | 58 | typedef uint32_t dc_serial_t; |
59 | 59 | ||
60 | /* these should agree with size of dc_serial_t */ | ||
61 | #define DC_SERHASH_START 0xffffffff | ||
62 | |||
63 | /* I was originally using FNV hash but decided this is probably okay | ||
64 | (for now) */ | ||
65 | #define dc_hash_serialnum(s, h) \ | ||
66 | ({ dc_serial_t __x = (s); crc_32(&(__x), sizeof(dc_serial_t), (h)); }) | ||
67 | #define DC_SERIAL_FMT "0x%08lX" | ||
68 | |||
60 | /** | 69 | /** |
61 | ****************************************************************************/ | 70 | ****************************************************************************/ |
62 | 71 | ||
@@ -132,10 +141,33 @@ void dircache_fileop_sync(struct file_base_binding *infop, | |||
132 | const struct dirinfo_native *dinp); | 141 | const struct dirinfo_native *dinp); |
133 | 142 | ||
134 | 143 | ||
135 | /** Dircache paths and files **/ | 144 | /** Dircache paths, files and shortcuts **/ |
136 | ssize_t dircache_get_path(const struct dircache_file *dcfilep, char *buf, | 145 | struct dircache_fileref |
137 | size_t size); | 146 | { |
138 | int dircache_get_file(const char *path, struct dircache_file *dcfilep); | 147 | struct dircache_file dcfile; |
148 | dc_serial_t serialhash; /* Hash of serialnumbers to root */ | ||
149 | }; | ||
150 | |||
151 | void dircache_fileref_init(struct dircache_fileref *dcfrefp); | ||
152 | ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, | ||
153 | char *buf, size_t size); | ||
154 | |||
155 | /* Bitflags for dircache_search() */ | ||
156 | enum dircache_search_flags | ||
157 | { | ||
158 | DCS_FILEREF = 0x01, /* Check fileref existence and serial number */ | ||
159 | _DCS_VERIFY_FLAG = 0x02, /* Internal: Only valid with DCS_FILEREF */ | ||
160 | DCS_FILEREF_VERIFY = 0x03, /* Do DCS_FILEREF check + verify serial hash */ | ||
161 | DCS_CACHED_PATH = 0x04, /* Check only cache for provided path */ | ||
162 | _DCS_STORAGE_FLAG = 0x08, /* Internal: Only valid with DCS_CACHED_PATH */ | ||
163 | DCS_STORAGE_PATH = 0x0c, /* Read-through if needed for provided path */ | ||
164 | DCS_UPDATE_FILEREF = 0x10, /* If fileref is not valid but path is found or | ||
165 | searching a path, update the reference | ||
166 | information */ | ||
167 | }; | ||
168 | |||
169 | int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, | ||
170 | const char *path); | ||
139 | 171 | ||
140 | 172 | ||
141 | /** Debug screen/info stuff **/ | 173 | /** Debug screen/info stuff **/ |
diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h index 15fb4bc38d..9fae16b551 100644 --- a/firmware/include/dircache_redirect.h +++ b/firmware/include/dircache_redirect.h | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | /*** | 25 | /*** |
26 | ** Internal redirects that depend upon whether or not dircache is made | 26 | ** Internal redirects that depend upon whether or not dircache is made |
27 | ** | ||
28 | ** Some stuff deals with it, some doesn't right now. This is a nexus point.. | ||
27 | **/ | 29 | **/ |
28 | 30 | ||
29 | /** File binding **/ | 31 | /** File binding **/ |
@@ -119,11 +121,6 @@ static inline void fileop_onsync_internal(struct filestr_base *stream) | |||
119 | #endif | 121 | #endif |
120 | } | 122 | } |
121 | 123 | ||
122 | static inline void fileop_ontruncate_internal(struct filestr_base *stream) | ||
123 | { | ||
124 | fileobj_fileop_truncate(stream); | ||
125 | } | ||
126 | |||
127 | static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) | 124 | static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) |
128 | { | 125 | { |
129 | #ifdef HAVE_DIRCACHE | 126 | #ifdef HAVE_DIRCACHE |
@@ -134,10 +131,20 @@ static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) | |||
134 | 131 | ||
135 | static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume)) | 132 | static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume)) |
136 | { | 133 | { |
137 | fileobj_mgr_unmount(IF_MV(volume)); | ||
138 | #ifdef HAVE_DIRCACHE | 134 | #ifdef HAVE_DIRCACHE |
135 | /* First, to avoid update of something about to be destroyed anyway */ | ||
139 | dircache_unmount(IF_MV(volume)); | 136 | dircache_unmount(IF_MV(volume)); |
140 | #endif | 137 | #endif |
138 | fileobj_mgr_unmount(IF_MV(volume)); | ||
139 | } | ||
140 | |||
141 | static inline void fileop_onunmount_internal(struct filestr_base *stream) | ||
142 | { | ||
143 | |||
144 | if (stream->flags & FD_WRITE) | ||
145 | force_close_writer_internal(stream); /* try to save stuff */ | ||
146 | else | ||
147 | fileop_onclose_internal(stream); /* just readers, bye */ | ||
141 | } | 148 | } |
142 | 149 | ||
143 | 150 | ||
diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h index d1bb67406a..acec81206e 100644 --- a/firmware/include/file_internal.h +++ b/firmware/include/file_internal.h | |||
@@ -81,6 +81,7 @@ | |||
81 | #define ATTR_NEW_FILE (ATTR_ARCHIVE) | 81 | #define ATTR_NEW_FILE (ATTR_ARCHIVE) |
82 | #define ATTR_NEW_DIRECTORY (ATTR_DIRECTORY) | 82 | #define ATTR_NEW_DIRECTORY (ATTR_DIRECTORY) |
83 | 83 | ||
84 | #define ATTR_SYSTEM_ROOT (ATTR_SYSROOT | ATTR_DIRECTORY) | ||
84 | #define ATTR_MOUNT_POINT (ATTR_VOLUME | ATTR_DIRECTORY) | 85 | #define ATTR_MOUNT_POINT (ATTR_VOLUME | ATTR_DIRECTORY) |
85 | 86 | ||
86 | /** File sector cache **/ | 87 | /** File sector cache **/ |
@@ -110,33 +111,35 @@ void file_cache_free(struct filestr_cache *cachep); | |||
110 | enum fildes_and_obj_flags | 111 | enum fildes_and_obj_flags |
111 | { | 112 | { |
112 | /* used in descriptor and common */ | 113 | /* used in descriptor and common */ |
113 | FDO_BUSY = 0x0001, /* descriptor/object is in use */ | 114 | FDO_BUSY = 0x0001, /* descriptor/object is in use */ |
114 | /* only used in individual stream descriptor */ | 115 | /* only used in individual stream descriptor */ |
115 | FD_WRITE = 0x0002, /* descriptor has write mode */ | 116 | FD_WRITE = 0x0002, /* descriptor has write mode */ |
116 | FD_WRONLY = 0x0004, /* descriptor is write mode only */ | 117 | FD_WRONLY = 0x0004, /* descriptor is write mode only */ |
117 | FD_APPEND = 0x0008, /* descriptor is append mode */ | 118 | FD_APPEND = 0x0008, /* descriptor is append mode */ |
119 | FD_NONEXIST = 0x8000, /* closed but not freed (uncombined) */ | ||
118 | /* only used as common flags */ | 120 | /* only used as common flags */ |
119 | FO_DIRECTORY = 0x0010, /* fileobj is a directory */ | 121 | FO_DIRECTORY = 0x0010, /* fileobj is a directory */ |
120 | FO_TRUNC = 0x0020, /* fileobj is opened to be truncated */ | 122 | FO_TRUNC = 0x0020, /* fileobj is opened to be truncated */ |
121 | FO_REMOVED = 0x0040, /* fileobj was deleted while open */ | 123 | FO_REMOVED = 0x0040, /* fileobj was deleted while open */ |
122 | FO_SINGLE = 0x0080, /* fileobj has only one stream open */ | 124 | FO_SINGLE = 0x0080, /* fileobj has only one stream open */ |
123 | FDO_MASK = 0x00ff, | 125 | FDO_MASK = 0x00ff, |
124 | /* bitflags that instruct various 'open' functions how to behave */ | 126 | FDO_CHG_MASK = FO_TRUNC, /* fileobj permitted external change */ |
125 | FF_FILE = 0x0000, /* expect file; accept file only */ | 127 | /* bitflags that instruct various 'open' functions how to behave; |
126 | FF_DIR = 0x0100, /* expect dir; accept dir only */ | 128 | * saved in stream flags (only) but not used by manager */ |
127 | FF_ANYTYPE = 0x0200, /* succeed if either file or dir */ | 129 | FF_FILE = 0x00000000, /* expect file; accept file only */ |
128 | FF_TYPEMASK = 0x0300, /* mask of typeflags */ | 130 | FF_DIR = 0x00010000, /* expect dir; accept dir only */ |
129 | FF_CREAT = 0x0400, /* create if file doesn't exist */ | 131 | FF_ANYTYPE = 0x00020000, /* succeed if either file or dir */ |
130 | FF_EXCL = 0x0800, /* fail if creating and file exists */ | 132 | FF_TYPEMASK = 0x00030000, /* mask of typeflags */ |
131 | FF_CHECKPREFIX = 0x1000, /* detect if file is prefix of path */ | 133 | FF_CREAT = 0x00040000, /* create if file doesn't exist */ |
132 | FF_NOISO = 0x2000, /* do not decode ISO filenames to UTF-8 */ | 134 | FF_EXCL = 0x00080000, /* fail if creating and file exists */ |
133 | FF_MASK = 0x3f00, | 135 | FF_CHECKPREFIX = 0x00100000, /* detect if file is prefix of path */ |
134 | /* special values used in isolation */ | 136 | FF_NOISO = 0x00200000, /* do not decode ISO filenames to UTF-8 */ |
135 | FV_NONEXIST = 0x8000, /* closed but not freed (unmounted) */ | 137 | FF_PROBE = 0x00400000, /* only test existence; don't open */ |
136 | FV_OPENSYSROOT = 0xc001, /* open sysroot, volume 0 not mounted */ | 138 | FF_CACHEONLY = 0x00800000, /* succeed only if in dircache */ |
139 | FF_SELFINFO = 0x01000000, /* return info on self as well */ | ||
140 | FF_MASK = 0x01ff0000, | ||
137 | }; | 141 | }; |
138 | 142 | ||
139 | |||
140 | /** Common data structures used throughout **/ | 143 | /** Common data structures used throughout **/ |
141 | 144 | ||
142 | /* basic file information about its location */ | 145 | /* basic file information about its location */ |
@@ -183,8 +186,7 @@ struct dirscan_info | |||
183 | struct filestr_base | 186 | struct filestr_base |
184 | { | 187 | { |
185 | struct ll_node node; /* list item node (first!) */ | 188 | struct ll_node node; /* list item node (first!) */ |
186 | uint16_t flags; /* FD_* bits of this stream */ | 189 | uint32_t flags; /* F[DF]_* bits of this stream */ |
187 | uint16_t unused; /* not used */ | ||
188 | struct filestr_cache cache; /* stream-local cache */ | 190 | struct filestr_cache cache; /* stream-local cache */ |
189 | struct filestr_cache *cachep; /* the cache in use (local or shared) */ | 191 | struct filestr_cache *cachep; /* the cache in use (local or shared) */ |
190 | struct file_base_info *infop; /* base file information */ | 192 | struct file_base_info *infop; /* base file information */ |
@@ -235,17 +237,25 @@ static inline void filestr_unlock(struct filestr_base *stream) | |||
235 | #define FILESTR_UNLOCK(type, stream) \ | 237 | #define FILESTR_UNLOCK(type, stream) \ |
236 | ({ if (FILESTR_##type) filestr_unlock(stream); }) | 238 | ({ if (FILESTR_##type) filestr_unlock(stream); }) |
237 | 239 | ||
238 | #define ATTR_PREFIX (0x8000) /* out of the way of all ATTR_* bits */ | 240 | /* auxilliary attributes - out of the way of regular ATTR_* bits */ |
241 | #define ATTR_SYSROOT (0x8000) | ||
242 | #define ATTR_PREFIX (0x4000) | ||
239 | 243 | ||
240 | /* structure to return detailed information about what you opened */ | 244 | /* structure to return detailed information about what you opened */ |
241 | struct path_component_info | 245 | struct path_component_info |
242 | { | 246 | { |
243 | const char *name; /* pointer to name within 'path' */ | 247 | const char *name; /* pointer to name within 'path' (OUT) */ |
244 | size_t length; /* length of component within 'path' */ | 248 | size_t length; /* length of component within 'path' */ |
245 | file_size_t filesize; /* size of the opened file (0 if dir) */ | 249 | file_size_t filesize; /* size of the opened file (0 if dir) */ |
246 | unsigned int attr; /* attributes of this component */ | 250 | unsigned int attr; /* attributes of this component */ |
247 | struct file_base_info *prefixp; /* base info to check as prefix (IN) */ | 251 | struct file_base_info *prefixp; /* base info to check as prefix |
248 | struct file_base_info parentinfo; /* parent directory info of file */ | 252 | (IN if FF_CHECKPREFIX) */ |
253 | union { | ||
254 | struct file_base_info parentinfo; /* parent directory base info of file | ||
255 | (if not FF_SELFINFO) */ | ||
256 | struct file_base_info info; /* base info of file itself | ||
257 | (if FF_SELFINFO) */ | ||
258 | }; | ||
249 | }; | 259 | }; |
250 | 260 | ||
251 | int open_stream_internal(const char *path, unsigned int callflags, | 261 | int open_stream_internal(const char *path, unsigned int callflags, |
@@ -261,6 +271,7 @@ int remove_stream_internal(const char *path, struct filestr_base *stream, | |||
261 | int test_stream_exists_internal(const char *path, unsigned int callflags); | 271 | int test_stream_exists_internal(const char *path, unsigned int callflags); |
262 | 272 | ||
263 | int open_noiso_internal(const char *path, int oflag); /* file.c */ | 273 | int open_noiso_internal(const char *path, int oflag); /* file.c */ |
274 | void force_close_writer_internal(struct filestr_base *stream); /* file.c */ | ||
264 | 275 | ||
265 | struct dirent; | 276 | struct dirent; |
266 | int uncached_readdir_dirent(struct filestr_base *stream, | 277 | int uncached_readdir_dirent(struct filestr_base *stream, |
@@ -326,22 +337,26 @@ static inline void file_internal_unlock_WRITER(void) | |||
326 | * not in the macro | 337 | * not in the macro |
327 | */ | 338 | */ |
328 | 339 | ||
340 | #define FILE_SET_CODE(_name, _keepcode, _value) \ | ||
341 | ({ __builtin_constant_p(_value) ? \ | ||
342 | ({ if ((_value) != (_keepcode)) _name = (_value); }) : \ | ||
343 | ({ _name = (_value); }); }) | ||
344 | |||
329 | /* set errno and rc and proceed to the "file_error:" label */ | 345 | /* set errno and rc and proceed to the "file_error:" label */ |
330 | #define FILE_ERROR(_errno, _rc) \ | 346 | #define FILE_ERROR(_errno, _rc) \ |
331 | ({ __builtin_constant_p(_errno) ? \ | 347 | ({ FILE_SET_CODE(errno, ERRNO, (_errno)); \ |
332 | ({ if ((_errno) != ERRNO) errno = (_errno); }) : \ | 348 | FILE_SET_CODE(rc, RC, (_rc)); \ |
333 | ({ errno = (_errno); }); \ | ||
334 | __builtin_constant_p(_rc) ? \ | ||
335 | ({ if ((_rc) != RC) rc = (_rc); }) : \ | ||
336 | ({ rc = (_rc); }); \ | ||
337 | goto file_error; }) | 349 | goto file_error; }) |
338 | 350 | ||
339 | /* set errno and return a value at the point of invocation */ | 351 | /* set errno and return a value at the point of invocation */ |
340 | #define FILE_ERROR_RETURN(_errno, _rc...) \ | 352 | #define FILE_ERROR_RETURN(_errno, _rc...) \ |
341 | ({ __builtin_constant_p(_errno) ? \ | 353 | ({ FILE_SET_CODE(errno, ERRNO, _errno); \ |
342 | ({ if ((_errno) != ERRNO) errno = (_errno); }) : \ | 354 | return _rc; }) |
343 | ({ errno = (_errno); }); \ | 355 | |
344 | return _rc; }) | 356 | /* set errno and return code, no branching */ |
357 | #define FILE_ERROR_SET(_errno, _rc) \ | ||
358 | ({ FILE_SET_CODE(errno, ERRNO, (_errno)); \ | ||
359 | FILE_SET_CODE(rc, RC, (_rc)); }) | ||
345 | 360 | ||
346 | 361 | ||
347 | /** Misc. stuff **/ | 362 | /** Misc. stuff **/ |
diff --git a/firmware/include/fileobj_mgr.h b/firmware/include/fileobj_mgr.h index c90a59bea0..627d2df341 100644 --- a/firmware/include/fileobj_mgr.h +++ b/firmware/include/fileobj_mgr.h | |||
@@ -41,12 +41,11 @@ void fileobj_fileop_rename(struct filestr_base *stream, | |||
41 | void fileobj_fileop_remove(struct filestr_base *stream, | 41 | void fileobj_fileop_remove(struct filestr_base *stream, |
42 | const struct file_base_info *oldinfop); | 42 | const struct file_base_info *oldinfop); |
43 | void fileobj_fileop_sync(struct filestr_base *stream); | 43 | void fileobj_fileop_sync(struct filestr_base *stream); |
44 | void fileobj_fileop_truncate(struct filestr_base *stream); | ||
45 | extern void ftruncate_internal_callback(struct filestr_base *stream, | ||
46 | struct filestr_base *s); | ||
47 | 44 | ||
48 | file_size_t * fileobj_get_sizep(const struct filestr_base *stream); | 45 | file_size_t * fileobj_get_sizep(const struct filestr_base *stream); |
49 | unsigned int fileobj_get_flags(const struct filestr_base *stream); | 46 | unsigned int fileobj_get_flags(const struct filestr_base *stream); |
47 | struct filestr_base * fileobj_get_next_stream(const struct filestr_base *stream, | ||
48 | const struct filestr_base *s); | ||
50 | void fileobj_change_flags(struct filestr_base *stream, | 49 | void fileobj_change_flags(struct filestr_base *stream, |
51 | unsigned int flags, unsigned int mask); | 50 | unsigned int flags, unsigned int mask); |
52 | void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)); | 51 | void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)); |