free_command() was abused as a completion callback. Introduce
finish_command() completion callback, so code that want to free a
command does not have to add dummy errors.
This will make it easier to manage worker state when a command
completes.
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
copy/multi-thread-copying.c | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/copy/multi-thread-copying.c b/copy/multi-thread-copying.c
index 855d1ba4..aa6a9f41 100644
--- a/copy/multi-thread-copying.c
+++ b/copy/multi-thread-copying.c
@@ -126,21 +126,22 @@ multi_thread_copying (void)
}
}
free (workers);
}
static void wait_for_request_slots (uintptr_t index);
static unsigned in_flight (uintptr_t index);
static void poll_both_ends (uintptr_t index);
static int finished_read (void *vp, int *error);
-static int free_command (void *vp, int *error);
+static int finished_command (void *vp, int *error);
+static void free_command (struct command *command);
static void fill_dst_range_with_zeroes (struct command *command);
static struct command *create_command (uint64_t offset, size_t len, bool zero,
uintptr_t index);
/* There are 'threads' worker threads, each copying work ranges from
* src to dst until there are no more work ranges.
*/
static void *
worker_thread (void *indexp)
{
@@ -402,53 +403,52 @@ finished_read (void *vp, int *error)
command->offset, strerror (*error));
exit (EXIT_FAILURE);
}
if (allocated || sparse_size == 0) {
/* If sparseness detection (see below) is turned off then we write
* the whole command.
*/
dst->ops->asynch_write (dst, command,
(nbd_completion_callback) {
- .callback = free_command,
+ .callback = finished_command,
.user_data = command,
});
}
else { /* Sparseness detection. */
const uint64_t start = command->offset;
const uint64_t end = start + command->slice.len;
uint64_t last_offset = start;
bool last_is_zero = false;
uint64_t i;
struct command *newcommand;
- int dummy = 0;
/* Iterate over whole blocks in the command, starting on a block
* boundary.
*/
for (i = MIN (ROUND_UP (start, sparse_size), end);
i + sparse_size <= end;
i += sparse_size) {
if (is_zero (slice_ptr (command->slice) + i-start, sparse_size)) {
/* It's a zero range. If the last was a zero too then we do
* nothing here which coalesces. Otherwise write the last data
* and start a new zero range.
*/
if (!last_is_zero) {
/* Write the last data (if any). */
if (i - last_offset > 0) {
newcommand = create_subcommand (command,
last_offset, i - last_offset,
false);
dst->ops->asynch_write (dst, newcommand,
(nbd_completion_callback) {
- .callback = free_command,
+ .callback = finished_command,
.user_data = newcommand,
});
}
/* Start the new zero range. */
last_offset = i;
last_is_zero = true;
}
}
else {
/* It's data. If the last was data too, do nothing =>
@@ -471,46 +471,46 @@ finished_read (void *vp, int *error)
} /* for i */
/* Write the last_offset up to i. */
if (i - last_offset > 0) {
if (!last_is_zero) {
newcommand = create_subcommand (command,
last_offset, i - last_offset,
false);
dst->ops->asynch_write (dst, newcommand,
(nbd_completion_callback) {
- .callback = free_command,
+ .callback = finished_command,
.user_data = newcommand,
});
}
else {
newcommand = create_subcommand (command,
last_offset, i - last_offset,
true);
fill_dst_range_with_zeroes (newcommand);
}
}
/* There may be an unaligned tail, so write that. */
if (end - i > 0) {
newcommand = create_subcommand (command, i, end - i, false);
dst->ops->asynch_write (dst, newcommand,
(nbd_completion_callback) {
- .callback = free_command,
+ .callback = finished_command,
.user_data = newcommand,
});
}
/* Free the original command since it has been split into
* subcommands and the original is no longer needed.
*/
- free_command (command, &dummy);
+ free_command (command);
}
return 1; /* auto-retires the command */
}
/* Fill a range in dst with zeroes. This is called from the copying
* loop when we see a zero range in the source. Depending on the
* command line flags this could mean:
*
* --destination-is-zero:
@@ -523,29 +523,28 @@ finished_read (void *vp, int *error)
* zeroing command or fallback to writing a command
* of zeroes.
*
* This takes over ownership of the command and frees it eventually.
*/
static void
fill_dst_range_with_zeroes (struct command *command)
{
char *data;
size_t data_size;
- int dummy = 0;
if (destination_is_zero)
goto free_and_return;
/* Try efficient zeroing. */
if (dst->ops->asynch_zero (dst, command,
(nbd_completion_callback) {
- .callback = free_command,
+ .callback = finished_command,
.user_data = command,
},
allocated))
return;
/* Fall back to loop writing zeroes. This is going to be slow
* anyway, so do it synchronously. XXX
*/
data_size = MIN (request_size, command->slice.len);
data = calloc (1, data_size);
@@ -559,36 +558,43 @@ fill_dst_range_with_zeroes (struct command *command)
if (len > data_size)
len = data_size;
dst->ops->synch_write (dst, data, len, command->offset);
command->slice.len -= len;
command->offset += len;
}
free (data);
free_and_return:
- free_command (command, &dummy);
+ free_command (command);
}
static int
-free_command (void *vp, int *error)
+finished_command (void *vp, int *error)
{
struct command *command = vp;
- struct buffer *buffer = command->slice.buffer;
if (*error) {
fprintf (stderr, "write at offset %" PRId64 " failed: %s\n",
command->offset, strerror (*error));
exit (EXIT_FAILURE);
}
+ free_command (command);
+
+ return 1; /* auto-retires the command */
+}
+
+static void
+free_command (struct command *command)
+{
+ struct buffer *buffer = command->slice.buffer;
+
if (buffer != NULL) {
if (--buffer->refs == 0) {
free (buffer->data);
free (buffer);
}
}
free (command);
-
- return 1; /* auto-retires the command */
}
--
2.35.1