mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 14:25:49 +00:00
kcmp: Introduce generic object ID generator
Just move the patched code from file-ids.c to kcmp-ids.c and make the former one be client for the latter. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
212
file-ids.c
212
file-ids.c
@@ -12,221 +12,13 @@
|
||||
#include "types.h"
|
||||
#include "file-ids.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
#include "kcmp-ids.h"
|
||||
#include "compiler.h"
|
||||
#include "syscall.h"
|
||||
#include "image.h"
|
||||
#include "util.h"
|
||||
|
||||
struct kid_tree {
|
||||
struct rb_root root;
|
||||
unsigned kcmp_type;
|
||||
unsigned long subid;
|
||||
|
||||
};
|
||||
|
||||
struct kid_elem {
|
||||
int pid;
|
||||
unsigned genid;
|
||||
unsigned idx;
|
||||
};
|
||||
|
||||
static struct kid_tree fd_tree = {
|
||||
.root = RB_ROOT,
|
||||
.kcmp_type = KCMP_FILE,
|
||||
.subid = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* We track shared files by global rbtree, where each node might
|
||||
* be a root for subtree. The reason for that is the nature of data
|
||||
* we obtain from operating system.
|
||||
*
|
||||
* Basically OS provides us two ways to distinguish files
|
||||
*
|
||||
* - information obtained from fstat call
|
||||
* - shiny new sys_kcmp system call (which may compare the file descriptor
|
||||
* pointers inside the kernel and provide us order info)
|
||||
*
|
||||
* So, to speedup procedure of searching for shared file descriptors
|
||||
* we use both techniques. From fstat call we get that named general file
|
||||
* IDs (genid) which are carried in the main rbtree.
|
||||
*
|
||||
* In case if two genid are the same -- we need to use a second way and
|
||||
* call for sys_kcmp. Thus, if kernel tells us that files have identical
|
||||
* genid but in real they are different from kernel point of view -- we assign
|
||||
* a second unique key (subid) to such file descriptor and put it into a subtree.
|
||||
*
|
||||
* So the tree will look like
|
||||
*
|
||||
* (root)
|
||||
* genid-1
|
||||
* / \
|
||||
* genid-2 genid-3
|
||||
* / \ / \
|
||||
*
|
||||
* Where each genid node might be a sub-rbtree as well
|
||||
*
|
||||
* (genid-N)
|
||||
* / \
|
||||
* subid-1 subid-2
|
||||
* / \ / \
|
||||
*
|
||||
* Carrying two rbtree at once allow us to minimize the number
|
||||
* of sys_kcmp syscalls, also to collect and dump file descriptors
|
||||
* in one pass.
|
||||
*/
|
||||
|
||||
struct kid_entry {
|
||||
struct rb_node node;
|
||||
|
||||
struct rb_root subtree_root;
|
||||
struct rb_node subtree_node;
|
||||
|
||||
u32 subid; /* subid is always unique */
|
||||
struct kid_elem elem;
|
||||
} __aligned(sizeof(long));
|
||||
|
||||
static void show_subnode(struct rb_node *node, int self)
|
||||
{
|
||||
struct kid_entry *this = rb_entry(node, struct kid_entry, subtree_node);
|
||||
|
||||
pr_info("\t\t| %x.%x %s\n", this->elem.genid, this->subid,
|
||||
self ? "(self)" : "");
|
||||
if (node->rb_left) {
|
||||
pr_info("\t\t| left:\n");
|
||||
show_subnode(node->rb_left, 0);
|
||||
pr_info("\t\t| --l\n");
|
||||
}
|
||||
if (node->rb_right) {
|
||||
pr_info("\t\t| right:\n");
|
||||
show_subnode(node->rb_right, 0);
|
||||
pr_info("\t\t| --r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void show_subtree(struct rb_root *root)
|
||||
{
|
||||
pr_info("\t\t| SubTree\n");
|
||||
show_subnode(root->rb_node, 1);
|
||||
}
|
||||
|
||||
static void show_node(struct rb_node *node)
|
||||
{
|
||||
struct kid_entry *this = rb_entry(node, struct kid_entry, node);
|
||||
|
||||
pr_info("\t%x.%x\n", this->elem.genid, this->subid);
|
||||
if (node->rb_left) {
|
||||
pr_info("\tleft:\n");
|
||||
show_node(node->rb_left);
|
||||
pr_info("\t--l\n");
|
||||
}
|
||||
if (node->rb_right) {
|
||||
pr_info("\tright:\n");
|
||||
show_node(node->rb_right);
|
||||
pr_info("\t--r\n");
|
||||
}
|
||||
|
||||
show_subtree(&this->subtree_root);
|
||||
pr_info("\t--s\n");
|
||||
}
|
||||
|
||||
static void kid_show_tree(struct kid_tree *tree)
|
||||
{
|
||||
struct rb_root *root = &tree->root;
|
||||
|
||||
pr_info("\tTree of %d objects\n", tree->kcmp_type);
|
||||
if (root->rb_node)
|
||||
show_node(root->rb_node);
|
||||
}
|
||||
|
||||
static struct kid_entry *alloc_kid_entry(struct kid_tree *tree, struct kid_elem *elem)
|
||||
{
|
||||
struct kid_entry *e;
|
||||
|
||||
e = xmalloc(sizeof(*e));
|
||||
if (!e)
|
||||
goto err;
|
||||
|
||||
e->subid = tree->subid++;
|
||||
e->elem = *elem;
|
||||
|
||||
/* Make sure no overflow here */
|
||||
BUG_ON(!e->subid);
|
||||
|
||||
rb_init_node(&e->node);
|
||||
rb_init_node(&e->subtree_node);
|
||||
e->subtree_root = RB_ROOT;
|
||||
rb_link_and_balance(&e->subtree_root, &e->subtree_node,
|
||||
NULL, &e->subtree_root.rb_node);
|
||||
err:
|
||||
return e;
|
||||
}
|
||||
|
||||
static u32 kid_generate_sub(struct kid_tree *tree, struct kid_entry *e,
|
||||
struct kid_elem *elem, int *new_id)
|
||||
{
|
||||
struct rb_node *node = e->subtree_root.rb_node;
|
||||
struct kid_entry *sub = NULL;
|
||||
|
||||
struct rb_node **new = &e->subtree_root.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
|
||||
BUG_ON(!node);
|
||||
|
||||
while (node) {
|
||||
struct kid_entry *this = rb_entry(node, struct kid_entry, subtree_node);
|
||||
int ret = sys_kcmp(this->elem.pid, elem->pid, tree->kcmp_type,
|
||||
this->elem.idx, elem->idx);
|
||||
|
||||
parent = *new;
|
||||
if (ret < 0)
|
||||
node = node->rb_left, new = &((*new)->rb_left);
|
||||
else if (ret > 0)
|
||||
node = node->rb_right, new = &((*new)->rb_right);
|
||||
else
|
||||
return this->subid;
|
||||
}
|
||||
|
||||
sub = alloc_kid_entry(tree, elem);
|
||||
if (!sub)
|
||||
return 0;
|
||||
|
||||
rb_link_and_balance(&e->subtree_root, &sub->subtree_node, parent, new);
|
||||
*new_id = 1;
|
||||
return sub->subid;
|
||||
}
|
||||
|
||||
static u32 kid_generate_gen(struct kid_tree *tree,
|
||||
struct kid_elem *elem, int *new_id)
|
||||
{
|
||||
struct rb_node *node = tree->root.rb_node;
|
||||
struct kid_entry *e = NULL;
|
||||
|
||||
struct rb_node **new = &tree->root.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
|
||||
while (node) {
|
||||
struct kid_entry *this = rb_entry(node, struct kid_entry, node);
|
||||
|
||||
parent = *new;
|
||||
if (elem->genid < this->elem.genid)
|
||||
node = node->rb_left, new = &((*new)->rb_left);
|
||||
else if (elem->genid > this->elem.genid)
|
||||
node = node->rb_right, new = &((*new)->rb_right);
|
||||
else
|
||||
return kid_generate_sub(tree, this, elem, new_id);
|
||||
}
|
||||
|
||||
e = alloc_kid_entry(tree, elem);
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
rb_link_and_balance(&tree->root, &e->node, parent, new);
|
||||
*new_id = 1;
|
||||
return e->subid;
|
||||
|
||||
}
|
||||
static DECLARE_KCMP_TREE(fd_tree, KCMP_FILE);
|
||||
|
||||
void fd_id_show_tree(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user