Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a49b8d22 authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge changes Ie9a781e4,I060788c9,Ie75e9440 into main

* changes:
  snapuserd: Remove dm-user specific code from ReadWorker.
  snapuserd: Add an IBlockServer abstraction around dm-user.
  snapuserd: Rename snapuserd_merge to merge_worker.
parents a28b62e0 a392fa3c
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -60,13 +60,14 @@ cc_library_static {
    local_include_dirs: ["include/"],
    srcs: [
        "dm-snapshot-merge/snapuserd.cpp",
        "dm-snapshot-merge/snapuserd_worker.cpp",
        "dm-snapshot-merge/snapuserd_readahead.cpp",
        "dm-snapshot-merge/snapuserd_worker.cpp",
        "dm_user_block_server.cpp",
        "snapuserd_buffer.cpp",
        "user-space-merge/handler_manager.cpp",
        "user-space-merge/merge_worker.cpp",
        "user-space-merge/read_worker.cpp",
        "user-space-merge/snapuserd_core.cpp",
        "user-space-merge/snapuserd_merge.cpp",
        "user-space-merge/snapuserd_readahead.cpp",
        "user-space-merge/snapuserd_transitions.cpp",
        "user-space-merge/snapuserd_verify.cpp",
+146 −0
Original line number Diff line number Diff line
// Copyright (C) 2023 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 <snapuserd/dm_user_block_server.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <snapuserd/snapuserd_kernel.h>
#include "snapuserd_logging.h"

namespace android {
namespace snapshot {

using android::base::unique_fd;

DmUserBlockServer::DmUserBlockServer(const std::string& misc_name, unique_fd&& ctrl_fd,
                                     Delegate* delegate, size_t buffer_size)
    : misc_name_(misc_name), ctrl_fd_(std::move(ctrl_fd)), delegate_(delegate) {
    buffer_.Initialize(sizeof(struct dm_user_header) + buffer_size);
}

bool DmUserBlockServer::ProcessRequests() {
    struct dm_user_header* header = buffer_.GetHeaderPtr();
    if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
        if (errno != ENOTBLK) {
            SNAP_PLOG(ERROR) << "Control-read failed";
        }

        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
        return false;
    }

    SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq;
    SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len;
    SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector;
    SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
    SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;

    if (!ProcessRequest(header)) {
        if (header->type != DM_USER_RESP_ERROR) {
            SendError();
        }
        return false;
    }
    return true;
}

bool DmUserBlockServer::ProcessRequest(dm_user_header* header) {
    // Use the same header buffer as the response header.
    int request_type = header->type;
    header->type = DM_USER_RESP_SUCCESS;
    header_response_ = true;

    // Reset the output buffer.
    buffer_.ResetBufferOffset();

    switch (request_type) {
        case DM_USER_REQ_MAP_READ:
            return delegate_->RequestSectors(header->sector, header->len);

        case DM_USER_REQ_MAP_WRITE:
            // We should not get any write request to dm-user as we mount all
            // partitions as read-only.
            SNAP_LOG(ERROR) << "Unexpected write request from dm-user";
            return false;

        default:
            SNAP_LOG(ERROR) << "Unexpected request from dm-user: " << request_type;
            return false;
    }
}

void* DmUserBlockServer::GetResponseBuffer(size_t size, size_t to_write) {
    return buffer_.AcquireBuffer(size, to_write);
}

bool DmUserBlockServer::SendBufferedIo() {
    return WriteDmUserPayload(buffer_.GetPayloadBytesWritten());
}

void DmUserBlockServer::SendError() {
    struct dm_user_header* header = buffer_.GetHeaderPtr();
    header->type = DM_USER_RESP_ERROR;
    // This is an issue with the dm-user interface. There
    // is no way to propagate the I/O error back to dm-user
    // if we have already communicated the header back. Header
    // is responded once at the beginning; however I/O can
    // be processed in chunks. If we encounter an I/O error
    // somewhere in the middle of the processing, we can't communicate
    // this back to dm-user.
    //
    // TODO: Fix the interface
    CHECK(header_response_);

    WriteDmUserPayload(0);
}

bool DmUserBlockServer::WriteDmUserPayload(size_t size) {
    size_t payload_size = size;
    void* buf = buffer_.GetPayloadBufPtr();
    if (header_response_) {
        payload_size += sizeof(struct dm_user_header);
        buf = buffer_.GetBufPtr();
    }

    if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) {
        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size;
        return false;
    }

    // After the first header is sent in response to a request, we cannot
    // send any additional headers.
    header_response_ = false;

    // Reset the buffer for use by the next request.
    buffer_.ResetBufferOffset();
    return true;
}

DmUserBlockServerOpener::DmUserBlockServerOpener(const std::string& misc_name,
                                                 const std::string& dm_user_path)
    : misc_name_(misc_name), dm_user_path_(dm_user_path) {}

std::unique_ptr<IBlockServer> DmUserBlockServerOpener::Open(IBlockServer::Delegate* delegate,
                                                            size_t buffer_size) {
    unique_fd fd(open(dm_user_path_.c_str(), O_RDWR | O_CLOEXEC));
    if (fd < 0) {
        SNAP_PLOG(ERROR) << "Could not open dm-user path: " << dm_user_path_;
        return nullptr;
    }
    return std::make_unique<DmUserBlockServer>(misc_name_, std::move(fd), delegate, buffer_size);
}

}  // namespace snapshot
}  // namespace android
+87 −0
Original line number Diff line number Diff line
// Copyright (C) 2023 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.

#pragma once

#include <stddef.h>
#include <stdint.h>

#include <memory>

namespace android {
namespace snapshot {

// These interfaces model the block device driver component of snapuserd (eg,
// dm-user).

// An open connection to a userspace block device control
class IBlockServer {
  public:
    class Delegate {
      public:
        virtual ~Delegate() {}

        // Respond to a request for reading a contiguous run of sectors. This
        // call should be followed by calls to GetResponseBuffer/CommitBuffer
        // until the |size| is fulfilled.
        //
        // If false is returned, an error will be automatically reported unless
        // SendError was called.
        virtual bool RequestSectors(uint64_t sector, uint64_t size) = 0;
    };

    virtual ~IBlockServer() {}

    // Process I/O requests. This can block the worker thread until either a
    // request is available or the underlying connection has been destroyed.
    //
    // True indicates that one or more requests was processed. False indicates
    // an unrecoverable condition and processing should stop.
    virtual bool ProcessRequests() = 0;

    // Return a buffer for fulfilling a RequestSectors request. This buffer
    // is valid until calling SendBufferedIo. This cannot be called outside
    // of RequestSectors().
    //
    // "to_write" must be <= "size". If it is < size, the excess bytes are
    // available for writing, but will not be send via SendBufferedIo, and
    // may be reallocated in the next call to GetResponseBuffer.
    //
    // All buffers returned are invalidated after SendBufferedIo or returning
    // control from RequestSectors.
    virtual void* GetResponseBuffer(size_t size, size_t to_write) = 0;

    // Send all outstanding buffers to the driver, in order. This should
    // be called at least once in response to RequestSectors. This returns
    // ownership of any buffers returned by GetResponseBuffer.
    //
    // If false is returned, an error is automatically reported to the driver.
    virtual bool SendBufferedIo() = 0;

    void* GetResponseBuffer(size_t size) { return GetResponseBuffer(size, size); }
};

class IBlockServerOpener {
  public:
    virtual ~IBlockServerOpener() = default;

    // Open a connection to the service. This is called on the daemon thread.
    //
    // buffer_size is the maximum amount of buffered I/O to use.
    virtual std::unique_ptr<IBlockServer> Open(IBlockServer::Delegate* delegate,
                                               size_t buffer_size) = 0;
};

}  // namespace snapshot
}  // namespace android
+63 −0
Original line number Diff line number Diff line
// Copyright (C) 2023 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.

#pragma once

#include <android-base/unique_fd.h>

#include <string>

#include <snapuserd/block_server.h>
#include <snapuserd/snapuserd_buffer.h>

namespace android {
namespace snapshot {

class DmUserBlockServer : public IBlockServer {
  public:
    DmUserBlockServer(const std::string& misc_name, android::base::unique_fd&& ctrl_fd,
                      Delegate* delegate, size_t buffer_size);

    bool ProcessRequests() override;
    void* GetResponseBuffer(size_t size, size_t to_write) override;
    bool SendBufferedIo() override;
    void SendError();

  private:
    bool ProcessRequest(dm_user_header* header);
    bool WriteDmUserPayload(size_t size);

    std::string misc_name_;
    android::base::unique_fd ctrl_fd_;
    Delegate* delegate_;

    // Per-request state.
    BufferSink buffer_;
    bool header_response_ = false;
};

class DmUserBlockServerOpener : public IBlockServerOpener {
  public:
    DmUserBlockServerOpener(const std::string& misc_name, const std::string& dm_user_path);

    std::unique_ptr<IBlockServer> Open(IBlockServer::Delegate* delegate,
                                       size_t buffer_size) override;

  private:
    std::string misc_name_;
    std::string dm_user_path_;
};

}  // namespace snapshot
}  // namespace android
+20 −0
Original line number Diff line number Diff line
// Copyright (C) 2023 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.

#pragma once

#include <android-base/logging.h>

#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
Loading