@@ -250,6 +250,189 @@ code = '''
250250 }
251251'''
252252
253+ # multiple handle allocation test
254+ #
255+ # this tests that multiple open handles to the same file don't clobber
256+ # each other
257+ [cases .test_alloc_multihandle ]
258+ defines.FILES = 2
259+ defines.SIZE = ' (((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
260+ defines.GC = [false , true ]
261+ defines.COMPACT_THRESH = [' -1' , ' 0' , ' BLOCK_SIZE/2' ]
262+ defines.INFER_BC = [false , true ]
263+ defines.SYNC = [false , true ]
264+ code = '''
265+ const char *names[] = {"eggs", "spinach"};
266+ lfs_file_t files[FILES];
267+
268+ lfs_t lfs;
269+ lfs_format(&lfs, cfg) => 0;
270+ struct lfs_config cfg_ = *cfg;
271+ if (INFER_BC) {
272+ cfg_.block_count = 0;
273+ }
274+ lfs_mount(&lfs, &cfg_) => 0;
275+ lfs_mkdir(&lfs, "breakfast") => 0;
276+
277+ // write one file
278+ char path[1024];
279+ sprintf(path, "breakfast/quiche");
280+ lfs_file_open(&lfs, &files[0], path,
281+ LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
282+ if (GC) {
283+ lfs_fs_gc(&lfs) => 0;
284+ }
285+ size_t size = strlen(names[0]);
286+ for (lfs_size_t i = 0; i < SIZE; i += size) {
287+ lfs_file_write(&lfs, &files[0], names[0], size) => size;
288+ }
289+ // sync?
290+ if (SYNC) {
291+ lfs_file_sync(&lfs, &files[0]) => 0;
292+ }
293+
294+ // write the other file
295+ sprintf(path, "breakfast/quiche");
296+ lfs_file_open(&lfs, &files[1], path,
297+ LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
298+ if (GC) {
299+ lfs_fs_gc(&lfs) => 0;
300+ }
301+ size = strlen(names[1]);
302+ for (lfs_size_t i = 0; i < SIZE; i += size) {
303+ lfs_file_write(&lfs, &files[1], names[1], size) => size;
304+ }
305+ // sync?
306+ if (SYNC) {
307+ lfs_file_sync(&lfs, &files[1]) => 0;
308+ }
309+
310+ // try to read from both
311+ for (int n = 0; n < FILES; n++) {
312+ lfs_file_rewind(&lfs, &files[n]) => 0;
313+ size_t size = strlen(names[n]);
314+ for (lfs_size_t i = 0; i < SIZE; i += size) {
315+ uint8_t buffer[1024];
316+ lfs_file_read(&lfs, &files[n], buffer, size) => size;
317+ assert(memcmp(buffer, names[n], size) == 0);
318+ }
319+ }
320+ for (int n = 0; n < FILES; n++) {
321+ lfs_file_close(&lfs, &files[n]) => 0;
322+ }
323+ lfs_unmount(&lfs) => 0;
324+
325+ // check after remounting
326+ lfs_mount(&lfs, &cfg_) => 0;
327+ {
328+ // last one wins
329+ int n = FILES-1;
330+ char path[1024];
331+ sprintf(path, "breakfast/quiche");
332+ lfs_file_t file;
333+ lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
334+ size_t size = strlen(names[n]);
335+ for (lfs_size_t i = 0; i < SIZE; i += size) {
336+ uint8_t buffer[1024];
337+ lfs_file_read(&lfs, &file, buffer, size) => size;
338+ assert(memcmp(buffer, names[n], size) == 0);
339+ }
340+ lfs_file_close(&lfs, &file) => 0;
341+ }
342+ lfs_unmount(&lfs) => 0;
343+ '''
344+
345+ # multiple handle allocation reuse test
346+ [cases .test_alloc_multihandle_reuse ]
347+ defines.FILES = 2
348+ defines.SIZE = ' (((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / (FILES+1))'
349+ defines.CYCLES = [1 , 10 ]
350+ defines.INFER_BC = [false , true ]
351+ defines.SYNC = [false , true ]
352+ code = '''
353+ const char *names[] = {"eggs", "spinach"};
354+ lfs_file_t files[FILES];
355+
356+ lfs_t lfs;
357+ lfs_format(&lfs, cfg) => 0;
358+ struct lfs_config cfg_ = *cfg;
359+ if (INFER_BC) {
360+ cfg_.block_count = 0;
361+ }
362+
363+ lfs_mount(&lfs, &cfg_) => 0;
364+ lfs_mkdir(&lfs, "breakfast") => 0;
365+
366+ // write one file
367+ char path[1024];
368+ sprintf(path, "breakfast/quiche");
369+ lfs_file_open(&lfs, &files[0], path,
370+ LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
371+ if (GC) {
372+ lfs_fs_gc(&lfs) => 0;
373+ }
374+ size_t size = strlen(names[0]);
375+ for (lfs_size_t i = 0; i < SIZE; i += size) {
376+ lfs_file_write(&lfs, &files[0], names[0], size) => size;
377+ }
378+ // sync?
379+ if (SYNC) {
380+ lfs_file_sync(&lfs, &files[0]) => 0;
381+ }
382+
383+ for (int c = 0; c < CYCLES; c++) {
384+ // write the other file
385+ sprintf(path, "breakfast/quiche");
386+ lfs_file_open(&lfs, &files[1], path,
387+ LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
388+ if (GC) {
389+ lfs_fs_gc(&lfs) => 0;
390+ }
391+ size = strlen(names[1]);
392+ for (lfs_size_t i = 0; i < SIZE; i += size) {
393+ lfs_file_write(&lfs, &files[1], names[1], size) => size;
394+ }
395+ // sync?
396+ if (SYNC) {
397+ lfs_file_sync(&lfs, &files[1]) => 0;
398+ }
399+
400+ // try to read from both
401+ for (int n = 0; n < FILES; n++) {
402+ lfs_file_rewind(&lfs, &files[n]) => 0;
403+ size_t size = strlen(names[n]);
404+ for (lfs_size_t i = 0; i < SIZE; i += size) {
405+ uint8_t buffer[1024];
406+ lfs_file_read(&lfs, &files[n], buffer, size) => size;
407+ assert(memcmp(buffer, names[n], size) == 0);
408+ }
409+ }
410+
411+ lfs_file_close(&lfs, &files[1]) => 0;
412+ }
413+ lfs_file_close(&lfs, &files[0]) => 0;
414+ lfs_unmount(&lfs) => 0;
415+
416+ // check after remounting
417+ lfs_mount(&lfs, &cfg_) => 0;
418+ {
419+ // last one wins
420+ int n = (SYNC) ? FILES-1 : 0;
421+ char path[1024];
422+ sprintf(path, "breakfast/quiche");
423+ lfs_file_t file;
424+ lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
425+ size_t size = strlen(names[n]);
426+ for (int i = 0; i < SIZE; i += size) {
427+ uint8_t buffer[1024];
428+ lfs_file_read(&lfs, &file, buffer, size) => size;
429+ assert(memcmp(buffer, names[n], size) == 0);
430+ }
431+ lfs_file_close(&lfs, &file) => 0;
432+ }
433+ lfs_unmount(&lfs) => 0;
434+ '''
435+
253436# exhaustion test
254437[cases .test_alloc_exhaustion ]
255438defines.INFER_BC = [false , true ]
0 commit comments