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

Commit 1b71fe2e authored by Al Viro's avatar Al Viro
Browse files

ceph analog of cifs build_path_from_dentry() race fix



... unfortunately, cifs bug got copied.  Fix is essentially the same.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent dc137bf5
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
	struct dentry *temp;
	char *path;
	int len, pos;
	unsigned seq;

	if (dentry == NULL)
		return ERR_PTR(-EINVAL);

retry:
	len = 0;
	seq = read_seqbegin(&rename_lock);
	rcu_read_lock();
	for (temp = dentry; !IS_ROOT(temp);) {
		struct inode *inode = temp->d_inode;
		if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
@@ -1455,10 +1458,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
			len += 1 + temp->d_name.len;
		temp = temp->d_parent;
		if (temp == NULL) {
			rcu_read_unlock();
			pr_err("build_path corrupt dentry %p\n", dentry);
			return ERR_PTR(-EINVAL);
		}
	}
	rcu_read_unlock();
	if (len)
		len--;  /* no leading '/' */

@@ -1467,9 +1472,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
		return ERR_PTR(-ENOMEM);
	pos = len;
	path[pos] = 0;	/* trailing null */
	rcu_read_lock();
	for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
		struct inode *inode = temp->d_inode;
		struct inode *inode;

		spin_lock(&temp->d_lock);
		inode = temp->d_inode;
		if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
			dout("build_path path+%d: %p SNAPDIR\n",
			     pos, temp);
@@ -1478,21 +1486,26 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
			break;
		} else {
			pos -= temp->d_name.len;
			if (pos < 0)
			if (pos < 0) {
				spin_unlock(&temp->d_lock);
				break;
			}
			strncpy(path + pos, temp->d_name.name,
				temp->d_name.len);
		}
		spin_unlock(&temp->d_lock);
		if (pos)
			path[--pos] = '/';
		temp = temp->d_parent;
		if (temp == NULL) {
			rcu_read_unlock();
			pr_err("build_path corrupt dentry\n");
			kfree(path);
			return ERR_PTR(-EINVAL);
		}
	}
	if (pos != 0) {
	rcu_read_unlock();
	if (pos != 0 || read_seqretry(&rename_lock, seq)) {
		pr_err("build_path did not end path lookup where "
		       "expected, namelen is %d, pos is %d\n", len, pos);
		/* presumably this is only possible if racing with a