[PATCH v1] erofs-utils: add hybrid source support for local metadata and gzran

Gao Xiang hsiangkao at linux.alibaba.com
Sun Sep 28 14:07:08 AEST 2025



On 2025/9/28 11:32, ChengyuZhu6 wrote:
> From: Chengyu Zhu <hudsonzhu at tencent.com>
> 
> Add support for combining local metadata files with remote OCI blobs
> through a new hybrid source mechanism. This enables local metadata
> storage while keeping blob data in remote registries.
> 


..

>   	oci_iostream = calloc(1, sizeof(*oci_iostream));
>   	if (!oci_iostream) {
>   		ocierofs_ctx_cleanup(ctx);
> diff --git a/mount/main.c b/mount/main.c
> index eb0dd01..fd5736d 100644
> --- a/mount/main.c
> +++ b/mount/main.c
> @@ -16,6 +16,7 @@
>   #include "erofs/io.h"
>   #include "../lib/liberofs_nbd.h"
>   #include "../lib/liberofs_oci.h"
> +#include "../lib/liberofs_gzran.h"
>   #ifdef HAVE_LINUX_LOOP_H
>   #include <linux/loop.h>
>   #else
> @@ -141,7 +142,25 @@ static int erofsmount_parse_oci_option(const char *option)
>   						if (!oci_cfg->password)
>   							return -ENOMEM;
>   					} else {
> -						return -EINVAL;
> +						p = strstr(option, "oci.local_meta=");

oci.tarindex ?

> +						if (p != NULL) {
> +							p += strlen("oci.local_meta=");
> +							free(oci_cfg->local_meta_path);
> +							oci_cfg->local_meta_path = strdup(p);
> +							if (!oci_cfg->local_meta_path)
> +								return -ENOMEM;
> +						} else {
> +							p = strstr(option, "oci.zinfo=");
> +							if (p != NULL) {
> +								p += strlen("oci.zinfo=");
> +								free(oci_cfg->zinfo_path);
> +								oci_cfg->zinfo_path = strdup(p);
> +								if (!oci_cfg->zinfo_path)
> +									return -ENOMEM;
> +							} else {
> +								return -EINVAL;
> +							}
> +						}
>   					}
>   				}
>   			}
> @@ -332,11 +351,265 @@ static int erofsmount_fuse(const char *source, const char *mountpoint,
>   	return 0;
>   }
>   
> +struct erofs_hybrid_source {

struct erofsmount_tarindex_source {

> +	struct erofs_vfile local_vf;

	struct erofs_vfile *tarindex_vf;

> +	struct erofs_vfile *gzran_vf;

	struct erofs_vfile *zinfo_vf;

> +	u64 local_size;
> +};
> +
>   struct erofsmount_nbd_ctx {
>   	struct erofs_vfile vd;		/* virtual device */
>   	struct erofs_vfile sk;		/* socket file */
>   };
>   
> +static ssize_t erofs_hybrid_pread(struct erofs_vfile *vf, void *buf,
> +				  size_t count, u64 offset)

s/hybrid/tarindex/

> +{
> +	struct erofs_hybrid_source *hs;
> +	ssize_t local_read, remote_read;
> +
> +	hs = *(struct erofs_hybrid_source **)vf->payload;
> +	if (!hs)
> +		return -EINVAL;
> +
> +	/* Handle device boundary probe requests */
> +	if (offset >= (INT64_MAX >> 9))

Let's define a macro for this.

> +		return 0;
> +
> +	if (hs->local_size == 0)
> +		return hs->gzran_vf->ops->pread(hs->gzran_vf, buf, count, offset);
> +
> +	if (offset >= hs->local_size) {
> +		u64 remote_offset = offset - hs->local_size;

no need to defina a variable, if it's needed, add a comment for this.

> +
> +		return hs->gzran_vf->ops->pread(hs->gzran_vf, buf, count, remote_offset);
> +	}
> +
> +	if (offset + count <= hs->local_size)
> +		return erofs_io_pread(&hs->local_vf, buf, count, offset);
> +
> +	u64 local_part = hs->local_size - offset;
> +	u64 remote_part = count - local_part;

they shouldn't be defined here.

Thanks,
Gao Xiang

> +
> +	local_read = erofs_io_pread(&hs->local_vf, buf, local_part, offset);
> +	if (local_read < 0)
> +		return local_read;
> +
> +	remote_read = hs->gzran_vf->ops->pread(hs->gzran_vf,
> +					      (char *)buf + local_read,
> +					      remote_part, 0);
> +	if (remote_read < 0)
> +		return remote_read;
> +	return local_read + remote_read;
> +}
> +
> +static void erofs_hybrid_close(struct erofs_vfile *vf)
> +{
> +	struct erofs_hybrid_source *hs;
> +
> +	if (!vf)
> +		return;
> +
> +	hs = *(struct erofs_hybrid_source **)vf->payload;
> +	if (!hs)
> +		return;
> +
> +	if (hs->local_size > 0)
> +		erofs_io_close(&hs->local_vf);
> +
> +	if (hs->gzran_vf)
> +		erofs_io_close(hs->gzran_vf);
> +
> +	free(hs);
> +}
> +
> +static int load_file_to_buf(const char *path, void **out, unsigned int *out_len)
> +{
> +	FILE *fp = NULL;
> +	void *buf = NULL;
> +	int ret = 0;
> +	long sz;
> +	size_t num;
> +
> +	fp = fopen(path, "rb");
> +	if (!fp)
> +		return -errno;
> +
> +	if (fseek(fp, 0, SEEK_END) != 0) {
> +		ret = -errno;
> +		goto out;
> +	}



More information about the Linux-erofs mailing list