+/*
+ * Copyright (C) 2012 GRNET S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
/* xsegbd.c
*
*/
#define XSEGBD_MINORS 1
/* define max request size to be used in xsegbd */
-//FIXME should we make this 4MB instead of 256KB ?
-//#define XSEGBD_MAX_REQUEST_SIZE 262144U
#define XSEGBD_MAX_REQUEST_SIZE 4194304U
MODULE_DESCRIPTION("xsegbd");
static long sector_size = 0;
static long blksize = 512;
static int major = 0;
-static int max_dev = 1024;
+static int max_dev = 200;
+static long start_portno = 0;
+static long end_portno = 199;
static char name[XSEGBD_SEGMENT_NAMELEN] = "xsegbd";
-static char spec[256] = "segdev:xsegbd:4:1024:12";
+static char spec[256] = "segdev:xsegbd:512:1024:12";
module_param(sector_size, long, 0644);
module_param(blksize, long, 0644);
-module_param(max_dev, int, 0644);
+module_param(start_portno, long, 0644);
+module_param(end_portno, long, 0644);
module_param(major, int, 0644);
module_param_string(name, name, sizeof(name), 0644);
module_param_string(spec, spec, sizeof(spec), 0644);
return xsegbd_dev;
}
+static int src_portno_to_id(xport src_portno)
+{
+ return (src_portno - start_portno);
+}
+
/* ************************* */
/* ***** sysfs helpers ***** */
/* ************************* */
blk_queue_physical_block_size(xsegbd_dev->blk_queue, blksize);
blk_queue_bounce_limit(xsegbd_dev->blk_queue, BLK_BOUNCE_ANY);
- //blk_queue_max_segments(dev->blk_queue, 512);
max_request_size_bytes = XSEGBD_MAX_REQUEST_SIZE;
blk_queue_max_hw_sectors(xsegbd_dev->blk_queue, max_request_size_bytes >> 9);
// blk_queue_max_sectors(xsegbd_dev->blk_queue, max_request_size_bytes >> 10);
+ blk_queue_max_segments(xsegbd_dev->blk_queue, 1024);
blk_queue_max_segment_size(xsegbd_dev->blk_queue, max_request_size_bytes);
blk_queue_io_min(xsegbd_dev->blk_queue, max_request_size_bytes);
blk_queue_io_opt(xsegbd_dev->blk_queue, max_request_size_bytes);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, xsegbd_dev->blk_queue);
/* vkoukis says we don't need partitions */
- xsegbd_dev->gd = disk = alloc_disk(1);
+ xsegbd_dev->gd = disk = alloc_disk(XSEGBD_MINORS);
if (!disk)
goto out;
disk->major = xsegbd_dev->major;
- disk->first_minor = 0; // id * XSEGBD_MINORS;
+ disk->first_minor = xsegbd_dev->id * XSEGBD_MINORS;
disk->fops = &xsegbd_ops;
disk->queue = xsegbd_dev->blk_queue;
disk->private_data = xsegbd_dev;
snprintf(disk->disk_name, 32, "xsegbd%u", xsegbd_dev->id);
ret = 0;
-
+
/* allow a non-zero sector_size parameter to override the disk size */
if (sector_size)
xsegbd_dev->sectors = sector_size;
if (xsegbd_dev->gd) {
if (xsegbd_dev->gd->flags & GENHD_FL_UP)
del_gendisk(xsegbd_dev->gd);
-
+
xsegbd_mapclose(xsegbd_dev);
}
-
+
spin_lock(&xsegbd_devices_lock);
- BUG_ON(xsegbd_devices[xsegbd_dev->src_portno] != xsegbd_dev);
- xsegbd_devices[xsegbd_dev->src_portno] = NULL;
+ BUG_ON(xsegbd_devices[xsegbd_dev->id] != xsegbd_dev);
+ xsegbd_devices[xsegbd_dev->id] = NULL;
spin_unlock(&xsegbd_devices_lock);
XSEGLOG("releasing id: %d", xsegbd_dev->id);
// xseg_cancel_wait(xsegbd_dev->xseg, xsegbd_dev->src_portno);
xseg_quit_local_signal(xsegbd_dev->xseg, xsegbd_dev->src_portno);
- if (xsegbd_dev->gd)
- put_disk(xsegbd_dev->gd);
if (xsegbd_dev->blk_queue)
blk_cleanup_queue(xsegbd_dev->blk_queue);
+ if (xsegbd_dev->gd)
+ put_disk(xsegbd_dev->gd);
-// if (xseg_free_requests(xsegbd_dev->xseg,
+// if (xseg_free_requests(xsegbd_dev->xseg,
// xsegbd_dev->src_portno, xsegbd_dev->nr_requests) < 0)
// XSEGLOG("Error trying to free requests!\n");
xsegbd_dev->xseg = NULL;
}
- unregister_blkdev(xsegbd_dev->major, XSEGBD_NAME);
-
if (xsegbd_dev->blk_req_pending){
kfree(xsegbd_dev->blk_req_pending);
xsegbd_dev->blk_req_pending = NULL;
xsegbd_dev->src_portno);
if (blkreq_idx == Noneidx)
break;
-
+
if (blkreq_idx >= xsegbd_dev->nr_requests) {
XSEGLOG("blkreq_idx >= xsegbd_dev->nr_requests");
- BUG_ON(1);
+ WARN_ON(1);
break;
}
-
+
spin_lock_irqsave(&xsegbd_dev->rqlock, flags);
blkreq = blk_fetch_request(rq);
if (!blkreq){
if (r < 0) {
XSEGLOG("couldn't prep request");
blk_end_request_err(blkreq, r);
- BUG_ON(1);
+ WARN_ON(1);
break;
}
r = -ENOMEM;
if (xreq->bufferlen - xsegbd_dev->targetlen < datalen){
XSEGLOG("malformed req buffers");
blk_end_request_err(blkreq, r);
- BUG_ON(1);
+ WARN_ON(1);
break;
}
pending->dev = xsegbd_dev;
pending->request = blkreq;
pending->comp = NULL;
-
+
xreq->size = datalen;
xreq->offset = blk_rq_pos(blkreq) << 9;
xreq->priv = (uint64_t) blkreq_idx;
WARN_ON(xseg_signal(xsegbd_dev->xsegbd->xseg, p) < 0);
}
if (xreq)
- BUG_ON(xseg_put_request(xsegbd_dev->xsegbd->xseg, xreq,
+ WARN_ON(xseg_put_request(xsegbd_dev->xsegbd->xseg, xreq,
xsegbd_dev->src_portno) == -1);
if (blkreq_idx != Noneidx)
- BUG_ON(xq_append_head(&xsegbd_dev->blk_queue_pending,
+ WARN_ON(xq_append_head(&xsegbd_dev->blk_queue_pending,
blkreq_idx, xsegbd_dev->src_portno) == Noneidx);
spin_lock_irq(&xsegbd_dev->rqlock);
}
if (!xreq)
goto out;
- BUG_ON(xseg_prep_request(xsegbd_dev->xseg, xreq, xsegbd_dev->targetlen,
+ WARN_ON(xseg_prep_request(xsegbd_dev->xseg, xreq, xsegbd_dev->targetlen,
sizeof(struct xseg_reply_info)));
init_completion(&comp);
blkreq_idx = xq_pop_head(&xsegbd_dev->blk_queue_pending, 1);
if (blkreq_idx == Noneidx)
goto out_put;
-
+
pending = &xsegbd_dev->blk_req_pending[blkreq_idx];
pending->dev = xsegbd_dev;
pending->request = NULL;
pending->comp = ∁
-
+
xreq->priv = (uint64_t) blkreq_idx;
target = xseg_get_target(xsegbd_dev->xseg, xreq);
xreq->op = X_INFO;
xseg_prepare_wait(xsegbd_dev->xseg, xsegbd_dev->src_portno);
- p = xseg_submit(xsegbd_dev->xseg, xreq,
+ p = xseg_submit(xsegbd_dev->xseg, xreq,
xsegbd_dev->src_portno, X_ALLOC);
if ( p == NoPort) {
XSEGLOG("couldn't submit request");
- BUG_ON(1);
+ WARN_ON(1);
goto out_queue;
}
WARN_ON(xseg_signal(xsegbd_dev->xseg, p) < 0);
XSEGLOG("Woken up after wait_for_completion_interruptible(), comp: %lx [%llu]", (unsigned long) pending->comp, (unsigned long long) blkreq_idx);
ret = update_dev_sectors_from_request(xsegbd_dev, xreq);
XSEGLOG("get_size: sectors = %ld\n", (long)xsegbd_dev->sectors);
-out_put:
- BUG_ON(xseg_put_request(xsegbd_dev->xseg, xreq, xsegbd_dev->src_portno) == -1);
-out:
- return ret;
out_queue:
pending->dev = NULL;
pending->comp = NULL;
xq_append_head(&xsegbd_dev->blk_queue_pending, blkreq_idx, 1);
-
- goto out;
+out_put:
+ WARN_ON(xseg_put_request(xsegbd_dev->xseg, xreq, xsegbd_dev->src_portno) == -1);
+out:
+ return ret;
}
static int xsegbd_mapclose(struct xsegbd_device *xsegbd_dev)
if (!xreq)
goto out;
- BUG_ON(xseg_prep_request(xsegbd_dev->xseg, xreq, xsegbd_dev->targetlen, 0));
+ WARN_ON(xseg_prep_request(xsegbd_dev->xseg, xreq, xsegbd_dev->targetlen, 0));
init_completion(&comp);
blkreq_idx = xq_pop_head(&xsegbd_dev->blk_queue_pending, 1);
if (blkreq_idx == Noneidx)
goto out_put;
-
+
pending = &xsegbd_dev->blk_req_pending[blkreq_idx];
pending->dev = xsegbd_dev;
pending->request = NULL;
pending->comp = ∁
-
+
xreq->priv = (uint64_t) blkreq_idx;
target = xseg_get_target(xsegbd_dev->xseg, xreq);
xsegbd_dev->src_portno, X_ALLOC);
if ( p == NoPort) {
XSEGLOG("couldn't submit request");
- BUG_ON(1);
+ WARN_ON(1);
goto out_queue;
}
WARN_ON(xseg_signal(xsegbd_dev->xseg, p) < 0);
ret = 0;
if (xreq->state & XS_FAILED)
XSEGLOG("Couldn't close disk on mapper");
-out_put:
- BUG_ON(xseg_put_request(xsegbd_dev->xseg, xreq, xsegbd_dev->src_portno) == -1);
-out:
- return ret;
out_queue:
pending->dev = NULL;
pending->comp = NULL;
xq_append_head(&xsegbd_dev->blk_queue_pending, blkreq_idx, 1);
-
- goto out;
+out_put:
+ WARN_ON(xseg_put_request(xsegbd_dev->xseg, xreq, xsegbd_dev->src_portno) == -1);
+out:
+ return ret;
}
static void xseg_callback(xport portno)
if (xsegbd_dev != pending->dev) {
//FIXME maybe put request?
XSEGLOG("xsegbd_dev != pending->dev");
- BUG_ON(1);
+ WARN_ON(1);
continue;
}
pending->dev = NULL;
if (!blkreq){
//FIXME maybe put request?
XSEGLOG("blkreq does not exist");
- BUG_ON(1);
+ WARN_ON(1);
continue;
}
err = 0;
if (!rq_data_dir(blkreq)){
xseg_to_blk(xsegbd_dev->xseg, xreq, blkreq);
- }
+ }
blk_end:
blk_end_request_all(blkreq, err);
-
+
ridx = xq_append_head(&xsegbd_dev->blk_queue_pending,
blkreq_idx, xsegbd_dev->src_portno);
if (ridx == Noneidx) {
if (xseg_put_request(xsegbd_dev->xseg, xreq,
xsegbd_dev->src_portno) < 0){
XSEGLOG("couldn't put req");
- BUG_ON(1);
+ WARN_ON(1);
}
}
if (xsegbd_dev) {
}
xsegbd_dev->targetlen = strlen(xsegbd_dev->target);
+ if (xsegbd_dev->src_portno < start_portno || xsegbd_dev->src_portno > end_portno){
+ XSEGLOG("Invadid portno");
+ ret = -EINVAL;
+ goto out_dev;
+ }
+ xsegbd_dev->id = src_portno_to_id(xsegbd_dev->src_portno);
+
spin_lock(&xsegbd_devices_lock);
- if (xsegbd_devices[xsegbd_dev->src_portno] != NULL) {
+ if (xsegbd_devices[xsegbd_dev->id] != NULL) {
ret = -EINVAL;
goto out_unlock;
}
- xsegbd_devices[xsegbd_dev->src_portno] = xsegbd_dev;
- xsegbd_dev->id = xsegbd_dev->src_portno;
+ xsegbd_devices[xsegbd_dev->id] = xsegbd_dev;
spin_unlock(&xsegbd_devices_lock);
- XSEGLOG("registering block device major %d", major);
- ret = register_blkdev(major, XSEGBD_NAME);
- if (ret < 0) {
- XSEGLOG("cannot register block device!");
- ret = -EBUSY;
- goto out_delentry;
- }
- xsegbd_dev->major = ret;
- XSEGLOG("registered block device major %d", xsegbd_dev->major);
+ xsegbd_dev->major = major;
ret = xsegbd_bus_add_dev(xsegbd_dev);
if (ret)
- goto out_blkdev;
+ goto out_delentry;
- if (!xq_alloc_seq(&xsegbd_dev->blk_queue_pending,
+ if (!xq_alloc_seq(&xsegbd_dev->blk_queue_pending,
xsegbd_dev->nr_requests,
xsegbd_dev->nr_requests))
goto out_bus;
if (!xsegbd_dev->blk_req_pending)
goto out_bus;
-
+
XSEGLOG("joining segment");
//FIXME use xsebd module config for now
xsegbd_dev->xseg = xseg_join( xsegbd.config.type,
xseg_callback );
if (!xsegbd_dev->xseg)
goto out_bus;
-
+
XSEGLOG("%s binding to source port %u (destination %u)", xsegbd_dev->target,
xsegbd_dev->src_portno, xsegbd_dev->dst_portno);
port = xseg_bind_port(xsegbd_dev->xseg, xsegbd_dev->src_portno, NULL);
if (xsegbd_dev->src_portno != xseg_portno(xsegbd_dev->xseg, port)) {
XSEGLOG("portno != xsegbd_dev->src_portno");
- BUG_ON(1);
+ WARN_ON(1);
ret = -EFAULT;
goto out_bus;
}
xsegbd_bus_del_dev(xsegbd_dev);
return ret;
-out_blkdev:
- unregister_blkdev(xsegbd_dev->major, XSEGBD_NAME);
-
out_delentry:
spin_lock(&xsegbd_devices_lock);
- xsegbd_devices[xsegbd_dev->src_portno] = NULL;
+ xsegbd_devices[xsegbd_dev->id] = NULL;
out_unlock:
spin_unlock(&xsegbd_devices_lock);
kfree(xsegbd_dev);
out:
+ module_put(THIS_MODULE);
return ret;
}
static int __init xsegbd_init(void)
{
int ret = -ENOMEM;
+ max_dev = end_portno - start_portno;
+ if (max_dev < 0){
+ XSEGLOG("invalid port numbers");
+ ret = -EINVAL;
+ goto out;
+ }
xsegbd_devices = kzalloc(max_dev * sizeof(struct xsegbd_devices *), GFP_KERNEL);
if (!xsegbd_devices)
goto out;
spin_lock_init(&xsegbd_devices_lock);
+ XSEGLOG("registering block device major %d", major);
+ ret = register_blkdev(major, XSEGBD_NAME);
+ if (ret < 0) {
+ XSEGLOG("cannot register block device!");
+ ret = -EBUSY;
+ goto out_free;
+ }
+ major = ret;
+ XSEGLOG("registered block device major %d", major);
+
ret = -ENOSYS;
ret = xsegbd_xseg_init();
if (ret)
- goto out_free;
+ goto out_unregister;
ret = xsegbd_sysfs_init();
if (ret)
out_xseg:
xsegbd_xseg_quit();
-
+
+out_unregister:
+ unregister_blkdev(major, XSEGBD_NAME);
+
out_free:
kfree(xsegbd_devices);
{
xsegbd_sysfs_cleanup();
xsegbd_xseg_quit();
+ unregister_blkdev(major, XSEGBD_NAME);
}
module_init(xsegbd_init);