Lines Matching +full:2 +full:- +full:layered
1 // SPDX-License-Identifier: GPL-2.0-only
13 * Read-only block devices on top of UBI volumes
15 * A simple implementation to allow a block device to be layered on top of a
16 * UBI volume. The implementation is provided by creating a static 1-to-1
40 #include <linux/blk-mq.h>
46 #include "ubi-media.h"
55 /* Maximum number of comma-separated items in the 'block=' parameter */
56 #define UBIBLOCK_PARAM_COUNT 2
110 return -EINVAL; in ubiblock_set_param()
114 pr_warn("UBI: block: empty 'block=' parameter - ignored\n"); in ubiblock_set_param()
121 return -EINVAL; in ubiblock_set_param()
127 if (buf[len - 1] == '\n') in ubiblock_set_param()
128 buf[len - 1] = '\0'; in ubiblock_set_param()
136 ret = kstrtoint(tokens[0], 10, ¶m->ubi_num); in ubiblock_set_param()
138 return -EINVAL; in ubiblock_set_param()
141 ret = kstrtoint(tokens[1], 10, ¶m->vol_id); in ubiblock_set_param()
143 param->vol_id = -1; in ubiblock_set_param()
144 strcpy(param->name, tokens[1]); in ubiblock_set_param()
149 strcpy(param->name, tokens[0]); in ubiblock_set_param()
150 param->ubi_num = -1; in ubiblock_set_param()
151 param->vol_id = -1; in ubiblock_set_param()
179 if (dev->ubi_num == ubi_num && dev->vol_id == vol_id) in find_dev_nolock()
189 struct ubiblock *dev = req->q->queuedata; in ubiblock_read()
195 offset = do_div(pos, dev->leb_size); in ubiblock_read()
204 if (offset + to_read > dev->leb_size) in ubiblock_read()
205 to_read = dev->leb_size - offset; in ubiblock_read()
207 ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read); in ubiblock_read()
211 bytes_left -= to_read; in ubiblock_read()
221 struct ubiblock *dev = bdev->bd_disk->private_data; in ubiblock_open()
224 mutex_lock(&dev->dev_mutex); in ubiblock_open()
225 if (dev->refcnt > 0) { in ubiblock_open()
234 * We want users to be aware they should only mount us as read-only. in ubiblock_open()
239 ret = -EROFS; in ubiblock_open()
243 dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY); in ubiblock_open()
244 if (IS_ERR(dev->desc)) { in ubiblock_open()
245 dev_err(disk_to_dev(dev->gd), "failed to open ubi volume %d_%d", in ubiblock_open()
246 dev->ubi_num, dev->vol_id); in ubiblock_open()
247 ret = PTR_ERR(dev->desc); in ubiblock_open()
248 dev->desc = NULL; in ubiblock_open()
253 dev->refcnt++; in ubiblock_open()
254 mutex_unlock(&dev->dev_mutex); in ubiblock_open()
258 mutex_unlock(&dev->dev_mutex); in ubiblock_open()
264 struct ubiblock *dev = gd->private_data; in ubiblock_release()
266 mutex_lock(&dev->dev_mutex); in ubiblock_release()
267 dev->refcnt--; in ubiblock_release()
268 if (dev->refcnt == 0) { in ubiblock_release()
269 ubi_close_volume(dev->desc); in ubiblock_release()
270 dev->desc = NULL; in ubiblock_release()
272 mutex_unlock(&dev->dev_mutex); in ubiblock_release()
278 geo->heads = 1; in ubiblock_getgeo()
279 geo->cylinders = 1; in ubiblock_getgeo()
280 geo->sectors = get_capacity(bdev->bd_disk); in ubiblock_getgeo()
281 geo->start = 0; in ubiblock_getgeo()
307 blk_rq_map_sg(req->q, req, pdu->usgl.sg); in ubiblock_do_work()
320 struct request *req = bd->rq; in ubiblock_queue_rq()
321 struct ubiblock *dev = hctx->queue->queuedata; in ubiblock_queue_rq()
326 ubi_sgl_init(&pdu->usgl); in ubiblock_queue_rq()
327 queue_work(dev->wq, &pdu->work); in ubiblock_queue_rq()
341 sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT); in ubiblock_init_request()
342 INIT_WORK(&pdu->work, ubiblock_do_work); in ubiblock_init_request()
354 u64 size = vi->used_bytes >> 9; in calc_disk_capacity()
356 if (vi->used_bytes % 512) { in calc_disk_capacity()
359 vi->used_bytes - (size << 9)); in calc_disk_capacity()
363 return -EFBIG; in calc_disk_capacity()
384 if (find_dev_nolock(vi->ubi_num, vi->vol_id)) { in ubiblock_create()
385 ret = -EEXIST; in ubiblock_create()
391 ret = -ENOMEM; in ubiblock_create()
395 mutex_init(&dev->dev_mutex); in ubiblock_create()
397 dev->ubi_num = vi->ubi_num; in ubiblock_create()
398 dev->vol_id = vi->vol_id; in ubiblock_create()
399 dev->leb_size = vi->usable_leb_size; in ubiblock_create()
401 dev->tag_set.ops = &ubiblock_mq_ops; in ubiblock_create()
402 dev->tag_set.queue_depth = 64; in ubiblock_create()
403 dev->tag_set.numa_node = NUMA_NO_NODE; in ubiblock_create()
404 dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; in ubiblock_create()
405 dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu); in ubiblock_create()
406 dev->tag_set.driver_data = dev; in ubiblock_create()
407 dev->tag_set.nr_hw_queues = 1; in ubiblock_create()
409 ret = blk_mq_alloc_tag_set(&dev->tag_set); in ubiblock_create()
411 dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed"); in ubiblock_create()
417 gd = blk_mq_alloc_disk(&dev->tag_set, dev); in ubiblock_create()
423 gd->fops = &ubiblock_ops; in ubiblock_create()
424 gd->major = ubiblock_major; in ubiblock_create()
425 gd->minors = 1; in ubiblock_create()
426 gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL); in ubiblock_create()
427 if (gd->first_minor < 0) { in ubiblock_create()
430 ret = -ENODEV; in ubiblock_create()
433 gd->flags |= GENHD_FL_NO_PART; in ubiblock_create()
434 gd->private_data = dev; in ubiblock_create()
435 sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); in ubiblock_create()
437 dev->gd = gd; in ubiblock_create()
439 dev->rq = gd->queue; in ubiblock_create()
440 blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT); in ubiblock_create()
446 dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name); in ubiblock_create()
447 if (!dev->wq) { in ubiblock_create()
448 ret = -ENOMEM; in ubiblock_create()
452 list_add_tail(&dev->list, &ubiblock_devices); in ubiblock_create()
455 ret = add_disk(dev->gd); in ubiblock_create()
459 dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", in ubiblock_create()
460 dev->ubi_num, dev->vol_id, vi->name); in ubiblock_create()
465 list_del(&dev->list); in ubiblock_create()
466 destroy_workqueue(dev->wq); in ubiblock_create()
468 idr_remove(&ubiblock_minor_idr, gd->first_minor); in ubiblock_create()
470 put_disk(dev->gd); in ubiblock_create()
472 blk_mq_free_tag_set(&dev->tag_set); in ubiblock_create()
484 del_gendisk(dev->gd); in ubiblock_cleanup()
486 destroy_workqueue(dev->wq); in ubiblock_cleanup()
488 dev_info(disk_to_dev(dev->gd), "released"); in ubiblock_cleanup()
489 put_disk(dev->gd); in ubiblock_cleanup()
490 blk_mq_free_tag_set(&dev->tag_set); in ubiblock_cleanup()
491 idr_remove(&ubiblock_minor_idr, dev->gd->first_minor); in ubiblock_cleanup()
500 dev = find_dev_nolock(vi->ubi_num, vi->vol_id); in ubiblock_remove()
502 ret = -ENODEV; in ubiblock_remove()
507 mutex_lock(&dev->dev_mutex); in ubiblock_remove()
508 if (dev->refcnt > 0) { in ubiblock_remove()
509 ret = -EBUSY; in ubiblock_remove()
514 list_del(&dev->list); in ubiblock_remove()
516 mutex_unlock(&dev->dev_mutex); in ubiblock_remove()
523 mutex_unlock(&dev->dev_mutex); in ubiblock_remove()
541 dev = find_dev_nolock(vi->ubi_num, vi->vol_id); in ubiblock_resize()
544 return -ENODEV; in ubiblock_resize()
550 if (ret == -EFBIG) { in ubiblock_resize()
551 dev_warn(disk_to_dev(dev->gd), in ubiblock_resize()
553 vi->size); in ubiblock_resize()
558 mutex_lock(&dev->dev_mutex); in ubiblock_resize()
560 if (get_capacity(dev->gd) != disk_capacity) { in ubiblock_resize()
561 set_capacity(dev->gd, disk_capacity); in ubiblock_resize()
562 dev_info(disk_to_dev(dev->gd), "resized to %lld bytes", in ubiblock_resize()
563 vi->used_bytes); in ubiblock_resize()
565 mutex_unlock(&dev->dev_mutex); in ubiblock_resize()
583 ubiblock_remove(&nt->vi); in ubiblock_notify()
586 ubiblock_resize(&nt->vi); in ubiblock_notify()
593 if (nt->vi.vol_type == UBI_STATIC_VOLUME) in ubiblock_notify()
594 ubiblock_resize(&nt->vi); in ubiblock_notify()
609 if (ubi_num == -1) in open_volume_desc()
612 else if (vol_id == -1) in open_volume_desc()
629 * the kernel command-line specifies multiple block devices and some in ubiblock_create_from_param()
635 desc = open_volume_desc(p->name, p->ubi_num, p->vol_id); in ubiblock_create_from_param()
639 p->ubi_num, p->vol_id, PTR_ERR(desc)); in ubiblock_create_from_param()
650 vi.name, p->ubi_num, p->vol_id, ret); in ubiblock_create_from_param()
664 WARN_ON(dev->desc); in ubiblock_remove_all()
666 list_del(&dev->list); in ubiblock_remove_all()