// Copyright 2016 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. #include #include #include #include #include #include #include #include #include #include #include #include "minfs-private.h" namespace minfs { zx_status_t Bcache::Readblk(blk_t bno, void* data) { off_t off = static_cast(bno) * kMinfsBlockSize; assert(off / kMinfsBlockSize == bno); // Overflow #ifndef __Fuchsia__ off += offset_; #endif if (lseek(fd_.get(), off, SEEK_SET) < 0) { FS_TRACE_ERROR("minfs: cannot seek to block %u\n", bno); return ZX_ERR_IO; } if (read(fd_.get(), data, kMinfsBlockSize) != kMinfsBlockSize) { FS_TRACE_ERROR("minfs: cannot read block %u\n", bno); return ZX_ERR_IO; } return ZX_OK; } zx_status_t Bcache::Writeblk(blk_t bno, const void* data) { off_t off = static_cast(bno) * kMinfsBlockSize; assert(off / kMinfsBlockSize == bno); // Overflow #ifndef __Fuchsia__ off += offset_; #endif if (lseek(fd_.get(), off, SEEK_SET) < 0) { FS_TRACE_ERROR("minfs: cannot seek to block %u\n", bno); return ZX_ERR_IO; } if (write(fd_.get(), data, kMinfsBlockSize) != kMinfsBlockSize) { FS_TRACE_ERROR("minfs: cannot write block %u\n", bno); return ZX_ERR_IO; } return ZX_OK; } int Bcache::Sync() { fs::WriteTxn sync_txn(this); sync_txn.EnqueueFlush(); return sync_txn.Transact(); } zx_status_t Bcache::Create(fbl::unique_ptr* out, fbl::unique_fd fd, uint32_t blockmax) { fbl::AllocChecker ac; fbl::unique_ptr bc(new (&ac) Bcache(fbl::move(fd), blockmax)); if (!ac.check()) { return ZX_ERR_NO_MEMORY; } #ifdef __Fuchsia__ zx::fifo fifo; ssize_t r; if ((r = ioctl_block_get_info(bc->fd_.get(), &bc->info_)) < 0) { FS_TRACE_ERROR("minfs: Cannot acquire block device information: %" PRId64 "\n", r); return static_cast(r); } else if (kMinfsBlockSize % bc->info_.block_size != 0) { FS_TRACE_ERROR("minfs: minfs Block size not multiple of underlying block size\n"); return ZX_ERR_BAD_STATE; } else if ((r = ioctl_block_get_fifos(bc->fd_.get(), fifo.reset_and_get_address())) < 0) { FS_TRACE_ERROR("minfs: Cannot acquire block device fifo: %" PRId64 "\n", r); return static_cast(r); } zx_status_t status; if ((status = block_client::Client::Create(fbl::move(fifo), &bc->fifo_client_)) != ZX_OK) { return status; } #endif *out = fbl::move(bc); return ZX_OK; } #ifdef __Fuchsia__ zx_status_t Bcache::GetDevicePath(size_t buffer_len, char* out_name, size_t* out_len) { ssize_t r = ioctl_device_get_topo_path(fd_.get(), out_name, buffer_len); if (r < 0) { return static_cast(r); } *out_len = r; return ZX_OK; } zx_status_t Bcache::AttachVmo(zx_handle_t vmo, vmoid_t* out) const { zx_handle_t xfer_vmo; zx_status_t status = zx_handle_duplicate(vmo, ZX_RIGHT_SAME_RIGHTS, &xfer_vmo); if (status != ZX_OK) { return status; } ssize_t r = ioctl_block_attach_vmo(fd_.get(), &xfer_vmo, out); if (r < 0) { zx_handle_close(xfer_vmo); return static_cast(r); } return ZX_OK; } #endif Bcache::Bcache(fbl::unique_fd fd, uint32_t blockmax) : fd_(fbl::move(fd)), blockmax_(blockmax) {} Bcache::~Bcache() { #ifdef __Fuchsia__ if (fd_) { ioctl_block_fifo_close(fd_.get()); } #endif } #ifndef __Fuchsia__ zx_status_t Bcache::SetOffset(off_t offset) { if (offset_ || extent_lengths_.size() > 0) { return ZX_ERR_ALREADY_BOUND; } offset_ = offset; return ZX_OK; } zx_status_t Bcache::SetSparse(off_t offset, const fbl::Vector& extent_lengths) { if (offset_ || extent_lengths_.size() > 0) { return ZX_ERR_ALREADY_BOUND; } ZX_ASSERT(extent_lengths.size() == EXTENT_COUNT); fbl::AllocChecker ac; extent_lengths_.reset(new (&ac) size_t[EXTENT_COUNT], EXTENT_COUNT); if (!ac.check()) { return ZX_ERR_NO_MEMORY; } extent_lengths_[0] = extent_lengths[0]; extent_lengths_[1] = extent_lengths[1]; extent_lengths_[2] = extent_lengths[2]; extent_lengths_[3] = extent_lengths[3]; extent_lengths_[4] = extent_lengths[4]; offset_ = offset; return ZX_OK; } // This is used by the ioctl wrappers in zircon/device/device.h. It's not // called by host tools, so just satisfy the linker with a stub. ssize_t fdio_ioctl(int fd, int op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len) { return -1; } #endif } // namespace minfs