projects/linux·commit ab5ed08f

Merge tag 'vfs-7.3-rc1.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

ab5ed08f · Linus Torvalds <[email protected]> · 2026-08-17 12:03:34 -07:00

Pull vfs lookup updates from Christian Brauner:
 "This refactors lookup_open() and adds vfs_lookup_open() for nfsd.

  mnt_want_write() and parent locking are moved into lookup_open()
  itself.

  audit_inode_child() is also now called in lookup_open() on failure.
  That is the calling convention in vfs_create() and vfs_mkdir(), but
  lookup_open() made no such call when atomic_open() should have created
  a file and did not. And neither did the regular ->create() path fwiw.

  This also contains work to remove the unneeded excl argument from the
  ->create() inode op"

* tag 'vfs-7.3-rc1.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  fs/namei.c: fix coding style in atomic_open() and lookup_open()
  fs/namei.c: fix kerneldoc of atomic_open() and vfs_lookup_open()
  fs/namei.c: update stale comments in lookup_open()
  Remove excl arg to ->create inode_operation
  fs/namei.c: update kerneldoc of atomic_open()
  vfs: call audit_inode_child() in lookup_open() on failure
  vfs: move create error && negative dentry case in lookup_open() up
  VFS: add vfs_lookup_open() for nfsd
  VFS: move delegated_inode retry loop into lookup_open()
  VFS: move mnt_want_write() and locking into lookup_open()
Commit
ab5ed08f2d8396fb8e3942569bbbd5cd569a753e
Parents
fff0150b · 89574177

Merge commit. Changes below are compared with the first parent: fff0150b.

Changes

54 files changed · +316 −174

FileStatusAddDelContent
Documentation/filesystems/locking.rstmodified+1−1View file
Documentation/filesystems/porting.rstmodified+8−0View file
Documentation/filesystems/vfs.rstmodified+1−1View file
fs/9p/vfs_inode.cmodified+1−2View file
fs/9p/vfs_inode_dotl.cmodified+1−2View file
fs/affs/affs.hmodified+1−1View file
fs/affs/namei.cmodified+1−1View file
fs/afs/dir.cmodified+2−2View file
fs/bad_inode.cmodified+1−1View file
fs/bfs/dir.cmodified+1−1View file
fs/btrfs/inode.cmodified+1−1View file
fs/ceph/dir.cmodified+1−1View file
fs/coda/dir.cmodified+1−1View file
fs/ecryptfs/inode.cmodified+1−1View file
fs/efivarfs/inode.cmodified+1−1View file
fs/exfat/namei.cmodified+1−1View file
fs/ext2/namei.cmodified+1−1View file
fs/ext4/namei.cmodified+1−1View file
fs/f2fs/namei.cmodified+1−1View file
fs/fat/namei_msdos.cmodified+1−1View file
fs/fat/namei_vfat.cmodified+1−1View file
fs/fuse/dir.cmodified+1−1View file
fs/gfs2/inode.cmodified+2−3View file
fs/hfs/dir.cmodified+1−1View file
fs/hfsplus/dir.cmodified+1−1View file
fs/hostfs/hostfs_kern.cmodified+1−1View file
fs/hpfs/namei.cmodified+1−1View file
fs/hugetlbfs/inode.cmodified+1−1View file
fs/jffs2/dir.cmodified+2−2View file
fs/jfs/namei.cmodified+1−1View file
fs/minix/namei.cmodified+1−1View file
fs/namei.cmodified+248−109View file
fs/nfs/dir.cmodified+2−2View file
fs/nfs/internal.hmodified+1−1View file
fs/nilfs2/namei.cmodified+1−1View file
fs/ntfs/namei.cmodified+1−1View file
fs/ntfs3/namei.cmodified+1−1View file
fs/ocfs2/dlmfs/dlmfs.cmodified+1−2View file
fs/ocfs2/namei.cmodified+1−2View file
fs/omfs/dir.cmodified+1−1View file
fs/orangefs/namei.cmodified+1−2View file
fs/overlayfs/dir.cmodified+1−1View file
fs/ramfs/inode.cmodified+1−1View file
fs/smb/client/cifsfs.hmodified+1−1View file
fs/smb/client/dir.cmodified+1−1View file
fs/ubifs/dir.cmodified+1−1View file
fs/udf/namei.cmodified+1−1View file
fs/ufs/namei.cmodified+1−2View file
fs/vboxsf/dir.cmodified+2−2View file
fs/xfs/xfs_iops.cmodified+2−3View file
include/linux/fs.hmodified+1−1View file
include/linux/namei.hmodified+3−0View file
ipc/mqueue.cmodified+1−1View file
mm/shmem.cmodified+1−1View file

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/filesystems/locking.rst

View file
diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst
index 08d01bc..c274c5e 100644
--- a/Documentation/filesystems/locking.rst
+++ b/Documentation/filesystems/locking.rst
@@ -61,7 +61,7 @@ inode_operations
prototypes::
- int (*create) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t, bool);
+ int (*create) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t);
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);

Documentation/filesystems/porting.rst

View file
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index d13f0a2..02522fb 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1401,3 +1401,11 @@ as with d_dispose_if_unused() these are not trivial; with this variant
of API it's more explicit, since grabbing ->d_lock is caller-side, but
d_dispose_if_unused() had all the same issues. It's a low-level primitive;
use only if you have no alternative.
+
+---
+
+**mandatory**
+
+The .create inode_operation no longer receives the 'excl' arg. It must
+always assume the file does not already exist. If the filesystem needs
+to be involved in non-exclusive create, it should provide atomic_open.

Documentation/filesystems/vfs.rst

View file
diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst
index 7c75314..651b83b 100644
--- a/Documentation/filesystems/vfs.rst
+++ b/Documentation/filesystems/vfs.rst
@@ -415,7 +415,7 @@ As of kernel 2.6.22, the following members are defined:
.. code-block:: c
struct inode_operations {
- int (*create) (struct mnt_idmap *, struct inode *,struct dentry *, umode_t, bool);
+ int (*create) (struct mnt_idmap *, struct inode *,struct dentry *, umode_t);
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);

fs/9p/vfs_inode.c

View file
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 5783d03..e47b90e 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -645,7 +645,6 @@ error:
* @dir: The parent directory
* @dentry: The name of file to be created
* @mode: The UNIX file mode to set
- * @excl: True if the file must not yet exist
*
* open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called
* for mknod(2).
@@ -654,7 +653,7 @@ error:
static int
v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
u32 perm = unixmode2p9mode(v9ses, mode);

fs/9p/vfs_inode_dotl.c

View file
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index f7396d2..d17c3b6 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -213,12 +213,11 @@ int v9fs_open_to_dotl_flags(int flags)
* @dir: directory inode that is being created
* @dentry: dentry that is being deleted
* @omode: create permissions
- * @excl: True if the file must not yet exist
*
*/
static int
v9fs_vfs_create_dotl(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t omode, bool excl)
+ struct dentry *dentry, umode_t omode)
{
return v9fs_vfs_mknod_dotl(idmap, dir, dentry, omode, 0);
}

fs/affs/affs.h

View file
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index 44a3f69..d6b3393 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -169,7 +169,7 @@ extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int l
extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);
extern int affs_unlink(struct inode *dir, struct dentry *dentry);
extern int affs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool);
+ struct dentry *dentry, umode_t mode);
extern struct dentry *affs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode);
extern int affs_rmdir(struct inode *dir, struct dentry *dentry);

fs/affs/namei.c

View file
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index c3c6532..b000108 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -243,7 +243,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
int
affs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct super_block *sb = dir->i_sb;
struct inode *inode;

fs/afs/dir.c

View file
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 6df56fe..6401fbd 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -34,7 +34,7 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nl
u64 ino, u32 uniquifier);
#define AFS_LOOKUP ((filldir_t)0x137UL)
static int afs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl);
+ struct dentry *dentry, umode_t mode);
static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode);
static int afs_rmdir(struct inode *dir, struct dentry *dentry);
@@ -1633,7 +1633,7 @@ static const struct afs_operation_ops afs_create_operation = {
* create a regular file on an AFS filesystem
*/
static int afs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct afs_operation *op;
struct afs_vnode *dvnode = AFS_FS_I(dir);

fs/bad_inode.c

View file
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index acf8613..486c40f 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -29,7 +29,7 @@ static const struct file_operations bad_file_ops =
static int bad_inode_create(struct mnt_idmap *idmap,
struct inode *dir, struct dentry *dentry,
- umode_t mode, bool excl)
+ umode_t mode)
{
return -EIO;
}

fs/bfs/dir.c

View file
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 5b40ab0..4c3b4db 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -83,7 +83,7 @@ const struct file_operations bfs_dir_operations = {
};
static int bfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
int err;
struct inode *inode;

fs/btrfs/inode.c

View file
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 2534cd9..910c062 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7007,7 +7007,7 @@ static int btrfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
}
static int btrfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct inode *inode;

fs/ceph/dir.c

View file
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index ef9e92e..cee7057 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -983,7 +983,7 @@ out:
}
static int ceph_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
return ceph_mknod(idmap, dir, dentry, mode, 0);
}

fs/coda/dir.c

View file
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 835eb7f..ea710a5 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -134,7 +134,7 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *de, umode_t mode, bool excl)
+ struct dentry *de, umode_t mode)
{
int error;
const char *name=de->d_name.name;

fs/ecryptfs/inode.c

View file
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 7aaf191..525297c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -268,7 +268,7 @@ out:
static int
ecryptfs_create(struct mnt_idmap *idmap,
struct inode *directory_inode, struct dentry *ecryptfs_dentry,
- umode_t mode, bool excl)
+ umode_t mode)
{
struct inode *ecryptfs_inode;
int rc;

fs/efivarfs/inode.c

View file
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
index 95dcad8..f0d0095 100644
--- a/fs/efivarfs/inode.c
+++ b/fs/efivarfs/inode.c
@@ -75,7 +75,7 @@ static bool efivarfs_valid_name(const char *str, int len)
}
static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct inode *inode = NULL;
struct efivar_entry *var;

fs/exfat/namei.c

View file
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index b7d5e44..cd9c9ec 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -538,7 +538,7 @@ out:
}
static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct super_block *sb = dir->i_sb;
struct inode *inode;

fs/ext2/namei.c

View file
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 0d09d22..742a78e 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -99,7 +99,7 @@ struct dentry *ext2_get_parent(struct dentry *child)
*/
static int ext2_create (struct mnt_idmap * idmap,
struct inode * dir, struct dentry * dentry,
- umode_t mode, bool excl)
+ umode_t mode)
{
struct inode *inode;
int err;

fs/ext4/namei.c

View file
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index cc49ae0..c3de64d 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2811,7 +2811,7 @@ static int ext4_add_nondir(handle_t *handle,
* with d_instantiate().
*/
static int ext4_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
handle_t *handle;
struct inode *inode;

fs/f2fs/namei.c

View file
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index cac03b8..648681c 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -366,7 +366,7 @@ fail_drop:
}
static int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct f2fs_lock_context lc;

fs/fat/namei_msdos.c

View file
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index c93e05d..ee6824c 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -265,7 +265,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
/***** Create a file */
static int msdos_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct super_block *sb = dir->i_sb;
struct inode *inode = NULL;

fs/fat/namei_vfat.c

View file
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index e909447..139d3ef 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -755,7 +755,7 @@ error:
}
static int vfat_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct super_block *sb = dir->i_sb;
struct inode *inode;

fs/fuse/dir.c

View file
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 0e2a103..0efb314 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1084,7 +1084,7 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir,
}
static int fuse_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *entry, umode_t mode, bool excl)
+ struct dentry *entry, umode_t mode)
{
return fuse_mknod(idmap, dir, entry, mode, 0);
}

fs/gfs2/inode.c

View file
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8a77794..17bfa28 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -963,15 +963,14 @@ fail:
* @dir: The directory in which to create the file
* @dentry: The dentry of the new file
* @mode: The mode of the new file
- * @excl: Force fail if inode exists
*
* Returns: errno
*/
static int gfs2_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
- return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl);
+ return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, 1);
}
/**

fs/hfs/dir.c

View file
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index e13450b..93edc5a 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -184,7 +184,7 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
* the directory and the name (and its length) of the new file.
*/
static int hfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct inode *inode;
int res;

fs/hfsplus/dir.c

View file
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 8bf6c7c..f0aae2c 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -562,7 +562,7 @@ out:
}
static int hfsplus_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode, 0);
}

fs/hostfs/hostfs_kern.c

View file
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index abe86d7..7add056 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -593,7 +593,7 @@ static struct inode *hostfs_iget(struct super_block *sb, char *name)
}
static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct inode *inode;
char *name;

fs/hpfs/namei.c

View file
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 353e13a..809113d 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -129,7 +129,7 @@ bail:
}
static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len;

fs/hugetlbfs/inode.c

View file
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 216e1a0..16d8437 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -979,7 +979,7 @@ static struct dentry *hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir
static int hugetlbfs_create(struct mnt_idmap *idmap,
struct inode *dir, struct dentry *dentry,
- umode_t mode, bool excl)
+ umode_t mode)
{
return hugetlbfs_mknod(idmap, dir, dentry, mode | S_IFREG, 0);
}

fs/jffs2/dir.c

View file
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c4088c3..3d4695b 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -26,7 +26,7 @@
static int jffs2_readdir (struct file *, struct dir_context *);
static int jffs2_create (struct mnt_idmap *, struct inode *,
- struct dentry *, umode_t, bool);
+ struct dentry *, umode_t);
static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
unsigned int);
static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
@@ -163,7 +163,7 @@ static int jffs2_readdir(struct file *file, struct dir_context *ctx)
static int jffs2_create(struct mnt_idmap *idmap, struct inode *dir_i,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
struct jffs2_raw_inode *ri;
struct jffs2_inode_info *f, *dir_f;

fs/jfs/namei.c

View file
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 442d626..2cf4e28 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -61,7 +61,7 @@ static inline void free_ea_wmap(struct inode *inode)
*
*/
static int jfs_create(struct mnt_idmap *idmap, struct inode *dip,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
int rc = 0;
tid_t tid; /* transaction id */

fs/minix/namei.c

View file
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 263e4ba..79e591b 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -64,7 +64,7 @@ static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
}
static int minix_create(struct mnt_idmap *idmap, struct inode *dir,
- struct dentry *dentry, umode_t mode, bool excl)
+ struct dentry *dentry, umode_t mode)
{
return minix_mknod(&nop_mnt_idmap, dir, dentry, mode, 0);
}

fs/namei.c

View file
diff --git a/fs/namei.c b/fs/namei.c
index 19ce43c..9c34304 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4199,7 +4199,7 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode,
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, di);
if (error)
return error;
- error = dir->i_op->create(idmap, dir, dentry, mode, true);
+ error = dir->i_op->create(idmap, dir, dentry, mode);
if (!error)
fsnotify_create(dir, dentry);
return error;
@@ -4336,50 +4336,83 @@ static int may_o_create(struct mnt_idmap *idmap,
return security_inode_create(dir->dentry->d_inode, dentry, mode);
}
-/*
- * Attempt to atomically look up, create and open a file from a negative
- * dentry.
- *
- * Returns 0 if successful. The file will have been created and attached to
- * @file by the filesystem calling finish_open().
- *
- * If the file was looked up only or didn't need creating, FMODE_OPENED won't
- * be set. The caller will need to perform the open themselves. @path will
- * have been updated to point to the new dentry. This may be negative.
- *
- * Returns an error code otherwise.
+/**
+ * atomic_open() - atomically look up, create and open a file
+ * @path: parent directory path
+ * @dentry: child to ->atomic_open()
+ * @file: file to attach child to
+ * @open_flag: open flags
+ * @mode: create mode
+ * @create_error: return value from may_o_create()
+ *
+ * Attempt to look up, create and open @dentry, which must be negative, in a
+ * single call into the filesystem.
+ *
+ * If a non-error dentry is returned then: when FMODE_OPENED is set,
+ * the file will have been attached to @file by the filesystem calling
+ * finish_open(). If FMODE_OPENED isn't set, the filesystem instead called
+ * finish_no_open() and the caller will need to perform the open themselves.
+ *
+ * FMODE_CREATED is set when the call to ->atomic_open() actually created
+ * the file.
+ *
+ * Returns: the opened or looked-up dentry, or ERR_PTR() on failure. The
+ * reference to @dentry is consumed in either case.
*/
static struct dentry *atomic_open(const struct path *path, struct dentry *dentry,
struct file *file,
- int open_flag, umode_t mode)
+ int open_flag, umode_t mode, int create_error)
{
struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
- struct inode *dir = path->dentry->d_inode;
+ struct inode *dir_inode = path->dentry->d_inode;
int error;
file->__f_path.dentry = DENTRY_NOT_SET;
file->__f_path.mnt = path->mnt;
- error = dir->i_op->atomic_open(dir, dentry, file,
+ error = dir_inode->i_op->atomic_open(dir_inode, dentry, file,
open_to_namei_flags(open_flag), mode);
d_lookup_done(dentry);
+
if (!error) {
if (file->f_mode & FMODE_OPENED) {
- if (unlikely(dentry != file->f_path.dentry)) {
+ /* finish_open() called */
+ struct dentry *opened = file->f_path.dentry;
+
+ if (unlikely(opened != dentry)) {
dput(dentry);
- dentry = dget(file->f_path.dentry);
+ dentry = dget(opened);
}
- } else if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
- error = -EIO;
- } else {
- if (file->f_path.dentry) {
+ } else if (likely(file->f_path.dentry != DENTRY_NOT_SET)) {
+ /* finish_no_open() called */
+ struct dentry *replaced = file->f_path.dentry;
+
+ if (replaced) {
dput(dentry);
- dentry = file->f_path.dentry;
+ dentry = replaced;
}
if (unlikely(d_is_negative(dentry)))
error = -ENOENT;
+ } else {
+ const char *fsname = dentry->d_sb->s_type->name;
+
+ WARN(1, "%s: ->atomic_open() left file->f_path.dentry unset!\n",
+ fsname);
+ error = -EIO;
}
}
+
if (error) {
+ if (unlikely(create_error) && error == -ENOENT) {
+ /*
+ * Should have done a create, but errored before.
+ * Some filesystems return -ENOENT directly instead of
+ * calling finish_no_open() with a negative dentry;
+ * either way it should only mean the child doesn't exist,
+ * so a refused create is safe to record here.
+ */
+ audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE);
+ error = create_error;
+ }
dput(dentry);
dentry = ERR_PTR(error);
}
@@ -4389,32 +4422,52 @@ static struct dentry *atomic_open(const struct path *path, struct dentry *dentry
/*
* Look up and maybe create and open the last component.
*
- * Must be called with parent locked (exclusive in O_CREAT case).
+ * Takes the parent inode lock itself, exclusive if O_CREAT was requested and
+ * shared otherwise, and drops it again before returning. The caller must not
+ * hold it.
*
- * Returns 0 on success, that is, if
- * the file was successfully atomically created (if necessary) and opened, or
- * the file was not completely opened at this time, though lookups and
- * creations were performed.
- * These case are distinguished by presence of FMODE_OPENED on file->f_mode.
- * In the latter case dentry returned in @path might be negative if O_CREAT
- * hadn't been specified.
+ * On success returns the dentry of the last component. If FMODE_OPENED is set
+ * on file->f_mode the file was also opened and attached to @file; otherwise
+ * only lookup and creation were performed and the caller has to open it. In
+ * the latter case the dentry may be negative if O_CREAT hadn't been specified.
*
- * An error code is returned on failure.
+ * Returns ERR_PTR() on failure.
*/
static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
- const struct open_flags *op,
- bool got_write, struct delegated_inode *delegated_inode)
+ const struct open_flags *op)
{
+ struct delegated_inode delegated_inode = { };
struct mnt_idmap *idmap;
struct dentry *dir = nd->path.dentry;
struct inode *dir_inode = dir->d_inode;
- int open_flag = op->open_flag;
+ int open_flag;

This diff is incomplete. Download the complete patch.

fs/nfs/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/nfs/internal.h

View file

This diff is incomplete. Download the complete patch.

fs/nilfs2/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/ntfs/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/ntfs3/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/ocfs2/dlmfs/dlmfs.c

View file

This diff is incomplete. Download the complete patch.

fs/ocfs2/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/omfs/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/orangefs/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/ramfs/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/smb/client/cifsfs.h

View file

This diff is incomplete. Download the complete patch.

fs/smb/client/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/ubifs/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/udf/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/ufs/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/vboxsf/dir.c

View file

This diff is incomplete. Download the complete patch.

fs/xfs/xfs_iops.c

View file

This diff is incomplete. Download the complete patch.

include/linux/fs.h

View file

This diff is incomplete. Download the complete patch.

include/linux/namei.h

View file

This diff is incomplete. Download the complete patch.

ipc/mqueue.c

View file

This diff is incomplete. Download the complete patch.

mm/shmem.c

View file

This diff is incomplete. Download the complete patch.