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

Commit aa8dd816 authored by Al Viro's avatar Al Viro Committed by Ilya Dryomov
Browse files

ceph: fix RCU case handling in ceph_d_revalidate()



For RCU case ->d_revalidate() is called with rcu_read_lock() and
without pinning the dentry passed to it.  Which means that it
can't rely upon ->d_inode remaining stable; that's the reason
for d_inode_rcu(), actually.

Make sure we don't reload ->d_inode there.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent ea60ed6f
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -1553,36 +1553,37 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
{
	int valid = 0;
	struct dentry *parent;
	struct inode *dir;
	struct inode *dir, *inode;

	if (flags & LOOKUP_RCU) {
		parent = READ_ONCE(dentry->d_parent);
		dir = d_inode_rcu(parent);
		if (!dir)
			return -ECHILD;
		inode = d_inode_rcu(dentry);
	} else {
		parent = dget_parent(dentry);
		dir = d_inode(parent);
		inode = d_inode(dentry);
	}

	dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
	     dentry, d_inode(dentry), ceph_dentry(dentry)->offset);
	     dentry, inode, ceph_dentry(dentry)->offset);

	/* always trust cached snapped dentries, snapdir dentry */
	if (ceph_snap(dir) != CEPH_NOSNAP) {
		dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
		     dentry, d_inode(dentry));
		     dentry, inode);
		valid = 1;
	} else if (d_really_is_positive(dentry) &&
		   ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
	} else if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
		valid = 1;
	} else {
		valid = dentry_lease_is_valid(dentry, flags);
		if (valid == -ECHILD)
			return valid;
		if (valid || dir_lease_is_valid(dir, dentry)) {
			if (d_really_is_positive(dentry))
				valid = ceph_is_any_caps(d_inode(dentry));
			if (inode)
				valid = ceph_is_any_caps(inode);
			else
				valid = 1;
		}