📄 rait-device.c
字号:
chunk_size = size / (chunks - 1); rval = malloc(chunk_size); if (chunks != chunk) { /* data block. */ memcpy(rval, data + chunk_size * (chunk - 1), chunk_size); } else { make_parity_block(data, rval, chunk_size, chunks); } return rval;}static gboolean rait_device_write_block (Device * dself, guint size, gpointer data, gboolean last_block) { GPtrArray * ops; guint i; gboolean success; guint data_children, num_children; int blocksize; RaitDevice * self; self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, FALSE); find_simple_params(RAIT_DEVICE(self), &num_children, &data_children, &blocksize); num_children = self->private->children->len; if (num_children != 1) data_children = num_children - 1; else data_children = num_children; g_return_val_if_fail(size % data_children == 0 || last_block, FALSE); if (last_block) { char *new_data; new_data = malloc(blocksize); memcpy(new_data, data, size); bzero(new_data + size, blocksize - size); data = new_data; size = blocksize; } ops = g_ptr_array_sized_new(num_children); for (i = 0; i < self->private->children->len; i ++) { WriteBlockOp * op; op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->short_block = last_block; op->size = size / data_children; if (num_children <= 2) { op->data = data; op->data_needs_free = FALSE; } else { op->data_needs_free = TRUE; op->data = extract_data_block(data, size, num_children, i + 1); } g_ptr_array_add(ops, op); } if (last_block) { amfree(data); } do_rait_child_ops(write_block_do_op, ops, NULL); success = g_ptr_array_and(ops, extract_boolean_generic_op); for (i = 0; i < self->private->children->len; i ++) { WriteBlockOp * op = g_ptr_array_index(ops, i); if (op->data_needs_free) free(op->data); } g_ptr_array_free_full(ops); if (!success) { return FALSE; } else { /* We don't chain up here because we must handle finish_file differently. If we were called with last_block, then the children have already called finish_file themselves. So we update the device block numbers manually. */ dself->block ++; if (last_block) dself->in_file = FALSE; return TRUE; }}/* A GFunc */static void finish_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { GenericOp * op = data; op->result = GINT_TO_POINTER(device_finish_file(op->child));}static gboolean rait_device_finish_file (Device * self) { GPtrArray * ops; gboolean success; ops = make_generic_boolean_op_array(RAIT_DEVICE(self)); do_rait_child_ops(finish_file_do_op, ops, NULL); success = g_ptr_array_and(ops, extract_boolean_generic_op); g_ptr_array_free_full(ops); if (!success) { return FALSE; } else if (parent_class->finish_file) { return parent_class->finish_file(self); } else { return TRUE; }}typedef struct { GenericOp base; guint requested_file; /* IN */ guint actual_file; /* OUT */} SeekFileOp;/* a GFunc. */static void seek_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { SeekFileOp * op = data; op->base.result = device_seek_file(op->base.child, op->requested_file); op->actual_file = op->base.child->file;}static dumpfile_t * rait_device_seek_file (Device * dself, guint file) { GPtrArray * ops; guint i; gboolean success; dumpfile_t * rval; RaitDevice * self = RAIT_DEVICE(dself); guint actual_file = 0; g_return_val_if_fail(self != NULL, FALSE); ops = g_ptr_array_sized_new(self->private->children->len); for (i = 0; i < self->private->children->len; i ++) { SeekFileOp * op; if ((int)i == self->private->failed) continue; /* This device is broken. */ op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->base.child_index = i; op->requested_file = file; g_ptr_array_add(ops, op); } do_rait_child_ops(seek_file_do_op, ops, NULL); /* This checks for NULL values, but we still have to check for consistant headers. */ success = g_ptr_array_union_robust(RAIT_DEVICE(self), ops, extract_boolean_pointer_op); rval = NULL; for (i = 0; i < self->private->children->len; i ++) { SeekFileOp * this_op; dumpfile_t * this_result; guint this_actual_file; if ((int)i == self->private->failed) continue; this_op = (SeekFileOp*)g_ptr_array_index(ops, i); this_result = this_op->base.result; this_actual_file = this_op->actual_file; if (rval == NULL) { rval = this_result; actual_file = this_actual_file; } else { if (headers_are_equal(rval, this_result) && actual_file == this_actual_file) { /* Do nothing. */ } else { success = FALSE; } free(this_result); } } g_ptr_array_free_full(ops); if (!success) { amfree(rval); return NULL; } else if (parent_class->seek_file) { parent_class->seek_file(dself, file); } return rval;}typedef struct { GenericOp base; guint64 block; /* IN */} SeekBlockOp;/* a GFunc. */static void seek_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { SeekBlockOp * op = data; op->base.result = GINT_TO_POINTER(device_seek_block(op->base.child, op->block));}static gboolean rait_device_seek_block (Device * dself, guint64 block) { GPtrArray * ops; guint i; gboolean success; RaitDevice * self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, FALSE); ops = g_ptr_array_sized_new(self->private->children->len); for (i = 0; i < self->private->children->len; i ++) { SeekBlockOp * op; if ((int)i == self->private->failed) continue; /* This device is broken. */ op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->base.child_index = i; op->block = block; g_ptr_array_add(ops, op); } do_rait_child_ops(seek_block_do_op, ops, NULL); success = g_ptr_array_union_robust(RAIT_DEVICE(self), ops, extract_boolean_generic_op); g_ptr_array_free_full(ops); if (!success) { return FALSE; } else if (parent_class->seek_block) { return parent_class->seek_block(dself, block); } else { return success; }}typedef struct { GenericOp base; gpointer buffer; /* IN */ int read_size; /* IN/OUT -- note not a pointer */ int desired_read_size; /* bookkeeping */} ReadBlockOp;/* a GFunc. */static void read_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { ReadBlockOp * op = data; op->base.result = GINT_TO_POINTER(device_read_block(op->base.child, op->buffer, &(op->read_size)));}/* A BooleanExtractor. This one checks for a successful read. */static gboolean extract_boolean_read_block_op_data(gpointer data) { ReadBlockOp * op = data; return GPOINTER_TO_INT(op->base.result) == op->desired_read_size;}/* A BooleanExtractor. This one checks for EOF. */static gboolean extract_boolean_read_block_op_eof(gpointer data) { ReadBlockOp * op = data; return op->base.child->is_eof;}static int g_ptr_array_count(GPtrArray * array, BooleanExtractor filter) { int rval; unsigned int i; rval = 0; for (i = 0; i < array->len ; i++) { if (filter(g_ptr_array_index(array, i))) rval ++; } return rval;}static gboolean raid_block_reconstruction(RaitDevice * self, GPtrArray * ops, gpointer buf) { guint num_children, data_children; int blocksize, child_blocksize; guint i; int parity_child; gpointer parity_block = NULL; gboolean success; success = TRUE; find_simple_params(self, &num_children, &data_children, &blocksize); if (num_children > 1) parity_child = num_children - 1; else parity_child = -1; child_blocksize = blocksize / data_children; for (i = 0; i < ops->len; i ++) { ReadBlockOp * op = g_ptr_array_index(ops, i); if (!extract_boolean_read_block_op_data(op)) continue; if ((int)(op->base.child_index) == parity_child) { parity_block = op->buffer; } else { memcpy((char *)buf + child_blocksize * op->base.child_index, op->buffer, child_blocksize); } } if (self->private->status == RAIT_STATUS_COMPLETE) { if (num_children >= 2) { /* Verify the parity block. This code is inefficient but does the job for the 2-device case, too. */ gpointer constructed_parity; GPtrArray * data_extents; constructed_parity = malloc(child_blocksize); data_extents = g_ptr_array_sized_new(data_children); for (i = 0; i < data_children; i ++) { ReadBlockOp * op = g_ptr_array_index(ops, i); g_assert(extract_boolean_read_block_op_data(op)); if ((int)op->base.child_index == parity_child) continue; g_ptr_array_add(data_extents, op->buffer); } make_parity_block_extents(data_extents, constructed_parity, child_blocksize); if (0 != memcmp(parity_block, constructed_parity, child_blocksize)) { g_fprintf(stderr, "RAIT is inconsistant: " "Parity block did not match data blocks.\n"); success = FALSE; } g_ptr_array_free(data_extents, TRUE); amfree(constructed_parity); } else { /* do nothing. */ } } else if (self->private->status == RAIT_STATUS_DEGRADED) { /* We are in degraded mode. What's missing? */ if (self->private->failed == parity_child) { /* do nothing. */ } else if (num_children >= 2) { /* Reconstruct failed block from parity block. */ GPtrArray * data_extents = g_ptr_array_new(); for (i = 0; i < data_children; i ++) { ReadBlockOp * op = g_ptr_array_index(ops, i); if (!extract_boolean_read_block_op_data(op)) continue; g_ptr_array_add(data_extents, op->buffer); } /* Conveniently, the reconstruction is the same procedure as the parity generation. This even works if there is only one remaining device! */ make_parity_block_extents(data_extents, (char *)buf + (child_blocksize * self->private->failed), child_blocksize); /* The array members belong to our ops argument. */ g_ptr_array_free(data_extents, TRUE); } else { g_assert_not_reached(); } } else { success = FALSE; } return success;}static intrait_device_read_block (Device * dself, gpointer buf, int * size) { GPtrArray * ops; guint i; gboolean success; guint num_children, data_children; int blocksize; RaitDevice * self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, -1); find_simple_params(self, &num_children, &data_children, &blocksize); g_return_val_if_fail(*size >= (int)device_write_min_size(dself), -1); g_assert(blocksize % data_children == 0); /* If not we are screwed */ ops = g_ptr_array_sized_new(num_children); for (i = 0; i < num_children; i ++) { ReadBlockOp * op; if ((int)i == self->private->failed) continue; /* This device is broken. */ op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->base.child_index = i; op->buffer = malloc(blocksize / data_children); op->desired_read_size = op->read_size = blocksize / data_children; g_ptr_array_add(ops, op); } do_rait_child_ops(read_block_do_op, ops, NULL); if (g_ptr_array_count(ops, extract_boolean_read_block_op_data)) { success = g_ptr_array_union_robust(RAIT_DEVICE(self), ops, extract_boolean_read_block_op_data) && raid_block_reconstruction(RAIT_DEVICE(self), ops, buf); } else { success = FALSE; if (g_ptr_array_union_robust(RAIT_DEVICE(self), ops, extract_boolean_read_block_op_eof)) { /* We hit EOF. */ dself->is_eof = TRUE; } } for (i = 0; i < ops->len; i ++) { ReadBlockOp * op = g_ptr_array_index(ops, i); amfree(op->buffer); } g_ptr_array_free_full(ops); if (success) { if (parent_class->read_block) parent_class->read_block(dself, buf, size); return blocksize; } else { return -1; }}typedef struct { GenericOp base; DevicePropertyId id; /* IN */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -