ext4l: Adjust folio offset and mapping operations

The existing folios macros assume page-aligned memory, but U-Boot uses
malloc'd buffers for simplicity.

Update the macros accordinging:

- offset_in_folio(): Calculate the offset from the folio's data pointer
- bh_offset(): Calculate the actual offset within the folio
- folio_set_bh(): Actually set b_folio and b_data
- kmap_local_folio(): Return a pointer to folio data + offset

Implement __filemap_get_folio(), folio_put() and folio_get() for
folio-lifecycle management.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
Simon Glass
2025-12-30 08:35:30 -07:00
parent bb745f843c
commit 6af248ee40
2 changed files with 99 additions and 14 deletions

View File

@@ -1247,16 +1247,21 @@ struct folio_batch {
/* folio operations - stubs */
#define folio_mark_dirty(f) do { (void)(f); } while (0)
#define offset_in_folio(f, p) ({ (void)(f); (unsigned int)((unsigned long)(p) & (PAGE_SIZE - 1)); })
/*
* offset_in_folio - calculate offset of pointer within folio's data
* In Linux this uses page alignment, but in U-Boot we use the folio's
* actual data pointer since our buffers are malloc'd.
*/
#define offset_in_folio(f, p) ((f) ? (unsigned int)((uintptr_t)(p) - (uintptr_t)(f)->data) : 0U)
#define folio_buffers(f) ({ (void)(f); (struct buffer_head *)NULL; })
#define virt_to_folio(p) ({ (void)(p); (struct folio *)NULL; })
#define folio_set_bh(bh, f, off) do { (void)(bh); (void)(f); (void)(off); } while (0)
#define folio_set_bh(bh, f, off) do { if ((bh) && (f)) { (bh)->b_folio = (f); (bh)->b_data = (char *)(f)->data + (off); } } while (0)
#define memcpy_from_folio(dst, f, off, len) do { (void)(dst); (void)(f); (void)(off); (void)(len); } while (0)
#define folio_test_uptodate(f) ({ (void)(f); 1; })
#define folio_pos(f) ({ (void)(f); 0LL; })
#define folio_size(f) ({ (void)(f); PAGE_SIZE; })
#define folio_unlock(f) do { (void)(f); } while (0)
#define folio_put(f) do { (void)(f); } while (0)
/* folio_put and folio_get are implemented in support.c */
#define folio_lock(f) do { (void)(f); } while (0)
#define folio_batch_init(fb) do { (fb)->nr = 0; } while (0)
#define filemap_get_folios(m, i, e, fb) ({ (void)(m); (void)(i); (void)(e); (void)(fb); 0U; })
@@ -1357,7 +1362,7 @@ static inline int generic_error_remove_folio(struct address_space *mapping,
#define FGP_WRITEBEGIN (FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE)
/* kmap/kunmap stubs for inline.c */
#define kmap_local_folio(folio, off) ({ (void)(folio); (void)(off); (void *)NULL; })
#define kmap_local_folio(folio, off) ((folio) ? (char *)(folio)->data + (off) : NULL)
#define kunmap_local(addr) do { (void)(addr); } while (0)
/* Folio zeroing stubs for inline.c */
@@ -1367,13 +1372,12 @@ static inline int generic_error_remove_folio(struct address_space *mapping,
/* mapping_gfp_mask stub */
#define mapping_gfp_mask(m) ({ (void)(m); GFP_KERNEL; })
/* __filemap_get_folio stub */
static inline struct folio *__filemap_get_folio(struct address_space *mapping,
pgoff_t index, unsigned int fgp_flags,
gfp_t gfp)
{
return NULL;
}
/* Folio operations - implemented in support.c */
struct folio *__filemap_get_folio(struct address_space *mapping,
pgoff_t index, unsigned int fgp_flags,
gfp_t gfp);
void folio_put(struct folio *folio);
void folio_get(struct folio *folio);
/* projid_t - project ID type */
typedef unsigned int projid_t;
@@ -1545,7 +1549,9 @@ static inline char *d_path(const struct path *path, char *buf, int buflen)
/* Buffer operations - additional */
#define getblk_unmovable(bdev, block, size) sb_getblk(bdev->bd_super, block)
#define create_empty_buffers(f, s, flags) ({ (void)(f); (void)(s); (void)(flags); (struct buffer_head *)NULL; })
#define bh_offset(bh) (0UL)
/* bh_offset returns offset of b_data within the folio */
#define bh_offset(bh) ((bh)->b_folio ? \
(unsigned long)((char *)(bh)->b_data - (char *)(bh)->b_folio->data) : 0UL)
#define block_invalidate_folio(f, o, l) do { } while (0)
#define block_write_end(pos, len, copied, folio) ({ (void)(pos); (void)(len); (void)(folio); (copied); })
#define block_dirty_folio(m, f) ({ (void)(m); (void)(f); false; })
@@ -2542,8 +2548,7 @@ static inline unsigned long ext4_find_next_bit_le(const void *addr,
/* WARN_RATELIMIT - just evaluate condition, no warning in U-Boot */
#define WARN_RATELIMIT(condition, ...) (condition)
/* folio_get - increment folio refcount (no-op in U-Boot) */
#define folio_get(f) do { (void)(f); } while (0)
/* folio_get - now implemented in support.c */
/* array_index_nospec - bounds checking without speculation (no-op in U-Boot) */
#define array_index_nospec(index, size) (index)

View File

@@ -626,3 +626,83 @@ int bh_read(struct buffer_head *bh, int flags)
submit_bh(REQ_OP_READ | flags, bh);
return buffer_uptodate(bh) ? 0 : -EIO;
}
/**
* __filemap_get_folio() - Get or create a folio for a mapping
* @mapping: The address_space to search
* @index: The page index
* @fgp_flags: Flags (FGP_CREAT to create if not found)
* @gfp: Memory allocation flags
* Return: Folio pointer or ERR_PTR on error
*/
struct folio *__filemap_get_folio(struct address_space *mapping,
pgoff_t index, unsigned int fgp_flags,
gfp_t gfp)
{
struct folio *folio;
int i;
/* Search for existing folio in cache */
if (mapping) {
for (i = 0; i < mapping->folio_cache_count; i++) {
folio = mapping->folio_cache[i];
if (folio && folio->index == index) {
/* Found existing folio, bump refcount */
folio->_refcount++;
return folio;
}
}
}
/* If not creating, return error */
if (!(fgp_flags & FGP_CREAT))
return ERR_PTR(-ENOENT);
/* Create new folio */
folio = kzalloc(sizeof(struct folio), gfp);
if (!folio)
return ERR_PTR(-ENOMEM);
folio->data = kzalloc(PAGE_SIZE, gfp);
if (!folio->data) {
kfree(folio);
return ERR_PTR(-ENOMEM);
}
folio->index = index;
folio->mapping = mapping;
folio->_refcount = 1;
/* Add to cache if there's room */
if (mapping && mapping->folio_cache_count < FOLIO_CACHE_MAX) {
mapping->folio_cache[mapping->folio_cache_count++] = folio;
/* Extra ref for cache */
folio->_refcount++;
}
return folio;
}
/**
* folio_put() - Release a reference to a folio
* @folio: The folio to release
*/
void folio_put(struct folio *folio)
{
if (!folio)
return;
if (--folio->_refcount > 0)
return;
kfree(folio->data);
kfree(folio);
}
/**
* folio_get() - Acquire a reference to a folio
* @folio: The folio to reference
*/
void folio_get(struct folio *folio)
{
if (folio)
folio->_refcount++;
}