Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 621e155a authored by Nick Piggin's avatar Nick Piggin
Browse files

fs: change d_compare for rcu-walk



Change d_compare so it may be called from lock-free RCU lookups. This
does put significant restrictions on what may be done from the callback,
however there don't seem to have been any problems with in-tree fses.
If some strange use case pops up that _really_ cannot cope with the
rcu-walk rules, we can just add new rcu-unaware callbacks, which would
cause name lookup to drop out of rcu-walk mode.

For in-tree filesystems, this is just a mechanical change.

Signed-off-by: default avatarNick Piggin <npiggin@kernel.dk>
parent fb2d5b86
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -11,7 +11,9 @@ be able to use diff(1).
prototypes:
prototypes:
	int (*d_revalidate)(struct dentry *, int);
	int (*d_revalidate)(struct dentry *, int);
	int (*d_hash) (struct dentry *, struct qstr *);
	int (*d_hash) (struct dentry *, struct qstr *);
	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
	int (*d_compare)(const struct dentry *, const struct inode *,
			const struct dentry *, const struct inode *,
			unsigned int, const char *, const struct qstr *);
	int (*d_delete)(struct dentry *);
	int (*d_delete)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	void (*d_iput)(struct dentry *, struct inode *);
+7 −0
Original line number Original line Diff line number Diff line
@@ -326,3 +326,10 @@ to it.
unreferenced dentries, and is now only called when the dentry refcount goes to
unreferenced dentries, and is now only called when the dentry refcount goes to
0. Even on 0 refcount transition, it must be able to tolerate being called 0,
0. Even on 0 refcount transition, it must be able to tolerate being called 0,
1, or more times (eg. constant, idempotent).
1, or more times (eg. constant, idempotent).

---
[mandatory]

	.d_compare() calling convention and locking rules are significantly
changed. Read updated documentation in Documentation/filesystems/vfs.txt (and
look at examples of other filesystems) for guidance.
+23 −3
Original line number Original line Diff line number Diff line
@@ -848,7 +848,9 @@ defined:
struct dentry_operations {
struct dentry_operations {
	int (*d_revalidate)(struct dentry *, struct nameidata *);
	int (*d_revalidate)(struct dentry *, struct nameidata *);
	int (*d_hash)(struct dentry *, struct qstr *);
	int (*d_hash)(struct dentry *, struct qstr *);
	int (*d_compare)(struct dentry *, struct qstr *, struct qstr *);
	int (*d_compare)(const struct dentry *, const struct inode *,
			const struct dentry *, const struct inode *,
			unsigned int, const char *, const struct qstr *);
	int (*d_delete)(const struct dentry *);
	int (*d_delete)(const struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	void (*d_iput)(struct dentry *, struct inode *);
@@ -860,9 +862,27 @@ struct dentry_operations {
	dcache. Most filesystems leave this as NULL, because all their
	dcache. Most filesystems leave this as NULL, because all their
	dentries in the dcache are valid
	dentries in the dcache are valid


  d_hash: called when the VFS adds a dentry to the hash table
  d_hash: called when the VFS adds a dentry to the hash table. The first
	dentry passed to d_hash is the parent directory that the name is
	to be hashed into.


  d_compare: called when a dentry should be compared with another
  d_compare: called to compare a dentry name with a given name. The first
	dentry is the parent of the dentry to be compared, the second is
	the parent's inode, then the dentry and inode (may be NULL) of the
	child dentry. len and name string are properties of the dentry to be
	compared. qstr is the name to compare it with.

	Must be constant and idempotent, and should not take locks if
	possible, and should not or store into the dentry or inodes.
	Should not dereference pointers outside the dentry or inodes without
	lots of care (eg.  d_parent, d_inode, d_name should not be used).

	However, our vfsmount is pinned, and RCU held, so the dentries and
	inodes won't disappear, neither will our sb or filesystem module.
	->i_sb and ->d_sb may be used.

	It is a tricky calling convention because it needs to be called under
	"rcu-walk", ie. without any locks or references on things.


  d_delete: called when the last reference to a dentry is dropped and the
  d_delete: called when the last reference to a dentry is dropped and the
	dcache is deciding whether or not to cache it. Return 1 to delete
	dcache is deciding whether or not to cache it. Return 1 to delete
+11 −5
Original line number Original line Diff line number Diff line
@@ -275,7 +275,10 @@ smb_dir_open(struct inode *dir, struct file *file)
 */
 */
static int smb_lookup_validate(struct dentry *, struct nameidata *);
static int smb_lookup_validate(struct dentry *, struct nameidata *);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static int smb_compare_dentry(const struct dentry *,
		const struct inode *,
		const struct dentry *, const struct inode *,
		unsigned int, const char *, const struct qstr *);
static int smb_delete_dentry(const struct dentry *);
static int smb_delete_dentry(const struct dentry *);


static const struct dentry_operations smbfs_dentry_operations =
static const struct dentry_operations smbfs_dentry_operations =
@@ -347,14 +350,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this)
}
}


static int
static int
smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
smb_compare_dentry(const struct dentry *parent,
		const struct inode *pinode,
		const struct dentry *dentry, const struct inode *inode,
		unsigned int len, const char *str, const struct qstr *name)
{
{
	int i, result = 1;
	int i, result = 1;


	if (a->len != b->len)
	if (len != name->len)
		goto out;
		goto out;
	for (i=0; i < a->len; i++) {
	for (i=0; i < len; i++) {
		if (tolower(a->name[i]) != tolower(b->name[i]))
		if (tolower(str[i]) != tolower(name->name[i]))
			goto out;
			goto out;
	}
	}
	result = 0;
	result = 0;
+5 −3
Original line number Original line Diff line number Diff line
@@ -237,17 +237,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr)
 * requirements of the underlying filesystem.
 * requirements of the underlying filesystem.
 */
 */
static int
static int
adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name)
adfs_compare(const struct dentry *parent, const struct inode *pinode,
		const struct dentry *dentry, const struct inode *inode,
		unsigned int len, const char *str, const struct qstr *name)
{
{
	int i;
	int i;


	if (entry->len != name->len)
	if (len != name->len)
		return 1;
		return 1;


	for (i = 0; i < name->len; i++) {
	for (i = 0; i < name->len; i++) {
		char a, b;
		char a, b;


		a = entry->name[i];
		a = str[i];
		b = name->name[i];
		b = name->name[i];


		if (a >= 'A' && a <= 'Z')
		if (a >= 'A' && a <= 'Z')
Loading