When caps_avail_count is in a low level, most newly trimmed caps will probably go into ->caps_list and caps_avail_count will be increased. Hence after trimming, should recheck caps_avail_count to effectly reuse newly trimmed caps. Also, when releasing unnecessary caps follow the same rule of ceph_put_cap. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxx> --- Only compile tested. fs/ceph/caps.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 6582c45..ba58422 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -165,6 +165,7 @@ int ceph_reserve_caps(struct ceph_mds_client *mdsc, int have; int alloc = 0; int max_caps; + int more_avail_caps; bool trimmed = false; struct ceph_mds_session *s; LIST_HEAD(newcaps); @@ -204,6 +205,24 @@ int ceph_reserve_caps(struct ceph_mds_client *mdsc, mutex_lock(&mdsc->mutex); } trimmed = true; + + spin_lock(&mdsc->caps_list_lock); + if (mdsc->caps_avail_count) { + if (mdsc->caps_avail_count + have + alloc >= need) + more_avail_caps = need - alloc - have; + else + more_avail_caps = mdsc->caps_avail_count; + + i += more_avail_caps; + have += more_avail_caps; + mdsc->caps_avail_count -= more_avail_caps; + mdsc->caps_reserve_count += more_avail_caps; + } + spin_unlock(&mdsc->caps_list_lock); + + if (i >= need) + break; + goto retry; } else { pr_warn("reserve caps ctx=%p ENOMEM " @@ -234,16 +253,30 @@ int ceph_reserve_caps(struct ceph_mds_client *mdsc, return 0; out_nomem: + + spin_lock(&mdsc->caps_list_lock); + mdsc->caps_avail_count += have; + mdsc->caps_reserve_count -= have; + while (!list_empty(&newcaps)) { cap = list_first_entry(&newcaps, struct ceph_cap, caps_item); list_del(&cap->caps_item); - kmem_cache_free(ceph_cap_cachep, cap); + + /* + * Keep some preallocated caps around (ceph_min_count), to + * avoid lots of free/alloc churn. + */ + if (mdsc->caps_avail_count >= mdsc->caps_reserve_count + + mdsc->caps_min_count) { + kmem_cache_free(ceph_cap_cachep, cap); + } else { + mdsc->caps_avail_count++; + mdsc->caps_total_count++; + list_add(&cap->caps_item, &mdsc->caps_list); + } } - spin_lock(&mdsc->caps_list_lock); - mdsc->caps_avail_count += have; - mdsc->caps_reserve_count -= have; BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + mdsc->caps_reserve_count + mdsc->caps_avail_count); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html