source: rtems/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.c @ 0ec9bbc

5
Last change on this file since 0ec9bbc was 64908df, checked in by Fan Deng <enetor@…>, on 10/10/17 at 23:28:34

Fixes bitmap allocation accounting logic in rtems-rfs-bitmaps.c

The bitmap allocation accounting logic in rtems-rfs-bitmaps.c is flawed
around control->free. Specifically:

In rtems_rfs_bitmap_map_set():
control->free is only decremented when its corresponding search bit is
toggled. This is wrong and will miss on average 31/32 set updates.

In rtems_rfs_bitmap_map_clear():
control->free is incremented unconditionally.

The correct behavior is:
When updating the map, check if the bit is already set/clear. Only update
control->free when the bit is toggled.

This change enforced the correct behavior.

Tested by inspecting the internal data structure.

  • Property mode set to 100644
File size: 19.0 KB
Line 
1/**
2 * @file
3 *
4 * @brief RTEMS File Systems Bitmap Routines
5 * @ingroup rtems_rfs
6 *
7 * These functions manage bit maps. A bit map consists of the map of bit
8 * allocated in a block and a search map where a bit represents 32 actual
9 * bits. The search map allows for a faster search for an available bit as 32
10 * search bits can checked in a test.
11 */
12
13/*
14 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25/**
26 * Set to 1 to enable warnings when developing.
27 */
28#define RTEMS_RFS_BITMAP_WARNINGS 0
29
30#if RTEMS_RFS_BITMAP_WARNINGS
31#include <stdio.h>
32#endif
33#include <stdlib.h>
34#include <rtems/rfs/rtems-rfs-bitmaps.h>
35
36/**
37 * Test a bit in an element. If set return true else return false.
38 *
39 * @param target The target to test the bit in.
40 * @param bit The bit to test.
41 * @retval true The bit is set.
42 * @retval false The bit is clear.
43 */
44static bool
45rtems_rfs_bitmap_test (rtems_rfs_bitmap_element target,
46                       rtems_rfs_bitmap_bit     bit)
47{
48  return RTEMS_RFS_BITMAP_TEST_BIT (target, bit);
49}
50
51/**
52 * Set the bits in the element. Bits not set in the bit argument are left
53 * unchanged.
54 *
55 * @param target The target element bits are set.
56 * @param bits The bits in the target to set. A 1 in the bits will set the
57 *             same bit in the target.
58 */
59static rtems_rfs_bitmap_element
60rtems_rfs_bitmap_set (rtems_rfs_bitmap_element target,
61                      rtems_rfs_bitmap_element bits)
62{
63  return RTEMS_RFS_BITMAP_SET_BITS (target, bits);
64}
65
66/**
67 * Clear the bits in the element. Bits not set in the bit argument are left
68 * unchanged.
69 *
70 * @param target The target element to clear the bits in.
71 * @param bits The bits in the target to clear. A 1 in the bits will clear the
72 *             bit in the target.
73 */
74static rtems_rfs_bitmap_element
75rtems_rfs_bitmap_clear (rtems_rfs_bitmap_element target,
76                        rtems_rfs_bitmap_element bits)
77{
78  return RTEMS_RFS_BITMAP_CLEAR_BITS (target, bits);
79}
80
81/**
82 * Merge the bits in 2 variables based on the mask. A set bit in the mask will
83 * merge the bits from bits1 and a clear bit will merge the bits from bits2.
84 * The mask is always defined as 1 being set and 0 being clear.
85 */
86static rtems_rfs_bitmap_element
87rtems_rfs_bitmap_merge (rtems_rfs_bitmap_element bits1,
88                        rtems_rfs_bitmap_element bits2,
89                        rtems_rfs_bitmap_element mask)
90{
91  /*
92   * Use the normal bit operators because we do not change the bits just merge
93   * the 2 separate parts.
94   */
95  bits1 &= mask;
96  bits2 &= RTEMS_RFS_BITMAP_INVERT_MASK (mask);
97  return bits1 | bits2;
98}
99
100/**
101 * Match the bits of 2 elements and return true if they match else return
102 * false.
103 *
104 * @param bits1 One set of bits to match.
105 * @param bits2 The second set of bits to match.
106 * @retval true The bits match.
107 * @retval false The bits do not match.
108 */
109static bool
110rtems_rfs_bitmap_match (rtems_rfs_bitmap_element bits1,
111                        rtems_rfs_bitmap_element bits2)
112{
113  return bits1 ^ bits2 ? false : true;
114}
115
116#if RTEMS_NOT_USED_BUT_KEPT
117/**
118 * Match the bits of 2 elements within the mask and return true if they match
119 * else return false.
120 *
121 * @param mask The mask over which the match occurs. A 1 is a valid mask bit.
122 * @param bits1 One set of bits to match.
123 * @param bits2 The second set of bits to match.
124 * @retval true The bits match.
125 * @retval false The bits do not match.
126 */
127static bool
128rtems_rfs_bitmap_match_masked (rtems_rfs_bitmap_element mask,
129                               rtems_rfs_bitmap_element bits1,
130                               rtems_rfs_bitmap_element bits2)
131{
132  return (bits1 ^ bits2) & mask ? false : true;
133}
134#endif
135
136/**
137 * Return the map after loading from disk if not already loaded.
138 *
139 * @param control The bitmap control.
140 * @param rtems_rfs_bitmap_map* Pointer to the bitmap map data if no error.
141 * @return int The error number (errno). No error if 0.
142 */
143static int
144rtems_rfs_bitmap_load_map (rtems_rfs_bitmap_control* control,
145                           rtems_rfs_bitmap_map*     map)
146{
147  int rc;
148
149  if (!control->buffer)
150    return ENXIO;
151
152  *map = NULL;
153
154  rc = rtems_rfs_buffer_handle_request (control->fs,
155                                        control->buffer,
156                                        control->block,
157                                        true);
158  if (rc)
159    return rc;
160
161  *map = rtems_rfs_buffer_data (control->buffer);
162  return 0;
163}
164
165rtems_rfs_bitmap_element
166rtems_rfs_bitmap_mask (unsigned int size)
167{
168  rtems_rfs_bitmap_element mask = RTEMS_RFS_BITMAP_ELEMENT_FULL_MASK;
169  mask >>= (rtems_rfs_bitmap_element_bits () - size);
170  return mask;
171}
172
173rtems_rfs_bitmap_element
174rtems_rfs_bitmap_mask_section (unsigned int start, unsigned int end)
175{
176  rtems_rfs_bitmap_element mask = 0;
177  if (end > start)
178    mask = rtems_rfs_bitmap_mask (end - start) << start;
179  return mask;
180}
181
182int
183rtems_rfs_bitmap_map_set (rtems_rfs_bitmap_control* control,
184                          rtems_rfs_bitmap_bit      bit)
185{
186  rtems_rfs_bitmap_map     map;
187  rtems_rfs_bitmap_map     search_map;
188  int                      index;
189  int                      offset;
190  int                      rc;
191  rtems_rfs_bitmap_element element;
192
193  rc = rtems_rfs_bitmap_load_map (control, &map);
194  if (rc > 0)
195    return rc;
196
197  if (bit >= control->size)
198    return EINVAL;
199
200  search_map = control->search_bits;
201  index      = rtems_rfs_bitmap_map_index (bit);
202  offset     = rtems_rfs_bitmap_map_offset (bit);
203  element    = map[index];
204  map[index] = rtems_rfs_bitmap_set (element, 1 << offset);
205
206  /*
207   * If the element does not change, the bit was already set. There will be no
208   * further action to take.
209   */
210  if (rtems_rfs_bitmap_match(element, map[index]))
211      return 0;
212
213  control->free--;
214
215  rtems_rfs_buffer_mark_dirty (control->buffer);
216  if (rtems_rfs_bitmap_match(map[index], RTEMS_RFS_BITMAP_ELEMENT_SET))
217  {
218    bit = index;
219    index  = rtems_rfs_bitmap_map_index (bit);
220    offset = rtems_rfs_bitmap_map_offset (bit);
221    search_map[index] = rtems_rfs_bitmap_set (search_map[index], 1 << offset);
222  }
223
224  return 0;
225}
226
227int
228rtems_rfs_bitmap_map_clear (rtems_rfs_bitmap_control* control,
229                            rtems_rfs_bitmap_bit      bit)
230{
231  rtems_rfs_bitmap_map     map;
232  rtems_rfs_bitmap_map     search_map;
233  int                      index;
234  int                      offset;
235  int                      rc;
236  rtems_rfs_bitmap_element element;
237
238  rc = rtems_rfs_bitmap_load_map (control, &map);
239  if (rc > 0)
240    return rc;
241
242  if (bit >= control->size)
243    return EINVAL;
244
245  search_map = control->search_bits;
246  index      = rtems_rfs_bitmap_map_index (bit);
247  offset     = rtems_rfs_bitmap_map_offset (bit);
248  element    = map[index];
249  map[index] = rtems_rfs_bitmap_clear (element, 1 << offset);
250
251  /*
252   * If the element does not change, the bit was already clear. There will be
253   * no further action to take.
254   */
255  if (rtems_rfs_bitmap_match(element, map[index]))
256      return 0;
257
258  bit               = index;
259  index             = rtems_rfs_bitmap_map_index (bit);
260  offset            = rtems_rfs_bitmap_map_offset(bit);
261  search_map[index] = rtems_rfs_bitmap_clear (search_map[index], 1 << offset);
262  rtems_rfs_buffer_mark_dirty (control->buffer);
263  control->free++;
264
265  return 0;
266}
267
268int
269rtems_rfs_bitmap_map_test (rtems_rfs_bitmap_control* control,
270                           rtems_rfs_bitmap_bit      bit,
271                           bool*                     state)
272{
273  rtems_rfs_bitmap_map map;
274  int                  index;
275  int                  rc;
276  rc = rtems_rfs_bitmap_load_map (control, &map);
277  if (rc > 0)
278    return rc;
279  if (bit >= control->size)
280    return EINVAL;
281  index = rtems_rfs_bitmap_map_index (bit);
282  *state = rtems_rfs_bitmap_test (map[index], bit);
283  return 0;
284}
285
286int
287rtems_rfs_bitmap_map_set_all (rtems_rfs_bitmap_control* control)
288{
289  rtems_rfs_bitmap_map map;
290  size_t               elements;
291  int                  e;
292  int                  rc;
293
294  rc = rtems_rfs_bitmap_load_map (control, &map);
295  if (rc > 0)
296    return rc;
297
298  elements = rtems_rfs_bitmap_elements (control->size);
299
300  control->free = 0;
301
302  for (e = 0; e < elements; e++)
303    map[e] = RTEMS_RFS_BITMAP_ELEMENT_SET;
304
305  elements = rtems_rfs_bitmap_elements (elements);
306
307  for (e = 0; e < elements; e++)
308    control->search_bits[e] = RTEMS_RFS_BITMAP_ELEMENT_SET;
309
310  rtems_rfs_buffer_mark_dirty (control->buffer);
311
312  return 0;
313}
314
315int
316rtems_rfs_bitmap_map_clear_all (rtems_rfs_bitmap_control* control)
317{
318  rtems_rfs_bitmap_map map;
319  rtems_rfs_bitmap_bit last_search_bit;
320  size_t               elements;
321  int                  e;
322  int                  rc;
323
324  rc = rtems_rfs_bitmap_load_map (control, &map);
325  if (rc > 0)
326    return rc;
327
328  elements = rtems_rfs_bitmap_elements (control->size);
329
330  control->free = control->size;
331
332  for (e = 0; e < elements; e++)
333    map[e] = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
334
335  /*
336   * Set the un-mapped bits in the last search element so the available logic
337   * works.
338   */
339  last_search_bit = rtems_rfs_bitmap_map_offset (elements);
340
341  if (last_search_bit == 0)
342    last_search_bit = rtems_rfs_bitmap_element_bits ();
343
344  elements = rtems_rfs_bitmap_elements (elements);
345
346  for (e = 0; e < (elements - 1); e++)
347    control->search_bits[e] = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
348
349  control->search_bits[elements - 1] =
350    rtems_rfs_bitmap_merge (RTEMS_RFS_BITMAP_ELEMENT_CLEAR,
351                            RTEMS_RFS_BITMAP_ELEMENT_SET,
352                            rtems_rfs_bitmap_mask (last_search_bit));
353
354  rtems_rfs_buffer_mark_dirty (control->buffer);
355
356  return 0;
357}
358
359static int
360rtems_rfs_search_map_for_clear_bit (rtems_rfs_bitmap_control* control,
361                                    rtems_rfs_bitmap_bit*     bit,
362                                    bool*                     found,
363                                    size_t                    window,
364                                    int                       direction)
365{
366  rtems_rfs_bitmap_map      map;
367  rtems_rfs_bitmap_bit      test_bit;
368  rtems_rfs_bitmap_bit      end_bit;
369  rtems_rfs_bitmap_element* search_bits;
370  int                       search_index;
371  int                       search_offset;
372  rtems_rfs_bitmap_element* map_bits;
373  int                       map_index;
374  int                       map_offset;
375  int                       rc;
376
377  *found = false;
378
379  /*
380   * Load the bitmap.
381   */
382  rc = rtems_rfs_bitmap_load_map (control, &map);
383  if (rc > 0)
384    return rc;
385
386  /*
387   * Calculate the bit we are testing plus the end point we search over.
388   */
389  test_bit = *bit;
390  end_bit  = test_bit + (window * direction);
391
392  if (end_bit < 0)
393    end_bit = 0;
394  else if (end_bit >= control->size)
395    end_bit = control->size - 1;
396
397  map_index     = rtems_rfs_bitmap_map_index (test_bit);
398  map_offset    = rtems_rfs_bitmap_map_offset (test_bit);
399  search_index  = rtems_rfs_bitmap_map_index (map_index);
400  search_offset = rtems_rfs_bitmap_map_offset (map_index);
401
402  search_bits = &control->search_bits[search_index];
403  map_bits    = &map[map_index];
404
405  /*
406   * Check each bit from the search map offset for a clear bit.
407   */
408  do
409  {
410    /*
411     * If any bit is clear find that bit and then search the map element. If
412     * all bits are set there are no map bits so move to the next search
413     * element.
414     */
415    if (!rtems_rfs_bitmap_match (*search_bits, RTEMS_RFS_BITMAP_ELEMENT_SET))
416    {
417      while ((search_offset >= 0)
418             && (search_offset < rtems_rfs_bitmap_element_bits ()))
419      {
420        if (!rtems_rfs_bitmap_test (*search_bits, search_offset))
421        {
422          /*
423           * Find the clear bit in the map. Update the search map and map if
424           * found. We may find none are spare if searching up from the seed.
425           */
426          while ((map_offset >= 0)
427                 && (map_offset < rtems_rfs_bitmap_element_bits ()))
428          {
429            if (!rtems_rfs_bitmap_test (*map_bits, map_offset))
430            {
431              *map_bits = rtems_rfs_bitmap_set (*map_bits, 1 << map_offset);
432              if (rtems_rfs_bitmap_match(*map_bits,
433                                         RTEMS_RFS_BITMAP_ELEMENT_SET))
434                *search_bits = rtems_rfs_bitmap_set (*search_bits,
435                                                     1 << search_offset);
436              control->free--;
437              *bit = test_bit;
438              *found = true;
439              rtems_rfs_buffer_mark_dirty (control->buffer);
440              return 0;
441            }
442
443            if (test_bit == end_bit)
444              break;
445
446            map_offset += direction;
447            test_bit   += direction;
448          }
449        }
450
451        map_bits  += direction;
452        map_index += direction;
453        map_offset = direction > 0 ? 0 : rtems_rfs_bitmap_element_bits () - 1;
454
455        test_bit = (map_index * rtems_rfs_bitmap_element_bits ()) + map_offset;
456
457        search_offset += direction;
458
459        if (((direction < 0) && (test_bit <= end_bit))
460            || ((direction > 0) && (test_bit >= end_bit)))
461          break;
462      }
463    }
464    else
465    {
466      /*
467       * Move to the next search element. We need to determine the number of
468       * bits in the search offset that are being skipped so the map bits
469       * pointer can be updated. If we are moving down and we have a search
470       * offset of 0 then the search map adjustment is to the top bit of the
471       * pervious search bit's value.
472       *
473       * Align test_bit either up or down depending on the direction to next 32
474       * bit boundary.
475       */
476      rtems_rfs_bitmap_bit bits_skipped;
477      test_bit &= ~((1 << RTEMS_RFS_ELEMENT_BITS_POWER_2) - 1);
478      if (direction > 0)
479      {
480        bits_skipped = rtems_rfs_bitmap_element_bits () - search_offset;
481        test_bit += bits_skipped * rtems_rfs_bitmap_element_bits ();
482        map_offset = 0;
483      }
484      else
485      {
486        bits_skipped = search_offset + 1;
487        /*
488         * Need to remove 1 for the rounding up. The above rounds down and
489         * adds 1. Remember the logic is for subtraction.
490         */
491        test_bit -= ((bits_skipped - 1) * rtems_rfs_bitmap_element_bits ()) + 1;
492        map_offset = rtems_rfs_bitmap_element_bits () - 1;
493      }
494      map_bits += direction * bits_skipped;
495      map_index += direction * bits_skipped;
496    }
497
498    search_bits  += direction;
499    search_offset = direction > 0 ? 0 : rtems_rfs_bitmap_element_bits () - 1;
500  }
501  while (((direction < 0) && (test_bit >= end_bit))
502         || ((direction > 0) && (test_bit <= end_bit)));
503
504  return 0;
505}
506
507int
508rtems_rfs_bitmap_map_alloc (rtems_rfs_bitmap_control* control,
509                            rtems_rfs_bitmap_bit      seed,
510                            bool*                     allocated,
511                            rtems_rfs_bitmap_bit*     bit)
512{
513  rtems_rfs_bitmap_bit upper_seed;
514  rtems_rfs_bitmap_bit lower_seed;
515  rtems_rfs_bitmap_bit window;     /* may become a parameter */
516  int                  rc = 0;
517
518  /*
519   * By default we assume the allocation failed.
520   */
521  *allocated = false;
522
523  /*
524   * The window is the number of bits we search over in either direction each
525   * time.
526   */
527  window = RTEMS_RFS_BITMAP_SEARCH_WINDOW;
528
529  /*
530   * Start from the seed and move in either direction. Search in window amounts
531   * of bits from the original seed above then below. That is search from the
532   * seed up then from the seed down a window number of bits, then repeat the
533   * process from the window distance from the seed, again above then
534   * below. Keep moving out until all bits have been searched.
535   */
536  upper_seed = seed;
537  lower_seed = seed;
538
539  /*
540   * If the upper and lower seed values have reached the limits of the bitmap
541   * we have searched all of the map. The seed may not be aligned to a window
542   * boundary so we may need to search a partial window and this may also not
543   * be balanced for the upper or lower seeds. We move to the limits, search
544   * then return false if no clear bits are found.
545   */
546  while (((upper_seed >= 0) && (upper_seed < control->size))
547         || ((lower_seed >= 0) && (lower_seed < control->size)))
548  {
549    /*
550     * Search up first so bits allocated in succession are grouped together.
551     */
552    if (upper_seed < control->size)
553    {
554      *bit = upper_seed;
555      rc = rtems_rfs_search_map_for_clear_bit (control, bit, allocated,
556                                               window, 1);
557      if ((rc > 0) || *allocated)
558        break;
559    }
560
561    if (lower_seed >= 0)
562    {
563      *bit = lower_seed;
564      rc = rtems_rfs_search_map_for_clear_bit (control, bit, allocated,
565                                               window, -1);
566      if ((rc > 0) || *allocated)
567        break;
568    }
569
570    /*
571     * Do not bound the limits at the edges of the map. Do not update if an
572     * edge has been passed.
573     */
574    if (upper_seed < control->size)
575      upper_seed += window;
576    if (lower_seed >= 0)
577      lower_seed -= window;
578  }
579
580  return 0;
581}
582
583int
584rtems_rfs_bitmap_create_search (rtems_rfs_bitmap_control* control)
585{
586  rtems_rfs_bitmap_map search_map;
587  rtems_rfs_bitmap_map map;
588  size_t               size;
589  rtems_rfs_bitmap_bit bit;
590  int                  rc;
591
592  rc = rtems_rfs_bitmap_load_map (control, &map);
593  if (rc > 0)
594    return rc;
595
596  control->free = 0;
597  search_map = control->search_bits;
598  size = control->size;
599  bit = 0;
600
601  *search_map = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
602  while (size)
603  {
604    rtems_rfs_bitmap_element bits;
605    int                      available;
606    if (size < rtems_rfs_bitmap_element_bits ())
607    {
608      bits = rtems_rfs_bitmap_merge (*map,
609                                     RTEMS_RFS_BITMAP_ELEMENT_SET,
610                                     rtems_rfs_bitmap_mask_section (0, size));
611      available = size;
612    }
613    else
614    {
615      bits      = *map;
616      available = rtems_rfs_bitmap_element_bits ();
617    }
618
619    if (rtems_rfs_bitmap_match (bits, RTEMS_RFS_BITMAP_ELEMENT_SET))
620      rtems_rfs_bitmap_set (*search_map, bit);
621    else
622    {
623      int b;
624      for (b = 0; b < available; b++)
625        if (!rtems_rfs_bitmap_test (bits, b))
626          control->free++;
627    }
628
629    size -= available;
630
631    /* Iterate from 0 to 1 less than the number of bits in an element */
632    if (bit == (rtems_rfs_bitmap_element_bits () - 1))
633    {
634      bit = 0;
635      search_map++;
636      *search_map = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
637    }
638    else
639      bit++;
640    map++;
641  }
642
643  return 0;
644}
645
646int
647rtems_rfs_bitmap_open (rtems_rfs_bitmap_control* control,
648                       rtems_rfs_file_system*    fs,
649                       rtems_rfs_buffer_handle*  buffer,
650                       size_t                    size,
651                       rtems_rfs_buffer_block    block)
652{
653  size_t elements = rtems_rfs_bitmap_elements (size);
654
655  control->buffer = buffer;
656  control->fs = fs;
657  control->block = block;
658  control->size = size;
659
660  elements = rtems_rfs_bitmap_elements (elements);
661  control->search_bits = malloc (elements * sizeof (rtems_rfs_bitmap_element));
662
663  if (!control->search_bits)
664    return ENOMEM;
665
666  return rtems_rfs_bitmap_create_search (control);
667}
668
669int
670rtems_rfs_bitmap_close (rtems_rfs_bitmap_control* control)
671{
672  free (control->search_bits);
673  return 0;
674}
Note: See TracBrowser for help on using the repository browser.