diff options
Diffstat (limited to 'fs/dcookies.c')
| -rw-r--r-- | fs/dcookies.c | 75 |
1 files changed, 48 insertions, 27 deletions
diff --git a/fs/dcookies.c b/fs/dcookies.c index 21af1629f9b..ac44a69fbea 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -13,16 +13,19 @@ */ #include <linux/syscalls.h> -#include <linux/module.h> +#include <linux/export.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 <linux/path.h> +#include <linux/compat.h> #include <asm/uaccess.h> /* The dcookies are allocated from a kmem_cache and @@ -30,8 +33,7 @@ * code here is particularly performance critical */ struct dcookie_struct { - struct dentry * dentry; - struct vfsmount * vfsmnt; + struct path path; struct list_head hash_list; }; @@ -50,7 +52,7 @@ static inline int is_live(void) /* 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; + return (unsigned long)dcs->path.dentry; } @@ -88,19 +90,22 @@ static void hash_dcookie(struct dcookie_struct * dcs) } -static struct dcookie_struct * alloc_dcookie(struct dentry * dentry, - struct vfsmount * vfsmnt) +static struct dcookie_struct *alloc_dcookie(struct path *path) { - struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL); + struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, + GFP_KERNEL); + struct dentry *d; if (!dcs) return NULL; - dentry->d_cookie = dcs; + d = path->dentry; + spin_lock(&d->d_lock); + d->d_flags |= DCACHE_COOKIE; + spin_unlock(&d->d_lock); - dcs->dentry = dget(dentry); - dcs->vfsmnt = mntget(vfsmnt); + dcs->path = *path; + path_get(path); hash_dcookie(dcs); - return dcs; } @@ -108,8 +113,7 @@ static struct dcookie_struct * alloc_dcookie(struct dentry * dentry, /* 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 get_dcookie(struct path *path, unsigned long *cookie) { int err = 0; struct dcookie_struct * dcs; @@ -121,14 +125,14 @@ int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, goto out; } - dcs = dentry->d_cookie; - - if (!dcs) - dcs = alloc_dcookie(dentry, vfsmnt); - - if (!dcs) { - err = -ENOMEM; - goto out; + if (path->dentry->d_flags & DCACHE_COOKIE) { + dcs = find_dcookie((unsigned long)path->dentry); + } else { + dcs = alloc_dcookie(path); + if (!dcs) { + err = -ENOMEM; + goto out; + } } *cookie = dcookie_value(dcs); @@ -142,7 +146,7 @@ out: /* 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) +SYSCALL_DEFINE3(lookup_dcookie, u64, cookie64, char __user *, buf, size_t, len) { unsigned long cookie = (unsigned long)cookie64; int err = -EINVAL; @@ -173,7 +177,9 @@ asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len) goto out; /* FIXME: (deleted) ? */ - path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE); + path = d_path(&dcs->path, kbuf, PAGE_SIZE); + + mutex_unlock(&dcookie_mutex); if (IS_ERR(path)) { err = PTR_ERR(path); @@ -191,11 +197,22 @@ asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len) out_free: kfree(kbuf); + return err; out: mutex_unlock(&dcookie_mutex); return err; } +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len) +{ +#ifdef __BIG_ENDIAN + return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len); +#else + return sys_lookup_dcookie(((u64)w1 << 32) | w0, buf, len); +#endif +} +#endif static int dcookie_init(void) { @@ -205,7 +222,7 @@ static int dcookie_init(void) dcookie_cache = kmem_cache_create("dcookie_cache", sizeof(struct dcookie_struct), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!dcookie_cache) goto out; @@ -253,9 +270,13 @@ out_kmem: static void free_dcookie(struct dcookie_struct * dcs) { - dcs->dentry->d_cookie = NULL; - dput(dcs->dentry); - mntput(dcs->vfsmnt); + struct dentry *d = dcs->path.dentry; + + spin_lock(&d->d_lock); + d->d_flags &= ~DCACHE_COOKIE; + spin_unlock(&d->d_lock); + + path_put(&dcs->path); kmem_cache_free(dcookie_cache, dcs); } |
