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

Commit 0689acfa authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-5.4-rc7' of git://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
 "Some late-breaking dentry handling fixes from Al and Jeff, a patch to
  further restrict copy_file_range() to avoid potential data corruption
  from Luis and a fix for !CONFIG_CEPH_FSCACHE kernels.

  Everything but the fscache fix is marked for stable"

* tag 'ceph-for-5.4-rc7' of git://github.com/ceph/ceph-client:
  ceph: return -EINVAL if given fsc mount option on kernel w/o support
  ceph: don't allow copy_file_range when stripe_count != 1
  ceph: don't try to handle hashed dentries in non-O_CREAT atomic_open
  ceph: add missing check in d_revalidate snapdir handling
  ceph: fix RCU case handling in ceph_d_revalidate()
  ceph: fix use-after-free in __ceph_remove_cap()
parents 6737e763 ff29fde8
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -1058,6 +1058,11 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)


	dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
	dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);


	/* remove from inode's cap rbtree, and clear auth cap */
	rb_erase(&cap->ci_node, &ci->i_caps);
	if (ci->i_auth_cap == cap)
		ci->i_auth_cap = NULL;

	/* remove from session list */
	/* remove from session list */
	spin_lock(&session->s_cap_lock);
	spin_lock(&session->s_cap_lock);
	if (session->s_cap_iterator == cap) {
	if (session->s_cap_iterator == cap) {
@@ -1091,11 +1096,6 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)


	spin_unlock(&session->s_cap_lock);
	spin_unlock(&session->s_cap_lock);


	/* remove from inode list */
	rb_erase(&cap->ci_node, &ci->i_caps);
	if (ci->i_auth_cap == cap)
		ci->i_auth_cap = NULL;

	if (removed)
	if (removed)
		ceph_put_cap(mdsc, cap);
		ceph_put_cap(mdsc, cap);


+8 −7
Original line number Original line Diff line number Diff line
@@ -1553,36 +1553,37 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
{
{
	int valid = 0;
	int valid = 0;
	struct dentry *parent;
	struct dentry *parent;
	struct inode *dir;
	struct inode *dir, *inode;


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


	dout("d_revalidate %p '%pd' inode %p offset %lld\n", 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 */
	/* always trust cached snapped dentries, snapdir dentry */
	if (ceph_snap(dir) != CEPH_NOSNAP) {
	if (ceph_snap(dir) != CEPH_NOSNAP) {
		dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
		dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
		     dentry, d_inode(dentry));
		     dentry, inode);
		valid = 1;
		valid = 1;
	} else if (d_really_is_positive(dentry) &&
	} else if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
		   ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
		valid = 1;
		valid = 1;
	} else {
	} else {
		valid = dentry_lease_is_valid(dentry, flags);
		valid = dentry_lease_is_valid(dentry, flags);
		if (valid == -ECHILD)
		if (valid == -ECHILD)
			return valid;
			return valid;
		if (valid || dir_lease_is_valid(dir, dentry)) {
		if (valid || dir_lease_is_valid(dir, dentry)) {
			if (d_really_is_positive(dentry))
			if (inode)
				valid = ceph_is_any_caps(d_inode(dentry));
				valid = ceph_is_any_caps(inode);
			else
			else
				valid = 1;
				valid = 1;
		}
		}
+13 −2
Original line number Original line Diff line number Diff line
@@ -462,6 +462,9 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
		err = ceph_security_init_secctx(dentry, mode, &as_ctx);
		err = ceph_security_init_secctx(dentry, mode, &as_ctx);
		if (err < 0)
		if (err < 0)
			goto out_ctx;
			goto out_ctx;
	} else if (!d_in_lookup(dentry)) {
		/* If it's not being looked up, it's negative */
		return -ENOENT;
	}
	}


	/* do the open */
	/* do the open */
@@ -1956,10 +1959,18 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
	if (ceph_test_mount_opt(src_fsc, NOCOPYFROM))
	if (ceph_test_mount_opt(src_fsc, NOCOPYFROM))
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;


	/*
	 * Striped file layouts require that we copy partial objects, but the
	 * OSD copy-from operation only supports full-object copies.  Limit
	 * this to non-striped file layouts for now.
	 */
	if ((src_ci->i_layout.stripe_unit != dst_ci->i_layout.stripe_unit) ||
	if ((src_ci->i_layout.stripe_unit != dst_ci->i_layout.stripe_unit) ||
	    (src_ci->i_layout.stripe_count != dst_ci->i_layout.stripe_count) ||
	    (src_ci->i_layout.stripe_count != 1) ||
	    (src_ci->i_layout.object_size != dst_ci->i_layout.object_size))
	    (dst_ci->i_layout.stripe_count != 1) ||
	    (src_ci->i_layout.object_size != dst_ci->i_layout.object_size)) {
		dout("Invalid src/dst files layout\n");
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;
	}


	if (len < src_ci->i_layout.object_size)
	if (len < src_ci->i_layout.object_size)
		return -EOPNOTSUPP; /* no remote copy will be done */
		return -EOPNOTSUPP; /* no remote copy will be done */
+1 −0
Original line number Original line Diff line number Diff line
@@ -1434,6 +1434,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
		dout(" final dn %p\n", dn);
		dout(" final dn %p\n", dn);
	} else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
	} else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
		    req->r_op == CEPH_MDS_OP_MKSNAP) &&
		    req->r_op == CEPH_MDS_OP_MKSNAP) &&
	           test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) &&
		   !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
		   !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
		struct inode *dir = req->r_parent;
		struct inode *dir = req->r_parent;


+10 −1
Original line number Original line Diff line number Diff line
@@ -268,6 +268,7 @@ static int parse_fsopt_token(char *c, void *private)
		}
		}
		break;
		break;
	case Opt_fscache_uniq:
	case Opt_fscache_uniq:
#ifdef CONFIG_CEPH_FSCACHE
		kfree(fsopt->fscache_uniq);
		kfree(fsopt->fscache_uniq);
		fsopt->fscache_uniq = kstrndup(argstr[0].from,
		fsopt->fscache_uniq = kstrndup(argstr[0].from,
					       argstr[0].to-argstr[0].from,
					       argstr[0].to-argstr[0].from,
@@ -276,7 +277,10 @@ static int parse_fsopt_token(char *c, void *private)
			return -ENOMEM;
			return -ENOMEM;
		fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
		fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
		break;
		break;
		/* misc */
#else
		pr_err("fscache support is disabled\n");
		return -EINVAL;
#endif
	case Opt_wsize:
	case Opt_wsize:
		if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE)
		if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE)
			return -EINVAL;
			return -EINVAL;
@@ -353,10 +357,15 @@ static int parse_fsopt_token(char *c, void *private)
		fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
		fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
		break;
		break;
	case Opt_fscache:
	case Opt_fscache:
#ifdef CONFIG_CEPH_FSCACHE
		fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
		fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
		kfree(fsopt->fscache_uniq);
		kfree(fsopt->fscache_uniq);
		fsopt->fscache_uniq = NULL;
		fsopt->fscache_uniq = NULL;
		break;
		break;
#else
		pr_err("fscache support is disabled\n");
		return -EINVAL;
#endif
	case Opt_nofscache:
	case Opt_nofscache:
		fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
		fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
		kfree(fsopt->fscache_uniq);
		kfree(fsopt->fscache_uniq);