kernel-fxtec-pro1x/fs/dcookies.c
Alexey Dobriyan 4e950f6f01 Remove fs.h from mm.h
Remove fs.h from mm.h. For this,
 1) Uninline vma_wants_writenotify(). It's pretty huge anyway.
 2) Add back fs.h or less bloated headers (err.h) to files that need it.

As result, on x86_64 allyesconfig, fs.h dependencies cut down from 3929 files
rebuilt down to 3444 (-12.3%).

Cross-compile tested without regressions on my two usual configs and (sigh):

alpha              arm-mx1ads        mips-bigsur          powerpc-ebony
alpha-allnoconfig  arm-neponset      mips-capcella        powerpc-g5
alpha-defconfig    arm-netwinder     mips-cobalt          powerpc-holly
alpha-up           arm-netx          mips-db1000          powerpc-iseries
arm                arm-ns9xxx        mips-db1100          powerpc-linkstation
arm-assabet        arm-omap_h2_1610  mips-db1200          powerpc-lite5200
arm-at91rm9200dk   arm-onearm        mips-db1500          powerpc-maple
arm-at91rm9200ek   arm-picotux200    mips-db1550          powerpc-mpc7448_hpc2
arm-at91sam9260ek  arm-pleb          mips-ddb5477         powerpc-mpc8272_ads
arm-at91sam9261ek  arm-pnx4008       mips-decstation      powerpc-mpc8313_rdb
arm-at91sam9263ek  arm-pxa255-idp    mips-e55             powerpc-mpc832x_mds
arm-at91sam9rlek   arm-realview      mips-emma2rh         powerpc-mpc832x_rdb
arm-ateb9200       arm-realview-smp  mips-excite          powerpc-mpc834x_itx
arm-badge4         arm-rpc           mips-fulong          powerpc-mpc834x_itxgp
arm-carmeva        arm-s3c2410       mips-ip22            powerpc-mpc834x_mds
arm-cerfcube       arm-shannon       mips-ip27            powerpc-mpc836x_mds
arm-clps7500       arm-shark         mips-ip32            powerpc-mpc8540_ads
arm-collie         arm-simpad        mips-jazz            powerpc-mpc8544_ds
arm-corgi          arm-spitz         mips-jmr3927         powerpc-mpc8560_ads
arm-csb337         arm-trizeps4      mips-malta           powerpc-mpc8568mds
arm-csb637         arm-versatile     mips-mipssim         powerpc-mpc85xx_cds
arm-ebsa110        i386              mips-mpc30x          powerpc-mpc8641_hpcn
arm-edb7211        i386-allnoconfig  mips-msp71xx         powerpc-mpc866_ads
arm-em_x270        i386-defconfig    mips-ocelot          powerpc-mpc885_ads
arm-ep93xx         i386-up           mips-pb1100          powerpc-pasemi
arm-footbridge     ia64              mips-pb1500          powerpc-pmac32
arm-fortunet       ia64-allnoconfig  mips-pb1550          powerpc-ppc64
arm-h3600          ia64-bigsur       mips-pnx8550-jbs     powerpc-prpmc2800
arm-h7201          ia64-defconfig    mips-pnx8550-stb810  powerpc-ps3
arm-h7202          ia64-gensparse    mips-qemu            powerpc-pseries
arm-hackkit        ia64-sim          mips-rbhma4200       powerpc-up
arm-integrator     ia64-sn2          mips-rbhma4500       s390
arm-iop13xx        ia64-tiger        mips-rm200           s390-allnoconfig
arm-iop32x         ia64-up           mips-sb1250-swarm    s390-defconfig
arm-iop33x         ia64-zx1          mips-sead            s390-up
arm-ixp2000        m68k              mips-tb0219          sparc
arm-ixp23xx        m68k-amiga        mips-tb0226          sparc-allnoconfig
arm-ixp4xx         m68k-apollo       mips-tb0287          sparc-defconfig
arm-jornada720     m68k-atari        mips-workpad         sparc-up
arm-kafa           m68k-bvme6000     mips-wrppmc          sparc64
arm-kb9202         m68k-hp300        mips-yosemite        sparc64-allnoconfig
arm-ks8695         m68k-mac          parisc               sparc64-defconfig
arm-lart           m68k-mvme147      parisc-allnoconfig   sparc64-up
arm-lpd270         m68k-mvme16x      parisc-defconfig     um-x86_64
arm-lpd7a400       m68k-q40          parisc-up            x86_64
arm-lpd7a404       m68k-sun3         powerpc              x86_64-allnoconfig
arm-lubbock        m68k-sun3x        powerpc-cell         x86_64-defconfig
arm-lusl7200       mips              powerpc-celleb       x86_64-up
arm-mainstone      mips-atlas        powerpc-chrp32

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-29 17:09:29 -07:00

330 lines
6.4 KiB
C

/*
* 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.
*/
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/mount.h>
#include <linux/capability.h>
#include <linux/dcache.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/dcookies.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
/* 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 dentry * dentry;
struct vfsmount * vfsmnt;
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->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);
}
static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
struct vfsmount * vfsmnt)
{
struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL);
if (!dcs)
return NULL;
dentry->d_cookie = dcs;
dcs->dentry = dget(dentry);
dcs->vfsmnt = mntget(vfsmnt);
hash_dcookie(dcs);
return dcs;
}
/* This is the main kernel-side routine that retrieves the cookie
* value for a dentry/vfsmnt pair.
*/
int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt,
unsigned long * cookie)
{
int err = 0;
struct dcookie_struct * dcs;
mutex_lock(&dcookie_mutex);
if (!is_live()) {
err = -EINVAL;
goto out;
}
dcs = dentry->d_cookie;
if (!dcs)
dcs = alloc_dcookie(dentry, vfsmnt);
if (!dcs) {
err = -ENOMEM;
goto out;
}
*cookie = dcookie_value(dcs);
out:
mutex_unlock(&dcookie_mutex);
return err;
}
/* And here is where the userspace process can look up the cookie value
* to retrieve the path.
*/
asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len)
{
unsigned long cookie = (unsigned long)cookie64;
int err = -EINVAL;
char * kbuf;
char * path;
size_t pathlen;
struct dcookie_struct * dcs;
/* we could leak path information to users
* without dir read permission without this
*/
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&dcookie_mutex);
if (!is_live()) {
err = -EINVAL;
goto out;
}
if (!(dcs = find_dcookie(cookie)))
goto out;
err = -ENOMEM;
kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!kbuf)
goto out;
/* FIXME: (deleted) ? */
path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE);
if (IS_ERR(path)) {
err = PTR_ERR(path);
goto out_free;
}
err = -ERANGE;
pathlen = kbuf + PAGE_SIZE - path;
if (pathlen <= len) {
err = pathlen;
if (copy_to_user(buf, path, pathlen))
err = -EFAULT;
}
out_free:
kfree(kbuf);
out:
mutex_unlock(&dcookie_mutex);
return err;
}
static int dcookie_init(void)
{
struct list_head * d;
unsigned int i, hash_bits;
int err = -ENOMEM;
dcookie_cache = kmem_cache_create("dcookie_cache",
sizeof(struct dcookie_struct),
0, 0, NULL);
if (!dcookie_cache)
goto out;
dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!dcookie_hashtable)
goto out_kmem;
err = 0;
/*
* Find the power-of-two list-heads that can fit into the allocation..
* We don't guarantee that "sizeof(struct list_head)" is necessarily
* a power-of-two.
*/
hash_size = PAGE_SIZE / sizeof(struct list_head);
hash_bits = 0;
do {
hash_bits++;
} while ((hash_size >> hash_bits) != 0);
hash_bits--;
/*
* Re-calculate the actual number of entries and the mask
* from the number of bits we can fit.
*/
hash_size = 1UL << hash_bits;
/* And initialize the newly allocated array */
d = dcookie_hashtable;
i = hash_size;
do {
INIT_LIST_HEAD(d);
d++;
i--;
} while (i);
out:
return err;
out_kmem:
kmem_cache_destroy(dcookie_cache);
goto out;
}
static void free_dcookie(struct dcookie_struct * dcs)
{
dcs->dentry->d_cookie = NULL;
dput(dcs->dentry);
mntput(dcs->vfsmnt);
kmem_cache_free(dcookie_cache, dcs);
}
static void dcookie_exit(void)
{
struct list_head * list;
struct list_head * pos;
struct list_head * pos2;
struct dcookie_struct * dcs;
size_t i;
for (i = 0; i < hash_size; ++i) {
list = dcookie_hashtable + i;
list_for_each_safe(pos, pos2, list) {
dcs = list_entry(pos, struct dcookie_struct, hash_list);
list_del(&dcs->hash_list);
free_dcookie(dcs);
}
}
kfree(dcookie_hashtable);
kmem_cache_destroy(dcookie_cache);
}
struct dcookie_user {
struct list_head next;
};
struct dcookie_user * dcookie_register(void)
{
struct dcookie_user * user;
mutex_lock(&dcookie_mutex);
user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
if (!user)
goto out;
if (!is_live() && dcookie_init())
goto out_free;
list_add(&user->next, &dcookie_users);
out:
mutex_unlock(&dcookie_mutex);
return user;
out_free:
kfree(user);
user = NULL;
goto out;
}
void dcookie_unregister(struct dcookie_user * user)
{
mutex_lock(&dcookie_mutex);
list_del(&user->next);
kfree(user);
if (!is_live())
dcookie_exit();
mutex_unlock(&dcookie_mutex);
}
EXPORT_SYMBOL_GPL(dcookie_register);
EXPORT_SYMBOL_GPL(dcookie_unregister);
EXPORT_SYMBOL_GPL(get_dcookie);