Skip to content

Commit

Permalink
stored: re-read large blocks in tape backend
Browse files Browse the repository at this point in the history
when the unix_tape_device encounters a block that is too large for the
buffer to handle, it will now re-read with incrementing buffer sizes
until it can provide the first part of the block.
This allows Bareos to reconfigure the block buffer size for tape devices
like it already does for file devices.
  • Loading branch information
arogge authored and BareosBot committed Aug 17, 2023
1 parent 18383f1 commit decfa5f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
39 changes: 39 additions & 0 deletions core/src/stored/backends/unix_tape_device.cc
Expand Up @@ -40,6 +40,9 @@
* @file
* UNIX Tape API device abstraction.
*/
#include <algorithm>
#include <vector>

#include <sys/ioctl.h>
#include <unistd.h>

Expand All @@ -49,6 +52,19 @@
#include "generic_tape_device.h"
#include "unix_tape_device.h"

namespace {
static constexpr size_t size_increment = 1024 * 1024;
static constexpr size_t max_size_increment = 16 * size_increment;
static constexpr size_t next_size_increment(size_t count)
{
if (count < size_increment) {
return size_increment;
} else {
return (count / size_increment) * 2 * size_increment;
}
}
} // namespace

namespace storagedaemon {

int unix_tape_device::d_ioctl(int fd, ioctl_req_t request, char* op)
Expand All @@ -61,6 +77,29 @@ unix_tape_device::unix_tape_device()
SetCap(CAP_ADJWRITESIZE); /* Adjust write size to min/max */
}

ssize_t unix_tape_device::d_read(int fd, void* buffer, size_t count)
{
ssize_t ret = ::read(fd, buffer, count);
/* when the driver fails to `read()` with `ENOMEM`, then the provided buffer
* was too small by re-reading with a temporary buffer that is enlarged
* step-by-step, we can read the block and returns its first `count` bytes.
* This allows the calling code to read the block header and resize its buffer
* according to the size recorded in that header.
*/
for (size_t bufsize = next_size_increment(count);
ret == -1 && errno == ENOMEM && bufsize <= max_size_increment;
bufsize = next_size_increment(bufsize)) {
std::vector<char> tmpbuf(bufsize);
bsr(1); // go back one block so we can re-read
block_num++; // re-increment the block counter that bsr() just incremented
if (auto tmpret = ::read(fd, tmpbuf.data(), tmpbuf.size()); tmpret != -1) {
memcpy(buffer, tmpbuf.data(), count);
ret = std::min(tmpret, static_cast<ssize_t>(count));
}
}
return ret;
}

REGISTER_SD_BACKEND(tape, unix_tape_device)

} /* namespace storagedaemon */
3 changes: 2 additions & 1 deletion core/src/stored/backends/unix_tape_device.h
Expand Up @@ -2,7 +2,7 @@
BAREOS® - Backup Archiving REcovery Open Sourced
Copyright (C) 2013-2013 Planets Communications B.V.
Copyright (C) 2013-2021 Bareos GmbH & Co. KG
Copyright (C) 2013-2023 Bareos GmbH & Co. KG
This program is Free Software; you can redistribute it and/or
modify it under the terms of version three of the GNU Affero General Public
Expand Down Expand Up @@ -36,6 +36,7 @@ class unix_tape_device : public generic_tape_device {
~unix_tape_device() { close(nullptr); };

int d_ioctl(int fd, ioctl_req_t request, char* op) override;
virtual ssize_t d_read(int fd, void* buffer, size_t count) override;
};

} /* namespace storagedaemon */
Expand Down

0 comments on commit decfa5f

Please sign in to comment.