[CRIU] [PATCH v3 1/6] files-reg: Account number of unlinked parent components of ghost file

Kirill Tkhai ktkhai at virtuozzo.com
Tue Jan 19 09:07:51 PST 2016


On 18.01.2016 21:05, Pavel Emelyanov wrote:
> On 12/29/2015 05:05 PM, Kirill Tkhai wrote:
>> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
>> ---
>>  files-reg.c               |   69 ++++++++++++++++++++++++++++++++++++++-------
>>  protobuf/ghost-file.proto |    1 +
>>  2 files changed, 60 insertions(+), 10 deletions(-)
>>
>> diff --git a/files-reg.c b/files-reg.c
>> index 0f89be5..3e09ae0 100644
>> --- a/files-reg.c
>> +++ b/files-reg.c
>> @@ -48,6 +48,7 @@ struct ghost_file {
>>  
>>  	u32			dev;
>>  	u32			ino;
>> +	u32			nr_up;
>>  
>>  	struct file_remap	remap;
>>  };
>> @@ -223,6 +224,7 @@ static int open_remap_ghost(struct reg_file_info *rfi,
>>  	gf->dev = gfe->dev;
>>  	gf->ino = gfe->ino;
>>  	gf->remap.rmnt_id = rfi->rfe->mnt_id;
>> +	gf->nr_up = gfe->has_nr_up ? gfe->nr_up : 0;
>>  
>>  	if (S_ISDIR(gfe->mode))
>>  		strncpy(gf->remap.rpath, rfi->path, PATH_MAX);
>> @@ -526,7 +528,50 @@ static struct collect_image_info remap_cinfo = {
>>  	.collect = collect_one_remap,
>>  };
>>  
>> -static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev)
>> +static int count_unlinked_parents(GhostFileEntry *gfe, const char *path, int mntns_root)
>> +{
>> +	struct stat st;
>> +	char buf[PATH_MAX], *p;
>> +	int count = 0;
>> +
>> +	strcpy(buf, path);
>> +
>> +	p = strrchr(buf, '/');
>> +	if (!p) {
>> +		pr_err("No parent for %s", buf);
>> +		count = -1;
>> +		goto out;
>> +	}
>> +
>> +	while (p > buf) {
>> +		*p = '\0';
>> +		if (fstatat(mntns_root, buf, &st, 0) == 0)
> 
> This place looks dangerous. Consider we get here after we've fstat()-ed the fd
> and found out that its n_link is 0. Then we go on and stat() it by path. But
> the path in question may refer to some other existing file and thus this whole
> logic becomes flawed.

Below code counts stable parents, i.e. existing directories only. How about this?

---
diff --git a/files-reg.c b/files-reg.c
index ea66af0..8fdab57 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -48,6 +48,7 @@ struct ghost_file {
 
 	u32			dev;
 	u32			ino;
+	u32			nr_stable;
 
 	struct file_remap	remap;
 };
@@ -223,6 +224,7 @@ static int open_remap_ghost(struct reg_file_info *rfi,
 	gf->dev = gfe->dev;
 	gf->ino = gfe->ino;
 	gf->remap.rmnt_id = rfi->rfe->mnt_id;
+	gf->nr_stable = gfe->has_nr_stable ? gfe->nr_stable : 0;
 
 	if (S_ISDIR(gfe->mode))
 		strncpy(gf->remap.rpath, rfi->path, PATH_MAX);
@@ -526,7 +528,47 @@ static struct collect_image_info remap_cinfo = {
 	.collect = collect_one_remap,
 };
 
-static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev)
+static int count_stable_parents(GhostFileEntry *gfe, char *path, int mntns_root)
+{
+	int ret = 0, count = 0;
+	struct stat64 st;
+	char *p = path;
+
+	while (1) {
+		p = strchr(p, '/');
+		if (!p)
+			break;
+		*p = '\0';
+
+		ret = fstatat64(mntns_root, path, &st, AT_SYMLINK_NOFOLLOW);
+		if (ret < 0 && errno != ENOENT) {
+			pr_err("Can't stat on %s\n", path);
+			*p = '/';
+			goto out;
+		}
+
+		*p = '/';
+
+		if (ret < 0)
+			break;
+		if ((st.st_mode & S_IFMT) != S_IFDIR)
+			break;
+		count++;
+		p++;
+	}
+
+	if (p && count) {
+		gfe->has_nr_stable = true;
+		gfe->nr_stable = count;
+		pr_debug("Ghost file %s has %d stable parent component(s)", path, count);
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
+static int dump_ghost_file(char *path, int _fd, u32 id, const struct stat *st,
+			   dev_t phys_dev, int mntns_root)
 {
 	struct cr_img *img;
 	GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT;
@@ -553,6 +595,9 @@ static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_de
 	gfe.dev = phys_dev;
 	gfe.ino = st->st_ino;
 
+	if (count_stable_parents(&gfe, path, mntns_root) < 0)
+		return -1;
+
 	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
 		gfe.has_rdev = true;
 		gfe.rdev = st->st_rdev;
@@ -616,8 +661,8 @@ struct file_remap *lookup_ghost_remap(u32 dev, u32 ino)
 	return NULL;
 }
 
-static int dump_ghost_remap(char *path, const struct stat *st,
-				int lfd, u32 id, struct ns_id *nsid)
+static int dump_ghost_remap(char *path, const struct stat *st, int lfd,
+			    u32 id, struct ns_id *nsid, int mntns_root)
 {
 	struct ghost_file *gf;
 	RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
@@ -645,7 +690,7 @@ static int dump_ghost_remap(char *path, const struct stat *st,
 	gf->id = ghost_file_ids++;
 	list_add_tail(&gf->list, &ghost_files);
 
-	if (dump_ghost_file(lfd, gf->id, st, phys_dev))
+	if (dump_ghost_file(path + 1, lfd, gf->id, st, phys_dev, mntns_root))
 		return -1;
 
 dump_entry:
@@ -934,6 +979,10 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms,
 		return 0;
 	}
 
+	mntns_root = mntns_get_root_fd(nsid);
+	if (mntns_root < 0)
+		return -1;
+
 	if (ost->st_nlink == 0) {
 		/*
 		 * Unpleasant, but easy case. File is completely invisible
@@ -942,7 +991,8 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms,
 		 * also open.
 		 */
 		strip_deleted(link);
-		return dump_ghost_remap(rpath + 1, ost, lfd, id, nsid);
+
+		return dump_ghost_remap(rpath + 1, ost, lfd, id, nsid, mntns_root);
 	}
 
 	if (nfs_silly_rename(rpath, parms)) {
@@ -957,10 +1007,6 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms,
 		return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id, nsid);
 	}
 
-	mntns_root = mntns_get_root_fd(nsid);
-	if (mntns_root < 0)
-		return -1;
-
 	ret = fstatat(mntns_root, rpath, &pst, 0);
 	if (ret < 0) {
 		/*
diff --git a/protobuf/ghost-file.proto b/protobuf/ghost-file.proto
index db056db..d74f195 100644
--- a/protobuf/ghost-file.proto
+++ b/protobuf/ghost-file.proto
@@ -11,4 +11,5 @@ message ghost_file_entry {
 	optional uint32		rdev		= 6 [(criu).dev = true, (criu).odev = true];
 	optional timeval	atim		= 7;
 	optional timeval	mtim		= 8;
+	optional uint32		nr_stable	= 9; /* Number of stable parent components */
 }


More information about the CRIU mailing list