From: Chengyu Zhu <hudson...@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 <hudson...@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) +{ + 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) +{ + 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); + if (ret) { + fclose(f); + return ret; + } + } + 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 +462,62 @@ 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); } +static int erofsmount_parse_recovery_ocilayer(struct ocierofs_config *oci_cfg, + char *source) +{ + char *platform, *b64cred, *layer_str; + int err; + char *endptr; + unsigned long v; + + platform = strchr(source, ' '); + if (platform) { + *platform++ = '\0'; + oci_cfg->image_ref = source; + oci_cfg->platform = platform; + } else { + oci_cfg->image_ref = source; + } + + b64cred = strchr(platform ?: source, ' '); + if (b64cred) { + *b64cred++ = '\0'; + err = ocierofs_b64_decode_userpass(b64cred, + &oci_cfg->username, + &oci_cfg->password); + if (err) + return err; + } + + layer_str = strchr(b64cred ?: (platform ?: source), ' '); + if (layer_str) { + *layer_str++ = '\0'; + v = strtoul(layer_str, &endptr, 10); + if (endptr == layer_str || *endptr != '\0') + return -EINVAL; + oci_cfg->layer_index = (int)v; + } + return 0; +} + static int erofsmount_nbd_fix_backend_linkage(int num, char **recp) { char *newrecp; @@ -491,15 +571,10 @@ static int erofsmount_startnbd_nl(pid_t *pid, struct erofs_nbd_source *source) exit(EXIT_FAILURE); ctx.vd.fd = err; } - - if (source->type == EROFSNBD_SOURCE_LOCAL) { - recp = erofsmount_write_recovery_info(source->device_path); - if (IS_ERR(recp)) { - erofs_io_close(&ctx.vd); - exit(EXIT_FAILURE); - } - } else { - recp = NULL; + recp = erofsmount_write_recovery_info(source); + if (IS_ERR(recp)) { + erofs_io_close(&ctx.vd); + exit(EXIT_FAILURE); } num = -1; @@ -595,19 +670,29 @@ static int erofsmount_reattach(const char *target) *(source++) = '\0'; } - if (strcmp(line, "LOCAL")) { + if (!strcmp(line, "LOCAL")) { + err = open(source, O_RDONLY); + if (err < 0) { + err = -errno; + goto err_line; + } + ctx.vd.fd = err; + } else if (!strcmp(line, "OCI_LAYER")) { + struct ocierofs_config oci_cfg = {}; + + err = erofsmount_parse_recovery_ocilayer(&oci_cfg, source); + if (err) + goto err_line; + + err = ocierofs_io_open(&ctx.vd, &oci_cfg); + if (err < 0) + goto err_line; + } else { err = -EOPNOTSUPP; erofs_err("unsupported source type %s recorded in recovery file", line); goto err_line; } - err = open(source, O_RDONLY); - if (err < 0) { - err = -errno; - goto err_line; - } - ctx.vd.fd = err; - err = erofs_nbd_nl_reconnect(nbdnum, identifier); if (err >= 0) { ctx.sk.fd = err; -- 2.51.0