trv: Reintroduced LFS3_T_EXCL

With the relaxation of traversal behavior under mutation, I think it
makes sense to bring back LFS3_T_EXCL. If only to allow traversals to
gaurantee termination under mutation. Now that traversals no longer
guarantee forward progress, it's possible to get stuck looping
indefinitely if the filesystem is constantly being mutated.

Non-excl traversals are probably still useful for GC work and debugging
threads, but LFS3_T_EXCL now allows traversals to terminate immediately
with LFS3_ERR_BUSY at the first sign of unrelated filesystem mutation:

  LFS3_T_EXCL  0x00000008  Error if filesystem modified

Internally, we already track unrelated mutation to avoid corrupt state
(LFS3_t_DIRTY), so this is a very low-cost feature:

                 code          stack          ctx
  before:       35944           2280          660
  after:        35964 (+0.1%)   2280 (+0.0%)  660 (+0.0%)

                 code          stack          ctx
  gbmap before: 38916           2296          772
  gbmap after:  38940 (+0.1%)   2296 (+0.0%)  772 (+0.0%)

                 code          stack          ctx
  gc before:    36016           2280          768
  gc after:     36036 (+0.1%)   2280 (+0.0%)  768 (+0.0%)
This commit is contained in:
Christopher Haster
2025-11-09 00:26:55 -06:00
parent 8bb43ac4b2
commit 4010afeafd
5 changed files with 405 additions and 29 deletions

11
lfs3.c
View File

@ -7355,6 +7355,10 @@ static inline bool lfs3_t_ismtreeonly(uint32_t flags) {
return flags & LFS3_T_MTREEONLY;
}
static inline bool lfs3_t_isexcl(uint32_t flags) {
return flags & LFS3_T_EXCL;
}
static inline bool lfs3_t_ismkconsistent(uint32_t flags) {
(void)flags;
#ifndef LFS3_RDONLY
@ -16914,6 +16918,7 @@ int lfs3_trv_open(lfs3_t *lfs3, lfs3_trv_t *trv, uint32_t flags) {
LFS3_IFDEF_RDONLY(0, LFS3_T_RDWR)
| LFS3_T_RDONLY
| LFS3_T_MTREEONLY
| LFS3_T_EXCL
| LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT)
| LFS3_IFDEF_RDONLY(0, LFS3_T_RELOOKAHEAD)
| LFS3_IFDEF_RDONLY(0,
@ -16959,6 +16964,12 @@ int lfs3_trv_read(lfs3_t *lfs3, lfs3_trv_t *trv,
struct lfs3_tinfo *tinfo) {
LFS3_ASSERT(lfs3_handle_isopen(lfs3, &trv->gc.t.h));
// filesystem modified? excl? terminate early
if (lfs3_t_isexcl(trv->gc.t.h.flags)
&& lfs3_t_isdirty(trv->gc.t.h.flags)) {
return LFS3_ERR_BUSY;
}
// check for pending grms every step, just in case some other
// operation introduced new grms
#ifndef LFS3_RDONLY

2
lfs3.h
View File

@ -77,6 +77,7 @@ enum lfs3_err {
LFS3_ERR_UNKNOWN = -1, // Unknown error
LFS3_ERR_INVAL = -22, // Invalid parameter
LFS3_ERR_NOTSUP = -95, // Operation not supported
LFS3_ERR_BUSY = -16, // Device or resource busy
LFS3_ERR_IO = -5, // Error during device operation
LFS3_ERR_CORRUPT = -84, // Corrupted
LFS3_ERR_NOENT = -2, // No directory entry
@ -318,6 +319,7 @@ enum lfs3_btype {
#define LFS3_T_RDONLY 1 // Open traversal as read only
#define LFS3_T_MTREEONLY \
0x00000002 // Only traverse the mtree
#define LFS3_T_EXCL 0x00000008 // Error if filesystem modified
#ifndef LFS3_RDONLY
#define LFS3_T_MKCONSISTENT \
0x00000100 // Make the filesystem consistent

View File

@ -12,6 +12,7 @@ ERR_OK = 0 # No error
ERR_UNKNOWN = -1 # Unknown error
ERR_INVAL = -22 # Invalid parameter
ERR_NOTSUP = -95 # Operation not supported
ERR_BUSY = -16 # Device or resource busy
ERR_IO = -5 # Error during device operation
ERR_CORRUPT = -84 # Corrupted
ERR_NOENT = -2 # No directory entry

View File

@ -139,6 +139,7 @@ T_MODE = 1 # -m The traversal's access mode
T_RDWR = 0 # -^ Open traversal as read and write
T_RDONLY = 1 # -^ Open traversal as read only
T_MTREEONLY = 0x00000002 # -- Only traverse the mtree
T_EXCL = 0x00000008 # -- Error if filesystem modified
T_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
T_RELOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
T_REGBMAP = 0x00000400 # -- Repopulate the gbmap

File diff suppressed because it is too large Load Diff