vfs: missing inode operation should return a consistent error code

Currently several different error codes are used in the VFS for
situations where the underlying filesystem does not support the
requested inode operation (such as mkdir, tmpfile, create, etc.)
Examples: create returns EACCES, mkdir EPERM, tmpfile EOPNOTSUPP,
fileattr_get ENOIOCTLCMD.

We should provide a sensible unified error code for these situations.
EOPNOTSUPP is already used for this both in the kernel (when lacking
tmpfile support) and in userland (e.g. glibc).[1] Restricting EOPNOTSUPP
to socket operations as POSIX suggests is not the current reality and
this was recently changed in the man page as well.[2]

vfs_fileattr_get|set return ENOIOCTLCMD, but this cannot be changed
since EOPNOTSUPP is already used to by underlying filesystems to indicate
that a flag is not supported. The change to EOPNOTSUPP was reverted by
4dd5b5ac08 ("Revert "fs: make vfs_fileattr_[get|set] return
-EOPNOTSUPP"")

[1]: https://lore.kernel.org/all/20260528-abnimmt-befreien-perspektive-a7930659fb40@brauner/
[2]: https://lore.kernel.org/linux-fsdevel/ahd3SmZZqnzP0-O2@devuan/T/#t

Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
Link: https://patch.msgid.link/20260531104947.6142-1-jkoolstra@xs4all.nl
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Jori Koolstra
2026-07-31 11:22:00 +02:00
committed by Christian Brauner
parent 895741772f
commit d350627017
2 changed files with 10 additions and 10 deletions
+9 -9
View File
@@ -4190,7 +4190,7 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode,
return error;
if (!dir->i_op->create)
return -EACCES; /* shouldn't it be ENOSYS? */
return -EOPNOTSUPP;
mode = vfs_prepare_mode(idmap, dir, mode, S_IALLUGO, S_IFREG);
error = security_inode_create(dir, dentry, mode);
@@ -4565,7 +4565,7 @@ retry:
file->f_mode |= FMODE_CREATED;
if (!dir_inode->i_op->create) {
error = -EACCES;
error = -EOPNOTSUPP;
goto out_dput;
}
@@ -5252,7 +5252,7 @@ int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
return -EPERM;
if (!dir->i_op->mknod)
return -EPERM;
return -EOPNOTSUPP;
mode = vfs_prepare_mode(idmap, dir, mode, mode, mode);
error = devcgroup_inode_mknod(mode, dev);
@@ -5391,7 +5391,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
if (error)
goto err;
error = -EPERM;
error = -EOPNOTSUPP;
if (!dir->i_op->mkdir)
goto err;
@@ -5495,7 +5495,7 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
return error;
if (!dir->i_op->rmdir)
return -EPERM;
return -EOPNOTSUPP;
dget(dentry);
inode_lock(dentry->d_inode);
@@ -5631,7 +5631,7 @@ int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
return error;
if (!dir->i_op->unlink)
return -EPERM;
return -EOPNOTSUPP;
inode_lock(target);
if (IS_SWAPFILE(target))
@@ -5782,7 +5782,7 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
return error;
if (!dir->i_op->symlink)
return -EPERM;
return -EOPNOTSUPP;
error = security_inode_symlink(dir, dentry, oldname);
if (error)
@@ -5904,7 +5904,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
if (HAS_UNMAPPED_ID(idmap, inode))
return -EPERM;
if (!dir->i_op->link)
return -EPERM;
return -EOPNOTSUPP;
if (S_ISDIR(inode->i_mode))
return -EPERM;
@@ -6113,7 +6113,7 @@ int vfs_rename(struct renamedata *rd)
return error;
if (!old_dir->i_op->rename)
return -EPERM;
return -EOPNOTSUPP;
/*
* If we are going to change the parent - check write permissions,
+1 -1
View File
@@ -76,7 +76,7 @@
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EOPNOTSUPP 95 /* Operation not supported */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */