2 * Copyright (C) 2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 struct nbdkit_extents
{
49 struct nbdkit_extent
*extents
;
50 size_t nr_extents
, allocated
;
52 uint64_t start
, end
; /* end is one byte beyond the end of the range */
54 /* Where we expect the next extent to be added. If
55 * nbdkit_add_extent has never been called this is -1. Note this
56 * field is updated even if we don't actually add the extent because
57 * it's used to check for API violations.
62 struct nbdkit_extents
*
63 nbdkit_extents_new (uint64_t start
, uint64_t end
)
65 struct nbdkit_extents
*r
;
67 if (start
> INT64_MAX
|| end
> INT64_MAX
) {
68 nbdkit_error ("nbdkit_extents_new: "
69 "start (%" PRIu64
") or end (%" PRIu64
") > INT64_MAX",
75 /* 0-length ranges are possible, so start == end is not an error. */
77 nbdkit_error ("nbdkit_extents_new: "
78 "start (%" PRIu64
") >= end (%" PRIu64
")",
84 r
= malloc (sizeof *r
);
86 nbdkit_error ("nbdkit_extents_new: malloc: %m");
90 r
->nr_extents
= r
->allocated
= 0;
98 nbdkit_extents_free (struct nbdkit_extents
*exts
)
101 free (exts
->extents
);
107 nbdkit_extents_count (const struct nbdkit_extents
*exts
)
109 return exts
->nr_extents
;
113 nbdkit_get_extent (const struct nbdkit_extents
*exts
, size_t i
)
115 assert (i
< exts
->nr_extents
);
116 return exts
->extents
[i
];
119 /* Insert *e in the list at the end. */
121 append_extent (struct nbdkit_extents
*exts
, const struct nbdkit_extent
*e
)
123 if (exts
->nr_extents
>= exts
->allocated
) {
124 size_t new_allocated
;
125 struct nbdkit_extent
*new_extents
;
127 new_allocated
= exts
->allocated
;
128 if (new_allocated
== 0)
132 realloc (exts
->extents
, new_allocated
* sizeof (struct nbdkit_extent
));
133 if (new_extents
== NULL
) {
134 nbdkit_error ("nbdkit_add_extent: realloc: %m");
137 exts
->allocated
= new_allocated
;
138 exts
->extents
= new_extents
;
141 exts
->extents
[exts
->nr_extents
] = *e
;
147 nbdkit_add_extent (struct nbdkit_extents
*exts
,
148 uint64_t offset
, uint64_t length
, uint32_t type
)
152 /* Extents must be added in strictly ascending, contiguous order. */
153 if (exts
->next
>= 0 && exts
->next
!= offset
) {
154 nbdkit_error ("nbdkit_add_extent: "
155 "extents must be added in ascending order and "
156 "must be contiguous");
159 exts
->next
= offset
+ length
;
161 /* Ignore zero-length extents. */
165 /* Ignore extents beyond the end of the range. */
166 if (offset
>= exts
->end
)
169 /* Shorten extents that overlap the end of the range. */
170 if (offset
+ length
>= exts
->end
) {
171 overlap
= offset
+ length
- exts
->end
;
175 if (exts
->nr_extents
== 0) {
176 /* If there are no existing extents, and the new extent is
177 * entirely before start, ignore it.
179 if (offset
+ length
<= exts
->start
)
182 /* If there are no existing extents, and the new extent is after
183 * start, then this is a bug in the plugin.
185 if (offset
> exts
->start
) {
186 nbdkit_error ("nbdkit_add_extent: "
187 "first extent must not be > start (%" PRIu64
")",
192 /* If there are no existing extents, and the new extent overlaps
193 * start, truncate it so it starts at start.
195 overlap
= exts
->start
- offset
;
200 /* If we get here we are going to either add or extend. */
201 if (exts
->nr_extents
> 0 &&
202 exts
->extents
[exts
->nr_extents
-1].type
== type
) {
203 /* Coalesce with the last extent. */
204 exts
->extents
[exts
->nr_extents
-1].length
+= length
;
208 /* Add a new extent. */
209 const struct nbdkit_extent e
=
210 { .offset
= offset
, .length
= length
, .type
= type
};
211 return append_extent (exts
, &e
);