@@ -35,6 +35,7 @@
#include <linux/genhd.h>
#include <linux/file.h>
#include <linux/module.h>
+#include <linux/configfs.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
@@ -114,6 +115,7 @@ static int iblock_configure_device(struct se_device *dev)
goto out_free_bioset;
}
ib_dev->ibd_bd = bd;
+ ib_dev->poll_batch = IBLOCK_POLL_BATCH;
q = bdev_get_queue(bd);
@@ -757,7 +759,8 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
}
iblock_submit_bios(&list);
- blk_mq_poll_batch(bdev_get_queue(IBLOCK_DEV(dev)->ibd_bd), 4);
+ blk_mq_poll_batch(bdev_get_queue(IBLOCK_DEV(dev)->ibd_bd),
+ IBLOCK_DEV(dev)->poll_batch);
iblock_complete_cmd(cmd);
return 0;
@@ -840,7 +843,38 @@ static bool iblock_get_write_cache(struct se_device *dev)
return test_bit(QUEUE_FLAG_WC, &q->queue_flags);
}
-static const struct target_backend_ops iblock_ops = {
+static ssize_t iblock_poll_batch_show(struct config_item *item, char *page)
+{
+ struct se_dev_attrib *da = container_of(to_config_group(item),
+ struct se_dev_attrib, da_group);
+ struct iblock_dev *ibd = container_of(da->da_dev,
+ struct iblock_dev, dev);
+
+ return snprintf(page, PAGE_SIZE, "%u\n", ibd->poll_batch);
+}
+
+static ssize_t iblock_poll_batch_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct se_dev_attrib *da = container_of(to_config_group(item),
+ struct se_dev_attrib, da_group);
+ struct iblock_dev *ibd = container_of(da->da_dev,
+ struct iblock_dev, dev);
+ u32 val;
+ int ret;
+
+ ret = kstrtou32(page, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ ibd->poll_batch = val;
+ return count;
+}
+CONFIGFS_ATTR(iblock_, poll_batch);
+
+static struct configfs_attribute **iblock_attrs;
+
+static struct target_backend_ops iblock_ops = {
.name = "iblock",
.inquiry_prod = "IBLOCK",
.inquiry_rev = IBLOCK_VERSION,
@@ -860,17 +894,40 @@ static bool iblock_get_write_cache(struct se_device *dev)
.get_io_min = iblock_get_io_min,
.get_io_opt = iblock_get_io_opt,
.get_write_cache = iblock_get_write_cache,
- .tb_dev_attrib_attrs = sbc_attrib_attrs,
+ .tb_dev_attrib_attrs = NULL,
};
static int __init iblock_module_init(void)
{
- return transport_backend_register(&iblock_ops);
+ int rc, i, len = 0;
+
+ for (i = 0; sbc_attrib_attrs[i] != NULL; i++) {
+ len += sizeof(struct configfs_attribute *);
+ }
+ len += sizeof(struct configfs_attribute *) * 2;
+
+ iblock_attrs = kzalloc(len, GFP_KERNEL);
+ if (!iblock_attrs)
+ return -ENOMEM;
+
+ for (i = 0; sbc_attrib_attrs[i] != NULL; i++) {
+ iblock_attrs[i] = sbc_attrib_attrs[i];
+ }
+ iblock_attrs[i] = &iblock_attr_poll_batch;
+ iblock_ops.tb_dev_attrib_attrs = iblock_attrs;
+
+ rc = transport_backend_register(&iblock_ops);
+ if (rc) {
+ kfree(iblock_attrs);
+ return rc;
+ }
+ return 0;
}
static void __exit iblock_module_exit(void)
{
target_backend_unregister(&iblock_ops);
+ kfree(iblock_attrs);
}
MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin");
@@ -8,6 +8,7 @@
#define IBLOCK_MAX_CDBS 16
#define IBLOCK_LBA_SHIFT 9
+#define IBLOCK_POLL_BATCH 4
struct iblock_req {
atomic_t pending;
@@ -23,6 +24,7 @@ struct iblock_dev {
struct bio_set *ibd_bio_set;
struct block_device *ibd_bd;
bool ibd_readonly;
+ unsigned int poll_batch;
} ____cacheline_aligned;
#endif /* TARGET_CORE_IBLOCK_H */