diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 3662dd4..9fd0515 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -71,7 +71,6 @@ static struct dentry_operations anon_inodefs_dentry_operations = { int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags) { - struct qstr this; struct dentry *dentry; struct file *file; int error, fd; @@ -89,10 +88,7 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, * using the inode sequence number. */ error = -ENOMEM; - this.name = name; - this.len = strlen(name); - this.hash = 0; - dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); + dentry = d_alloc_unhashed(name, anon_inode_inode); if (!dentry) goto err_put_unused_fd; @@ -104,9 +100,6 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, atomic_inc(&anon_inode_inode->i_count); dentry->d_op = &anon_inodefs_dentry_operations; - /* Do not publish this dentry inside the global dentry hash table */ - dentry->d_flags &= ~DCACHE_UNHASHED; - d_instantiate(dentry, anon_inode_inode); error = -ENFILE; file = alloc_file(anon_inode_mnt, dentry, diff --git a/fs/dcache.c b/fs/dcache.c index a1d86c7..43ef88d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1111,6 +1111,39 @@ struct dentry * d_alloc_root(struct inode * root_inode) return res; } +/** + * d_alloc_unhashed - allocate unhashed dentry + * @name: dentry name + * @inode: inode to allocate the dentry for + * + * Allocate an unhashed dentry for the inode given. The inode is + * instantiated and returned. %NULL is returned if there is insufficient + * memory. Unhashed dentries have themselves as a parent. + */ + +struct dentry * d_alloc_unhashed(const char *name, struct inode *inode) +{ + struct qstr q = { .name = name, .len = strlen(name) }; + struct dentry *res; + + res = d_alloc(NULL, &q); + if (res) { + res->d_sb = inode->i_sb; + res->d_parent = res; + /* + * We dont want to push this dentry into global dentry + * hash table, so we pretend the dentry is already hashed + * by unsetting DCACHE_UNHASHED. This permits + * /proc/$pid/fd/XXX to work for sockets, pipes, and + * anonymous files (signalfd, timerfd, ...) + */ + res->d_flags &= ~DCACHE_UNHASHED; + res->d_flags |= DCACHE_DISCONNECTED; + d_instantiate(res, inode); + } + return res; +} + static inline struct hlist_head *d_hash(struct dentry *parent, unsigned long hash) { diff --git a/fs/pipe.c b/fs/pipe.c index 7aea8b8..29fcac2 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -918,7 +918,6 @@ struct file *create_write_pipe(int flags) struct inode *inode; struct file *f; struct dentry *dentry; - struct qstr name = { .name = "" }; err = -ENFILE; inode = get_pipe_inode(); @@ -926,18 +925,11 @@ struct file *create_write_pipe(int flags) goto err; err = -ENOMEM; - dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name); + dentry = d_alloc_unhashed("", inode); if (!dentry) goto err_inode; dentry->d_op = &pipefs_dentry_operations; - /* - * We dont want to publish this dentry into global dentry hash table. - * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED - * This permits a working /proc/$pid/fd/XXX on pipes - */ - dentry->d_flags &= ~DCACHE_UNHASHED; - d_instantiate(dentry, inode); err = -ENFILE; f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index a37359d..12438d6 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -238,6 +238,7 @@ extern int d_invalidate(struct dentry *); /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode *); +extern struct dentry * d_alloc_unhashed(const char *, struct inode *); /* - the ramfs-type tree */ extern void d_genocide(struct dentry *); diff --git a/net/socket.c b/net/socket.c index e9d65ea..b659b5d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -371,20 +371,12 @@ static int sock_alloc_fd(struct file **filep, int flags) static int sock_attach_fd(struct socket *sock, struct file *file, int flags) { struct dentry *dentry; - struct qstr name = { .name = "" }; - dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); + dentry = d_alloc_unhashed("", SOCK_INODE(sock)); if (unlikely(!dentry)) return -ENOMEM; dentry->d_op = &sockfs_dentry_operations; - /* - * We dont want to push this dentry into global dentry hash table. - * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED - * This permits a working /proc/$pid/fd/XXX on sockets - */ - dentry->d_flags &= ~DCACHE_UNHASHED; - d_instantiate(dentry, SOCK_INODE(sock)); sock->file = file; init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,