summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mboxd_windows.c7
-rw-r--r--pnor_partition.cpp61
-rw-r--r--pnor_partition.hpp36
-rw-r--r--pnor_partition_table.cpp4
-rw-r--r--test/vpnor/Makefile.am.include3
5 files changed, 77 insertions, 34 deletions
diff --git a/mboxd_windows.c b/mboxd_windows.c
index fd679bc..9742180 100644
--- a/mboxd_windows.c
+++ b/mboxd_windows.c
@@ -619,7 +619,12 @@ int create_map_window(struct mbox_context *context,
reset_window(context, cur);
return rc;
}
- /* rc isn't guaranteed to be aligned, so align up */
+ /*
+ * rc isn't guaranteed to be aligned, so align up
+ *
+ * FIXME: This should only be the case for the vpnor ToC now, so handle
+ * it there
+ */
cur->size = align_up(rc, (1ULL << context->block_size_shift));
/* Would like a known value, pick 0xFF to it looks like erased flash */
memset(cur->mem + rc, 0xFF, cur->size - rc);
diff --git a/pnor_partition.cpp b/pnor_partition.cpp
index 390c4d5..84aeb3f 100644
--- a/pnor_partition.cpp
+++ b/pnor_partition.cpp
@@ -10,11 +10,14 @@
#include <phosphor-logging/elog-errors.hpp>
#include <assert.h>
+#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <syslog.h>
+#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <unistd.h>
#include "common.h"
@@ -86,7 +89,31 @@ fs::path Request::getPartitionFilePath(int flags)
return dst;
}
-ssize_t Request::fulfil(void *buf, size_t len, int flags)
+size_t Request::clamp(size_t len)
+{
+ size_t maxAccess = offset + len;
+ size_t partSize = partition.data.size << ctx->block_size_shift;
+ return std::min(maxAccess, partSize) - offset;
+}
+
+void Request::resize(const fs::path &path, size_t len)
+{
+ size_t maxAccess = offset + len;
+ size_t fileSize = fs::file_size(path);
+ if (maxAccess < fileSize)
+ {
+ return;
+ }
+ MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess);
+ int rc = truncate(path.c_str(), maxAccess);
+ if (rc == -1)
+ {
+ MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno);
+ throw std::system_error(errno, std::system_category());
+ }
+}
+
+size_t Request::fulfil(const fs::path &path, int flags, void *buf, size_t len)
{
if (!(flags == O_RDONLY || flags == O_RDWR))
{
@@ -96,8 +123,6 @@ ssize_t Request::fulfil(void *buf, size_t len, int flags)
throw std::invalid_argument(err.str());
}
- fs::path path = getPartitionFilePath(flags);
-
int fd = ::open(path.c_str(), flags);
if (fd == -1)
{
@@ -106,45 +131,29 @@ ssize_t Request::fulfil(void *buf, size_t len, int flags)
throw std::system_error(errno, std::system_category());
}
+ size_t fileSize = fs::file_size(path);
int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0);
- auto map = mmap(NULL, partition.data.actual, mprot, MAP_SHARED, fd, 0);
+ auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
close(fd);
- MSG_ERR("Failed to map backing file '%s' for %d bytes: %d\n",
- path.c_str(), partition.data.actual, errno);
+ MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n",
+ path.c_str(), fileSize, errno);
throw std::system_error(errno, std::system_category());
}
// copy to the reserved memory area
if (flags == O_RDONLY)
{
- len = std::min(partition.data.actual - offset, len);
- memcpy(buf, (char *)map + offset, len);
+ memset(buf, 0xff, len);
+ memcpy(buf, (char *)map + offset, std::min(len, fileSize));
}
else
{
- // if the asked offset + no of bytes to read is greater
- // then size of the partition file then throw error.
- //
- // FIXME: Don't use .actual, use (.size << ctx->block_size_shift),
- // otherwise we can't grow the size of the data to fill the partition
- if ((base + offset + len) > (base + partition.data.actual))
- {
- munmap(map, partition.data.actual);
- close(fd);
-
- /* FIXME: offset calculation */
- std::stringstream err;
- err << "Request size 0x" << std::hex << len << " from offset 0x"
- << std::hex << offset << " exceeds the partition size 0x"
- << std::hex << partition.data.actual;
- throw OutOfBoundsOffset(err.str());
- }
memcpy((char *)map + offset, buf, len);
set_flash_bytemap(ctx, base + offset, len, FLASH_DIRTY);
}
- munmap(map, partition.data.actual);
+ munmap(map, fileSize);
close(fd);
return len;
diff --git a/pnor_partition.hpp b/pnor_partition.hpp
index 80777ce..eb63a39 100644
--- a/pnor_partition.hpp
+++ b/pnor_partition.hpp
@@ -48,15 +48,44 @@ class Request
ssize_t read(void* dst, size_t len)
{
- return fulfil(dst, len, O_RDONLY);
+ len = clamp(len);
+ constexpr auto flags = O_RDONLY;
+ fs::path path = getPartitionFilePath(flags);
+ return fulfil(path, flags, dst, len);
}
ssize_t write(void* dst, size_t len)
{
- return fulfil(dst, len, O_RDWR);
+ if (len != clamp(len))
+ {
+ std::stringstream err;
+ err << "Request size 0x" << std::hex << len << " from offset 0x"
+ << std::hex << offset << " exceeds the partition size 0x"
+ << std::hex << (partition.data.size << ctx->block_size_shift);
+ throw OutOfBoundsOffset(err.str());
+ }
+ constexpr auto flags = O_RDWR;
+ /* Ensure file is at least the size of the maximum access */
+ fs::path path = getPartitionFilePath(flags);
+ resize(path, len);
+ return fulfil(path, flags, dst, len);
}
private:
+ /** @brief Clamp the access length to the maximum supported by the ToC */
+ size_t clamp(size_t len);
+
+ /** @brief Ensure the backing file is sized appropriately for the access
+ *
+ * We need to ensure the file is big enough to satisfy the request so that
+ * mmap() will succeed for the required size.
+ *
+ * @return The valid access length
+ *
+ * Throws: std::system_error
+ */
+ void resize(const std::experimental::filesystem::path& path, size_t len);
+
/** @brief Returns the partition file path associated with the offset.
*
* The search strategy for the partition file depends on the value of the
@@ -97,7 +126,8 @@ class Request
* @param[out] dst - The buffer to fill with partition data
* @param[in] len - The length of the destination buffer
*/
- ssize_t fulfil(void* dst, size_t len, int flags);
+ size_t fulfil(const std::experimental::filesystem::path& path, int flags,
+ void* dst, size_t len);
struct mbox_context* ctx;
const pnor_partition& partition;
diff --git a/pnor_partition_table.cpp b/pnor_partition_table.cpp
index 376b191..4ad07bc 100644
--- a/pnor_partition_table.cpp
+++ b/pnor_partition_table.cpp
@@ -154,8 +154,10 @@ const pnor_partition& Table::partition(size_t offset) const
for (decltype(numParts) i{}; i < numParts; ++i)
{
const struct pnor_partition& part = table.partitions[i];
+ size_t len = part.data.size;
+
if ((blockOffset >= part.data.base) &&
- (blockOffset < (part.data.base + part.data.size)))
+ (blockOffset < (part.data.base + len)))
{
return part;
}
diff --git a/test/vpnor/Makefile.am.include b/test/vpnor/Makefile.am.include
index 8d0dd65..09a4cc8 100644
--- a/test/vpnor/Makefile.am.include
+++ b/test/vpnor/Makefile.am.include
@@ -274,7 +274,4 @@ check_PROGRAMS += \
%reldir%/create_read_window_partition_invalid \
%reldir%/read_patch \
%reldir%/write_patch_resize
-
-XFAIL_TESTS += %reldir%/read_patch
-XFAIL_TESTS += %reldir%/write_patch_resize
endif
OpenPOWER on IntegriCloud