📄 rait-device.c
字号:
/* A BooleanExtractor */static gboolean extract_boolean_generic_op(gpointer data) { GenericOp * op = data; return GPOINTER_TO_INT(op->result);}/* A BooleanExtractor */static gboolean extract_boolean_pointer_op(gpointer data) { GenericOp * op = data; return op->result != NULL;}/* Does the equivalent of this perl command: ! (first { !extractor($_) } @_ That is, calls extractor on each element of the array, and returns TRUE if and only if all calls to extractor return TRUE.*/static gboolean g_ptr_array_and(GPtrArray * array, BooleanExtractor extractor) { guint i; if (array == NULL || array->len <= 0) return FALSE; for (i = 0; i < array->len; i ++) { if (!extractor(g_ptr_array_index(array, i))) return FALSE; } return TRUE;}/* Takes a RaitDevice, and makes a GPtrArray of GenericOp. */static GPtrArray * make_generic_boolean_op_array(RaitDevice* self) { GPtrArray * rval; guint i; rval = g_ptr_array_sized_new(self->private->children->len); for (i = 0; i < self->private->children->len; i ++) { GenericOp * op; op = malloc(sizeof(*op)); op->child = g_ptr_array_index(self->private->children, i); op->child_index = i; g_ptr_array_add(rval, op); } return rval;}/* Takes a GPtrArray of GenericOp, and a BooleanExtractor, and does all the proper handling for the result of operations that allow device isolation. Returns FALSE only if an unrecoverable error occured. */static gboolean g_ptr_array_union_robust(RaitDevice * self, GPtrArray * ops, BooleanExtractor extractor) { gboolean success; gpointer isolated_op = NULL; for (;;) { success = g_ptr_array_and(ops, extractor); if (success || self->private->status != RAIT_STATUS_COMPLETE) { break; } else { guint i; /* First device failure, note the device and march on. */ self->private->status = RAIT_STATUS_DEGRADED; for (i = 0; i < ops->len; i ++) { GenericOp * op = g_ptr_array_index(ops, i); if (!(op->result)) { isolated_op = g_ptr_array_remove_index_fast(ops, i); self->private->failed = op->child_index; g_fprintf(stderr, "RAIT array %s Isolated device %s.\n", DEVICE(self)->device_name, op->child->device_name); break; } } } } /* Return isolated op so any data members can be freed. */ if (isolated_op != NULL) { g_ptr_array_add(ops, isolated_op); } return success;}typedef struct { Device * result; /* IN */ char * device_name; /* OUT */} OpenDeviceOp;/* A GFunc. */static void open_device_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { OpenDeviceOp * op = data; op->result = device_open(op->device_name); amfree(op->device_name);}/* Returns TRUE if and only if the volume label and time are equal. */static gboolean compare_volume_results(Device * a, Device * b) { if (a->volume_time != b->volume_time) return FALSE; if (a->volume_label == NULL && b->volume_label == NULL) return TRUE; if (a->volume_label == NULL || b->volume_label == NULL) return FALSE; return 0 == strcmp(a->volume_label, b->volume_label);}static gboolean rait_device_open_device (Device * dself, char * device_name) { char ** device_names; GPtrArray * open_device_ops; guint i; gboolean failure; RaitDevice * self; self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail (device_name != NULL, FALSE); device_names = parse_device_name(device_name); if (device_names == NULL) return FALSE; /* Open devices in a separate thread, in case they have to rewind etc. */ open_device_ops = g_ptr_array_new(); for (i = 0; device_names[i] != NULL; i ++) { OpenDeviceOp *op; op = malloc(sizeof(*op)); op->device_name = device_names[i]; op->result = NULL; g_ptr_array_add(open_device_ops, op); } free(device_names); do_rait_child_ops(open_device_do_op, open_device_ops, NULL); failure = FALSE; /* Check results of opening devices. */ for (i = 0; i < open_device_ops->len; i ++) { OpenDeviceOp *op = g_ptr_array_index(open_device_ops, i); if (op->result != NULL) { g_ptr_array_add(self->private->children, op->result); } else { failure = TRUE; } } g_ptr_array_free_full(open_device_ops); failure = failure || !find_block_size(self); if (failure) return FALSE; /* This will clean up any created children. */ register_properties(self); /* Chain up. */ if (parent_class->open_device) { return parent_class->open_device(dself, device_name); } else { return TRUE; }}/* A GFunc. */static void read_label_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { GenericOp * op = data; op->result = GINT_TO_POINTER(device_read_label(op->child));}static ReadLabelStatusFlags rait_device_read_label(Device * dself) { RaitDevice * self; GPtrArray * ops; ReadLabelStatusFlags failed_result = 0; ReadLabelStatusFlags rval; GenericOp * failed_op = NULL; /* If this is non-null, we will isolate. */ unsigned int i; Device * first_success = NULL; self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, FALSE); amfree(dself->volume_label); ops = make_generic_boolean_op_array(self); do_rait_child_ops(read_label_do_op, ops, NULL); for (i = 0; i < ops->len; i ++) { GenericOp * op = g_ptr_array_index(ops, i); ReadLabelStatusFlags result = GPOINTER_TO_INT(op->result); if (op->result == READ_LABEL_STATUS_SUCCESS) { if (first_success == NULL) { /* This is the first successful device. */ first_success = op->child; } else if (!compare_volume_results(first_success, op->child)) { /* Doesn't match. :-( */ g_fprintf(stderr, "Inconsistant volume labels: " "Got %s/%s against %s/%s.\n", first_success->volume_label, first_success->volume_time, op->child->volume_label, op->child->volume_time); failed_result |= READ_LABEL_STATUS_VOLUME_ERROR; failed_op = NULL; } } else { if (failed_result == 0 && self->private->status == RAIT_STATUS_COMPLETE) { /* This is the first failed device; note it and we'll isolate later. */ failed_op = op; failed_result = result; } else { /* We've encountered multiple failures. OR them together. */ failed_result |= result; failed_op = NULL; } } } if (failed_op != NULL) { /* We have a single device to isolate. */ failed_result = READ_LABEL_STATUS_SUCCESS; /* Recover later */ self->private->failed = failed_op->child_index; g_fprintf(stderr, "RAIT array %s Isolated device %s.\n", dself->device_name, failed_op->child->device_name); } if (failed_result != READ_LABEL_STATUS_SUCCESS) { /* We had multiple failures or an inconsistency. */ rval = failed_result; } else { /* Everything peachy. */ rval = READ_LABEL_STATUS_SUCCESS; g_assert(first_success != NULL); if (first_success->volume_label != NULL) { dself->volume_label = g_strdup(first_success->volume_label); } if (first_success->volume_time != NULL) { dself->volume_time = g_strdup(first_success->volume_time); } } g_ptr_array_free_full(ops); return rval;}typedef struct { GenericOp base; DeviceAccessMode mode; /* IN */ char * label; /* IN */ char * timestamp; /* IN */} StartOp;/* A GFunc. */static void start_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { DeviceClass *klass; StartOp * param = data; klass = DEVICE_GET_CLASS(param->base.child); if (klass->start) { param->base.result = GINT_TO_POINTER((klass->start)(param->base.child, param->mode, param->label, param->timestamp)); } else { param->base.result = FALSE; }}static gboolean rait_device_start (Device * dself, DeviceAccessMode mode, char * label, char * timestamp) { GPtrArray * ops; guint i; gboolean success; RaitDevice * self; 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 ++) { StartOp * op; op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->mode = mode; op->label = g_strdup(label); op->timestamp = g_strdup(timestamp); g_ptr_array_add(ops, op); } do_rait_child_ops(start_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->start) { return parent_class->start(dself, mode, label, timestamp); } else { return TRUE; }}typedef struct { GenericOp base; const dumpfile_t * info; /* IN */} StartFileOp;/* a GFunc */static void start_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { StartFileOp * op = data; op->base.result = GINT_TO_POINTER(device_start_file(op->base.child, op->info));}static gbooleanrait_device_start_file (Device * dself, const dumpfile_t * info) { GPtrArray * ops; guint i; gboolean success; RaitDevice * self; 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 ++) { StartFileOp * op; op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->info = info; g_ptr_array_add(ops, op); } do_rait_child_ops(start_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->start_file) { return parent_class->start_file(dself, info); } else { return TRUE; }}static void find_simple_params(RaitDevice * self, guint * num_children, guint * data_children, int * blocksize) { int num, data; num = self->private->children->len; if (num > 1) data = num - 1; else data = num; if (num_children != NULL) *num_children = num; if (data_children != NULL) *data_children = data; if (blocksize != NULL) { *blocksize = device_write_min_size(DEVICE(self)); }}typedef struct { GenericOp base; guint size; /* IN */ gpointer data; /* IN */ gboolean short_block; /* IN */ gboolean data_needs_free; /* bookkeeping */} WriteBlockOp;/* a GFunc. */static void write_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { WriteBlockOp * op = data; op->base.result = GINT_TO_POINTER(device_write_block(op->base.child, op->size, op->data, op->short_block));}/* Parity block generation. Performance of this function can be improved considerably by using larger-sized integers or assembly-coded vector instructions. Parameters are: % data - All data chunks in series (chunk_size * num_chunks bytes) % parity - Allocated space for parity block (chunk_size bytes) */static void make_parity_block(char * data, char * parity, guint chunk_size, guint num_chunks) { guint i; bzero(parity, chunk_size); for (i = 0; i < num_chunks - 1; i ++) { guint j; for (j = 0; j < chunk_size; j ++) { parity[j] ^= data[chunk_size*i + j]; } }}/* Does the same thing as make_parity_block, but instead of using a single memory chunk holding all chunks, it takes a GPtrArray of chunks. */static void make_parity_block_extents(GPtrArray * data, char * parity, guint chunk_size) { guint i; bzero(parity, chunk_size); for (i = 0; i < data->len; i ++) { guint j; char * data_chunk; data_chunk = g_ptr_array_index(data, i); for (j = 0; j < chunk_size; j ++) { parity[j] ^= data_chunk[j]; } }}/* Does the parity creation algorithm. Allocates and returns a single device block from a larger RAIT block. chunks and chunk are 1-indexed. */static char * extract_data_block(char * data, guint size, guint chunks, guint chunk) { char * rval; guint chunk_size; g_return_val_if_fail(chunks > 0 && chunk > 0 && chunk <= chunks, NULL); g_return_val_if_fail(data != NULL, NULL); g_return_val_if_fail(size > 0 && size % (chunks - 1) == 0, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -