summaryrefslogtreecommitdiffstats
path: root/fs/ceph/caps.c
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 /fs/ceph/caps.c
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>
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r--fs/ceph/caps.c61
1 files changed, 53 insertions, 8 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,