ceph: mark cap remove with RB_CLEAR_NODE() instead of setting ci=NULL

__ceph_remove_cap() erases the ceph_cap object from the RB tree, thus
it seems natural to use RB_CLEAR_NODE() / RB_EMPTY_NODE() for the
removal check.

Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Max Kellermann 2026-07-06 09:38:11 +02:00 committed by Ilya Dryomov
parent 8619a36ff5
commit af05588c97
2 changed files with 19 additions and 4 deletions

View File

@ -1168,8 +1168,11 @@ static void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
cap->session = NULL;
removed = 1;
}
/* protect backpointer with s_cap_lock: see iterate_session_caps */
cap->ci = NULL;
/* protect removal marker with both i_ceph_lock and
s_cap_lock, so either one can be used to check for
removal */
RB_CLEAR_NODE(&cap->ci_node);
/*
* s_cap_reconnect is protected by s_cap_lock. no one changes

View File

@ -203,7 +203,19 @@ struct ceph_fs_client {
*/
struct ceph_cap {
struct ceph_inode_info *ci;
struct rb_node ci_node; /* per-ci cap tree */
/**
* Per-ci cap tree. Protected with
* `ceph_inode_info.i_ceph_lock`.
*
* Clearing this field with RB_CLEAR_NODE() requires holding
* both `ceph_inode_info.i_ceph_lock` and
* `ceph_mds_session->s_cap_lock`. Calling RB_EMPTY_NODE()
* (via ceph_cap_is_removed()) requires holding at least one
* of these.
*/
struct rb_node ci_node;
struct ceph_mds_session *session;
struct list_head session_caps; /* per-session caplist */
u64 cap_id; /* unique cap id (mds provided) */
@ -1289,7 +1301,7 @@ extern void ceph_add_cap(struct inode *inode,
*/
static inline bool ceph_cap_is_removed(const struct ceph_cap *cap)
{
return !cap->ci;
return RB_EMPTY_NODE(&cap->ci_node);
}
extern void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,