[PATCH v3] erofs-utils: mount: add OCI recovery support for NBD reattach

Gao Xiang hsiangkao at linux.alibaba.com
Tue Sep 9 20:54:43 AEST 2025



On 2025/9/9 18:28, ChengyuZhu6 wrote:
> From: Chengyu Zhu <hudsonzhu at tencent.com>
> 
> This commit implements recovery support for OCI-based NBD mounts,
> allowing the system to properly reattach NBD devices after
> NBD disconnection.
> 
> Signed-off-by: Chengyu Zhu <hudsonzhu at tencent.com>
> ---
>   lib/liberofs_oci.h |   5 ++
>   lib/remotes/oci.c  | 129 +++++++++++++++++++++++++++++++++++++++++
>   mount/main.c       | 141 ++++++++++++++++++++++++++++++++++++---------
>   3 files changed, 247 insertions(+), 28 deletions(-)
> 
> diff --git a/lib/liberofs_oci.h b/lib/liberofs_oci.h
> index 01a83aa..e910e6a 100644
> --- a/lib/liberofs_oci.h
> +++ b/lib/liberofs_oci.h
> @@ -71,6 +71,11 @@ int ocierofs_build_trees(struct erofs_importer *importer,
>   			 const struct ocierofs_config *cfg);
>   int ocierofs_io_open(struct erofs_vfile *vf, const struct ocierofs_config *cfg);
>   
> +int ocierofs_b64_encode_userpass(const char *username, const char *password,
> +				 char **out_b64);
> +int ocierofs_b64_decode_userpass(const char *b64,
> +				 char **out_user, char **out_pass);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c
> index de18daa..4e46e0b 100644
> --- a/lib/remotes/oci.c
> +++ b/lib/remotes/oci.c
> @@ -1471,6 +1471,135 @@ int ocierofs_io_open(struct erofs_vfile *vfile, const struct ocierofs_config *cf
>   	*(struct ocierofs_iostream **)vfile->payload = oci_iostream;
>   	return 0;
>   }
> +
> +static const char ocierofs_b64_tbl[] =
> +	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
> +
> +int ocierofs_b64_encode_userpass(const char *username, const char *password,
> +				 char **out_b64)

I think ocierofs_encode_userpass() is enough.


> +{
> +	const unsigned char *in;
> +	size_t ulen = username ? strlen(username) : 0;
> +	size_t plen = password ? strlen(password) : 0;
> +	size_t inlen = ulen + 1 + plen;
> +	size_t outlen;
> +	unsigned char *buf;
> +	char *out;
> +	size_t i, j;
> +	unsigned int octet_a, octet_b, octet_c, triple;
> +
> +	if (!out_b64)
> +		return -EINVAL;
> +	*out_b64 = NULL;
> +
> +	buf = malloc(inlen + 1);
> +	if (!buf)
> +		return -ENOMEM;
> +	memcpy(buf, username ? username : "", ulen);
> +	buf[ulen] = ':';
> +	memcpy(buf + ulen + 1, password ? password : "", plen);
> +	buf[inlen] = '\0';
> +	in = buf;
> +
> +	outlen = 4 * ((inlen + 2) / 3);
> +	out = malloc(outlen + 1);
> +	if (!out) {
> +		free(buf);
> +		return -ENOMEM;
> +	}
> +
> +	for (i = 0, j = 0; i < inlen;) {
> +		octet_a = i < inlen ? in[i++] : 0;
> +		octet_b = i < inlen ? in[i++] : 0;
> +		octet_c = i < inlen ? in[i++] : 0;
> +		triple = (octet_a << 16) | (octet_b << 8) | octet_c;
> +		out[j++] = ocierofs_b64_tbl[(triple >> 18) & 0x3F];
> +		out[j++] = ocierofs_b64_tbl[(triple >> 12) & 0x3F];
> +		out[j++] = (i - 1 > inlen) ? '=' : ocierofs_b64_tbl[(triple >> 6) & 0x3F];
> +		out[j++] = (i > inlen) ? '=' : ocierofs_b64_tbl[triple & 0x3F];
> +	}
> +	if (inlen % 3 == 1) {
> +		out[outlen - 1] = '=';
> +		out[outlen - 2] = '=';
> +	} else if (inlen % 3 == 2) {
> +		out[outlen - 1] = '=';
> +	}
> +	out[outlen] = '\0';
> +	free(buf);
> +	*out_b64 = out;
> +	return 0;
> +}
> +
> +static int ocierofs_b64_inv(int c)
> +{
> +	if (c >= 'A' && c <= 'Z')
> +		return c - 'A';
> +	if (c >= 'a' && c <= 'z')
> +		return c - 'a' + 26;
> +	if (c >= '0' && c <= '9')
> +		return c - '0' + 52;
> +	if (c == '+')
> +		return 62;
> +	if (c == '/')
> +		return 63;
> +	return -1;
> +}
> +
> +int ocierofs_b64_decode_userpass(const char *b64,
> +				 char **out_user, char **out_pass)

same ocierofs_decode_userpass().


Also lib/tar.c already has base64_decode(), I wonder
if it's can be reused.


> +{
> +	size_t len, i, j;
> +	unsigned char *out;
> +	int val = 0, valb = -8, c;
> +
> +	if (!b64 || !out_user || !out_pass)
> +		return -EINVAL;
> +	*out_user = NULL;
> +	*out_pass = NULL;
> +
> +	len = strlen(b64);
> +	out = malloc(len * 3 / 4 + 1);
> +	if (!out)
> +		return -ENOMEM;
> +
> +	for (i = 0, j = 0; i < len; i++) {
> +		c = b64[i];
> +
> +		if (c == '=')
> +			break;
> +		c = ocierofs_b64_inv(c);
> +		if (c < 0)
> +			continue;
> +		val = (val << 6) + c;
> +		valb += 6;
> +		if (valb >= 0) {
> +			out[j++] = (unsigned char)((val >> valb) & 0xFF);
> +			valb -= 8;
> +		}
> +	}
> +	out[j] = '\0';
> +
> +	{
> +		char *colon = (char *)memchr(out, ':', j);
> +
> +		if (!colon) {
> +			free(out);
> +			return -EINVAL;
> +		}
> +		*colon = '\0';
> +		*out_user = strdup((char *)out);
> +		*out_pass = strdup(colon + 1);
> +		free(out);
> +		if (!*out_user || !*out_pass) {
> +			free(*out_user);
> +			free(*out_pass);
> +			*out_user = *out_pass = NULL;
> +			return -ENOMEM;
> +		}
> +	}
> +	return 0;
> +}
> +
>   #else
>   int ocierofs_io_open(struct erofs_vfile *vfile, const struct ocierofs_config *cfg)
>   {
> diff --git a/mount/main.c b/mount/main.c
> index c52ac3b..4fe54c5 100644
> --- a/mount/main.c
> +++ b/mount/main.c
> @@ -401,10 +401,48 @@ out_closefd:
>   	return err;
>   }
>   
> -static char *erofsmount_write_recovery_info(const char *source)
> +static int erofsmount_write_recovery_oci(FILE *f, struct erofs_nbd_source *source)
> +{
> +	char *b64cred = NULL;
> +	int ret;
> +
> +	if (source->ocicfg.username || source->ocicfg.password) {
> +		ret = ocierofs_b64_encode_userpass(
> +			source->ocicfg.username,
> +			source->ocicfg.password,
> +			&b64cred);

I think you could just return `char *` or ERR_PTR(-ENOMEM)

Thanks,
Gao Xiang


More information about the Linux-erofs mailing list