144 lines
5.0 KiB
C
144 lines
5.0 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) 2014-2020 Douglas Gilbert.
|
||
|
|
* All rights reserved.
|
||
|
|
* Use of this source code is governed by a BSD-style
|
||
|
|
* license that can be found in the BSD_LICENSE file.
|
||
|
|
*
|
||
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
||
|
|
*/
|
||
|
|
|
||
|
|
// C standard headers
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#define __STDC_FORMAT_MACROS 1
|
||
|
|
#include <inttypes.h>
|
||
|
|
|
||
|
|
// C++ standard headers
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
// This file is a C++ header file
|
||
|
|
|
||
|
|
|
||
|
|
#define SG_SGL_MAX_ELEMENTS 16384
|
||
|
|
|
||
|
|
#define SG_COUNT_INDEFINITE (-1)
|
||
|
|
#define SG_LBA_INVALID SG_COUNT_INDEFINITE
|
||
|
|
|
||
|
|
// Sizing matches largest SCSI READ and WRITE commands plus those of Unix
|
||
|
|
// read(2)s and write(2)s. User can give larger than 31 bit 'num's but they
|
||
|
|
// are split into several consecutive elements.
|
||
|
|
class scat_gath_elem {
|
||
|
|
public:
|
||
|
|
uint64_t lba; // of start block
|
||
|
|
uint32_t num; // number of blocks from and including start block
|
||
|
|
|
||
|
|
void make_bad() { lba = UINT64_MAX; num = UINT32_MAX; }
|
||
|
|
bool is_bad() const { return (lba == UINT64_MAX && num == UINT32_MAX); }
|
||
|
|
};
|
||
|
|
|
||
|
|
// Consider "linearity" as a scatter gather list property. Elements of this
|
||
|
|
// of from the strongest form to the weakest.
|
||
|
|
enum sgl_linearity_e {
|
||
|
|
SGL_LINEAR = 0, // empty list and 0,0 considered linear
|
||
|
|
SGL_MONOTONIC, // since not linear, implies holes
|
||
|
|
SGL_MONO_OVERLAP, // monotonic but same LBA in two or more elements
|
||
|
|
SGL_NON_MONOTONIC // weakest
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
// Holds one scatter gather list and its associated metadata
|
||
|
|
class scat_gath_list {
|
||
|
|
public:
|
||
|
|
scat_gath_list() : linearity(SGL_LINEAR), sum_hard(false), m_errno(0),
|
||
|
|
high_lba_p1(0), lowest_lba(0), sum(0) { }
|
||
|
|
|
||
|
|
scat_gath_list(const scat_gath_list &) = default;
|
||
|
|
scat_gath_list & operator=(const scat_gath_list &) = default;
|
||
|
|
~scat_gath_list() = default;
|
||
|
|
|
||
|
|
bool empty() const;
|
||
|
|
bool empty_or_00() const;
|
||
|
|
int num_elems() const;
|
||
|
|
int64_t get_lowest_lba(bool ignore_degen, bool always_last) const;
|
||
|
|
int64_t get_low_lba_from_linear() const;
|
||
|
|
bool is_pipe_suitable() const;
|
||
|
|
|
||
|
|
friend bool sgls_eq_off(const scat_gath_list &left, int l_e_ind,
|
||
|
|
int l_blk_off,
|
||
|
|
const scat_gath_list &right, int r_e_ind,
|
||
|
|
int r_blk_off, bool allow_partial);
|
||
|
|
|
||
|
|
bool load_from_cli(const char * cl_p, bool b_vb);
|
||
|
|
bool load_from_file(const char * file_name, bool def_hex, bool flexible,
|
||
|
|
bool b_vb);
|
||
|
|
int append_1or(int64_t extra_blks, int64_t start_lba);
|
||
|
|
int append_1or(int64_t extra_blks);
|
||
|
|
|
||
|
|
void dbg_print(bool skip_meta, const char * id_str, bool to_stdout,
|
||
|
|
bool show_sgl) const;
|
||
|
|
|
||
|
|
// calculates and sets following bool-s and int64_t-s
|
||
|
|
void sum_scan(const char * id_str, bool show_sgl, bool b_verbose);
|
||
|
|
|
||
|
|
void set_weaker_linearity(enum sgl_linearity_e lin);
|
||
|
|
enum sgl_linearity_e linearity;
|
||
|
|
const char * linearity_as_str() const;
|
||
|
|
|
||
|
|
bool sum_hard; // 'num' in last element of 'sgl' is > 0
|
||
|
|
int m_errno; // OS failure errno
|
||
|
|
int64_t high_lba_p1; // highest LBA plus 1, next write from and above
|
||
|
|
int64_t lowest_lba; // initialized to 0
|
||
|
|
int64_t sum; // of all 'num' elements in 'sgl'
|
||
|
|
|
||
|
|
friend int diff_between_iters(const class scat_gath_iter & left,
|
||
|
|
const class scat_gath_iter & right);
|
||
|
|
|
||
|
|
private:
|
||
|
|
friend class scat_gath_iter;
|
||
|
|
|
||
|
|
bool file2sgl_helper(FILE * fp, const char * fnp, bool def_hex,
|
||
|
|
bool flexible, bool b_vb);
|
||
|
|
|
||
|
|
std::vector<scat_gath_elem> sgl; // an array on heap [0..num_elems())
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
class scat_gath_iter {
|
||
|
|
public:
|
||
|
|
explicit scat_gath_iter(const scat_gath_list & my_scat_gath_list);
|
||
|
|
scat_gath_iter(const scat_gath_iter & src) = default;
|
||
|
|
scat_gath_iter& operator=(const scat_gath_iter&) = delete;
|
||
|
|
~scat_gath_iter() = default;
|
||
|
|
|
||
|
|
int64_t current_lba() const;
|
||
|
|
int64_t current_lba_rem_num(int & rem_num) const;
|
||
|
|
class scat_gath_elem current_elem() const;
|
||
|
|
bool at_end() const;
|
||
|
|
bool is_sgl_linear() const; // the whole list
|
||
|
|
// Should return 1 or more unless max_n<=0 or at_end()
|
||
|
|
int linear_for_n_blks(int max_n) const;
|
||
|
|
|
||
|
|
bool set_by_blk_idx(int64_t _blk_idx);
|
||
|
|
// add/sub blocks return true if they reach EOL/start, else false
|
||
|
|
bool add_blks(uint64_t blk_count);
|
||
|
|
bool sub_blks(uint64_t blk_count);
|
||
|
|
|
||
|
|
void dbg_print(const char * id_str, bool to_stdout, int verbose) const;
|
||
|
|
|
||
|
|
friend int diff_between_iters(const class scat_gath_iter & left,
|
||
|
|
const class scat_gath_iter & right);
|
||
|
|
|
||
|
|
friend bool sgls_eq_from_iters(const class scat_gath_iter & left,
|
||
|
|
const class scat_gath_iter & right,
|
||
|
|
bool allow_partial);
|
||
|
|
|
||
|
|
private:
|
||
|
|
const scat_gath_list &sglist;
|
||
|
|
|
||
|
|
// dual representation: either it_el_ind,it_blk_off or blk_idx
|
||
|
|
int it_el_ind; // refers to sge==sglist[it_el_ind]
|
||
|
|
int it_blk_off; // refers to LBA==(sge.lba + it_blk_off)
|
||
|
|
int64_t blk_idx; // in range: [0 .. sglist.sum)
|
||
|
|
bool extend_last;
|
||
|
|
};
|