4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* Copies heavily from e2fsprogs lib/ext2fs/unix_io.c: */
36 * io.c --- This is an nbdkit filter implementation of the I/O manager.
38 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
39 * 2002 by Theodore Ts'o.
42 * This file may be redistributed under the terms of the GNU Library
43 * General Public License, version 2.
55 * For checking structure magic numbers...
58 #define EXT2_CHECK_MAGIC(struct, code) \
59 if ((struct)->magic != (code)) return (code)
61 struct io_private_data
{
65 struct struct_io_stats io_stats
;
69 io_get_stats (io_channel channel
, io_stats
*stats
)
73 struct io_private_data
*data
;
75 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
76 data
= (struct io_private_data
*) channel
->private_data
;
77 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
80 *stats
= &data
->io_stats
;
86 * Here are the raw I/O functions
89 raw_read_blk (io_channel channel
,
90 struct io_private_data
*data
,
91 unsigned long long block
,
92 int count
, void *bufv
)
98 unsigned char *buf
= bufv
;
100 size
= (count
< 0) ? -count
: (ext2_loff_t
) count
* channel
->block_size
;
101 data
->io_stats
.bytes_read
+= size
;
102 location
= ((ext2_loff_t
) block
* channel
->block_size
) + data
->offset
;
104 /* TODO is 32-bit overflow ever likely to be a problem? */
105 if (data
->next
->pread (data
->next
, buf
, size
, location
, 0, &errno
) == 0)
109 if (channel
->read_error
)
110 retval
= (channel
->read_error
)(channel
, block
, count
, buf
,
111 size
, actual
, retval
);
116 raw_write_blk (io_channel channel
,
117 struct io_private_data
*data
,
118 unsigned long long block
,
119 int count
, const void *bufv
)
122 ext2_loff_t location
;
125 const unsigned char *buf
= bufv
;
128 size
= channel
->block_size
;
133 size
= (ext2_loff_t
) count
* channel
->block_size
;
135 data
->io_stats
.bytes_written
+= size
;
137 location
= ((ext2_loff_t
) block
* channel
->block_size
) + data
->offset
;
139 /* TODO is 32-bit overflow ever likely to be a problem? */
140 if (data
->next
->pwrite (data
->next
, buf
, size
, location
, 0,
145 if (channel
->write_error
)
146 retval
= (channel
->write_error
)(channel
, block
, count
, buf
,
147 size
, actual
, retval
);
152 nbdkit_io_encode (const nbdkit_next
*next
)
156 if (asprintf (&ret
, "nbdkit:%p", next
) < 0)
162 nbdkit_io_decode (const char *name
, nbdkit_next
**next
)
166 if (sscanf (name
, "nbdkit:%p%n", next
, &n
) != 1 || n
!= strlen (name
))
172 io_open (const char *name
, int flags
,
176 io_channel io
= NULL
;
177 struct io_private_data
*data
= NULL
;
180 if (nbdkit_io_decode (name
, &next
) == -1)
181 return EXT2_ET_BAD_DEVICE_NAME
;
183 retval
= ext2fs_get_mem (sizeof (struct struct_io_channel
), &io
);
186 memset (io
, 0, sizeof (struct struct_io_channel
));
187 io
->magic
= EXT2_ET_MAGIC_IO_CHANNEL
;
188 retval
= ext2fs_get_mem (sizeof (struct io_private_data
), &data
);
192 io
->manager
= nbdkit_io_manager
;
193 retval
= ext2fs_get_mem (strlen (name
)+1, &io
->name
);
197 strcpy (io
->name
, name
);
198 io
->private_data
= data
;
199 io
->block_size
= 1024;
204 memset (data
, 0, sizeof (struct io_private_data
));
205 data
->magic
= EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
;
206 data
->io_stats
.num_fields
= 2;
209 /* Too bad NBD doesn't tell us if next->trim guarantees read as zero. */
210 /* if (next-> XXX (...)
211 io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; */
213 if (flags
& IO_FLAG_RW
&& next
->can_write (next
) != 1) {
222 ext2fs_free_mem (&data
);
225 ext2fs_free_mem (&io
->name
);
227 ext2fs_free_mem (&io
);
233 io_close (io_channel channel
)
235 struct io_private_data
*data
;
236 errcode_t retval
= 0;
238 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
239 data
= (struct io_private_data
*) channel
->private_data
;
240 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
242 if (--channel
->refcount
> 0)
245 ext2fs_free_mem (&channel
->private_data
);
247 ext2fs_free_mem (&channel
->name
);
248 ext2fs_free_mem (&channel
);
253 io_set_blksize (io_channel channel
, int blksize
)
255 struct io_private_data
*data
;
257 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
258 data
= (struct io_private_data
*) channel
->private_data
;
259 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
261 channel
->block_size
= blksize
;
266 io_read_blk64 (io_channel channel
, unsigned long long block
,
267 int count
, void *buf
)
269 struct io_private_data
*data
;
271 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
272 data
= (struct io_private_data
*) channel
->private_data
;
273 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
275 return raw_read_blk (channel
, data
, block
, count
, buf
);
279 io_read_blk (io_channel channel
, unsigned long block
,
280 int count
, void *buf
)
282 return io_read_blk64 (channel
, block
, count
, buf
);
286 io_write_blk64 (io_channel channel
, unsigned long long block
,
287 int count
, const void *buf
)
289 struct io_private_data
*data
;
291 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
292 data
= (struct io_private_data
*) channel
->private_data
;
293 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
295 return raw_write_blk (channel
, data
, block
, count
, buf
);
298 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_CACHE_READAHEAD
300 io_cache_readahead (io_channel channel
,
301 unsigned long long block
,
302 unsigned long long count
)
304 struct io_private_data
*data
;
306 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
307 data
= (struct io_private_data
*)channel
->private_data
;
308 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
310 if (data
->next
->can_cache (data
->next
) == NBDKIT_CACHE_NATIVE
) {
311 /* TODO is 32-bit overflow ever likely to be a problem? */
312 if (data
->next
->cache (data
->next
,
313 (ext2_loff_t
)count
* channel
->block_size
,
314 ((ext2_loff_t
)block
* channel
->block_size
+
321 return EXT2_ET_OP_NOT_SUPPORTED
;
326 io_write_blk (io_channel channel
, unsigned long block
,
327 int count
, const void *buf
)
329 return io_write_blk64 (channel
, block
, count
, buf
);
333 io_write_byte (io_channel channel
, unsigned long offset
,
334 int size
, const void *buf
)
336 struct io_private_data
*data
;
338 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
339 data
= (struct io_private_data
*) channel
->private_data
;
340 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
342 if (data
->next
->pwrite (data
->next
, buf
, size
,
343 offset
+ data
->offset
, 0, &errno
) == -1)
350 * Flush data buffers to disk.
353 io_flush (io_channel channel
)
355 struct io_private_data
*data
;
356 errcode_t retval
= 0;
358 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
359 data
= (struct io_private_data
*) channel
->private_data
;
360 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
362 if (data
->next
->can_flush (data
->next
) == 1)
363 if (data
->next
->flush (data
->next
, 0, &errno
) == -1)
369 io_set_option (io_channel channel
, const char *option
,
372 struct io_private_data
*data
;
373 unsigned long long tmp
;
376 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
377 data
= (struct io_private_data
*) channel
->private_data
;
378 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
380 if (!strcmp (option
, "offset")) {
382 return EXT2_ET_INVALID_ARGUMENT
;
384 tmp
= strtoull (arg
, &end
, 0);
386 return EXT2_ET_INVALID_ARGUMENT
;
388 if (data
->offset
< 0)
389 return EXT2_ET_INVALID_ARGUMENT
;
392 return EXT2_ET_INVALID_ARGUMENT
;
396 io_discard (io_channel channel
, unsigned long long block
,
397 unsigned long long count
)
399 struct io_private_data
*data
;
401 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
402 data
= (struct io_private_data
*) channel
->private_data
;
403 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
405 if (data
->next
->can_trim (data
->next
) == 1) {
406 /* TODO is 32-bit overflow ever likely to be a problem? */
407 if (data
->next
->trim (data
->next
,
408 (off_t
)(count
) * channel
->block_size
,
409 ((off_t
)(block
) * channel
->block_size
+
413 if (errno
== EOPNOTSUPP
)
419 return EXT2_ET_UNIMPLEMENTED
;
422 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_ZEROOUT
424 io_zeroout (io_channel channel
, unsigned long long block
,
425 unsigned long long count
)
427 struct io_private_data
*data
;
429 EXT2_CHECK_MAGIC (channel
, EXT2_ET_MAGIC_IO_CHANNEL
);
430 data
= (struct io_private_data
*) channel
->private_data
;
431 EXT2_CHECK_MAGIC (data
, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL
);
433 if (data
->next
->can_zero (data
->next
) > NBDKIT_ZERO_NONE
) {
434 /* TODO is 32-bit overflow ever likely to be a problem? */
435 if (data
->next
->zero (data
->next
,
436 (off_t
)(count
) * channel
->block_size
,
437 ((off_t
)(block
) * channel
->block_size
+
439 NBDKIT_FLAG_MAY_TRIM
, &errno
) == 0)
441 if (errno
== EOPNOTSUPP
)
447 return EXT2_ET_UNIMPLEMENTED
;
451 static struct struct_io_manager struct_nbdkit_manager
= {
452 .magic
= EXT2_ET_MAGIC_IO_MANAGER
,
453 .name
= "nbdkit I/O Manager",
456 .set_blksize
= io_set_blksize
,
457 .read_blk
= io_read_blk
,
458 .write_blk
= io_write_blk
,
460 .write_byte
= io_write_byte
,
461 .set_option
= io_set_option
,
462 .get_stats
= io_get_stats
,
463 .read_blk64
= io_read_blk64
,
464 .write_blk64
= io_write_blk64
,
465 .discard
= io_discard
,
466 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_CACHE_READAHEAD
467 .cache_readahead
= io_cache_readahead
,
469 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_ZEROOUT
470 .zeroout
= io_zeroout
,
474 io_manager nbdkit_io_manager
= &struct_nbdkit_manager
;