def device_to_data(device_id, pos, len)
      dev_blk  = device_block(pos)
      dev_off  = device_block_offset(pos)
      data_map = data_mapping.map_for(device_id)

      total_len = 0
      data_blks = []

      num_data_blks = (len / data_block_size).to_i + 1
      0.upto(num_data_blks - 1) do |i|
        current_blk = dev_blk + i
        blk_len = 0

        if data_map.block?(current_blk)
          data_blk = data_map.data_block(current_blk)
          blk_start = data_blk * data_block_size

          if i.zero?
            blk_start += dev_off
            blk_len    = data_block_size - dev_off - 1

          elsif i == num_data_blks - 1
            blk_len = len - total_len

          else
            blk_len = data_block_size
          end

          data_blks << [current_blk, data_blk, blk_start, blk_len]

        # Missing block may be caused by trying to read beyond end of
        # LVM device (too large pos or len):
        else
          remaining  = (len - total_len)
          blk_len    = remaining > data_block_size ? data_block_size : remaining
          data_blks << [current_blk, nil, nil, blk_len]
        end

        total_len += blk_len
      end

      data_blks
    end
def device_to_data(device_id, pos, len)
      dev_blk  = device_block(pos)
      dev_off  = device_block_offset(pos)
      data_map = data_mapping.map_for(device_id)

      total_len = 0
      data_blks = []

      num_data_blks = (len / data_block_size).to_i + 1
      0.upto(num_data_blks - 1) do |i|
        current_blk = dev_blk + i
        blk_len = 0

        if data_map.block?(current_blk)
          data_blk = data_map.data_block(current_blk)
          blk_start = data_blk * data_block_size

          if i.zero?
            blk_start += dev_off
            blk_len    = data_block_size - dev_off - 1

          elsif i == num_data_blks - 1
            blk_len = len - total_len

          else
            blk_len = data_block_size
          end

          data_blks << [current_blk, data_blk, blk_start, blk_len]

        # Missing block may be caused by trying to read beyond end of
        # LVM device (too large pos or len):
        else
          remaining  = (len - total_len)
          blk_len    = remaining > data_block_size ? data_block_size : remaining
          data_blks << [current_blk, nil, nil, blk_len]
        end

        total_len += blk_len
      end

      data_blks
    end
Return array of tuples device block ids, data block ids, addresses, and lengths to
 read from them to read the specified device offset & length.

 Note: data blocks may not amount to total requested length (if requesting
 data from unallocated space).

 @see DataMap#block?