xref: /aosp_15_r20/external/sg3_utils/testing/sg_scat_gath.cpp (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2014-2020 Douglas Gilbert.
3*44704f69SBart Van Assche  * All rights reserved.
4*44704f69SBart Van Assche  * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche  * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche  *
7*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche  *
9*44704f69SBart Van Assche  * Version 1.02 [20201124]
10*44704f69SBart Van Assche  */
11*44704f69SBart Van Assche 
12*44704f69SBart Van Assche // C headers
13*44704f69SBart Van Assche #include <stdio.h>
14*44704f69SBart Van Assche #include <stdint.h>
15*44704f69SBart Van Assche #include <string.h>
16*44704f69SBart Van Assche #include <limits.h>
17*44704f69SBart Van Assche #include <ctype.h>
18*44704f69SBart Van Assche #include <errno.h>
19*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
20*44704f69SBart Van Assche #include <inttypes.h>
21*44704f69SBart Van Assche 
22*44704f69SBart Van Assche // C++ headers
23*44704f69SBart Van Assche #include <array>
24*44704f69SBart Van Assche 
25*44704f69SBart Van Assche #include "sg_scat_gath.h"
26*44704f69SBart Van Assche #include "sg_lib.h"
27*44704f69SBart Van Assche #include "sg_pr2serr.h"
28*44704f69SBart Van Assche 
29*44704f69SBart Van Assche using namespace std;
30*44704f69SBart Van Assche 
31*44704f69SBart Van Assche #define MAX_SGL_NUM_VAL (INT32_MAX - 1)  /* should reduce for testing */
32*44704f69SBart Van Assche // #define MAX_SGL_NUM_VAL 7  /* should reduce for testing */
33*44704f69SBart Van Assche #if MAX_SGL_NUM_VAL > INT32_MAX
34*44704f69SBart Van Assche #error "MAX_SGL_NUM_VAL cannot exceed 2^31 - 1"
35*44704f69SBart Van Assche #endif
36*44704f69SBart Van Assche 
37*44704f69SBart Van Assche bool
empty() const38*44704f69SBart Van Assche scat_gath_list::empty() const
39*44704f69SBart Van Assche {
40*44704f69SBart Van Assche     return sgl.empty();
41*44704f69SBart Van Assche }
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche bool
empty_or_00() const44*44704f69SBart Van Assche scat_gath_list::empty_or_00() const
45*44704f69SBart Van Assche {
46*44704f69SBart Van Assche     if (sgl.empty())
47*44704f69SBart Van Assche         return true;
48*44704f69SBart Van Assche     return ((sgl.size() == 1) && (sgl[0].lba == 0) && (sgl[0].num == 0));
49*44704f69SBart Van Assche }
50*44704f69SBart Van Assche 
51*44704f69SBart Van Assche int
num_elems() const52*44704f69SBart Van Assche scat_gath_list::num_elems() const
53*44704f69SBart Van Assche {
54*44704f69SBart Van Assche     return sgl.size();
55*44704f69SBart Van Assche }
56*44704f69SBart Van Assche 
57*44704f69SBart Van Assche 
58*44704f69SBart Van Assche /* Read numbers (up to 64 bits in size) from command line (comma (or
59*44704f69SBart Van Assche  * (single) space **) separated list). Assumed decimal unless prefixed
60*44704f69SBart Van Assche  * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
61*44704f69SBart Van Assche  * Returns 0 if ok, or 1 if error. Assumed to be LBA (64 bit) and
62*44704f69SBart Van Assche  * number_of_block (32 bit) pairs. ** Space on command line needs to
63*44704f69SBart Van Assche  * be escaped, otherwise it is an operand/option separator. */
64*44704f69SBart Van Assche bool
load_from_cli(const char * cl_p,bool b_vb)65*44704f69SBart Van Assche scat_gath_list::load_from_cli(const char * cl_p, bool b_vb)
66*44704f69SBart Van Assche {
67*44704f69SBart Van Assche     bool split, full_pair;
68*44704f69SBart Van Assche     int in_len, k, j;
69*44704f69SBart Van Assche     const int max_nbs = MAX_SGL_NUM_VAL;
70*44704f69SBart Van Assche     int64_t ll, large_num;
71*44704f69SBart Van Assche     uint64_t prev_lba;
72*44704f69SBart Van Assche     char * cp;
73*44704f69SBart Van Assche     char * c2p;
74*44704f69SBart Van Assche     const char * lcp;
75*44704f69SBart Van Assche     class scat_gath_elem sge;
76*44704f69SBart Van Assche 
77*44704f69SBart Van Assche     if (NULL == cl_p) {
78*44704f69SBart Van Assche         pr2serr("%s: bad arguments\n", __func__);
79*44704f69SBart Van Assche         goto err_out;
80*44704f69SBart Van Assche     }
81*44704f69SBart Van Assche     lcp = cl_p;
82*44704f69SBart Van Assche     in_len = strlen(cl_p);
83*44704f69SBart Van Assche     if ('-' == cl_p[0]) {        /* read from stdin */
84*44704f69SBart Van Assche         pr2serr("%s: logic error: no stdin here\n", __func__);
85*44704f69SBart Van Assche         goto err_out;
86*44704f69SBart Van Assche     } else {        /* list of numbers (default decimal) on command line */
87*44704f69SBart Van Assche         k = strspn(cl_p, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
88*44704f69SBart Van Assche         if (in_len != k) {
89*44704f69SBart Van Assche             if (b_vb)
90*44704f69SBart Van Assche                 pr2serr("%s: error at pos %d\n", __func__, k + 1);
91*44704f69SBart Van Assche             goto err_out;
92*44704f69SBart Van Assche         }
93*44704f69SBart Van Assche         j = 0;
94*44704f69SBart Van Assche         full_pair = true;
95*44704f69SBart Van Assche         for (k = 0, split = false; ; ++k) {
96*44704f69SBart Van Assche             if (split) {
97*44704f69SBart Van Assche                 /* splitting given elem with large number_of_blocks into
98*44704f69SBart Van Assche                  * multiple elems within array being built */
99*44704f69SBart Van Assche                 ++j;
100*44704f69SBart Van Assche                 sge.lba = prev_lba + (uint64_t)max_nbs;
101*44704f69SBart Van Assche                 if (large_num > max_nbs) {
102*44704f69SBart Van Assche                     sge.num = (uint32_t)max_nbs;
103*44704f69SBart Van Assche                     prev_lba = sge.lba;
104*44704f69SBart Van Assche                     large_num -= max_nbs;
105*44704f69SBart Van Assche                     sgl.push_back(sge);
106*44704f69SBart Van Assche                 } else {
107*44704f69SBart Van Assche                     sge.num = (uint32_t)large_num;
108*44704f69SBart Van Assche                     split = false;
109*44704f69SBart Van Assche                     if (b_vb)
110*44704f69SBart Van Assche                         pr2serr("%s: split large sg elem into %d element%s\n",
111*44704f69SBart Van Assche                                 __func__, j, (j == 1 ? "" : "s"));
112*44704f69SBart Van Assche                     sgl.push_back(sge);
113*44704f69SBart Van Assche                     goto check_for_next;
114*44704f69SBart Van Assche                 }
115*44704f69SBart Van Assche                 continue;
116*44704f69SBart Van Assche             }
117*44704f69SBart Van Assche             full_pair = false;
118*44704f69SBart Van Assche             ll = sg_get_llnum(lcp);
119*44704f69SBart Van Assche             if (-1 != ll) {
120*44704f69SBart Van Assche                 sge.lba = (uint64_t)ll;
121*44704f69SBart Van Assche                 cp = (char *)strchr(lcp, ',');
122*44704f69SBart Van Assche                 c2p = (char *)strchr(lcp, ' ');
123*44704f69SBart Van Assche                 if (NULL == cp) {
124*44704f69SBart Van Assche                     cp = c2p;
125*44704f69SBart Van Assche                     if (NULL == cp)
126*44704f69SBart Van Assche                         break;
127*44704f69SBart Van Assche                 }
128*44704f69SBart Van Assche                 if (c2p && (c2p < cp))
129*44704f69SBart Van Assche                     cp = c2p;
130*44704f69SBart Van Assche                 lcp = cp + 1;
131*44704f69SBart Van Assche             } else {
132*44704f69SBart Van Assche                 if (b_vb)
133*44704f69SBart Van Assche                     pr2serr("%s: error at pos %d\n", __func__,
134*44704f69SBart Van Assche                             (int)(lcp - cl_p + 1));
135*44704f69SBart Van Assche                 goto err_out;
136*44704f69SBart Van Assche             }
137*44704f69SBart Van Assche             ll = sg_get_llnum(lcp);
138*44704f69SBart Van Assche             if (ll >= 0) {
139*44704f69SBart Van Assche                 full_pair = true;
140*44704f69SBart Van Assche                 if (ll > max_nbs) {
141*44704f69SBart Van Assche                     sge.num = (uint32_t)max_nbs;
142*44704f69SBart Van Assche                     prev_lba = sge.lba;
143*44704f69SBart Van Assche                     large_num = ll - max_nbs;
144*44704f69SBart Van Assche                     split = true;
145*44704f69SBart Van Assche                     j = 1;
146*44704f69SBart Van Assche                     continue;
147*44704f69SBart Van Assche                 }
148*44704f69SBart Van Assche                 sge.num = (uint32_t)ll;
149*44704f69SBart Van Assche             } else {    /* bad or negative number as number_of_blocks */
150*44704f69SBart Van Assche                 if (b_vb)
151*44704f69SBart Van Assche                     pr2serr("%s: bad number at pos %d\n", __func__,
152*44704f69SBart Van Assche                             (int)(lcp - cl_p + 1));
153*44704f69SBart Van Assche                 goto err_out;
154*44704f69SBart Van Assche             }
155*44704f69SBart Van Assche             sgl.push_back(sge);
156*44704f69SBart Van Assche check_for_next:
157*44704f69SBart Van Assche             cp = (char *)strchr(lcp, ',');
158*44704f69SBart Van Assche             c2p = (char *)strchr(lcp, ' ');
159*44704f69SBart Van Assche             if (NULL == cp) {
160*44704f69SBart Van Assche                 cp = c2p;
161*44704f69SBart Van Assche                 if (NULL == cp)
162*44704f69SBart Van Assche                     break;
163*44704f69SBart Van Assche             }
164*44704f69SBart Van Assche             if (c2p && (c2p < cp))
165*44704f69SBart Van Assche                 cp = c2p;
166*44704f69SBart Van Assche             lcp = cp + 1;
167*44704f69SBart Van Assche         }       /* end of for loop over items in operand */
168*44704f69SBart Van Assche         /* other than first pair, expect even number of items */
169*44704f69SBart Van Assche         if ((k > 0) && (! full_pair)) {
170*44704f69SBart Van Assche             if (b_vb)
171*44704f69SBart Van Assche                 pr2serr("%s:  expected even number of items: "
172*44704f69SBart Van Assche                         "LBA0,NUM0,LBA1,NUM1...\n", __func__);
173*44704f69SBart Van Assche             goto err_out;
174*44704f69SBart Van Assche         }
175*44704f69SBart Van Assche     }
176*44704f69SBart Van Assche     return true;
177*44704f69SBart Van Assche err_out:
178*44704f69SBart Van Assche     if (0 == m_errno)
179*44704f69SBart Van Assche         m_errno = SG_LIB_SYNTAX_ERROR;
180*44704f69SBart Van Assche     return false;
181*44704f69SBart Van Assche }
182*44704f69SBart Van Assche 
183*44704f69SBart Van Assche bool
file2sgl_helper(FILE * fp,const char * fnp,bool def_hex,bool flexible,bool b_vb)184*44704f69SBart Van Assche scat_gath_list::file2sgl_helper(FILE * fp, const char * fnp, bool def_hex,
185*44704f69SBart Van Assche                                 bool flexible, bool b_vb)
186*44704f69SBart Van Assche {
187*44704f69SBart Van Assche     bool bit0;
188*44704f69SBart Van Assche     bool pre_addr1 = true;
189*44704f69SBart Van Assche     bool pre_hex_seen = false;
190*44704f69SBart Van Assche     int in_len, k, j, m, ind;
191*44704f69SBart Van Assche     const int max_nbs = MAX_SGL_NUM_VAL;
192*44704f69SBart Van Assche     int off = 0;
193*44704f69SBart Van Assche     int64_t ll;
194*44704f69SBart Van Assche     uint64_t ull, prev_lba;
195*44704f69SBart Van Assche     char * lcp;
196*44704f69SBart Van Assche     class scat_gath_elem sge;
197*44704f69SBart Van Assche     char line[1024];
198*44704f69SBart Van Assche 
199*44704f69SBart Van Assche     for (j = 0 ; ; ++j) {
200*44704f69SBart Van Assche         if (NULL == fgets(line, sizeof(line), fp))
201*44704f69SBart Van Assche             break;
202*44704f69SBart Van Assche         // could improve with carry_over logic if sizeof(line) too small
203*44704f69SBart Van Assche         in_len = strlen(line);
204*44704f69SBart Van Assche         if (in_len > 0) {
205*44704f69SBart Van Assche             if ('\n' == line[in_len - 1]) {
206*44704f69SBart Van Assche                 --in_len;
207*44704f69SBart Van Assche                 line[in_len] = '\0';
208*44704f69SBart Van Assche             } else {
209*44704f69SBart Van Assche                 m_errno = SG_LIB_SYNTAX_ERROR;
210*44704f69SBart Van Assche                 if (b_vb)
211*44704f69SBart Van Assche                     pr2serr("%s: %s: line too long, max %d bytes\n",
212*44704f69SBart Van Assche                             __func__, fnp, (int)(sizeof(line) - 1));
213*44704f69SBart Van Assche                 goto err_out;
214*44704f69SBart Van Assche             }
215*44704f69SBart Van Assche         }
216*44704f69SBart Van Assche         if (in_len < 1)
217*44704f69SBart Van Assche             continue;
218*44704f69SBart Van Assche         lcp = line;
219*44704f69SBart Van Assche         m = strspn(lcp, " \t");
220*44704f69SBart Van Assche         if (m == in_len)
221*44704f69SBart Van Assche             continue;
222*44704f69SBart Van Assche         lcp += m;
223*44704f69SBart Van Assche         in_len -= m;
224*44704f69SBart Van Assche         if ('#' == *lcp)
225*44704f69SBart Van Assche             continue;
226*44704f69SBart Van Assche         if (pre_addr1 || pre_hex_seen) {
227*44704f69SBart Van Assche             /* Accept lines with leading 'HEX' and ignore as long as there
228*44704f69SBart Van Assche              * is one _before_ any LBA,NUM lines in the file. This allows
229*44704f69SBart Van Assche              * HEX marked sgls to be concaternated together. */
230*44704f69SBart Van Assche             if (('H' == toupper(lcp[0])) && ('E' == toupper(lcp[1])) &&
231*44704f69SBart Van Assche                 ('X' == toupper(lcp[2]))) {
232*44704f69SBart Van Assche                 pre_hex_seen = true;
233*44704f69SBart Van Assche                 if (def_hex)
234*44704f69SBart Van Assche                     continue; /* bypass 'HEX' marker line if expecting hex */
235*44704f69SBart Van Assche                 else {
236*44704f69SBart Van Assche                     if (flexible) {
237*44704f69SBart Van Assche                         def_hex = true; /* okay, switch to hex parse */
238*44704f69SBart Van Assche                         continue;
239*44704f69SBart Van Assche                     } else {
240*44704f69SBart Van Assche                         pr2serr("%s: %s: 'hex' string detected on line %d, "
241*44704f69SBart Van Assche                                 "expecting decimal\n", __func__, fnp, j + 1);
242*44704f69SBart Van Assche                         m_errno = EINVAL;
243*44704f69SBart Van Assche                         goto err_out;
244*44704f69SBart Van Assche                     }
245*44704f69SBart Van Assche                 }
246*44704f69SBart Van Assche             }
247*44704f69SBart Van Assche         }
248*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXbBdDiIkKmMgGtTpP, \t");
249*44704f69SBart Van Assche         if ((k < in_len) && ('#' != lcp[k])) {
250*44704f69SBart Van Assche             m_errno = EINVAL;
251*44704f69SBart Van Assche             if (b_vb)
252*44704f69SBart Van Assche                 pr2serr("%s: %s: syntax error at line %d, pos %d\n",
253*44704f69SBart Van Assche                         __func__, fnp, j + 1, m + k + 1);
254*44704f69SBart Van Assche             goto err_out;
255*44704f69SBart Van Assche         }
256*44704f69SBart Van Assche         for (k = 0; k < 256; ++k) {
257*44704f69SBart Van Assche             /* limit parseable items on one line to 256 */
258*44704f69SBart Van Assche             if (def_hex) {      /* don't accept negatives or multipliers */
259*44704f69SBart Van Assche                 if (1 == sscanf(lcp, "%" SCNx64, &ull))
260*44704f69SBart Van Assche                     ll = (int64_t)ull;
261*44704f69SBart Van Assche                 else
262*44704f69SBart Van Assche                     ll = -1;    /* use (2**64 - 1) as error flag */
263*44704f69SBart Van Assche             } else
264*44704f69SBart Van Assche                 ll = sg_get_llnum(lcp);
265*44704f69SBart Van Assche             if (-1 != ll) {
266*44704f69SBart Van Assche                 ind = ((off + k) >> 1);
267*44704f69SBart Van Assche                 bit0 = !! (0x1 & (off + k));
268*44704f69SBart Van Assche                 if (ind >= SG_SGL_MAX_ELEMENTS) {
269*44704f69SBart Van Assche                     m_errno = EINVAL;
270*44704f69SBart Van Assche                     if (b_vb)
271*44704f69SBart Van Assche                         pr2serr("%s: %s: array length exceeded\n", __func__,
272*44704f69SBart Van Assche                                 fnp);
273*44704f69SBart Van Assche                     goto err_out;
274*44704f69SBart Van Assche                 }
275*44704f69SBart Van Assche                 if (bit0) {     /* bit0 set when decoding a NUM */
276*44704f69SBart Van Assche                     if (ll < 0) {
277*44704f69SBart Van Assche                         m_errno = EINVAL;
278*44704f69SBart Van Assche                         if (b_vb)
279*44704f69SBart Van Assche                             pr2serr("%s: %s: bad number in line %d, at pos "
280*44704f69SBart Van Assche                                     "%d\n", __func__, fnp, j + 1,
281*44704f69SBart Van Assche                                     (int)(lcp - line + 1));
282*44704f69SBart Van Assche                         goto err_out;
283*44704f69SBart Van Assche                     }
284*44704f69SBart Van Assche                     if (ll > max_nbs) {
285*44704f69SBart Van Assche                         int h = 1;
286*44704f69SBart Van Assche 
287*44704f69SBart Van Assche                         /* split up this elem into multiple, smaller elems */
288*44704f69SBart Van Assche                         do {
289*44704f69SBart Van Assche                             sge.num = (uint32_t)max_nbs;
290*44704f69SBart Van Assche                             prev_lba = sge.lba;
291*44704f69SBart Van Assche                             sgl.push_back(sge);
292*44704f69SBart Van Assche                             sge.lba = prev_lba + (uint64_t)max_nbs;
293*44704f69SBart Van Assche                             ++h;
294*44704f69SBart Van Assche                             off += 2;
295*44704f69SBart Van Assche                             ll -= max_nbs;
296*44704f69SBart Van Assche                         } while (ll > max_nbs);
297*44704f69SBart Van Assche                         if (b_vb)
298*44704f69SBart Van Assche                             pr2serr("%s: split large sg elem into %d "
299*44704f69SBart Van Assche                                     "elements\n", __func__, h);
300*44704f69SBart Van Assche                     }
301*44704f69SBart Van Assche                     sge.num = (uint32_t)ll;
302*44704f69SBart Van Assche                     sgl.push_back(sge);
303*44704f69SBart Van Assche                 } else {        /* bit0 clear when decoding a LBA */
304*44704f69SBart Van Assche                     if (pre_addr1)
305*44704f69SBart Van Assche                         pre_addr1 = false;
306*44704f69SBart Van Assche                     sge.lba = (uint64_t)ll;
307*44704f69SBart Van Assche                 }
308*44704f69SBart Van Assche             } else {    /* failed to decode number on line */
309*44704f69SBart Van Assche                 if ('#' == *lcp) { /* numbers before #, rest of line comment */
310*44704f69SBart Van Assche                     --k;
311*44704f69SBart Van Assche                     break;      /* goes to next line */
312*44704f69SBart Van Assche                 }
313*44704f69SBart Van Assche                 m_errno = EINVAL;
314*44704f69SBart Van Assche                 if (b_vb)
315*44704f69SBart Van Assche                     pr2serr("%s: %s: error in line %d, at pos %d\n",
316*44704f69SBart Van Assche                             __func__, fnp, j + 1, (int)(lcp - line + 1));
317*44704f69SBart Van Assche                 goto err_out;
318*44704f69SBart Van Assche             }
319*44704f69SBart Van Assche             lcp = strpbrk(lcp, " ,\t#");
320*44704f69SBart Van Assche             if ((NULL == lcp) || ('#' == *lcp))
321*44704f69SBart Van Assche                 break;
322*44704f69SBart Van Assche             lcp += strspn(lcp, " ,\t");
323*44704f69SBart Van Assche             if ('\0' == *lcp)
324*44704f69SBart Van Assche                 break;
325*44704f69SBart Van Assche         }       /* <<< end of for(k < 256) loop */
326*44704f69SBart Van Assche         off += (k + 1);
327*44704f69SBart Van Assche     }   /* <<< end of for loop, one iteration per line */
328*44704f69SBart Van Assche     /* allow one items, but not higher odd number of items */
329*44704f69SBart Van Assche     if ((off > 1) && (0x1 & off)) {
330*44704f69SBart Van Assche         m_errno = EINVAL;
331*44704f69SBart Van Assche         if (b_vb)
332*44704f69SBart Van Assche             pr2serr("%s: %s: expect even number of items: "
333*44704f69SBart Van Assche                     "LBA0,NUM0,LBA1,NUM1...\n", __func__, fnp);
334*44704f69SBart Van Assche         goto err_out;
335*44704f69SBart Van Assche     }
336*44704f69SBart Van Assche     clearerr(fp);    /* even EOF on first pass needs this before rescan */
337*44704f69SBart Van Assche     return true;
338*44704f69SBart Van Assche err_out:
339*44704f69SBart Van Assche     clearerr(fp);
340*44704f69SBart Van Assche     return false;
341*44704f69SBart Van Assche }
342*44704f69SBart Van Assche 
343*44704f69SBart Van Assche /* Read numbers from filename (or stdin), line by line (comma (or (single)
344*44704f69SBart Van Assche  * space) separated list); places starting_LBA,number_of_block pairs in an
345*44704f69SBart Van Assche  * array of scat_gath_elem elements pointed to by the returned value. If
346*44704f69SBart Van Assche  * this fails NULL is returned and an error number is written to errp (if it
347*44704f69SBart Van Assche  * is non-NULL). Assumed decimal (and may have suffix multipliers) when
348*44704f69SBart Van Assche  * def_hex==false; if a number is prefixed by '0x', '0X' or contains trailing
349*44704f69SBart Van Assche  * 'h' or 'H' that denotes a hex number. When def_hex==true all numbers are
350*44704f69SBart Van Assche  * assumed to be hex (ignored '0x' prefixes and 'h' suffixes) and multipliers
351*44704f69SBart Van Assche  * are not permitted. Heap allocates an array just big enough to hold all
352*44704f69SBart Van Assche  * elements if the file is countable. Pipes and stdin are not considered
353*44704f69SBart Van Assche  * countable. In the non-countable case an array of MAX_FIXED_SGL_ELEMS
354*44704f69SBart Van Assche  * elements is pre-allocated; if it is exceeded sg_convert_errno(EDOM) is
355*44704f69SBart Van Assche  * placed in *errp (if it is non-NULL). One of the first actions is to write
356*44704f69SBart Van Assche  * 0 to *errp (if it is non-NULL) so the caller does not need to zero it
357*44704f69SBart Van Assche  * before calling. */
358*44704f69SBart Van Assche bool
load_from_file(const char * file_name,bool def_hex,bool flexible,bool b_vb)359*44704f69SBart Van Assche scat_gath_list::load_from_file(const char * file_name, bool def_hex,
360*44704f69SBart Van Assche                                bool flexible, bool b_vb)
361*44704f69SBart Van Assche {
362*44704f69SBart Van Assche     bool have_stdin;
363*44704f69SBart Van Assche     bool have_err = false;
364*44704f69SBart Van Assche     FILE * fp;
365*44704f69SBart Van Assche     const char * fnp;
366*44704f69SBart Van Assche 
367*44704f69SBart Van Assche     have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0]));
368*44704f69SBart Van Assche     if (have_stdin) {
369*44704f69SBart Van Assche         fp = stdin;
370*44704f69SBart Van Assche         fnp = "<stdin>";
371*44704f69SBart Van Assche     } else {
372*44704f69SBart Van Assche         fnp = file_name;
373*44704f69SBart Van Assche         fp = fopen(fnp, "r");
374*44704f69SBart Van Assche         if (NULL == fp) {
375*44704f69SBart Van Assche             m_errno = errno;
376*44704f69SBart Van Assche             if (b_vb)
377*44704f69SBart Van Assche                 pr2serr("%s: opening %s: %s\n", __func__, fnp,
378*44704f69SBart Van Assche                         safe_strerror(m_errno));
379*44704f69SBart Van Assche             return false;
380*44704f69SBart Van Assche         }
381*44704f69SBart Van Assche     }
382*44704f69SBart Van Assche     if (! file2sgl_helper(fp, fnp, def_hex, flexible, b_vb))
383*44704f69SBart Van Assche         have_err = true;
384*44704f69SBart Van Assche     if (! have_stdin)
385*44704f69SBart Van Assche         fclose(fp);
386*44704f69SBart Van Assche     return have_err ? false : true;
387*44704f69SBart Van Assche }
388*44704f69SBart Van Assche 
389*44704f69SBart Van Assche const char *
linearity_as_str() const390*44704f69SBart Van Assche scat_gath_list::linearity_as_str() const
391*44704f69SBart Van Assche {
392*44704f69SBart Van Assche     switch (linearity) {
393*44704f69SBart Van Assche     case SGL_LINEAR:
394*44704f69SBart Van Assche         return "linear";
395*44704f69SBart Van Assche     case SGL_MONOTONIC:
396*44704f69SBart Van Assche         return "monotonic";
397*44704f69SBart Van Assche     case SGL_MONO_OVERLAP:
398*44704f69SBart Van Assche         return "monotonic, overlapping";
399*44704f69SBart Van Assche     case SGL_NON_MONOTONIC:
400*44704f69SBart Van Assche         return "non-monotonic";
401*44704f69SBart Van Assche     default:
402*44704f69SBart Van Assche         return "unknown";
403*44704f69SBart Van Assche     }
404*44704f69SBart Van Assche }
405*44704f69SBart Van Assche 
406*44704f69SBart Van Assche void
set_weaker_linearity(enum sgl_linearity_e lin)407*44704f69SBart Van Assche scat_gath_list::set_weaker_linearity(enum sgl_linearity_e lin)
408*44704f69SBart Van Assche {
409*44704f69SBart Van Assche     int i_lin = (int)lin;
410*44704f69SBart Van Assche 
411*44704f69SBart Van Assche     if (i_lin > (int)linearity)
412*44704f69SBart Van Assche         linearity = lin;
413*44704f69SBart Van Assche }
414*44704f69SBart Van Assche 
415*44704f69SBart Van Assche /* id_str may be NULL (if so replace by "unknown"), present to enhance verbose
416*44704f69SBart Van Assche  * output. */
417*44704f69SBart Van Assche void
dbg_print(bool skip_meta,const char * id_str,bool to_stdout,bool show_sgl) const418*44704f69SBart Van Assche scat_gath_list::dbg_print(bool skip_meta, const char * id_str, bool to_stdout,
419*44704f69SBart Van Assche                           bool show_sgl) const
420*44704f69SBart Van Assche {
421*44704f69SBart Van Assche     int num = sgl.size();
422*44704f69SBart Van Assche     const char * caller = id_str ? id_str : "unknown";
423*44704f69SBart Van Assche     FILE * fp = to_stdout ? stdout : stderr;
424*44704f69SBart Van Assche 
425*44704f69SBart Van Assche     if (! skip_meta) {
426*44704f69SBart Van Assche         fprintf(fp, "%s: elems=%d, sgl %spresent, linearity=%s\n",
427*44704f69SBart Van Assche                 caller, num, (sgl.empty() ? "not " : ""),
428*44704f69SBart Van Assche                 linearity_as_str());
429*44704f69SBart Van Assche         fprintf(fp, "  sum=%" PRId64 ", sum_hard=%s lowest=0x%" PRIx64
430*44704f69SBart Van Assche                 ", high_lba_p1=", sum, (sum_hard ? "true" : "false"),
431*44704f69SBart Van Assche                 lowest_lba);
432*44704f69SBart Van Assche         fprintf(fp, "0x%" PRIx64 "\n", high_lba_p1);
433*44704f69SBart Van Assche     }
434*44704f69SBart Van Assche     fprintf(fp, "  >> %s scatter gather list (%d element%s):\n", caller, num,
435*44704f69SBart Van Assche             (num == 1 ? "" : "s"));
436*44704f69SBart Van Assche     if (show_sgl) {
437*44704f69SBart Van Assche         int k;
438*44704f69SBart Van Assche 
439*44704f69SBart Van Assche         for (k = 0; k < num; ++k) {
440*44704f69SBart Van Assche             const class scat_gath_elem & sge = sgl[k];
441*44704f69SBart Van Assche 
442*44704f69SBart Van Assche             fprintf(fp, "    lba: 0x%" PRIx64 ", number: 0x%" PRIx32,
443*44704f69SBart Van Assche                     sge.lba, sge.num);
444*44704f69SBart Van Assche             if (sge.lba > 0)
445*44704f69SBart Van Assche                 fprintf(fp, " [next lba: 0x%" PRIx64 "]", sge.lba + sge.num);
446*44704f69SBart Van Assche             fprintf(fp, "\n");
447*44704f69SBart Van Assche         }
448*44704f69SBart Van Assche     }
449*44704f69SBart Van Assche }
450*44704f69SBart Van Assche 
451*44704f69SBart Van Assche /* Assumes sgl array (vector) is setup. The other fields in this object are
452*44704f69SBart Van Assche  * set by analyzing sgl in a single pass. The fields that are set are:
453*44704f69SBart Van Assche  * fragmented, lowest_lba, high_lba_p1, monotonic, overlapping, sum and
454*44704f69SBart Van Assche  * sum_hard. Degenerate elements (i.e. those with 0 blocks) are ignored apart
455*44704f69SBart Van Assche  * from when one is last which makes sum_hard false and its LBA becomes
456*44704f69SBart Van Assche  * high_lba_p1 if it is the highest in the list. An empty sgl is equivalent
457*44704f69SBart Van Assche  * to a 1 element list with [0, 0], so sum_hard==false, monit==true,
458*44704f69SBart Van Assche  * fragmented==false and overlapping==false . id_str may be NULL, present
459*44704f69SBart Van Assche  * to enhance verbose output. */
460*44704f69SBart Van Assche void
sum_scan(const char * id_str,bool show_sgl,bool b_vb)461*44704f69SBart Van Assche scat_gath_list::sum_scan(const char * id_str, bool show_sgl, bool b_vb)
462*44704f69SBart Van Assche {
463*44704f69SBart Van Assche     bool degen = false;
464*44704f69SBart Van Assche     bool first = true;
465*44704f69SBart Van Assche     bool regular = true;        /* no overlapping segments detected */
466*44704f69SBart Van Assche     int k;
467*44704f69SBart Van Assche     int elems = sgl.size();
468*44704f69SBart Van Assche     uint32_t prev_num, t_num;
469*44704f69SBart Van Assche     uint64_t prev_lba, t_lba, low, high, end;
470*44704f69SBart Van Assche 
471*44704f69SBart Van Assche     sum = 0;
472*44704f69SBart Van Assche     for (k = 0, low = 0, high = 0; k < elems; ++k) {
473*44704f69SBart Van Assche         const class scat_gath_elem & sge = sgl[k];
474*44704f69SBart Van Assche 
475*44704f69SBart Van Assche         degen = false;
476*44704f69SBart Van Assche         t_num = sge.num;
477*44704f69SBart Van Assche         if (0 == t_num) {
478*44704f69SBart Van Assche             degen = true;
479*44704f69SBart Van Assche             if (! first)
480*44704f69SBart Van Assche                 continue;       /* ignore degen element that not first */
481*44704f69SBart Van Assche         }
482*44704f69SBart Van Assche         if (first) {
483*44704f69SBart Van Assche             low = sge.lba;
484*44704f69SBart Van Assche             sum = t_num;
485*44704f69SBart Van Assche             high = sge.lba + sge.num;
486*44704f69SBart Van Assche             first = false;
487*44704f69SBart Van Assche         } else {
488*44704f69SBart Van Assche             t_lba = sge.lba;
489*44704f69SBart Van Assche             if ((prev_lba + prev_num) != t_lba)
490*44704f69SBart Van Assche                 set_weaker_linearity(SGL_MONOTONIC);
491*44704f69SBart Van Assche             sum += t_num;
492*44704f69SBart Van Assche             end = t_lba + t_num;
493*44704f69SBart Van Assche             if (end > high)
494*44704f69SBart Van Assche                 high = end;     /* high is one plus highest LBA */
495*44704f69SBart Van Assche             if (prev_lba < t_lba)
496*44704f69SBart Van Assche                 ;
497*44704f69SBart Van Assche             else if (prev_lba == t_lba) {
498*44704f69SBart Van Assche                 if (prev_num > 0) {
499*44704f69SBart Van Assche                     set_weaker_linearity(SGL_MONO_OVERLAP);
500*44704f69SBart Van Assche                     break;
501*44704f69SBart Van Assche                 }
502*44704f69SBart Van Assche             } else {
503*44704f69SBart Van Assche                 low = t_lba;
504*44704f69SBart Van Assche                 set_weaker_linearity(SGL_NON_MONOTONIC);
505*44704f69SBart Van Assche                 break;
506*44704f69SBart Van Assche             }
507*44704f69SBart Van Assche             if (regular) {
508*44704f69SBart Van Assche                 if ((prev_lba + prev_num) > t_lba)
509*44704f69SBart Van Assche                     regular = false;
510*44704f69SBart Van Assche             }
511*44704f69SBart Van Assche         }
512*44704f69SBart Van Assche         prev_lba = sge.lba;
513*44704f69SBart Van Assche         prev_num = sge.num;
514*44704f69SBart Van Assche     }           /* end of for loop while still elements and monot true */
515*44704f69SBart Van Assche 
516*44704f69SBart Van Assche     if (k < elems) {    /* only here if above breaks are taken */
517*44704f69SBart Van Assche         prev_lba = t_lba;
518*44704f69SBart Van Assche         ++k;
519*44704f69SBart Van Assche         for ( ; k < elems; ++k) {
520*44704f69SBart Van Assche             const class scat_gath_elem & sge = sgl[k];
521*44704f69SBart Van Assche 
522*44704f69SBart Van Assche             degen = false;
523*44704f69SBart Van Assche             t_lba = sge.lba;
524*44704f69SBart Van Assche             t_num = sge.num;
525*44704f69SBart Van Assche             if (0 == t_num) {
526*44704f69SBart Van Assche                 degen = true;
527*44704f69SBart Van Assche                 continue;
528*44704f69SBart Van Assche             }
529*44704f69SBart Van Assche             sum += t_num;
530*44704f69SBart Van Assche             end = t_lba + t_num;
531*44704f69SBart Van Assche             if (end > high)
532*44704f69SBart Van Assche                 high = end;
533*44704f69SBart Van Assche             if (prev_lba > t_lba) {
534*44704f69SBart Van Assche                 if (t_lba < low)
535*44704f69SBart Van Assche                     low = t_lba;
536*44704f69SBart Van Assche             }
537*44704f69SBart Van Assche             prev_lba = t_lba;
538*44704f69SBart Van Assche         }
539*44704f69SBart Van Assche     } else
540*44704f69SBart Van Assche         if (! regular)
541*44704f69SBart Van Assche             set_weaker_linearity(SGL_MONO_OVERLAP);
542*44704f69SBart Van Assche 
543*44704f69SBart Van Assche     lowest_lba = low;
544*44704f69SBart Van Assche     if (degen && (elems > 0)) { /* last element always impacts high_lba_p1 */
545*44704f69SBart Van Assche         t_lba = sgl[elems - 1].lba;
546*44704f69SBart Van Assche         high_lba_p1 = (t_lba > high) ? t_lba : high;
547*44704f69SBart Van Assche     } else
548*44704f69SBart Van Assche         high_lba_p1 = high;
549*44704f69SBart Van Assche     sum_hard = (elems > 0) ? ! degen : false;
550*44704f69SBart Van Assche     if (b_vb)
551*44704f69SBart Van Assche         dbg_print(false, id_str, false, show_sgl);
552*44704f69SBart Van Assche }
553*44704f69SBart Van Assche 
554*44704f69SBart Van Assche /* Usually will append (or add to start if empty) sge unless 'extra_blks'
555*44704f69SBart Van Assche  * exceeds MAX_SGL_NUM_VAL. In that case multiple sge_s are added with
556*44704f69SBart Van Assche  * sge.num = MAX_SGL_NUM_VAL or less (for final sge) until extra_blks is
557*44704f69SBart Van Assche  * exhausted. Returns new size of scatter gather list. */
558*44704f69SBart Van Assche int
append_1or(int64_t extra_blks,int64_t start_lba)559*44704f69SBart Van Assche scat_gath_list::append_1or(int64_t extra_blks, int64_t start_lba)
560*44704f69SBart Van Assche {
561*44704f69SBart Van Assche     int o_num = sgl.size();
562*44704f69SBart Van Assche     const int max_nbs = MAX_SGL_NUM_VAL;
563*44704f69SBart Van Assche     int64_t cnt = 0;
564*44704f69SBart Van Assche     class scat_gath_elem sge;
565*44704f69SBart Van Assche 
566*44704f69SBart Van Assche     if ((extra_blks <= 0) && (start_lba < 0))
567*44704f69SBart Van Assche         return o_num;       /* nothing to do */
568*44704f69SBart Van Assche     if ((o_num > 0) && (! sum_hard)) {
569*44704f69SBart Van Assche         sge = sgl[o_num - 1];   /* assume sge.num==0 */
570*44704f69SBart Van Assche         if (sge.lba == (uint64_t)start_lba) {
571*44704f69SBart Van Assche             if (extra_blks <= max_nbs)
572*44704f69SBart Van Assche                 sge.num = extra_blks;
573*44704f69SBart Van Assche             else
574*44704f69SBart Van Assche                 sge.num = max_nbs;
575*44704f69SBart Van Assche             sgl[o_num - 1] = sge;
576*44704f69SBart Van Assche             cnt = sge.num;
577*44704f69SBart Van Assche             sum += cnt;
578*44704f69SBart Van Assche             sum_hard = true;
579*44704f69SBart Van Assche             if (cnt <= extra_blks) {
580*44704f69SBart Van Assche                 high_lba_p1 = sge.lba + cnt;
581*44704f69SBart Van Assche                 return o_num;
582*44704f69SBart Van Assche             }
583*44704f69SBart Van Assche         }
584*44704f69SBart Van Assche     } else if (0 == o_num) {
585*44704f69SBart Van Assche         lowest_lba = start_lba;
586*44704f69SBart Van Assche         if (0 == extra_blks) {
587*44704f69SBart Van Assche             sge.lba = start_lba;
588*44704f69SBart Van Assche             sge.num = 0;
589*44704f69SBart Van Assche             sgl.push_back(sge);
590*44704f69SBart Van Assche             high_lba_p1 = sge.lba;
591*44704f69SBart Van Assche             return sgl.size();
592*44704f69SBart Van Assche         }
593*44704f69SBart Van Assche     }
594*44704f69SBart Van Assche     for ( ; cnt < extra_blks; cnt += max_nbs) {
595*44704f69SBart Van Assche         sge.lba = start_lba + cnt;
596*44704f69SBart Van Assche         if ((extra_blks - cnt) <= max_nbs)
597*44704f69SBart Van Assche             sge.num = extra_blks - cnt;
598*44704f69SBart Van Assche         else
599*44704f69SBart Van Assche             sge.num = max_nbs;
600*44704f69SBart Van Assche         sgl.push_back(sge);
601*44704f69SBart Van Assche         sum += sge.num;
602*44704f69SBart Van Assche     }           /* always loops at least once */
603*44704f69SBart Van Assche     sum_hard = true;
604*44704f69SBart Van Assche     high_lba_p1 = sge.lba + sge.num;
605*44704f69SBart Van Assche     return sgl.size();
606*44704f69SBart Van Assche }
607*44704f69SBart Van Assche 
608*44704f69SBart Van Assche int
append_1or(int64_t extra_blks)609*44704f69SBart Van Assche scat_gath_list::append_1or(int64_t extra_blks)
610*44704f69SBart Van Assche {
611*44704f69SBart Van Assche     int o_num = sgl.size();
612*44704f69SBart Van Assche 
613*44704f69SBart Van Assche     if (o_num < 1)
614*44704f69SBart Van Assche         return append_1or(extra_blks, 0);
615*44704f69SBart Van Assche 
616*44704f69SBart Van Assche     class scat_gath_elem sge = sgl[o_num - 1];
617*44704f69SBart Van Assche 
618*44704f69SBart Van Assche     return append_1or(extra_blks, sge.lba + sge.num);
619*44704f69SBart Van Assche }
620*44704f69SBart Van Assche 
621*44704f69SBart Van Assche 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)622*44704f69SBart Van Assche sgls_eq_off(const scat_gath_list & left, int l_e_ind, int l_blk_off,
623*44704f69SBart Van Assche             const scat_gath_list & right, int r_e_ind, int r_blk_off,
624*44704f69SBart Van Assche             bool allow_partial)
625*44704f69SBart Van Assche {
626*44704f69SBart Van Assche     int lelems = left.sgl.size();
627*44704f69SBart Van Assche     int relems = right.sgl.size();
628*44704f69SBart Van Assche 
629*44704f69SBart Van Assche     while ((l_e_ind < lelems) && (r_e_ind < relems)) {
630*44704f69SBart Van Assche         if ((left.sgl[l_e_ind].lba + l_blk_off) !=
631*44704f69SBart Van Assche             (right.sgl[r_e_ind].lba + r_blk_off))
632*44704f69SBart Van Assche             return false;
633*44704f69SBart Van Assche 
634*44704f69SBart Van Assche         int lrem = left.sgl[l_e_ind].num - l_blk_off;
635*44704f69SBart Van Assche         int rrem = right.sgl[r_e_ind].num - r_blk_off;
636*44704f69SBart Van Assche 
637*44704f69SBart Van Assche         if (lrem == rrem) {
638*44704f69SBart Van Assche             ++l_e_ind;
639*44704f69SBart Van Assche             l_blk_off = 0;
640*44704f69SBart Van Assche             ++r_e_ind;
641*44704f69SBart Van Assche             r_blk_off = 0;
642*44704f69SBart Van Assche         } else if (lrem < rrem) {
643*44704f69SBart Van Assche             ++l_e_ind;
644*44704f69SBart Van Assche             l_blk_off = 0;
645*44704f69SBart Van Assche             r_blk_off += lrem;
646*44704f69SBart Van Assche         } else {
647*44704f69SBart Van Assche             ++r_e_ind;
648*44704f69SBart Van Assche             r_blk_off = 0;
649*44704f69SBart Van Assche             l_blk_off += rrem;
650*44704f69SBart Van Assche         }
651*44704f69SBart Van Assche     }
652*44704f69SBart Van Assche     if ((l_e_ind >= lelems) && (r_e_ind >= relems))
653*44704f69SBart Van Assche         return true;
654*44704f69SBart Van Assche     return allow_partial;
655*44704f69SBart Van Assche }
656*44704f69SBart Van Assche 
657*44704f69SBart Van Assche /* If bad arguments returns -1, otherwise returns the lowest LBA in *sglp .
658*44704f69SBart Van Assche  * If no elements considered returns 0. If ignore_degen is true than
659*44704f69SBart Van Assche  * ignores all elements with sge.num zero unless always_last is also
660*44704f69SBart Van Assche  * true in which case the last element is always considered. */
661*44704f69SBart Van Assche int64_t
get_lowest_lba(bool ignore_degen,bool always_last) const662*44704f69SBart Van Assche scat_gath_list::get_lowest_lba(bool ignore_degen, bool always_last) const
663*44704f69SBart Van Assche {
664*44704f69SBart Van Assche     int k;
665*44704f69SBart Van Assche     const int num_elems = sgl.size();
666*44704f69SBart Van Assche     bool some = (num_elems > 0);
667*44704f69SBart Van Assche     int64_t res = INT64_MAX;
668*44704f69SBart Van Assche 
669*44704f69SBart Van Assche     for (k = 0; k < num_elems; ++k) {
670*44704f69SBart Van Assche         if ((0 == sgl[k].num) && ignore_degen)
671*44704f69SBart Van Assche             continue;
672*44704f69SBart Van Assche         if ((int64_t)sgl[k].lba < res)
673*44704f69SBart Van Assche             res = sgl[k].lba;
674*44704f69SBart Van Assche     }
675*44704f69SBart Van Assche     if (always_last && some) {
676*44704f69SBart Van Assche         if ((int64_t)sgl[k - 1].lba < res)
677*44704f69SBart Van Assche             res = sgl[k - 1].lba;
678*44704f69SBart Van Assche     }
679*44704f69SBart Van Assche     return (INT64_MAX == res) ? 0 : res;
680*44704f69SBart Van Assche }
681*44704f69SBart Van Assche 
682*44704f69SBart Van Assche /* Returns >= 0 if sgl can be simplified to a single LBA. So an empty sgl
683*44704f69SBart Van Assche  * will return 0; a one element sgl will return its LBA. A multiple element
684*44704f69SBart Van Assche  * sgl only returns the first element's LBA (that is not degenerate) if the
685*44704f69SBart Van Assche  * sgl is monotonic and not fragmented. In the extreme case takes last
686*44704f69SBart Van Assche  * element's LBA if all prior elements are degenerate. Else returns -1 .
687*44704f69SBart Van Assche  * Assumes sgl_sum_scan() has been called. */
688*44704f69SBart Van Assche int64_t
get_low_lba_from_linear() const689*44704f69SBart Van Assche scat_gath_list::get_low_lba_from_linear() const
690*44704f69SBart Van Assche {
691*44704f69SBart Van Assche     const int num_elems = sgl.size();
692*44704f69SBart Van Assche     int k;
693*44704f69SBart Van Assche 
694*44704f69SBart Van Assche     if (num_elems <= 1)
695*44704f69SBart Van Assche         return (1 == num_elems) ? sgl[0].lba : 0;
696*44704f69SBart Van Assche     else {
697*44704f69SBart Van Assche         if (linearity == SGL_LINEAR) {
698*44704f69SBart Van Assche             for (k = 0; k < (num_elems - 1); ++k) {
699*44704f69SBart Van Assche                 if (sgl[k].num > 0)
700*44704f69SBart Van Assche                     return sgl[k].lba;
701*44704f69SBart Van Assche             }
702*44704f69SBart Van Assche             /* take last element's LBA if all earlier are degenerate */
703*44704f69SBart Van Assche             return sgl[k].lba;
704*44704f69SBart Van Assche         } else
705*44704f69SBart Van Assche             return -1;
706*44704f69SBart Van Assche     }
707*44704f69SBart Van Assche }
708*44704f69SBart Van Assche 
709*44704f69SBart Van Assche bool
is_pipe_suitable() const710*44704f69SBart Van Assche scat_gath_list::is_pipe_suitable() const
711*44704f69SBart Van Assche {
712*44704f69SBart Van Assche     return (lowest_lba == 0) && (linearity == SGL_LINEAR);
713*44704f69SBart Van Assche }
714*44704f69SBart Van Assche 
scat_gath_iter(const scat_gath_list & parent)715*44704f69SBart Van Assche scat_gath_iter::scat_gath_iter(const scat_gath_list & parent)
716*44704f69SBart Van Assche     : sglist(parent), it_el_ind(0), it_blk_off(0), blk_idx(0)
717*44704f69SBart Van Assche {
718*44704f69SBart Van Assche     int elems = sglist.num_elems();
719*44704f69SBart Van Assche 
720*44704f69SBart Van Assche     if (elems > 0)
721*44704f69SBart Van Assche         extend_last = (0 == sglist.sgl[elems - 1].num);
722*44704f69SBart Van Assche }
723*44704f69SBart Van Assche 
724*44704f69SBart Van Assche bool
set_by_blk_idx(int64_t _blk_idx)725*44704f69SBart Van Assche scat_gath_iter::set_by_blk_idx(int64_t _blk_idx)
726*44704f69SBart Van Assche {
727*44704f69SBart Van Assche     bool first;
728*44704f69SBart Van Assche     int k;
729*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
730*44704f69SBart Van Assche     const int last_ind = elems - 1;
731*44704f69SBart Van Assche     int64_t bc = _blk_idx;
732*44704f69SBart Van Assche 
733*44704f69SBart Van Assche     if (bc < 0)
734*44704f69SBart Van Assche         return false;
735*44704f69SBart Van Assche 
736*44704f69SBart Van Assche     if (bc == blk_idx)
737*44704f69SBart Van Assche         return true;
738*44704f69SBart Van Assche     else if (bc > blk_idx) {
739*44704f69SBart Van Assche         k = it_el_ind;
740*44704f69SBart Van Assche         bc -= blk_idx;
741*44704f69SBart Van Assche     } else
742*44704f69SBart Van Assche         k = 0;
743*44704f69SBart Van Assche     for (first = true; k < elems; ++k, first = false) {
744*44704f69SBart Van Assche         uint32_t num = ((k == last_ind) && extend_last) ? MAX_SGL_NUM_VAL :
745*44704f69SBart Van Assche                                                           sglist.sgl[k].num;
746*44704f69SBart Van Assche         if (first) {
747*44704f69SBart Van Assche             if ((int64_t)(num - it_blk_off) < bc)
748*44704f69SBart Van Assche                 bc -= (num - it_blk_off);
749*44704f69SBart Van Assche             else {
750*44704f69SBart Van Assche                 it_blk_off = bc + it_blk_off;
751*44704f69SBart Van Assche                 break;
752*44704f69SBart Van Assche             }
753*44704f69SBart Van Assche         } else {
754*44704f69SBart Van Assche             if ((int64_t)num < bc)
755*44704f69SBart Van Assche                 bc -= num;
756*44704f69SBart Van Assche             else {
757*44704f69SBart Van Assche                 it_blk_off = (uint32_t)bc;
758*44704f69SBart Van Assche                 break;
759*44704f69SBart Van Assche             }
760*44704f69SBart Van Assche         }
761*44704f69SBart Van Assche     }
762*44704f69SBart Van Assche     it_el_ind = k;
763*44704f69SBart Van Assche     blk_idx = _blk_idx;
764*44704f69SBart Van Assche 
765*44704f69SBart Van Assche     if (k < elems)
766*44704f69SBart Van Assche         return true;
767*44704f69SBart Van Assche     else if ((k == elems) && (0 == it_blk_off))
768*44704f69SBart Van Assche         return true;    /* EOL */
769*44704f69SBart Van Assche     else
770*44704f69SBart Van Assche         return false;
771*44704f69SBart Van Assche }
772*44704f69SBart Van Assche 
773*44704f69SBart Van Assche /* Given a blk_count, the iterator (*iter_p) is moved toward the EOL.
774*44704f69SBart Van Assche  * Returns true unless blk_count takes iterator two or more past the last
775*44704f69SBart Van Assche  * element. So if blk_count takes the iterator to the EOL, this function
776*44704f69SBart Van Assche  * returns true. Takes into account iterator's extend_last flag. */
777*44704f69SBart Van Assche bool
add_blks(uint64_t blk_count)778*44704f69SBart Van Assche scat_gath_iter::add_blks(uint64_t blk_count)
779*44704f69SBart Van Assche {
780*44704f69SBart Van Assche     bool first;
781*44704f69SBart Van Assche     int k;
782*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
783*44704f69SBart Van Assche     const int last_ind = elems - 1;
784*44704f69SBart Van Assche     uint64_t bc = blk_count;
785*44704f69SBart Van Assche 
786*44704f69SBart Van Assche     if (0 == bc)
787*44704f69SBart Van Assche         return true;
788*44704f69SBart Van Assche     for (first = true, k = it_el_ind; k < elems; ++k) {
789*44704f69SBart Van Assche         uint32_t num = ((k == last_ind) && extend_last) ? MAX_SGL_NUM_VAL :
790*44704f69SBart Van Assche                                                           sglist.sgl[k].num;
791*44704f69SBart Van Assche         if (first) {
792*44704f69SBart Van Assche             first = false;
793*44704f69SBart Van Assche             if ((uint64_t)(num - it_blk_off) <= bc)
794*44704f69SBart Van Assche                 bc -= (num - it_blk_off);
795*44704f69SBart Van Assche             else {
796*44704f69SBart Van Assche                 it_blk_off = bc + it_blk_off;
797*44704f69SBart Van Assche                 break;
798*44704f69SBart Van Assche             }
799*44704f69SBart Van Assche         } else {
800*44704f69SBart Van Assche             if ((uint64_t)num <= bc)
801*44704f69SBart Van Assche                 bc -= num;
802*44704f69SBart Van Assche             else {
803*44704f69SBart Van Assche                 it_blk_off = (uint32_t)bc;
804*44704f69SBart Van Assche                 break;
805*44704f69SBart Van Assche             }
806*44704f69SBart Van Assche         }
807*44704f69SBart Van Assche     }
808*44704f69SBart Van Assche     it_el_ind = k;
809*44704f69SBart Van Assche     blk_idx += blk_count;
810*44704f69SBart Van Assche 
811*44704f69SBart Van Assche     if (k < elems)
812*44704f69SBart Van Assche         return true;
813*44704f69SBart Van Assche     else if ((k == elems) && (0 == it_blk_off))
814*44704f69SBart Van Assche         return true;    /* EOL */
815*44704f69SBart Van Assche     else
816*44704f69SBart Van Assche         return false;
817*44704f69SBart Van Assche }
818*44704f69SBart Van Assche 
819*44704f69SBart Van Assche /* Move the iterator from its current position (which may be to EOL) towards
820*44704f69SBart Van Assche  * the start of the sgl (i.e. backwards) for blk_count blocks. Returns true
821*44704f69SBart Van Assche  * if iterator is valid after the move, else returns false. N.B. if false is
822*44704f69SBart Van Assche  * returned, then the iterator is invalid and may need to set it to a valid
823*44704f69SBart Van Assche  * value. */
824*44704f69SBart Van Assche bool
sub_blks(uint64_t blk_count)825*44704f69SBart Van Assche scat_gath_iter::sub_blks(uint64_t blk_count)
826*44704f69SBart Van Assche {
827*44704f69SBart Van Assche     bool first;
828*44704f69SBart Van Assche     int k = it_el_ind;
829*44704f69SBart Van Assche     uint64_t bc = 0;
830*44704f69SBart Van Assche     const uint64_t orig_blk_count = blk_count;
831*44704f69SBart Van Assche 
832*44704f69SBart Van Assche     if (0 == blk_count)
833*44704f69SBart Van Assche         return true;
834*44704f69SBart Van Assche     for (first = true; k >= 0; --k) {
835*44704f69SBart Van Assche         if (first) {
836*44704f69SBart Van Assche             if (blk_count > (uint64_t)it_blk_off)
837*44704f69SBart Van Assche                 blk_count -= it_blk_off;
838*44704f69SBart Van Assche             else {
839*44704f69SBart Van Assche                 it_blk_off -= blk_count;
840*44704f69SBart Van Assche                 break;
841*44704f69SBart Van Assche             }
842*44704f69SBart Van Assche             first = false;
843*44704f69SBart Van Assche         } else {
844*44704f69SBart Van Assche             uint32_t off = sglist.sgl[k].num;
845*44704f69SBart Van Assche 
846*44704f69SBart Van Assche             bc = blk_count;
847*44704f69SBart Van Assche             if (bc > (uint64_t)off)
848*44704f69SBart Van Assche                 blk_count -= off;
849*44704f69SBart Van Assche             else {
850*44704f69SBart Van Assche                 bc = off - bc;
851*44704f69SBart Van Assche                 break;
852*44704f69SBart Van Assche             }
853*44704f69SBart Van Assche         }
854*44704f69SBart Van Assche     }
855*44704f69SBart Van Assche     if (k < 0) {
856*44704f69SBart Van Assche         blk_idx = 0;
857*44704f69SBart Van Assche         it_blk_off = 0;
858*44704f69SBart Van Assche         return false;           /* bad situation */
859*44704f69SBart Van Assche     }
860*44704f69SBart Van Assche     if ((int64_t)orig_blk_count <= blk_idx)
861*44704f69SBart Van Assche         blk_idx -= orig_blk_count;
862*44704f69SBart Van Assche     else
863*44704f69SBart Van Assche         blk_idx = 0;
864*44704f69SBart Van Assche     it_el_ind = k;
865*44704f69SBart Van Assche     if (! first)
866*44704f69SBart Van Assche         it_blk_off = (uint32_t)bc;
867*44704f69SBart Van Assche     return true;
868*44704f69SBart Van Assche }
869*44704f69SBart Van Assche 
870*44704f69SBart Van Assche /* Returns LBA referred to by iterator if valid or returns SG_LBA_INVALID
871*44704f69SBart Van Assche  * (-1) if at end or invalid. */
872*44704f69SBart Van Assche int64_t
current_lba() const873*44704f69SBart Van Assche scat_gath_iter::current_lba() const
874*44704f69SBart Van Assche {
875*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
876*44704f69SBart Van Assche     int64_t res = SG_LBA_INVALID; /* for at end or invalid (-1) */
877*44704f69SBart Van Assche 
878*44704f69SBart Van Assche     if (it_el_ind < elems) {
879*44704f69SBart Van Assche         class scat_gath_elem sge = sglist.sgl[it_el_ind];
880*44704f69SBart Van Assche 
881*44704f69SBart Van Assche         if ((uint32_t)it_blk_off < sge.num)
882*44704f69SBart Van Assche             return sge.lba + it_blk_off;
883*44704f69SBart Van Assche         else if (((uint32_t)it_blk_off == sge.num) &&
884*44704f69SBart Van Assche                  ((it_el_ind + 1) < elems)) {
885*44704f69SBart Van Assche             class scat_gath_iter iter(*this);
886*44704f69SBart Van Assche 
887*44704f69SBart Van Assche             ++iter.it_el_ind;
888*44704f69SBart Van Assche             iter.it_blk_off = 0;
889*44704f69SBart Van Assche             /* worst case recursion will stop at end of sgl */
890*44704f69SBart Van Assche             return iter.current_lba();
891*44704f69SBart Van Assche         }
892*44704f69SBart Van Assche     }
893*44704f69SBart Van Assche     return res;
894*44704f69SBart Van Assche }
895*44704f69SBart Van Assche 
896*44704f69SBart Van Assche int64_t
current_lba_rem_num(int & rem_num) const897*44704f69SBart Van Assche scat_gath_iter::current_lba_rem_num(int & rem_num) const
898*44704f69SBart Van Assche {
899*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
900*44704f69SBart Van Assche     int64_t res = SG_LBA_INVALID; /* for at end or invalid (-1) */
901*44704f69SBart Van Assche 
902*44704f69SBart Van Assche     if (it_el_ind < elems) {
903*44704f69SBart Van Assche         class scat_gath_elem sge = sglist.sgl[it_el_ind];
904*44704f69SBart Van Assche 
905*44704f69SBart Van Assche         if ((uint32_t)it_blk_off < sge.num) {
906*44704f69SBart Van Assche             rem_num = sge.num - it_blk_off;
907*44704f69SBart Van Assche             return sge.lba + it_blk_off;
908*44704f69SBart Van Assche         } else if (((uint32_t)it_blk_off == sge.num) &&
909*44704f69SBart Van Assche                  ((it_el_ind + 1) < elems)) {
910*44704f69SBart Van Assche             class scat_gath_iter iter(*this);
911*44704f69SBart Van Assche 
912*44704f69SBart Van Assche             ++iter.it_el_ind;
913*44704f69SBart Van Assche             iter.it_blk_off = 0;
914*44704f69SBart Van Assche             /* worst case recursion will stop at end of sgl */
915*44704f69SBart Van Assche             return iter.current_lba_rem_num(rem_num);
916*44704f69SBart Van Assche         }
917*44704f69SBart Van Assche     }
918*44704f69SBart Van Assche     rem_num = -1;
919*44704f69SBart Van Assche     return res;
920*44704f69SBart Van Assche }
921*44704f69SBart Van Assche 
922*44704f69SBart Van Assche class scat_gath_elem
current_elem() const923*44704f69SBart Van Assche scat_gath_iter::current_elem() const
924*44704f69SBart Van Assche {
925*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
926*44704f69SBart Van Assche     class scat_gath_elem sge;
927*44704f69SBart Van Assche 
928*44704f69SBart Van Assche     sge.make_bad();
929*44704f69SBart Van Assche     if (it_el_ind < elems)
930*44704f69SBart Van Assche         return sglist.sgl[it_el_ind];
931*44704f69SBart Van Assche     return sge;
932*44704f69SBart Van Assche }
933*44704f69SBart Van Assche 
934*44704f69SBart Van Assche /* Returns true of no sgl or sgl is at the end [elems, 0], otherwise it
935*44704f69SBart Van Assche  * returns false. */
936*44704f69SBart Van Assche bool
at_end() const937*44704f69SBart Van Assche scat_gath_iter::at_end() const
938*44704f69SBart Van Assche {
939*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
940*44704f69SBart Van Assche 
941*44704f69SBart Van Assche     return ((0 == elems) || ((it_el_ind == elems) && (0 == it_blk_off)));
942*44704f69SBart Van Assche }
943*44704f69SBart Van Assche 
944*44704f69SBart Van Assche /* Returns true if associated iterator is monotonic (increasing) and not
945*44704f69SBart Van Assche  * fragmented. Empty sgl and single element degenerate considered linear.
946*44704f69SBart Van Assche  * Assumes sgl_sum_scan() has been called on sgl. */
947*44704f69SBart Van Assche bool
is_sgl_linear() const948*44704f69SBart Van Assche scat_gath_iter::is_sgl_linear() const
949*44704f69SBart Van Assche {
950*44704f69SBart Van Assche     return sglist.linearity == SGL_LINEAR;
951*44704f69SBart Van Assche }
952*44704f69SBart Van Assche 
953*44704f69SBart Van Assche /* Should return 1 or more unless max_n<=0 or at_end() */
954*44704f69SBart Van Assche int
linear_for_n_blks(int max_n) const955*44704f69SBart Van Assche scat_gath_iter::linear_for_n_blks(int max_n) const
956*44704f69SBart Van Assche {
957*44704f69SBart Van Assche     int k, rem;
958*44704f69SBart Van Assche     const int elems = sglist.sgl.size();
959*44704f69SBart Van Assche     uint64_t prev_lba;
960*44704f69SBart Van Assche     class scat_gath_elem sge;
961*44704f69SBart Van Assche 
962*44704f69SBart Van Assche     if (at_end() || (max_n <= 0))
963*44704f69SBart Van Assche         return 0;
964*44704f69SBart Van Assche     sge = sglist.sgl[it_el_ind];
965*44704f69SBart Van Assche     rem = (int)sge.num - it_blk_off;
966*44704f69SBart Van Assche     if (rem <= 0) {
967*44704f69SBart Van Assche         sge = sglist.sgl[it_el_ind + 1];
968*44704f69SBart Van Assche         rem = (int)sge.num;
969*44704f69SBart Van Assche     }
970*44704f69SBart Van Assche     if (max_n <= rem)
971*44704f69SBart Van Assche         return max_n;
972*44704f69SBart Van Assche     prev_lba = sge.lba + sge.num;
973*44704f69SBart Van Assche     for (k = it_el_ind + 1; k < elems; ++k) {
974*44704f69SBart Van Assche         sge = sglist.sgl[k];
975*44704f69SBart Van Assche         if (sge.lba != prev_lba)
976*44704f69SBart Van Assche             return rem;
977*44704f69SBart Van Assche         rem += sge.num;
978*44704f69SBart Van Assche         if (max_n <= rem)
979*44704f69SBart Van Assche             return max_n;
980*44704f69SBart Van Assche         prev_lba = sge.lba + sge.num;
981*44704f69SBart Van Assche     }
982*44704f69SBart Van Assche     return rem;
983*44704f69SBart Van Assche }
984*44704f69SBart Van Assche 
985*44704f69SBart Van Assche /* id_str may be NULL (if so replace by "unknown"), present to enhance verbose
986*44704f69SBart Van Assche  * output. */
987*44704f69SBart Van Assche void
dbg_print(const char * id_str,bool to_stdout,int verbose) const988*44704f69SBart Van Assche scat_gath_iter::dbg_print(const char * id_str, bool to_stdout,
989*44704f69SBart Van Assche                           int verbose) const
990*44704f69SBart Van Assche {
991*44704f69SBart Van Assche     const char * caller = id_str ? id_str : "unknown";
992*44704f69SBart Van Assche     FILE * fp = to_stdout ? stdout : stderr;
993*44704f69SBart Van Assche 
994*44704f69SBart Van Assche     fprintf(fp, "%s: it_el_ind=%d, it_blk_off=%d, blk_idx=%" PRId64 "\n",
995*44704f69SBart Van Assche             caller, it_el_ind, it_blk_off, blk_idx);
996*44704f69SBart Van Assche     fprintf(fp, "  extend_last=%d\n", extend_last);
997*44704f69SBart Van Assche     if (verbose)
998*44704f69SBart Van Assche         sglist.dbg_print(false, " iterator's", to_stdout, verbose > 1);
999*44704f69SBart Van Assche }
1000*44704f69SBart Van Assche 
1001*44704f69SBart Van Assche /* Calculates difference between iterators, logically: res <-- lhs - rhs
1002*44704f69SBart Van Assche  * Checks that lhsp and rhsp have same underlying sgl, if not returns
1003*44704f69SBart Van Assche  * INT_MIN. Assumes iterators close enough for result to lie in range
1004*44704f69SBart Van Assche  * from (-INT_MAX) to INT_MAX (inclusive). */
1005*44704f69SBart Van Assche int
diff_between_iters(const class scat_gath_iter & left,const class scat_gath_iter & right)1006*44704f69SBart Van Assche diff_between_iters(const class scat_gath_iter & left,
1007*44704f69SBart Van Assche                    const class scat_gath_iter & right)
1008*44704f69SBart Van Assche {
1009*44704f69SBart Van Assche     int res, k, r_e_ind, l_e_ind;
1010*44704f69SBart Van Assche 
1011*44704f69SBart Van Assche     if (&left.sglist != &right.sglist) {
1012*44704f69SBart Van Assche         pr2serr("%s: bad args\n", __func__);
1013*44704f69SBart Van Assche         return INT_MIN;
1014*44704f69SBart Van Assche     }
1015*44704f69SBart Van Assche     r_e_ind = right.it_el_ind;
1016*44704f69SBart Van Assche     l_e_ind = left.it_el_ind;
1017*44704f69SBart Van Assche     if (l_e_ind < r_e_ind) { /* so difference will be negative */
1018*44704f69SBart Van Assche         res = diff_between_iters(right, left);        /* cheat */
1019*44704f69SBart Van Assche         if (INT_MIN == res)
1020*44704f69SBart Van Assche             return res;
1021*44704f69SBart Van Assche         return -res;
1022*44704f69SBart Van Assche     } else if (l_e_ind == r_e_ind)
1023*44704f69SBart Van Assche         return (int)left.it_blk_off - (int)right.it_blk_off;
1024*44704f69SBart Van Assche     /* (l_e_ind > r_e_ind) so (lhs > rhs) */
1025*44704f69SBart Van Assche     res = (int)right.sglist.sgl[r_e_ind].num - right.it_blk_off;
1026*44704f69SBart Van Assche     for (k = 1; (r_e_ind + k) < l_e_ind; ++k) {
1027*44704f69SBart Van Assche         // pr2serr("%s: k=%d, res=%d, num=%d\n", __func__, k, res,
1028*44704f69SBart Van Assche         //         (int)right.sglist.sgl[r_e_ind + k].num);
1029*44704f69SBart Van Assche         res += (int)right.sglist.sgl[r_e_ind + k].num;
1030*44704f69SBart Van Assche     }
1031*44704f69SBart Van Assche     res += left.it_blk_off;
1032*44704f69SBart Van Assche     // pr2serr("%s: at exit res=%d\n", __func__, res);
1033*44704f69SBart Van Assche     return res;
1034*44704f69SBart Van Assche }
1035*44704f69SBart Van Assche 
1036*44704f69SBart Van Assche /* Compares from the current iterator positions of left and left until
1037*44704f69SBart Van Assche  * the shorter list is exhausted. Returns false on the first inequality.
1038*44704f69SBart Van Assche  * If no inequality and both remaining lists are same length then returns
1039*44704f69SBart Van Assche  * true. If no inequality but remaining lists differ in length then returns
1040*44704f69SBart Van Assche  * allow_partial. */
1041*44704f69SBart Van Assche bool
sgls_eq_from_iters(const class scat_gath_iter & left,const class scat_gath_iter & right,bool allow_partial)1042*44704f69SBart Van Assche sgls_eq_from_iters(const class scat_gath_iter & left,
1043*44704f69SBart Van Assche                    const class scat_gath_iter & right,
1044*44704f69SBart Van Assche                    bool allow_partial)
1045*44704f69SBart Van Assche {
1046*44704f69SBart Van Assche     return sgls_eq_off(left.sglist, left.it_el_ind, left.it_blk_off,
1047*44704f69SBart Van Assche                        right.sglist, right.it_el_ind, right.it_blk_off,
1048*44704f69SBart Van Assche                        allow_partial);
1049*44704f69SBart Van Assche }
1050