1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libext2fs_blockserver/lib/src/blockserver_io.c Tue May 04 00:19:19 2021 +0200
1.3 @@ -0,0 +1,284 @@
1.4 +/*
1.5 + * blockserver_io.c --- L4Re block server I/O manager.
1.6 + *
1.7 + * Copyright (C) 2019, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This library is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU Library General Public
1.11 + * License as published by the Free Software Foundation; either
1.12 + * version 2 of the License, or (at your option) any later version.
1.13 + *
1.14 + * This library is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.17 + * Library General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU Library General Public
1.20 + * License along with this library; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1.22 + * 02110-1301 USA
1.23 + */
1.24 +
1.25 +#include <stdio.h>
1.26 +#include <stdlib.h>
1.27 +
1.28 +#include <ext2fs/ext2fs.h>
1.29 +#include <fsclient/client.h>
1.30 +
1.31 +
1.32 +
1.33 +/* Specific data for interacting with block devices. */
1.34 +
1.35 +struct blockserver_private_data
1.36 +{
1.37 + int magic;
1.38 + int flags;
1.39 + file_t *file;
1.40 +};
1.41 +
1.42 +io_manager blockserver_io_manager; /* defined below */
1.43 +
1.44 +const char *blockserver_default_cap = "server";
1.45 +
1.46 +
1.47 +
1.48 +/* Allocate and initialise a channel for the indicated block device. */
1.49 +
1.50 +static errcode_t blockserver_open_channel(const char *name,
1.51 + file_t *file, int flags,
1.52 + io_channel *channel,
1.53 + io_manager io_mgr)
1.54 +{
1.55 + io_channel io = NULL;
1.56 + struct blockserver_private_data *data = NULL;
1.57 + errcode_t retval;
1.58 +
1.59 + /* Allocate memory for the channel. */
1.60 +
1.61 + retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
1.62 + if (retval)
1.63 + goto free_io;
1.64 +
1.65 + /* Initialise the channel. */
1.66 +
1.67 + memset(io, 0, sizeof(struct struct_io_channel));
1.68 +
1.69 + io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
1.70 + io->manager = io_mgr;
1.71 + io->block_size = 1024;
1.72 + io->read_error = 0;
1.73 + io->write_error = 0;
1.74 + io->refcount = 1;
1.75 +
1.76 + /* Allocate memory for the name and store it. */
1.77 +
1.78 + retval = ext2fs_get_mem(strlen(name)+1, &io->name);
1.79 + if (retval)
1.80 + goto free_io;
1.81 +
1.82 + strcpy(io->name, name);
1.83 +
1.84 + /* Allocate memory for the private data. */
1.85 +
1.86 + retval = ext2fs_get_mem(sizeof(struct blockserver_private_data), &data);
1.87 + if (retval)
1.88 + goto free_data;
1.89 +
1.90 + /* Initialise the private data. */
1.91 +
1.92 + io->private_data = data;
1.93 +
1.94 + memset(data, 0, sizeof(struct blockserver_private_data));
1.95 +
1.96 + data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
1.97 + data->flags = flags;
1.98 + data->file = file;
1.99 +
1.100 + /* Return the allocated channel. */
1.101 +
1.102 + *channel = io;
1.103 + return 0;
1.104 +
1.105 + /* Deallocation upon failure. */
1.106 +
1.107 +free_data:
1.108 + if (data)
1.109 + ext2fs_free_mem(&data);
1.110 +
1.111 +free_io:
1.112 + if (io)
1.113 + {
1.114 + if (io->name)
1.115 + ext2fs_free_mem(&io->name);
1.116 + ext2fs_free_mem(&io);
1.117 + }
1.118 +
1.119 + return retval;
1.120 +}
1.121 +
1.122 +
1.123 +
1.124 +/* Open a block device using the named capability. */
1.125 +
1.126 +static errcode_t blockserver_open(const char *name, int flags, io_channel *channel)
1.127 +{
1.128 + /* Open a device via the named capability. */
1.129 +
1.130 + file_t *file = client_open_device(blockserver_default_cap, name, flags);
1.131 +
1.132 + /* NOTE: May want a more appropriate error code. */
1.133 +
1.134 + if (file == NULL)
1.135 + return EXT2_ET_BAD_DEVICE_NAME;
1.136 +
1.137 + return blockserver_open_channel(name, file, flags, channel, blockserver_io_manager);
1.138 +}
1.139 +
1.140 +
1.141 +
1.142 +/* Close the block device associated with the given channel. */
1.143 +
1.144 +static errcode_t blockserver_close(io_channel channel)
1.145 +{
1.146 + struct blockserver_private_data *data;
1.147 +
1.148 + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1.149 + data = (struct blockserver_private_data *) channel->private_data;
1.150 + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1.151 +
1.152 + client_close(data->file);
1.153 + return 0;
1.154 +}
1.155 +
1.156 +/* Update the block size in use. */
1.157 +
1.158 +static errcode_t blockserver_set_blksize(io_channel channel, int blksize)
1.159 +{
1.160 + struct blockserver_private_data *data;
1.161 +
1.162 + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1.163 + data = (struct blockserver_private_data *) channel->private_data;
1.164 + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1.165 +
1.166 + if (channel->block_size != blksize)
1.167 + channel->block_size = blksize;
1.168 +
1.169 + return 0;
1.170 +}
1.171 +
1.172 +/* Flush unwritten data. Without a cache, this does nothing. */
1.173 +
1.174 +static errcode_t blockserver_flush(io_channel channel)
1.175 +{
1.176 + return 0;
1.177 +}
1.178 +
1.179 +static errcode_t blockserver_set_option(io_channel channel, const char *option, const char *arg)
1.180 +{
1.181 + return 0;
1.182 +}
1.183 +
1.184 +static errcode_t blockserver_get_stats(io_channel channel, io_stats *stats)
1.185 +{
1.186 + return 0;
1.187 +}
1.188 +
1.189 +static errcode_t blockserver_read_blk64(io_channel channel, unsigned long long block, int count, void *buf)
1.190 +{
1.191 + /* Negative count values indicate a precise amount to read. */
1.192 +
1.193 + unsigned long long to_read = count < 0 ? -count : count * channel->block_size;
1.194 + ssize_t read;
1.195 + struct blockserver_private_data *data;
1.196 + errcode_t retval = 0;
1.197 +
1.198 + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1.199 + data = (struct blockserver_private_data *) channel->private_data;
1.200 + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1.201 +
1.202 + /* Perform the read at the given location. */
1.203 +
1.204 + client_seek(data->file, block * channel->block_size, SEEK_SET);
1.205 + read = client_read(data->file, buf, to_read);
1.206 +
1.207 + /* Check for a short read. */
1.208 +
1.209 + if ((read < 0) || ((size_t) read < to_read))
1.210 + retval = EXT2_ET_SHORT_READ;
1.211 +
1.212 + /* Handle read errors generally. */
1.213 +
1.214 + if (retval)
1.215 + if (channel->read_error)
1.216 + retval = (channel->read_error)(channel, block, count, buf,
1.217 + to_read, read, retval);
1.218 +
1.219 + return retval;
1.220 +}
1.221 +
1.222 +static errcode_t blockserver_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf)
1.223 +{
1.224 + /* Negative count values indicate a precise amount to write. */
1.225 +
1.226 + unsigned long long to_write = count < 0 ? -count : count * channel->block_size;
1.227 + ssize_t written;
1.228 + struct blockserver_private_data *data;
1.229 + errcode_t retval = 0;
1.230 +
1.231 + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1.232 + data = (struct blockserver_private_data *) channel->private_data;
1.233 + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1.234 +
1.235 + /* Perform the write at the given location. */
1.236 +
1.237 + client_seek(data->file, block * channel->block_size, SEEK_SET);
1.238 + written = client_write(data->file, buf, to_write);
1.239 +
1.240 + /* Check for a short write. */
1.241 +
1.242 + if ((written < 0) || ((size_t) written < to_write))
1.243 + retval = EXT2_ET_SHORT_WRITE;
1.244 +
1.245 + /* Handle write errors generally. */
1.246 +
1.247 + if (retval)
1.248 + if (channel->write_error)
1.249 + retval = (channel->write_error)(channel, block, count, buf,
1.250 + to_write, written, retval);
1.251 +
1.252 + return retval;
1.253 +}
1.254 +
1.255 +static errcode_t blockserver_read_blk(io_channel channel, unsigned long block, int count, void *buf)
1.256 +{
1.257 + return blockserver_read_blk64(channel, block, count, buf);
1.258 +}
1.259 +
1.260 +static errcode_t blockserver_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
1.261 +{
1.262 + return blockserver_write_blk64(channel, block, count, buf);
1.263 +}
1.264 +
1.265 +/* Unsupported operations are omitted: see io_manager.c for optional operation
1.266 + details. */
1.267 +
1.268 +static struct struct_io_manager struct_blockserver_manager = {
1.269 + .magic = EXT2_ET_MAGIC_IO_MANAGER,
1.270 + .name = "L4Re blockserver I/O Manager",
1.271 + .open = blockserver_open,
1.272 + .close = blockserver_close,
1.273 + .set_blksize = blockserver_set_blksize,
1.274 + .read_blk = blockserver_read_blk,
1.275 + .write_blk = blockserver_write_blk,
1.276 + .flush = blockserver_flush,
1.277 + .write_byte = 0,
1.278 + .set_option = blockserver_set_option,
1.279 + .get_stats = blockserver_get_stats,
1.280 + .read_blk64 = blockserver_read_blk64,
1.281 + .write_blk64 = blockserver_write_blk64,
1.282 + .discard = 0,
1.283 + .cache_readahead = 0,
1.284 + .zeroout = 0,
1.285 +};
1.286 +
1.287 +io_manager blockserver_io_manager = &struct_blockserver_manager;