[PATCH v6] erofs-utils: mount: add OCI recovery support for NBD reattach
Gao Xiang
hsiangkao at linux.alibaba.com
Wed Sep 10 15:10:36 AEST 2025
On 2025/9/10 11:44, 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 | 3 +
> lib/remotes/oci.c | 77 +++++++++++++++++++++++
> mount/main.c | 153 ++++++++++++++++++++++++++++++++++++---------
> 3 files changed, 205 insertions(+), 28 deletions(-)
>
> diff --git a/lib/liberofs_oci.h b/lib/liberofs_oci.h
> index 01a83aa..aa41141 100644
> --- a/lib/liberofs_oci.h
> +++ b/lib/liberofs_oci.h
> @@ -71,6 +71,9 @@ 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);
>
> +char *ocierofs_encode_userpass(const char *username, const char *password);
> +int ocierofs_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..7f16741 100644
> --- a/lib/remotes/oci.c
> +++ b/lib/remotes/oci.c
> @@ -24,6 +24,7 @@
> #include "erofs/io.h"
> #include "erofs/print.h"
> #include "erofs/tar.h"
> +#include "liberofs_base64.h"
> #include "liberofs_oci.h"
> #include "liberofs_private.h"
>
> @@ -1471,6 +1472,82 @@ int ocierofs_io_open(struct erofs_vfile *vfile, const struct ocierofs_config *cf
> *(struct ocierofs_iostream **)vfile->payload = oci_iostream;
> return 0;
> }
> +
> +char *ocierofs_encode_userpass(const char *username, const char *password)
> +{
> + 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;
> + int ret;
> +
> + buf = malloc(inlen + 1);
> + if (!buf)
> + return ERR_PTR(-ENOMEM);
> + memcpy(buf, username ? username : "", ulen);
> + buf[ulen] = ':';
> + memcpy(buf + ulen + 1, password ? password : "", plen);
> + buf[inlen] = '\0';
Just:
asprintf(buf, "%s:%s", username ?: "",
password ?: "");
> +
> + outlen = 4 * ((inlen + 2) / 3);
It seems like
`outlen = 4 * DIV_ROUND_UP(inlen, 3);`
> + out = malloc(outlen + 1);
> + if (!out) {
> + free(buf);
> + return ERR_PTR(-ENOMEM);
> + }
> + ret = erofs_base64_encode(buf, inlen, out);
> + if (ret < 0) {
> + free(buf);
> + free(out);
> + return ERR_PTR(ret);
> + }
> + out[ret] = '\0';
> + free(buf);
> + return out;
> +}
> +
> +int ocierofs_decode_userpass(const char *b64, char **out_user, char **out_pass)
> +{
> + size_t len;
> + unsigned char *out;
> + int ret;
> + char *colon;
> +
> + 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;
> + ret = erofs_base64_decode(b64, len, out);
> + if (ret < 0) {
> + free(out);
> + return ret;
> + }
> + out[ret] = '\0';
> + colon = (char *)memchr(out, ':', ret);
> + 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..f6d0e1e 100644
> --- a/mount/main.c
> +++ b/mount/main.c
> @@ -401,10 +401,45 @@ 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) {
> + b64cred = ocierofs_encode_userpass(
> + source->ocicfg.username,
> + source->ocicfg.password);
> + if (IS_ERR(b64cred))
> + return PTR_ERR(b64cred);
> + }
> + ret = fprintf(f, "OCI_LAYER %s %s %s %d\n",
> + source->ocicfg.image_ref ?: "",
> + source->ocicfg.platform ?: "",
> + b64cred ?: "",
> + source->ocicfg.layer_index);
> + free(b64cred);
> + return ret < 0 ? -ENOMEM : 0;
> +}
> +
> +static int erofsmount_write_recovery_local(FILE *f, struct erofs_nbd_source *source)
> {
> - char recp[] = "/var/run/erofs/mountnbd_XXXXXX";
> char *realp;
> + int err;
> +
> + realp = realpath(source->device_path, NULL);
> + if (!realp)
> + return -errno;
> +
> + /* TYPE<LOCAL> <SOURCE PATH>\n(more..) */
> + err = fprintf(f, "LOCAL %s\n", realp) < 0;
> + free(realp);
> + return err ? -ENOMEM : 0;
> +}
> +
> +static char *erofsmount_write_recovery_info(struct erofs_nbd_source *source)
> +{
> + char recp[] = "/var/run/erofs/mountnbd_XXXXXX";
> int fd, err;
> FILE *f;
>
> @@ -424,20 +459,77 @@ static char *erofsmount_write_recovery_info(const char *source)
> return ERR_PTR(-errno);
> }
>
> - realp = realpath(source, NULL);
> - if (!realp) {
> - fclose(f);
> - return ERR_PTR(-errno);
> + if (source->type == EROFSNBD_SOURCE_OCI) {
> + err = erofsmount_write_recovery_oci(f, source);
> + if (err) {
> + fclose(f);
> + return ERR_PTR(err);
> + }
> + } else {
> + err = erofsmount_write_recovery_local(f, source);
> + if (err) {
> + fclose(f);
> + return ERR_PTR(err);
> + }
> }
> - /* TYPE<LOCAL> <SOURCE PATH>\n(more..) */
> - err = fprintf(f, "LOCAL %s\n", realp) < 0;
> +
> fclose(f);
> - free(realp);
> - if (err)
> - return ERR_PTR(-ENOMEM);
> return strdup(recp) ?: ERR_PTR(-ENOMEM);
> }
>
> +/**
> + * Parses input string in format: "image_ref [platform] [b64cred_or_layer] [layer]"
> + * Supports 4 scenarios:
> + * 1. "image_ref platform" - basic format with platform
> + * 2. "image_ref platform layer" - with layer index only
> + * 3. "image_ref platform b64cred" - with base64 credentials
> + * 4. "image_ref platform b64cred layer" - with both credentials and layer
what's the extract behavior of case 1,3, I think we should just bail out instead?
so that I think the order should be
"<image_ref> <platform> <layer num> [b64cred]" instead.
Thanks,
Gao Xiang
More information about the Linux-erofs
mailing list