aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhi Zhang <zhang.david2011@gmail.com>2018-01-24 08:24:33 -0500
committerIlya Dryomov <idryomov@gmail.com>2018-01-29 12:36:12 -0500
commite30ee58121e34831b9665934d70dbc72ab0fe2fb (patch)
tree23b4eb7cb77f82d5326efbe3af44d152aa75a953
parent0f439c746c8cb370ce3ae1668182b18a5cb12b14 (diff)
ceph: try to allocate enough memory for reserved caps
ceph_reserve_caps() may not reserve enough caps under high memory pressure, but it saved the needed caps number that expected to be reserved. When getting caps, crash would happen due to number mismatch. Now we will try to trim more caps when failing to allocate memory for caps need to be reserved, then try again. If still failing to allocate memory, return -ENOMEM. Signed-off-by: Zhi Zhang <zhang.david2011@gmail.com> Reviewed-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r--fs/ceph/caps.c61
-rw-r--r--fs/ceph/mds_client.c24
-rw-r--r--fs/ceph/mds_client.h3
-rw-r--r--fs/ceph/super.h2
4 files changed, 74 insertions, 16 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 1726ddcf5e34..8e66fb0e743d 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -154,13 +154,19 @@ void ceph_adjust_min_caps(struct ceph_mds_client *mdsc, int delta)
154 spin_unlock(&mdsc->caps_list_lock); 154 spin_unlock(&mdsc->caps_list_lock);
155} 155}
156 156
157void ceph_reserve_caps(struct ceph_mds_client *mdsc, 157/*
158 * Called under mdsc->mutex.
159 */
160int ceph_reserve_caps(struct ceph_mds_client *mdsc,
158 struct ceph_cap_reservation *ctx, int need) 161 struct ceph_cap_reservation *ctx, int need)
159{ 162{
160 int i; 163 int i, j;
161 struct ceph_cap *cap; 164 struct ceph_cap *cap;
162 int have; 165 int have;
163 int alloc = 0; 166 int alloc = 0;
167 int max_caps;
168 bool trimmed = false;
169 struct ceph_mds_session *s;
164 LIST_HEAD(newcaps); 170 LIST_HEAD(newcaps);
165 171
166 dout("reserve caps ctx=%p need=%d\n", ctx, need); 172 dout("reserve caps ctx=%p need=%d\n", ctx, need);
@@ -179,16 +185,37 @@ void ceph_reserve_caps(struct ceph_mds_client *mdsc,
179 spin_unlock(&mdsc->caps_list_lock); 185 spin_unlock(&mdsc->caps_list_lock);
180 186
181 for (i = have; i < need; i++) { 187 for (i = have; i < need; i++) {
188retry:
182 cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); 189 cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
183 if (!cap) 190 if (!cap) {
184 break; 191 if (!trimmed) {
192 for (j = 0; j < mdsc->max_sessions; j++) {
193 s = __ceph_lookup_mds_session(mdsc, j);
194 if (!s)
195 continue;
196 mutex_unlock(&mdsc->mutex);
197
198 mutex_lock(&s->s_mutex);
199 max_caps = s->s_nr_caps - (need - i);
200 ceph_trim_caps(mdsc, s, max_caps);
201 mutex_unlock(&s->s_mutex);
202
203 ceph_put_mds_session(s);
204 mutex_lock(&mdsc->mutex);
205 }
206 trimmed = true;
207 goto retry;
208 } else {
209 pr_warn("reserve caps ctx=%p ENOMEM "
210 "need=%d got=%d\n",
211 ctx, need, have + alloc);
212 goto out_nomem;
213 }
214 }
185 list_add(&cap->caps_item, &newcaps); 215 list_add(&cap->caps_item, &newcaps);
186 alloc++; 216 alloc++;
187 } 217 }
188 /* we didn't manage to reserve as much as we needed */ 218 BUG_ON(have + alloc != need);
189 if (have + alloc != need)
190 pr_warn("reserve caps ctx=%p ENOMEM need=%d got=%d\n",
191 ctx, need, have + alloc);
192 219
193 spin_lock(&mdsc->caps_list_lock); 220 spin_lock(&mdsc->caps_list_lock);
194 mdsc->caps_total_count += alloc; 221 mdsc->caps_total_count += alloc;
@@ -204,6 +231,24 @@ void ceph_reserve_caps(struct ceph_mds_client *mdsc,
204 dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n", 231 dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n",
205 ctx, mdsc->caps_total_count, mdsc->caps_use_count, 232 ctx, mdsc->caps_total_count, mdsc->caps_use_count,
206 mdsc->caps_reserve_count, mdsc->caps_avail_count); 233 mdsc->caps_reserve_count, mdsc->caps_avail_count);
234 return 0;
235
236out_nomem:
237 while (!list_empty(&newcaps)) {
238 cap = list_first_entry(&newcaps,
239 struct ceph_cap, caps_item);
240 list_del(&cap->caps_item);
241 kmem_cache_free(ceph_cap_cachep, cap);
242 }
243
244 spin_lock(&mdsc->caps_list_lock);
245 mdsc->caps_avail_count += have;
246 mdsc->caps_reserve_count -= have;
247 BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count +
248 mdsc->caps_reserve_count +
249 mdsc->caps_avail_count);
250 spin_unlock(&mdsc->caps_list_lock);
251 return -ENOMEM;
207} 252}
208 253
209int ceph_unreserve_caps(struct ceph_mds_client *mdsc, 254int ceph_unreserve_caps(struct ceph_mds_client *mdsc,
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 251dc44d84a0..2e8f90f96540 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -604,10 +604,20 @@ static void __register_request(struct ceph_mds_client *mdsc,
604 struct ceph_mds_request *req, 604 struct ceph_mds_request *req,
605 struct inode *dir) 605 struct inode *dir)
606{ 606{
607 int ret = 0;
608
607 req->r_tid = ++mdsc->last_tid; 609 req->r_tid = ++mdsc->last_tid;
608 if (req->r_num_caps) 610 if (req->r_num_caps) {
609 ceph_reserve_caps(mdsc, &req->r_caps_reservation, 611 ret = ceph_reserve_caps(mdsc, &req->r_caps_reservation,
610 req->r_num_caps); 612 req->r_num_caps);
613 if (ret < 0) {
614 pr_err("__register_request %p "
615 "failed to reserve caps: %d\n", req, ret);
616 /* set req->r_err to fail early from __do_request */
617 req->r_err = ret;
618 return;
619 }
620 }
611 dout("__register_request %p tid %lld\n", req, req->r_tid); 621 dout("__register_request %p tid %lld\n", req, req->r_tid);
612 ceph_mdsc_get_request(req); 622 ceph_mdsc_get_request(req);
613 insert_request(&mdsc->request_tree, req); 623 insert_request(&mdsc->request_tree, req);
@@ -1545,9 +1555,9 @@ out:
1545/* 1555/*
1546 * Trim session cap count down to some max number. 1556 * Trim session cap count down to some max number.
1547 */ 1557 */
1548static int trim_caps(struct ceph_mds_client *mdsc, 1558int ceph_trim_caps(struct ceph_mds_client *mdsc,
1549 struct ceph_mds_session *session, 1559 struct ceph_mds_session *session,
1550 int max_caps) 1560 int max_caps)
1551{ 1561{
1552 int trim_caps = session->s_nr_caps - max_caps; 1562 int trim_caps = session->s_nr_caps - max_caps;
1553 1563
@@ -2776,7 +2786,7 @@ static void handle_session(struct ceph_mds_session *session,
2776 break; 2786 break;
2777 2787
2778 case CEPH_SESSION_RECALL_STATE: 2788 case CEPH_SESSION_RECALL_STATE:
2779 trim_caps(mdsc, session, le32_to_cpu(h->max_caps)); 2789 ceph_trim_caps(mdsc, session, le32_to_cpu(h->max_caps));
2780 break; 2790 break;
2781 2791
2782 case CEPH_SESSION_FLUSHMSG: 2792 case CEPH_SESSION_FLUSHMSG:
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 837ac4b087a0..71e3b783ee6f 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -444,4 +444,7 @@ ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target);
444extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc, 444extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc,
445 struct ceph_mds_session *session); 445 struct ceph_mds_session *session);
446 446
447extern int ceph_trim_caps(struct ceph_mds_client *mdsc,
448 struct ceph_mds_session *session,
449 int max_caps);
447#endif 450#endif
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 601100da738f..21b2e5b004eb 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -649,7 +649,7 @@ extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check);
649extern void ceph_caps_init(struct ceph_mds_client *mdsc); 649extern void ceph_caps_init(struct ceph_mds_client *mdsc);
650extern void ceph_caps_finalize(struct ceph_mds_client *mdsc); 650extern void ceph_caps_finalize(struct ceph_mds_client *mdsc);
651extern void ceph_adjust_min_caps(struct ceph_mds_client *mdsc, int delta); 651extern void ceph_adjust_min_caps(struct ceph_mds_client *mdsc, int delta);
652extern void ceph_reserve_caps(struct ceph_mds_client *mdsc, 652extern int ceph_reserve_caps(struct ceph_mds_client *mdsc,
653 struct ceph_cap_reservation *ctx, int need); 653 struct ceph_cap_reservation *ctx, int need);
654extern int ceph_unreserve_caps(struct ceph_mds_client *mdsc, 654extern int ceph_unreserve_caps(struct ceph_mds_client *mdsc,
655 struct ceph_cap_reservation *ctx); 655 struct ceph_cap_reservation *ctx);