// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Author: Gabriel BenHanokh * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "simple_bitmap.h" #include "include/ceph_assert.h" #include "bluestore_types.h" #include "common/debug.h" #define dout_context cct #define dout_subsys ceph_subsys_bluestore #undef dout_prefix #define dout_prefix *_dout << __func__ << "::SBMAP::" << this << " " static struct extent_t null_extent = {0, 0}; //---------------------------------------------------------------------------- //throw bad_alloc SimpleBitmap::SimpleBitmap(CephContext *_cct, uint64_t num_bits) :cct(_cct) { m_num_bits = num_bits; m_word_count = bits_to_words(num_bits); if (num_bits & BITS_IN_WORD_MASK) { m_word_count++; } m_arr = new uint64_t [m_word_count]; clear_all(); } //---------------------------------------------------------------------------- SimpleBitmap::~SimpleBitmap() { delete [] m_arr; } //---------------------------------------------------------------------------- bool SimpleBitmap::set(uint64_t offset, uint64_t length) { dout(20) <<" [" << std::hex << offset << ", " << length << "]" << dendl; if (offset + length > m_num_bits) { derr << __func__ << "::offset + length = " << offset + length << " exceeds map size = " << m_num_bits << dendl; ceph_assert(offset + length <= m_num_bits); return false; } auto [word_index, first_bit_set] = split(offset); // special case optimization if (length == 1) { uint64_t set_mask = 1ULL << first_bit_set; m_arr[word_index] |= set_mask; return true; } // handle the first word which might be incomplete if (first_bit_set != 0) { uint64_t set_mask = FULL_MASK << first_bit_set; uint64_t first_bit_clr = first_bit_set + length; if (first_bit_clr <= BITS_IN_WORD) { if (first_bit_clr < BITS_IN_WORD) { uint64_t clr_bits = BITS_IN_WORD - first_bit_clr; uint64_t clr_mask = FULL_MASK >> clr_bits; set_mask &= clr_mask; } m_arr[word_index] |= set_mask; return true; } else { // set all bits in this word starting from first_bit_set m_arr[word_index] |= set_mask; word_index ++; length -= (BITS_IN_WORD - first_bit_set); } } // set a range of full words uint64_t full_words_count = bits_to_words(length); uint64_t end = word_index + full_words_count; for (; word_index < end; word_index++) { m_arr[word_index] = FULL_MASK; } length -= words_to_bits(full_words_count); // set bits in the last word if (length) { uint64_t set_mask = ~(FULL_MASK << length); m_arr[word_index] |= set_mask; } return true; } //---------------------------------------------------------------------------- bool SimpleBitmap::clr(uint64_t offset, uint64_t length) { if (offset + length > m_num_bits) { derr << __func__ << "::offset + length = " << offset + length << " exceeds map size = " << m_num_bits << dendl; ceph_assert(offset + length <= m_num_bits); return false; } auto [word_index, first_bit_clr] = split(offset); // special case optimization if (length == 1) { uint64_t set_mask = 1ULL << first_bit_clr; uint64_t clr_mask = ~set_mask; m_arr[word_index] &= clr_mask; return true; } // handle the first word when we we are unaligned on word boundaries if (first_bit_clr != 0) { uint64_t clr_mask = ~(FULL_MASK << first_bit_clr); uint64_t first_bit_set = first_bit_clr + length; // special case - we only work on a single word if (first_bit_set <= BITS_IN_WORD) { if (first_bit_set < BITS_IN_WORD) { uint64_t set_mask = FULL_MASK << first_bit_set; clr_mask |= set_mask; } m_arr[word_index] &= clr_mask; return true; } else { // clear all bits in this word starting from first_bit_clr // and continue to the next word m_arr[word_index] &= clr_mask; word_index ++; length -= (BITS_IN_WORD - first_bit_clr); } } // clear a range of full words uint64_t full_words_count = bits_to_words(length); uint64_t end = word_index + full_words_count; for (; word_index < end; word_index++) { m_arr[word_index] = 0; } length -= words_to_bits(full_words_count); // set bits in the last word if (length) { uint64_t clr_mask = (FULL_MASK << length); m_arr[word_index] &= clr_mask; } return true; } //---------------------------------------------------------------------------- extent_t SimpleBitmap::get_next_set_extent(uint64_t offset) { if (offset >= m_num_bits ) { return null_extent; } auto [word_idx, bits_to_clear] = split(offset); uint64_t word = m_arr[word_idx]; word &= (FULL_MASK << bits_to_clear); // if there are no set bits in this word if (word == 0) { // skip past all clear words while (++word_idx < m_word_count && !m_arr[word_idx]); if (word_idx < m_word_count ) { word = m_arr[word_idx]; } else { return null_extent; } } // ffs is 1 based, must dec by one as we are zero based int ffs = __builtin_ffsll(word) - 1; extent_t ext; ext.offset = words_to_bits(word_idx) + ffs; if (ext.offset >= m_num_bits ) { return null_extent; } // set all bits from current to LSB uint64_t clr_mask = FULL_MASK << ffs; uint64_t set_mask = ~clr_mask; word |= set_mask; // skipped past fully set words if (word == FULL_MASK) { while ( (++word_idx < m_word_count) && (m_arr[word_idx] == FULL_MASK) ); if (word_idx < m_word_count) { word = m_arr[word_idx]; } else { // bitmap is set from ext.offset until the last bit ext.length = (m_num_bits - ext.offset); return ext; } } ceph_assert(word != FULL_MASK); int ffz = __builtin_ffsll(~word) - 1; uint64_t zoffset = words_to_bits(word_idx) + ffz; ext.length = (zoffset - ext.offset); return ext; } //---------------------------------------------------------------------------- extent_t SimpleBitmap::get_next_clr_extent(uint64_t offset) { if (offset >= m_num_bits ) { return null_extent; } uint64_t word_idx = offset_to_index(offset); uint64_t word = m_arr[word_idx]; // set all bit set before offset offset &= BITS_IN_WORD_MASK; if (offset != 0) { uint64_t bits_to_set = BITS_IN_WORD - offset; uint64_t set_mask = FULL_MASK >> bits_to_set; word |= set_mask; } if (word == FULL_MASK) { // skipped past fully set words while ( (++word_idx < m_word_count) && (m_arr[word_idx] == FULL_MASK) ); if (word_idx < m_word_count) { word = m_arr[word_idx]; } else { dout(10) << "2)Reached the end of the bitmap" << dendl; return null_extent; } } int ffz = __builtin_ffsll(~word) - 1; extent_t ext; ext.offset = words_to_bits(word_idx) + ffz; if (ext.offset >= m_num_bits ) { return null_extent; } // clear all bits from current position to LSB word &= (FULL_MASK << ffz); // skip past all clear words if (word == 0) { while ( (++word_idx < m_word_count) && (m_arr[word_idx] == 0) ); if (word_idx < m_word_count) { word = m_arr[word_idx]; } else { // bitmap is set from ext.offset until the last bit ext.length = (m_num_bits - ext.offset); return ext; } } // ffs is 1 based, must dec by one as we are zero based int ffs = __builtin_ffsll(word) - 1; uint64_t soffset = words_to_bits(word_idx) + ffs; ext.length = (soffset - ext.offset); return ext; }