blob: 451e6d06c5cb69b19857e7f03baae682782a898c [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_LIB_MACHINA_QCOW_REFCOUNT_H_
#define GARNET_LIB_MACHINA_QCOW_REFCOUNT_H_
#include <fbl/array.h>
#include <stdint.h>
#include <zircon/types.h>
#include "garnet/lib/machina/bits.h"
#include "lib/fxl/macros.h"
namespace machina {
struct QcowHeader;
// The QCOW refcount table manages the number of references to each physical
// cluster on the disk.
//
// In the simple case, a refcount of 0 indicates the block is currently unused
// and is free to be allocated whenever more disk clusters are required.
//
// A refcount of 1 indicates the cluster is in use by exactly one purpose. Reads
// and writes can touch the block directly.
//
// A refcount > 1 indicates that the block is shared. Reads may complete
// normally but writes will require the cluster to be copied to a new cluster
// for the write before completing.
class QcowRefcount {
public:
QcowRefcount();
QcowRefcount(QcowRefcount&& other);
QcowRefcount& operator=(QcowRefcount&& other);
// Read in the top level refcount table.
zx_status_t Load(int fd, const QcowHeader& header);
// Reads the refcount for the physical cluster with the provided |index|. The
// index is the cluster number, or in other words:
//
// cluster_offset = cluster_number << cluster_bits
//
// On success |ZX_OK| is returned and the clusters refcount is written to
// |count|.
zx_status_t ReadRefcount(size_t index, uint64_t* count);
// Writes the refcount for the physical cluster with the provided |index|. The
// index is the cluster number, or in other words:
//
// cluster_offset = cluster_number << cluster_bits
//
// On success |ZX_OK| is returned and the clusters refcount is written to
// |count|. If |count| would overflow refcount field |ZX_ERR_INVALID_ARGS| is
// returned.
zx_status_t WriteRefcount(size_t index, uint64_t count);
private:
FXL_DISALLOW_COPY_AND_ASSIGN(QcowRefcount);
// The number of bits used for each clusters refcount field.
uint32_t refcount_bits() const { return 1u << refcount_order_; }
// A bit mask that matches the width of the culsters refcount field.
uint64_t refcount_mask() const { return bit_mask<uint64_t>(refcount_bits()); }
zx_status_t ReadRefcountBlock(uint32_t block_index, uint8_t** block);
int fd_ = -1;
uint32_t refcount_order_;
uint32_t cluster_size_;
// Retain the entire top level refcount table in memory.
using RefcountTableEntry = uint64_t;
fbl::Array<RefcountTableEntry> refcount_table_;
// Only cache the most recently accessed refcount block.
int64_t loaded_block_index_ = -1;
fbl::Array<uint8_t> loaded_block_;
};
} // namespace machina
#endif // GARNET_LIB_MACHINA_QCOW_REFCOUNT_H_