fuse: add support for striped backing

Add the FUSE_BACKING_MAP_CYCLIC flag for FUSE_NOTIFY_BACKING_MAP
notifications to enable creating striped maps.

This is just a set of regular extents that repeats after the end of the
last extent using a striping pattern (i.e. on the target backings the
stripes have a contiguous footprint).

Two additional limits apply compared to non-cyclic extent map population:

 - the size of the extents (chunk size) must be equal

 - the extents must start from zero offset and follow each other without
   gaps.

Originally-by: John Groves <john@groves.net>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2026-09-21 13:12:23 +02:00
parent e8bc74b6ed
commit dfc68b6c99
4 changed files with 33 additions and 5 deletions

View File

@ -103,12 +103,18 @@ static int fuse_ext_map_iomap_begin(struct inode *inode, loff_t offset, loff_t l
{
struct fuse_backing *fb = fuse_inode_backing(get_fuse_inode(inode));
struct fuse_iext *fie;
u64 ncycle = 0, seq_off = 0, addr, tmp;
loff_t ext_len;
if (!fb || fb->type != FUSE_BACKING_EXTMAP)
return fuse_EIO("missing or wrong type backing");
fie = fuse_find_extent(&fb->extents, offset);
if (fb->cycle_length) {
ncycle = div64_u64(offset, fb->cycle_length);
seq_off = ncycle * fb->cycle_length;
}
fie = fuse_find_extent(&fb->extents, offset - seq_off);
if (!fie)
return fuse_EIO("missing mapping");
@ -121,9 +127,15 @@ static int fuse_ext_map_iomap_begin(struct inode *inode, loff_t offset, loff_t l
}
ext_len = fie->end - fie->start;
addr = fie->backing_offset;
if (check_mul_overflow(ncycle, ext_len, &tmp) || check_add_overflow(addr, tmp, &addr))
return fuse_EIO("extent address overflow");
iomap->offset = fie->start;
iomap->addr = fie->backing_offset;
if (check_add_overflow(addr, ext_len, &tmp))
return fuse_EIO("extent end overflow");
iomap->offset = fie->start + seq_off;
iomap->addr = addr;
iomap->length = ext_len;
iomap->dax_dev = fie->backing->dax_dev;
iomap->type = IOMAP_MAPPED;
@ -259,6 +271,7 @@ int fuse_ext_map_populate(struct fuse_conn *fc, struct fuse_notify_backing_map_o
struct fuse_backing *fb;
unsigned int i;
int err;
u64 chunk_size = 0;
if (!arg->num_extents)
return fuse_EIO("no extents");
@ -276,7 +289,18 @@ int fuse_ext_map_populate(struct fuse_conn *fc, struct fuse_notify_backing_map_o
return -EINVAL;
}
if (arg->flags & FUSE_BACKING_MAP_CYCLIC) {
chunk_size = ext[0].length;
err = -EINVAL;
if (check_mul_overflow(chunk_size, arg->num_extents, &fb->cycle_length))
goto err_put;
}
for (i = 0; i < arg->num_extents; i++) {
err = -EINVAL;
if (chunk_size && (ext[i].offset != chunk_size * i || ext[i].length != chunk_size))
goto err_put;
err = fuse_add_extent(fc, &fb->extents, &ext[i]);
if (err)
goto err_put;

View File

@ -110,6 +110,7 @@ struct fuse_backing {
};
struct {
struct rb_root extents;
u64 cycle_length;
};
};
u64 backing_id;

View File

@ -461,7 +461,7 @@ static int fuse_notify_map(struct fuse_conn *fc, unsigned int size,
if (outarg.reserved[0] != 0 || outarg.reserved[1] != 0)
return -EINVAL;
if (outarg.flags & ~FUSE_BACKING_MAP_CREATE)
if (outarg.flags & ~(FUSE_BACKING_MAP_CREATE | FUSE_BACKING_MAP_CYCLIC))
return -EINVAL;
if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))

View File

@ -255,7 +255,8 @@
* - add FUSE_DEV_IOC_BACKING_CREATE, struct fuse_backing_create_in
* - add FUSE_NOTIFY_BACKING_REMOVE, struct fuse_notify_backing_remove_out
* - add backing_id_64 to fuse_open_out
* - add FUSE_NOTIFY_BACKING_MAP, fuse_notify_backing_map_out, fuse_extent, FUSE_BACKING_MAP_CREATE
* - add FUSE_NOTIFY_BACKING_MAP, fuse_notify_backing_map_out, fuse_extent
* - add FUSE_BACKING_MAP_CREATE, FUSE_BACKING_MAP_CYCLIC
*/
#ifndef _LINUX_FUSE_H
@ -1219,8 +1220,10 @@ struct fuse_notify_backing_remove_out {
* notify_map flags
*
* FUSE_BACKING_MAP_CREATE: create backing with the supplied ID
* FUSE_BACKING_MAP_CYCLIC: map repeats after last extent
*/
#define FUSE_BACKING_MAP_CREATE (1 << 0)
#define FUSE_BACKING_MAP_CYCLIC (1 << 1)
struct fuse_notify_backing_map_out {
uint64_t backing_id;