Commit 33865354 authored by Pavel Emelyanov's avatar Pavel Emelyanov

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: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 51af2575
...@@ -37,6 +37,7 @@ OBJS += util.o ...@@ -37,6 +37,7 @@ OBJS += util.o
OBJS += util-net.o OBJS += util-net.o
OBJS += sysctl.o OBJS += sysctl.o
OBJS += ptrace.o OBJS += ptrace.o
OBJS += kcmp-ids.o
OBJS += rbtree.o OBJS += rbtree.o
OBJS += log.o OBJS += log.o
OBJS += libnetlink.o OBJS += libnetlink.o
......
...@@ -12,221 +12,13 @@ ...@@ -12,221 +12,13 @@
#include "types.h" #include "types.h"
#include "file-ids.h" #include "file-ids.h"
#include "rbtree.h" #include "rbtree.h"
#include "kcmp-ids.h"
#include "compiler.h" #include "compiler.h"
#include "syscall.h" #include "syscall.h"
#include "image.h" #include "image.h"
#include "util.h" #include "util.h"
struct kid_tree { static DECLARE_KCMP_TREE(fd_tree, KCMP_FILE);
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;
}
void fd_id_show_tree(void) void fd_id_show_tree(void)
{ {
......
#ifndef __KCMP_IDS_H__
#define __KCMP_IDS_H__
struct kid_tree {
struct rb_root root;
unsigned kcmp_type;
unsigned long subid;
};
#define DECLARE_KCMP_TREE(name, type) \
struct kid_tree name = { \
.root = RB_ROOT, \
.kcmp_type = type, \
.subid = 1, \
}
struct kid_elem {
int pid;
unsigned genid;
unsigned idx;
};
u32 kid_generate_gen(struct kid_tree *tree,
struct kid_elem *elem, int *new_id);
void kid_show_tree(struct kid_tree *tree);
#endif
#include <unistd.h>
#include "types.h"
#include "rbtree.h"
#include "util.h"
#include "syscall.h"
#include "kcmp-ids.h"
/*
* 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");
}
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;
}
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment