mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH 0/1] vfs: pass S_IFDIR mode to vfs_prepare_mode()
@ 2026-06-11 14:57 Jori Koolstra
  2026-06-11 14:57 ` [RFC PATCH 1/1] " Jori Koolstra
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Jori Koolstra @ 2026-06-11 14:57 UTC (permalink / raw)
  To: Christian Brauner, Jan Kara, Steve French, Steve French, Al Viro,
	NeilBrown, Jeff Layton
  Cc: linux-cifs, linux-fsdevel, linux-kernel, jkoolstra

There is a comment in vfs_prepare_mode() that says:

  Note that it's currently valid for @type to be 0 if a directory is
  created. Filesystems raise that flag individually and we need to check
  whether each filesystem can deal with receiving S_IFDIR from the vfs
  before we enforce a non-zero type.

This is a bit challenging since there are many filesystems. Claude Opus
4.8 was used to generate the context for each mkdir implementation from
which it can be judged whether passing S_IFDIR is safe. The result was
then verified by hand by looking at how the mode argument is used in
each case. To check whether all mkdir implementations are convered,
'rg "\.mkdir" ' was used and checked against the list of uses Claude
found.

The only mkdir implementation that I am not as sure of is
cifs_mkdir(). So this goes cc to the cifs people. But of course, I might
have made errors in other places (except probably not for the A list as
those are all just mode | S_IFDIR cases without other uses of mode
besides logging)


This is the AI context I worked with:

Here's each filesystem with the exact line(s) that make it safe, grouped by why.

  A. Forces S_IFDIR itself (redundant if pre-set → harmless)

  9p          fs/9p/vfs_inode.c:683        perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
  9p (dotl)   fs/9p/vfs_inode_dotl.c:365   omode |= S_IFDIR;
  affs        fs/affs/namei.c:290          inode->i_mode = S_IFDIR | mode;
  afs         fs/afs/dir.c:1326            op->create.mode = S_IFDIR | mode;
  autofs      fs/autofs/root.c:744         inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode);
  btrfs       fs/btrfs/inode.c:7123        inode_init_owner(idmap, inode, dir, S_IFDIR | mode);
  ceph        fs/ceph/dir.c:1145           mode |= S_IFDIR;
  ext2        fs/ext2/namei.c:239          inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
  ext4        fs/ext4/namei.c:3012         inode = ext4_new_inode_start_handle(idmap, dir, S_IFDIR | mode,
  f2fs        fs/f2fs/namei.c:745          inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL);
  fuse        fs/fuse/dir.c:1131           return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR);
  gfs2        fs/gfs2/inode.c:1351         gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, ...)
  hfs         fs/hfs/dir.c:228             inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
  hfsplus     fs/hfsplus/dir.c:579         hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0)
  hpfs        fs/hpfs/namei.c:66           result->i_mode |= S_IFDIR;
  hugetlbfs   fs/hugetlbfs/inode.c:974     mode | S_IFDIR, 0);
  jffs2       fs/jffs2/dir.c:465           mode |= S_IFDIR;
  jfs         fs/jfs/namei.c:226           ip = ialloc(dip, S_IFDIR | mode);
  minix       fs/minix/namei.c:113         inode = minix_new_inode(dir, S_IFDIR | mode);
  nilfs2      fs/nilfs2/namei.c:234        inode = nilfs_new_inode(dir, S_IFDIR | mode);
  ntfs3       fs/ntfs3/namei.c:216         S_IFDIR | mode, 0, NULL, 0, NULL));
  ocfs2       fs/ocfs2/namei.c:660         ocfs2_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0);
  dlmfs       fs/ocfs2/dlmfs/dlmfs.c:425   inode = dlmfs_get_inode(dir, dentry, mode | S_IFDIR);
  omfs        fs/omfs/dir.c:285            return ERR_PTR(omfs_add_node(dir, dentry, mode | S_IFDIR));
  orangefs    fs/orangefs/namei.c:336      orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref);
  ramfs       fs/ramfs/inode.c:124         ramfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0);
  ubifs       fs/ubifs/dir.c:1034          inode = ubifs_new_inode(c, dir, S_IFDIR | mode, false);
  udf         fs/udf/namei.c:431           inode = udf_new_inode(dir, S_IFDIR | mode);
  ufs         fs/ufs/namei.c:177           inode = ufs_new_inode(dir, S_IFDIR|mode);
  xfs         fs/xfs/xfs_iops.c:309        xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL)
  nfs         fs/nfs/dir.c:2475            attr.ia_mode = mode | S_IFDIR;

  B. Masks the type bits away before use (pre-set S_IFDIR stripped)

  overlayfs   fs/overlayfs/dir.c:743       ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL)
  vboxsf      fs/vboxsf/dir.c:272-273      params.info.attr.mode = (mode & 0777) |
                                             (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE);
  nfs (v3)    fs/nfs/nfs3xdr.c:562         *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
  nfs (v4)    fs/nfs/nfs4xdr.c:1170,1196   *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);

  C. Type comes from elsewhere — incoming mode's type is never consulted

  exfat       fs/exfat/namei.c:856         exfat_add_entry(dir, ..., TYPE_DIR, &info);   // literal dir type
  fat/msdos   fs/fat/namei_msdos.c:376     msdos_add_entry(dir, ..., 1, ...);            // is_dir=1 literal
  fat/vfat    fs/fat/namei_vfat.c:867      vfat_add_entry(dir, &dentry->d_name, 1, ...); // is_dir=1 literal
  coda        fs/coda/dir.c:182            attrs.va_mode = mode;     // type assigned by Venus userspace server
  hostfs      fs/hostfs/hostfs_kern.c:698  err = do_mkdir(file, mode);  // type re-read from host stat()
  cifs        fs/smb/client/inode.c:2253   cifs_mkdir(...)  // SMB protocol carries dir-vs-file separately, not in mode
  ecryptfs    fs/ecryptfs/inode.c:521      vfs_mkdir(&nop_mnt_idmap, lower_dir, ...)  // delegates to lower fs (cat.
  A/B)
  bad_inode   fs/bad_inode.c:64            return ERR_PTR(-EIO);     // never creates anything

  These ignore the type field of mode entirely (or never create an inode), so a pre-set S_IFDIR is irrelevant.

  D. Pseudo-filesystems — mode is permission-only or dropped

  configfs    fs/configfs/dir.c            mode unused; dir created by make_group()/make_item() callbacks
  kernfs      fs/kernfs/dir.c:1382         scops->mkdir(parent, dentry->d_name.name, mode)  // passed on, never
  type-switched
  resctrl     fs/resctrl/rdtgroup.c:3936   rdtgroup_mkdir() branches on parent/name, not on mode's type bits
  tracefs     fs/tracefs/inode.c:~222      tracefs_ops.mkdir(name.name.name)  // mode dropped entirely

Jori Koolstra (1):
  vfs: pass S_IFDIR mode to vfs_prepare_mode()

 fs/namei.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-06-14 16:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-11 14:57 [RFC PATCH 0/1] vfs: pass S_IFDIR mode to vfs_prepare_mode() Jori Koolstra
2026-06-11 14:57 ` [RFC PATCH 1/1] " Jori Koolstra
2026-06-11 15:33 ` [RFC PATCH 0/1] " Jan Kara
2026-06-11 20:20   ` Jori Koolstra
2026-06-12 10:33     ` Jan Kara
2026-06-12 12:19       ` Christian Brauner
2026-06-11 16:37 ` Al Viro
2026-06-11 20:16   ` Jori Koolstra
2026-06-13  1:44 ` NeilBrown
2026-06-14 16:57   ` Jori Koolstra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®