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