^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);