aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/reservations.c
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.com>2009-12-07 16:10:48 -0500
committerJoel Becker <joel.becker@oracle.com>2010-05-05 21:17:30 -0400
commitd02f00cc057809d96c044cc72d5b9809d59f7d49 (patch)
tree44a6d81ecf9fb4b5aa91c0501a8da2ee36890a38 /fs/ocfs2/reservations.c
parentec20cec7a351584ca6c70ead012e73d61f9a8e04 (diff)
ocfs2: allocation reservations
This patch improves Ocfs2 allocation policy by allowing an inode to reserve a portion of the local alloc bitmap for itself. The reserved portion (allocation window) is advisory in that other allocation windows might steal it if the local alloc bitmap becomes full. Otherwise, the reservations are honored and guaranteed to be free. When the local alloc window is moved to a different portion of the bitmap, existing reservations are discarded. Reservation windows are represented internally by a red-black tree. Within that tree, each node represents the reservation window of one inode. An LRU of active reservations is also maintained. When new data is written, we allocate it from the inodes window. When all bits in a window are exhausted, we allocate a new one as close to the previous one as possible. Should we not find free space, an existing reservation is pulled off the LRU and cannibalized. Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/reservations.c')
-rw-r--r--fs/ocfs2/reservations.c849
1 files changed, 849 insertions, 0 deletions
diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c
new file mode 100644
index 000000000000..79642d608210
--- /dev/null
+++ b/fs/ocfs2/reservations.c
@@ -0,0 +1,849 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * reservations.c
5 *
6 * Allocation reservations implementation
7 *
8 * Some code borrowed from fs/ext3/balloc.c and is:
9 *
10 * Copyright (C) 1992, 1993, 1994, 1995
11 * Remy Card (card@masi.ibp.fr)
12 * Laboratoire MASI - Institut Blaise Pascal
13 * Universite Pierre et Marie Curie (Paris VI)
14 *
15 * The rest is copyright (C) 2010 Novell. All rights reserved.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public
19 * License version 2 as published by the Free Software Foundation.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 */
26
27#include <linux/fs.h>
28#include <linux/types.h>
29#include <linux/slab.h>
30#include <linux/highmem.h>
31#include <linux/bitops.h>
32#include <linux/list.h>
33
34#define MLOG_MASK_PREFIX ML_RESERVATIONS
35#include <cluster/masklog.h>
36
37#include "ocfs2.h"
38
39#ifdef CONFIG_OCFS2_DEBUG_FS
40#define OCFS2_CHECK_RESERVATIONS
41#endif
42
43DEFINE_SPINLOCK(resv_lock);
44
45#define OCFS2_MIN_RESV_WINDOW_BITS 8
46#define OCFS2_MAX_RESV_WINDOW_BITS 1024
47
48static unsigned int ocfs2_resv_window_bits(struct ocfs2_reservation_map *resmap,
49 struct ocfs2_alloc_reservation *resv)
50{
51 struct ocfs2_super *osb = resmap->m_osb;
52 unsigned int bits;
53
54 /* 8, 16, 32, 64, 128, 256, 512, 1024 */
55 bits = 4 << osb->osb_resv_level;
56
57 return bits;
58}
59
60static inline unsigned int ocfs2_resv_end(struct ocfs2_alloc_reservation *resv)
61{
62 if (resv->r_len)
63 return resv->r_start + resv->r_len - 1;
64 return resv->r_start;
65}
66
67static inline int ocfs2_resv_empty(struct ocfs2_alloc_reservation *resv)
68{
69 return !!(resv->r_len == 0);
70}
71
72static inline int ocfs2_resmap_disabled(struct ocfs2_reservation_map *resmap)
73{
74 if (resmap->m_osb->osb_resv_level == 0)
75 return 1;
76 return 0;
77}
78
79static void ocfs2_dump_resv(struct ocfs2_reservation_map *resmap)
80{
81 struct ocfs2_super *osb = resmap->m_osb;
82 struct rb_node *node;
83 struct ocfs2_alloc_reservation *resv;
84 int i = 0;
85
86 mlog(ML_NOTICE, "Dumping resmap for device %s. Bitmap length: %u\n",
87 osb->dev_str, resmap->m_bitmap_len);
88
89 node = rb_first(&resmap->m_reservations);
90 while (node) {
91 resv = rb_entry(node, struct ocfs2_alloc_reservation, r_node);
92
93 mlog(ML_NOTICE, "start: %u\tend: %u\tlen: %u\tlast_start: %u"
94 "\tlast_len: %u\n", resv->r_start,
95 ocfs2_resv_end(resv), resv->r_len, resv->r_last_start,
96 resv->r_last_len);
97
98 node = rb_next(node);
99 i++;
100 }
101
102 mlog(ML_NOTICE, "%d reservations found. LRU follows\n", i);
103
104 i = 0;
105 list_for_each_entry(resv, &resmap->m_lru, r_lru) {
106 mlog(ML_NOTICE, "LRU(%d) start: %u\tend: %u\tlen: %u\t"
107 "last_start: %u\tlast_len: %u\n", i, resv->r_start,
108 ocfs2_resv_end(resv), resv->r_len, resv->r_last_start,
109 resv->r_last_len);
110
111 i++;
112 }
113}
114
115#ifdef OCFS2_CHECK_RESERVATIONS
116static int ocfs2_validate_resmap_bits(struct ocfs2_reservation_map *resmap,
117 int i,
118 struct ocfs2_alloc_reservation *resv)
119{
120 char *disk_bitmap = resmap->m_disk_bitmap;
121 unsigned int start = resv->r_start;
122 unsigned int end = ocfs2_resv_end(resv);
123
124 while (start <= end) {
125 if (ocfs2_test_bit(start, disk_bitmap)) {
126 mlog(ML_ERROR,
127 "reservation %d covers an allocated area "
128 "starting at bit %u!\n", i, start);
129 return 1;
130 }
131
132 start++;
133 }
134 return 0;
135}
136
137static void ocfs2_check_resmap(struct ocfs2_reservation_map *resmap)
138{
139 unsigned int off = 0;
140 int i = 0;
141 struct rb_node *node;
142 struct ocfs2_alloc_reservation *resv;
143
144 node = rb_first(&resmap->m_reservations);
145 while (node) {
146 resv = rb_entry(node, struct ocfs2_alloc_reservation, r_node);
147
148 if (i > 0 && resv->r_start <= off) {
149 mlog(ML_ERROR, "reservation %d has bad start off!\n",
150 i);
151 goto bad;
152 }
153
154 if (resv->r_len == 0) {
155 mlog(ML_ERROR, "reservation %d has no length!\n",
156 i);
157 goto bad;
158 }
159
160 if (resv->r_start > ocfs2_resv_end(resv)) {
161 mlog(ML_ERROR, "reservation %d has invalid range!\n",
162 i);
163 goto bad;
164 }
165
166 if (ocfs2_resv_end(resv) >= resmap->m_bitmap_len) {
167 mlog(ML_ERROR, "reservation %d extends past bitmap!\n",
168 i);
169 goto bad;
170 }
171
172 if (ocfs2_validate_resmap_bits(resmap, i, resv))
173 goto bad;
174
175 off = ocfs2_resv_end(resv);
176 node = rb_next(node);
177
178 i++;
179 }
180 return;
181
182bad:
183 ocfs2_dump_resv(resmap);
184 BUG();
185}
186#else
187static inline void ocfs2_check_resmap(struct ocfs2_reservation_map *resmap)
188{
189
190}
191#endif
192
193void ocfs2_resv_init_once(struct ocfs2_alloc_reservation *resv)
194{
195 memset(resv, 0, sizeof(*resv));
196 INIT_LIST_HEAD(&resv->r_lru);
197}
198
199void ocfs2_resv_set_type(struct ocfs2_alloc_reservation *resv,
200 unsigned int flags)
201{
202 BUG_ON(flags & ~OCFS2_RESV_TYPES);
203
204 resv->r_flags |= flags;
205}
206
207int ocfs2_resmap_init(struct ocfs2_super *osb,
208 struct ocfs2_reservation_map *resmap)
209{
210 memset(resmap, 0, sizeof(*resmap));
211
212 resmap->m_osb = osb;
213 resmap->m_reservations = RB_ROOT;
214 /* m_bitmap_len is initialized to zero by the above memset. */
215 INIT_LIST_HEAD(&resmap->m_lru);
216
217 return 0;
218}
219
220static void ocfs2_resv_mark_lru(struct ocfs2_reservation_map *resmap,
221 struct ocfs2_alloc_reservation *resv)
222{
223 assert_spin_locked(&resv_lock);
224
225 if (!list_empty(&resv->r_lru))
226 list_del_init(&resv->r_lru);
227
228 list_add_tail(&resv->r_lru, &resmap->m_lru);
229}
230
231static void __ocfs2_resv_trunc(struct ocfs2_alloc_reservation *resv)
232{
233 resv->r_len = 0;
234 resv->r_start = 0;
235}
236
237static void ocfs2_resv_remove(struct ocfs2_reservation_map *resmap,
238 struct ocfs2_alloc_reservation *resv)
239{
240 if (resv->r_flags & OCFS2_RESV_FLAG_INUSE) {
241 list_del_init(&resv->r_lru);
242 rb_erase(&resv->r_node, &resmap->m_reservations);
243 resv->r_flags &= ~OCFS2_RESV_FLAG_INUSE;
244 }
245}
246
247static void __ocfs2_resv_discard(struct ocfs2_reservation_map *resmap,
248 struct ocfs2_alloc_reservation *resv)
249{
250 assert_spin_locked(&resv_lock);
251
252 __ocfs2_resv_trunc(resv);
253 /*
254 * last_len and last_start no longer make sense if
255 * we're changing the range of our allocations.
256 */
257 resv->r_last_len = resv->r_last_start = 0;
258
259 ocfs2_resv_remove(resmap, resv);
260}
261
262/* does nothing if 'resv' is null */
263void ocfs2_resv_discard(struct ocfs2_reservation_map *resmap,
264 struct ocfs2_alloc_reservation *resv)
265{
266 if (resv) {
267 spin_lock(&resv_lock);
268 __ocfs2_resv_discard(resmap, resv);
269 spin_unlock(&resv_lock);
270 }
271}
272
273static void ocfs2_resmap_clear_all_resv(struct ocfs2_reservation_map *resmap)
274{
275 struct rb_node *node;
276 struct ocfs2_alloc_reservation *resv;
277
278 assert_spin_locked(&resv_lock);
279
280 while ((node = rb_last(&resmap->m_reservations)) != NULL) {
281 resv = rb_entry(node, struct ocfs2_alloc_reservation, r_node);
282
283 __ocfs2_resv_discard(resmap, resv);
284 }
285}
286
287void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap,
288 unsigned int clen, char *disk_bitmap)
289{
290 if (ocfs2_resmap_disabled(resmap))
291 return;
292
293 spin_lock(&resv_lock);
294
295 ocfs2_resmap_clear_all_resv(resmap);
296 resmap->m_bitmap_len = clen;
297 resmap->m_disk_bitmap = disk_bitmap;
298
299 spin_unlock(&resv_lock);
300}
301
302void ocfs2_resmap_uninit(struct ocfs2_reservation_map *resmap)
303{
304 /* Does nothing for now. Keep this around for API symmetry */
305}
306
307static void ocfs2_resv_insert(struct ocfs2_reservation_map *resmap,
308 struct ocfs2_alloc_reservation *new)
309{
310 struct rb_root *root = &resmap->m_reservations;
311 struct rb_node *parent = NULL;
312 struct rb_node **p = &root->rb_node;
313 struct ocfs2_alloc_reservation *tmp;
314
315 assert_spin_locked(&resv_lock);
316
317 mlog(0, "Insert reservation start: %u len: %u\n", new->r_start,
318 new->r_len);
319
320 while (*p) {
321 parent = *p;
322
323 tmp = rb_entry(parent, struct ocfs2_alloc_reservation, r_node);
324
325 if (new->r_start < tmp->r_start) {
326 p = &(*p)->rb_left;
327
328 /*
329 * This is a good place to check for
330 * overlapping reservations.
331 */
332 BUG_ON(ocfs2_resv_end(new) >= tmp->r_start);
333 } else if (new->r_start > ocfs2_resv_end(tmp)) {
334 p = &(*p)->rb_right;
335 } else {
336 /* This should never happen! */
337 mlog(ML_ERROR, "Duplicate reservation window!\n");
338 BUG();
339 }
340 }
341
342 rb_link_node(&new->r_node, parent, p);
343 rb_insert_color(&new->r_node, root);
344 new->r_flags |= OCFS2_RESV_FLAG_INUSE;
345
346 ocfs2_resv_mark_lru(resmap, new);
347
348 ocfs2_check_resmap(resmap);
349}
350
351/**
352 * ocfs2_find_resv_lhs() - find the window which contains goal
353 * @resmap: reservation map to search
354 * @goal: which bit to search for
355 *
356 * If a window containing that goal is not found, we return the window
357 * which comes before goal. Returns NULL on empty rbtree or no window
358 * before goal.
359 */
360static struct ocfs2_alloc_reservation *
361ocfs2_find_resv_lhs(struct ocfs2_reservation_map *resmap, unsigned int goal)
362{
363 struct ocfs2_alloc_reservation *resv = NULL;
364 struct ocfs2_alloc_reservation *prev_resv = NULL;
365 struct rb_node *node = resmap->m_reservations.rb_node;
366 struct rb_node *prev = NULL;
367
368 assert_spin_locked(&resv_lock);
369
370 if (!node)
371 return NULL;
372
373 node = rb_first(&resmap->m_reservations);
374 while (node) {
375 resv = rb_entry(node, struct ocfs2_alloc_reservation, r_node);
376
377 if (resv->r_start <= goal && ocfs2_resv_end(resv) >= goal)
378 break;
379
380 /* Check if we overshot the reservation just before goal? */
381 if (resv->r_start > goal) {
382 resv = prev_resv;
383 break;
384 }
385
386 prev_resv = resv;
387 prev = node;
388 node = rb_next(node);
389 }
390
391 return resv;
392}
393
394/*
395 * We are given a range within the bitmap, which corresponds to a gap
396 * inside the reservations tree (search_start, search_len). The range
397 * can be anything from the whole bitmap, to a gap between
398 * reservations.
399 *
400 * The start value of *rstart is insignificant.
401 *
402 * This function searches the bitmap range starting at search_start
403 * with length csearch_len for a set of contiguous free bits. We try
404 * to find up to 'wanted' bits, but can sometimes return less.
405 *
406 * Returns the length of allocation, 0 if no free bits are found.
407 *
408 * *cstart and *clen will also be populated with the result.
409 */
410static int ocfs2_resmap_find_free_bits(struct ocfs2_reservation_map *resmap,
411 unsigned int wanted,
412 unsigned int search_start,
413 unsigned int search_len,
414 unsigned int *rstart,
415 unsigned int *rlen)
416{
417 void *bitmap = resmap->m_disk_bitmap;
418 unsigned int best_start, best_len = 0;
419 int offset, start, found;
420
421 mlog(0, "Find %u bits within range (%u, len %u) resmap len: %u\n",
422 wanted, search_start, search_len, resmap->m_bitmap_len);
423
424 found = best_start = best_len = 0;
425
426 start = search_start;
427 while ((offset = ocfs2_find_next_zero_bit(bitmap, resmap->m_bitmap_len,
428 start)) != -1) {
429 /* Search reached end of the region */
430 if (offset >= (search_start + search_len))
431 break;
432
433 if (offset == start) {
434 /* we found a zero */
435 found++;
436 /* move start to the next bit to test */
437 start++;
438 } else {
439 /* got a zero after some ones */
440 found = 1;
441 start = offset + 1;
442 }
443 if (found > best_len) {
444 best_len = found;
445 best_start = start - found;
446 }
447
448 if (found >= wanted)
449 break;
450 }
451
452 if (best_len == 0)
453 return 0;
454
455 if (best_len >= wanted)
456 best_len = wanted;
457
458 *rlen = best_len;
459 *rstart = best_start;
460
461 mlog(0, "Found start: %u len: %u\n", best_start, best_len);
462
463 return *rlen;
464}
465
466static void __ocfs2_resv_find_window(struct ocfs2_reservation_map *resmap,
467 struct ocfs2_alloc_reservation *resv,
468 unsigned int goal, unsigned int wanted)
469{
470 struct rb_root *root = &resmap->m_reservations;
471 unsigned int gap_start, gap_end, gap_len;
472 struct ocfs2_alloc_reservation *prev_resv, *next_resv;
473 struct rb_node *prev, *next;
474 unsigned int cstart, clen;
475 unsigned int best_start = 0, best_len = 0;
476
477 /*
478 * Nasty cases to consider:
479 *
480 * - rbtree is empty
481 * - our window should be first in all reservations
482 * - our window should be last in all reservations
483 * - need to make sure we don't go past end of bitmap
484 */
485
486 mlog(0, "resv start: %u resv end: %u goal: %u wanted: %u\n",
487 resv->r_start, ocfs2_resv_end(resv), goal, wanted);
488
489 assert_spin_locked(&resv_lock);
490
491 if (RB_EMPTY_ROOT(root)) {
492 /*
493 * Easiest case - empty tree. We can just take
494 * whatever window of free bits we want.
495 */
496
497 mlog(0, "Empty root\n");
498
499 clen = ocfs2_resmap_find_free_bits(resmap, wanted, goal,
500 resmap->m_bitmap_len - goal,
501 &cstart, &clen);
502
503 /*
504 * This should never happen - the local alloc window
505 * will always have free bits when we're called.
506 */
507 BUG_ON(goal == 0 && clen == 0);
508
509 if (clen == 0)
510 return;
511
512 resv->r_start = cstart;
513 resv->r_len = clen;
514
515 ocfs2_resv_insert(resmap, resv);
516 return;
517 }
518
519 prev_resv = ocfs2_find_resv_lhs(resmap, goal);
520
521 if (prev_resv == NULL) {
522 mlog(0, "Goal on LHS of leftmost window\n");
523
524 /*
525 * A NULL here means that the search code couldn't
526 * find a window that starts before goal.
527 *
528 * However, we can take the first window after goal,
529 * which is also by definition, the leftmost window in
530 * the entire tree. If we can find free bits in the
531 * gap between goal and the LHS window, then the
532 * reservation can safely be placed there.
533 *
534 * Otherwise we fall back to a linear search, checking
535 * the gaps in between windows for a place to
536 * allocate.
537 */
538
539 next = rb_first(root);
540 next_resv = rb_entry(next, struct ocfs2_alloc_reservation,
541 r_node);
542
543 /*
544 * The search should never return such a window. (see
545 * comment above
546 */
547 if (next_resv->r_start <= goal) {
548 mlog(ML_ERROR, "goal: %u next_resv: start %u len %u\n",
549 goal, next_resv->r_start, next_resv->r_len);
550 ocfs2_dump_resv(resmap);
551 BUG();
552 }
553
554 clen = ocfs2_resmap_find_free_bits(resmap, wanted, goal,
555 next_resv->r_start - goal,
556 &cstart, &clen);
557 if (clen) {
558 best_len = clen;
559 best_start = cstart;
560 if (best_len == wanted)
561 goto out_insert;
562 }
563
564 prev_resv = next_resv;
565 next_resv = NULL;
566 }
567
568 prev = &prev_resv->r_node;
569
570 /* Now we do a linear search for a window, starting at 'prev_rsv' */
571 while (1) {
572 next = rb_next(prev);
573 if (next) {
574 mlog(0, "One more resv found in linear search\n");
575 next_resv = rb_entry(next,
576 struct ocfs2_alloc_reservation,
577 r_node);
578
579 gap_start = ocfs2_resv_end(prev_resv) + 1;
580 gap_end = next_resv->r_start - 1;
581 gap_len = gap_end - gap_start + 1;
582 } else {
583 mlog(0, "No next node\n");
584 /*
585 * We're at the rightmost edge of the
586 * tree. See if a reservation between this
587 * window and the end of the bitmap will work.
588 */
589 gap_start = ocfs2_resv_end(prev_resv) + 1;
590 gap_len = resmap->m_bitmap_len - gap_start;
591 gap_end = resmap->m_bitmap_len - 1;
592 }
593
594 /*
595 * No need to check this gap if we have already found
596 * a larger region of free bits.
597 */
598 if (gap_len <= best_len)
599 goto next_resv;
600
601 clen = ocfs2_resmap_find_free_bits(resmap, wanted, gap_start,
602 gap_len, &cstart, &clen);
603 if (clen == wanted) {
604 best_len = clen;
605 best_start = cstart;
606 goto out_insert;
607 } else if (clen > best_len) {
608 best_len = clen;
609 best_start = cstart;
610 }
611
612next_resv:
613 if (!next)
614 break;
615
616 prev = next;
617 prev_resv = rb_entry(prev, struct ocfs2_alloc_reservation,
618 r_node);
619 }
620
621out_insert:
622 if (best_len) {
623 resv->r_start = best_start;
624 resv->r_len = best_len;
625 ocfs2_resv_insert(resmap, resv);
626 }
627}
628
629static void ocfs2_cannibalize_resv(struct ocfs2_reservation_map *resmap,
630 struct ocfs2_alloc_reservation *resv,
631 unsigned int wanted)
632{
633 struct ocfs2_alloc_reservation *lru_resv;
634 int tmpwindow = !!(resv->r_flags & OCFS2_RESV_FLAG_TMP);
635 unsigned int min_bits;
636
637 if (!tmpwindow)
638 min_bits = ocfs2_resv_window_bits(resmap, resv) >> 1;
639 else
640 min_bits = wanted; /* We at know the temp window will use all
641 * of these bits */
642
643 /*
644 * Take the first reservation off the LRU as our 'target'. We
645 * don't try to be smart about it. There might be a case for
646 * searching based on size but I don't have enough data to be
647 * sure. --Mark (3/16/2010)
648 */
649 lru_resv = list_first_entry(&resmap->m_lru,
650 struct ocfs2_alloc_reservation, r_lru);
651
652 mlog(0, "lru resv: start: %u len: %u end: %u\n", lru_resv->r_start,
653 lru_resv->r_len, ocfs2_resv_end(lru_resv));
654
655 /*
656 * Cannibalize (some or all) of the target reservation and
657 * feed it to the current window.
658 */
659 if (lru_resv->r_len <= min_bits) {
660 /*
661 * Discard completely if size is less than or equal to a
662 * reasonable threshold - 50% of window bits for non temporary
663 * windows.
664 */
665 resv->r_start = lru_resv->r_start;
666 resv->r_len = lru_resv->r_len;
667
668 __ocfs2_resv_discard(resmap, lru_resv);
669 } else {
670 unsigned int shrink;
671 if (tmpwindow)
672 shrink = min_bits;
673 else
674 shrink = lru_resv->r_len / 2;
675
676 lru_resv->r_len -= shrink;
677
678 resv->r_start = ocfs2_resv_end(lru_resv) + 1;
679 resv->r_len = shrink;
680 }
681
682 mlog(0, "Reservation now looks like: r_start: %u r_end: %u "
683 "r_len: %u r_last_start: %u r_last_len: %u\n",
684 resv->r_start, ocfs2_resv_end(resv), resv->r_len,
685 resv->r_last_start, resv->r_last_len);
686
687 ocfs2_resv_insert(resmap, resv);
688}
689
690static void ocfs2_resv_find_window(struct ocfs2_reservation_map *resmap,
691 struct ocfs2_alloc_reservation *resv,
692 unsigned int wanted)
693{
694 unsigned int goal = 0;
695
696 BUG_ON(!ocfs2_resv_empty(resv));
697
698 /*
699 * Begin by trying to get a window as close to the previous
700 * one as possible. Using the most recent allocation as a
701 * start goal makes sense.
702 */
703 if (resv->r_last_len) {
704 goal = resv->r_last_start + resv->r_last_len;
705 if (goal >= resmap->m_bitmap_len)
706 goal = 0;
707 }
708
709 __ocfs2_resv_find_window(resmap, resv, goal, wanted);
710
711 /* Search from last alloc didn't work, try once more from beginning. */
712 if (ocfs2_resv_empty(resv) && goal != 0)
713 __ocfs2_resv_find_window(resmap, resv, 0, wanted);
714
715 if (ocfs2_resv_empty(resv)) {
716 /*
717 * Still empty? Pull oldest one off the LRU, remove it from
718 * tree, put this one in it's place.
719 */
720 ocfs2_cannibalize_resv(resmap, resv, wanted);
721 }
722
723 BUG_ON(ocfs2_resv_empty(resv));
724}
725
726int ocfs2_resmap_resv_bits(struct ocfs2_reservation_map *resmap,
727 struct ocfs2_alloc_reservation *resv,
728 int *cstart, int *clen)
729{
730 unsigned int wanted = *clen;
731
732 if (resv == NULL || ocfs2_resmap_disabled(resmap))
733 return -ENOSPC;
734
735 spin_lock(&resv_lock);
736
737 /*
738 * We don't want to over-allocate for temporary
739 * windows. Otherwise, we run the risk of fragmenting the
740 * allocation space.
741 */
742 wanted = ocfs2_resv_window_bits(resmap, resv);
743 if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen)
744 wanted = *clen;
745
746 if (ocfs2_resv_empty(resv)) {
747 mlog(0, "empty reservation, find new window\n");
748
749 /*
750 * Try to get a window here. If it works, we must fall
751 * through and test the bitmap . This avoids some
752 * ping-ponging of windows due to non-reserved space
753 * being allocation before we initialize a window for
754 * that inode.
755 */
756 ocfs2_resv_find_window(resmap, resv, wanted);
757 }
758
759 BUG_ON(ocfs2_resv_empty(resv));
760
761 *cstart = resv->r_start;
762 *clen = resv->r_len;
763
764 spin_unlock(&resv_lock);
765 return 0;
766}
767
768static void
769 ocfs2_adjust_resv_from_alloc(struct ocfs2_reservation_map *resmap,
770 struct ocfs2_alloc_reservation *resv,
771 unsigned int start, unsigned int end)
772{
773 unsigned int lhs = 0, rhs = 0;
774
775 BUG_ON(start < resv->r_start);
776
777 /*
778 * Completely used? We can remove it then.
779 */
780 if (ocfs2_resv_end(resv) <= end && resv->r_start >= start) {
781 __ocfs2_resv_discard(resmap, resv);
782 return;
783 }
784
785 if (end < ocfs2_resv_end(resv))
786 rhs = end - ocfs2_resv_end(resv);
787
788 if (start > resv->r_start)
789 lhs = start - resv->r_start;
790
791 /*
792 * This should have been trapped above. At the very least, rhs
793 * should be non zero.
794 */
795 BUG_ON(rhs == 0 && lhs == 0);
796
797 if (rhs >= lhs) {
798 unsigned int old_end = ocfs2_resv_end(resv);
799
800 resv->r_start = end + 1;
801 resv->r_len = old_end - resv->r_start + 1;
802 } else {
803 resv->r_len = start - resv->r_start;
804 }
805}
806
807void ocfs2_resmap_claimed_bits(struct ocfs2_reservation_map *resmap,
808 struct ocfs2_alloc_reservation *resv,
809 u32 cstart, u32 clen)
810{
811 unsigned int cend = cstart + clen - 1;
812
813 if (resmap == NULL || ocfs2_resmap_disabled(resmap))
814 return;
815
816 if (resv == NULL)
817 return;
818
819 spin_lock(&resv_lock);
820
821 mlog(0, "claim bits: cstart: %u cend: %u clen: %u r_start: %u "
822 "r_end: %u r_len: %u, r_last_start: %u r_last_len: %u\n",
823 cstart, cend, clen, resv->r_start, ocfs2_resv_end(resv),
824 resv->r_len, resv->r_last_start, resv->r_last_len);
825
826 BUG_ON(cstart < resv->r_start);
827 BUG_ON(cstart > ocfs2_resv_end(resv));
828 BUG_ON(cend > ocfs2_resv_end(resv));
829
830 ocfs2_adjust_resv_from_alloc(resmap, resv, cstart, cend);
831 resv->r_last_start = cstart;
832 resv->r_last_len = clen;
833
834 /*
835 * May have been discarded above from
836 * ocfs2_adjust_resv_from_alloc().
837 */
838 if (!ocfs2_resv_empty(resv))
839 ocfs2_resv_mark_lru(resmap, resv);
840
841 mlog(0, "Reservation now looks like: r_start: %u r_end: %u "
842 "r_len: %u r_last_start: %u r_last_len: %u\n",
843 resv->r_start, ocfs2_resv_end(resv), resv->r_len,
844 resv->r_last_start, resv->r_last_len);
845
846 ocfs2_check_resmap(resmap);
847
848 spin_unlock(&resv_lock);
849}