Checklist/UnlinkedFiles/Solutions/Relink

From Linux Checkpoint / Restart Wiki
Revision as of 03:20, 22 February 2010 by Mhelsley (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Use vfs_link() to relink the unlinked file back into the filesystem for checkpointing by the normal filesystem checkpoint procedure (e.g. snapshots, freeze fs + backup, etc). There are lots of corner cases involved here but the code would look roughly like:

+/*
+ * Relink an unlinked file near its original location.
+ * /foo/bar becomes /foo/.relinked/bar during checkpoint
+ * then becomes /foo/bar briefly during restart (may involve a mv to
+ * preserve a new /foo/bar).
+ */
+static int relink_file(struct ckpt_ctx *ctx, struct file *file)
+{
+       char pathname[PATH_MAX];
+       char filename[PATH_MAX];
+       char *pn;
+       char *rlink;
+       size_t len;
+       struct nameidata nd;
+       struct dentry *d_ent;
+       int err;
+
+       pn = d_path(&file->f_path, pathname, sizeof(pathname));
+       if (IS_ERR(pn)) {
+               /* TODO */
+       }
+       len = strlen(pn);
+       memmove(pathname, pn, len + 1);
+       /* We know file is unlinked -- remove the otherwise-ambiguous string */
+       len -= strlen(" (deleted)");
+       rlink = pn + len;
+       *rlink = '\0';
+
+       /* We need to add a .relinked sibling directory */
+       while (*rlink != '/')
+               rlink--;
+       rlink++;
+       /* Save the filename */
+       strcpy(filename, rlink);
+       /* Make pathname the sibling directory */
+       strncat(rlink, ".relinked", PATH_MAX - (rlink - pathname));
+       err = sys_mkdir(pn, S_IRWXU);
+       if (err < 0 && err != -EEXIST) {
+               /* TODO */
+       }
+
+       /* Link the file into its .relinked sibling directory */
+       rlink += strlen(".relinked");
+       strncat(rlink, filename, PATH_MAX - (rlink - pathname));
+       err = path_lookup(pathname, LOOKUP_CREATE, &nd);
+       if (err < 0)
+               return err;
+       if (file->f_vfsmnt != nd.mnt) {
+               /* Should never happen */
+               err = -EXDEV;
+               goto release;
+       }
+       d_ent = lookup_create(&nd, 0);
+       if (IS_ERR(d_ent)) {
+               err = PTR_ERR(d_ent);
+               goto up;
+       }
+       err = vfs_link(file->f_dentry, nd.dentry->d_inode, d_ent);
+       dput(d_ent);
+up:
+       up(&nd.entry->d_inode->i_sem);
+release:
+       path_release(&nd);
+       return err;
+}
Personal tools