mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 22:05:36 +00:00
files-reg: fix error handling of rm_parent_dirs
If unlinkat fails it means that fs is in "corrupted" state - spoiled with non-unlinked auxiliary directories. While on it add fixme note as this function can be racy and BUG_ON if path contains double slashes. Cherry-picked from Virtuozzo criu: https://src.openvz.org/projects/OVZ/repos/criu/commits/b7b4e69fd Changes: simplify while loop condition, remove confusing FIXME, remove excess !count check in favour of while loop condition check Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
5a0943c900
commit
cfed6f35e1
@@ -1792,30 +1792,42 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rm_parent_dirs(int mntns_root, char *path, int count)
|
static int rm_parent_dirs(int mntns_root, char *path, int count)
|
||||||
{
|
{
|
||||||
char *p, *prev = NULL;
|
char *p, *prev = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
if (!count)
|
while (count-- > 0) {
|
||||||
return;
|
|
||||||
|
|
||||||
while (count > 0) {
|
|
||||||
count -= 1;
|
|
||||||
p = strrchr(path, '/');
|
p = strrchr(path, '/');
|
||||||
if (p)
|
if (p) {
|
||||||
|
/* We don't handle "//" in path */
|
||||||
|
BUG_ON(prev && (prev - p == 1));
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
} else {
|
||||||
|
/* Inconsistent path and count */
|
||||||
|
pr_perror("Can't strrchr \"/\" in \"%s\"/\"%s\"]"
|
||||||
|
" left count=%d\n",
|
||||||
|
path, prev ? prev + 1 : "", count + 1);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
if (prev)
|
if (prev)
|
||||||
*prev = '/';
|
*prev = '/';
|
||||||
|
|
||||||
if (unlinkat(mntns_root, path, AT_REMOVEDIR))
|
|
||||||
pr_perror("Can't remove %s AT %d", path, mntns_root);
|
|
||||||
else
|
|
||||||
pr_debug("Unlinked parent dir: %s AT %d\n", path, mntns_root);
|
|
||||||
prev = p;
|
prev = p;
|
||||||
|
|
||||||
|
if (unlinkat(mntns_root, path, AT_REMOVEDIR)) {
|
||||||
|
pr_perror("Can't remove %s AT %d", path, mntns_root);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pr_debug("Unlinked parent dir: %s AT %d\n", path, mntns_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
err:
|
||||||
if (prev)
|
if (prev)
|
||||||
*prev = '/';
|
*prev = '/';
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Construct parent dir name and mkdir parent/grandparents if they're not exist */
|
/* Construct parent dir name and mkdir parent/grandparents if they're not exist */
|
||||||
@@ -1847,6 +1859,7 @@ static int make_parent_dirs_if_need(int mntns_root, char *path)
|
|||||||
err = mkdirat(mntns_root, path, 0777);
|
err = mkdirat(mntns_root, path, 0777);
|
||||||
if (err && errno != EEXIST) {
|
if (err && errno != EEXIST) {
|
||||||
pr_perror("Can't create dir: %s AT %d", path, mntns_root);
|
pr_perror("Can't create dir: %s AT %d", path, mntns_root);
|
||||||
|
/* Failing anyway -> no retcode check */
|
||||||
rm_parent_dirs(mntns_root, path, count);
|
rm_parent_dirs(mntns_root, path, count);
|
||||||
count = -1;
|
count = -1;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1933,10 +1946,11 @@ out_root:
|
|||||||
|
|
||||||
if (linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->uid, rfi->remap->gid, 0) < 0) {
|
if (linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->uid, rfi->remap->gid, 0) < 0) {
|
||||||
int errno_saved = errno;
|
int errno_saved = errno;
|
||||||
rm_parent_dirs(mntns_root, path, *level);
|
|
||||||
errno = errno_saved;
|
if (!rm_parent_dirs(mntns_root, path, *level) && errno_saved == EEXIST) {
|
||||||
if (errno == EEXIST)
|
errno = errno_saved;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2124,7 +2138,8 @@ ext:
|
|||||||
pr_perror("Failed to unlink the remap file");
|
pr_perror("Failed to unlink the remap file");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
rm_parent_dirs(mntns_root, rfi->path, level);
|
if (rm_parent_dirs(mntns_root, rfi->path, level))
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(remap_open_lock);
|
mutex_unlock(remap_open_lock);
|
||||||
|
Reference in New Issue
Block a user