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/common/fileobj_mgr.c | |
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/common/fileobj_mgr.c')
-rw-r--r-- | firmware/common/fileobj_mgr.c | 126 |
1 files changed, 66 insertions, 60 deletions
diff --git a/firmware/common/fileobj_mgr.c b/firmware/common/fileobj_mgr.c index 8e7831d36c..e34a460e10 100644 --- a/firmware/common/fileobj_mgr.c +++ b/firmware/common/fileobj_mgr.c | |||
@@ -187,7 +187,8 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
187 | ll_insert_last(&fobp->list, &stream->node); | 187 | ll_insert_last(&fobp->list, &stream->node); |
188 | 188 | ||
189 | /* initiate the new stream into the enclave */ | 189 | /* initiate the new stream into the enclave */ |
190 | stream->flags = FDO_BUSY | (callflags & (FD_WRITE|FD_WRONLY|FD_APPEND)); | 190 | stream->flags = FDO_BUSY | |
191 | (callflags & (FF_MASK|FD_WRITE|FD_WRONLY|FD_APPEND)); | ||
191 | stream->infop = &fobp->bind.info; | 192 | stream->infop = &fobp->bind.info; |
192 | stream->fatstr.fatfilep = &fobp->bind.info.fatfile; | 193 | stream->fatstr.fatfilep = &fobp->bind.info.fatfile; |
193 | stream->bindp = &fobp->bind; | 194 | stream->bindp = &fobp->bind; |
@@ -202,14 +203,6 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
202 | fobp->writers = 0; | 203 | fobp->writers = 0; |
203 | fobp->size = 0; | 204 | fobp->size = 0; |
204 | 205 | ||
205 | if (callflags & FD_WRITE) | ||
206 | { | ||
207 | /* first one is a writer */ | ||
208 | fobp->writers = 1; | ||
209 | file_cache_init(&fobp->cache); | ||
210 | filestr_assign_cache(stream, &fobp->cache); | ||
211 | } | ||
212 | |||
213 | fileobj_bind_file(&fobp->bind); | 206 | fileobj_bind_file(&fobp->bind); |
214 | } | 207 | } |
215 | else | 208 | else |
@@ -225,32 +218,33 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
225 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", | 218 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", |
226 | __func__, stream, callflags); | 219 | __func__, stream, callflags); |
227 | } | 220 | } |
221 | } | ||
228 | 222 | ||
229 | if (fobp->writers) | 223 | if ((callflags & FD_WRITE) && ++fobp->writers == 1) |
230 | { | 224 | { |
231 | /* already writers present */ | 225 | /* first writer */ |
232 | fobp->writers++; | 226 | file_cache_init(&fobp->cache); |
233 | filestr_assign_cache(stream, &fobp->cache); | 227 | FOR_EACH_STREAM(FIRST, fobp, s) |
234 | } | 228 | filestr_assign_cache(s, &fobp->cache); |
235 | else if (callflags & FD_WRITE) | 229 | } |
236 | { | 230 | else if (fobp->writers) |
237 | /* first writer */ | 231 | { |
238 | fobp->writers = 1; | 232 | /* already writers present */ |
239 | file_cache_init(&fobp->cache); | 233 | filestr_assign_cache(stream, &fobp->cache); |
240 | FOR_EACH_STREAM(FIRST, fobp, s) | 234 | } |
241 | filestr_assign_cache(s, &fobp->cache); | 235 | else |
242 | } | 236 | { |
243 | /* else another reader */ | 237 | /* another reader and no writers present */ |
238 | file_cache_reset(stream->cachep); | ||
244 | } | 239 | } |
245 | } | 240 | } |
246 | 241 | ||
247 | /* close the stream and free associated resources */ | 242 | /* close the stream and free associated resources */ |
248 | void fileobj_fileop_close(struct filestr_base *stream) | 243 | void fileobj_fileop_close(struct filestr_base *stream) |
249 | { | 244 | { |
250 | switch (stream->flags) | 245 | if (!(stream->flags & FDO_BUSY)) |
251 | { | 246 | { |
252 | case 0: /* not added to manager */ | 247 | /* not added to manager or forced-closed by unmounting */ |
253 | case FV_NONEXIST: /* forced-closed by unmounting */ | ||
254 | filestr_base_destroy(stream); | 248 | filestr_base_destroy(stream); |
255 | return; | 249 | return; |
256 | } | 250 | } |
@@ -260,30 +254,30 @@ void fileobj_fileop_close(struct filestr_base *stream) | |||
260 | 254 | ||
261 | ll_remove(&fobp->list, &stream->node); | 255 | ll_remove(&fobp->list, &stream->node); |
262 | 256 | ||
263 | if ((foflags & FO_SINGLE) || fobp->writers == 0) | 257 | if (foflags & FO_SINGLE) |
264 | { | 258 | { |
265 | if (foflags & FO_SINGLE) | 259 | /* last stream for file; close everything */ |
266 | { | 260 | fileobj_unbind_file(&fobp->bind); |
267 | /* last stream for file; close everything */ | ||
268 | fileobj_unbind_file(&fobp->bind); | ||
269 | 261 | ||
270 | if (fobp->writers) | 262 | if (fobp->writers) |
271 | file_cache_free(&fobp->cache); | 263 | file_cache_free(&fobp->cache); |
272 | 264 | ||
273 | binding_add_to_free_list(fobp); | 265 | binding_add_to_free_list(fobp); |
274 | } | ||
275 | } | 266 | } |
276 | else if ((stream->flags & FD_WRITE) && --fobp->writers == 0) | 267 | else |
277 | { | 268 | { |
278 | /* only readers remain; switch back to stream-local caching */ | 269 | if ((stream->flags & FD_WRITE) && --fobp->writers == 0) |
279 | FOR_EACH_STREAM(FIRST, fobp, s) | 270 | { |
280 | filestr_copy_cache(s, &fobp->cache); | 271 | /* only readers remain; switch back to stream-local caching */ |
272 | FOR_EACH_STREAM(FIRST, fobp, s) | ||
273 | filestr_copy_cache(s, &fobp->cache); | ||
281 | 274 | ||
282 | file_cache_free(&fobp->cache); | 275 | file_cache_free(&fobp->cache); |
283 | } | 276 | } |
284 | 277 | ||
285 | if (!(foflags & FO_SINGLE) && fobp->list.head == fobp->list.tail) | 278 | if (fobp->list.head == fobp->list.tail) |
286 | fobp->flags |= FO_SINGLE; /* only one open stream remaining */ | 279 | fobp->flags |= FO_SINGLE; /* only one open stream remaining */ |
280 | } | ||
287 | 281 | ||
288 | filestr_base_destroy(stream); | 282 | filestr_base_destroy(stream); |
289 | } | 283 | } |
@@ -320,15 +314,10 @@ void fileobj_fileop_rename(struct filestr_base *stream, | |||
320 | /* informs manager than directory entries have been updated */ | 314 | /* informs manager than directory entries have been updated */ |
321 | void fileobj_fileop_sync(struct filestr_base *stream) | 315 | void fileobj_fileop_sync(struct filestr_base *stream) |
322 | { | 316 | { |
323 | fileobj_sync_parent((const struct file_base_info *[]){ stream->infop }, 1); | 317 | if (((struct fileobj_binding *)stream->bindp)->flags & FO_REMOVED) |
324 | } | 318 | return; /* no dir to sync */ |
325 | 319 | ||
326 | /* inform manager that file has been truncated */ | 320 | fileobj_sync_parent((const struct file_base_info *[]){ stream->infop }, 1); |
327 | void fileobj_fileop_truncate(struct filestr_base *stream) | ||
328 | { | ||
329 | /* let caller update internal info */ | ||
330 | FOR_EACH_STREAM(FIRST, (struct fileobj_binding *)stream->bindp, s) | ||
331 | ftruncate_internal_callback(stream, s); | ||
332 | } | 321 | } |
333 | 322 | ||
334 | /* query for the pointer to the size storage for the file object */ | 323 | /* query for the pointer to the size storage for the file object */ |
@@ -340,6 +329,16 @@ file_size_t * fileobj_get_sizep(const struct filestr_base *stream) | |||
340 | return &((struct fileobj_binding *)stream->bindp)->size; | 329 | return &((struct fileobj_binding *)stream->bindp)->size; |
341 | } | 330 | } |
342 | 331 | ||
332 | /* iterate the list of streams for this stream's file */ | ||
333 | struct filestr_base * fileobj_get_next_stream(const struct filestr_base *stream, | ||
334 | const struct filestr_base *s) | ||
335 | { | ||
336 | if (!stream->bindp) | ||
337 | return NULL; | ||
338 | |||
339 | return s ? STREAM_NEXT(s) : STREAM_FIRST((struct fileobj_binding *)stream->bindp); | ||
340 | } | ||
341 | |||
343 | /* query manager bitflags for the file object */ | 342 | /* query manager bitflags for the file object */ |
344 | unsigned int fileobj_get_flags(const struct filestr_base *stream) | 343 | unsigned int fileobj_get_flags(const struct filestr_base *stream) |
345 | { | 344 | { |
@@ -349,20 +348,21 @@ unsigned int fileobj_get_flags(const struct filestr_base *stream) | |||
349 | return ((struct fileobj_binding *)stream->bindp)->flags; | 348 | return ((struct fileobj_binding *)stream->bindp)->flags; |
350 | } | 349 | } |
351 | 350 | ||
352 | /* change manager bitflags for the file object */ | 351 | /* change manager bitflags for the file object (permitted only) */ |
353 | void fileobj_change_flags(struct filestr_base *stream, | 352 | void fileobj_change_flags(struct filestr_base *stream, |
354 | unsigned int flags, unsigned int mask) | 353 | unsigned int flags, unsigned int mask) |
355 | { | 354 | { |
356 | struct fileobj_binding *fobp = (struct fileobj_binding *)stream->bindp; | 355 | struct fileobj_binding *fobp = (struct fileobj_binding *)stream->bindp; |
357 | if (fobp) | 356 | if (!fobp) |
358 | fobp->flags = (fobp->flags & ~mask) | (flags & mask); | 357 | return; |
358 | |||
359 | mask &= FDO_CHG_MASK; | ||
360 | fobp->flags = (fobp->flags & ~mask) | (flags & mask); | ||
359 | } | 361 | } |
360 | 362 | ||
361 | /* mark all open streams on a device as "nonexistant" */ | 363 | /* mark all open streams on a device as "nonexistant" */ |
362 | void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)) | 364 | void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)) |
363 | { | 365 | { |
364 | /* right now, there is nothing else to be freed when marking a descriptor | ||
365 | as "nonexistant" but a callback could be added if that changes */ | ||
366 | FOR_EACH_VOLUME(volume, v) | 366 | FOR_EACH_VOLUME(volume, v) |
367 | { | 367 | { |
368 | struct fileobj_binding *fobp; | 368 | struct fileobj_binding *fobp; |
@@ -371,11 +371,17 @@ void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)) | |||
371 | struct filestr_base *s; | 371 | struct filestr_base *s; |
372 | while ((s = STREAM_FIRST(fobp))) | 372 | while ((s = STREAM_FIRST(fobp))) |
373 | { | 373 | { |
374 | /* last ditch effort to preserve FS integrity; we could still | ||
375 | be alive (soft unmount, maybe); we get informed early */ | ||
376 | fileop_onunmount_internal(s); | ||
377 | |||
378 | if (STREAM_FIRST(fobp) == s) | ||
379 | fileop_onclose_internal(s); /* above didn't close it */ | ||
380 | |||
374 | /* keep it "busy" to avoid races; any valid file/directory | 381 | /* keep it "busy" to avoid races; any valid file/directory |
375 | descriptor returned by an open call should always be | 382 | descriptor returned by an open call should always be |
376 | closed by whomever opened it (of course!) */ | 383 | closed by whoever opened it (of course!) */ |
377 | fileop_onclose_internal(s); | 384 | s->flags = (s->flags & ~FDO_BUSY) | FD_NONEXIST; |
378 | s->flags = FV_NONEXIST; | ||
379 | } | 385 | } |
380 | } | 386 | } |
381 | } | 387 | } |