In order to re-attach, it's necessary to know the exact image
source for local images.

For later remote images, more information is expected to be recorded.

Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
v3:
 - should record realpath() in recovery files.

 mount/main.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 88 insertions(+), 7 deletions(-)

diff --git a/mount/main.c b/mount/main.c
index d82e526..9123618 100644
--- a/mount/main.c
+++ b/mount/main.c
@@ -300,6 +300,71 @@ out_closefd:
        return err;
 }
 
+static char *erofsmount_write_recovery_info(const char *source)
+{
+       char recp[] = "/var/run/erofs/mountnbd_XXXXXX";
+       char *realp;
+       int fd, err;
+       FILE *f;
+
+       fd = mkstemp(recp);
+       if (fd < 0 && errno == ENOENT) {
+               err = mkdir("/var/run/erofs", 0700);
+               if (err)
+                       return ERR_PTR(-errno);
+               fd = mkstemp(recp);
+       }
+       if (fd < 0)
+               return ERR_PTR(-errno);
+
+       f = fdopen(fd, "w+");
+       if (!f) {
+               close(fd);
+               return ERR_PTR(-errno);
+       }
+
+       realp = realpath(source, NULL);
+       if (!realp) {
+               fclose(f);
+               return ERR_PTR(-errno);
+       }
+       /* 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_nbd_fix_backend_linkage(int num, char **recp)
+{
+       char *newrecp;
+       int err;
+
+       newrecp = erofs_nbd_get_identifier(num);
+       if (!IS_ERR(newrecp)) {
+               err = strlen(newrecp);
+               if (newrecp[err - 1] == '\n')
+                       newrecp[err - 1] = '\0';
+               err = strcmp(newrecp, *recp) ? -EFAULT : 0;
+               free(newrecp);
+               return err;
+       }
+
+       if (asprintf(&newrecp, "/var/run/erofs/mountnbd_nbd%d", num) <= 0)
+               return -ENOMEM;
+
+       if (rename(*recp, newrecp) < 0) {
+               err = -errno;
+               free(newrecp);
+               return err;
+       }
+       free(*recp);
+       *recp = newrecp;
+       return 0;
+}
+
 static int erofsmount_startnbd_nl(pid_t *pid, const char *source)
 {
        struct erofsmount_nbd_ctx ctx = {};
@@ -318,26 +383,42 @@ static int erofsmount_startnbd_nl(pid_t *pid, const char 
*source)
                return err;
        }
        if ((*pid = fork()) == 0) {
+               char *recp;
+
                /* Otherwise, NBD disconnect sends SIGPIPE, skipping cleanup */
                if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
                        close(ctx.vd.fd);
                        exit(EXIT_FAILURE);
                }
-
+               recp = erofsmount_write_recovery_info(source);
+               if (IS_ERR(recp)) {
+                       close(ctx.vd.fd);
+                       exit(EXIT_FAILURE);
+               }
                num = -1;
-               err = erofs_nbd_nl_connect(&num, 9, INT64_MAX >> 9, NULL);
+               err = erofs_nbd_nl_connect(&num, 9, INT64_MAX >> 9, recp);
                if (err >= 0) {
                        ctx.sk.fd = err;
-                       err = write(pipefd[1], &num, sizeof(int));
-                       if (err >= sizeof(int)) {
+                       err = erofsmount_nbd_fix_backend_linkage(num, &recp);
+                       if (err) {
+                               close(ctx.sk.fd);
+                       } else {
+                               err = write(pipefd[1], &num, sizeof(int));
+                               if (err < 0)
+                                       err = -errno;
                                close(pipefd[1]);
                                close(pipefd[0]);
-                               err = 
(int)(uintptr_t)erofsmount_nbd_loopfn(&ctx);
-                               exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
+                               if (err >= sizeof(int)) {
+                                       err = 
(int)(uintptr_t)erofsmount_nbd_loopfn(&ctx);
+                                       goto out_fork;
+                               }
                        }
                }
                close(ctx.vd.fd);
-               exit(EXIT_FAILURE);
+out_fork:
+               (void)unlink(recp);
+               free(recp);
+               exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
        }
        close(pipefd[1]);
        err = read(pipefd[0], &num, sizeof(int));
-- 
2.43.0


Reply via email to