1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
//
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "update_engine/payload_consumer/cow_writer_file_descriptor.h"
#include <memory>
#include <utility>
#include <base/logging.h>
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/file_descriptor.h"
namespace chromeos_update_engine {
CowWriterFileDescriptor::CowWriterFileDescriptor(
std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer)
: cow_writer_(std::move(cow_writer)),
cow_reader_(cow_writer_->OpenReader()) {
CHECK_NE(cow_writer_, nullptr);
CHECK_NE(cow_reader_, nullptr);
}
bool CowWriterFileDescriptor::Open(const char* path, int flags, mode_t mode) {
LOG(ERROR) << "CowWriterFileDescriptor doesn't support Open()";
return false;
}
bool CowWriterFileDescriptor::Open(const char* path, int flags) {
LOG(ERROR) << "CowWriterFileDescriptor doesn't support Open()";
return false;
}
ssize_t CowWriterFileDescriptor::Read(void* buf, size_t count) {
if (dirty_) {
// OK, CowReader provides a snapshot view of what the cow contains. Which
// means any writes happened after opening a CowReader isn't visible to
// that CowReader. Therefore, we re-open CowReader whenever we attempt a
// read after write. This does incur an overhead everytime you read after
// write.
// The usage of |dirty_| flag to coordinate re-open is a very coarse grained
// checked. This implementation has suboptimal performance. For better
// performance, keep track of blocks which are overwritten, and only re-open
// if reading a dirty block.
// TODO(b/173432386) Implement finer grained dirty checks
const auto offset = cow_reader_->Seek(0, SEEK_CUR);
cow_reader_.reset();
if (!cow_writer_->Finalize()) {
LOG(ERROR) << "Failed to Finalize() cow writer";
return -1;
}
cow_reader_ = cow_writer_->OpenReader();
if (cow_reader_ == nullptr) {
LOG(ERROR) << "Failed to re-open cow reader after writing to COW";
return -1;
}
const auto pos = cow_reader_->Seek(offset, SEEK_SET);
if (pos != offset) {
LOG(ERROR) << "Failed to seek to previous position after re-opening cow "
"reader, expected "
<< offset << " actual: " << pos;
return -1;
}
dirty_ = false;
}
return cow_reader_->Read(buf, count);
}
ssize_t CowWriterFileDescriptor::Write(const void* buf, size_t count) {
auto offset = cow_reader_->Seek(0, SEEK_CUR);
CHECK_EQ(offset % cow_writer_->options().block_size, 0);
auto success = cow_writer_->AddRawBlocks(
offset / cow_writer_->options().block_size, buf, count);
if (success) {
if (cow_reader_->Seek(count, SEEK_CUR) < 0) {
return -1;
}
dirty_ = true;
return count;
}
return -1;
}
off64_t CowWriterFileDescriptor::Seek(const off64_t offset, int whence) {
return cow_reader_->Seek(offset, whence);
}
uint64_t CowWriterFileDescriptor::BlockDevSize() {
LOG(ERROR) << "CowWriterFileDescriptor doesn't support BlockDevSize()";
return 0;
}
bool CowWriterFileDescriptor::BlkIoctl(int request,
uint64_t start,
uint64_t length,
int* result) {
LOG(ERROR) << "CowWriterFileDescriptor doesn't support BlkIoctl()";
return false;
}
bool CowWriterFileDescriptor::Flush() {
// CowWriter already automatilly flushes, no need to do anything.
return true;
}
bool CowWriterFileDescriptor::Close() {
if (cow_writer_) {
// b/186196758
// When calling
// InitializeAppend(kEndOfInstall), the SnapshotWriter only reads up to the
// given label. But OpenReader() completely disregards the resume label and
// reads all ops. Therefore, update_engine sees the verity data. However,
// when calling SnapshotWriter::Finalize(), data after resume label are
// discarded, therefore verity data is gone. To prevent phantom reads, don't
// call Finalize() unless we actually write something.
if (dirty_) {
TEST_AND_RETURN_FALSE(cow_writer_->Finalize());
}
cow_writer_ = nullptr;
}
if (cow_reader_) {
TEST_AND_RETURN_FALSE(cow_reader_->Close());
cow_reader_ = nullptr;
}
return true;
}
bool CowWriterFileDescriptor::IsSettingErrno() {
return false;
}
bool CowWriterFileDescriptor::IsOpen() {
return cow_writer_ != nullptr && cow_reader_ != nullptr;
}
CowWriterFileDescriptor::~CowWriterFileDescriptor() {
Close();
}
} // namespace chromeos_update_engine
|