From 435d5f4bb2ccba3b791d9ef61d2590e30b8e806e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 31 Oct 2014 22:56:04 -0400 Subject: common object embedded into various struct ....ns for now - just move corresponding ->proc_inum instances over there Acked-by: "Eric W. Biederman" Signed-off-by: Al Viro --- fs/mount.h | 3 ++- fs/namespace.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/mount.h b/fs/mount.h index f82c62840905..0ad6f760ce52 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -1,10 +1,11 @@ #include #include #include +#include struct mnt_namespace { atomic_t count; - unsigned int proc_inum; + struct ns_common ns; struct mount * root; struct list_head list; struct user_namespace *user_ns; diff --git a/fs/namespace.c b/fs/namespace.c index 5b66b2b3624d..adc2ea2532a0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2640,7 +2640,7 @@ dput_out: static void free_mnt_ns(struct mnt_namespace *ns) { - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); put_user_ns(ns->user_ns); kfree(ns); } @@ -2662,7 +2662,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); if (!new_ns) return ERR_PTR(-ENOMEM); - ret = proc_alloc_inum(&new_ns->proc_inum); + ret = proc_alloc_inum(&new_ns->ns.inum); if (ret) { kfree(new_ns); return ERR_PTR(ret); @@ -3201,7 +3201,7 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) static unsigned int mntns_inum(void *ns) { struct mnt_namespace *mnt_ns = ns; - return mnt_ns->proc_inum; + return mnt_ns->ns.inum; } const struct proc_ns_operations mntns_operations = { -- cgit v1.2.3 From 58be28256d98a6b996b20f49130ea11afb8de75a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:00:23 -0400 Subject: make mntns ->get()/->put()/->install()/->inum() work with &mnt_ns->ns Acked-by: "Eric W. Biederman" Signed-off-by: Al Viro --- fs/namespace.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/namespace.c b/fs/namespace.c index adc2ea2532a0..5c21fdadabe4 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1582,6 +1582,11 @@ static bool is_mnt_ns_file(struct dentry *dentry) return true; } +struct mnt_namespace *to_mnt_ns(struct ns_common *ns) +{ + return container_of(ns, struct mnt_namespace, ns); +} + static bool mnt_ns_loop(struct dentry *dentry) { /* Could bind mounting the mount namespace inode cause a @@ -1591,7 +1596,7 @@ static bool mnt_ns_loop(struct dentry *dentry) if (!is_mnt_ns_file(dentry)) return false; - mnt_ns = get_proc_ns(dentry->d_inode)->ns; + mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)->ns); return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; } @@ -3146,14 +3151,14 @@ found: static void *mntns_get(struct task_struct *task) { - struct mnt_namespace *ns = NULL; + struct ns_common *ns = NULL; struct nsproxy *nsproxy; task_lock(task); nsproxy = task->nsproxy; if (nsproxy) { - ns = nsproxy->mnt_ns; - get_mnt_ns(ns); + ns = &nsproxy->mnt_ns->ns; + get_mnt_ns(to_mnt_ns(ns)); } task_unlock(task); @@ -3162,13 +3167,13 @@ static void *mntns_get(struct task_struct *task) static void mntns_put(void *ns) { - put_mnt_ns(ns); + put_mnt_ns(to_mnt_ns(ns)); } static int mntns_install(struct nsproxy *nsproxy, void *ns) { struct fs_struct *fs = current->fs; - struct mnt_namespace *mnt_ns = ns; + struct mnt_namespace *mnt_ns = to_mnt_ns(ns); struct path root; if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || @@ -3200,8 +3205,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) static unsigned int mntns_inum(void *ns) { - struct mnt_namespace *mnt_ns = ns; - return mnt_ns->ns.inum; + struct ns_common *p = ns; + return p->inum; } const struct proc_ns_operations mntns_operations = { -- cgit v1.2.3 From 64964528b24ea390824f0e5ce9d34b8d39b28cde Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:37:32 -0400 Subject: make proc_ns_operations work with struct ns_common * instead of void * We can do that now. And kill ->inum(), while we are at it - all instances are identical. Signed-off-by: Al Viro --- fs/namespace.c | 13 +++---------- fs/proc/inode.c | 2 +- fs/proc/namespaces.c | 8 ++++---- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/namespace.c b/fs/namespace.c index 5c21fdadabe4..b9c16c3f63f5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3149,7 +3149,7 @@ found: return visible; } -static void *mntns_get(struct task_struct *task) +static struct ns_common *mntns_get(struct task_struct *task) { struct ns_common *ns = NULL; struct nsproxy *nsproxy; @@ -3165,12 +3165,12 @@ static void *mntns_get(struct task_struct *task) return ns; } -static void mntns_put(void *ns) +static void mntns_put(struct ns_common *ns) { put_mnt_ns(to_mnt_ns(ns)); } -static int mntns_install(struct nsproxy *nsproxy, void *ns) +static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) { struct fs_struct *fs = current->fs; struct mnt_namespace *mnt_ns = to_mnt_ns(ns); @@ -3203,17 +3203,10 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) return 0; } -static unsigned int mntns_inum(void *ns) -{ - struct ns_common *p = ns; - return p->inum; -} - const struct proc_ns_operations mntns_operations = { .name = "mnt", .type = CLONE_NEWNS, .get = mntns_get, .put = mntns_put, .install = mntns_install, - .inum = mntns_inum, }; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 333080d7a671..43b703c6cd3b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -33,7 +33,7 @@ static void proc_evict_inode(struct inode *inode) struct proc_dir_entry *de; struct ctl_table_header *head; const struct proc_ns_operations *ns_ops; - void *ns; + struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); clear_inode(inode); diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 89026095f2b5..995e8e98237d 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -64,7 +64,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, struct inode *inode; struct proc_inode *ei; struct qstr qname = { .name = "", }; - void *ns; + struct ns_common *ns; ns = ns_ops->get(task); if (!ns) @@ -76,7 +76,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, return ERR_PTR(-ENOMEM); } - inode = iget_locked(sb, ns_ops->inum(ns)); + inode = iget_locked(sb, ns->inum); if (!inode) { dput(dentry); ns_ops->put(ns); @@ -144,7 +144,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl struct proc_inode *ei = PROC_I(inode); const struct proc_ns_operations *ns_ops = ei->ns.ns_ops; struct task_struct *task; - void *ns; + struct ns_common *ns; char name[50]; int res = -EACCES; @@ -160,7 +160,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl if (!ns) goto out_put_task; - snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); + snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns->inum); res = readlink_copy(buffer, buflen, name); ns_ops->put(ns); out_put_task: -- cgit v1.2.3 From 6344c433a452b1a05d03a61a6a85d89f793bb7b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:45:45 -0400 Subject: new helpers: ns_alloc_inum/ns_free_inum take struct ns_common *, for now simply wrappers around proc_{alloc,free}_inum() Signed-off-by: Al Viro --- fs/namespace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/namespace.c b/fs/namespace.c index b9c16c3f63f5..30738d200866 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2645,7 +2645,7 @@ dput_out: static void free_mnt_ns(struct mnt_namespace *ns) { - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); put_user_ns(ns->user_ns); kfree(ns); } @@ -2667,7 +2667,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); if (!new_ns) return ERR_PTR(-ENOMEM); - ret = proc_alloc_inum(&new_ns->ns.inum); + ret = ns_alloc_inum(&new_ns->ns); if (ret) { kfree(new_ns); return ERR_PTR(ret); -- cgit v1.2.3 From 33c429405a2c8d9e42afb9fee88a63cfb2de1e98 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 02:32:53 -0400 Subject: copy address of proc_ns_ops into ns_common Signed-off-by: Al Viro --- fs/namespace.c | 1 + fs/proc/inode.c | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namespace.c b/fs/namespace.c index 30738d200866..f815218f92d3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2672,6 +2672,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) kfree(new_ns); return ERR_PTR(ret); } + new_ns->ns.ops = &mntns_operations; new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); atomic_set(&new_ns->count, 1); new_ns->root = NULL; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 43b703c6cd3b..a212996e0987 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -32,7 +32,6 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; struct ctl_table_header *head; - const struct proc_ns_operations *ns_ops; struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); @@ -51,10 +50,9 @@ static void proc_evict_inode(struct inode *inode) sysctl_head_put(head); } /* Release any associated namespace */ - ns_ops = PROC_I(inode)->ns.ns_ops; ns = PROC_I(inode)->ns.ns; - if (ns_ops && ns) - ns_ops->put(ns); + if (ns && ns->ops) + ns->ops->put(ns); } static struct kmem_cache * proc_inode_cachep; -- cgit v1.2.3 From f77c80142e1afe6d5c16975ca5d7d1fc324b16f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 03:13:17 -0400 Subject: bury struct proc_ns in fs/proc a) make get_proc_ns() return a pointer to struct ns_common b) mirror ns_ops in dentry->d_fsdata of ns dentries, so that is_mnt_ns_file() could get away with fewer dereferences. That way struct proc_ns becomes invisible outside of fs/proc/*.c Signed-off-by: Al Viro --- fs/namespace.c | 13 ++----------- fs/proc/internal.h | 5 +++++ fs/proc/namespaces.c | 7 ++++--- 3 files changed, 11 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/namespace.c b/fs/namespace.c index f815218f92d3..9dfb4cac0c41 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1570,16 +1570,7 @@ static bool is_mnt_ns_file(struct dentry *dentry) { /* Is this a proxy for a mount namespace? */ struct inode *inode = dentry->d_inode; - struct proc_ns *ei; - - if (!proc_ns_inode(inode)) - return false; - - ei = get_proc_ns(inode); - if (ei->ns_ops != &mntns_operations) - return false; - - return true; + return proc_ns_inode(inode) && dentry->d_fsdata == &mntns_operations; } struct mnt_namespace *to_mnt_ns(struct ns_common *ns) @@ -1596,7 +1587,7 @@ static bool mnt_ns_loop(struct dentry *dentry) if (!is_mnt_ns_file(dentry)) return false; - mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)->ns); + mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)); return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; } diff --git a/fs/proc/internal.h b/fs/proc/internal.h index aa7a0ee182e1..0fabc48d905f 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -57,6 +57,11 @@ union proc_op { struct task_struct *task); }; +struct proc_ns { + struct ns_common *ns; + const struct proc_ns_operations *ns_ops; +}; + struct proc_inode { struct pid *pid; int fd; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 995e8e98237d..18fc1cf899de 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -45,7 +45,7 @@ static const struct inode_operations ns_inode_operations = { static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = dentry->d_fsdata; return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", ns_ops->name, inode->i_ino); @@ -75,6 +75,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, ns_ops->put(ns); return ERR_PTR(-ENOMEM); } + dentry->d_fsdata = (void *)ns_ops; inode = iget_locked(sb, ns->inum); if (!inode) { @@ -286,9 +287,9 @@ out_invalid: return ERR_PTR(-EINVAL); } -struct proc_ns *get_proc_ns(struct inode *inode) +struct ns_common *get_proc_ns(struct inode *inode) { - return &PROC_I(inode)->ns; + return PROC_I(inode)->ns.ns; } bool proc_ns_inode(struct inode *inode) -- cgit v1.2.3 From e149ed2b805fefdccf7ccdfc19eca22fdd4514ac Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 10:57:28 -0400 Subject: take the targets of /proc/*/ns/* symlinks to separate fs New pseudo-filesystem: nsfs. Targets of /proc/*/ns/* live there now. It's not mountable (not even registered, so it's not in /proc/filesystems, etc.). Files on it *are* bindable - we explicitly permit that in do_loopback(). This stuff lives in fs/nsfs.c now; proc_ns_fget() moved there as well. get_proc_ns() is a macro now (it's simply returning ->i_private; would have been an inline, if not for header ordering headache). proc_ns_inode() is an ex-parrot. The interface used in procfs is ns_get_path(path, task, ops) and ns_get_name(buf, size, task, ops). Dentries and inodes are never hashed; a non-counting reference to dentry is stashed in ns_common (removed by ->d_prune()) and reused by ns_get_path() if present. See ns_get_path()/ns_prune_dentry/nsfs_evict() for details of that mechanism. As the result, proc_ns_follow_link() has stopped poking in nd->path.mnt; it does nd_jump_link() on a consistent pair it gets from ns_get_path(). Signed-off-by: Al Viro --- fs/Makefile | 2 +- fs/internal.h | 5 ++ fs/namespace.c | 9 ++- fs/nsfs.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/inode.c | 5 -- fs/proc/namespaces.c | 152 +++++------------------------------------------- 6 files changed, 186 insertions(+), 148 deletions(-) create mode 100644 fs/nsfs.c (limited to 'fs') diff --git a/fs/Makefile b/fs/Makefile index 34a1b9dea6dd..34393376eaa2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o fs_pin.o + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o diff --git a/fs/internal.h b/fs/internal.h index 757ba2abf21e..e9a61fe67575 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -147,3 +147,8 @@ extern const struct file_operations pipefifo_fops; */ extern void sb_pin_kill(struct super_block *sb); extern void mnt_pin_kill(struct mount *m); + +/* + * fs/nsfs.c + */ +extern struct dentry_operations ns_dentry_operations; diff --git a/fs/namespace.c b/fs/namespace.c index 9dfb4cac0c41..30df6e7dd807 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1569,8 +1569,8 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) static bool is_mnt_ns_file(struct dentry *dentry) { /* Is this a proxy for a mount namespace? */ - struct inode *inode = dentry->d_inode; - return proc_ns_inode(inode) && dentry->d_fsdata == &mntns_operations; + return dentry->d_op == &ns_dentry_operations && + dentry->d_fsdata == &mntns_operations; } struct mnt_namespace *to_mnt_ns(struct ns_common *ns) @@ -2016,7 +2016,10 @@ static int do_loopback(struct path *path, const char *old_name, if (IS_MNT_UNBINDABLE(old)) goto out2; - if (!check_mnt(parent) || !check_mnt(old)) + if (!check_mnt(parent)) + goto out2; + + if (!check_mnt(old) && old_path.dentry->d_op != &ns_dentry_operations) goto out2; if (!recurse && has_locked_children(old, old_path.dentry)) diff --git a/fs/nsfs.c b/fs/nsfs.c new file mode 100644 index 000000000000..af1b24fa899d --- /dev/null +++ b/fs/nsfs.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include + +static struct vfsmount *nsfs_mnt; + +static const struct file_operations ns_file_operations = { + .llseek = no_llseek, +}; + +static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + const struct proc_ns_operations *ns_ops = dentry->d_fsdata; + + return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", + ns_ops->name, inode->i_ino); +} + +static void ns_prune_dentry(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + if (inode) { + struct ns_common *ns = inode->i_private; + atomic_long_set(&ns->stashed, 0); + } +} + +const struct dentry_operations ns_dentry_operations = +{ + .d_prune = ns_prune_dentry, + .d_delete = always_delete_dentry, + .d_dname = ns_dname, +}; + +static void nsfs_evict(struct inode *inode) +{ + struct ns_common *ns = inode->i_private; + clear_inode(inode); + ns->ops->put(ns); +} + +void *ns_get_path(struct path *path, struct task_struct *task, + const struct proc_ns_operations *ns_ops) +{ + struct vfsmount *mnt = mntget(nsfs_mnt); + struct qstr qname = { .name = "", }; + struct dentry *dentry; + struct inode *inode; + struct ns_common *ns; + unsigned long d; + +again: + ns = ns_ops->get(task); + if (!ns) { + mntput(mnt); + return ERR_PTR(-ENOENT); + } + rcu_read_lock(); + d = atomic_long_read(&ns->stashed); + if (!d) + goto slow; + dentry = (struct dentry *)d; + if (!lockref_get_not_dead(&dentry->d_lockref)) + goto slow; + rcu_read_unlock(); + ns_ops->put(ns); +got_it: + path->mnt = mnt; + path->dentry = dentry; + return NULL; +slow: + rcu_read_unlock(); + inode = new_inode_pseudo(mnt->mnt_sb); + if (!inode) { + ns_ops->put(ns); + mntput(mnt); + return ERR_PTR(-ENOMEM); + } + inode->i_ino = ns->inum; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_flags |= S_IMMUTABLE; + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_fop = &ns_file_operations; + inode->i_private = ns; + + dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); + if (!dentry) { + iput(inode); + mntput(mnt); + return ERR_PTR(-ENOMEM); + } + d_instantiate(dentry, inode); + dentry->d_fsdata = (void *)ns_ops; + d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); + if (d) { + d_delete(dentry); /* make sure ->d_prune() does nothing */ + dput(dentry); + cpu_relax(); + goto again; + } + goto got_it; +} + +int ns_get_name(char *buf, size_t size, struct task_struct *task, + const struct proc_ns_operations *ns_ops) +{ + struct ns_common *ns; + int res = -ENOENT; + ns = ns_ops->get(task); + if (ns) { + res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum); + ns_ops->put(ns); + } + return res; +} + +struct file *proc_ns_fget(int fd) +{ + struct file *file; + + file = fget(fd); + if (!file) + return ERR_PTR(-EBADF); + + if (file->f_op != &ns_file_operations) + goto out_invalid; + + return file; + +out_invalid: + fput(file); + return ERR_PTR(-EINVAL); +} + +static const struct super_operations nsfs_ops = { + .statfs = simple_statfs, + .evict_inode = nsfs_evict, +}; +static struct dentry *nsfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, + &ns_dentry_operations, NSFS_MAGIC); +} +static struct file_system_type nsfs = { + .name = "nsfs", + .mount = nsfs_mount, + .kill_sb = kill_anon_super, +}; + +void __init nsfs_init(void) +{ + nsfs_mnt = kern_mount(&nsfs); + if (IS_ERR(nsfs_mnt)) + panic("can't set nsfs up\n"); + nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; +} diff --git a/fs/proc/inode.c b/fs/proc/inode.c index a212996e0987..57a9be9a6668 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -32,7 +32,6 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; struct ctl_table_header *head; - struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); clear_inode(inode); @@ -49,10 +48,6 @@ static void proc_evict_inode(struct inode *inode) RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); sysctl_head_put(head); } - /* Release any associated namespace */ - ns = PROC_I(inode)->ns.ns; - if (ns && ns->ops) - ns->ops->put(ns); } static struct kmem_cache * proc_inode_cachep; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 18fc1cf899de..aaaac77abad0 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -1,10 +1,6 @@ #include #include -#include #include -#include -#include -#include #include #include #include @@ -34,139 +30,45 @@ static const struct proc_ns_operations *ns_entries[] = { &mntns_operations, }; -static const struct file_operations ns_file_operations = { - .llseek = no_llseek, -}; - -static const struct inode_operations ns_inode_operations = { - .setattr = proc_setattr, -}; - -static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) -{ - struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = dentry->d_fsdata; - - return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", - ns_ops->name, inode->i_ino); -} - -const struct dentry_operations ns_dentry_operations = -{ - .d_delete = always_delete_dentry, - .d_dname = ns_dname, -}; - -static struct dentry *proc_ns_get_dentry(struct super_block *sb, - struct task_struct *task, const struct proc_ns_operations *ns_ops) -{ - struct dentry *dentry, *result; - struct inode *inode; - struct proc_inode *ei; - struct qstr qname = { .name = "", }; - struct ns_common *ns; - - ns = ns_ops->get(task); - if (!ns) - return ERR_PTR(-ENOENT); - - dentry = d_alloc_pseudo(sb, &qname); - if (!dentry) { - ns_ops->put(ns); - return ERR_PTR(-ENOMEM); - } - dentry->d_fsdata = (void *)ns_ops; - - inode = iget_locked(sb, ns->inum); - if (!inode) { - dput(dentry); - ns_ops->put(ns); - return ERR_PTR(-ENOMEM); - } - - ei = PROC_I(inode); - if (inode->i_state & I_NEW) { - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_op = &ns_inode_operations; - inode->i_mode = S_IFREG | S_IRUGO; - inode->i_fop = &ns_file_operations; - ei->ns.ns_ops = ns_ops; - ei->ns.ns = ns; - unlock_new_inode(inode); - } else { - ns_ops->put(ns); - } - - d_set_d_op(dentry, &ns_dentry_operations); - result = d_instantiate_unique(dentry, inode); - if (result) { - dput(dentry); - dentry = result; - } - - return dentry; -} - static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; - struct super_block *sb = inode->i_sb; - struct proc_inode *ei = PROC_I(inode); + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; struct task_struct *task; struct path ns_path; void *error = ERR_PTR(-EACCES); task = get_proc_task(inode); if (!task) - goto out; + return error; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) - goto out_put_task; - - ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); - if (IS_ERR(ns_path.dentry)) { - error = ERR_CAST(ns_path.dentry); - goto out_put_task; + if (ptrace_may_access(task, PTRACE_MODE_READ)) { + error = ns_get_path(&ns_path, task, ns_ops); + if (!error) + nd_jump_link(nd, &ns_path); } - - ns_path.mnt = mntget(nd->path.mnt); - nd_jump_link(nd, &ns_path); - error = NULL; - -out_put_task: put_task_struct(task); -out: return error; } static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct inode *inode = dentry->d_inode; - struct proc_inode *ei = PROC_I(inode); - const struct proc_ns_operations *ns_ops = ei->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; struct task_struct *task; - struct ns_common *ns; char name[50]; int res = -EACCES; task = get_proc_task(inode); if (!task) - goto out; - - if (!ptrace_may_access(task, PTRACE_MODE_READ)) - goto out_put_task; + return res; - res = -ENOENT; - ns = ns_ops->get(task); - if (!ns) - goto out_put_task; - - snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns->inum); - res = readlink_copy(buffer, buflen, name); - ns_ops->put(ns); -out_put_task: + if (ptrace_may_access(task, PTRACE_MODE_READ)) { + res = ns_get_name(name, sizeof(name), task, ns_ops); + if (res >= 0) + res = readlink_copy(buffer, buflen, name); + } put_task_struct(task); -out: return res; } @@ -268,31 +170,3 @@ const struct inode_operations proc_ns_dir_inode_operations = { .getattr = pid_getattr, .setattr = proc_setattr, }; - -struct file *proc_ns_fget(int fd) -{ - struct file *file; - - file = fget(fd); - if (!file) - return ERR_PTR(-EBADF); - - if (file->f_op != &ns_file_operations) - goto out_invalid; - - return file; - -out_invalid: - fput(file); - return ERR_PTR(-EINVAL); -} - -struct ns_common *get_proc_ns(struct inode *inode) -{ - return PROC_I(inode)->ns.ns; -} - -bool proc_ns_inode(struct inode *inode) -{ - return inode->i_fop == &ns_file_operations; -} -- cgit v1.2.3 From 3d3d35b1e94ec918fc0ae670663235bf197d8609 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 11:10:28 -0400 Subject: kill proc_ns completely procfs inodes need only the ns_ops part; nsfs inodes don't need it at all Signed-off-by: Al Viro --- fs/proc/inode.c | 3 +-- fs/proc/internal.h | 7 +------ fs/proc/namespaces.c | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 57a9be9a6668..8420a2f80811 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -66,8 +66,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb) ei->pde = NULL; ei->sysctl = NULL; ei->sysctl_entry = NULL; - ei->ns.ns = NULL; - ei->ns.ns_ops = NULL; + ei->ns_ops = NULL; inode = &ei->vfs_inode; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; return inode; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 0fabc48d905f..d689fd6960d5 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -57,11 +57,6 @@ union proc_op { struct task_struct *task); }; -struct proc_ns { - struct ns_common *ns; - const struct proc_ns_operations *ns_ops; -}; - struct proc_inode { struct pid *pid; int fd; @@ -69,7 +64,7 @@ struct proc_inode { struct proc_dir_entry *pde; struct ctl_table_header *sysctl; struct ctl_table *sysctl_entry; - struct proc_ns ns; + const struct proc_ns_operations *ns_ops; struct inode vfs_inode; }; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index aaaac77abad0..c9eac4563fa8 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -33,7 +33,7 @@ static const struct proc_ns_operations *ns_entries[] = { static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; struct path ns_path; void *error = ERR_PTR(-EACCES); @@ -54,7 +54,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; char name[50]; int res = -EACCES; @@ -92,7 +92,7 @@ static int proc_ns_instantiate(struct inode *dir, ei = PROC_I(inode); inode->i_mode = S_IFLNK|S_IRWXUGO; inode->i_op = &proc_ns_link_inode_operations; - ei->ns.ns_ops = ns_ops; + ei->ns_ops = ns_ops; d_set_d_op(dentry, &pid_dentry_operations); d_add(dentry, inode); -- cgit v1.2.3 From 1f55a6ec940fb45e3edaa52b6e9fc40cf8e18dcb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 19:30:41 -0400 Subject: make nameidata completely opaque outside of fs/namei.c Signed-off-by: Al Viro --- fs/namei.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index db5fe86319e6..398a73b522cb 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -487,6 +487,18 @@ void path_put(const struct path *path) } EXPORT_SYMBOL(path_put); +struct nameidata { + struct path path; + struct qstr last; + struct path root; + struct inode *inode; /* path.dentry.d_inode */ + unsigned int flags; + unsigned seq, m_seq; + int last_type; + unsigned depth; + char *saved_names[MAX_NESTED_LINKS + 1]; +}; + /* * Path walking has 2 modes, rcu-walk and ref-walk (see * Documentation/filesystems/path-lookup.txt). In situations when we can't @@ -695,6 +707,18 @@ void nd_jump_link(struct nameidata *nd, struct path *path) nd->flags |= LOOKUP_JUMPED; } +void nd_set_link(struct nameidata *nd, char *path) +{ + nd->saved_names[nd->depth] = path; +} +EXPORT_SYMBOL(nd_set_link); + +char *nd_get_link(struct nameidata *nd) +{ + return nd->saved_names[nd->depth]; +} +EXPORT_SYMBOL(nd_get_link); + static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) { struct inode *inode = link->dentry->d_inode; -- cgit v1.2.3 From bd9b51e79cb0b8bc00a7e0076a4a8963ca4a797c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 18 Nov 2014 23:38:21 -0500 Subject: make default ->i_fop have ->open() fail with ENXIO As it is, default ->i_fop has NULL ->open() (along with all other methods). The only case where it matters is reopening (via procfs symlink) a file that didn't get its ->f_op from ->i_fop - anything else will have ->i_fop assigned to something sane (default would fail on read/write/ioctl/etc.). Unfortunately, such case exists - alloc_file() users, especially anon_get_file() ones. There we have tons of opened files of very different kinds sharing the same inode. As the result, attempt to reopen those via procfs succeeds and you get a descriptor you can't do anything with. Moreover, in case of sockets we set ->i_fop that will only be used on such reopen attempts - and put a failing ->open() into it to make sure those do not succeed. It would be simpler to put such ->open() into default ->i_fop and leave it unchanged both for anon inode (as we do anyway) and for socket ones. Result: * everything going through do_dentry_open() works as it used to * sock_no_open() kludge is gone * attempts to reopen anon-inode files fail as they really ought to * ditto for aio_private_file() * ditto for perfmon - this one actually tried to imitate sock_no_open() trick, but failed to set ->i_fop, so in the current tree reopens succeed and yield completely useless descriptor. Intent clearly had been to fail with -ENXIO on such reopens; now it actually does. * everything else that used alloc_file() keeps working - it has ->i_fop set for its inodes anyway Signed-off-by: Al Viro --- fs/inode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/inode.c b/fs/inode.c index 26753ba7b6d6..5b83ef7fc8d5 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -114,6 +114,11 @@ int proc_nr_inodes(struct ctl_table *table, int write, } #endif +static int no_open(struct inode *inode, struct file *file) +{ + return -ENXIO; +} + /** * inode_init_always - perform inode structure intialisation * @sb: superblock inode belongs to @@ -125,7 +130,7 @@ int proc_nr_inodes(struct ctl_table *table, int write, int inode_init_always(struct super_block *sb, struct inode *inode) { static const struct inode_operations empty_iops; - static const struct file_operations empty_fops; + static const struct file_operations no_open_fops = {.open = no_open}; struct address_space *const mapping = &inode->i_data; inode->i_sb = sb; @@ -133,7 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) inode->i_flags = 0; atomic_set(&inode->i_count, 1); inode->i_op = &empty_iops; - inode->i_fop = &empty_fops; + inode->i_fop = &no_open_fops; inode->__i_nlink = 1; inode->i_opflags = 0; i_uid_write(inode, 0); @@ -1801,7 +1806,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) } else if (S_ISFIFO(mode)) inode->i_fop = &pipefifo_fops; else if (S_ISSOCK(mode)) - inode->i_fop = &bad_sock_fops; + ; /* leave it no_open_fops */ else printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" " inode %s:%lu\n", mode, inode->i_sb->s_id, -- cgit v1.2.3 From 5e53084d7734a1e1a64346f8480c0bb66c218764 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 20 Nov 2014 14:14:42 -0500 Subject: path_init(): store the "base" pointer to file in nameidata itself Signed-off-by: Al Viro --- fs/namei.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 398a73b522cb..e967f43e56ae 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -496,6 +496,7 @@ struct nameidata { unsigned seq, m_seq; int last_type; unsigned depth; + struct file *base; char *saved_names[MAX_NESTED_LINKS + 1]; }; @@ -1845,13 +1846,14 @@ static int link_path_walk(const char *name, struct nameidata *nd) } static int path_init(int dfd, const char *name, unsigned int flags, - struct nameidata *nd, struct file **fp) + struct nameidata *nd) { int retval = 0; nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags | LOOKUP_JUMPED; nd->depth = 0; + nd->base = NULL; if (flags & LOOKUP_ROOT) { struct dentry *root = nd->root.dentry; struct inode *inode = root->d_inode; @@ -1921,7 +1923,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, nd->path = f.file->f_path; if (flags & LOOKUP_RCU) { if (f.flags & FDPUT_FPUT) - *fp = f.file; + nd->base = f.file; nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); rcu_read_lock(); } else { @@ -1954,7 +1956,6 @@ static inline int lookup_last(struct nameidata *nd, struct path *path) static int path_lookupat(int dfd, const char *name, unsigned int flags, struct nameidata *nd) { - struct file *base = NULL; struct path path; int err; @@ -1972,7 +1973,7 @@ static int path_lookupat(int dfd, const char *name, * be handled by restarting a traditional ref-walk (which will always * be able to complete). */ - err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base); + err = path_init(dfd, name, flags | LOOKUP_PARENT, nd); if (unlikely(err)) goto out; @@ -2008,8 +2009,8 @@ static int path_lookupat(int dfd, const char *name, } out: - if (base) - fput(base); + if (nd->base) + fput(nd->base); if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { path_put(&nd->root); @@ -2321,11 +2322,10 @@ out: static int path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags) { - struct file *base = NULL; struct nameidata nd; int err; - err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base); + err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd); if (unlikely(err)) goto out; @@ -2349,8 +2349,8 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags put_link(&nd, &link, cookie); } out: - if (base) - fput(base); + if (nd.base) + fput(nd.base); if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT)) path_put(&nd.root); @@ -3205,7 +3205,6 @@ out: static struct file *path_openat(int dfd, struct filename *pathname, struct nameidata *nd, const struct open_flags *op, int flags) { - struct file *base = NULL; struct file *file; struct path path; int opened = 0; @@ -3222,7 +3221,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, goto out; } - error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base); + error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd); if (unlikely(error)) goto out; @@ -3255,8 +3254,8 @@ static struct file *path_openat(int dfd, struct filename *pathname, out: if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) path_put(&nd->root); - if (base) - fput(base); + if (nd->base) + fput(nd->base); if (!(opened & FILE_OPENED)) { BUG_ON(!error); put_filp(file); -- cgit v1.2.3 From 893b7775a70e2e2050d5c3829996e906f7a3410c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 20 Nov 2014 14:18:09 -0500 Subject: fs/namei.c: new helper (path_cleanup()) All callers of path_init() proceed to do the identical cleanup when they are done with nameidata. Don't open-code it... Signed-off-by: Al Viro --- fs/namei.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index e967f43e56ae..cfebb4fe675d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1943,6 +1943,16 @@ static int path_init(int dfd, const char *name, unsigned int flags, return -ECHILD; } +static void path_cleanup(struct nameidata *nd) +{ + if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { + path_put(&nd->root); + nd->root.mnt = NULL; + } + if (unlikely(nd->base)) + fput(nd->base); +} + static inline int lookup_last(struct nameidata *nd, struct path *path) { if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) @@ -2009,13 +2019,7 @@ static int path_lookupat(int dfd, const char *name, } out: - if (nd->base) - fput(nd->base); - - if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { - path_put(&nd->root); - nd->root.mnt = NULL; - } + path_cleanup(nd); return err; } @@ -2349,12 +2353,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags put_link(&nd, &link, cookie); } out: - if (nd.base) - fput(nd.base); - - if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT)) - path_put(&nd.root); - + path_cleanup(&nd); return err; } @@ -3252,10 +3251,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, put_link(nd, &link, cookie); } out: - if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) - path_put(&nd->root); - if (nd->base) - fput(nd->base); + path_cleanup(nd); if (!(opened & FILE_OPENED)) { BUG_ON(!error); put_filp(file); -- cgit v1.2.3 From 980f3ea2f650b0416c7768af09f4dcbd464d6e43 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 20 Nov 2014 14:20:24 -0500 Subject: path_init(): don't bother with LOOKUP_PARENT in argument Signed-off-by: Al Viro --- fs/namei.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index cfebb4fe675d..285001f7b84e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1851,7 +1851,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, int retval = 0; nd->last_type = LAST_ROOT; /* if there are only slashes... */ - nd->flags = flags | LOOKUP_JUMPED; + nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; nd->depth = 0; nd->base = NULL; if (flags & LOOKUP_ROOT) { @@ -1983,7 +1983,7 @@ static int path_lookupat(int dfd, const char *name, * be handled by restarting a traditional ref-walk (which will always * be able to complete). */ - err = path_init(dfd, name, flags | LOOKUP_PARENT, nd); + err = path_init(dfd, name, flags, nd); if (unlikely(err)) goto out; @@ -2329,7 +2329,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags struct nameidata nd; int err; - err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd); + err = path_init(dfd, name, flags, &nd); if (unlikely(err)) goto out; @@ -3220,7 +3220,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, goto out; } - error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd); + error = path_init(dfd, pathname->name, flags, nd); if (unlikely(error)) goto out; -- cgit v1.2.3 From d465887f9d6b692214b0edffddf150eb702d35d9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 20 Nov 2014 14:23:33 -0500 Subject: fs/namei.c: fold link_path_walk() call into path_init() Signed-off-by: Al Viro --- fs/namei.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 285001f7b84e..7241e267f769 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1873,7 +1873,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, } else { path_get(&nd->path); } - return 0; + goto done; } nd->root.mnt = NULL; @@ -1934,13 +1934,16 @@ static int path_init(int dfd, const char *name, unsigned int flags, nd->inode = nd->path.dentry->d_inode; if (!(flags & LOOKUP_RCU)) - return 0; + goto done; if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) - return 0; + goto done; if (!(nd->flags & LOOKUP_ROOT)) nd->root.mnt = NULL; rcu_read_unlock(); return -ECHILD; +done: + current->total_link_count = 0; + return link_path_walk(name, nd); } static void path_cleanup(struct nameidata *nd) @@ -1984,13 +1987,6 @@ static int path_lookupat(int dfd, const char *name, * be able to complete). */ err = path_init(dfd, name, flags, nd); - - if (unlikely(err)) - goto out; - - current->total_link_count = 0; - err = link_path_walk(name, nd); - if (!err && !(flags & LOOKUP_PARENT)) { err = lookup_last(nd, &path); while (err > 0) { @@ -2018,7 +2014,6 @@ static int path_lookupat(int dfd, const char *name, } } -out: path_cleanup(nd); return err; } @@ -2333,11 +2328,6 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags if (unlikely(err)) goto out; - current->total_link_count = 0; - err = link_path_walk(name, &nd); - if (err) - goto out; - err = mountpoint_last(&nd, path); while (err > 0) { void *cookie; @@ -3224,11 +3214,6 @@ static struct file *path_openat(int dfd, struct filename *pathname, if (unlikely(error)) goto out; - current->total_link_count = 0; - error = link_path_walk(pathname->name, nd); - if (unlikely(error)) - goto out; - error = do_last(nd, &path, file, op, &opened, pathname); while (unlikely(error > 0)) { /* trailing symlink */ struct path link = path; -- cgit v1.2.3 From 93fe74b2e2b5d266d630f0c3f8287efcbe6ecd10 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Dec 2014 13:19:03 -0500 Subject: coda_venus_readdir(): use file_inode() Signed-off-by: Al Viro --- fs/coda/dir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 7ff025966e4f..86c893884eb9 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -426,7 +426,6 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) struct coda_file_info *cfi; struct coda_inode_info *cii; struct file *host_file; - struct dentry *de; struct venus_dirent *vdir; unsigned long vdir_size = offsetof(struct venus_dirent, d_name); unsigned int type; @@ -438,8 +437,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); host_file = cfi->cfi_container; - de = coda_file->f_path.dentry; - cii = ITOC(de->d_inode); + cii = ITOC(file_inode(coda_file)); vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); if (!vdir) return -ENOMEM; -- cgit v1.2.3