On Mon, 20 May 2024 at 01:23, Jiri Slaby <jirislaby@xxxxxxxxxx> wrote: > > So what about LEGACY_NO_MODE which would set "i_mode = 0" and mangle the > WARN_ON appropriately. Like in the patch attached? It works (when > applied together with the anon_inode name fix). No, that's horrendous. We actually have a much better place to handle this nasty thing: pidfs_getattr() for the returned st_mode, and pidfs_dname() for the name. So how about just a patch like this? It doesn't do anything *internally* to the inodes, but it fixes up what we expose to user level to make it look like lsof expects. Linus
fs/pidfs.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/pidfs.c b/fs/pidfs.c index a63d5d24aa02..5231ddb27d25 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -169,6 +169,24 @@ static int pidfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, return -EOPNOTSUPP; } + +/* + * User space expects pidfs inodes to have no file type in st_mode. + * + * In particular, 'lsof' has this legacy logic: + * + * type = s->st_mode & S_IFMT; + * switch (type) { + * ... + * case 0: + * if (!strcmp(p, "anon_inode")) + * Lf->ntype = Ntype = N_ANON_INODE; + * + * to detect our old anon_inode logic. + * + * Rather than mess with our internal sane inode data, just fix it + * up here in getattr() by masking off the format bits. + */ static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags) @@ -176,6 +194,7 @@ static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path, struct inode *inode = d_inode(path->dentry); generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); + stat->mode &= ~S_IFMT; return 0; } @@ -199,12 +218,16 @@ static const struct super_operations pidfs_sops = { .statfs = simple_statfs, }; +/* + * 'lsof' has knowledge of out historical anon_inode use, and expects + * the pidfs dentry name to start with 'anon_inode'. + */ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen) { struct inode *inode = d_inode(dentry); struct pid *pid = inode->i_private; - return dynamic_dname(buffer, buflen, "pidfd:[%llu]", pid->ino); + return dynamic_dname(buffer, buflen, "anon_inode:[pidfd-%llu]", pid->ino); } static const struct dentry_operations pidfs_dentry_operations = {