Home | History | Annotate | Download | only in module
      1 /**
      2  * @file op_dname.c
      3  * dentry stack walking
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  */
     11 
     12 #include <linux/sched.h>
     13 #include <linux/unistd.h>
     14 #include <linux/mman.h>
     15 #include <linux/file.h>
     16 
     17 #include "oprofile.h"
     18 #include "op_dcache.h"
     19 #include "op_util.h"
     20 
     21 /* --------- device routines ------------- */
     22 
     23 uint op_dname_top;
     24 struct qstr ** op_dname_stack;
     25 char * op_pool_pos;
     26 char * op_pool_start;
     27 char * op_pool_end;
     28 
     29 static ulong hash_map_open;
     30 static struct op_hash_index * hash_map;
     31 
     32 unsigned long is_map_ready(void)
     33 {
     34 	return hash_map_open;
     35 }
     36 
     37 int oprof_init_hashmap(void)
     38 {
     39 	uint i;
     40 
     41 	op_dname_stack = kmalloc(DNAME_STACK_MAX * sizeof(struct qstr *), GFP_KERNEL);
     42 	if (!op_dname_stack)
     43 		return -EFAULT;
     44 	op_dname_top = 0;
     45 	memset(op_dname_stack, 0, DNAME_STACK_MAX * sizeof(struct qstr *));
     46 
     47 	hash_map = rvmalloc(PAGE_ALIGN(OP_HASH_MAP_SIZE));
     48 	if (!hash_map)
     49 		return -EFAULT;
     50 
     51 	for (i = 0; i < OP_HASH_MAP_NR; ++i) {
     52 		hash_map[i].name = 0;
     53 		hash_map[i].parent = -1;
     54 	}
     55 
     56 	op_pool_start = (char *)(hash_map + OP_HASH_MAP_NR);
     57 	op_pool_end = op_pool_start + POOL_SIZE;
     58 	op_pool_pos = op_pool_start;
     59 
     60 	/* Ensure that the zero hash map entry is never used, we use this
     61 	 * value as end of path terminator */
     62 	hash_map[0].name = alloc_in_pool("/", 1);
     63 	hash_map[0].parent = 0;
     64 
     65 	return 0;
     66 }
     67 
     68 void oprof_free_hashmap(void)
     69 {
     70 	kfree(op_dname_stack);
     71 	rvfree(hash_map, PAGE_ALIGN(OP_HASH_MAP_SIZE));
     72 }
     73 
     74 int oprof_hash_map_open(void)
     75 {
     76 	if (test_and_set_bit(0, &hash_map_open))
     77 		return -EBUSY;
     78 
     79 	return 0;
     80 }
     81 
     82 int oprof_hash_map_release(void)
     83 {
     84 	if (!hash_map_open)
     85 		return -EFAULT;
     86 
     87 	clear_bit(0, &hash_map_open);
     88 	return 0;
     89 }
     90 
     91 int oprof_hash_map_mmap(struct file * file, struct vm_area_struct * vma)
     92 {
     93 	ulong start = (ulong)vma->vm_start;
     94 	ulong page, pos;
     95 	ulong size = (ulong)(vma->vm_end-vma->vm_start);
     96 
     97 	if (size > PAGE_ALIGN(OP_HASH_MAP_SIZE) || (vma->vm_flags & VM_WRITE) || GET_VM_OFFSET(vma))
     98 		return -EINVAL;
     99 
    100 	pos = (ulong)hash_map;
    101 	while (size > 0) {
    102 		page = kvirt_to_pa(pos);
    103 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
    104 			return -EAGAIN;
    105 		start += PAGE_SIZE;
    106 		pos += PAGE_SIZE;
    107 		size -= PAGE_SIZE;
    108 	}
    109 	return 0;
    110 }
    111 
    112 
    113 #ifndef NEED_2_2_DENTRIES
    114 int wind_dentries_2_4(struct dentry * dentry, struct vfsmount * vfsmnt, struct dentry * root, struct vfsmount * rootmnt)
    115 {
    116 	struct dentry * d = dentry;
    117 	struct vfsmount * v = vfsmnt;
    118 
    119 	/* wind the dentries onto the stack pages */
    120 	for (;;) {
    121 		/* deleted ? */
    122 		if (!IS_ROOT(d) && list_empty(&d->d_hash))
    123 			return 0;
    124 
    125 		/* the root */
    126 		if (d == root && v == rootmnt)
    127 			break;
    128 
    129 		if (d == v->mnt_root || IS_ROOT(d)) {
    130 			if (v->mnt_parent == v)
    131 				break;
    132 			/* cross the mount point */
    133 			d = v->mnt_mountpoint;
    134 			v = v->mnt_parent;
    135 		}
    136 
    137 		push_dname(&d->d_name);
    138 
    139 		d = d->d_parent;
    140 	}
    141 
    142 	return 1;
    143 }
    144 
    145 /* called with note_lock held */
    146 uint do_path_hash_2_4(struct dentry * dentry, struct vfsmount * vfsmnt)
    147 {
    148 	uint value;
    149 	struct vfsmount * rootmnt;
    150 	struct dentry * root;
    151 
    152 	read_lock(&current->fs->lock);
    153 	rootmnt = mntget(current->fs->rootmnt);
    154 	root = dget(current->fs->root);
    155 	read_unlock(&current->fs->lock);
    156 
    157 	spin_lock(&dcache_lock);
    158 
    159 	value = do_hash(dentry, vfsmnt, root, rootmnt);
    160 
    161 	spin_unlock(&dcache_lock);
    162 	dput(root);
    163 	mntput(rootmnt);
    164 	return value;
    165 }
    166 #endif /* NEED_2_2_DENTRIES */
    167 
    168 /* called with note_lock held */
    169 uint do_hash(struct dentry * dentry, struct vfsmount * vfsmnt, struct dentry * root, struct vfsmount * rootmnt)
    170 {
    171 	struct qstr * dname;
    172 	uint value = -1;
    173 	uint firsthash;
    174 	uint incr;
    175 	uint parent = 0;
    176 	struct op_hash_index * entry;
    177 
    178 	if (!wind_dentries(dentry, vfsmnt, root, rootmnt))
    179 		goto out;
    180 
    181 	/* unwind and hash */
    182 
    183 	while ((dname = pop_dname())) {
    184 		/* if N is prime, value in [0-N[ and incr = max(1, value) then
    185 		 * iteration: value = (value + incr) % N covers the range [0-N[
    186 		 * in N iterations */
    187 		incr = firsthash = value = name_hash(dname->name, dname->len, parent);
    188 		if (incr == 0)
    189 			incr = 1;
    190 
    191 	retry:
    192 		entry = &hash_map[value];
    193 		/* existing entry ? */
    194 		if (streq(get_from_pool(entry->name), dname->name)
    195 			&& entry->parent == parent)
    196 			goto next;
    197 
    198 		/* new entry ? */
    199 		if (entry->parent == -1) {
    200 			if (add_hash_entry(entry, parent, dname->name, dname->len))
    201 				goto fullpool;
    202 			goto next;
    203 		}
    204 
    205 		/* nope, find another place in the table */
    206 		value = (value + incr) % OP_HASH_MAP_NR;
    207 
    208 		if (value == firsthash)
    209 			goto fulltable;
    210 
    211 		goto retry;
    212 	next:
    213 		parent = value;
    214 	}
    215 
    216 out:
    217 	op_dname_top = 0;
    218 	return value;
    219 fullpool:
    220 	printk(KERN_ERR "oprofile: string pool exhausted.\n");
    221 	value = -1;
    222 	goto out;
    223 fulltable:
    224 	printk(KERN_ERR "oprofile: component hash table full :(\n");
    225 	value = -1;
    226 	goto out;
    227 }
    228