79 lines
2.1 KiB
C
79 lines
2.1 KiB
C
// SPDX-License-Identifier: ISC
|
|
|
|
#include <zinnia/alloc.h>
|
|
#include <zinnia/atomic.h>
|
|
#include <zinnia/blockdev.h>
|
|
#include <stdint.h>
|
|
|
|
struct partition {
|
|
struct blockdev blk;
|
|
struct blockdev* parent;
|
|
uint64_t start;
|
|
};
|
|
|
|
static _Atomic(uint32_t) next_minor;
|
|
|
|
static errno_t partition_submit(struct blockdev* blk, struct bio* bio) {
|
|
struct partition* part = containerof(blk, struct partition, blk);
|
|
struct blockdev* parent = part->parent;
|
|
|
|
if (bio->op != BIO_FLUSH) {
|
|
if (bio->lba >= blk->lba_count) {
|
|
bio_complete(bio, bio->op == BIO_READ ? 0 : ENOSPC, 0);
|
|
return 0;
|
|
}
|
|
if (bio->op == BIO_WRITE && bio->num_lbas > blk->lba_count - bio->lba) {
|
|
bio_complete(bio, ENOSPC, 0);
|
|
return 0;
|
|
}
|
|
bio->lba += part->start;
|
|
}
|
|
return parent->ops->submit(parent, bio);
|
|
}
|
|
|
|
static errno_t partition_ioctl(
|
|
struct blockdev* blk,
|
|
struct vfs_file* file,
|
|
uintptr_t request,
|
|
uintptr_t arg,
|
|
uintptr_t* out
|
|
) {
|
|
struct blockdev* parent = containerof(blk, struct partition, blk)->parent;
|
|
if (!parent->ops->ioctl)
|
|
return ENOTTY;
|
|
return parent->ops->ioctl(parent, file, request, arg, out);
|
|
}
|
|
|
|
static void partition_destroy(struct blockdev* blk) {
|
|
struct partition* part = containerof(blk, struct partition, blk);
|
|
blockdev_unref(part->parent);
|
|
mem_free(part);
|
|
}
|
|
|
|
static const struct blockdev_ops partition_ops = {
|
|
.submit = partition_submit,
|
|
.ioctl = partition_ioctl,
|
|
.destroy = partition_destroy,
|
|
};
|
|
|
|
errno_t partition_new(struct blockdev* parent, uint64_t start_lba, uint64_t lba_count, struct blockdev** out) {
|
|
struct partition* part = mem_alloc(sizeof(struct partition), 0);
|
|
if (!part)
|
|
return ENOMEM;
|
|
|
|
blockdev_init(
|
|
&part->blk,
|
|
&partition_ops,
|
|
259,
|
|
atomic_fetch_add(&next_minor, 1, ATOMIC_RELAXED),
|
|
parent->lba_size,
|
|
lba_count
|
|
);
|
|
part->blk.limits = parent->limits;
|
|
blockdev_ref(parent);
|
|
part->parent = parent;
|
|
part->start = start_lba;
|
|
*out = &part->blk;
|
|
return 0;
|
|
}
|