2
* undo_io.c --- This is the undo io manager that copies the old data that
3
* copies the old data being overwritten into a tdb database
5
* Copyright IBM Corporation, 2007
6
* Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
9
* This file may be redistributed under the terms of the GNU Public
14
#define _LARGEFILE_SOURCE
15
#define _LARGEFILE64_SOURCE
28
#include <sys/utsname.h>
34
#include <sys/types.h>
36
#if HAVE_SYS_RESOURCE_H
37
#include <sys/resource.h>
46
#define ATTR(x) __attribute__(x)
52
* For checking structure magic numbers...
55
#define EXT2_CHECK_MAGIC(struct, code) \
56
if ((struct)->magic != (code)) return (code)
58
struct undo_private_data {
63
/* The backing io channel */
69
/* to support offset in unix I/O manager */
73
static errcode_t undo_open(const char *name, int flags, io_channel *channel);
74
static errcode_t undo_close(io_channel channel);
75
static errcode_t undo_set_blksize(io_channel channel, int blksize);
76
static errcode_t undo_read_blk(io_channel channel, unsigned long block,
77
int count, void *data);
78
static errcode_t undo_write_blk(io_channel channel, unsigned long block,
79
int count, const void *data);
80
static errcode_t undo_flush(io_channel channel);
81
static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
82
int size, const void *data);
83
static errcode_t undo_set_option(io_channel channel, const char *option,
86
static struct struct_io_manager struct_undo_manager = {
87
EXT2_ET_MAGIC_IO_MANAGER,
99
io_manager undo_io_manager = &struct_undo_manager;
100
static io_manager undo_io_backing_manager ;
101
static char *tdb_file;
102
static int actual_size;
104
static unsigned char mtime_key[] = "filesystem MTIME";
105
static unsigned char blksize_key[] = "filesystem BLKSIZE";
106
static unsigned char uuid_key[] = "filesystem UUID";
108
errcode_t set_undo_io_backing_manager(io_manager manager)
111
* We may want to do some validation later
113
undo_io_backing_manager = manager;
117
errcode_t set_undo_io_backup_file(char *file_name)
119
tdb_file = strdup(file_name);
121
if (tdb_file == NULL) {
122
return EXT2_ET_NO_MEMORY;
128
static errcode_t write_file_system_identity(io_channel undo_channel,
132
struct ext2_super_block super;
133
TDB_DATA tdb_key, tdb_data;
134
struct undo_private_data *data;
138
data = (struct undo_private_data *) undo_channel->private_data;
139
channel = data->real;
140
block_size = channel->block_size;
142
io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
143
retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
147
/* Write to tdb file in the file system byte order */
148
tdb_key.dptr = mtime_key;
149
tdb_key.dsize = sizeof(mtime_key);
150
tdb_data.dptr = (unsigned char *) &(super.s_mtime);
151
tdb_data.dsize = sizeof(super.s_mtime);
153
retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
155
retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
159
tdb_key.dptr = uuid_key;
160
tdb_key.dsize = sizeof(uuid_key);
161
tdb_data.dptr = (unsigned char *)&(super.s_uuid);
162
tdb_data.dsize = sizeof(super.s_uuid);
164
retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
166
retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
170
io_channel_set_blksize(channel, block_size);
174
static errcode_t write_block_size(TDB_CONTEXT *tdb, int block_size)
177
TDB_DATA tdb_key, tdb_data;
179
tdb_key.dptr = blksize_key;
180
tdb_key.dsize = sizeof(blksize_key);
181
tdb_data.dptr = (unsigned char *)&(block_size);
182
tdb_data.dsize = sizeof(block_size);
184
retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
186
retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
192
static errcode_t undo_write_tdb(io_channel channel,
193
unsigned long block, int count)
197
unsigned long block_num, backing_blk_num;
198
errcode_t retval = 0;
200
struct undo_private_data *data;
201
TDB_DATA tdb_key, tdb_data;
202
unsigned char *read_ptr;
203
unsigned long end_block;
205
data = (struct undo_private_data *) channel->private_data;
207
if (data->tdb == NULL) {
209
* Transaction database not initialized
215
size = channel->block_size;
220
size = count * channel->block_size;
223
* Data is stored in tdb database as blocks of tdb_data_size size
224
* This helps in efficient lookup further.
226
* We divide the disk to blocks of tdb_data_size.
228
offset = (block * channel->block_size) + data->offset ;
229
block_num = offset / data->tdb_data_size;
230
end_block = (offset + size) / data->tdb_data_size;
232
tdb_transaction_start(data->tdb);
233
while (block_num <= end_block ) {
235
tdb_key.dptr = (unsigned char *)&block_num;
236
tdb_key.dsize = sizeof(block_num);
238
* Check if we have the record already
240
if (tdb_exists(data->tdb, tdb_key)) {
241
/* Try the next block */
246
* Read one block using the backing I/O manager
247
* The backing I/O manager block size may be
248
* different from the tdb_data_size.
249
* Also we need to recalcuate the block number with respect
250
* to the backing I/O manager.
252
offset = block_num * data->tdb_data_size;
253
backing_blk_num = (offset - data->offset) / channel->block_size;
255
count = data->tdb_data_size +
256
((offset - data->offset) % channel->block_size);
257
retval = ext2fs_get_mem(count, &read_ptr);
259
tdb_transaction_cancel(data->tdb);
263
memset(read_ptr, 0, count);
265
if ((count % channel->block_size) == 0)
266
sz = count / channel->block_size;
269
retval = io_channel_read_blk(data->real, backing_blk_num,
272
if (retval != EXT2_ET_SHORT_READ) {
274
tdb_transaction_cancel(data->tdb);
278
* short read so update the record size
281
tdb_data.dsize = actual_size;
283
tdb_data.dsize = data->tdb_data_size;
285
tdb_data.dptr = read_ptr +
286
((offset - data->offset) % channel->block_size);
288
printf("Printing with key %ld data %x and size %d\n",
293
if (!data->tdb_written) {
294
data->tdb_written = 1;
295
/* Write the blocksize to tdb file */
296
retval = write_block_size(data->tdb,
297
data->tdb_data_size);
299
tdb_transaction_cancel(data->tdb);
300
retval = EXT2_ET_TDB_ERR_IO;
305
retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT);
308
* TDB_ERR_EXISTS cannot happen because we
309
* have already verified it doesn't exist
311
tdb_transaction_cancel(data->tdb);
312
retval = EXT2_ET_TDB_ERR_IO;
320
tdb_transaction_commit(data->tdb);
325
static errcode_t undo_io_read_error(io_channel channel ATTR((unused)),
326
unsigned long block ATTR((unused)),
327
int count ATTR((unused)),
328
void *data ATTR((unused)),
329
size_t size ATTR((unused)),
331
errcode_t error ATTR((unused)))
333
actual_size = actual;
337
static void undo_err_handler_init(io_channel channel)
339
channel->read_error = undo_io_read_error;
342
static errcode_t undo_open(const char *name, int flags, io_channel *channel)
344
io_channel io = NULL;
345
struct undo_private_data *data = NULL;
349
return EXT2_ET_BAD_DEVICE_NAME;
350
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
353
memset(io, 0, sizeof(struct struct_io_channel));
354
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
355
retval = ext2fs_get_mem(sizeof(struct undo_private_data), &data);
359
io->manager = undo_io_manager;
360
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
364
strcpy(io->name, name);
365
io->private_data = data;
366
io->block_size = 1024;
371
memset(data, 0, sizeof(struct undo_private_data));
372
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
374
if (undo_io_backing_manager) {
375
retval = undo_io_backing_manager->open(name, flags,
383
/* setup the tdb file */
384
data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST,
385
O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
392
* setup err handler for read so that we know
393
* when the backing manager fails do short read
395
undo_err_handler_init(data->real);
402
io_channel_close(data->real);
404
ext2fs_free_mem(&data);
406
ext2fs_free_mem(&io);
410
static errcode_t undo_close(io_channel channel)
412
struct undo_private_data *data;
413
errcode_t retval = 0;
415
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
416
data = (struct undo_private_data *) channel->private_data;
417
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
419
if (--channel->refcount > 0)
421
/* Before closing write the file system identity */
422
retval = write_file_system_identity(channel, data->tdb);
426
retval = io_channel_close(data->real);
428
tdb_close(data->tdb);
429
ext2fs_free_mem(&channel->private_data);
431
ext2fs_free_mem(&channel->name);
432
ext2fs_free_mem(&channel);
437
static errcode_t undo_set_blksize(io_channel channel, int blksize)
439
struct undo_private_data *data;
440
errcode_t retval = 0;
442
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
443
data = (struct undo_private_data *) channel->private_data;
444
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
447
retval = io_channel_set_blksize(data->real, blksize);
449
* Set the block size used for tdb
451
if (!data->tdb_data_size) {
452
data->tdb_data_size = blksize;
454
channel->block_size = blksize;
458
static errcode_t undo_read_blk(io_channel channel, unsigned long block,
459
int count, void *buf)
461
errcode_t retval = 0;
462
struct undo_private_data *data;
464
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
465
data = (struct undo_private_data *) channel->private_data;
466
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
469
retval = io_channel_read_blk(data->real, block, count, buf);
474
static errcode_t undo_write_blk(io_channel channel, unsigned long block,
475
int count, const void *buf)
477
struct undo_private_data *data;
478
errcode_t retval = 0;
480
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
481
data = (struct undo_private_data *) channel->private_data;
482
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
484
* First write the existing content into database
486
retval = undo_write_tdb(channel, block, count);
490
retval = io_channel_write_blk(data->real, block, count, buf);
495
static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
496
int size, const void *buf)
498
struct undo_private_data *data;
499
errcode_t retval = 0;
500
ext2_loff_t location;
501
unsigned long blk_num, count;;
503
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
504
data = (struct undo_private_data *) channel->private_data;
505
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
507
location = offset + data->offset;
508
blk_num = location/channel->block_size;
510
* the size specified may spread across multiple blocks
511
* also make sure we account for the fact that block start
512
* offset for tdb is different from the backing I/O manager
513
* due to possible different block size
515
count = (size + (location % channel->block_size) +
516
channel->block_size -1)/channel->block_size;
517
retval = undo_write_tdb(channel, blk_num, count);
520
if (data->real && data->real->manager->write_byte)
521
retval = io_channel_write_byte(data->real, offset, size, buf);
527
* Flush data buffers to disk.
529
static errcode_t undo_flush(io_channel channel)
531
errcode_t retval = 0;
532
struct undo_private_data *data;
534
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
535
data = (struct undo_private_data *) channel->private_data;
536
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
539
retval = io_channel_flush(data->real);
544
static errcode_t undo_set_option(io_channel channel, const char *option,
547
errcode_t retval = 0;
548
struct undo_private_data *data;
552
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
553
data = (struct undo_private_data *) channel->private_data;
554
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
556
if (!strcmp(option, "tdb_data_size")) {
558
return EXT2_ET_INVALID_ARGUMENT;
560
tmp = strtoul(arg, &end, 0);
562
return EXT2_ET_INVALID_ARGUMENT;
563
if (!data->tdb_data_size || !data->tdb_written) {
564
data->tdb_data_size = tmp;
569
* Need to support offset option to work with
572
if (data->real && data->real->manager->set_option) {
573
retval = data->real->manager->set_option(data->real,
576
if (!retval && !strcmp(option, "offset")) {
578
return EXT2_ET_INVALID_ARGUMENT;
580
tmp = strtoul(arg, &end, 0);
582
return EXT2_ET_INVALID_ARGUMENT;