mirror of
https://github.com/schoebel/mars
synced 2025-05-01 07:38:07 +00:00
qio: new brick, replacing historic aio
This commit is contained in:
parent
812cfa685e
commit
26d5f34fbd
@ -57,6 +57,8 @@ mars-objs := \
|
|||||||
mars_net.o \
|
mars_net.o \
|
||||||
mars_server.o \
|
mars_server.o \
|
||||||
mars_client.o \
|
mars_client.o \
|
||||||
|
mars_qio.o \
|
||||||
|
lib_qio_rw.o \
|
||||||
mars_aio.o \
|
mars_aio.o \
|
||||||
mars_sio.o \
|
mars_sio.o \
|
||||||
mars_bio.o \
|
mars_bio.o \
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#
|
#
|
||||||
# MARS configuration
|
# MARS configuration
|
||||||
#
|
#
|
||||||
|
# This version uses new features like $(shell,$command) etc.
|
||||||
|
# An old version without such features can be found in then plain old
|
||||||
|
# Kconfig file.
|
||||||
|
|
||||||
config MARS
|
config MARS
|
||||||
tristate "block storage replication MARS"
|
tristate "block storage replication MARS"
|
||||||
@ -434,5 +437,47 @@ config MARS_PREFER_SIO
|
|||||||
depends on MARS
|
depends on MARS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
|
BAD_PERFORMANCE
|
||||||
Normally OFF for production systems.
|
Normally OFF for production systems.
|
||||||
Only use as alternative for testing.
|
Only use as alternative for testing.
|
||||||
|
|
||||||
|
config MARS_CANNOT_USE_AIO_ANYMORE
|
||||||
|
bool
|
||||||
|
# AFAICS the old aio brick cannot be used anymore, starting with
|
||||||
|
# LTS kernels >= 5.10.
|
||||||
|
# Maybe that certain Frankenstein kernels can play a different game,
|
||||||
|
# but suchalike is not my game.
|
||||||
|
# So I exclude the historic AIO right here, as best as I can at the moment.
|
||||||
|
# Maybe there is a bug at Kconfig level I did not notice yet.
|
||||||
|
# Hopefully this will continue to work with future upstream kernel releases.
|
||||||
|
# When it fails with old / Frankenstein kernel, only a warning should appear,
|
||||||
|
# which should then be ignored.
|
||||||
|
default y if $(shell,/bin/sh -c "if grep -q -s QUEUE_FLAG_STABLE_WRITES $abs_srctree/include/linux/blkdev.h; then echo y; else echo n; fi")
|
||||||
|
|
||||||
|
config MARS_PREFER_QIO
|
||||||
|
bool "prefer future qio brick instead of historic aio"
|
||||||
|
depends on MARS
|
||||||
|
depends on !MARS_CANNOT_USE_AIO_ANYMORE
|
||||||
|
depends on $(shell,/bin/sh -c "if grep -q -s QUEUE_FLAG_BIDI $abs_srctree/include/linux/blkdev.h; then echo NONE_NONE; else echo MARS; fi")
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
EXPERIMENTAL
|
||||||
|
Normally OFF for kernels < 5.10.x.
|
||||||
|
Only use as alternative for testing with those
|
||||||
|
kernels where it MAY work.
|
||||||
|
At the moment, this has not yet the maturity
|
||||||
|
you might expect.
|
||||||
|
AFAICS this is not usable before 8b3238cabd50e2715b6544e724e74685209b190a
|
||||||
|
(and maybe some more upstream patches, dto for Frankenstein kernels)
|
||||||
|
|
||||||
|
config MARS_TESTING_QIO_UNSAFE_PERFORMANCE
|
||||||
|
bool "DANGEROUS - only for testing"
|
||||||
|
depends on MARS_PREFER_QIO
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
EXPERIMENTAL
|
||||||
|
Please do not enable this unless you know exactly what you are doing.
|
||||||
|
Although it passes all my other tests, a primary crash will
|
||||||
|
easily lead to corrupt transaction logfiles. So you will always
|
||||||
|
need a forced primary somewhere, losing data.
|
||||||
|
NEVER FOR PRODUCTION!
|
||||||
|
416
kernel/lib_qio_rw.c
Normal file
416
kernel/lib_qio_rw.c
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* MARS Long Distance Replication Software
|
||||||
|
*
|
||||||
|
* This file is part of MARS project: http://schoebel.github.io/mars/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2014 Thomas Schoebel-Theuer
|
||||||
|
* Copyright (C) 2011-2014 1&1 Internet AG
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
/* Needed since 9a07000400c853c
|
||||||
|
* detected via d3d1e320d43a7ba
|
||||||
|
*/
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#ifndef __sched
|
||||||
|
#include <linux/sched/xacct.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
|
||||||
|
#include "lib_qio_rw.h"
|
||||||
|
|
||||||
|
#include <linux/backing-dev.h>
|
||||||
|
|
||||||
|
#define MARS_MAX_TRANSFER (128 * 1024)
|
||||||
|
|
||||||
|
#define MARS_MAX_RW_COUNT (MAX_RW_COUNT > MARS_MAX_TRANSFER ? \
|
||||||
|
MARS_MAX_TRANSFER :\
|
||||||
|
MAX_RW_COUNT)
|
||||||
|
|
||||||
|
#define MARS_NOT_STARTED (-EHWPOISON)
|
||||||
|
|
||||||
|
/******** KONVETIONS ****/
|
||||||
|
|
||||||
|
//#define KONVENTION_RET_LEN
|
||||||
|
|
||||||
|
/* Some code stolen from fs/ext4/file.c ext4_file_read_iter()
|
||||||
|
* and reduced / adapted to qio_rw.
|
||||||
|
* TODO: adapt this to any upstream kernel changes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
ssize_t qio_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||||
|
{
|
||||||
|
if (!iov_iter_count(to))
|
||||||
|
return 0; /* skip atime */
|
||||||
|
|
||||||
|
return generic_file_read_iter(iocb, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some code stolen from fs/ext4/file.c ext4_file_write_iter() => ext4_buffered_write_iter()
|
||||||
|
* and reduced / adapted to qio_rw.
|
||||||
|
* TODO: adapt this to any upstream kernel changes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
ssize_t qio_file_write_iter(struct kiocb *iocb, struct iov_iter *from,
|
||||||
|
bool wait_for_sync)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
|
|
||||||
|
if (iocb->ki_flags & IOCB_NOWAIT)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
inode_lock(inode);
|
||||||
|
|
||||||
|
current->backing_dev_info = inode_to_bdi(inode);
|
||||||
|
ret = generic_perform_write(iocb->ki_filp, from, iocb->ki_pos);
|
||||||
|
current->backing_dev_info = NULL;
|
||||||
|
|
||||||
|
inode_unlock(inode);
|
||||||
|
|
||||||
|
if (likely(ret > 0)) {
|
||||||
|
iocb->ki_pos += ret;
|
||||||
|
if (wait_for_sync)
|
||||||
|
ret = generic_write_sync(iocb, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KONVENTION_RET_LEN /* only for elder kernels */
|
||||||
|
static
|
||||||
|
int __fake_readahead(struct file *file,
|
||||||
|
loff_t pos, int len)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
pgoff_t index;
|
||||||
|
|
||||||
|
for (index = pos / PAGE_SIZE;
|
||||||
|
index <= (pos + len - 1) / PAGE_SIZE;
|
||||||
|
index++) {
|
||||||
|
struct page *tmp_page;
|
||||||
|
|
||||||
|
/* Stolen from fs/f2fs/super.c f2fs_quota_read()
|
||||||
|
*/
|
||||||
|
repeat:
|
||||||
|
tmp_page =
|
||||||
|
read_cache_page_gfp(file->f_mapping,
|
||||||
|
index,
|
||||||
|
GFP_NOFS);
|
||||||
|
if (IS_ERR(tmp_page) && PTR_ERR(tmp_page) == -ENOMEM) {
|
||||||
|
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QIO_MAX_KVEC (MARS_MAX_RW_COUNT / PAGE_SIZE + 2)
|
||||||
|
|
||||||
|
int qio_init_kvec(struct kvec iov[],
|
||||||
|
void *buf, size_t count)
|
||||||
|
{
|
||||||
|
__u64 segment = (__u64)buf / PAGE_SIZE;
|
||||||
|
__u64 first_usable_len;
|
||||||
|
__u64 this_len;
|
||||||
|
int nr = 0;
|
||||||
|
|
||||||
|
first_usable_len = (__u64)buf - segment * PAGE_SIZE;
|
||||||
|
if (!first_usable_len)
|
||||||
|
first_usable_len = PAGE_SIZE;
|
||||||
|
this_len = first_usable_len;
|
||||||
|
if (count < first_usable_len)
|
||||||
|
this_len = count;
|
||||||
|
while (count > 0) {
|
||||||
|
iov[nr].iov_base = buf;
|
||||||
|
iov[nr].iov_len = this_len;
|
||||||
|
buf += this_len;
|
||||||
|
count -= this_len;
|
||||||
|
nr++;
|
||||||
|
this_len = count;
|
||||||
|
if (this_len > PAGE_SIZE)
|
||||||
|
this_len = PAGE_SIZE;
|
||||||
|
if (this_len > count)
|
||||||
|
this_len = count;
|
||||||
|
}
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some code stolen from fs/read_write.c __kernel_read()
|
||||||
|
* and adapted to qio_rw.
|
||||||
|
* TODO: adapt this to any upstream kernel changes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
ssize_t qio_read_start(struct file *file,
|
||||||
|
void *buf, size_t count,
|
||||||
|
loff_t *pos,
|
||||||
|
void *private,
|
||||||
|
bool nowait)
|
||||||
|
{
|
||||||
|
const size_t real_count = min_t(size_t, count, MARS_MAX_RW_COUNT);
|
||||||
|
struct qio_rw *qio_rw = private;
|
||||||
|
struct kiocb *kiocb = &qio_rw->kiocb;
|
||||||
|
struct iov_iter *iter = &qio_rw->from_to;
|
||||||
|
ssize_t ret;
|
||||||
|
int nr_segs;
|
||||||
|
struct kvec iov[QIO_MAX_KVEC];
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(!(file->f_mode & FMODE_READ)))
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(file->f_mode & FMODE_CAN_READ))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nr_segs = qio_init_kvec(iov, buf, real_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also fail if ->read_iter and ->read are both wired up as that
|
||||||
|
* implies very convoluted semantics.
|
||||||
|
*/
|
||||||
|
if (unlikely(!file->f_op->read_iter || file->f_op->read))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
qio_rw->qio_phase = QIO_RW_RD_STARTED;
|
||||||
|
qio_rw->submission_ret = MARS_NOT_STARTED;
|
||||||
|
qio_rw->completion_ret = MARS_NOT_STARTED;
|
||||||
|
|
||||||
|
iov_iter_kvec(iter, READ, iov, nr_segs, real_count);
|
||||||
|
|
||||||
|
init_sync_kiocb(kiocb, file);
|
||||||
|
kiocb->ki_pos = *pos;
|
||||||
|
kiocb->ki_flags = iocb_flags(file);
|
||||||
|
|
||||||
|
/* Some important commentary from mm/filemap.c generic_file_read_iter()
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* generic_file_read_iter - generic filesystem read routine
|
||||||
|
* @iocb: kernel I/O control block
|
||||||
|
* @iter: destination for the data read
|
||||||
|
*
|
||||||
|
* This is the "read_iter()" routine for all filesystems
|
||||||
|
* that can use the page cache directly.
|
||||||
|
*
|
||||||
|
* The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall
|
||||||
|
* be returned when no data can be read without waiting for I/O requests
|
||||||
|
* to complete; it doesn't prevent readahead.
|
||||||
|
*
|
||||||
|
* The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O
|
||||||
|
* requests shall be made for the read or for readahead. When no data
|
||||||
|
* can be read, -EAGAIN shall be returned. When readahead would be
|
||||||
|
* triggered, a partial, possibly empty read shall be returned.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* * number of bytes copied, even for partial reads
|
||||||
|
* * negative error code (or 0 if IOCB_NOIO) if nothing was read
|
||||||
|
*/
|
||||||
|
if (nowait) {
|
||||||
|
kiocb->ki_flags |= IOCB_NOWAIT;
|
||||||
|
/* AFAIKS the following is not necessary (but not tested
|
||||||
|
* for all combinations of kernels with QIO):
|
||||||
|
* kiocb->ki_flags |= IOCB_NOIO;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In place of file->f_op->read_iter()
|
||||||
|
* Our qio version should not block unnecessarily.
|
||||||
|
*/
|
||||||
|
ret = qio_file_read_iter(kiocb, iter);
|
||||||
|
|
||||||
|
#ifndef KONVENTION_RET_LEN
|
||||||
|
/* only for elder kernels */
|
||||||
|
if (ret == -EAGAIN) {
|
||||||
|
int ahead_status;
|
||||||
|
|
||||||
|
ahead_status = __fake_readahead(file, *pos, real_count);
|
||||||
|
/* CHECK: can we better this? */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#ifdef KONVENTION_RET_LEN
|
||||||
|
if (ret < real_count && ret > 0) {
|
||||||
|
ret = -EAGAIN;
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret > real_count) {
|
||||||
|
ret = -EIO;
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Adaptation of calling concentions */
|
||||||
|
/* Hmm, how can we deal with any short reads?
|
||||||
|
* This type of workaround might cause problems.
|
||||||
|
*/
|
||||||
|
if (!ret)
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
|
/* Success. */
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
*pos += ret;
|
||||||
|
add_rchar(current, ret);
|
||||||
|
inc_syscr(current);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some code stolen from fs/read_write.c __kernel_write()
|
||||||
|
* and adapted to qio_rw.
|
||||||
|
* TODO: adapt this to any upstream kernel changes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
ssize_t qio_write_start(struct file *file,
|
||||||
|
void *buf, size_t count,
|
||||||
|
loff_t *pos,
|
||||||
|
void *private,
|
||||||
|
bool wait_for_sync)
|
||||||
|
{
|
||||||
|
const size_t real_count = min_t(size_t, count, MARS_MAX_RW_COUNT);
|
||||||
|
struct qio_rw *qio_rw = private;
|
||||||
|
struct kvec iov = {
|
||||||
|
.iov_base = (void *)buf,
|
||||||
|
.iov_len = real_count,
|
||||||
|
};
|
||||||
|
struct kiocb *kiocb = &qio_rw->kiocb;
|
||||||
|
struct iov_iter *iter = &qio_rw->from_to;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE)))
|
||||||
|
return -EBADF;
|
||||||
|
if (!(file->f_mode & FMODE_CAN_WRITE))
|
||||||
|
return -EINVAL;
|
||||||
|
/*
|
||||||
|
* Also fail if ->write_iter and ->write are both wired up as that
|
||||||
|
* implies very convoluted semantics.
|
||||||
|
*/
|
||||||
|
if (unlikely(!file->f_op->write_iter || file->f_op->write))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
qio_rw->qio_phase = QIO_RW_WR_STARTED;
|
||||||
|
qio_rw->submission_ret = MARS_NOT_STARTED;
|
||||||
|
qio_rw->completion_ret = MARS_NOT_STARTED;
|
||||||
|
|
||||||
|
iov_iter_kvec(iter, WRITE, &iov, 1, iov.iov_len);
|
||||||
|
|
||||||
|
init_sync_kiocb(kiocb, file);
|
||||||
|
kiocb->ki_pos = *pos;
|
||||||
|
kiocb->ki_flags = iocb_flags(file);
|
||||||
|
|
||||||
|
#if 0 // only for devel testing, to DISAPPEAR
|
||||||
|
kiocb->ki_waitq = &qio_rw->wait;
|
||||||
|
kiocb->ki_flags |= IOCB_WAITQ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_MARS_TESTING_QIO_UNSAFE_PERFORMANCE
|
||||||
|
/* Full kiocb->ki_flags |= IOCB_SYNC; not needed AFAIK */
|
||||||
|
/* But the following is ABSOLUTELY needed: */
|
||||||
|
kiocb->ki_flags |= IOCB_DSYNC;
|
||||||
|
#else
|
||||||
|
#warning DANGEROUS test code - this will ensure CORRUPTED DATA!
|
||||||
|
#endif
|
||||||
|
kiocb->ki_flags |= IOCB_APPEND;
|
||||||
|
|
||||||
|
/* In place of file->f_op->write_iter()
|
||||||
|
* Our qio version should not block unnecessarily.
|
||||||
|
*/
|
||||||
|
ret = qio_file_write_iter(kiocb, iter, wait_for_sync);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#ifdef KONVENTION_RET_LEN
|
||||||
|
if (ret < real_count && ret > 0) {
|
||||||
|
ret = -EAGAIN;
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret > real_count) {
|
||||||
|
ret = -EIO;
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Adaptation of calling concentions */
|
||||||
|
if (!ret) {
|
||||||
|
ret = real_count - iov.iov_len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* Success. */
|
||||||
|
qio_rw->submission_ret = ret;
|
||||||
|
*pos = kiocb->ki_pos;
|
||||||
|
add_wchar(current, ret);
|
||||||
|
inc_syscw(current);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
|
||||||
|
ssize_t qio_rw_wait(struct file *file,
|
||||||
|
bool is_write,
|
||||||
|
bool needs_write_sync,
|
||||||
|
void *private)
|
||||||
|
{
|
||||||
|
struct qio_rw *qio_rw = private;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
/* Corresponds to (not everywhere implemented) IOCB_NOWAIT
|
||||||
|
* thus we need to return the final result right now.
|
||||||
|
*/
|
||||||
|
ret = qio_rw->submission_ret;
|
||||||
|
if (needs_write_sync) {
|
||||||
|
ret = generic_write_sync(&qio_rw->kiocb, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_qio_rw(struct qio_rw *qio_rw)
|
||||||
|
{
|
||||||
|
/* nothing to do here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit_qio_rw(struct qio_rw *qio_rw)
|
||||||
|
{
|
||||||
|
/* nothing to do here */
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct qio_rw_operations qio_rw_operations = {
|
||||||
|
.qio_read_start = qio_read_start,
|
||||||
|
.qio_write_start = qio_write_start,
|
||||||
|
.qio_rw_wait = qio_rw_wait,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ENABLE_MARS_QIO */
|
||||||
|
|
||||||
|
int __init init_lib_qio_rw(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit_lib_qio_rw(void)
|
||||||
|
{
|
||||||
|
/* nothing to do here */
|
||||||
|
}
|
98
kernel/lib_qio_rw.h
Normal file
98
kernel/lib_qio_rw.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* MARS Long Distance Replication Software
|
||||||
|
*
|
||||||
|
* This file is part of MARS project: http://schoebel.github.io/mars/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2022 Thomas Schoebel-Theuer
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MARS_LIB_QIO_RW_H
|
||||||
|
#define MARS_LIB_QIO_RW_H
|
||||||
|
|
||||||
|
#include "brick.h"
|
||||||
|
#include "lamport.h"
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/uio.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
|
|
||||||
|
/* Minor abstraction to/from the kernel IO interface.
|
||||||
|
* (a) hopefully this interface will remain stable until MARS
|
||||||
|
* can go upstream. Only the implementation in lib_qio_rw.c
|
||||||
|
* should need to cope with kernel versions.
|
||||||
|
* (b) keep the door open for alternative kernel adaptors, maybe even
|
||||||
|
* more direct access to the page cache, or some future developments.
|
||||||
|
*
|
||||||
|
* Architectural differences to kernel_{read,write}():
|
||||||
|
* (1) The interface is as similar as possible, for long-term
|
||||||
|
* code maintenance.
|
||||||
|
* (2) Submission should work as non-blocking as possible ;)
|
||||||
|
* (3) *_wait() operations are supposed to block any (separate)
|
||||||
|
* kernel threads.
|
||||||
|
* Any information transfer between submission and (internal)
|
||||||
|
* completion path(s) goes via *private, which should always
|
||||||
|
* start with prefix "struct qio_rw_...", but may append further
|
||||||
|
* external items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum qio_rw_phase {
|
||||||
|
QIO_RW_NOTSTARTED,
|
||||||
|
QIO_RW_RD_STARTED,
|
||||||
|
QIO_RW_WR_STARTED,
|
||||||
|
QIO_RW_WAITING,
|
||||||
|
QIO_RW_COMPLETED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_rw {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
/* from general kernel infrastructure */
|
||||||
|
struct kiocb kiocb;
|
||||||
|
struct iov_iter from_to;
|
||||||
|
/* from io_uring */
|
||||||
|
/* currently unused: struct io_async_rw rw; */
|
||||||
|
/* private */
|
||||||
|
ssize_t submission_ret;
|
||||||
|
ssize_t completion_ret;
|
||||||
|
enum qio_rw_phase qio_phase;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_rw_operations {
|
||||||
|
ssize_t (*qio_read_start)(struct file *file,
|
||||||
|
void *buf, size_t count,
|
||||||
|
loff_t *pos,
|
||||||
|
void *private,
|
||||||
|
bool nowait);
|
||||||
|
ssize_t (*qio_write_start)(struct file *file,
|
||||||
|
void *buf, size_t count,
|
||||||
|
loff_t *pos,
|
||||||
|
void *private,
|
||||||
|
bool wait_for_sync);
|
||||||
|
ssize_t (*qio_rw_wait)(struct file *file,
|
||||||
|
bool is_write,
|
||||||
|
bool needs_write_sync,
|
||||||
|
void *private);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct qio_rw_operations qio_rw_operations;
|
||||||
|
|
||||||
|
extern void init_qio_rw(struct qio_rw *qio_rw);
|
||||||
|
extern void exit_qio_rw(struct qio_rw *qio_rw);
|
||||||
|
|
||||||
|
#endif
|
@ -469,22 +469,42 @@ extern int mars_throttle_end;
|
|||||||
*/
|
*/
|
||||||
extern const struct generic_brick_type *_client_brick_type;
|
extern const struct generic_brick_type *_client_brick_type;
|
||||||
extern const struct generic_brick_type *_bio_brick_type;
|
extern const struct generic_brick_type *_bio_brick_type;
|
||||||
|
extern const struct generic_brick_type *_qio_brick_type;
|
||||||
extern const struct generic_brick_type *_aio_brick_type;
|
extern const struct generic_brick_type *_aio_brick_type;
|
||||||
extern const struct generic_brick_type *_sio_brick_type;
|
extern const struct generic_brick_type *_sio_brick_type;
|
||||||
|
|
||||||
#if !defined(CONFIG_MARS_PREFER_SIO) && (defined(MARS_HAS_PREPATCH) || defined(MARS_HAS_PREPATCH_V2))
|
#if defined(IOCB_NOWAIT) && \
|
||||||
|
/* see dde0c2e79848298cc25621ad080d47f94dbd7cce */ \
|
||||||
|
defined(IOCB_DSYNC) && \
|
||||||
|
/* temporary CONFIG option, only for kernels ~5.1 to ~5.7, to disappear after 5.10 goes EOL */ \
|
||||||
|
defined(CONFIG_MARS_PREFER_QIO) && \
|
||||||
|
!defined(CONFIG_MARS_PREFER_SIO) && \
|
||||||
|
1
|
||||||
|
#define ENABLE_MARS_QIO
|
||||||
|
#else
|
||||||
|
#if !defined(CONFIG_MARS_PREFER_SIO) && \
|
||||||
|
(defined(MARS_HAS_PREPATCH) || \
|
||||||
|
defined(MARS_HAS_PREPATCH_V2) || \
|
||||||
|
defined(MARS_HAS_PREPATCH_V3a) || \
|
||||||
|
1)
|
||||||
#define ENABLE_MARS_AIO
|
#define ENABLE_MARS_AIO
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_MARS_QIO)
|
||||||
|
# define any_io_brick_type qio_brick_type
|
||||||
|
#elif defined(ENABLE_MARS_AIO)
|
||||||
|
# define any_io_brick_type aio_brick_type
|
||||||
|
#else
|
||||||
|
# define any_io_brick_type sio_brick_type
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MARS_AIO
|
#ifdef ENABLE_MARS_AIO
|
||||||
/* Kludge: our kernel threads will have no mm context, but need one
|
/* Kludge: our kernel threads will have no mm context, but need one
|
||||||
* for stuff like ioctx_alloc() / aio_setup_ring() etc
|
* for stuff like ioctx_alloc() / aio_setup_ring() etc
|
||||||
* which expect userspace resources.
|
* which expect userspace resources.
|
||||||
* We fake one.
|
* We fake one.
|
||||||
* TODO: factor out the userspace stuff from AIO such that
|
* TODO: REMOVE THIS in favor of QIO
|
||||||
* this fake is no longer necessary.
|
|
||||||
* Even better: replace do_mmap() in AIO stuff by something
|
|
||||||
* more friendly to kernelspace apps.
|
|
||||||
*/
|
*/
|
||||||
#include <linux/mmu_context.h>
|
#include <linux/mmu_context.h>
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* HISTORIC - please avoid this ASAP
|
||||||
|
*/
|
||||||
|
|
||||||
//#define BRICK_DEBUGGING
|
//#define BRICK_DEBUGGING
|
||||||
#define MARS_DEBUGGING
|
#define MARS_DEBUGGING
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* HISTORIC - please avoid this ASAP
|
||||||
|
*/
|
||||||
#ifndef MARS_AIO_H
|
#ifndef MARS_AIO_H
|
||||||
#define MARS_AIO_H
|
#define MARS_AIO_H
|
||||||
|
|
||||||
|
1330
kernel/mars_qio.c
Normal file
1330
kernel/mars_qio.c
Normal file
File diff suppressed because it is too large
Load Diff
111
kernel/mars_qio.h
Normal file
111
kernel/mars_qio.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* MARS Long Distance Replication Software
|
||||||
|
*
|
||||||
|
* This file is part of MARS project: http://schoebel.github.io/mars/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2014 Thomas Schoebel-Theuer
|
||||||
|
* Copyright (C) 2011-2014 1&1 Internet AG
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MARS_QIO_H
|
||||||
|
#define MARS_QIO_H
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
#include "lib_qio_rw.h"
|
||||||
|
#include "lib_mapfree.h"
|
||||||
|
|
||||||
|
#define QIO_IO_R_MAX_LATENCY 50000 // 50 ms
|
||||||
|
#define QIO_IO_W_MAX_LATENCY 150000 // 150 ms
|
||||||
|
|
||||||
|
extern int mars_qio_hang_timeout_s;
|
||||||
|
|
||||||
|
struct qio_anchors {
|
||||||
|
struct mutex prio_mutex;
|
||||||
|
struct list_head submitted_list;
|
||||||
|
wait_queue_head_t event;
|
||||||
|
struct task_struct *thread;
|
||||||
|
struct qio_brick *brick;
|
||||||
|
int anch_prio;
|
||||||
|
bool should_wake_now;
|
||||||
|
bool should_terminate;
|
||||||
|
bool has_terminated;
|
||||||
|
bool all_have_expired;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_mref_aspect {
|
||||||
|
GENERIC_ASPECT(mref);
|
||||||
|
struct list_head io_head;
|
||||||
|
struct lamport_time started_stamp;
|
||||||
|
struct lamport_time enqueue_stamp;
|
||||||
|
struct lamport_time dequeue_stamp;
|
||||||
|
struct lamport_time completion_stamp;
|
||||||
|
struct qio_anchors *anch;
|
||||||
|
struct qio_rw qio_rw;
|
||||||
|
int alloc_len;
|
||||||
|
int qio_error;
|
||||||
|
int nr_requeue;
|
||||||
|
bool do_dealloc;
|
||||||
|
bool is_write;
|
||||||
|
bool is_active;
|
||||||
|
bool use_nowait;
|
||||||
|
bool has_expired;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_brick {
|
||||||
|
MARS_BRICK(qio);
|
||||||
|
/* in parameters */
|
||||||
|
bool o_creat;
|
||||||
|
/* out parameters */
|
||||||
|
int error;
|
||||||
|
/* private */
|
||||||
|
struct file *file;
|
||||||
|
struct mapfree_info *mf;
|
||||||
|
struct qio_anchors thread_anch[2];
|
||||||
|
/* statistics */
|
||||||
|
struct lamport_time last_started_stamp;
|
||||||
|
struct lamport_time last_submitted_stamp;
|
||||||
|
#ifdef CONFIG_MARS_DEBUG
|
||||||
|
struct lamport_time last_dequeue_stamp;
|
||||||
|
#endif
|
||||||
|
struct lamport_time last_completion_stamp;
|
||||||
|
struct lamport_time last_hanging_stamp;
|
||||||
|
atomic_t flying_reads;
|
||||||
|
atomic_t flying_writes;
|
||||||
|
#ifdef CONFIG_MARS_DEBUG
|
||||||
|
loff_t submit_pos;
|
||||||
|
loff_t complet_pos;
|
||||||
|
int submit_len;
|
||||||
|
int complet_len;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_input {
|
||||||
|
MARS_INPUT(qio);
|
||||||
|
/* parameters */
|
||||||
|
/* private */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qio_output {
|
||||||
|
MARS_OUTPUT(qio);
|
||||||
|
/* parameters */
|
||||||
|
/* private */
|
||||||
|
};
|
||||||
|
|
||||||
|
MARS_TYPES(qio);
|
||||||
|
|
||||||
|
#endif
|
@ -37,6 +37,7 @@
|
|||||||
#define _STRATEGY
|
#define _STRATEGY
|
||||||
#include "mars.h"
|
#include "mars.h"
|
||||||
#include "mars_bio.h"
|
#include "mars_bio.h"
|
||||||
|
#include "mars_qio.h"
|
||||||
#include "mars_aio.h"
|
#include "mars_aio.h"
|
||||||
#include "mars_sio.h"
|
#include "mars_sio.h"
|
||||||
|
|
||||||
@ -367,11 +368,13 @@ void _clean_list(struct server_brick *brick, struct list_head *start, bool was_w
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MARS_PREFER_SIO /* Historic, to disappear, ONLY FOR TESTING */
|
||||||
static
|
static
|
||||||
int _set_server_sio_params(struct mars_brick *_brick, void *private)
|
int _set_server_sio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct sio_brick *sio_brick = (void*)_brick;
|
struct sio_brick *sio_brick = (void *)_brick;
|
||||||
if (_brick->type != (void*)_sio_brick_type) {
|
|
||||||
|
if (_brick->type != (void *)_sio_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -380,15 +383,27 @@ int _set_server_sio_params(struct mars_brick *_brick, void *private)
|
|||||||
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
static
|
||||||
|
int _set_server_qio_params(struct mars_brick *_brick, void *private)
|
||||||
|
{
|
||||||
|
struct qio_brick *qio_brick = (void *)_brick;
|
||||||
|
|
||||||
|
qio_brick->o_creat = false;
|
||||||
|
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
static
|
static
|
||||||
int _set_server_aio_params(struct mars_brick *_brick, void *private)
|
int _set_server_aio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct aio_brick *aio_brick = (void*)_brick;
|
struct aio_brick *aio_brick = (void *)_brick;
|
||||||
if (_brick->type == (void*)_sio_brick_type) {
|
|
||||||
return _set_server_sio_params(_brick, private);
|
if (_brick->type != (void *)_aio_brick_type) {
|
||||||
}
|
|
||||||
if (_brick->type != (void*)_aio_brick_type) {
|
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -398,22 +413,33 @@ int _set_server_aio_params(struct mars_brick *_brick, void *private)
|
|||||||
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
int _set_server_bio_params(struct mars_brick *_brick, void *private)
|
int _set_server_bio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct bio_brick *bio_brick;
|
struct bio_brick *bio_brick;
|
||||||
if (_brick->type == (void*)_aio_brick_type) {
|
|
||||||
return _set_server_aio_params(_brick, private);
|
#ifdef CONFIG_MARS_PREFER_SIO /* Historic, to disappear, ONLY FOR TESTING */
|
||||||
}
|
|
||||||
if (_brick->type == (void*)_sio_brick_type) {
|
if (_brick->type == (void*)_sio_brick_type) {
|
||||||
return _set_server_sio_params(_brick, private);
|
return _set_server_sio_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type != (void*)_bio_brick_type) {
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
if (_brick->type == (void *)_qio_brick_type) {
|
||||||
|
return _set_server_qio_params(_brick, private);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
|
if (_brick->type == (void *)_aio_brick_type) {
|
||||||
|
return _set_server_aio_params(_brick, private);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_brick->type != (void *)_bio_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
bio_brick = (void*)_brick;
|
bio_brick = (void *)_brick;
|
||||||
bio_brick->ra_pages = 0;
|
bio_brick->ra_pages = 0;
|
||||||
bio_brick->do_sync = true;
|
bio_brick->do_sync = true;
|
||||||
bio_brick->do_unplug = true;
|
bio_brick->do_unplug = true;
|
||||||
@ -619,6 +645,9 @@ int handler_thread(void *data)
|
|||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
CHECK_PTR(path, err);
|
CHECK_PTR(path, err);
|
||||||
CHECK_PTR_NULL(_bio_brick_type, err);
|
CHECK_PTR_NULL(_bio_brick_type, err);
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
CHECK_PTR_NULL(_qio_brick_type, err);
|
||||||
|
#endif
|
||||||
|
|
||||||
prev = make_brick_all(
|
prev = make_brick_all(
|
||||||
handler_global,
|
handler_global,
|
||||||
@ -626,8 +655,8 @@ int handler_thread(void *data)
|
|||||||
_set_server_bio_params,
|
_set_server_bio_params,
|
||||||
NULL,
|
NULL,
|
||||||
path,
|
path,
|
||||||
(const struct generic_brick_type*)_bio_brick_type,
|
(const struct generic_brick_type *)_bio_brick_type,
|
||||||
(const struct generic_brick_type*[]){},
|
(const struct generic_brick_type *[]){},
|
||||||
2, // start always
|
2, // start always
|
||||||
path,
|
path,
|
||||||
(const char *[]){},
|
(const char *[]){},
|
||||||
|
@ -486,7 +486,7 @@ void sio_ref_io(struct sio_output *output, struct mref_object *mref)
|
|||||||
list_add_tail(&mref_a->io_head, &tinfo->mref_list);
|
list_add_tail(&mref_a->io_head, &tinfo->mref_list);
|
||||||
traced_unlock(&tinfo->lock, flags);
|
traced_unlock(&tinfo->lock, flags);
|
||||||
|
|
||||||
wake_up_interruptible(&tinfo->event);
|
brick_wake_smp(&tinfo->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sio_thread(void *data)
|
static int sio_thread(void *data)
|
||||||
@ -502,7 +502,7 @@ static int sio_thread(void *data)
|
|||||||
struct sio_mref_aspect *mref_a;
|
struct sio_mref_aspect *mref_a;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
wait_event_interruptible_timeout(
|
brick_wait_smp(
|
||||||
tinfo->event,
|
tinfo->event,
|
||||||
!list_empty(&tinfo->mref_list) || brick_thread_should_stop(),
|
!list_empty(&tinfo->mref_list) || brick_thread_should_stop(),
|
||||||
HZ);
|
HZ);
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#include "../mars_copy.h"
|
#include "../mars_copy.h"
|
||||||
#include "../mars_bio.h"
|
#include "../mars_bio.h"
|
||||||
#include "../mars_sio.h"
|
#include "../mars_sio.h"
|
||||||
|
#include "../mars_qio.h"
|
||||||
#include "../mars_aio.h"
|
#include "../mars_aio.h"
|
||||||
#include "../mars_trans_logger.h"
|
#include "../mars_trans_logger.h"
|
||||||
#include "../mars_if.h"
|
#include "../mars_if.h"
|
||||||
@ -1020,8 +1021,9 @@ int mars_mem_gb = 16;
|
|||||||
static
|
static
|
||||||
int _set_trans_params(struct mars_brick *_brick, void *private)
|
int _set_trans_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct trans_logger_brick *trans_brick = (void*)_brick;
|
struct trans_logger_brick *trans_brick = (void *)_brick;
|
||||||
if (_brick->type != (void*)&trans_logger_brick_type) {
|
|
||||||
|
if (_brick->type != (void *)&trans_logger_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1059,8 +1061,9 @@ struct client_cookie {
|
|||||||
static
|
static
|
||||||
int _set_client_params(struct mars_brick *_brick, void *private)
|
int _set_client_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct client_brick *client_brick = (void*)_brick;
|
struct client_brick *client_brick = (void *)_brick;
|
||||||
struct client_cookie *clc = private;
|
struct client_cookie *clc = private;
|
||||||
|
|
||||||
client_brick->limit_mode = clc ? clc->limit_mode : false;
|
client_brick->limit_mode = clc ? clc->limit_mode : false;
|
||||||
client_brick->killme = true;
|
client_brick->killme = true;
|
||||||
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
||||||
@ -1070,11 +1073,12 @@ int _set_client_params(struct mars_brick *_brick, void *private)
|
|||||||
static
|
static
|
||||||
int _set_sio_params(struct mars_brick *_brick, void *private)
|
int _set_sio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct sio_brick *sio_brick = (void*)_brick;
|
struct sio_brick *sio_brick = (void *)_brick;
|
||||||
if (_brick->type == (void*)&client_brick_type) {
|
|
||||||
|
if (_brick->type == (void *)&client_brick_type) {
|
||||||
return _set_client_params(_brick, private);
|
return _set_client_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type != (void*)&sio_brick_type) {
|
if (_brick->type != (void *)&sio_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1085,18 +1089,25 @@ int _set_sio_params(struct mars_brick *_brick, void *private)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
static
|
static
|
||||||
int _set_aio_params(struct mars_brick *_brick, void *private)
|
int _set_aio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct aio_brick *aio_brick = (void*)_brick;
|
struct aio_brick *aio_brick = (void *)_brick;
|
||||||
struct client_cookie *clc = private;
|
struct client_cookie *clc = private;
|
||||||
if (_brick->type == (void*)&client_brick_type) {
|
|
||||||
|
if (_brick->type == (void *)&client_brick_type) {
|
||||||
return _set_client_params(_brick, private);
|
return _set_client_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type == (void*)&sio_brick_type) {
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
if (_brick->type == (void *)&qio_brick_type) {
|
||||||
|
return _set_qio_params(_brick, private);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_brick->type == (void *)&sio_brick_type) {
|
||||||
return _set_sio_params(_brick, private);
|
return _set_sio_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type != (void*)&aio_brick_type) {
|
if (_brick->type != (void *)&aio_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1107,25 +1118,68 @@ int _set_aio_params(struct mars_brick *_brick, void *private)
|
|||||||
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#define _set_aio_params _set_sio_params
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
static
|
||||||
|
int _set_qio_params(struct mars_brick *_brick, void *private)
|
||||||
|
{
|
||||||
|
struct qio_brick *qio_brick = (void *)_brick;
|
||||||
|
struct client_cookie *clc = private;
|
||||||
|
|
||||||
|
if (_brick->type == (void *)&client_brick_type) {
|
||||||
|
return _set_client_params(_brick, private);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
|
if (_brick->type == (void *)&aio_brick_type) {
|
||||||
|
return _set_aio_params(_brick, private);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_brick->type == (void *)&sio_brick_type) {
|
||||||
|
return _set_sio_params(_brick, private);
|
||||||
|
}
|
||||||
|
if (_brick->type != (void *)&qio_brick_type) {
|
||||||
|
MARS_ERR("bad qio brick type\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
qio_brick->o_creat = clc && clc->create_mode;
|
||||||
|
qio_brick->killme = true;
|
||||||
|
MARS_INF("name = '%s' path = '%s'\n",
|
||||||
|
_brick->brick_name, _brick->brick_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define _set_qio_params _set_aio_params
|
||||||
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
int _set_bio_params(struct mars_brick *_brick, void *private)
|
int _set_bio_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct bio_brick *bio_brick;
|
struct bio_brick *bio_brick;
|
||||||
if (_brick->type == (void*)&client_brick_type) {
|
|
||||||
|
if (_brick->type == (void *)&client_brick_type) {
|
||||||
return _set_client_params(_brick, private);
|
return _set_client_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type == (void*)&aio_brick_type) {
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
if (_brick->type == (void *)&qio_brick_type) {
|
||||||
|
return _set_qio_params(_brick, private);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
|
if (_brick->type == (void *)&aio_brick_type) {
|
||||||
return _set_aio_params(_brick, private);
|
return _set_aio_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type == (void*)&sio_brick_type) {
|
#endif
|
||||||
|
if (_brick->type == (void *)&sio_brick_type) {
|
||||||
return _set_sio_params(_brick, private);
|
return _set_sio_params(_brick, private);
|
||||||
}
|
}
|
||||||
if (_brick->type != (void*)&bio_brick_type) {
|
if (_brick->type != (void *)&bio_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
bio_brick = (void*)_brick;
|
bio_brick = (void *)_brick;
|
||||||
bio_brick->ra_pages = BIO_READAHEAD;
|
bio_brick->ra_pages = BIO_READAHEAD;
|
||||||
bio_brick->do_sync = BIO_SYNC;
|
bio_brick->do_sync = BIO_SYNC;
|
||||||
bio_brick->do_unplug = BIO_UNPLUG;
|
bio_brick->do_unplug = BIO_UNPLUG;
|
||||||
@ -1137,9 +1191,10 @@ int _set_bio_params(struct mars_brick *_brick, void *private)
|
|||||||
static
|
static
|
||||||
int _set_if_params(struct mars_brick *_brick, void *private)
|
int _set_if_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct if_brick *if_brick = (void*)_brick;
|
struct if_brick *if_brick = (void *)_brick;
|
||||||
struct mars_rotate *rot = private;
|
struct mars_rotate *rot = private;
|
||||||
if (_brick->type != (void*)&if_brick_type) {
|
|
||||||
|
if (_brick->type != (void *)&if_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1179,11 +1234,11 @@ struct copy_cookie {
|
|||||||
static
|
static
|
||||||
int _set_copy_params(struct mars_brick *_brick, void *private)
|
int _set_copy_params(struct mars_brick *_brick, void *private)
|
||||||
{
|
{
|
||||||
struct copy_brick *copy_brick = (void*)_brick;
|
struct copy_brick *copy_brick = (void *)_brick;
|
||||||
struct copy_cookie *cc = private;
|
struct copy_cookie *cc = private;
|
||||||
int status = 1;
|
int status = 1;
|
||||||
|
|
||||||
if (_brick->type != (void*)©_brick_type) {
|
if (_brick->type != (void *)©_brick_type) {
|
||||||
MARS_ERR("bad brick type\n");
|
MARS_ERR("bad brick type\n");
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
@ -2104,8 +2159,8 @@ int __make_copy(struct mars_dent *belongs,
|
|||||||
_set_bio_params,
|
_set_bio_params,
|
||||||
&clc[i],
|
&clc[i],
|
||||||
NULL,
|
NULL,
|
||||||
(const struct generic_brick_type*)&bio_brick_type,
|
(const struct generic_brick_type *)&bio_brick_type,
|
||||||
(const struct generic_brick_type*[]){},
|
(const struct generic_brick_type *[]){},
|
||||||
switch_copy || (copy && !copy->power.led_off) ? 2 : -1,
|
switch_copy || (copy && !copy->power.led_off) ? 2 : -1,
|
||||||
cc.fullpath[i],
|
cc.fullpath[i],
|
||||||
(const char *[]){},
|
(const char *[]){},
|
||||||
@ -4637,11 +4692,11 @@ int make_log_init(struct mars_dent *dent)
|
|||||||
aio_brick =
|
aio_brick =
|
||||||
make_brick_all(mars_global,
|
make_brick_all(mars_global,
|
||||||
aio_dent,
|
aio_dent,
|
||||||
_set_aio_params,
|
_set_qio_params,
|
||||||
NULL,
|
NULL,
|
||||||
aio_path,
|
aio_path,
|
||||||
(const struct generic_brick_type*)&aio_brick_type,
|
(const struct generic_brick_type *)&any_io_brick_type,
|
||||||
(const struct generic_brick_type*[]){},
|
(const struct generic_brick_type *[]){},
|
||||||
switch_on ||
|
switch_on ||
|
||||||
(rot->trans_brick &&
|
(rot->trans_brick &&
|
||||||
!rot->trans_brick->power.led_off) ? 2 : -1,
|
!rot->trans_brick->power.led_off) ? 2 : -1,
|
||||||
@ -4664,7 +4719,8 @@ int make_log_init(struct mars_dent *dent)
|
|||||||
output = aio_brick->outputs[0];
|
output = aio_brick->outputs[0];
|
||||||
status = output->ops->mars_get_info(output, &rot->aio_info);
|
status = output->ops->mars_get_info(output, &rot->aio_info);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
MARS_ERR("cannot get info on '%s'\n", aio_path);
|
MARS_ERR("cannot get info on '%s', status=%d\n",
|
||||||
|
aio_path, status);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
MARS_DBG("logfile '%s' size = %lld\n", aio_path, rot->aio_info.current_size);
|
MARS_DBG("logfile '%s' size = %lld\n", aio_path, rot->aio_info.current_size);
|
||||||
@ -5406,11 +5462,11 @@ void _rotate_trans(struct mars_rotate *rot)
|
|||||||
rot->next_relevant_brick =
|
rot->next_relevant_brick =
|
||||||
make_brick_all(mars_global,
|
make_brick_all(mars_global,
|
||||||
rot->next_relevant_log,
|
rot->next_relevant_log,
|
||||||
_set_aio_params,
|
_set_qio_params,
|
||||||
NULL,
|
NULL,
|
||||||
rot->next_relevant_log->d_path,
|
rot->next_relevant_log->d_path,
|
||||||
(const struct generic_brick_type*)&aio_brick_type,
|
(const struct generic_brick_type *)&any_io_brick_type,
|
||||||
(const struct generic_brick_type*[]){},
|
(const struct generic_brick_type *[]){},
|
||||||
2, // create + activate
|
2, // create + activate
|
||||||
rot->next_relevant_log->d_path,
|
rot->next_relevant_log->d_path,
|
||||||
(const char *[]){},
|
(const char *[]){},
|
||||||
@ -5554,11 +5610,11 @@ int _start_trans(struct mars_rotate *rot)
|
|||||||
rot->relevant_brick =
|
rot->relevant_brick =
|
||||||
make_brick_all(mars_global,
|
make_brick_all(mars_global,
|
||||||
rot->relevant_log,
|
rot->relevant_log,
|
||||||
_set_aio_params,
|
_set_qio_params,
|
||||||
NULL,
|
NULL,
|
||||||
rot->relevant_log->d_path,
|
rot->relevant_log->d_path,
|
||||||
(const struct generic_brick_type*)&aio_brick_type,
|
(const struct generic_brick_type *)&any_io_brick_type,
|
||||||
(const struct generic_brick_type*[]){},
|
(const struct generic_brick_type *[]){},
|
||||||
2, // start always
|
2, // start always
|
||||||
rot->relevant_log->d_path,
|
rot->relevant_log->d_path,
|
||||||
(const char *[]){},
|
(const char *[]){},
|
||||||
@ -6180,10 +6236,18 @@ int make_bio(struct mars_dent *dent)
|
|||||||
__show_actual(rot->parent_path,
|
__show_actual(rot->parent_path,
|
||||||
"disk-error",
|
"disk-error",
|
||||||
((struct bio_brick *)brick)->error);
|
((struct bio_brick *)brick)->error);
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
else if (brick->type == (void *)&qio_brick_type)
|
||||||
|
__show_actual(rot->parent_path,
|
||||||
|
"disk-error",
|
||||||
|
((struct qio_brick *)brick)->error);
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
else if (brick->type == (void *)&aio_brick_type && brick->outputs[0])
|
else if (brick->type == (void *)&aio_brick_type && brick->outputs[0])
|
||||||
__show_actual(rot->parent_path,
|
__show_actual(rot->parent_path,
|
||||||
"disk-error",
|
"disk-error",
|
||||||
((struct aio_brick *)brick)->outputs[0]->error);
|
((struct aio_brick *)brick)->outputs[0]->error);
|
||||||
|
#endif
|
||||||
else if (brick->type == (void *)&sio_brick_type && brick->outputs[0])
|
else if (brick->type == (void *)&sio_brick_type && brick->outputs[0])
|
||||||
__show_actual(rot->parent_path,
|
__show_actual(rot->parent_path,
|
||||||
"disk-error",
|
"disk-error",
|
||||||
@ -7777,7 +7841,12 @@ static int _main_thread(void *data)
|
|||||||
static const struct mars_brick_type *type_list[] = {
|
static const struct mars_brick_type *type_list[] = {
|
||||||
(void *)©_brick_type,
|
(void *)©_brick_type,
|
||||||
(void *)&client_brick_type,
|
(void *)&client_brick_type,
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
(void *)&qio_brick_type,
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
(void *)&aio_brick_type,
|
(void *)&aio_brick_type,
|
||||||
|
#endif
|
||||||
(void *)&sio_brick_type,
|
(void *)&sio_brick_type,
|
||||||
(void *)&bio_brick_type,
|
(void *)&bio_brick_type,
|
||||||
NULL
|
NULL
|
||||||
@ -8219,7 +8288,10 @@ static int __init init_main(void)
|
|||||||
#endif
|
#endif
|
||||||
DO_INIT(mars_net);
|
DO_INIT(mars_net);
|
||||||
DO_INIT(mars_client);
|
DO_INIT(mars_client);
|
||||||
|
DO_INIT(mars_qio);
|
||||||
|
#ifdef ENABLE_MARS_AIO
|
||||||
DO_INIT(mars_aio);
|
DO_INIT(mars_aio);
|
||||||
|
#endif
|
||||||
DO_INIT(mars_sio);
|
DO_INIT(mars_sio);
|
||||||
DO_INIT(mars_bio);
|
DO_INIT(mars_bio);
|
||||||
DO_INIT(mars_server);
|
DO_INIT(mars_server);
|
||||||
@ -8283,7 +8355,9 @@ MODULE_INFO(prepatch, "has_prepatch_v1");
|
|||||||
#else
|
#else
|
||||||
MODULE_INFO(prepatch, "no_prepatch");
|
MODULE_INFO(prepatch, "no_prepatch");
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_MARS_AIO
|
#if defined(ENABLE_MARS_QIO)
|
||||||
|
MODULE_INFO(io_driver, "qio");
|
||||||
|
#elif defined(ENABLE_MARS_AIO)
|
||||||
MODULE_INFO(io_driver, "aio");
|
MODULE_INFO(io_driver, "aio");
|
||||||
#else
|
#else
|
||||||
MODULE_INFO(io_driver, "sio");
|
MODULE_INFO(io_driver, "sio");
|
||||||
@ -8297,7 +8371,9 @@ MODULE_INFO(io_driver, "sio");
|
|||||||
* sysadmin informations. Sysadmins should not react
|
* sysadmin informations. Sysadmins should not react
|
||||||
* surprised, as far as possible.
|
* surprised, as far as possible.
|
||||||
*/
|
*/
|
||||||
#if defined(CONFIG_KASAN)
|
#if defined(CONFIG_MARS_TESTING_QIO_UNSAFE_PERFORMANCE)
|
||||||
|
#define KERN_DEBUG_INFO "DAMGEROUS_not_for_production_leads_to_CORRUPTED_DATA"
|
||||||
|
#elif defined(CONFIG_KASAN)
|
||||||
#define KERN_DEBUG_INFO "CONFIG_KASAN"
|
#define KERN_DEBUG_INFO "CONFIG_KASAN"
|
||||||
#elif defined(CONFIG_DEBUG_PAGEALLOC)
|
#elif defined(CONFIG_DEBUG_PAGEALLOC)
|
||||||
#define KERN_DEBUG_INFO "CONFIG_DEBUG_PAGEALLOC"
|
#define KERN_DEBUG_INFO "CONFIG_DEBUG_PAGEALLOC"
|
||||||
|
@ -50,8 +50,6 @@
|
|||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/statfs.h>
|
#include <linux/statfs.h>
|
||||||
|
|
||||||
#define SKIP_BIO false
|
|
||||||
|
|
||||||
#include "../brick_wait.h"
|
#include "../brick_wait.h"
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
@ -3292,6 +3290,8 @@ const struct generic_brick_type *_client_brick_type = NULL;
|
|||||||
EXPORT_SYMBOL_GPL(_client_brick_type);
|
EXPORT_SYMBOL_GPL(_client_brick_type);
|
||||||
const struct generic_brick_type *_bio_brick_type = NULL;
|
const struct generic_brick_type *_bio_brick_type = NULL;
|
||||||
EXPORT_SYMBOL_GPL(_bio_brick_type);
|
EXPORT_SYMBOL_GPL(_bio_brick_type);
|
||||||
|
const struct generic_brick_type *_qio_brick_type = NULL;
|
||||||
|
EXPORT_SYMBOL_GPL(_qio_brick_type);
|
||||||
const struct generic_brick_type *_aio_brick_type = NULL;
|
const struct generic_brick_type *_aio_brick_type = NULL;
|
||||||
EXPORT_SYMBOL_GPL(_aio_brick_type);
|
EXPORT_SYMBOL_GPL(_aio_brick_type);
|
||||||
const struct generic_brick_type *_sio_brick_type = NULL;
|
const struct generic_brick_type *_sio_brick_type = NULL;
|
||||||
@ -3413,7 +3413,10 @@ struct mars_brick *make_brick_all(
|
|||||||
|
|
||||||
// some generic brick replacements (better performance / network functionality)
|
// some generic brick replacements (better performance / network functionality)
|
||||||
brick = NULL;
|
brick = NULL;
|
||||||
if ((new_brick_type == _bio_brick_type || new_brick_type == _aio_brick_type)
|
if ((new_brick_type == _bio_brick_type ||
|
||||||
|
new_brick_type == _qio_brick_type ||
|
||||||
|
new_brick_type == _aio_brick_type ||
|
||||||
|
false)
|
||||||
&& _client_brick_type != NULL) {
|
&& _client_brick_type != NULL) {
|
||||||
char *remote = strchr(new_name, '@');
|
char *remote = strchr(new_name, '@');
|
||||||
if (remote) {
|
if (remote) {
|
||||||
@ -3427,20 +3430,61 @@ struct mars_brick *make_brick_all(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!brick && new_brick_type == _bio_brick_type && _aio_brick_type) {
|
/* Important: never use bio on a non-blockdev.
|
||||||
|
* Omly logfiles are subject of [qas]io.
|
||||||
|
* Qio is the new default, when present.
|
||||||
|
*/
|
||||||
|
if (!brick) {
|
||||||
struct kstat test = {};
|
struct kstat test = {};
|
||||||
int status = mars_stat(new_path, &test, false);
|
int test_status = mars_stat(new_path, &test, false);
|
||||||
if (SKIP_BIO || status < 0 || !S_ISBLK(test.mode)) {
|
bool subst_file =
|
||||||
new_brick_type = _aio_brick_type;
|
(test_status < 0 || !S_ISBLK(test.mode));
|
||||||
MARS_DBG("substitute bio by aio\n");
|
|
||||||
|
if (test_status >= 0) {
|
||||||
|
if (S_ISREG(test.mode))
|
||||||
|
subst_file = true;
|
||||||
|
if (S_ISLNK(test.mode))
|
||||||
|
subst_file = false;
|
||||||
|
} else if (!strstr(new_path, "/log-")) {
|
||||||
|
/* We cannot stat, thus we need to assume that
|
||||||
|
* only log-* is a regular file where qio
|
||||||
|
* (or the historic aio / sio) can work on.
|
||||||
|
*/
|
||||||
|
subst_file = false;
|
||||||
|
}
|
||||||
|
#if defined(ENABLE_MARS_AIO)
|
||||||
|
/* Old variant, to disappear.
|
||||||
|
*/
|
||||||
|
if (subst_file &&
|
||||||
|
_aio_brick_type &&
|
||||||
|
new_brick_type != _aio_brick_type) {
|
||||||
|
MARS_DBG("substitute %s by aio\n",
|
||||||
|
new_brick_type->type_name);
|
||||||
|
new_brick_type = _aio_brick_type;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#ifndef ENABLE_MARS_AIO
|
|
||||||
if (!brick && new_brick_type == _aio_brick_type && _sio_brick_type) {
|
|
||||||
new_brick_type = _sio_brick_type;
|
|
||||||
MARS_DBG("substitute aio by sio\n");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_MARS_QIO
|
||||||
|
if (subst_file &&
|
||||||
|
_qio_brick_type &&
|
||||||
|
new_brick_type != _qio_brick_type) {
|
||||||
|
MARS_DBG("substitute %s by qio\n",
|
||||||
|
new_brick_type->type_name);
|
||||||
|
new_brick_type = _qio_brick_type;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MARS_PREFER_SIO /* Historic, to disappear, ONLY FOR TESTING */
|
||||||
|
if (subst_file &&
|
||||||
|
_sio_brick_type &&
|
||||||
|
new_brick_type != _sio_brick_type) {
|
||||||
|
MARS_DBG("substitute any (%s) by sio for TESTING\n",
|
||||||
|
new_brick_type->type_name);
|
||||||
|
new_brick_type = _sio_brick_type;
|
||||||
|
}
|
||||||
|
if (subst_file && new_brick_type != _sio_brick_type) {
|
||||||
|
MARS_ERR("CONFIG_MARS_PREFER_SIO: cannot substitute anything by sio\n");
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MARS_PREFER_SIO, ONLY FOR TESTING */
|
||||||
|
}
|
||||||
|
|
||||||
// create it...
|
// create it...
|
||||||
if (!brick)
|
if (!brick)
|
||||||
|
Loading…
Reference in New Issue
Block a user