summaryrefslogtreecommitdiff
path: root/fs/pidfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pidfs.c')
-rw-r--r--fs/pidfs.c59
1 files changed, 38 insertions, 21 deletions
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 6c3f010074af..cf606f15def5 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -14,6 +14,8 @@
#include <linux/seq_file.h>
#include <uapi/linux/pidfd.h>
+#include "internal.h"
+
static int pidfd_release(struct inode *inode, struct file *file)
{
#ifndef CONFIG_FS_PID
@@ -186,9 +188,21 @@ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen)
d_inode(dentry)->i_ino);
}
+static void pidfs_prune_dentry(struct dentry *dentry)
+{
+ struct inode *inode;
+
+ inode = d_inode(dentry);
+ if (inode) {
+ struct pid *pid = inode->i_private;
+ WRITE_ONCE(pid->stashed, NULL);
+ }
+}
+
static const struct dentry_operations pidfs_dentry_operations = {
.d_delete = always_delete_dentry,
.d_dname = pidfs_dname,
+ .d_prune = pidfs_prune_dentry,
};
static int pidfs_init_fs_context(struct fs_context *fc)
@@ -213,34 +227,28 @@ static struct file_system_type pidfs_type = {
struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
{
- struct inode *inode;
struct file *pidfd_file;
+ struct path path;
+ int ret;
- inode = iget_locked(pidfs_sb, pid->ino);
- if (!inode)
- return ERR_PTR(-ENOMEM);
-
- if (inode->i_state & I_NEW) {
+ do {
/*
* Inode numbering for pidfs start at RESERVED_PIDS + 1.
* This avoids collisions with the root inode which is 1
* for pseudo filesystems.
*/
- inode->i_ino = pid->ino;
- inode->i_mode = S_IFREG | S_IRUGO;
- inode->i_op = &pidfs_inode_operations;
- inode->i_fop = &pidfs_file_operations;
- inode->i_flags |= S_IMMUTABLE;
- inode->i_private = get_pid(pid);
- simple_inode_init_ts(inode);
- unlock_new_inode(inode);
- }
-
- pidfd_file = alloc_file_pseudo(inode, pidfs_mnt, "", flags,
- &pidfs_file_operations);
- if (IS_ERR(pidfd_file))
- iput(inode);
-
+ ret = path_from_stashed(&pid->stashed, pid->ino, pidfs_mnt,
+ &pidfs_file_operations,
+ &pidfs_inode_operations, get_pid(pid),
+ &path);
+ if (ret <= 0 && ret != -EAGAIN)
+ put_pid(pid);
+ } while (ret == -EAGAIN);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ pidfd_file = dentry_open(&path, flags, current_cred());
+ path_put(&path);
return pidfd_file;
}
@@ -253,6 +261,11 @@ void __init pidfs_init(void)
pidfs_sb = pidfs_mnt->mnt_sb;
}
+bool is_pidfs_sb(const struct super_block *sb)
+{
+ return sb == pidfs_mnt->mnt_sb;
+}
+
#else /* !CONFIG_FS_PID */
struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
@@ -269,4 +282,8 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
}
void __init pidfs_init(void) { }
+bool is_pidfs_sb(const struct super_block *sb)
+{
+ return false;
+}
#endif