summaryrefslogtreecommitdiff
path: root/firmware/common/fileobj_mgr.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2017-01-08 17:14:10 -0500
committerMichael Sevakis <jethead71@rockbox.org>2017-01-17 14:35:36 -0500
commita931c76b3a46d1884e985a3bfc82b947521dab97 (patch)
tree1141cf9a9a8c123bde3d76d147ee1e910c7c6045 /firmware/common/fileobj_mgr.c
parent0056ea8a256af0e2daaf451af43c00708a31d4df (diff)
downloadrockbox-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.c126
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 */
248void fileobj_fileop_close(struct filestr_base *stream) 243void 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 */
321void fileobj_fileop_sync(struct filestr_base *stream) 315void 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);
327void 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 */
333struct 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 */
344unsigned int fileobj_get_flags(const struct filestr_base *stream) 343unsigned 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) */
353void fileobj_change_flags(struct filestr_base *stream, 352void 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" */
362void fileobj_mgr_unmount(IF_MV_NONVOID(int volume)) 364void 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 }