Skip to content

Commit 1101a95

Browse files
committed
LiveUpdate support for individually resumable partitions
1 parent 99f7c11 commit 1101a95

8 files changed

Lines changed: 130 additions & 38 deletions

File tree

lib/LiveUpdate/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ add_custom_target(hotswap64 DEPENDS hotswap64.bin)
1919

2020
# LiveUpdate static library
2121
add_library(liveupdate STATIC
22-
storage.cpp update.cpp resume.cpp rollback.cpp hotswap.cpp
23-
serialize_tcp.cpp hotswap64_blob.asm
22+
storage.cpp partition.cpp update.cpp resume.cpp rollback.cpp
23+
serialize_tcp.cpp hotswap.cpp hotswap64_blob.asm
2424
)
2525
add_dependencies(liveupdate hotswap64)
2626
install(TARGETS liveupdate DESTINATION includeos/${ARCH}/lib)

lib/LiveUpdate/liveupdate.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ struct LiveUpdate
7777
// Attempt to restore existing stored entries.
7878
// Returns false if there was nothing there. or if the process failed
7979
// to be sure that only failure can return false, use is_resumable first
80-
static bool resume(std::string key, resume_func default_handler);
80+
static void resume(std::string key, resume_func default_handler);
8181

8282
// When explicitly resuming from heap, heap overrun checks are disabled
83-
static bool resume_from_heap(void* location, resume_func default_handler);
83+
static void resume_from_heap(void* location, std::string key, resume_func);
8484

8585
// Retrieve the recorded length, in bytes, of a valid storage area
8686
// Throws std::runtime_error when something bad happens

lib/LiveUpdate/partition.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2017 IncludeOS AS, Oslo, Norway
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
/**
17+
* Master thesis
18+
* by Alf-Andre Walla 2016-2017
19+
*
20+
**/
21+
#include "storage.hpp"
22+
#include <util/crc32.hpp>
23+
24+
inline uint32_t liu_crc32(const void* buf, size_t len)
25+
{
26+
return crc32_fast(buf, len);
27+
}
28+
29+
uint32_t partition_header::generate_checksum(const char* vla) const {
30+
return liu_crc32(&vla[this->offset], this->length);
31+
}
32+
33+
int storage_header::create_partition(const std::string key)
34+
{
35+
if (key.size() > sizeof(partition_header::name)-1)
36+
throw std::length_error("Key '" + key + "' too long");
37+
if (partitions >= ptable.size())
38+
throw std::out_of_range("Partition table is full");
39+
auto& part = ptable.at(partitions);
40+
snprintf(part.name, sizeof(part.name), "%s", key.c_str());
41+
part.offset = this->length;
42+
return partitions++;
43+
}
44+
int storage_header::find_partition(const char* key)
45+
{
46+
for (uint32_t p = 0; p < this->partitions; p++)
47+
{
48+
auto& part = ptable.at(p);
49+
if (strncmp(part.name, key, sizeof(part.name)))
50+
{
51+
uint32_t chsum = part.generate_checksum(this->vla);
52+
if (part.crc == chsum) {
53+
return p;
54+
}
55+
throw std::runtime_error("Invalid CRC in partition '" + std::string(key) + "'");
56+
}
57+
}
58+
throw std::out_of_range("Could not find partition named " + std::string(key));
59+
}
60+
void storage_header::finish_partition(int p)
61+
{
62+
// make sure partition ends properly
63+
this->add_end();
64+
// write length and crc
65+
auto& part = ptable.at(p);
66+
part.length = this->length - part.offset;
67+
part.crc = part.generate_checksum(this->vla);
68+
}
69+
void storage_header::zero_partition(int p)
70+
{
71+
auto& part = ptable.at(p);
72+
memset(&vla[part.offset], 0, part.length);
73+
memset(&part, 0, sizeof(partition_header));
74+
}

lib/LiveUpdate/resume.cpp

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern char* heap_end;
3434

3535
namespace liu
3636
{
37+
static void resume_begin(storage_header&, const char*, LiveUpdate::resume_func);
3738
static std::map<uint16_t, LiveUpdate::resume_func> resume_funcs;
3839

3940
bool LiveUpdate::is_resumable()
@@ -45,44 +46,40 @@ bool LiveUpdate::is_resumable(void* location)
4546
return ((storage_header*) location)->validate();
4647
}
4748

48-
static bool resume_helper(void* location, LiveUpdate::resume_func func)
49+
static void resume_helper(void* location, std::string key, LiveUpdate::resume_func func)
4950
{
5051
// check if an update has occurred
51-
if (!LiveUpdate::is_resumable(location)) return false;
52+
if (!LiveUpdate::is_resumable(location))
53+
throw std::runtime_error("Trying to resume from invalid storage area");
5254

5355
LPRINT("* Restoring data...\n");
5456
// restore connections etc.
55-
extern bool resume_begin(storage_header&, LiveUpdate::resume_func);
56-
return resume_begin(*(storage_header*) location, func);
57+
resume_begin(*(storage_header*) location, key.c_str(), func);
5758
}
58-
bool LiveUpdate::resume(std::string key, resume_func func)
59+
void LiveUpdate::resume(std::string key, resume_func func)
5960
{
6061
void* location = OS::liveupdate_storage_area();
6162
/// memory sanity check
6263
if (heap_end >= (char*) location) {
6364
fprintf(stderr,
6465
"WARNING: LiveUpdate storage area inside heap (margin: %ld)\n",
6566
(long int) (heap_end - (char*) location));
66-
return false;
67+
throw std::runtime_error("LiveUpdate storage area inside heap");
6768
}
68-
return resume_helper(location, func);
69+
resume_helper(location, key, func);
6970
}
70-
bool LiveUpdate::resume_from_heap(void* location, LiveUpdate::resume_func func)
71+
void LiveUpdate::resume_from_heap(void* location, std::string key, LiveUpdate::resume_func func)
7172
{
72-
return resume_helper(location, func);
73+
resume_helper(location, key, func);
7374
}
7475

75-
bool resume_begin(storage_header& storage, LiveUpdate::resume_func func)
76+
void resume_begin(storage_header& storage, const char* key, LiveUpdate::resume_func func)
7677
{
77-
/// restore each entry one by one, calling registered handlers
78-
auto num_ents = storage.get_entries();
79-
if (num_ents > 1) {
80-
LPRINT("* Resuming %d stored entries\n", num_ents-1);
81-
} else {
82-
LPRINT("* No stored entries to resume\n");
83-
}
78+
int p = storage.find_partition(key);
79+
LPRINT("* Resuming from partition %d\n", p);
8480

85-
for (auto* ptr = storage.begin(); ptr->type != TYPE_END;)
81+
/// restore each entry one by one, calling registered handlers
82+
for (auto* ptr = storage.begin(p); ptr->type != TYPE_END;)
8683
{
8784
auto* oldptr = ptr;
8885
// resume wrapper
@@ -102,10 +99,8 @@ bool resume_begin(storage_header& storage, LiveUpdate::resume_func func)
10299
}
103100
/// wake all the slumbering IP stacks
104101
serialized_tcp::wakeup_ip_networks();
105-
/// zero out all the state for security reasons
106-
storage.zero();
107-
108-
return true;
102+
/// zero out the partition for security reasons
103+
storage.zero_partition(p);
109104
}
110105

111106
void LiveUpdate::on_resume(uint16_t id, resume_func func)

lib/LiveUpdate/storage.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
#include <cassert>
2626
//#define VERIFY_MEMORY
2727

28+
inline uint32_t liu_crc32(const void* buf, size_t len)
29+
{
30+
return crc32_fast(buf, len);
31+
}
32+
2833
const uint64_t storage_header::LIVEUPD_MAGIC = 0xbaadb33fdeadc0de;
2934

3035
storage_header::storage_header()
@@ -33,11 +38,6 @@ storage_header::storage_header()
3338
//printf("%p --> %#llx\n", this, value);
3439
}
3540

36-
inline uint32_t liu_crc32(const void* buf, size_t len)
37-
{
38-
return crc32_fast(buf, len);
39-
}
40-
4141
void storage_header::add_marker(uint16_t id)
4242
{
4343
create_entry(TYPE_MARKER, id, 0);
@@ -134,7 +134,9 @@ void storage_header::finalize()
134134
{
135135
if (this->magic != LIVEUPD_MAGIC)
136136
throw std::runtime_error("Magic field invalidated during store process");
137-
add_end();
137+
// add end if missing
138+
if (this->length == 0) this->add_end();
139+
// generate checksum for header
138140
this->crc = generate_checksum();
139141
}
140142
bool storage_header::validate() noexcept
@@ -153,7 +155,7 @@ uint32_t storage_header::generate_checksum() noexcept
153155
this->crc = 0;
154156

155157
const char* begin = (const char*) this;
156-
size_t len = sizeof(storage_header) + this->length;
158+
size_t len = sizeof(storage_header);
157159
uint32_t checksum = liu_crc32(begin, len);
158160

159161
this->crc = crc_copy;
@@ -166,9 +168,9 @@ void storage_header::zero()
166168
assert(this->magic == 0);
167169
}
168170

169-
storage_entry* storage_header::begin()
171+
storage_entry* storage_header::begin(int p)
170172
{
171-
return (storage_entry*) vla;
173+
return (storage_entry*) &vla[ptable.at(p).offset];
172174
}
173175
storage_entry* storage_header::next(storage_entry* ptr)
174176
{

lib/LiveUpdate/storage.hpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
**/
2121
#pragma once
2222
#include <cstdint>
23+
#include <array>
2324
#include <string>
2425
#include <vector>
2526
#include <delegate>
@@ -86,6 +87,16 @@ struct storage_entry
8687
uint32_t checksum() const;
8788
};
8889

90+
struct partition_header
91+
{
92+
uint32_t generate_checksum(const char* vla) const;
93+
94+
char name[16] = {0};
95+
uint32_t crc = 0;
96+
uint32_t offset = 0;
97+
uint32_t length = 0;
98+
};
99+
89100
struct storage_header
90101
{
91102
typedef delegate<int(char*)> construct_func;
@@ -102,6 +113,10 @@ struct storage_header
102113
}
103114

104115
storage_header();
116+
int create_partition(std::string key);
117+
int find_partition(const char*);
118+
void finish_partition(int);
119+
void zero_partition(int);
105120

106121
void add_marker(uint16_t id);
107122
void add_int (uint16_t id, int value);
@@ -113,7 +128,7 @@ struct storage_header
113128
void add_string_vector(uint16_t id, const std::vector<std::string>& vec);
114129
void add_end();
115130

116-
storage_entry* begin();
131+
storage_entry* begin(int p);
117132
storage_entry* next(storage_entry*);
118133

119134
template <typename... Args>
@@ -138,6 +153,8 @@ struct storage_header
138153
uint32_t crc;
139154
uint32_t entries = 0;
140155
uint32_t length = 0;
156+
std::array<partition_header, 16> ptable;
157+
uint32_t partitions = 0;
141158
char vla[0];
142159
};
143160

lib/LiveUpdate/update.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,13 @@ size_t update_store_data(void* location, const buffer_t* blob)
276276
/// callback for storing stuff, if provided
277277
for (const auto& pair : storage_callbacks)
278278
{
279+
// create partition
280+
int p = storage->create_partition(pair.first);
281+
// run serialization process
279282
Storage wrapper {*storage};
280283
pair.second(wrapper, blob);
284+
// add end for partition
285+
storage->finish_partition(p);
281286
}
282287

283288
/// finalize

lib/uplink/ws_uplink.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ namespace uplink {
7474
if(liu::LiveUpdate::is_resumable())
7575
{
7676
MYINFO("Found resumable state, try restoring...");
77-
auto success = liu::LiveUpdate::resume("uplink", {this, &WS_uplink::restore});
78-
CHECK(success, "Success");
77+
liu::LiveUpdate::resume("uplink", {this, &WS_uplink::restore});
7978
}
8079

8180
client_ = std::make_unique<http::Client>(inet.tcp(),

0 commit comments

Comments
 (0)