2 * Copyright (c) 2005-2008 Zmanda, Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
21 /* The RAIT device encapsulates some number of other devices into a single
22 * redundant device. */
28 #include "glib-util.h"
30 #include "fileheader.h"
31 #include "semaphore.h"
33 /* Just a note about the failure mode of different operations:
34 - Recovers from a failure (enters degraded mode)
36 seek_file() -- explodes if headers don't match.
37 seek_block() -- explodes if headers don't match.
38 read_block() -- explodes if data doesn't match.
40 - Operates in degraded mode (but dies if a new problem shows up)
41 read_label() -- but dies on label mismatch.
42 start() -- but dies when writing in degraded mode.
46 - Dies in degraded mode (even if remaining devices are OK)
54 * Type checking and casting macros
56 #define TYPE_RAIT_DEVICE (rait_device_get_type())
57 #define RAIT_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice)
58 #define RAIT_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice const)
59 #define RAIT_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), rait_device_get_type(), RaitDeviceClass)
60 #define IS_RAIT_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), rait_device_get_type ())
62 #define RAIT_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), rait_device_get_type(), RaitDeviceClass)
63 static GType rait_device_get_type (void);
66 * Main object structure
68 typedef struct RaitDevice_s {
71 struct RaitDevicePrivate_s * private;
77 typedef struct _RaitDeviceClass RaitDeviceClass;
78 struct _RaitDeviceClass {
79 DeviceClass __parent__;
83 RAIT_STATUS_COMPLETE, /* All subdevices OK. */
84 RAIT_STATUS_DEGRADED, /* One subdevice failed. */
85 RAIT_STATUS_FAILED /* Two or more subdevices failed. */
88 /* Older versions of glib have a deadlock in their thread pool implementations,
89 * so we include a simple thread-pool implementation here to replace it.
91 * This implementation assumes that threads are used for paralellizing a single
92 * operation, so all threads run a function to completion before the main thread
93 * continues. This simplifies some of the locking semantics, and in particular
94 * there is no need to wait for stray threads to finish an operation when
95 * finalizing the RaitDevice object or when beginning a new operation.
97 #if !(GLIB_CHECK_VERSION(2,10,0))
98 #define USE_INTERNAL_THREADPOOL
101 typedef struct RaitDevicePrivate_s {
102 GPtrArray * children;
103 /* These flags are only relevant for reading. */
105 /* If status == RAIT_STATUS_DEGRADED, this holds the index of the
106 failed node. It holds a negative number otherwise. */
109 /* the child block size */
110 gsize child_block_size;
112 #ifdef USE_INTERNAL_THREADPOOL
113 /* array of ThreadInfo for performing parallel operations */
116 /* value of this semaphore is the number of threaded operations
118 semaphore_t *threads_sem;
122 #ifdef USE_INTERNAL_THREADPOOL
123 typedef struct ThreadInfo {
126 /* struct fields below are protected by this mutex and condition variable */
134 /* give threads access to active_threads and its mutex/cond */
135 struct RaitDevicePrivate_s *private;
140 #define PRIVATE(o) (o->private)
142 #define rait_device_in_error(dev) \
143 (device_in_error((dev)) || PRIVATE(RAIT_DEVICE((dev)))->status == RAIT_STATUS_FAILED)
145 void rait_device_register (void);
147 /* here are local prototypes */
148 static void rait_device_init (RaitDevice * o);
149 static void rait_device_class_init (RaitDeviceClass * c);
150 static void rait_device_base_init (RaitDeviceClass * c);
151 static void rait_device_open_device (Device * self, char * device_name, char * device_type, char * device_node);
152 static gboolean rait_device_start (Device * self, DeviceAccessMode mode,
153 char * label, char * timestamp);
154 static gboolean rait_device_configure(Device * self, gboolean use_global_config);
155 static gboolean rait_device_start_file(Device * self, dumpfile_t * info);
156 static gboolean rait_device_write_block (Device * self, guint size, gpointer data);
157 static gboolean rait_device_finish_file (Device * self);
158 static dumpfile_t * rait_device_seek_file (Device * self, guint file);
159 static gboolean rait_device_seek_block (Device * self, guint64 block);
160 static int rait_device_read_block (Device * self, gpointer buf,
162 static gboolean rait_device_recycle_file (Device * self, guint filenum);
163 static gboolean rait_device_finish (Device * self);
164 static DeviceStatusFlags rait_device_read_label(Device * dself);
165 static void find_simple_params(RaitDevice * self, guint * num_children,
166 guint * data_children);
168 /* property handlers */
170 static gboolean property_get_block_size_fn(Device *self,
171 DevicePropertyBase *base, GValue *val,
172 PropertySurety *surety, PropertySource *source);
174 static gboolean property_set_block_size_fn(Device *self,
175 DevicePropertyBase *base, GValue *val,
176 PropertySurety surety, PropertySource source);
178 static gboolean property_get_canonical_name_fn(Device *self,
179 DevicePropertyBase *base, GValue *val,
180 PropertySurety *surety, PropertySource *source);
182 static gboolean property_get_concurrency_fn(Device *self,
183 DevicePropertyBase *base, GValue *val,
184 PropertySurety *surety, PropertySource *source);
186 static gboolean property_get_streaming_fn(Device *self,
187 DevicePropertyBase *base, GValue *val,
188 PropertySurety *surety, PropertySource *source);
190 static gboolean property_get_boolean_and_fn(Device *self,
191 DevicePropertyBase *base, GValue *val,
192 PropertySurety *surety, PropertySource *source);
194 static gboolean property_get_medium_access_type_fn(Device *self,
195 DevicePropertyBase *base, GValue *val,
196 PropertySurety *surety, PropertySource *source);
198 static gboolean property_get_free_space_fn(Device *self,
199 DevicePropertyBase *base, GValue *val,
200 PropertySurety *surety, PropertySource *source);
202 static gboolean property_get_max_volume_usage_fn(Device *self,
203 DevicePropertyBase *base, GValue *val,
204 PropertySurety *surety, PropertySource *source);
206 static gboolean property_set_max_volume_usage_fn(Device *self,
207 DevicePropertyBase *base, GValue *val,
208 PropertySurety surety, PropertySource source);
211 /* pointer to the class of our parent */
212 static DeviceClass *parent_class = NULL;
215 rait_device_get_type (void)
217 static GType type = 0;
219 if G_UNLIKELY(type == 0) {
220 static const GTypeInfo info = {
221 sizeof (RaitDeviceClass),
222 (GBaseInitFunc) rait_device_base_init,
223 (GBaseFinalizeFunc) NULL,
224 (GClassInitFunc) rait_device_class_init,
225 (GClassFinalizeFunc) NULL,
226 NULL /* class_data */,
229 (GInstanceInitFunc) rait_device_init,
233 type = g_type_register_static (TYPE_DEVICE, "RaitDevice", &info,
240 static void g_object_unref_foreach(gpointer data,
241 gpointer user_data G_GNUC_UNUSED) {
242 if (data != NULL && G_IS_OBJECT(data)) {
243 g_object_unref(data);
248 rait_device_finalize(GObject *obj_self)
250 RaitDevice *self = RAIT_DEVICE (obj_self);
251 if(G_OBJECT_CLASS(parent_class)->finalize) \
252 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
253 if(self->private->children) {
254 g_ptr_array_foreach(self->private->children,
255 g_object_unref_foreach, NULL);
256 g_ptr_array_free (self->private->children, TRUE);
257 self->private->children = NULL;
259 #ifdef USE_INTERNAL_THREADPOOL
260 g_assert(PRIVATE(self)->threads_sem == NULL || PRIVATE(self)->threads_sem->value == 0);
262 if (PRIVATE(self)->threads) {
265 for (i = 0; i < PRIVATE(self)->threads->len; i++) {
266 ThreadInfo *inf = &g_array_index(PRIVATE(self)->threads, ThreadInfo, i);
268 /* NOTE: the thread is waiting on this condition right now, not
269 * executing an operation. */
271 /* ask the thread to die */
272 g_mutex_lock(inf->mutex);
274 g_cond_signal(inf->cond);
275 g_mutex_unlock(inf->mutex);
277 /* and wait for it to die, which should happen soon */
278 g_thread_join(inf->thread);
282 g_mutex_free(inf->mutex);
284 g_cond_free(inf->cond);
288 if (PRIVATE(self)->threads_sem)
289 semaphore_free(PRIVATE(self)->threads_sem);
291 amfree(self->private);
295 rait_device_init (RaitDevice * o G_GNUC_UNUSED)
297 PRIVATE(o) = g_new(RaitDevicePrivate, 1);
298 PRIVATE(o)->children = g_ptr_array_new();
299 PRIVATE(o)->status = RAIT_STATUS_COMPLETE;
300 PRIVATE(o)->failed = -1;
301 #ifdef USE_INTERNAL_THREADPOOL
302 PRIVATE(o)->threads = NULL;
303 PRIVATE(o)->threads_sem = NULL;
308 rait_device_class_init (RaitDeviceClass * c)
310 GObjectClass *g_object_class = (GObjectClass*) c;
311 DeviceClass *device_class = (DeviceClass *)c;
313 parent_class = g_type_class_ref (TYPE_DEVICE);
315 device_class->open_device = rait_device_open_device;
316 device_class->configure = rait_device_configure;
317 device_class->start = rait_device_start;
318 device_class->start_file = rait_device_start_file;
319 device_class->write_block = rait_device_write_block;
320 device_class->finish_file = rait_device_finish_file;
321 device_class->seek_file = rait_device_seek_file;
322 device_class->seek_block = rait_device_seek_block;
323 device_class->read_block = rait_device_read_block;
324 device_class->recycle_file = rait_device_recycle_file;
325 device_class->finish = rait_device_finish;
326 device_class->read_label = rait_device_read_label;
328 g_object_class->finalize = rait_device_finalize;
330 #ifndef USE_INTERNAL_THREADPOOL
331 #if !GLIB_CHECK_VERSION(2,10,2)
332 /* Versions of glib before 2.10.2 crash if
333 * g_thread_pool_set_max_unused_threads is called before the first
334 * invocation of g_thread_pool_new. So we make up a thread pool, but don't
335 * start any threads in it, and free it */
337 GThreadPool *pool = g_thread_pool_new((GFunc)-1, NULL, -1, FALSE, NULL);
338 g_thread_pool_free(pool, TRUE, FALSE);
342 g_thread_pool_set_max_unused_threads(-1);
347 rait_device_base_init (RaitDeviceClass * c)
349 DeviceClass *device_class = (DeviceClass *)c;
351 /* the RAIT device overrides most of the standard properties, so that it
352 * can calculate them by querying the same property on the children */
353 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
354 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
355 property_get_block_size_fn,
356 property_set_block_size_fn);
358 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
359 PROPERTY_ACCESS_GET_MASK,
360 property_get_canonical_name_fn, NULL);
362 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
363 PROPERTY_ACCESS_GET_MASK,
364 property_get_concurrency_fn, NULL);
366 device_class_register_property(device_class, PROPERTY_STREAMING,
367 PROPERTY_ACCESS_GET_MASK,
368 property_get_streaming_fn, NULL);
370 device_class_register_property(device_class, PROPERTY_APPENDABLE,
371 PROPERTY_ACCESS_GET_MASK,
372 property_get_boolean_and_fn, NULL);
374 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
375 PROPERTY_ACCESS_GET_MASK,
376 property_get_boolean_and_fn, NULL);
378 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
379 PROPERTY_ACCESS_GET_MASK,
380 property_get_medium_access_type_fn, NULL);
382 device_class_register_property(device_class, PROPERTY_FREE_SPACE,
383 PROPERTY_ACCESS_GET_MASK,
384 property_get_free_space_fn, NULL);
386 device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
387 PROPERTY_ACCESS_GET_MASK,
388 property_get_max_volume_usage_fn,
389 property_set_max_volume_usage_fn);
392 /* This function does something a little clever and a little
393 * complicated. It takes an array of operations and runs the given
394 * function on each element in the array. The trick is that it runs them
395 * all in parallel, in different threads. This is more efficient than it
396 * sounds because we use a GThreadPool, which means calling this function
397 * will probably not start any new threads at all, but rather use
398 * existing ones. The func is called with two gpointer arguments: The
399 * first from the array, the second is the data argument.
401 * When it returns, all the operations have been successfully
402 * executed. If you want results from your operations, do it yourself
406 #ifdef USE_INTERNAL_THREADPOOL
407 static gpointer rait_thread_pool_func(gpointer data) {
408 ThreadInfo *inf = data;
410 g_mutex_lock(inf->mutex);
412 while (!inf->die && !inf->func)
413 g_cond_wait(inf->cond, inf->mutex);
419 /* invoke the function */
420 inf->func(inf->data, NULL);
424 /* indicate that we're finished; will not block */
425 semaphore_down(inf->private->threads_sem);
428 g_mutex_unlock(inf->mutex);
432 static void do_thread_pool_op(RaitDevice *self, GFunc func, GPtrArray * ops) {
435 if (PRIVATE(self)->threads_sem == NULL)
436 PRIVATE(self)->threads_sem = semaphore_new_with_value(0);
438 if (PRIVATE(self)->threads == NULL)
439 PRIVATE(self)->threads = g_array_sized_new(FALSE, TRUE,
440 sizeof(ThreadInfo), ops->len);
442 g_assert(PRIVATE(self)->threads_sem->value == 0);
444 if (PRIVATE(self)->threads->len < ops->len)
445 g_array_set_size(PRIVATE(self)->threads, ops->len);
447 /* the semaphore will hit zero when each thread has decremented it */
448 semaphore_force_set(PRIVATE(self)->threads_sem, ops->len);
450 for (i = 0; i < ops->len; i++) {
451 ThreadInfo *inf = &g_array_index(PRIVATE(self)->threads, ThreadInfo, i);
453 inf->mutex = g_mutex_new();
454 inf->cond = g_cond_new();
455 inf->private = PRIVATE(self);
456 inf->thread = g_thread_create(rait_thread_pool_func, inf, TRUE, NULL);
459 /* set up the info the thread needs and trigger it to start */
460 g_mutex_lock(inf->mutex);
461 inf->data = g_ptr_array_index(ops, i);
463 g_cond_signal(inf->cond);
464 g_mutex_unlock(inf->mutex);
467 /* wait until semaphore hits zero */
468 semaphore_wait_empty(PRIVATE(self)->threads_sem);
471 #else /* USE_INTERNAL_THREADPOOL */
473 static void do_thread_pool_op(RaitDevice *self G_GNUC_UNUSED, GFunc func, GPtrArray * ops) {
477 pool = g_thread_pool_new(func, NULL, -1, FALSE, NULL);
478 for (i = 0; i < ops->len; i ++) {
479 g_thread_pool_push(pool, g_ptr_array_index(ops, i), NULL);
482 g_thread_pool_free(pool, FALSE, TRUE);
485 #endif /* USE_INTERNAL_THREADPOOL */
487 /* This does the above, in a serial fashion (and without using threads) */
488 static void do_unthreaded_ops(RaitDevice *self G_GNUC_UNUSED, GFunc func, GPtrArray * ops) {
491 for (i = 0; i < ops->len; i ++) {
492 func(g_ptr_array_index(ops, i), NULL);
496 /* This is the one that code below should call. It switches
497 automatically between do_thread_pool_op and do_unthreaded_ops,
498 depending on g_thread_supported(). */
499 static void do_rait_child_ops(RaitDevice *self, GFunc func, GPtrArray * ops) {
500 if (g_thread_supported()) {
501 do_thread_pool_op(self, func, ops);
503 do_unthreaded_ops(self, func, ops);
507 /* Helper for parse_device_name; returns a list of un-escaped strings for
508 * the first "component" of str, where a component is a plain string or a
509 * brace-enclosed set of alternatives. str is pointing to the first character
510 * of the next component on return. */
512 parse_device_name_component(char **str)
514 GPtrArray *result = g_ptr_array_new();
518 char *local = g_malloc(strlen(*str)+1);
519 char *current = local;
523 if (*p == '\0' || *p == '{') {
524 /* unterminated { .. } or extra '{' */
526 g_ptr_array_free(result, TRUE);
530 if (*p == '}' || *p == ',') {
532 g_ptr_array_add(result, g_strdup(current));
542 if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
555 /* no braces -- just un-escape a plain string */
556 char *local = g_malloc(strlen(*str)+1);
560 while (*p && *p != '{') {
562 if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
568 g_ptr_array_add(result, local);
575 /* Take a text string user_name, and break it out into an argv-style
576 array of strings, using a {..,..} syntax similar to shell brace expansion.
579 "{foo,bar,bat}" -> [ "foo", "bar", "bat" ]
580 "foo{1,2}bar" -> [ "foo1bar", "foo2bar" ]
581 "foo{1\,2,3}bar" -> [ "foo1,2bar", "foo3bar" ]
582 "{a,b}-{1,2}" -> [ "a-1", "a-2", "b-1", "b-2" ]
584 Note that nested braces are not processed. Braces, commas, and backslashes
585 may be escaped with backslashes. Returns NULL on invalid strings.
589 parse_device_name(char * user_name)
591 GPtrArray *rval = g_ptr_array_new();
593 g_ptr_array_add(rval, g_strdup(""));
596 GPtrArray *new_components;
600 new_components = parse_device_name_component(&user_name);
601 if (!new_components) {
603 g_ptr_array_free(rval, TRUE);
607 new_rval = g_ptr_array_new();
609 /* do a cartesian join of rval and new_components */
610 for (i = 0; i < rval->len; i++) {
611 for (j = 0; j < new_components->len; j++) {
612 g_ptr_array_add(new_rval, g_strconcat(
613 g_ptr_array_index(rval, i),
614 g_ptr_array_index(new_components, j),
619 g_ptr_array_free(rval, TRUE);
620 g_ptr_array_free(new_components, TRUE);
628 child_device_names_to_rait_name(RaitDevice * self) {
629 GString *rait_name = NULL;
632 rait_name = g_string_new("rait:{");
634 for (i = 0; i < self->private->children->len; i ++) {
635 Device *child = g_ptr_array_index(self->private->children, i);
636 const char *child_name = NULL;
638 gboolean got_prop = FALSE;
640 bzero(&val, sizeof(val));
642 if ((signed)i != self->private->failed) {
643 if (device_property_get(child, PROPERTY_CANONICAL_NAME, &val)) {
644 child_name = g_value_get_string(&val);
650 child_name = "MISSING";
652 g_string_append_printf(rait_name, "%s%s", child_name,
653 (i < self->private->children->len-1)? "," : "");
659 g_string_append(rait_name, "}");
660 return g_string_free(rait_name, FALSE);
663 /* Find a workable child block size, based on the block size ranges of our
666 * The algorithm is to construct the intersection of all child devices'
667 * [min,max] block size ranges, and then pick the block size closest to 32k
668 * that is in the resulting range. This avoids picking ridiculously small (1
669 * byte) or large (INT_MAX) block sizes when using devices with wide-open block
672 * This function returns the calculated child block size directly, and the RAIT
673 * device's blocksize via rait_size, if not NULL. It is resilient to errors in
674 * a single child device, but sets the device's error status and returns 0 if
675 * it cannot determine an agreeable block size.
678 calculate_block_size_from_children(RaitDevice * self, gsize *rait_size)
681 gsize max = SIZE_MAX;
682 gboolean found_one = FALSE;
686 for (i = 0; i < self->private->children->len; i ++) {
687 gsize child_min = SIZE_MAX, child_max = 0;
689 GValue property_result;
690 PropertySource source;
692 bzero(&property_result, sizeof(property_result));
694 if ((signed)i == self->private->failed)
697 child = g_ptr_array_index(self->private->children, i);
698 if (!device_property_get_ex(child, PROPERTY_BLOCK_SIZE,
699 &property_result, NULL, &source)) {
700 g_warning("Error getting BLOCK_SIZE from %s: %s",
701 child->device_name, device_error_or_status(child));
705 /* if the block size has been set explicitly, then we need to use that blocksize;
706 * otherwise (even if it was DETECTED), override it. */
707 if (source == PROPERTY_SOURCE_USER) {
708 child_min = child_max = g_value_get_int(&property_result);
710 if (!device_property_get(child, PROPERTY_MIN_BLOCK_SIZE,
712 g_warning("Error getting MIN_BLOCK_SIZE from %s: %s",
713 child->device_name, device_error_or_status(child));
716 child_min = g_value_get_uint(&property_result);
718 if (!device_property_get(child, PROPERTY_MAX_BLOCK_SIZE,
720 g_warning("Error getting MAX_BLOCK_SIZE from %s: %s",
721 child->device_name, device_error_or_status(child));
724 child_max = g_value_get_uint(&property_result);
726 if (child_min == 0 || child_max == 0 || (child_min > child_max)) {
727 g_warning("Invalid min, max block sizes from %s", child->device_name);
733 min = MAX(min, child_min);
734 max = MIN(max, child_max);
738 device_set_error((Device*)self,
739 stralloc(_("Could not find any child devices' block size ranges")),
740 DEVICE_STATUS_DEVICE_ERROR);
745 device_set_error((Device*)self,
746 stralloc(_("No block size is acceptable to all child devices")),
747 DEVICE_STATUS_DEVICE_ERROR);
751 /* Now pick a number. If 32k is in range, we use that; otherwise, we use
752 * the nearest acceptable size. */
753 result = CLAMP(32768, min, max);
757 find_simple_params(self, NULL, &data_children);
758 *rait_size = result * data_children;
764 /* Set BLOCK_SIZE on all children */
766 set_block_size_on_children(RaitDevice *self, gsize child_block_size)
770 PropertySource source;
772 bzero(&val, sizeof(val));
774 g_assert(child_block_size < INT_MAX);
775 g_value_init(&val, G_TYPE_INT);
776 g_value_set_int(&val, (gint)child_block_size);
778 for (i = 0; i < self->private->children->len; i ++) {
780 GValue property_result;
782 bzero(&property_result, sizeof(property_result));
784 if ((signed)i == self->private->failed)
787 child = g_ptr_array_index(self->private->children, i);
789 /* first, make sure the block size is at its default, or is already
791 if (device_property_get_ex(child, PROPERTY_BLOCK_SIZE,
792 &property_result, NULL, &source)) {
793 gsize from_child = g_value_get_int(&property_result);
794 if (source != PROPERTY_SOURCE_DEFAULT
795 && from_child != child_block_size) {
796 device_set_error((Device *)self,
797 vstrallocf(_("Child device %s already has its block size set to %zd, not %zd"),
798 child->device_name, from_child, child_block_size),
799 DEVICE_STATUS_DEVICE_ERROR);
803 /* failing to get the block size isn't necessarily fatal.. */
804 g_warning("Error getting BLOCK_SIZE from %s: %s",
805 child->device_name, device_error_or_status(child));
807 g_value_unset(&property_result);
809 if (!device_property_set(child, PROPERTY_BLOCK_SIZE, &val)) {
810 device_set_error((Device *)self,
811 vstrallocf(_("Error setting block size on %s"), child->device_name),
812 DEVICE_STATUS_DEVICE_ERROR);
820 /* The time for users to specify block sizes has ended; set this device's
821 * block-size attributes for easy access by other RAIT functions. Returns
822 * FALSE on error, with the device's error status already set. */
824 fix_block_size(RaitDevice *self)
826 Device *dself = (Device *)self;
827 gsize my_block_size, child_block_size;
829 if (dself->block_size_source == PROPERTY_SOURCE_DEFAULT) {
830 child_block_size = calculate_block_size_from_children(self, &my_block_size);
831 if (child_block_size == 0)
834 self->private->child_block_size = child_block_size;
835 dself->block_size = my_block_size;
836 dself->block_size_surety = PROPERTY_SURETY_GOOD;
837 dself->block_size_source = PROPERTY_SOURCE_DETECTED;
841 find_simple_params(self, NULL, &data_children);
842 g_assert((dself->block_size % data_children) == 0);
843 child_block_size = dself->block_size / data_children;
846 /* now tell the children we mean it */
847 if (!set_block_size_on_children(self, child_block_size))
853 /* This structure contains common fields for many operations. Not all
854 operations use all fields, however. */
856 gpointer result; /* May be a pointer; may be an integer or boolean
857 stored with GINT_TO_POINTER. */
858 Device * child; /* The device in question. Used by all
860 guint child_index; /* For recoverable operations (read-related
861 operations), this field provides the number
862 of this child in the self->private->children
866 typedef gboolean (*BooleanExtractor)(gpointer data);
868 /* A BooleanExtractor */
869 static gboolean extract_boolean_generic_op(gpointer data) {
870 GenericOp * op = data;
871 return GPOINTER_TO_INT(op->result);
874 /* A BooleanExtractor */
875 static gboolean extract_boolean_pointer_op(gpointer data) {
876 GenericOp * op = data;
877 return op->result != NULL;
880 /* Does the equivalent of this perl command:
881 ! (first { !extractor($_) } @_
882 That is, calls extractor on each element of the array, and returns
883 TRUE if and only if all calls to extractor return TRUE. This function
884 stops as soon as an extractor returns false, so it's best if extractor
885 functions have no side effects.
887 static gboolean g_ptr_array_and(GPtrArray * array,
888 BooleanExtractor extractor) {
890 if (array == NULL || array->len <= 0)
893 for (i = 0; i < array->len; i ++) {
894 if (!extractor(g_ptr_array_index(array, i)))
901 /* Takes a RaitDevice, and makes a GPtrArray of GenericOp. */
902 static GPtrArray * make_generic_boolean_op_array(RaitDevice* self) {
906 rval = g_ptr_array_sized_new(self->private->children->len);
907 for (i = 0; i < self->private->children->len; i ++) {
910 if ((signed)i == self->private->failed) {
914 op = g_new(GenericOp, 1);
915 op->child = g_ptr_array_index(self->private->children, i);
917 g_ptr_array_add(rval, op);
923 /* Takes a GPtrArray of GenericOp, and a BooleanExtractor, and does
924 all the proper handling for the result of operations that allow
925 device isolation. Returns FALSE only if an unrecoverable error
927 static gboolean g_ptr_array_union_robust(RaitDevice * self, GPtrArray * ops,
928 BooleanExtractor extractor) {
933 /* We found one or more failed elements. See which elements failed, and
935 for (i = 0; i < ops->len; i ++) {
936 GenericOp * op = g_ptr_array_index(ops, i);
937 if (!extractor(op)) {
938 self->private->failed = op->child_index;
939 g_warning("RAIT array %s isolated device %s: %s",
940 DEVICE(self)->device_name,
941 op->child->device_name,
942 device_error(op->child));
948 /* no failures? great! */
952 /* a single failure in COMPLETE just puts us in DEGRADED mode */
953 if (self->private->status == RAIT_STATUS_COMPLETE && nfailed == 1) {
954 self->private->status = RAIT_STATUS_DEGRADED;
955 self->private->failed = lastfailed;
956 g_warning("RAIT array %s DEGRADED", DEVICE(self)->device_name);
959 self->private->status = RAIT_STATUS_FAILED;
960 g_warning("RAIT array %s FAILED", DEVICE(self)->device_name);
968 char * device_name; /* IN */
969 Device * result; /* OUT */
973 static void device_open_do_op(gpointer data,
974 gpointer user_data G_GNUC_UNUSED) {
975 OpenDeviceOp * op = data;
977 if (strcmp(op->device_name, "ERROR") == 0 ||
978 strcmp(op->device_name, "MISSING") == 0 ||
979 strcmp(op->device_name, "DEGRADED") == 0) {
980 g_warning("RAIT device %s contains a missing element, attempting "
981 "degraded mode.\n", op->rait_name);
984 op->result = device_open(op->device_name);
988 /* Returns TRUE if and only if the volume label and time are equal. */
989 static gboolean compare_volume_results(Device * a, Device * b) {
990 return (0 == compare_possibly_null_strings(a->volume_time, b->volume_time)
991 && 0 == compare_possibly_null_strings(a->volume_label, b->volume_label));
994 /* Stickes new_message at the end of *old_message; frees new_message and
995 * may change *old_message. */
996 static void append_message(char ** old_message, char * new_message) {
998 if (*old_message == NULL || **old_message == '\0') {
1001 rval = g_strdup_printf("%s; %s", *old_message, new_message);
1002 amfree(new_message);
1004 amfree(*old_message);
1005 *old_message = rval;
1009 rait_device_open_device (Device * dself, char * device_name,
1010 char * device_type G_GNUC_UNUSED, char * device_node) {
1011 GPtrArray *device_names;
1012 GPtrArray * device_open_ops;
1015 char *failure_errmsgs;
1016 DeviceStatusFlags failure_flags;
1019 self = RAIT_DEVICE(dself);
1021 device_names = parse_device_name(device_node);
1023 if (device_names == NULL) {
1024 device_set_error(dself,
1025 vstrallocf(_("Invalid RAIT device name '%s'"), device_name),
1026 DEVICE_STATUS_DEVICE_ERROR);
1030 /* Open devices in a separate thread, in case they have to rewind etc. */
1031 device_open_ops = g_ptr_array_new();
1033 for (i = 0; i < device_names->len; i++) {
1035 char *name = g_ptr_array_index(device_names, i);
1037 op = g_new(OpenDeviceOp, 1);
1038 op->device_name = name;
1041 op->rait_name = device_name;
1042 g_ptr_array_add(device_open_ops, op);
1045 g_ptr_array_free(device_names, TRUE);
1046 do_rait_child_ops(self, device_open_do_op, device_open_ops);
1049 failure_errmsgs = NULL;
1052 /* Check results of opening devices. */
1053 for (i = 0; i < device_open_ops->len; i ++) {
1054 OpenDeviceOp *op = g_ptr_array_index(device_open_ops, i);
1056 if (op->result != NULL &&
1057 op->result->status == DEVICE_STATUS_SUCCESS) {
1058 g_ptr_array_add(self->private->children, op->result);
1060 char * this_failure_errmsg =
1061 g_strdup_printf("%s: %s", op->device_name,
1062 device_error_or_status(op->result));
1063 DeviceStatusFlags status =
1064 op->result == NULL ?
1065 DEVICE_STATUS_DEVICE_ERROR : op->result->status;
1066 append_message(&failure_errmsgs,
1067 strdup(this_failure_errmsg));
1068 failure_flags |= status;
1069 if (self->private->status == RAIT_STATUS_COMPLETE) {
1070 /* The first failure just puts us in degraded mode. */
1072 device_name, this_failure_errmsg);
1073 g_warning("%s: %s failed, entering degraded mode.",
1074 device_name, op->device_name);
1075 g_ptr_array_add(self->private->children, op->result);
1076 self->private->status = RAIT_STATUS_DEGRADED;
1077 self->private->failed = i;
1079 /* The second and further failures are fatal. */
1083 amfree(op->device_name);
1086 g_ptr_array_free_full(device_open_ops);
1089 self->private->status = RAIT_STATUS_FAILED;
1090 device_set_error(dself, failure_errmsgs, failure_flags);
1095 if (parent_class->open_device) {
1096 parent_class->open_device(dself, device_name, device_type, device_node);
1102 static void read_label_do_op(gpointer data,
1103 gpointer user_data G_GNUC_UNUSED) {
1104 GenericOp * op = data;
1105 op->result = GINT_TO_POINTER(device_read_label(op->child));
1108 static DeviceStatusFlags rait_device_read_label(Device * dself) {
1111 DeviceStatusFlags failed_result = 0;
1112 char *failed_errmsg = NULL;
1114 Device * first_success = NULL;
1116 self = RAIT_DEVICE(dself);
1118 amfree(dself->volume_time);
1119 amfree(dself->volume_label);
1120 amfree(dself->volume_header);
1122 if (rait_device_in_error(self))
1123 return dself->status | DEVICE_STATUS_DEVICE_ERROR;
1125 /* nail down our block size, if we haven't already */
1126 if (!fix_block_size(self))
1129 ops = make_generic_boolean_op_array(self);
1131 do_rait_child_ops(self, read_label_do_op, ops);
1133 for (i = 0; i < ops->len; i ++) {
1134 GenericOp * op = g_ptr_array_index(ops, i);
1135 DeviceStatusFlags result = GPOINTER_TO_INT(op->result);
1136 if (op->result == DEVICE_STATUS_SUCCESS) {
1137 if (first_success == NULL) {
1138 /* This is the first successful device. */
1139 first_success = op->child;
1140 } else if (!compare_volume_results(first_success, op->child)) {
1141 /* Doesn't match. :-( */
1142 failed_errmsg = vstrallocf("Inconsistent volume labels/datestamps: "
1143 "Got %s/%s on %s against %s/%s on %s.",
1144 first_success->volume_label,
1145 first_success->volume_time,
1146 first_success->device_name,
1147 op->child->volume_label,
1148 op->child->volume_time,
1149 op->child->device_name);
1150 g_warning("%s", failed_errmsg);
1151 failed_result |= DEVICE_STATUS_VOLUME_ERROR;
1154 failed_result |= result;
1158 if (failed_result != DEVICE_STATUS_SUCCESS) {
1159 /* We had multiple failures or an inconsistency. */
1160 device_set_error(dself, failed_errmsg, failed_result);
1162 /* Everything peachy. */
1163 amfree(failed_errmsg);
1165 g_assert(first_success != NULL);
1166 if (first_success->volume_label != NULL) {
1167 dself->volume_label = g_strdup(first_success->volume_label);
1169 if (first_success->volume_time != NULL) {
1170 dself->volume_time = g_strdup(first_success->volume_time);
1172 if (first_success->volume_header != NULL) {
1173 dself->volume_header = dumpfile_copy(first_success->volume_header);
1177 g_ptr_array_free_full(ops);
1179 return dself->status;
1184 DeviceAccessMode mode; /* IN */
1185 char * label; /* IN */
1186 char * timestamp; /* IN */
1190 static void start_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1192 StartOp * param = data;
1194 klass = DEVICE_GET_CLASS(param->base.child);
1196 param->base.result =
1197 GINT_TO_POINTER((klass->start)(param->base.child,
1198 param->mode, param->label,
1201 param->base.result = FALSE;
1206 rait_device_configure(Device * dself, gboolean use_global_config)
1208 RaitDevice *self = RAIT_DEVICE(dself);
1211 for (i = 0; i < self->private->children->len; i ++) {
1214 if ((signed)i == self->private->failed)
1217 child = g_ptr_array_index(self->private->children, i);
1218 /* unconditionally configure the child without the global
1220 if (!device_configure(child, FALSE))
1224 if (parent_class->configure) {
1225 return parent_class->configure(dself, use_global_config);
1232 rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
1238 DeviceStatusFlags total_status;
1239 char *failure_errmsgs = NULL;
1240 char * label_from_device = NULL;
1242 self = RAIT_DEVICE(dself);
1244 if (rait_device_in_error(self)) return FALSE;
1246 /* No starting in degraded mode. */
1247 if (self->private->status != RAIT_STATUS_COMPLETE &&
1248 (mode == ACCESS_WRITE || mode == ACCESS_APPEND)) {
1249 device_set_error(dself,
1250 g_strdup_printf(_("RAIT device %s is read-only "
1251 "because it is in degraded mode.\n"),
1252 dself->device_name),
1253 DEVICE_STATUS_DEVICE_ERROR);
1257 /* nail down our block size, if we haven't already */
1258 if (!fix_block_size(self))
1261 dself->access_mode = mode;
1262 dself->in_file = FALSE;
1264 ops = g_ptr_array_sized_new(self->private->children->len);
1265 for (i = 0; i < self->private->children->len; i ++) {
1268 if ((signed)i == self->private->failed) {
1272 op = g_new(StartOp, 1);
1273 op->base.child = g_ptr_array_index(self->private->children, i);
1275 op->label = g_strdup(label);
1276 op->timestamp = g_strdup(timestamp);
1277 g_ptr_array_add(ops, op);
1280 do_rait_child_ops(self, start_do_op, ops);
1282 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1284 /* Check results of starting devices; this is mostly about the
1285 * VOLUME_UNLABELED flag. */
1287 for (i = 0; i < ops->len; i ++) {
1288 StartOp * op = g_ptr_array_index(ops, i);
1289 Device *child = op->base.child;
1291 total_status |= child->status;
1292 if (child->status != DEVICE_STATUS_SUCCESS) {
1293 /* record the error message and move on. */
1294 append_message(&failure_errmsgs,
1295 g_strdup_printf("%s: %s",
1297 device_error_or_status(child)));
1299 if (child->volume_label != NULL && child->volume_time != NULL) {
1300 if (dself->volume_label != NULL && dself->volume_time != NULL) {
1301 if (strcmp(child->volume_label, dself->volume_label) != 0 ||
1302 strcmp(child->volume_time, dself->volume_time) != 0) {
1303 /* Mismatch! (Two devices provided different labels) */
1304 char * this_message =
1305 g_strdup_printf("%s: Label (%s/%s) is different "
1306 "from label (%s/%s) found at "
1309 child->volume_label,
1311 dself->volume_label,
1314 append_message(&failure_errmsgs, this_message);
1315 total_status |= DEVICE_STATUS_DEVICE_ERROR;
1318 /* First device with a volume. */
1319 dself->volume_label = g_strdup(child->volume_label);
1320 dself->volume_time = g_strdup(child->volume_time);
1321 label_from_device = g_strdup(child->device_name);
1324 /* Device problem, it says it succeeded but sets no label? */
1325 char * this_message =
1326 g_strdup_printf("%s: Says label read, but no volume "
1327 "label found.", child->device_name);
1328 append_message(&failure_errmsgs, this_message);
1329 total_status |= DEVICE_STATUS_DEVICE_ERROR;
1334 amfree(label_from_device);
1335 g_ptr_array_free_full(ops);
1337 dself->status = total_status;
1340 device_set_error(dself, failure_errmsgs, total_status);
1344 amfree(failure_errmsgs);
1350 dumpfile_t * info; /* IN */
1355 static void start_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1356 StartFileOp * op = data;
1357 op->base.result = GINT_TO_POINTER(device_start_file(op->base.child,
1359 op->fileno = op->base.child->file;
1360 if (op->fileno < 1) {
1361 op->base.result = FALSE;
1366 rait_device_start_file (Device * dself, dumpfile_t * info) {
1371 int actual_file = -1;
1373 self = RAIT_DEVICE(dself);
1375 if (rait_device_in_error(self)) return FALSE;
1376 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1378 ops = g_ptr_array_sized_new(self->private->children->len);
1379 for (i = 0; i < self->private->children->len; i ++) {
1381 op = g_new(StartFileOp, 1);
1382 op->base.child = g_ptr_array_index(self->private->children, i);
1383 /* each child gets its own copy of the header, to munge as it
1384 * likes (setting blocksize, at least) */
1385 op->info = dumpfile_copy(info);
1386 g_ptr_array_add(ops, op);
1389 do_rait_child_ops(self, start_file_do_op, ops);
1391 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1393 for (i = 0; i < self->private->children->len && success; i ++) {
1394 StartFileOp * op = g_ptr_array_index(ops, i);
1395 if (!op->base.result)
1397 g_assert(op->fileno >= 1);
1398 if (actual_file < 1) {
1399 actual_file = op->fileno;
1401 if (actual_file != op->fileno) {
1402 /* File number mismatch! Aah, my hair is on fire! */
1403 device_set_error(dself,
1404 g_strdup_printf("File number mismatch in "
1405 "rait_device_start_file(): "
1406 "Child %s reported file number "
1407 "%d, another child reported "
1409 op->base.child->device_name,
1410 op->fileno, actual_file),
1411 DEVICE_STATUS_DEVICE_ERROR);
1413 op->base.result = FALSE;
1417 for (i = 0; i < ops->len && success; i ++) {
1418 StartFileOp * op = g_ptr_array_index(ops, i);
1419 if (op->info) dumpfile_free(op->info);
1421 g_ptr_array_free_full(ops);
1424 if (!device_in_error(dself)) {
1425 device_set_error(dself, stralloc("One or more devices "
1426 "failed to start_file"),
1427 DEVICE_STATUS_DEVICE_ERROR);
1432 dself->in_file = TRUE;
1433 g_assert(actual_file >= 1);
1434 dself->file = actual_file;
1439 static void find_simple_params(RaitDevice * self,
1440 guint * num_children,
1441 guint * data_children) {
1444 num = self->private->children->len;
1449 if (num_children != NULL)
1450 *num_children = num;
1451 if (data_children != NULL)
1452 *data_children = data;
1457 guint size; /* IN */
1458 gpointer data; /* IN */
1459 gboolean data_needs_free; /* bookkeeping */
1463 static void write_block_do_op(gpointer data,
1464 gpointer user_data G_GNUC_UNUSED) {
1465 WriteBlockOp * op = data;
1468 GINT_TO_POINTER(device_write_block(op->base.child, op->size, op->data));
1471 /* Parity block generation. Performance of this function can be improved
1472 considerably by using larger-sized integers or
1473 assembly-coded vector instructions. Parameters are:
1474 % data - All data chunks in series (chunk_size * num_chunks bytes)
1475 % parity - Allocated space for parity block (chunk_size bytes)
1477 static void make_parity_block(char * data, char * parity,
1478 guint chunk_size, guint num_chunks) {
1480 bzero(parity, chunk_size);
1481 for (i = 0; i < num_chunks - 1; i ++) {
1483 for (j = 0; j < chunk_size; j ++) {
1484 parity[j] ^= data[chunk_size*i + j];
1489 /* Does the same thing as make_parity_block, but instead of using a
1490 single memory chunk holding all chunks, it takes a GPtrArray of
1492 static void make_parity_block_extents(GPtrArray * data, char * parity,
1495 bzero(parity, chunk_size);
1496 for (i = 0; i < data->len; i ++) {
1499 data_chunk = g_ptr_array_index(data, i);
1500 for (j = 0; j < chunk_size; j ++) {
1501 parity[j] ^= data_chunk[j];
1506 /* Does the parity creation algorithm. Allocates and returns a single
1507 device block from a larger RAIT block. chunks and chunk are 1-indexed. */
1508 static char * extract_data_block(char * data, guint size,
1509 guint chunks, guint chunk) {
1513 g_assert(chunks > 0 && chunk > 0 && chunk <= chunks);
1514 g_assert(data != NULL);
1515 g_assert(size > 0 && size % (chunks - 1) == 0);
1517 chunk_size = size / (chunks - 1);
1518 rval = g_malloc(chunk_size);
1519 if (chunks != chunk) {
1521 memcpy(rval, data + chunk_size * (chunk - 1), chunk_size);
1523 make_parity_block(data, rval, chunk_size, chunks);
1530 rait_device_write_block (Device * dself, guint size, gpointer data) {
1534 guint data_children, num_children;
1535 gsize blocksize = dself->block_size;
1537 gboolean last_block = (size < blocksize);
1539 self = RAIT_DEVICE(dself);
1541 if (rait_device_in_error(self)) return FALSE;
1542 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1544 find_simple_params(RAIT_DEVICE(self), &num_children, &data_children);
1545 num_children = self->private->children->len;
1546 if (num_children != 1)
1547 data_children = num_children - 1;
1549 data_children = num_children;
1551 g_assert(size % data_children == 0 || last_block);
1553 /* zero out to the end of a short block -- tape devices only write
1558 new_data = g_malloc(blocksize);
1559 memcpy(new_data, data, size);
1560 bzero(new_data + size, blocksize - size);
1566 ops = g_ptr_array_sized_new(num_children);
1567 for (i = 0; i < self->private->children->len; i ++) {
1569 op = g_malloc(sizeof(*op));
1570 op->base.child = g_ptr_array_index(self->private->children, i);
1571 op->size = size / data_children;
1572 if (num_children <= 2) {
1574 op->data_needs_free = FALSE;
1576 op->data_needs_free = TRUE;
1577 op->data = extract_data_block(data, size, num_children, i + 1);
1579 g_ptr_array_add(ops, op);
1582 do_rait_child_ops(self, write_block_do_op, ops);
1584 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1586 for (i = 0; i < self->private->children->len; i ++) {
1587 WriteBlockOp * op = g_ptr_array_index(ops, i);
1588 if (op->data_needs_free)
1596 g_ptr_array_free_full(ops);
1599 /* TODO be more specific here */
1600 /* TODO: handle EOF here -- if one or more (or two or more??)
1601 * children have is_eof* set, then reflect that in our error
1602 * status, and finish_file all of the non-EOF children. What's
1603 * more fun is when one device fails and must be isolated at
1604 * the same time another hits EOF. */
1605 device_set_error(dself,
1606 stralloc("One or more devices failed to write_block"),
1607 DEVICE_STATUS_DEVICE_ERROR);
1617 static void finish_file_do_op(gpointer data,
1618 gpointer user_data G_GNUC_UNUSED) {
1619 GenericOp * op = data;
1621 op->result = GINT_TO_POINTER(device_finish_file(op->child));
1628 rait_device_finish_file (Device * dself) {
1631 RaitDevice * self = RAIT_DEVICE(dself);
1633 g_assert(self != NULL);
1634 if (rait_device_in_error(dself)) return FALSE;
1635 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1637 ops = make_generic_boolean_op_array(self);
1639 do_rait_child_ops(self, finish_file_do_op, ops);
1641 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1643 g_ptr_array_free_full(ops);
1646 /* TODO: be more specific here */
1647 device_set_error(dself,
1648 g_strdup("One or more devices failed to finish_file"),
1649 DEVICE_STATUS_DEVICE_ERROR);
1653 dself->in_file = FALSE;
1659 guint requested_file; /* IN */
1660 guint actual_file; /* OUT */
1664 static void seek_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1665 SeekFileOp * op = data;
1666 op->base.result = device_seek_file(op->base.child, op->requested_file);
1667 op->actual_file = op->base.child->file;
1671 rait_device_seek_file (Device * dself, guint file) {
1676 RaitDevice * self = RAIT_DEVICE(dself);
1677 guint actual_file = 0;
1678 gboolean in_file = FALSE;
1680 if (rait_device_in_error(self)) return NULL;
1682 dself->in_file = FALSE;
1683 dself->is_eof = FALSE;
1686 ops = g_ptr_array_sized_new(self->private->children->len);
1687 for (i = 0; i < self->private->children->len; i ++) {
1689 if ((int)i == self->private->failed)
1690 continue; /* This device is broken. */
1691 op = g_new(SeekFileOp, 1);
1692 op->base.child = g_ptr_array_index(self->private->children, i);
1693 op->base.child_index = i;
1694 op->requested_file = file;
1695 g_ptr_array_add(ops, op);
1698 do_rait_child_ops(self, seek_file_do_op, ops);
1700 /* This checks for NULL values, but we still have to check for
1701 consistant headers. */
1702 success = g_ptr_array_union_robust(RAIT_DEVICE(self),
1703 ops, extract_boolean_pointer_op);
1706 for (i = 0; i < ops->len; i ++) {
1707 SeekFileOp * this_op;
1708 dumpfile_t * this_result;
1709 guint this_actual_file;
1710 gboolean this_in_file;
1712 this_op = (SeekFileOp*)g_ptr_array_index(ops, i);
1714 if ((signed)this_op->base.child_index == self->private->failed)
1717 this_result = this_op->base.result;
1718 this_actual_file = this_op->actual_file;
1719 this_in_file = this_op->base.child->in_file;
1723 actual_file = this_actual_file;
1724 in_file = this_in_file;
1726 if (headers_are_equal(rval, this_result) &&
1727 actual_file == this_actual_file &&
1728 in_file == this_in_file) {
1737 g_ptr_array_free_full(ops);
1741 /* TODO: be more specific here */
1742 device_set_error(dself,
1743 g_strdup("One or more devices failed to seek_file"),
1744 DEVICE_STATUS_DEVICE_ERROR);
1748 /* update our state */
1749 dself->in_file = in_file;
1750 dself->file = actual_file;
1757 guint64 block; /* IN */
1761 static void seek_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1762 SeekBlockOp * op = data;
1764 GINT_TO_POINTER(device_seek_block(op->base.child, op->block));
1768 rait_device_seek_block (Device * dself, guint64 block) {
1773 RaitDevice * self = RAIT_DEVICE(dself);
1775 if (rait_device_in_error(self)) return FALSE;
1777 ops = g_ptr_array_sized_new(self->private->children->len);
1778 for (i = 0; i < self->private->children->len; i ++) {
1780 if ((int)i == self->private->failed)
1781 continue; /* This device is broken. */
1782 op = g_new(SeekBlockOp, 1);
1783 op->base.child = g_ptr_array_index(self->private->children, i);
1784 op->base.child_index = i;
1786 g_ptr_array_add(ops, op);
1789 do_rait_child_ops(self, seek_block_do_op, ops);
1791 success = g_ptr_array_union_robust(RAIT_DEVICE(self),
1792 ops, extract_boolean_generic_op);
1794 g_ptr_array_free_full(ops);
1797 /* TODO: be more specific here */
1798 device_set_error(dself,
1799 stralloc("One or more devices failed to seek_block"),
1800 DEVICE_STATUS_DEVICE_ERROR);
1804 dself->block = block;
1810 gpointer buffer; /* IN */
1811 int read_size; /* IN/OUT -- note not a pointer */
1812 int desired_read_size; /* bookkeeping */
1816 static void read_block_do_op(gpointer data,
1817 gpointer user_data G_GNUC_UNUSED) {
1818 ReadBlockOp * op = data;
1820 GINT_TO_POINTER(device_read_block(op->base.child, op->buffer,
1822 if (op->read_size > op->desired_read_size) {
1823 g_warning("child device %s tried to return an oversized block, which the RAIT device does not support",
1824 op->base.child->device_name);
1828 /* A BooleanExtractor. This one checks for a successful read. */
1829 static gboolean extract_boolean_read_block_op_data(gpointer data) {
1830 ReadBlockOp * op = data;
1831 return GPOINTER_TO_INT(op->base.result) == op->desired_read_size;
1834 /* A BooleanExtractor. This one checks for EOF. */
1835 static gboolean extract_boolean_read_block_op_eof(gpointer data) {
1836 ReadBlockOp * op = data;
1837 return op->base.child->is_eof;
1840 /* Counts the number of elements in an array matching a given proposition. */
1841 static int g_ptr_array_count(GPtrArray * array, BooleanExtractor filter) {
1845 for (i = 0; i < array->len ; i++) {
1846 if (filter(g_ptr_array_index(array, i)))
1852 static gboolean raid_block_reconstruction(RaitDevice * self, GPtrArray * ops,
1853 gpointer buf, size_t bufsize) {
1854 guint num_children, data_children;
1856 gsize child_blocksize;
1859 gpointer parity_block = NULL;
1864 blocksize = DEVICE(self)->block_size;
1865 find_simple_params(self, &num_children, &data_children);
1867 if (num_children > 1)
1868 parity_child = num_children - 1;
1872 child_blocksize = blocksize / data_children;
1874 for (i = 0; i < ops->len; i ++) {
1875 ReadBlockOp * op = g_ptr_array_index(ops, i);
1876 if (!extract_boolean_read_block_op_data(op))
1878 if ((int)(op->base.child_index) == parity_child) {
1879 parity_block = op->buffer;
1881 g_assert(child_blocksize * (op->base.child_index+1) <= bufsize);
1882 memcpy((char *)buf + child_blocksize * op->base.child_index, op->buffer,
1886 g_assert(parity_block != NULL); /* should have found parity_child */
1888 if (self->private->status == RAIT_STATUS_COMPLETE) {
1889 if (num_children >= 2) {
1890 /* Verify the parity block. This code is inefficient but
1891 does the job for the 2-device case, too. */
1892 gpointer constructed_parity;
1893 GPtrArray * data_extents;
1895 constructed_parity = g_malloc(child_blocksize);
1896 data_extents = g_ptr_array_sized_new(data_children);
1897 for (i = 0; i < data_children; i ++) {
1898 ReadBlockOp * op = g_ptr_array_index(ops, i);
1899 g_assert(extract_boolean_read_block_op_data(op));
1900 if ((int)op->base.child_index == parity_child)
1902 g_ptr_array_add(data_extents, op->buffer);
1904 make_parity_block_extents(data_extents, constructed_parity,
1907 if (0 != memcmp(parity_block, constructed_parity,
1909 device_set_error(DEVICE(self),
1910 stralloc(_("RAIT is inconsistent: Parity block did not match data blocks.")),
1911 DEVICE_STATUS_DEVICE_ERROR);
1912 /* TODO: can't we just isolate the device in this case? */
1915 g_ptr_array_free(data_extents, TRUE);
1916 amfree(constructed_parity);
1917 } else { /* do nothing. */ }
1918 } else if (self->private->status == RAIT_STATUS_DEGRADED) {
1919 g_assert(self->private->failed >= 0 && self->private->failed < (int)num_children);
1920 /* We are in degraded mode. What's missing? */
1921 if (self->private->failed == parity_child) {
1923 } else if (num_children >= 2) {
1924 /* Reconstruct failed block from parity block. */
1925 GPtrArray * data_extents = g_ptr_array_new();
1927 for (i = 0; i < data_children; i ++) {
1928 ReadBlockOp * op = g_ptr_array_index(ops, i);
1929 if (!extract_boolean_read_block_op_data(op))
1931 g_ptr_array_add(data_extents, op->buffer);
1934 /* Conveniently, the reconstruction is the same procedure
1935 as the parity generation. This even works if there is
1936 only one remaining device! */
1937 make_parity_block_extents(data_extents,
1938 (char *)buf + (child_blocksize *
1939 self->private->failed),
1942 /* The array members belong to our ops argument. */
1943 g_ptr_array_free(data_extents, TRUE);
1945 g_assert_not_reached();
1948 /* device is already in FAILED state -- we shouldn't even be here */
1955 rait_device_read_block (Device * dself, gpointer buf, int * size) {
1959 guint num_children, data_children;
1960 gsize blocksize = dself->block_size;
1961 gsize child_blocksize;
1963 RaitDevice * self = RAIT_DEVICE(dself);
1965 if (rait_device_in_error(self)) return -1;
1967 find_simple_params(self, &num_children, &data_children);
1969 /* tell caller they haven't given us a big enough buffer */
1970 if (blocksize > (gsize)*size) {
1971 g_assert(blocksize < INT_MAX);
1972 *size = (int)blocksize;
1976 g_assert(blocksize % data_children == 0); /* see find_block_size */
1977 child_blocksize = blocksize / data_children;
1979 ops = g_ptr_array_sized_new(num_children);
1980 for (i = 0; i < num_children; i ++) {
1982 if ((int)i == self->private->failed)
1983 continue; /* This device is broken. */
1984 op = g_new(ReadBlockOp, 1);
1985 op->base.child = g_ptr_array_index(self->private->children, i);
1986 op->base.child_index = i;
1987 op->buffer = g_malloc(child_blocksize);
1988 op->desired_read_size = op->read_size = child_blocksize;
1989 g_ptr_array_add(ops, op);
1992 do_rait_child_ops(self, read_block_do_op, ops);
1994 if (g_ptr_array_count(ops, extract_boolean_read_block_op_data)) {
1995 if (!g_ptr_array_union_robust(RAIT_DEVICE(self),
1997 extract_boolean_read_block_op_data)) {
1998 /* TODO: be more specific */
1999 device_set_error(dself,
2000 stralloc(_("Error occurred combining blocks from child devices")),
2001 DEVICE_STATUS_DEVICE_ERROR);
2004 /* raid_block_reconstruction sets the error status if necessary */
2005 success = raid_block_reconstruction(RAIT_DEVICE(self),
2006 ops, buf, (size_t)*size);
2010 if (g_ptr_array_union_robust(RAIT_DEVICE(self),
2012 extract_boolean_read_block_op_eof)) {
2013 device_set_error(dself,
2015 DEVICE_STATUS_SUCCESS);
2016 dself->is_eof = TRUE;
2017 dself->in_file = FALSE;
2019 device_set_error(dself,
2020 stralloc(_("All child devices failed to read, but not all are at eof")),
2021 DEVICE_STATUS_DEVICE_ERROR);
2025 for (i = 0; i < ops->len; i ++) {
2026 ReadBlockOp * op = g_ptr_array_index(ops, i);
2029 g_ptr_array_free_full(ops);
2040 /* property utility functions */
2044 DevicePropertyId id; /* IN */
2045 GValue value; /* IN/OUT */
2046 PropertySurety surety; /* IN (for set) */
2047 PropertySource source; /* IN (for set) */
2050 /* Creates a GPtrArray of PropertyOf for a get or set operation. */
2051 static GPtrArray * make_property_op_array(RaitDevice * self,
2052 DevicePropertyId id,
2054 PropertySurety surety,
2055 PropertySource source) {
2058 ops = g_ptr_array_sized_new(self->private->children->len);
2059 for (i = 0; i < self->private->children->len; i ++) {
2062 if ((signed)i == self->private->failed) {
2066 op = g_new(PropertyOp, 1);
2067 op->base.child = g_ptr_array_index(self->private->children, i);
2069 bzero(&(op->value), sizeof(op->value));
2070 if (value != NULL) {
2071 g_value_unset_copy(value, &(op->value));
2073 op->surety = surety;
2074 op->source = source;
2075 g_ptr_array_add(ops, op);
2082 static void property_get_do_op(gpointer data,
2083 gpointer user_data G_GNUC_UNUSED) {
2084 PropertyOp * op = data;
2086 bzero(&(op->value), sizeof(op->value));
2088 GINT_TO_POINTER(device_property_get(op->base.child, op->id,
2093 static void property_set_do_op(gpointer data,
2094 gpointer user_data G_GNUC_UNUSED) {
2095 PropertyOp * op = data;
2098 GINT_TO_POINTER(device_property_set_ex(op->base.child, op->id,
2099 &(op->value), op->surety,
2101 g_value_unset(&(op->value));
2104 /* PropertyGetFns and PropertySetFns */
2107 property_get_block_size_fn(Device *dself,
2108 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2109 PropertySurety *surety, PropertySource *source)
2111 RaitDevice *self = RAIT_DEVICE(dself);
2112 gsize my_block_size;
2114 if (dself->block_size_source != PROPERTY_SOURCE_DEFAULT) {
2115 my_block_size = dself->block_size;
2118 *surety = dself->block_size_surety;
2120 gsize child_block_size;
2121 child_block_size = calculate_block_size_from_children(self,
2123 if (child_block_size == 0)
2127 *surety = PROPERTY_SURETY_BAD; /* may still change */
2131 g_value_unset_init(val, G_TYPE_INT);
2132 g_assert(my_block_size < G_MAXINT); /* gsize -> gint */
2133 g_value_set_int(val, (gint)my_block_size);
2137 *source = dself->block_size_source;
2143 property_set_block_size_fn(Device *dself,
2144 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2145 PropertySurety surety, PropertySource source)
2147 RaitDevice *self = RAIT_DEVICE(dself);
2148 gint my_block_size = g_value_get_int(val);
2149 guint data_children;
2151 find_simple_params(self, NULL, &data_children);
2152 if ((my_block_size % data_children) != 0) {
2153 device_set_error(dself,
2154 vstrallocf(_("Block size must be a multiple of %d"), data_children),
2155 DEVICE_STATUS_DEVICE_ERROR);
2159 dself->block_size = my_block_size;
2160 dself->block_size_source = source;
2161 dself->block_size_surety = surety;
2163 if (!fix_block_size(self))
2170 property_get_canonical_name_fn(Device *dself,
2171 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2172 PropertySurety *surety, PropertySource *source)
2174 RaitDevice *self = RAIT_DEVICE(dself);
2175 char *canonical = child_device_names_to_rait_name(self);
2178 g_value_unset_init(val, G_TYPE_STRING);
2179 g_value_set_string(val, canonical);
2184 *surety = PROPERTY_SURETY_GOOD;
2187 *source = PROPERTY_SOURCE_DETECTED;
2193 property_get_concurrency_fn(Device *dself,
2194 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2195 PropertySurety *surety, PropertySource *source)
2197 RaitDevice *self = RAIT_DEVICE(dself);
2198 ConcurrencyParadigm result;
2203 ops = make_property_op_array(self, PROPERTY_CONCURRENCY, NULL, 0, 0);
2204 do_rait_child_ops(self, property_get_do_op, ops);
2206 /* find the most restrictive paradigm acceptable to all
2208 result = CONCURRENCY_PARADIGM_RANDOM_ACCESS;
2210 for (i = 0; i < ops->len; i ++) {
2211 ConcurrencyParadigm cur;
2212 PropertyOp * op = g_ptr_array_index(ops, i);
2214 if (!op->base.result
2215 || G_VALUE_TYPE(&(op->value)) != CONCURRENCY_PARADIGM_TYPE) {
2220 cur = g_value_get_enum(&(op->value));
2221 if (result == CONCURRENCY_PARADIGM_EXCLUSIVE ||
2222 cur == CONCURRENCY_PARADIGM_EXCLUSIVE) {
2223 result = CONCURRENCY_PARADIGM_EXCLUSIVE;
2224 } else if (result == CONCURRENCY_PARADIGM_SHARED_READ ||
2225 cur == CONCURRENCY_PARADIGM_SHARED_READ) {
2226 result = CONCURRENCY_PARADIGM_SHARED_READ;
2227 } else if (result == CONCURRENCY_PARADIGM_RANDOM_ACCESS &&
2228 cur == CONCURRENCY_PARADIGM_RANDOM_ACCESS) {
2229 result = CONCURRENCY_PARADIGM_RANDOM_ACCESS;
2236 g_ptr_array_free_full(ops);
2240 g_value_unset_init(val, CONCURRENCY_PARADIGM_TYPE);
2241 g_value_set_enum(val, result);
2245 *surety = PROPERTY_SURETY_GOOD;
2248 *source = PROPERTY_SOURCE_DETECTED;
2255 property_get_streaming_fn(Device *dself,
2256 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2257 PropertySurety *surety, PropertySource *source)
2259 RaitDevice *self = RAIT_DEVICE(dself);
2260 StreamingRequirement result;
2265 ops = make_property_op_array(self, PROPERTY_STREAMING, NULL, 0, 0);
2266 do_rait_child_ops(self, property_get_do_op, ops);
2268 /* combine the child streaming requirements, selecting the strongest
2269 * requirement of the bunch. */
2270 result = STREAMING_REQUIREMENT_NONE;
2272 for (i = 0; i < ops->len; i ++) {
2273 StreamingRequirement cur;
2274 PropertyOp * op = g_ptr_array_index(ops, i);
2276 if (!op->base.result
2277 || G_VALUE_TYPE(&(op->value)) != STREAMING_REQUIREMENT_TYPE) {
2282 cur = g_value_get_enum(&(op->value));
2283 if (result == STREAMING_REQUIREMENT_REQUIRED ||
2284 cur == STREAMING_REQUIREMENT_REQUIRED) {
2285 result = STREAMING_REQUIREMENT_REQUIRED;
2286 } else if (result == STREAMING_REQUIREMENT_DESIRED ||
2287 cur == STREAMING_REQUIREMENT_DESIRED) {
2288 result = STREAMING_REQUIREMENT_DESIRED;
2289 } else if (result == STREAMING_REQUIREMENT_NONE &&
2290 cur == STREAMING_REQUIREMENT_NONE) {
2291 result = STREAMING_REQUIREMENT_NONE;
2298 g_ptr_array_free_full(ops);
2302 g_value_unset_init(val, STREAMING_REQUIREMENT_TYPE);
2303 g_value_set_enum(val, result);
2307 *surety = PROPERTY_SURETY_GOOD;
2310 *source = PROPERTY_SOURCE_DETECTED;
2317 property_get_boolean_and_fn(Device *dself,
2318 DevicePropertyBase *base, GValue *val,
2319 PropertySurety *surety, PropertySource *source)
2321 RaitDevice *self = RAIT_DEVICE(dself);
2327 ops = make_property_op_array(self, base->ID, NULL, 0, 0);
2328 do_rait_child_ops(self, property_get_do_op, ops);
2330 /* combine the child values, applying a simple AND */
2333 for (i = 0; i < ops->len; i ++) {
2334 PropertyOp * op = g_ptr_array_index(ops, i);
2336 if (!op->base.result || !G_VALUE_HOLDS_BOOLEAN(&(op->value))) {
2341 if (!g_value_get_boolean(&(op->value))) {
2347 g_ptr_array_free_full(ops);
2351 g_value_unset_init(val, G_TYPE_BOOLEAN);
2352 g_value_set_boolean(val, result);
2356 *surety = PROPERTY_SURETY_GOOD;
2359 *source = PROPERTY_SOURCE_DETECTED;
2366 property_get_medium_access_type_fn(Device *dself,
2367 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2368 PropertySurety *surety, PropertySource *source)
2370 RaitDevice *self = RAIT_DEVICE(dself);
2371 MediaAccessMode result;
2376 ops = make_property_op_array(self, PROPERTY_MEDIUM_ACCESS_TYPE, NULL, 0, 0);
2377 do_rait_child_ops(self, property_get_do_op, ops);
2379 /* combine the modes as best we can */
2382 for (i = 0; i < ops->len; i ++) {
2383 MediaAccessMode cur;
2384 PropertyOp * op = g_ptr_array_index(ops, i);
2386 if (!op->base.result || G_VALUE_TYPE(&(op->value)) != MEDIA_ACCESS_MODE_TYPE) {
2391 cur = g_value_get_enum(&(op->value));
2395 } else if ((result == MEDIA_ACCESS_MODE_READ_ONLY &&
2396 cur == MEDIA_ACCESS_MODE_WRITE_ONLY) ||
2397 (result == MEDIA_ACCESS_MODE_WRITE_ONLY &&
2398 cur == MEDIA_ACCESS_MODE_READ_ONLY)) {
2399 /* Invalid combination; one device can only read, other
2403 } else if (result == MEDIA_ACCESS_MODE_READ_ONLY ||
2404 cur == MEDIA_ACCESS_MODE_READ_ONLY) {
2405 result = MEDIA_ACCESS_MODE_READ_ONLY;
2406 } else if (result == MEDIA_ACCESS_MODE_WRITE_ONLY ||
2407 cur == MEDIA_ACCESS_MODE_WRITE_ONLY) {
2408 result = MEDIA_ACCESS_MODE_WRITE_ONLY;
2409 } else if (result == MEDIA_ACCESS_MODE_WORM ||
2410 cur == MEDIA_ACCESS_MODE_WORM) {
2411 result = MEDIA_ACCESS_MODE_WORM;
2412 } else if (result == MEDIA_ACCESS_MODE_READ_WRITE &&
2413 cur == MEDIA_ACCESS_MODE_READ_WRITE) {
2414 result = MEDIA_ACCESS_MODE_READ_WRITE;
2421 g_ptr_array_free_full(ops);
2425 g_value_unset_init(val, MEDIA_ACCESS_MODE_TYPE);
2426 g_value_set_enum(val, result);
2430 *surety = PROPERTY_SURETY_GOOD;
2433 *source = PROPERTY_SOURCE_DETECTED;
2440 property_get_free_space_fn(Device *dself,
2441 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2442 PropertySurety *surety, PropertySource *source)
2444 RaitDevice *self = RAIT_DEVICE(dself);
2445 QualifiedSize result;
2448 guint data_children;
2450 ops = make_property_op_array(self, PROPERTY_MEDIUM_ACCESS_TYPE, NULL, 0, 0);
2451 do_rait_child_ops(self, property_get_do_op, ops);
2453 /* Find the minimal available space of any child, with some funny business
2454 * to deal with varying degrees of accuracy. */
2455 result.accuracy = SIZE_ACCURACY_UNKNOWN;
2457 for (i = 0; i < ops->len; i ++) {
2459 PropertyOp * op = g_ptr_array_index(ops, i);
2461 if (!op->base.result || G_VALUE_TYPE(&(op->value)) != QUALIFIED_SIZE_TYPE) {
2462 /* maybe this child can't tell us .. so this is just an estimate */
2463 if (result.accuracy == SIZE_ACCURACY_REAL)
2464 result.accuracy = SIZE_ACCURACY_ESTIMATE;
2469 cur = *(QualifiedSize*)(g_value_get_boxed(&(op->value)));
2471 if (result.accuracy != cur.accuracy) {
2472 result.accuracy = SIZE_ACCURACY_ESTIMATE;
2475 if (result.accuracy == SIZE_ACCURACY_UNKNOWN &&
2476 cur.accuracy != SIZE_ACCURACY_UNKNOWN) {
2477 result.bytes = cur.bytes;
2478 } else if (result.accuracy != SIZE_ACCURACY_UNKNOWN &&
2479 cur.accuracy == SIZE_ACCURACY_UNKNOWN) {
2480 /* result.bytes unchanged. */
2482 result.bytes = MIN(result.bytes, cur.bytes);
2486 g_ptr_array_free_full(ops);
2488 /* result contains the minimum size available on any child. We
2489 * can use that space on each of our data children, so the total
2491 find_simple_params(self, NULL, &data_children);
2492 result.bytes *= data_children;
2495 g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
2496 g_value_set_boxed(val, &result);
2500 *surety = (result.accuracy == SIZE_ACCURACY_UNKNOWN)?
2501 PROPERTY_SURETY_BAD : PROPERTY_SURETY_GOOD;
2504 *source = PROPERTY_SOURCE_DETECTED;
2510 property_get_max_volume_usage_fn(Device *dself,
2511 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2512 PropertySurety *surety, PropertySource *source)
2514 RaitDevice *self = RAIT_DEVICE(dself);
2518 guint data_children;
2520 ops = make_property_op_array(self, PROPERTY_MAX_VOLUME_USAGE, NULL, 0, 0);
2521 do_rait_child_ops(self, property_get_do_op, ops);
2523 /* look for the smallest value that is set */
2525 for (i = 0; i < ops->len; i ++) {
2527 PropertyOp * op = g_ptr_array_index(ops, i);
2529 if (!op->base.result || !G_VALUE_HOLDS_UINT64(&(op->value))) {
2530 continue; /* ignore children without this property */
2533 cur = g_value_get_uint64(&(op->value));
2535 result = MIN(cur, result);
2538 g_ptr_array_free_full(ops);
2541 /* result contains the minimum usage on any child. We can use that space
2542 * on each of our data children, so the total is larger */
2543 find_simple_params(self, NULL, &data_children);
2544 result *= data_children;
2547 g_value_unset_init(val, G_TYPE_UINT64);
2548 g_value_set_uint64(val, result);
2552 *surety = PROPERTY_SURETY_GOOD;
2555 *source = PROPERTY_SOURCE_DETECTED;
2559 /* no result from any children, so we effectively don't have this property */
2565 property_set_max_volume_usage_fn(Device *dself,
2566 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2567 PropertySurety surety, PropertySource source)
2569 RaitDevice *self = RAIT_DEVICE(dself);
2570 guint64 parent_usage;
2571 guint64 child_usage;
2576 guint data_children;
2578 parent_usage = g_value_get_uint64(val);
2579 find_simple_params(self, NULL, &data_children);
2581 child_usage = parent_usage / data_children;
2583 bzero(&child_val, sizeof(child_val));
2584 g_value_init(&child_val, G_TYPE_UINT64);
2585 g_value_set_uint64(&child_val, child_usage);
2587 ops = make_property_op_array(self, PROPERTY_MAX_VOLUME_USAGE,
2588 &child_val, surety, source);
2589 do_rait_child_ops(self, property_set_do_op, ops);
2591 /* if any of the kids succeeded, then we did too */
2593 for (i = 0; i < ops->len; i ++) {
2594 PropertyOp * op = g_ptr_array_index(ops, i);
2596 if (op->base.result) {
2602 g_ptr_array_free_full(ops);
2613 static void recycle_file_do_op(gpointer data,
2614 gpointer user_data G_GNUC_UNUSED) {
2615 RecycleFileOp * op = data;
2617 GINT_TO_POINTER(device_recycle_file(op->base.child, op->filenum));
2621 rait_device_recycle_file (Device * dself, guint filenum) {
2626 RaitDevice * self = RAIT_DEVICE(dself);
2628 if (rait_device_in_error(self)) return FALSE;
2630 ops = g_ptr_array_sized_new(self->private->children->len);
2631 for (i = 0; i < self->private->children->len; i ++) {
2633 op = g_new(RecycleFileOp, 1);
2634 op->base.child = g_ptr_array_index(self->private->children, i);
2635 op->filenum = filenum;
2636 g_ptr_array_add(ops, op);
2639 do_rait_child_ops(self, recycle_file_do_op, ops);
2641 success = g_ptr_array_and(ops, extract_boolean_generic_op);
2643 g_ptr_array_free_full(ops);
2646 /* TODO: be more specific here */
2647 device_set_error(dself,
2648 stralloc(_("One or more devices failed to recycle_file")),
2649 DEVICE_STATUS_DEVICE_ERROR);
2656 static void finish_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
2657 GenericOp * op = data;
2658 op->result = GINT_TO_POINTER(device_finish(op->child));
2662 rait_device_finish (Device * self) {
2666 if (rait_device_in_error(self)) return FALSE;
2668 ops = make_generic_boolean_op_array(RAIT_DEVICE(self));
2670 do_rait_child_ops(RAIT_DEVICE(self), finish_do_op, ops);
2672 success = g_ptr_array_and(ops, extract_boolean_generic_op);
2674 g_ptr_array_free_full(ops);
2676 self->access_mode = ACCESS_NULL;
2685 rait_device_factory (char * device_name, char * device_type, char * device_node) {
2687 g_assert(0 == strcmp(device_type, "rait"));
2688 rval = DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL));
2689 device_open_device(rval, device_name, device_type, device_node);
2694 rait_device_register (void) {
2695 static const char * device_prefix_list[] = {"rait", NULL};
2696 register_device(rait_device_factory, device_prefix_list);