Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * dcookies.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright 2002 John Levon <levon@movementarian.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Persistent cookie-path mappings. These are used by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * profilers to convert a per-task EIP value into something
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * non-transitory that can be processed at a later date.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * This is done by locking the dentry/vfsmnt pair in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * kernel until released by the tasks needing the persistent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * objects. The tag is simply an unsigned long that refers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * to the pair and can be looked up from userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/syscalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/mount.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/dcache.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/dcookies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/path.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/compat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) /* The dcookies are allocated from a kmem_cache and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * hashed onto a small number of lists. None of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  * code here is particularly performance critical
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) struct dcookie_struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	struct path path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	struct list_head hash_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) static LIST_HEAD(dcookie_users);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) static DEFINE_MUTEX(dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) static struct kmem_cache *dcookie_cache __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) static struct list_head *dcookie_hashtable __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) static size_t hash_size __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static inline int is_live(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	return !(list_empty(&dcookie_users));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) /* The dentry is locked, its address will do for the cookie */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) static inline unsigned long dcookie_value(struct dcookie_struct * dcs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	return (unsigned long)dcs->path.dentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) static size_t dcookie_hash(unsigned long dcookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	return (dcookie >> L1_CACHE_SHIFT) & (hash_size - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) static struct dcookie_struct * find_dcookie(unsigned long dcookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	struct dcookie_struct *found = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	struct dcookie_struct * dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct list_head * pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct list_head * list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	list = dcookie_hashtable + dcookie_hash(dcookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	list_for_each(pos, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		dcs = list_entry(pos, struct dcookie_struct, hash_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		if (dcookie_value(dcs) == dcookie) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 			found = dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	return found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static void hash_dcookie(struct dcookie_struct * dcs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	list_add(&dcs->hash_list, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) static struct dcookie_struct *alloc_dcookie(const struct path *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 							GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	struct dentry *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	if (!dcs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	d = path->dentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	spin_lock(&d->d_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	d->d_flags |= DCACHE_COOKIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	spin_unlock(&d->d_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	dcs->path = *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	path_get(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	hash_dcookie(dcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	return dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* This is the main kernel-side routine that retrieves the cookie
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)  * value for a dentry/vfsmnt pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int get_dcookie(const struct path *path, unsigned long *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	struct dcookie_struct * dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	mutex_lock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	if (!is_live()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	if (path->dentry->d_flags & DCACHE_COOKIE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		dcs = find_dcookie((unsigned long)path->dentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		dcs = alloc_dcookie(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		if (!dcs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	*cookie = dcookie_value(dcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	mutex_unlock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* And here is where the userspace process can look up the cookie value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)  * to retrieve the path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int do_lookup_dcookie(u64 cookie64, char __user *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	unsigned long cookie = (unsigned long)cookie64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	char * kbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	char * path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	size_t pathlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	struct dcookie_struct * dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	/* we could leak path information to users
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	 * without dir read permission without this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	mutex_lock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	if (!is_live()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	if (!(dcs = find_dcookie(cookie)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	if (!kbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	/* FIXME: (deleted) ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	path = d_path(&dcs->path, kbuf, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	mutex_unlock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	if (IS_ERR(path)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		err = PTR_ERR(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	err = -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)  
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	pathlen = kbuf + PAGE_SIZE - path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (pathlen <= len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		err = pathlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		if (copy_to_user(buf, path, pathlen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 			err = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	kfree(kbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	mutex_unlock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) SYSCALL_DEFINE3(lookup_dcookie, u64, cookie64, char __user *, buf, size_t, len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	return do_lookup_dcookie(cookie64, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) #ifdef __BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	return do_lookup_dcookie(((u64)w0 << 32) | w1, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	return do_lookup_dcookie(((u64)w1 << 32) | w0, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static int dcookie_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	struct list_head * d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	unsigned int i, hash_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	int err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	dcookie_cache = kmem_cache_create("dcookie_cache",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		sizeof(struct dcookie_struct),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	if (!dcookie_cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	if (!dcookie_hashtable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		goto out_kmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	 * Find the power-of-two list-heads that can fit into the allocation..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	 * We don't guarantee that "sizeof(struct list_head)" is necessarily
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	 * a power-of-two.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	hash_size = PAGE_SIZE / sizeof(struct list_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	hash_bits = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 		hash_bits++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	} while ((hash_size >> hash_bits) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	hash_bits--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	 * Re-calculate the actual number of entries and the mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	 * from the number of bits we can fit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	hash_size = 1UL << hash_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	/* And initialize the newly allocated array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	d = dcookie_hashtable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	i = hash_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 		INIT_LIST_HEAD(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 		d++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		i--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	} while (i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) out_kmem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	kmem_cache_destroy(dcookie_cache);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static void free_dcookie(struct dcookie_struct * dcs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	struct dentry *d = dcs->path.dentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	spin_lock(&d->d_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	d->d_flags &= ~DCACHE_COOKIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	spin_unlock(&d->d_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	path_put(&dcs->path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	kmem_cache_free(dcookie_cache, dcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void dcookie_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	struct list_head * list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	struct list_head * pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	struct list_head * pos2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	struct dcookie_struct * dcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	for (i = 0; i < hash_size; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		list = dcookie_hashtable + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 		list_for_each_safe(pos, pos2, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			dcs = list_entry(pos, struct dcookie_struct, hash_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			list_del(&dcs->hash_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 			free_dcookie(dcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	kfree(dcookie_hashtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	kmem_cache_destroy(dcookie_cache);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct dcookie_user {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	struct list_head next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)  
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct dcookie_user * dcookie_register(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	struct dcookie_user * user;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	mutex_lock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	if (!user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	if (!is_live() && dcookie_init())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	list_add(&user->next, &dcookie_users);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	mutex_unlock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	return user;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	kfree(user);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	user = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) void dcookie_unregister(struct dcookie_user * user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	mutex_lock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	list_del(&user->next);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	kfree(user);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (!is_live())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		dcookie_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	mutex_unlock(&dcookie_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) EXPORT_SYMBOL_GPL(dcookie_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) EXPORT_SYMBOL_GPL(dcookie_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) EXPORT_SYMBOL_GPL(get_dcookie);