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. -----BEGIN PGP SIGNATURE----- iQFHBAABCAAxFiEEydHwtzie9C7TfviiSn/eOAIR84sFAl3FjtQTHGlkcnlvbW92 QGdtYWlsLmNvbQAKCRBKf944AhHziyjfCACbNiRHpTWfuZ1iHXXCpo0tAixOT6i0 9ZlE8yiF6U6iH7uv/MuIeJ+Qeep9+6wwgJYEJKcF0e+Raiob7womDO+yeDx6RYrC bqq6OLjJl8VbfeQWvJTmisGTPpvOsOKxxXIKG6vx1zJaJ69yENilFZ0biis14iTu RRDvtSntc96OhZ3n8IXie2+f9purYeIKhiCZqx9WzYZOk5sb3zGyhqD+Wh5kxkEh QzwwZ/G5RYvMMhL0o13uMZrjqozGTI9Qm09u7+EikIXFFtt+szEdgFd4pQPhsC1D VmpdrvV4ml8JnbkENiZ7tlHCcICQJfgMWNcLVgHvD6808CJ0UP5Cq/jP =34Iz -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
0689acfad3
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue