summaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2013-10-01 16:44:54 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2013-10-25 05:41:37 +0200
commitb70a80e7a133a0c86f2fa078e7c144597c516415 (patch)
tree378dbeeafc1510fb326eda10e1f48085be098f6c /fs/dcache.c
parentmove taking vfsmount_lock down into prepend_path() (diff)
downloadlinux-b70a80e7a133a0c86f2fa078e7c144597c516415.tar.xz
linux-b70a80e7a133a0c86f2fa078e7c144597c516415.zip
vfs: introduce d_instantiate_no_diralias()
...which just returns -EBUSY if a directory alias would be created. This is to be used by fuse mkdir to make sure that a buggy or malicious userspace filesystem doesn't do anything nasty. Previously fuse used a private mutex for this purpose, which can now go away. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index d888223a5486..c8e83d0d61ac 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1801,6 +1801,33 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
EXPORT_SYMBOL(d_instantiate_unique);
+/**
+ * d_instantiate_no_diralias - instantiate a non-aliased dentry
+ * @entry: dentry to complete
+ * @inode: inode to attach to this dentry
+ *
+ * Fill in inode information in the entry. If a directory alias is found, then
+ * return an error (and drop inode). Together with d_materialise_unique() this
+ * guarantees that a directory inode may never have more than one alias.
+ */
+int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
+{
+ BUG_ON(!hlist_unhashed(&entry->d_alias));
+
+ spin_lock(&inode->i_lock);
+ if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
+ spin_unlock(&inode->i_lock);
+ iput(inode);
+ return -EBUSY;
+ }
+ __d_instantiate(entry, inode);
+ spin_unlock(&inode->i_lock);
+ security_d_instantiate(entry, inode);
+
+ return 0;
+}
+EXPORT_SYMBOL(d_instantiate_no_diralias);
+
struct dentry *d_make_root(struct inode *root_inode)
{
struct dentry *res = NULL;