ceph: fix use-after-dereference of NULL ci in __ceph_remove_cap()

The NULL check for "ci" in __ceph_remove_cap() was dead code because
ci was dereferenced via &ci->netfs.inode before the check, and
cap->session was dereferenced via session->s_mdsc->fsc->client even
earlier.  On a double-remove, both cap->ci and cap->session are set
to NULL by the first call, so the second call would crash before
ever reaching the guard.

Move ci, session, cl, and inode initializations after the NULL check
so that the early-return actually works.

Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Xiubo Li 2026-07-14 14:20:37 +08:00 committed by Ilya Dryomov
parent af59562a5b
commit a354d7eaa1

View File

@ -1129,18 +1129,21 @@ int ceph_is_any_caps(struct inode *inode)
*/
void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
{
struct ceph_mds_session *session = cap->session;
struct ceph_client *cl = session->s_mdsc->fsc->client;
struct ceph_inode_info *ci = cap->ci;
struct inode *inode = &ci->netfs.inode;
struct ceph_mds_session *session;
struct ceph_client *cl;
struct ceph_inode_info *ci;
struct inode *inode;
struct ceph_mds_client *mdsc;
int removed = 0;
/* 'ci' being NULL means the remove have already occurred */
if (!ci) {
doutc(cl, "inode is NULL\n");
ci = cap->ci;
if (!ci)
return;
}
session = cap->session;
cl = session->s_mdsc->fsc->client;
inode = &ci->netfs.inode;
lockdep_assert_held(&ci->i_ceph_lock);