11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dcookies.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2002 John Levon <levon@movementarian.org> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Persistent cookie-path mappings. These are used by 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * profilers to convert a per-task EIP value into something 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * non-transitory that can be processed at a later date. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is done by locking the dentry/vfsmnt pair in the 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel until released by the tasks needing the persistent 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * objects. The tag is simply an unsigned long that refers 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the pair and can be looked up from userspace. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/syscalls.h> 16630d9c47274aa89bfa77fe6556d7818bdcb12992Paul Gortmaker#include <linux/export.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mount.h> 2016f7e0fe2ecc30f30652e8185e1772cdebe39109Randy Dunlap#include <linux/capability.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dcache.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 234e950f6f0189f65f8bf069cf2272649ef418f5e4Alexey Dobriyan#include <linux/err.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dcookies.h> 26353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar#include <linux/mutex.h> 27448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck#include <linux/path.h> 28d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#include <linux/compat.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The dcookies are allocated from a kmem_cache and 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hashed onto a small number of lists. None of the 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * code here is particularly performance critical 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dcookie_struct { 36448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck struct path path; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head hash_list; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(dcookie_users); 41353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnarstatic DEFINE_MUTEX(dcookie_mutex); 42e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic struct kmem_cache *dcookie_cache __read_mostly; 43fa3536cc144c1298f2ed9416c33f3b77fa2cd37aEric Dumazetstatic struct list_head *dcookie_hashtable __read_mostly; 44fa3536cc144c1298f2ed9416c33f3b77fa2cd37aEric Dumazetstatic size_t hash_size __read_mostly; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int is_live(void) 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return !(list_empty(&dcookie_users)); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The dentry is locked, its address will do for the cookie */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned long dcookie_value(struct dcookie_struct * dcs) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 55448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck return (unsigned long)dcs->path.dentry; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic size_t dcookie_hash(unsigned long dcookie) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (dcookie >> L1_CACHE_SHIFT) & (hash_size - 1); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dcookie_struct * find_dcookie(unsigned long dcookie) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_struct *found = NULL; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_struct * dcs; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * pos; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * list; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list = dcookie_hashtable + dcookie_hash(dcookie); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(pos, list) { 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcs = list_entry(pos, struct dcookie_struct, hash_list); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dcookie_value(dcs) == dcookie) { 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = dcs; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return found; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hash_dcookie(struct dcookie_struct * dcs) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs)); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&dcs->hash_list, list); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93448678a0f3cdd0157f00e98bd337e32030273637Jan Blunckstatic struct dcookie_struct *alloc_dcookie(struct path *path) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, 96448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck GFP_KERNEL); 97c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin struct dentry *d; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dcs) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin d = path->dentry; 102c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin spin_lock(&d->d_lock); 103c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin d->d_flags |= DCACHE_COOKIE; 104c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin spin_unlock(&d->d_lock); 105c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin 106448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck dcs->path = *path; 107448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck path_get(path); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_dcookie(dcs); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dcs; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is the main kernel-side routine that retrieves the cookie 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value for a dentry/vfsmnt pair. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 116448678a0f3cdd0157f00e98bd337e32030273637Jan Blunckint get_dcookie(struct path *path, unsigned long *cookie) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_struct * dcs; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_lock(&dcookie_mutex); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_live()) { 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin if (path->dentry->d_flags & DCACHE_COOKIE) { 129c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin dcs = find_dcookie((unsigned long)path->dentry); 130c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin } else { 131448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck dcs = alloc_dcookie(path); 132c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin if (!dcs) { 133c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin err = -ENOMEM; 134c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin goto out; 135c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cookie = dcookie_value(dcs); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 141353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_unlock(&dcookie_mutex); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* And here is where the userspace process can look up the cookie value 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to retrieve the path. 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1494a0fd5bf0fd0795af8f1be3b261f5cf146a4cb9bAl ViroSYSCALL_DEFINE3(lookup_dcookie, u64, cookie64, char __user *, buf, size_t, len) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cookie = (unsigned long)cookie64; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -EINVAL; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char * kbuf; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char * path; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t pathlen; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_struct * dcs; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we could leak path information to users 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without dir read permission without this 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 164353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_lock(&dcookie_mutex); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_live()) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(dcs = find_dcookie(cookie))) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbuf) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: (deleted) ? */ 180cf28b4863f9ee8f122e8ff3ac0d403e07ba9c6d9Jan Blunck path = d_path(&dcs->path, kbuf, PAGE_SIZE); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 182fe47ae7f53e179d2ef6771024feb000cbb86640fRobert Richter mutex_unlock(&dcookie_mutex); 183fe47ae7f53e179d2ef6771024feb000cbb86640fRobert Richter 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(path)) { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(path); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ERANGE; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pathlen = kbuf + PAGE_SIZE - path; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pathlen <= len) { 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = pathlen; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(buf, path, pathlen)) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EFAULT; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbuf); 200fe47ae7f53e179d2ef6771024feb000cbb86640fRobert Richter return err; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 202353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_unlock(&dcookie_mutex); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 206d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#ifdef CONFIG_COMPAT 207d8d14bd09cddbaf0168d61af638455a26bd027ffHeiko CarstensCOMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len) 208d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro{ 209d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#ifdef __BIG_ENDIAN 210d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len); 211d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#else 212d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro return sys_lookup_dcookie(((u64)w1 << 32) | w0, buf, len); 213d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#endif 214d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro} 215d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro#endif 216d5dc77bfeeab0b03a32e3db5e31e2f64605634abAl Viro 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dcookie_init(void) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * d; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i, hash_bits; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOMEM; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcookie_cache = kmem_cache_create("dcookie_cache", 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct dcookie_struct), 22520c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt 0, 0, NULL); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dcookie_cache) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dcookie_hashtable) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_kmem; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find the power-of-two list-heads that can fit into the allocation.. 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't guarantee that "sizeof(struct list_head)" is necessarily 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a power-of-two. 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_size = PAGE_SIZE / sizeof(struct list_head); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_bits = 0; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_bits++; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((hash_size >> hash_bits) != 0); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_bits--; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-calculate the actual number of entries and the mask 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the number of bits we can fit. 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash_size = 1UL << hash_bits; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* And initialize the newly allocated array */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = dcookie_hashtable; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = hash_size; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(d); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d++; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (i); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_kmem: 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kmem_cache_destroy(dcookie_cache); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void free_dcookie(struct dcookie_struct * dcs) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 273c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin struct dentry *d = dcs->path.dentry; 274c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin 275c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin spin_lock(&d->d_lock); 276c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin d->d_flags &= ~DCACHE_COOKIE; 277c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin spin_unlock(&d->d_lock); 278c2452f32786159ed85f0e4b21fec09258f822fc8Nick Piggin 279448678a0f3cdd0157f00e98bd337e32030273637Jan Blunck path_put(&dcs->path); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kmem_cache_free(dcookie_cache, dcs); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dcookie_exit(void) 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * list; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * pos; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head * pos2; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_struct * dcs; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t i; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < hash_size; ++i) { 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list = dcookie_hashtable + i; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(pos, pos2, list) { 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcs = list_entry(pos, struct dcookie_struct, hash_list); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&dcs->hash_list); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dcookie(dcs); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dcookie_hashtable); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kmem_cache_destroy(dcookie_cache); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dcookie_user { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head next; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dcookie_user * dcookie_register(void) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dcookie_user * user; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 314353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_lock(&dcookie_mutex); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!user) 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_live() && dcookie_init()) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&user->next, &dcookie_users); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 326353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_unlock(&dcookie_mutex); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return user; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(user); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user = NULL; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dcookie_unregister(struct dcookie_user * user) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 337353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_lock(&dcookie_mutex); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&user->next); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(user); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_live()) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcookie_exit(); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 345353ab6e97b8f209dbecc9f650f1f84e3da2a7bb1Ingo Molnar mutex_unlock(&dcookie_mutex); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(dcookie_register); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(dcookie_unregister); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(get_dcookie); 351