Source
x
COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len)
/*
* dcookies.c
*
* Copyright 2002 John Levon <levon@movementarian.org>
*
* Persistent cookie-path mappings. These are used by
* profilers to convert a per-task EIP value into something
* non-transitory that can be processed at a later date.
* This is done by locking the dentry/vfsmnt pair in the
* kernel until released by the tasks needing the persistent
* objects. The tag is simply an unsigned long that refers
* to the pair and can be looked up from userspace.
*/
/* The dcookies are allocated from a kmem_cache and
* hashed onto a small number of lists. None of the
* code here is particularly performance critical
*/
struct dcookie_struct {
struct path path;
struct list_head hash_list;
};
static LIST_HEAD(dcookie_users);
static DEFINE_MUTEX(dcookie_mutex);
static struct kmem_cache *dcookie_cache __read_mostly;
static struct list_head *dcookie_hashtable __read_mostly;
static size_t hash_size __read_mostly;
static inline int is_live(void)
{
return !(list_empty(&dcookie_users));
}
/* The dentry is locked, its address will do for the cookie */
static inline unsigned long dcookie_value(struct dcookie_struct * dcs)
{
return (unsigned long)dcs->path.dentry;
}
static size_t dcookie_hash(unsigned long dcookie)
{
return (dcookie >> L1_CACHE_SHIFT) & (hash_size - 1);
}
static struct dcookie_struct * find_dcookie(unsigned long dcookie)
{
struct dcookie_struct *found = NULL;
struct dcookie_struct * dcs;
struct list_head * pos;
struct list_head * list;
list = dcookie_hashtable + dcookie_hash(dcookie);
list_for_each(pos, list) {
dcs = list_entry(pos, struct dcookie_struct, hash_list);
if (dcookie_value(dcs) == dcookie) {
found = dcs;
break;
}
}
return found;
}
static void hash_dcookie(struct dcookie_struct * dcs)
{
struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
list_add(&dcs->hash_list, list);
}