diff options
author | Frederic Robra | 2019-08-23 12:09:03 +0200 |
---|---|---|
committer | Frederic Robra | 2019-08-23 12:09:03 +0200 |
commit | f6c99126c9df1cae6a8d9b51998760a5896f4e9d (patch) | |
tree | 7cb2032c6e2960eed328dcff9903ae41886a18c8 /src/kernel/mq.c | |
parent | changed strategy to connect to diffrent sockets (diff) | |
download | dnbd3-ng-f6c99126c9df1cae6a8d9b51998760a5896f4e9d.tar.gz dnbd3-ng-f6c99126c9df1cae6a8d9b51998760a5896f4e9d.tar.xz dnbd3-ng-f6c99126c9df1cae6a8d9b51998760a5896f4e9d.zip |
moved mq part to new file
fixed various bugs
Diffstat (limited to 'src/kernel/mq.c')
-rw-r--r-- | src/kernel/mq.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/kernel/mq.c b/src/kernel/mq.c new file mode 100644 index 0000000..0a99817 --- /dev/null +++ b/src/kernel/mq.c @@ -0,0 +1,251 @@ +/* + * This file is part of the Distributed Network Block Device 3 + * + * Copyright(c) 2019 Frederic Robra <frederic@robra.org> + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mq.h" +#include "net.h" + +#include <linux/wait.h> +#include <linux/blk-mq.h> + +/** + * dnbd3_busy_iter - iterator for blk_mq_tagset_busy_iter + * @req: the request + * @priv: the passed argument from blk_mq_tagset_busy_iter + * @arg2: unknown + */ +static void dnbd3_busy_iter(struct request *req, void *priv, bool arg2) +{ + bool *is_busy = (bool *) priv; + *is_busy = true; +} + +/** + * dnbd3_is_mq_busy - check if mq is busy + * @dev: the device + */ +bool dnbd3_is_mq_busy(struct dnbd3_device *dev) +{ + struct blk_mq_tag_set *set = &dev->tag_set; + bool is_busy = false; + + blk_mq_tagset_busy_iter(set, dnbd3_busy_iter, &is_busy); + + /* + * just for demonstration + * with this it is possible to iterate through the hardware queues + * + int i = 0; + struct request_queue *q; + struct blk_mq_hw_ctx *hctx; + list_for_each_entry(q, &set->tag_list, tag_set_list) { + + for (i = 0; i < NUMBER_CONNECTIONS; i++) { + hctx = q->queue_hw_ctx[i]; + debug_dev(dev, "%i %lu", i, hctx->queued); + } + } + */ + + return is_busy; +} + + +/** + * dnbd3_requeue_cmd - requeue a command once + * @cmd: the command to requeue + */ +void dnbd3_requeue_cmd(struct dnbd3_cmd *cmd) +{ + struct request *req = blk_mq_rq_from_pdu(cmd); + if (!cmd->requed) { + cmd->requed = true; + blk_mq_requeue_request(req, true); + } +} + +/** + * dnbd3_end_cmd - end a blk request + * @cmd: the command to end the request with + * @error: the status + */ +void dnbd3_end_cmd(struct dnbd3_cmd *cmd, blk_status_t error) +{ + struct request *req = blk_mq_rq_from_pdu(cmd); + blk_mq_end_request(req, error); +} + +/** + * dnbd3_is_any_sock_alive - check if any socket is alive + * @cmd: the command + */ +static bool dnbd3_is_any_sock_alive(struct dnbd3_cmd *cmd) { + int i; + for (i = 0; i < NUMBER_CONNECTIONS; i++) { + if (dnbd3_is_sock_alive(cmd->dnbd3->socks[i])) { + return true; + } + } + return false; +} + +/** + * dnbd3_handle_cmd - handles a mq command + * @cmd: the cmd to send + * @index: the index of the queue + */ +static int dnbd3_handle_cmd(struct dnbd3_cmd *cmd, int index) +{ + struct request *req = blk_mq_rq_from_pdu(cmd); + struct dnbd3_device *dev = cmd->dnbd3; + struct dnbd3_sock *sock = &dev->socks[index]; + int ret = -1; + +// debug_dev(dev, "handle request at position %lu, size %d, index %d", +// blk_rq_pos(req), blk_rq_bytes(req), index); + + + if (!(sock->server && sock->sock && !sock->panic)) { + warn_dev(dev, "attempted send on invalid socket %d", index); +// msleep(SOCKET_TIMEOUT_CLIENT_DATA * 1000); + + if (dnbd3_is_any_sock_alive(cmd)) { + info_dev(dev, "reset request to new socket"); + dnbd3_requeue_cmd(cmd); + ret = 0; + goto out; + } else { + error_dev(dev, "ending request, no socket found"); + dnbd3_end_cmd(cmd, BLK_STS_IOERR); + ret = -EIO; + goto out; + } + } + + cmd->status = BLK_STS_OK; + + mutex_lock(&sock->tx_lock); + if (unlikely(!sock->sock)) { + mutex_unlock(&sock->tx_lock); + warn_sock(sock, "not connected"); + return -EIO; + } + + blk_mq_start_request(req); + if (unlikely(sock->pending && sock->pending != req)) { + dnbd3_requeue_cmd(cmd); + ret = 0; + goto out; + } + + ret = dnbd3_send_request(sock, blk_mq_rq_from_pdu(cmd), cmd); + if (ret == -EAGAIN) { + dev_err_ratelimited(disk_to_dev(dev->disk), "request send failed, requeueing\n"); + dnbd3_requeue_cmd(cmd); + ret = 0; + } +out: + mutex_unlock(&sock->tx_lock); + return ret; +} + +/** + * dnbd3_queue_rq - queue request + * @hctx: state for a hardware queue facing the hardware block device + * @bd: the queue data including the request + */ +static blk_status_t dnbd3_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) +{ + struct dnbd3_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); + int ret; + + mutex_lock(&cmd->lock); + + cmd->requed = false; + + ret = dnbd3_handle_cmd(cmd, hctx->queue_num); + if (ret < 0) { + ret = BLK_STS_IOERR; + } else if (ret >= 0) { + ret = BLK_STS_OK; + } + mutex_unlock(&cmd->lock); + + return ret; +} + +/** + * dnbd3_init_request - init a mq request + * @set: the mq tag set + * @rq: the request + * @hctx_idx: + * @numa_node: + */ +static int dnbd3_init_request(struct blk_mq_tag_set *set, struct request *rq, + unsigned int hctx_idx, unsigned int numa_node) +{ + struct dnbd3_cmd *cmd = blk_mq_rq_to_pdu(rq); + cmd->dnbd3 = set->driver_data; + cmd->requed = false; + mutex_init(&cmd->lock); + return 0; +} + +/** + * dnbd3_xmit_timeout - timeout function for mq + * @req: the timedout request + * @reserved: + */ +static enum blk_eh_timer_return dnbd3_xmit_timeout(struct request *req, + bool reserved) +{ + struct dnbd3_cmd *cmd = blk_mq_rq_to_pdu(req); + struct dnbd3_device *dev = cmd->dnbd3; + warn_dev(dev, "received timeout"); + + if (!mutex_trylock(&cmd->lock)) { + return BLK_EH_RESET_TIMER; + } + + if (dnbd3_is_any_sock_alive(cmd)) { + info_dev(dev, "reset request to new socket"); + dnbd3_requeue_cmd(cmd); + return BLK_EH_DONE; + } + + dev_err_ratelimited(disk_to_dev(dev->disk), "connection timed out\n"); + cmd->status = BLK_STS_IOERR; +// blk_mq_complete_request(req); + dnbd3_end_cmd(cmd, BLK_STS_TIMEOUT); + return BLK_EH_DONE; +} + +/** + * struct blk_mq_ops - dnbd3_mq_ops + * multiqueue operations + */ +struct blk_mq_ops dnbd3_mq_ops = { + .queue_rq = dnbd3_queue_rq, + .init_request = dnbd3_init_request, + .timeout = dnbd3_xmit_timeout, +}; + + + |