1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#define DEBUG_SUBSYSTEM S_FLD
45
46# include <linux/libcfs/libcfs.h>
47# include <linux/module.h>
48# include <linux/jbd.h>
49# include <asm/div64.h>
50
51#include <obd.h>
52#include <obd_class.h>
53#include <lustre_ver.h>
54#include <obd_support.h>
55#include <lprocfs_status.h>
56
57#include <dt_object.h>
58#include <md_object.h>
59#include <lustre_req_layout.h>
60#include <lustre_fld.h>
61#include "fld_internal.h"
62
63
64
65
66struct fld_cache *fld_cache_init(const char *name,
67 int cache_size, int cache_threshold)
68{
69 struct fld_cache *cache;
70 ENTRY;
71
72 LASSERT(name != NULL);
73 LASSERT(cache_threshold < cache_size);
74
75 OBD_ALLOC_PTR(cache);
76 if (cache == NULL)
77 RETURN(ERR_PTR(-ENOMEM));
78
79 INIT_LIST_HEAD(&cache->fci_entries_head);
80 INIT_LIST_HEAD(&cache->fci_lru);
81
82 cache->fci_cache_count = 0;
83 rwlock_init(&cache->fci_lock);
84
85 strlcpy(cache->fci_name, name,
86 sizeof(cache->fci_name));
87
88 cache->fci_cache_size = cache_size;
89 cache->fci_threshold = cache_threshold;
90
91
92 memset(&cache->fci_stat, 0, sizeof(cache->fci_stat));
93
94 CDEBUG(D_INFO, "%s: FLD cache - Size: %d, Threshold: %d\n",
95 cache->fci_name, cache_size, cache_threshold);
96
97 RETURN(cache);
98}
99
100
101
102
103void fld_cache_fini(struct fld_cache *cache)
104{
105 __u64 pct;
106 ENTRY;
107
108 LASSERT(cache != NULL);
109 fld_cache_flush(cache);
110
111 if (cache->fci_stat.fst_count > 0) {
112 pct = cache->fci_stat.fst_cache * 100;
113 do_div(pct, cache->fci_stat.fst_count);
114 } else {
115 pct = 0;
116 }
117
118 CDEBUG(D_INFO, "FLD cache statistics (%s):\n", cache->fci_name);
119 CDEBUG(D_INFO, " Total reqs: "LPU64"\n", cache->fci_stat.fst_count);
120 CDEBUG(D_INFO, " Cache reqs: "LPU64"\n", cache->fci_stat.fst_cache);
121 CDEBUG(D_INFO, " Cache hits: "LPU64"%%\n", pct);
122
123 OBD_FREE_PTR(cache);
124
125 EXIT;
126}
127
128
129
130
131void fld_cache_entry_delete(struct fld_cache *cache,
132 struct fld_cache_entry *node)
133{
134 list_del(&node->fce_list);
135 list_del(&node->fce_lru);
136 cache->fci_cache_count--;
137 OBD_FREE_PTR(node);
138}
139
140
141
142
143static void fld_fix_new_list(struct fld_cache *cache)
144{
145 struct fld_cache_entry *f_curr;
146 struct fld_cache_entry *f_next;
147 struct lu_seq_range *c_range;
148 struct lu_seq_range *n_range;
149 struct list_head *head = &cache->fci_entries_head;
150 ENTRY;
151
152restart_fixup:
153
154 list_for_each_entry_safe(f_curr, f_next, head, fce_list) {
155 c_range = &f_curr->fce_range;
156 n_range = &f_next->fce_range;
157
158 LASSERT(range_is_sane(c_range));
159 if (&f_next->fce_list == head)
160 break;
161
162 if (c_range->lsr_flags != n_range->lsr_flags)
163 continue;
164
165 LASSERTF(c_range->lsr_start <= n_range->lsr_start,
166 "cur lsr_start "DRANGE" next lsr_start "DRANGE"\n",
167 PRANGE(c_range), PRANGE(n_range));
168
169
170 if (c_range->lsr_end == n_range->lsr_start) {
171 if (c_range->lsr_index != n_range->lsr_index)
172 continue;
173 n_range->lsr_start = c_range->lsr_start;
174 fld_cache_entry_delete(cache, f_curr);
175 continue;
176 }
177
178
179 if (n_range->lsr_start < c_range->lsr_end) {
180 if (c_range->lsr_index == n_range->lsr_index) {
181 n_range->lsr_start = c_range->lsr_start;
182 n_range->lsr_end = max(c_range->lsr_end,
183 n_range->lsr_end);
184 fld_cache_entry_delete(cache, f_curr);
185 } else {
186 if (n_range->lsr_end <= c_range->lsr_end) {
187 *n_range = *c_range;
188 fld_cache_entry_delete(cache, f_curr);
189 } else
190 n_range->lsr_start = c_range->lsr_end;
191 }
192
193
194
195 goto restart_fixup;
196 }
197
198
199 if (c_range->lsr_start == n_range->lsr_start &&
200 c_range->lsr_end == n_range->lsr_end)
201 fld_cache_entry_delete(cache, f_curr);
202 }
203
204 EXIT;
205}
206
207
208
209
210static inline void fld_cache_entry_add(struct fld_cache *cache,
211 struct fld_cache_entry *f_new,
212 struct list_head *pos)
213{
214 list_add(&f_new->fce_list, pos);
215 list_add(&f_new->fce_lru, &cache->fci_lru);
216
217 cache->fci_cache_count++;
218 fld_fix_new_list(cache);
219}
220
221
222
223
224
225static int fld_cache_shrink(struct fld_cache *cache)
226{
227 struct fld_cache_entry *flde;
228 struct list_head *curr;
229 int num = 0;
230 ENTRY;
231
232 LASSERT(cache != NULL);
233
234 if (cache->fci_cache_count < cache->fci_cache_size)
235 RETURN(0);
236
237 curr = cache->fci_lru.prev;
238
239 while (cache->fci_cache_count + cache->fci_threshold >
240 cache->fci_cache_size && curr != &cache->fci_lru) {
241
242 flde = list_entry(curr, struct fld_cache_entry, fce_lru);
243 curr = curr->prev;
244 fld_cache_entry_delete(cache, flde);
245 num++;
246 }
247
248 CDEBUG(D_INFO, "%s: FLD cache - Shrunk by "
249 "%d entries\n", cache->fci_name, num);
250
251 RETURN(0);
252}
253
254
255
256
257void fld_cache_flush(struct fld_cache *cache)
258{
259 ENTRY;
260
261 write_lock(&cache->fci_lock);
262 cache->fci_cache_size = 0;
263 fld_cache_shrink(cache);
264 write_unlock(&cache->fci_lock);
265
266 EXIT;
267}
268
269
270
271
272
273
274void fld_cache_punch_hole(struct fld_cache *cache,
275 struct fld_cache_entry *f_curr,
276 struct fld_cache_entry *f_new)
277{
278 const struct lu_seq_range *range = &f_new->fce_range;
279 const seqno_t new_start = range->lsr_start;
280 const seqno_t new_end = range->lsr_end;
281 struct fld_cache_entry *fldt;
282
283 ENTRY;
284 OBD_ALLOC_GFP(fldt, sizeof *fldt, GFP_ATOMIC);
285 if (!fldt) {
286 OBD_FREE_PTR(f_new);
287 EXIT;
288
289 return;
290 }
291
292
293
294
295
296
297
298 fldt->fce_range.lsr_start = new_end;
299 fldt->fce_range.lsr_end = f_curr->fce_range.lsr_end;
300 fldt->fce_range.lsr_index = f_curr->fce_range.lsr_index;
301
302
303 f_curr->fce_range.lsr_end = new_start;
304
305
306 fld_cache_entry_add(cache, f_new, &f_curr->fce_list);
307 fld_cache_entry_add(cache, fldt, &f_new->fce_list);
308
309
310 EXIT;
311}
312
313
314
315
316static void fld_cache_overlap_handle(struct fld_cache *cache,
317 struct fld_cache_entry *f_curr,
318 struct fld_cache_entry *f_new)
319{
320 const struct lu_seq_range *range = &f_new->fce_range;
321 const seqno_t new_start = range->lsr_start;
322 const seqno_t new_end = range->lsr_end;
323 const mdsno_t mdt = range->lsr_index;
324
325
326
327
328 if (f_curr->fce_range.lsr_index == mdt) {
329 f_curr->fce_range.lsr_start = min(f_curr->fce_range.lsr_start,
330 new_start);
331
332 f_curr->fce_range.lsr_end = max(f_curr->fce_range.lsr_end,
333 new_end);
334
335 OBD_FREE_PTR(f_new);
336 fld_fix_new_list(cache);
337
338 } else if (new_start <= f_curr->fce_range.lsr_start &&
339 f_curr->fce_range.lsr_end <= new_end) {
340
341
342
343 f_curr->fce_range = *range;
344 OBD_FREE_PTR(f_new);
345 fld_fix_new_list(cache);
346
347 } else if (f_curr->fce_range.lsr_start < new_start &&
348 new_end < f_curr->fce_range.lsr_end) {
349
350
351 fld_cache_punch_hole(cache, f_curr, f_new);
352
353 } else if (new_end <= f_curr->fce_range.lsr_end) {
354
355
356
357
358 LASSERT(new_start <= f_curr->fce_range.lsr_start);
359
360 f_curr->fce_range.lsr_start = new_end;
361 fld_cache_entry_add(cache, f_new, f_curr->fce_list.prev);
362
363 } else if (f_curr->fce_range.lsr_start <= new_start) {
364
365
366
367
368 LASSERT(f_curr->fce_range.lsr_end <= new_end);
369
370 f_curr->fce_range.lsr_end = new_start;
371 fld_cache_entry_add(cache, f_new, &f_curr->fce_list);
372 } else
373 CERROR("NEW range ="DRANGE" curr = "DRANGE"\n",
374 PRANGE(range),PRANGE(&f_curr->fce_range));
375}
376
377struct fld_cache_entry
378*fld_cache_entry_create(const struct lu_seq_range *range)
379{
380 struct fld_cache_entry *f_new;
381
382 LASSERT(range_is_sane(range));
383
384 OBD_ALLOC_PTR(f_new);
385 if (!f_new)
386 RETURN(ERR_PTR(-ENOMEM));
387
388 f_new->fce_range = *range;
389 RETURN(f_new);
390}
391
392
393
394
395
396
397
398int fld_cache_insert_nolock(struct fld_cache *cache,
399 struct fld_cache_entry *f_new)
400{
401 struct fld_cache_entry *f_curr;
402 struct fld_cache_entry *n;
403 struct list_head *head;
404 struct list_head *prev = NULL;
405 const seqno_t new_start = f_new->fce_range.lsr_start;
406 const seqno_t new_end = f_new->fce_range.lsr_end;
407 __u32 new_flags = f_new->fce_range.lsr_flags;
408 ENTRY;
409
410
411
412
413
414
415
416 if (!cache->fci_no_shrink)
417 fld_cache_shrink(cache);
418
419 head = &cache->fci_entries_head;
420
421 list_for_each_entry_safe(f_curr, n, head, fce_list) {
422
423 if (new_end < f_curr->fce_range.lsr_start ||
424 (new_end == f_curr->fce_range.lsr_start &&
425 new_flags != f_curr->fce_range.lsr_flags))
426 break;
427
428 prev = &f_curr->fce_list;
429
430 if (new_start < f_curr->fce_range.lsr_end &&
431 new_flags == f_curr->fce_range.lsr_flags) {
432 fld_cache_overlap_handle(cache, f_curr, f_new);
433 goto out;
434 }
435 }
436
437 if (prev == NULL)
438 prev = head;
439
440 CDEBUG(D_INFO, "insert range "DRANGE"\n", PRANGE(&f_new->fce_range));
441
442 fld_cache_entry_add(cache, f_new, prev);
443out:
444 RETURN(0);
445}
446
447int fld_cache_insert(struct fld_cache *cache,
448 const struct lu_seq_range *range)
449{
450 struct fld_cache_entry *flde;
451 int rc;
452
453 flde = fld_cache_entry_create(range);
454 if (IS_ERR(flde))
455 RETURN(PTR_ERR(flde));
456
457 write_lock(&cache->fci_lock);
458 rc = fld_cache_insert_nolock(cache, flde);
459 write_unlock(&cache->fci_lock);
460 if (rc)
461 OBD_FREE_PTR(flde);
462
463 RETURN(rc);
464}
465
466void fld_cache_delete_nolock(struct fld_cache *cache,
467 const struct lu_seq_range *range)
468{
469 struct fld_cache_entry *flde;
470 struct fld_cache_entry *tmp;
471 struct list_head *head;
472
473 head = &cache->fci_entries_head;
474 list_for_each_entry_safe(flde, tmp, head, fce_list) {
475
476 if (range->lsr_start == flde->fce_range.lsr_start ||
477 (range->lsr_end == flde->fce_range.lsr_end &&
478 range->lsr_flags == flde->fce_range.lsr_flags)) {
479 fld_cache_entry_delete(cache, flde);
480 break;
481 }
482 }
483}
484
485
486
487
488
489void fld_cache_delete(struct fld_cache *cache,
490 const struct lu_seq_range *range)
491{
492 write_lock(&cache->fci_lock);
493 fld_cache_delete_nolock(cache, range);
494 write_unlock(&cache->fci_lock);
495}
496
497struct fld_cache_entry
498*fld_cache_entry_lookup_nolock(struct fld_cache *cache,
499 struct lu_seq_range *range)
500{
501 struct fld_cache_entry *flde;
502 struct fld_cache_entry *got = NULL;
503 struct list_head *head;
504
505 head = &cache->fci_entries_head;
506 list_for_each_entry(flde, head, fce_list) {
507 if (range->lsr_start == flde->fce_range.lsr_start ||
508 (range->lsr_end == flde->fce_range.lsr_end &&
509 range->lsr_flags == flde->fce_range.lsr_flags)) {
510 got = flde;
511 break;
512 }
513 }
514
515 RETURN(got);
516}
517
518
519
520
521struct fld_cache_entry
522*fld_cache_entry_lookup(struct fld_cache *cache, struct lu_seq_range *range)
523{
524 struct fld_cache_entry *got = NULL;
525 ENTRY;
526
527 read_lock(&cache->fci_lock);
528 got = fld_cache_entry_lookup_nolock(cache, range);
529 read_unlock(&cache->fci_lock);
530 RETURN(got);
531}
532
533
534
535
536int fld_cache_lookup(struct fld_cache *cache,
537 const seqno_t seq, struct lu_seq_range *range)
538{
539 struct fld_cache_entry *flde;
540 struct fld_cache_entry *prev = NULL;
541 struct list_head *head;
542 ENTRY;
543
544 read_lock(&cache->fci_lock);
545 head = &cache->fci_entries_head;
546
547 cache->fci_stat.fst_count++;
548 list_for_each_entry(flde, head, fce_list) {
549 if (flde->fce_range.lsr_start > seq) {
550 if (prev != NULL)
551 *range = prev->fce_range;
552 break;
553 }
554
555 prev = flde;
556 if (range_within(&flde->fce_range, seq)) {
557 *range = flde->fce_range;
558
559 cache->fci_stat.fst_cache++;
560 read_unlock(&cache->fci_lock);
561 RETURN(0);
562 }
563 }
564 read_unlock(&cache->fci_lock);
565 RETURN(-ENOENT);
566}
567