drivers/mtd/ubi/block.c

Source file repositories/reference/linux-study-clean/drivers/mtd/ubi/block.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/ubi/block.c
Extension
.c
Size
15948 bytes
Lines
679
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct blk_mq_ops ubiblock_mq_ops = {
	.queue_rq       = ubiblock_queue_rq,
	.init_request	= ubiblock_init_request,
};

static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
{
	u64 size = vi->used_bytes >> 9;

	if (vi->used_bytes % 512) {
		if (vi->vol_type == UBI_DYNAMIC_VOLUME)
			pr_warn("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
				vi->used_bytes - (size << 9));
		else
			pr_info("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
				vi->used_bytes - (size << 9));
	}

	if ((sector_t)size != size)
		return -EFBIG;

	*disk_capacity = size;

	return 0;
}

int ubiblock_create(struct ubi_volume_info *vi)
{
	struct queue_limits lim = {
		.max_segments		= UBI_MAX_SG_COUNT,
	};
	struct ubiblock *dev;
	struct gendisk *gd;
	u64 disk_capacity;
	int ret;

	ret = calc_disk_capacity(vi, &disk_capacity);
	if (ret) {
		return ret;
	}

	/* Check that the volume isn't already handled */
	mutex_lock(&devices_mutex);
	if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
		ret = -EEXIST;
		goto out_unlock;
	}

	dev = kzalloc_obj(struct ubiblock);
	if (!dev) {
		ret = -ENOMEM;
		goto out_unlock;
	}

	mutex_init(&dev->dev_mutex);

	dev->ubi_num = vi->ubi_num;
	dev->vol_id = vi->vol_id;
	dev->leb_size = vi->usable_leb_size;

	dev->tag_set.ops = &ubiblock_mq_ops;
	dev->tag_set.queue_depth = 64;
	dev->tag_set.numa_node = NUMA_NO_NODE;
	dev->tag_set.flags = BLK_MQ_F_BLOCKING;
	dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
	dev->tag_set.driver_data = dev;
	dev->tag_set.nr_hw_queues = 1;

	ret = blk_mq_alloc_tag_set(&dev->tag_set);
	if (ret) {
		pr_err("ubiblock%d_%d: blk_mq_alloc_tag_set failed\n",
			dev->ubi_num, dev->vol_id);
		goto out_free_dev;
	}


	/* Initialize the gendisk of this ubiblock device */
	gd = blk_mq_alloc_disk(&dev->tag_set, &lim, dev);
	if (IS_ERR(gd)) {
		ret = PTR_ERR(gd);
		goto out_free_tags;
	}

	gd->fops = &ubiblock_ops;
	gd->major = ubiblock_major;
	gd->minors = 1;
	gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
	if (gd->first_minor < 0) {
		pr_err("ubiblock%d_%d: block: dynamic minor allocation failed\n",
			dev->ubi_num, dev->vol_id);

Annotation

Implementation Notes