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

5
Last change on this file since cfe8f7a was cfe8f7a, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/20 at 14:14:06

doxygen: Switch @brief and @ingroup

This order change fixes the Latex documentation build via Doxygen.

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