lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250206054504.2950516-11-neilb@suse.de>
Date: Thu,  6 Feb 2025 16:42:47 +1100
From: NeilBrown <neilb@...e.de>
To: Alexander Viro <viro@...iv.linux.org.uk>,
	Christian Brauner <brauner@...nel.org>,
	Jan Kara <jack@...e.cz>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	Jeff Layton <jlayton@...nel.org>,
	Dave Chinner <david@...morbit.com>
Cc: linux-fsdevel@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: [PATCH 10/19] VFS: introduce inode flags to report locking needs for directory ops

If a filesystem supports _async ops for some directory ops we can take a
"shared" lock on i_rwsem otherwise we must take an "exclusive" lock.  As
the filesystem may support some async ops but not others we need to
easily determine which.

With this patch we group the ops into 4 groups that are likely be
supported together:

CREATE: create, link, mkdir, mknod
REMOVE: rmdir, unlink
RENAME: rename
OPEN: atomic_open, create

and set S_ASYNC_XXX for each when the inode in initialised.

We also add a LOOKUP_REMOVE intent flag which will be used by locking
interfaces to help know which group is being used.

Signed-off-by: NeilBrown <neilb@...e.de>
---
 fs/dcache.c           | 24 ++++++++++++++++++++++++
 include/linux/fs.h    |  5 +++++
 include/linux/namei.h |  5 +++--
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index e49607d00d2d..37c0f655166d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -384,6 +384,27 @@ static inline void __d_set_inode_and_type(struct dentry *dentry,
 	smp_store_release(&dentry->d_flags, flags);
 }
 
+static void set_inode_flags(struct inode *inode)
+{
+	const struct inode_operations *i_op = inode->i_op;
+
+	lockdep_assert_held(&inode->i_lock);
+	if ((i_op->create_async || !i_op->create) &&
+	    (i_op->link_async || !i_op->link) &&
+	    (i_op->symlink_async || !i_op->symlink) &&
+	    (i_op->mkdir_async || !i_op->mkdir) &&
+	    (i_op->mknod_async || !i_op->mknod))
+		inode->i_flags |= S_ASYNC_CREATE;
+	if ((i_op->unlink_async || !i_op->unlink) &&
+	    (i_op->mkdir_async || !i_op->mkdir))
+		inode->i_flags |= S_ASYNC_REMOVE;
+	if (i_op->rename_async)
+		inode->i_flags |= S_ASYNC_RENAME;
+	if (i_op->atomic_open_async ||
+	    (!i_op->atomic_open && i_op->create_async))
+		inode->i_flags |= S_ASYNC_OPEN;
+}
+
 static inline void __d_clear_type_and_inode(struct dentry *dentry)
 {
 	unsigned flags = READ_ONCE(dentry->d_flags);
@@ -1893,6 +1914,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 	raw_write_seqcount_begin(&dentry->d_seq);
 	__d_set_inode_and_type(dentry, inode, add_flags);
 	raw_write_seqcount_end(&dentry->d_seq);
+	set_inode_flags(inode);
 	fsnotify_update_flags(dentry);
 	spin_unlock(&dentry->d_lock);
 }
@@ -1999,6 +2021,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, bool disconnected)
 
 		spin_lock(&new->d_lock);
 		__d_set_inode_and_type(new, inode, add_flags);
+		set_inode_flags(inode);
 		hlist_add_head(&new->d_u.d_alias, &inode->i_dentry);
 		if (!disconnected) {
 			hlist_bl_lock(&sb->s_roots);
@@ -2701,6 +2724,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
 		raw_write_seqcount_begin(&dentry->d_seq);
 		__d_set_inode_and_type(dentry, inode, add_flags);
 		raw_write_seqcount_end(&dentry->d_seq);
+		set_inode_flags(inode);
 		fsnotify_update_flags(dentry);
 	}
 	__d_rehash(dentry);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e414400c2487..9a9282fef347 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2361,6 +2361,11 @@ struct super_operations {
 #define S_VERITY	(1 << 16) /* Verity file (using fs/verity/) */
 #define S_KERNEL_FILE	(1 << 17) /* File is in use by the kernel (eg. fs/cachefiles) */
 
+#define S_ASYNC_CREATE	BIT(18)	/* create, link, symlink, mkdir, mknod all _async */
+#define S_ASYNC_REMOVE	BIT(19)	/* unlink, mkdir both _async */
+#define S_ASYNC_RENAME	BIT(20) /* rename_async supported */
+#define S_ASYNC_OPEN	BIT(21) /* atomic_open_async or create_async supported */
+
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
  * flags just means all the inodes inherit those flags by default. It might be
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 76c587a5ec3a..72e351640406 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -40,10 +40,11 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
 #define LOOKUP_CREATE		BIT(17)	/* ... in object creation */
 #define LOOKUP_EXCL		BIT(18)	/* ... in target must not exist */
 #define LOOKUP_RENAME_TARGET	BIT(19)	/* ... in destination of rename() */
+#define LOOKUP_REMOVE		BIT(20)	/* ... in target of object removal */
 
 #define LOOKUP_INTENT_FLAGS	(LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_EXCL |	\
-				 LOOKUP_RENAME_TARGET)
-/* 4 spare bits for intent */
+				 LOOKUP_RENAME_TARGET | LOOKUP_REMOVE)
+/* 3 spare bits for intent */
 
 /* Scoping flags for lookup. */
 #define LOOKUP_NO_SYMLINKS	BIT(24) /* No symlink crossing. */
-- 
2.47.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ