int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{ struct mtd_blktrans_ops *tr = new->tr; struct mtd_blktrans_dev *d; struct queue_limits lim = { }; int last_devnum = -1; struct gendisk *gd; int ret;
lockdep_assert_held(&mtd_table_mutex);
list_for_each_entry(d, &tr->devs, list) { if (new->devnum == -1) { /* Use first free number */ if (d->devnum != last_devnum+1) { /* Found a free devnum. Plug it in here */
new->devnum = last_devnum+1;
list_add_tail(&new->list, &d->list); goto added;
}
} elseif (d->devnum == new->devnum) { /* Required number taken */ return -EBUSY;
} elseif (d->devnum > new->devnum) { /* Required number was free */
list_add_tail(&new->list, &d->list); goto added;
}
last_devnum = d->devnum;
}
ret = -EBUSY; if (new->devnum == -1)
new->devnum = last_devnum+1;
/* Check that the device and any partitions will get valid * minor numbers and that the disk naming code below can cope
* with this number. */ if (new->devnum > (MINORMASK >> tr->part_bits) ||
(tr->part_bits && new->devnum >= 27 * 26)) return ret;
list_add_tail(&new->list, &tr->devs);
added:
mutex_init(&new->lock);
kref_init(&new->ref); if (!tr->writesect)
new->readonly = 1;
ret = -ENOMEM;
new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL); if (!new->tag_set) goto out_list_del;
ret = blk_mq_alloc_sq_tag_set(new->tag_set, &mtd_mq_ops, 2,
BLK_MQ_F_BLOCKING); if (ret) goto out_kfree_tag_set;
lim.logical_block_size = tr->blksize; if (tr->discard)
lim.max_hw_discard_sectors = UINT_MAX; if (tr->flush)
lim.features |= BLK_FEAT_WRITE_CACHE;
/* Create gendisk */
gd = blk_mq_alloc_disk(new->tag_set, &lim, new); if (IS_ERR(gd)) {
ret = PTR_ERR(gd); goto out_free_tag_set;
}
/* freeze+quiesce queue to ensure all requests are flushed */
memflags = blk_mq_freeze_queue(old->rq);
blk_mq_quiesce_queue(old->rq);
blk_mq_unquiesce_queue(old->rq);
blk_mq_unfreeze_queue(old->rq, memflags);
/* If the device is currently open, tell trans driver to close it,
then put mtd device, and don't touch it again */
mutex_lock(&old->lock); if (old->open) { if (old->tr->release)
old->tr->release(old);
__put_mtd_device(old->mtd);
}
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
{ struct mtd_info *mtd; int ret;
/* Register the notifier if/when the first device type is registered, to prevent the link/init ordering from fucking
us over. */ if (!blktrans_notifier.list.next)
register_mtd_user(&blktrans_notifier);
ret = register_blkdev(tr->major, tr->name); if (ret < 0) {
printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
tr->name, tr->major, ret); return ret;
}
staticvoid __exit mtd_blktrans_exit(void)
{ /* No race here -- if someone's currently in register_mtd_blktrans
we're screwed anyway. */ if (blktrans_notifier.list.next)
unregister_mtd_user(&blktrans_notifier);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.