summaryrefslogtreecommitdiff
path: root/fs/libfs.c
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2024-03-12 10:39:44 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2024-03-13 12:53:53 -0700
commit9d9539db8638cfe053fcd1f441746f0e2c8c2d32 (patch)
treeade3be60a23f710040dc8856d9d386676b701bd2 /fs/libfs.c
parentce0c1c92656e3ea3840c4a5c748aa352285cae9c (diff)
pidfs: remove config option
As Linus suggested this enables pidfs unconditionally. A key property to retain is the ability to compare pidfds by inode number (cf. [1]). That's extremely helpful just as comparing namespace file descriptors by inode number is. They are used in a variety of scenarios where they need to be compared, e.g., when receiving a pidfd via SO_PEERPIDFD from a socket to trivially authenticate a the sender and various other use-cases. For 64bit systems this is pretty trivial to do. For 32bit it's slightly more annoying as we discussed but we simply add a dumb ida based allocator that gets used on 32bit. This gives the same guarantees about inode numbers on 64bit without any overflow risk. Practically, we'll never run into overflow issues because we're constrained by the number of processes that can exist on 32bit and by the number of open files that can exist on a 32bit system. On 64bit none of this matters and things are very simple. If 32bit also needs the uniqueness guarantee they can simply parse the contents of /proc/<pid>/fd/<nr>. The uniqueness guarantees have a variety of use-cases. One of the most obvious ones is that they will make pidfiles (or "pidfdfiles", I guess) reliable as the unique identifier can be placed into there that won't be reycled. Also a frequent request. Note, I took the chance and simplified path_from_stashed() even further. Instead of passing the inode number explicitly to path_from_stashed() we let the filesystem handle that internally. So path_from_stashed() ends up even simpler than it is now. This is also a good solution allowing the cleanup code to be clean and consistent between 32bit and 64bit. The cleanup path in prepare_anon_dentry() is also switched around so we put the inode before the dentry allocation. This means we only have to call the cleanup handler for the filesystem's inode data once and can rely ->evict_inode() otherwise. Aside from having to have a bit of extra code for 32bit it actually ends up a nice cleanup for path_from_stashed() imho. Tested on both 32 and 64bit including error injection. Link: https://github.com/systemd/systemd/pull/31713 [1] Link: https://lore.kernel.org/r/20240312-dingo-sehnlich-b3ecc35c6de7@brauner Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/libfs.c')
-rw-r--r--fs/libfs.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index 0d14ae808fcf..3a6f2cb364f8 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -2001,34 +2001,40 @@ static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
}
static struct dentry *prepare_anon_dentry(struct dentry **stashed,
- unsigned long ino,
struct super_block *sb,
void *data)
{
struct dentry *dentry;
struct inode *inode;
const struct stashed_operations *sops = sb->s_fs_info;
-
- dentry = d_alloc_anon(sb);
- if (!dentry)
- return ERR_PTR(-ENOMEM);
+ int ret;
inode = new_inode_pseudo(sb);
if (!inode) {
- dput(dentry);
+ sops->put_data(data);
return ERR_PTR(-ENOMEM);
}
- inode->i_ino = ino;
inode->i_flags |= S_IMMUTABLE;
inode->i_mode = S_IFREG;
simple_inode_init_ts(inode);
- sops->init_inode(inode, data);
+
+ ret = sops->init_inode(inode, data);
+ if (ret < 0) {
+ iput(inode);
+ return ERR_PTR(ret);
+ }
/* Notice when this is changed. */
WARN_ON_ONCE(!S_ISREG(inode->i_mode));
WARN_ON_ONCE(!IS_IMMUTABLE(inode));
+ dentry = d_alloc_anon(sb);
+ if (!dentry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+
/* Store address of location where dentry's supposed to be stashed. */
dentry->d_fsdata = stashed;
@@ -2062,7 +2068,6 @@ static struct dentry *stash_dentry(struct dentry **stashed,
/**
* path_from_stashed - create path from stashed or new dentry
* @stashed: where to retrieve or stash dentry
- * @ino: inode number to use
* @mnt: mnt of the filesystems to use
* @data: data to store in inode->i_private
* @path: path to create
@@ -2077,8 +2082,8 @@ static struct dentry *stash_dentry(struct dentry **stashed,
*
* Return: On success zero and on failure a negative error is returned.
*/
-int path_from_stashed(struct dentry **stashed, unsigned long ino,
- struct vfsmount *mnt, void *data, struct path *path)
+int path_from_stashed(struct dentry **stashed, struct vfsmount *mnt, void *data,
+ struct path *path)
{
struct dentry *dentry;
const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info;
@@ -2091,11 +2096,9 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino,
}
/* Allocate a new dentry. */
- dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, data);
- if (IS_ERR(dentry)) {
- sops->put_data(data);
+ dentry = prepare_anon_dentry(stashed, mnt->mnt_sb, data);
+ if (IS_ERR(dentry))
return PTR_ERR(dentry);
- }
/* Added a new dentry. @data is now owned by the filesystem. */
path->dentry = stash_dentry(stashed, dentry);