1 /*
2 * Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20 */
21
22 /* The RAIT device encapsulates some number of other devices into a single
23 * redundant device. */
24
25 #include "amanda.h"
26 #include "property.h"
27 #include "util.h"
28 #include <glib.h>
29 #include "glib-util.h"
30 #include "device.h"
31 #include "fileheader.h"
32 #include "amsemaphore.h"
33
34 /* Just a note about the failure mode of different operations:
35 - Recovers from a failure (enters degraded mode)
36 open_device()
37 seek_file() -- explodes if headers don't match.
38 seek_block() -- explodes if headers don't match.
39 read_block() -- explodes if data doesn't match.
40
41 - Operates in degraded mode (but dies if a new problem shows up)
42 read_label() -- but dies on label mismatch.
43 start() -- but dies when writing in degraded mode.
44 property functions
45 finish()
46
47 - Dies in degraded mode (even if remaining devices are OK)
48 start_file()
49 write_block()
50 finish_file()
51 recycle_file()
52 */
53
54 /*
55 * Type checking and casting macros
56 */
57 #define TYPE_RAIT_DEVICE (rait_device_get_type())
58 #define RAIT_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice)
59 #define RAIT_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice const)
60 #define RAIT_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), rait_device_get_type(), RaitDeviceClass)
61 #define IS_RAIT_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), rait_device_get_type ())
62
63 #define RAIT_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), rait_device_get_type(), RaitDeviceClass)
64 static GType rait_device_get_type (void);
65
66 /*
67 * Main object structure
68 */
69 typedef struct RaitDevice_s {
70 Device __parent__;
71
72 struct RaitDevicePrivate_s * private;
73 } RaitDevice;
74
75 /*
76 * Class definition
77 */
78 typedef struct _RaitDeviceClass RaitDeviceClass;
79 struct _RaitDeviceClass {
80 DeviceClass __parent__;
81 };
82
83 typedef enum {
84 RAIT_STATUS_COMPLETE, /* All subdevices OK. */
85 RAIT_STATUS_DEGRADED, /* One subdevice failed. */
86 RAIT_STATUS_FAILED /* Two or more subdevices failed. */
87 } RaitStatus;
88
89 /* Older versions of glib have a deadlock in their thread pool implementations,
90 * so we include a simple thread-pool implementation here to replace it.
91 *
92 * This implementation assumes that threads are used for paralellizing a single
93 * operation, so all threads run a function to completion before the main thread
94 * continues. This simplifies some of the locking semantics, and in particular
95 * there is no need to wait for stray threads to finish an operation when
96 * finalizing the RaitDevice object or when beginning a new operation.
97 */
98 #if !(GLIB_CHECK_VERSION(2,10,0))
99 #define USE_INTERNAL_THREADPOOL
100 #endif
101
102 typedef struct RaitDevicePrivate_s {
103 GPtrArray * children;
104 /* These flags are only relevant for reading. */
105 RaitStatus status;
106 /* If status == RAIT_STATUS_DEGRADED, this holds the index of the
107 failed node. It holds a negative number otherwise. */
108 int failed;
109
110 /* the child block size */
111 gsize child_block_size;
112
113 #ifdef USE_INTERNAL_THREADPOOL
114 /* array of ThreadInfo for performing parallel operations */
115 GArray *threads;
116
117 /* value of this semaphore is the number of threaded operations
118 * in progress */
119 amsemaphore_t *threads_sem;
120 #endif
121 } RaitDevicePrivate;
122
123 #ifdef USE_INTERNAL_THREADPOOL
124 typedef struct ThreadInfo {
125 GThread *thread;
126
127 /* struct fields below are protected by this mutex and condition variable */
128 GMutex *mutex;
129 GCond *cond;
130
131 gboolean die;
132 GFunc func;
133 gpointer data;
134
135 /* give threads access to active_threads and its mutex/cond */
136 struct RaitDevicePrivate_s *private;
137 } ThreadInfo;
138 #endif
139
140 /* This device uses a special sentinel node to indicate that the child devices
141 * will be set later (in rait_device_open). It contains a control character to
142 * make it difficult to enter accidentally in an Amanda config. */
143 #define DEFER_CHILDREN_SENTINEL "DEFER\1"
144
145 #define PRIVATE(o) (o->private)
146
147 #define rait_device_in_error(dev) \
148 (device_in_error((dev)) || PRIVATE(RAIT_DEVICE((dev)))->status == RAIT_STATUS_FAILED)
149
150 void rait_device_register (void);
151
152 /* here are local prototypes */
153 static void rait_device_init (RaitDevice * o);
154 static void rait_device_class_init (RaitDeviceClass * c);
155 static void rait_device_base_init (RaitDeviceClass * c);
156 static void rait_device_open_device (Device * self, char * device_name, char * device_type, char * device_node);
157 static gboolean rait_device_start (Device * self, DeviceAccessMode mode,
158 char * label, char * timestamp);
159 static gboolean rait_device_configure(Device * self, gboolean use_global_config);
160 static gboolean rait_device_start_file(Device * self, dumpfile_t * info);
161 static gboolean rait_device_write_block (Device * self, guint size, gpointer data);
162 static gboolean rait_device_finish_file (Device * self);
163 static dumpfile_t * rait_device_seek_file (Device * self, guint file);
164 static gboolean rait_device_seek_block (Device * self, guint64 block);
165 static int rait_device_read_block (Device * self, gpointer buf,
166 int * size);
167 static gboolean rait_device_recycle_file (Device * self, guint filenum);
168 static gboolean rait_device_finish (Device * self);
169 static DeviceStatusFlags rait_device_read_label(Device * dself);
170 static void find_simple_params(RaitDevice * self, guint * num_children,
171 guint * data_children);
172
173 /* property handlers */
174
175 static gboolean property_get_block_size_fn(Device *self,
176 DevicePropertyBase *base, GValue *val,
177 PropertySurety *surety, PropertySource *source);
178
179 static gboolean property_set_block_size_fn(Device *self,
180 DevicePropertyBase *base, GValue *val,
181 PropertySurety surety, PropertySource source);
182
183 static gboolean property_get_canonical_name_fn(Device *self,
184 DevicePropertyBase *base, GValue *val,
185 PropertySurety *surety, PropertySource *source);
186
187 static gboolean property_get_concurrency_fn(Device *self,
188 DevicePropertyBase *base, GValue *val,
189 PropertySurety *surety, PropertySource *source);
190
191 static gboolean property_get_streaming_fn(Device *self,
192 DevicePropertyBase *base, GValue *val,
193 PropertySurety *surety, PropertySource *source);
194
195 static gboolean property_get_boolean_and_fn(Device *self,
196 DevicePropertyBase *base, GValue *val,
197 PropertySurety *surety, PropertySource *source);
198
199 static gboolean property_get_medium_access_type_fn(Device *self,
200 DevicePropertyBase *base, GValue *val,
201 PropertySurety *surety, PropertySource *source);
202
203 static gboolean property_get_max_volume_usage_fn(Device *self,
204 DevicePropertyBase *base, GValue *val,
205 PropertySurety *surety, PropertySource *source);
206
207 static gboolean property_set_max_volume_usage_fn(Device *self,
208 DevicePropertyBase *base, GValue *val,
209 PropertySurety surety, PropertySource source);
210
211
212 /* pointer to the class of our parent */
213 static DeviceClass *parent_class = NULL;
214
215 static GType
rait_device_get_type(void)216 rait_device_get_type (void)
217 {
218 static GType type = 0;
219
220 if G_UNLIKELY(type == 0) {
221 static const GTypeInfo info = {
222 sizeof (RaitDeviceClass),
223 (GBaseInitFunc) rait_device_base_init,
224 (GBaseFinalizeFunc) NULL,
225 (GClassInitFunc) rait_device_class_init,
226 (GClassFinalizeFunc) NULL,
227 NULL /* class_data */,
228 sizeof (RaitDevice),
229 0 /* n_preallocs */,
230 (GInstanceInitFunc) rait_device_init,
231 NULL
232 };
233
234 type = g_type_register_static (TYPE_DEVICE, "RaitDevice", &info,
235 (GTypeFlags)0);
236 }
237
238 return type;
239 }
240
g_object_unref_foreach(gpointer data,gpointer user_data G_GNUC_UNUSED)241 static void g_object_unref_foreach(gpointer data,
242 gpointer user_data G_GNUC_UNUSED) {
243 if (data != NULL && G_IS_OBJECT(data)) {
244 g_object_unref(data);
245 }
246 }
247
248 static void
rait_device_finalize(GObject * obj_self)249 rait_device_finalize(GObject *obj_self)
250 {
251 RaitDevice *self = RAIT_DEVICE (obj_self);
252 if(G_OBJECT_CLASS(parent_class)->finalize) \
253 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
254 if(self->private->children) {
255 g_ptr_array_foreach(self->private->children,
256 g_object_unref_foreach, NULL);
257 g_ptr_array_free (self->private->children, TRUE);
258 self->private->children = NULL;
259 }
260 #ifdef USE_INTERNAL_THREADPOOL
261 g_assert(PRIVATE(self)->threads_sem == NULL || PRIVATE(self)->threads_sem->value == 0);
262
263 if (PRIVATE(self)->threads) {
264 guint i;
265
266 for (i = 0; i < PRIVATE(self)->threads->len; i++) {
267 ThreadInfo *inf = &g_array_index(PRIVATE(self)->threads, ThreadInfo, i);
268 if (inf->thread) {
269 /* NOTE: the thread is waiting on this condition right now, not
270 * executing an operation. */
271
272 /* ask the thread to die */
273 g_mutex_lock(inf->mutex);
274 inf->die = TRUE;
275 g_cond_signal(inf->cond);
276 g_mutex_unlock(inf->mutex);
277
278 /* and wait for it to die, which should happen soon */
279 g_thread_join(inf->thread);
280 }
281
282 if (inf->mutex)
283 g_mutex_free(inf->mutex);
284 if (inf->cond)
285 g_cond_free(inf->cond);
286 }
287 }
288
289 if (PRIVATE(self)->threads_sem)
290 amsemaphore_free(PRIVATE(self)->threads_sem);
291 #endif
292 amfree(self->private);
293 }
294
295 static void
rait_device_init(RaitDevice * o G_GNUC_UNUSED)296 rait_device_init (RaitDevice * o G_GNUC_UNUSED)
297 {
298 PRIVATE(o) = g_new(RaitDevicePrivate, 1);
299 PRIVATE(o)->children = g_ptr_array_new();
300 PRIVATE(o)->status = RAIT_STATUS_COMPLETE;
301 PRIVATE(o)->failed = -1;
302 #ifdef USE_INTERNAL_THREADPOOL
303 PRIVATE(o)->threads = NULL;
304 PRIVATE(o)->threads_sem = NULL;
305 #endif
306 }
307
308 static void
rait_device_class_init(RaitDeviceClass * c)309 rait_device_class_init (RaitDeviceClass * c)
310 {
311 GObjectClass *g_object_class = (GObjectClass*) c;
312 DeviceClass *device_class = (DeviceClass *)c;
313
314 parent_class = g_type_class_ref (TYPE_DEVICE);
315
316 device_class->open_device = rait_device_open_device;
317 device_class->configure = rait_device_configure;
318 device_class->start = rait_device_start;
319 device_class->start_file = rait_device_start_file;
320 device_class->write_block = rait_device_write_block;
321 device_class->finish_file = rait_device_finish_file;
322 device_class->seek_file = rait_device_seek_file;
323 device_class->seek_block = rait_device_seek_block;
324 device_class->read_block = rait_device_read_block;
325 device_class->recycle_file = rait_device_recycle_file;
326 device_class->finish = rait_device_finish;
327 device_class->read_label = rait_device_read_label;
328
329 g_object_class->finalize = rait_device_finalize;
330
331 #ifndef USE_INTERNAL_THREADPOOL
332 #if !GLIB_CHECK_VERSION(2,10,2)
333 /* Versions of glib before 2.10.2 crash if
334 * g_thread_pool_set_max_unused_threads is called before the first
335 * invocation of g_thread_pool_new. So we make up a thread pool, but don't
336 * start any threads in it, and free it */
337 {
338 GThreadPool *pool = g_thread_pool_new((GFunc)-1, NULL, -1, FALSE, NULL);
339 g_thread_pool_free(pool, TRUE, FALSE);
340 }
341 #endif
342
343 g_thread_pool_set_max_unused_threads(-1);
344 #endif
345 }
346
347 static void
rait_device_base_init(RaitDeviceClass * c)348 rait_device_base_init (RaitDeviceClass * c)
349 {
350 DeviceClass *device_class = (DeviceClass *)c;
351
352 /* the RAIT device overrides most of the standard properties, so that it
353 * can calculate them by querying the same property on the children */
354 device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
355 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
356 property_get_block_size_fn,
357 property_set_block_size_fn);
358
359 device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
360 PROPERTY_ACCESS_GET_MASK,
361 property_get_canonical_name_fn, NULL);
362
363 device_class_register_property(device_class, PROPERTY_CONCURRENCY,
364 PROPERTY_ACCESS_GET_MASK,
365 property_get_concurrency_fn, NULL);
366
367 device_class_register_property(device_class, PROPERTY_STREAMING,
368 PROPERTY_ACCESS_GET_MASK,
369 property_get_streaming_fn, NULL);
370
371 device_class_register_property(device_class, PROPERTY_APPENDABLE,
372 PROPERTY_ACCESS_GET_MASK,
373 property_get_boolean_and_fn, NULL);
374
375 device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
376 PROPERTY_ACCESS_GET_MASK,
377 property_get_boolean_and_fn, NULL);
378
379 device_class_register_property(device_class, PROPERTY_FULL_DELETION,
380 PROPERTY_ACCESS_GET_MASK,
381 property_get_boolean_and_fn, NULL);
382
383 device_class_register_property(device_class, PROPERTY_LEOM,
384 PROPERTY_ACCESS_GET_MASK,
385 property_get_boolean_and_fn, NULL);
386
387 device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
388 PROPERTY_ACCESS_GET_MASK,
389 property_get_medium_access_type_fn, NULL);
390
391 device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
392 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
393 property_get_max_volume_usage_fn,
394 property_set_max_volume_usage_fn);
395 }
396
397 /* This function does something a little clever and a little
398 * complicated. It takes an array of operations and runs the given
399 * function on each element in the array. The trick is that it runs them
400 * all in parallel, in different threads. This is more efficient than it
401 * sounds because we use a GThreadPool, which means calling this function
402 * will probably not start any new threads at all, but rather use
403 * existing ones. The func is called with two gpointer arguments: The
404 * first from the array, the second is the data argument.
405 *
406 * When it returns, all the operations have been successfully
407 * executed. If you want results from your operations, do it yourself
408 * through the array.
409 */
410
411 #ifdef USE_INTERNAL_THREADPOOL
rait_thread_pool_func(gpointer data)412 static gpointer rait_thread_pool_func(gpointer data) {
413 ThreadInfo *inf = data;
414
415 g_mutex_lock(inf->mutex);
416 while (TRUE) {
417 while (!inf->die && !inf->func)
418 g_cond_wait(inf->cond, inf->mutex);
419
420 if (inf->die)
421 break;
422
423 if (inf->func) {
424 /* invoke the function */
425 inf->func(inf->data, NULL);
426 inf->func = NULL;
427 inf->data = NULL;
428
429 /* indicate that we're finished; will not block */
430 amsemaphore_down(inf->private->threads_sem);
431 }
432 }
433 g_mutex_unlock(inf->mutex);
434 return NULL;
435 }
436
do_thread_pool_op(RaitDevice * self,GFunc func,GPtrArray * ops)437 static void do_thread_pool_op(RaitDevice *self, GFunc func, GPtrArray * ops) {
438 guint i;
439
440 if (PRIVATE(self)->threads_sem == NULL)
441 PRIVATE(self)->threads_sem = amsemaphore_new_with_value(0);
442
443 if (PRIVATE(self)->threads == NULL)
444 PRIVATE(self)->threads = g_array_sized_new(FALSE, TRUE,
445 sizeof(ThreadInfo), ops->len);
446
447 g_assert(PRIVATE(self)->threads_sem->value == 0);
448
449 if (PRIVATE(self)->threads->len < ops->len)
450 g_array_set_size(PRIVATE(self)->threads, ops->len);
451
452 /* the semaphore will hit zero when each thread has decremented it */
453 amsemaphore_force_set(PRIVATE(self)->threads_sem, ops->len);
454
455 for (i = 0; i < ops->len; i++) {
456 ThreadInfo *inf = &g_array_index(PRIVATE(self)->threads, ThreadInfo, i);
457 if (!inf->thread) {
458 inf->mutex = g_mutex_new();
459 inf->cond = g_cond_new();
460 inf->private = PRIVATE(self);
461 inf->thread = g_thread_create(rait_thread_pool_func, inf, TRUE, NULL);
462 }
463
464 /* set up the info the thread needs and trigger it to start */
465 g_mutex_lock(inf->mutex);
466 inf->data = g_ptr_array_index(ops, i);
467 inf->func = func;
468 g_cond_signal(inf->cond);
469 g_mutex_unlock(inf->mutex);
470 }
471
472 /* wait until semaphore hits zero */
473 amsemaphore_wait_empty(PRIVATE(self)->threads_sem);
474 }
475
476 #else /* USE_INTERNAL_THREADPOOL */
477
do_thread_pool_op(RaitDevice * self G_GNUC_UNUSED,GFunc func,GPtrArray * ops)478 static void do_thread_pool_op(RaitDevice *self G_GNUC_UNUSED, GFunc func, GPtrArray * ops) {
479 GThreadPool * pool;
480 guint i;
481
482 pool = g_thread_pool_new(func, NULL, -1, FALSE, NULL);
483 for (i = 0; i < ops->len; i ++) {
484 g_thread_pool_push(pool, g_ptr_array_index(ops, i), NULL);
485 }
486
487 g_thread_pool_free(pool, FALSE, TRUE);
488 }
489
490 #endif /* USE_INTERNAL_THREADPOOL */
491
492 /* This does the above, in a serial fashion (and without using threads) */
do_unthreaded_ops(RaitDevice * self G_GNUC_UNUSED,GFunc func,GPtrArray * ops)493 static void do_unthreaded_ops(RaitDevice *self G_GNUC_UNUSED, GFunc func, GPtrArray * ops) {
494 guint i;
495
496 for (i = 0; i < ops->len; i ++) {
497 func(g_ptr_array_index(ops, i), NULL);
498 }
499 }
500
501 /* This is the one that code below should call. It switches
502 automatically between do_thread_pool_op and do_unthreaded_ops,
503 depending on g_thread_supported(). */
do_rait_child_ops(RaitDevice * self,GFunc func,GPtrArray * ops)504 static void do_rait_child_ops(RaitDevice *self, GFunc func, GPtrArray * ops) {
505 if (g_thread_supported()) {
506 do_thread_pool_op(self, func, ops);
507 } else {
508 do_unthreaded_ops(self, func, ops);
509 }
510 }
511
512 static char *
child_device_names_to_rait_name(RaitDevice * self)513 child_device_names_to_rait_name(RaitDevice * self) {
514 GPtrArray *kids;
515 char *braced, *result;
516 guint i;
517
518 kids = g_ptr_array_sized_new(self->private->children->len);
519 for (i = 0; i < self->private->children->len; i ++) {
520 Device *child = g_ptr_array_index(self->private->children, i);
521 const char *child_name = NULL;
522 GValue val;
523 gboolean got_prop = FALSE;
524
525 bzero(&val, sizeof(val));
526
527 if ((signed)i != self->private->failed) {
528 if (device_property_get(child, PROPERTY_CANONICAL_NAME, &val)) {
529 child_name = g_value_get_string(&val);
530 got_prop = TRUE;
531 }
532 }
533
534 if (!got_prop)
535 child_name = "MISSING";
536
537 g_ptr_array_add(kids, g_strdup(child_name));
538
539 if (got_prop)
540 g_value_unset(&val);
541 }
542
543 braced = collapse_braced_alternates(kids);
544 result = g_strdup_printf("rait:%s", braced);
545 g_free(braced);
546
547 return result;
548 }
549
550 /* Find a workable child block size, based on the block size ranges of our
551 * child devices.
552 *
553 * The algorithm is to construct the intersection of all child devices'
554 * [min,max] block size ranges, and then pick the block size closest to 32k
555 * that is in the resulting range. This avoids picking ridiculously small (1
556 * byte) or large (INT_MAX) block sizes when using devices with wide-open block
557 * size ranges.
558
559 * This function returns the calculated child block size directly, and the RAIT
560 * device's blocksize via rait_size, if not NULL. It is resilient to errors in
561 * a single child device, but sets the device's error status and returns 0 if
562 * it cannot determine an agreeable block size.
563 */
564 static gsize
calculate_block_size_from_children(RaitDevice * self,gsize * rait_size)565 calculate_block_size_from_children(RaitDevice * self, gsize *rait_size)
566 {
567 gsize min = 0;
568 gsize max = SIZE_MAX;
569 gboolean found_one = FALSE;
570 gsize result;
571 guint i;
572
573 for (i = 0; i < self->private->children->len; i ++) {
574 gsize child_min = SIZE_MAX, child_max = 0;
575 Device *child;
576 GValue property_result;
577 PropertySource source;
578
579 bzero(&property_result, sizeof(property_result));
580
581 if ((signed)i == self->private->failed)
582 continue;
583
584 child = g_ptr_array_index(self->private->children, i);
585 if (!device_property_get_ex(child, PROPERTY_BLOCK_SIZE,
586 &property_result, NULL, &source)) {
587 g_warning("Error getting BLOCK_SIZE from %s: %s",
588 child->device_name, device_error_or_status(child));
589 continue;
590 }
591
592 /* if the block size has been set explicitly, then we need to use that blocksize;
593 * otherwise (even if it was DETECTED), override it. */
594 if (source == PROPERTY_SOURCE_USER) {
595 child_min = child_max = g_value_get_int(&property_result);
596 } else {
597 if (!device_property_get(child, PROPERTY_MIN_BLOCK_SIZE,
598 &property_result)) {
599 g_warning("Error getting MIN_BLOCK_SIZE from %s: %s",
600 child->device_name, device_error_or_status(child));
601 continue;
602 }
603 child_min = g_value_get_uint(&property_result);
604
605 if (!device_property_get(child, PROPERTY_MAX_BLOCK_SIZE,
606 &property_result)) {
607 g_warning("Error getting MAX_BLOCK_SIZE from %s: %s",
608 child->device_name, device_error_or_status(child));
609 continue;
610 }
611 child_max = g_value_get_uint(&property_result);
612
613 if (child_min == 0 || child_max == 0 || (child_min > child_max)) {
614 g_warning("Invalid min, max block sizes from %s", child->device_name);
615 continue;
616 }
617 }
618
619 found_one = TRUE;
620 min = MAX(min, child_min);
621 max = MIN(max, child_max);
622 }
623
624 if (!found_one) {
625 device_set_error((Device*)self,
626 stralloc(_("Could not find any child devices' block size ranges")),
627 DEVICE_STATUS_DEVICE_ERROR);
628 return 0;
629 }
630
631 if (min > max) {
632 device_set_error((Device*)self,
633 stralloc(_("No block size is acceptable to all child devices")),
634 DEVICE_STATUS_DEVICE_ERROR);
635 return 0;
636 }
637
638 /* Now pick a number. If 32k is in range, we use that; otherwise, we use
639 * the nearest acceptable size. */
640 result = CLAMP(32768, min, max);
641
642 if (rait_size) {
643 guint data_children;
644 find_simple_params(self, NULL, &data_children);
645 *rait_size = result * data_children;
646 }
647
648 return result;
649 }
650
651 /* Set BLOCK_SIZE on all children */
652 static gboolean
set_block_size_on_children(RaitDevice * self,gsize child_block_size)653 set_block_size_on_children(RaitDevice *self, gsize child_block_size)
654 {
655 GValue val;
656 guint i;
657 PropertySource source;
658
659 bzero(&val, sizeof(val));
660
661 g_assert(child_block_size < INT_MAX);
662 g_value_init(&val, G_TYPE_INT);
663 g_value_set_int(&val, (gint)child_block_size);
664
665 for (i = 0; i < self->private->children->len; i ++) {
666 Device *child;
667 GValue property_result;
668
669 bzero(&property_result, sizeof(property_result));
670
671 if ((signed)i == self->private->failed)
672 continue;
673
674 child = g_ptr_array_index(self->private->children, i);
675
676 /* first, make sure the block size is at its default, or is already
677 * correct */
678 if (device_property_get_ex(child, PROPERTY_BLOCK_SIZE,
679 &property_result, NULL, &source)) {
680 gsize from_child = g_value_get_int(&property_result);
681 g_value_unset(&property_result);
682 if (source != PROPERTY_SOURCE_DEFAULT
683 && from_child != child_block_size) {
684 device_set_error((Device *)self,
685 vstrallocf(_("Child device %s already has its block size set to %zd, not %zd"),
686 child->device_name, from_child, child_block_size),
687 DEVICE_STATUS_DEVICE_ERROR);
688 return FALSE;
689 }
690 } else {
691 /* failing to get the block size isn't necessarily fatal.. */
692 g_warning("Error getting BLOCK_SIZE from %s: %s",
693 child->device_name, device_error_or_status(child));
694 }
695
696 if (!device_property_set(child, PROPERTY_BLOCK_SIZE, &val)) {
697 device_set_error((Device *)self,
698 vstrallocf(_("Error setting block size on %s"), child->device_name),
699 DEVICE_STATUS_DEVICE_ERROR);
700 return FALSE;
701 }
702 }
703
704 return TRUE;
705 }
706
707 /* The time for users to specify block sizes has ended; set this device's
708 * block-size attributes for easy access by other RAIT functions. Returns
709 * FALSE on error, with the device's error status already set. */
710 static gboolean
fix_block_size(RaitDevice * self)711 fix_block_size(RaitDevice *self)
712 {
713 Device *dself = (Device *)self;
714 gsize my_block_size, child_block_size;
715
716 if (dself->block_size_source == PROPERTY_SOURCE_DEFAULT) {
717 child_block_size = calculate_block_size_from_children(self, &my_block_size);
718 if (child_block_size == 0)
719 return FALSE;
720
721 self->private->child_block_size = child_block_size;
722 dself->block_size = my_block_size;
723 dself->block_size_surety = PROPERTY_SURETY_GOOD;
724 dself->block_size_source = PROPERTY_SOURCE_DETECTED;
725 } else {
726 guint data_children;
727
728 find_simple_params(self, NULL, &data_children);
729 g_assert((dself->block_size % data_children) == 0);
730 child_block_size = dself->block_size / data_children;
731 }
732
733 /* now tell the children we mean it */
734 if (!set_block_size_on_children(self, child_block_size))
735 return FALSE;
736
737 return TRUE;
738 }
739
740 /* This structure contains common fields for many operations. Not all
741 operations use all fields, however. */
742 typedef struct {
743 gpointer result; /* May be a pointer; may be an integer or boolean
744 stored with GINT_TO_POINTER. */
745 Device * child; /* The device in question. Used by all
746 operations. */
747 guint child_index; /* For recoverable operations (read-related
748 operations), this field provides the number
749 of this child in the self->private->children
750 array. */
751 } GenericOp;
752
753 typedef gboolean (*BooleanExtractor)(gpointer data);
754
755 /* A BooleanExtractor */
extract_boolean_generic_op(gpointer data)756 static gboolean extract_boolean_generic_op(gpointer data) {
757 GenericOp * op = data;
758 return GPOINTER_TO_INT(op->result);
759 }
760
761 /* A BooleanExtractor */
extract_boolean_pointer_op(gpointer data)762 static gboolean extract_boolean_pointer_op(gpointer data) {
763 GenericOp * op = data;
764 return op->result != NULL;
765 }
766
767 /* Does the equivalent of this perl command:
768 ! (first { !extractor($_) } @_
769 That is, calls extractor on each element of the array, and returns
770 TRUE if and only if all calls to extractor return TRUE. This function
771 stops as soon as an extractor returns false, so it's best if extractor
772 functions have no side effects.
773 */
g_ptr_array_and(GPtrArray * array,BooleanExtractor extractor)774 static gboolean g_ptr_array_and(GPtrArray * array,
775 BooleanExtractor extractor) {
776 guint i;
777 if (array == NULL || array->len <= 0)
778 return FALSE;
779
780 for (i = 0; i < array->len; i ++) {
781 if (!extractor(g_ptr_array_index(array, i)))
782 return FALSE;
783 }
784
785 return TRUE;
786 }
787
788 /* Takes a RaitDevice, and makes a GPtrArray of GenericOp. */
make_generic_boolean_op_array(RaitDevice * self)789 static GPtrArray * make_generic_boolean_op_array(RaitDevice* self) {
790 GPtrArray * rval;
791 guint i;
792
793 rval = g_ptr_array_sized_new(self->private->children->len);
794 for (i = 0; i < self->private->children->len; i ++) {
795 GenericOp * op;
796
797 if ((signed)i == self->private->failed) {
798 continue;
799 }
800
801 op = g_new(GenericOp, 1);
802 op->child = g_ptr_array_index(self->private->children, i);
803 op->child_index = i;
804 g_ptr_array_add(rval, op);
805 }
806
807 return rval;
808 }
809
810 /* Takes a GPtrArray of GenericOp, and a BooleanExtractor, and does
811 all the proper handling for the result of operations that allow
812 device isolation. Returns FALSE only if an unrecoverable error
813 occured. */
g_ptr_array_union_robust(RaitDevice * self,GPtrArray * ops,BooleanExtractor extractor)814 static gboolean g_ptr_array_union_robust(RaitDevice * self, GPtrArray * ops,
815 BooleanExtractor extractor) {
816 int nfailed = 0;
817 int lastfailed = 0;
818 guint i;
819
820 /* We found one or more failed elements. See which elements failed, and
821 * isolate them*/
822 for (i = 0; i < ops->len; i ++) {
823 GenericOp * op = g_ptr_array_index(ops, i);
824 if (!extractor(op)) {
825 self->private->failed = op->child_index;
826 g_warning("RAIT array %s isolated device %s: %s",
827 DEVICE(self)->device_name,
828 op->child->device_name,
829 device_error(op->child));
830 nfailed++;
831 lastfailed = i;
832 }
833 }
834
835 /* no failures? great! */
836 if (nfailed == 0)
837 return TRUE;
838
839 /* a single failure in COMPLETE just puts us in DEGRADED mode */
840 if (self->private->status == RAIT_STATUS_COMPLETE && nfailed == 1) {
841 self->private->status = RAIT_STATUS_DEGRADED;
842 self->private->failed = lastfailed;
843 g_warning("RAIT array %s DEGRADED", DEVICE(self)->device_name);
844 return TRUE;
845 } else {
846 self->private->status = RAIT_STATUS_FAILED;
847 g_warning("RAIT array %s FAILED", DEVICE(self)->device_name);
848 return FALSE;
849 }
850 }
851
852 typedef struct {
853 RaitDevice * self;
854 char *rait_name;
855 char * device_name; /* IN */
856 Device * result; /* OUT */
857 } OpenDeviceOp;
858
859 /* A GFunc. */
device_open_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)860 static void device_open_do_op(gpointer data,
861 gpointer user_data G_GNUC_UNUSED) {
862 OpenDeviceOp * op = data;
863
864 if (strcmp(op->device_name, "ERROR") == 0 ||
865 strcmp(op->device_name, "MISSING") == 0 ||
866 strcmp(op->device_name, "DEGRADED") == 0) {
867 g_warning("RAIT device %s contains a missing element, attempting "
868 "degraded mode.\n", op->rait_name);
869 op->result = NULL;
870 } else {
871 op->result = device_open(op->device_name);
872 }
873 }
874
875 /* Returns TRUE if and only if the volume label and time are equal. */
compare_volume_results(Device * a,Device * b)876 static gboolean compare_volume_results(Device * a, Device * b) {
877 return (0 == compare_possibly_null_strings(a->volume_time, b->volume_time)
878 && 0 == compare_possibly_null_strings(a->volume_label, b->volume_label));
879 }
880
881 /* Stickes new_message at the end of *old_message; frees new_message and
882 * may change *old_message. */
append_message(char ** old_message,char * new_message)883 static void append_message(char ** old_message, char * new_message) {
884 char * rval;
885 if (*old_message == NULL || **old_message == '\0') {
886 rval = new_message;
887 } else {
888 rval = g_strdup_printf("%s; %s", *old_message, new_message);
889 amfree(new_message);
890 }
891 amfree(*old_message);
892 *old_message = rval;
893 }
894
895 static gboolean
open_child_devices(Device * dself,char * device_name,char * device_node)896 open_child_devices (Device * dself, char * device_name,
897 char * device_node) {
898 GPtrArray *device_names;
899 GPtrArray * device_open_ops;
900 guint i;
901 gboolean failure;
902 char *failure_errmsgs;
903 DeviceStatusFlags failure_flags;
904 RaitDevice * self;
905
906 self = RAIT_DEVICE(dself);
907
908 device_names = expand_braced_alternates(device_node);
909
910 if (device_names == NULL) {
911 device_set_error(dself,
912 vstrallocf(_("Invalid RAIT device name '%s'"), device_name),
913 DEVICE_STATUS_DEVICE_ERROR);
914 return FALSE;
915 }
916
917 /* Open devices in a separate thread, in case they have to rewind etc. */
918 device_open_ops = g_ptr_array_new();
919
920 for (i = 0; i < device_names->len; i++) {
921 OpenDeviceOp *op;
922 char *name = g_ptr_array_index(device_names, i);
923
924 op = g_new(OpenDeviceOp, 1);
925 op->device_name = name;
926 op->result = NULL;
927 op->self = self;
928 op->rait_name = device_name;
929 g_ptr_array_add(device_open_ops, op);
930 }
931
932 g_ptr_array_free(device_names, TRUE);
933 do_rait_child_ops(self, device_open_do_op, device_open_ops);
934
935 failure = FALSE;
936 failure_errmsgs = NULL;
937 failure_flags = 0;
938
939 /* Check results of opening devices. */
940 for (i = 0; i < device_open_ops->len; i ++) {
941 OpenDeviceOp *op = g_ptr_array_index(device_open_ops, i);
942
943 if (op->result != NULL &&
944 op->result->status == DEVICE_STATUS_SUCCESS) {
945 g_ptr_array_add(self->private->children, op->result);
946 } else {
947 char * this_failure_errmsg =
948 g_strdup_printf("%s: %s", op->device_name,
949 device_error_or_status(op->result));
950 DeviceStatusFlags status =
951 op->result == NULL ?
952 DEVICE_STATUS_DEVICE_ERROR : op->result->status;
953 append_message(&failure_errmsgs,
954 strdup(this_failure_errmsg));
955 failure_flags |= status;
956 if (self->private->status == RAIT_STATUS_COMPLETE) {
957 /* The first failure just puts us in degraded mode. */
958 g_warning("%s: %s",
959 device_name, this_failure_errmsg);
960 g_warning("%s: %s failed, entering degraded mode.",
961 device_name, op->device_name);
962 g_ptr_array_add(self->private->children, op->result);
963 self->private->status = RAIT_STATUS_DEGRADED;
964 self->private->failed = i;
965 } else {
966 /* The second and further failures are fatal. */
967 failure = TRUE;
968 }
969 }
970 amfree(op->device_name);
971 }
972
973 g_ptr_array_free_full(device_open_ops);
974
975 if (failure) {
976 self->private->status = RAIT_STATUS_FAILED;
977 device_set_error(dself, failure_errmsgs, failure_flags);
978 return FALSE;
979 }
980
981 return TRUE;
982 }
983
984 static void
rait_device_open_device(Device * dself,char * device_name,char * device_type G_GNUC_UNUSED,char * device_node)985 rait_device_open_device (Device * dself, char * device_name,
986 char * device_type G_GNUC_UNUSED, char * device_node) {
987
988 if (0 != strcmp(device_node, DEFER_CHILDREN_SENTINEL)) {
989 if (!open_child_devices(dself, device_name, device_node))
990 return;
991
992 /* Chain up. */
993 if (parent_class->open_device) {
994 parent_class->open_device(dself, device_name, device_type, device_node);
995 }
996 }
997 }
998
999 Device *
rait_device_open_from_children(GSList * child_devices)1000 rait_device_open_from_children (GSList *child_devices) {
1001 Device *dself;
1002 RaitDevice *self;
1003 GSList *iter;
1004 char *device_name;
1005 int nfailures;
1006 int i;
1007
1008 /* first, open a RAIT device using the DEFER_CHILDREN_SENTINEL */
1009 dself = device_open("rait:" DEFER_CHILDREN_SENTINEL);
1010 if (!IS_RAIT_DEVICE(dself)) {
1011 return dself;
1012 }
1013
1014 /* set its children */
1015 self = RAIT_DEVICE(dself);
1016 nfailures = 0;
1017 for (i=0, iter = child_devices; iter; i++, iter = iter->next) {
1018 Device *kid = iter->data;
1019
1020 /* a NULL kid is OK -- it opens the device in degraded mode */
1021 if (!kid) {
1022 nfailures++;
1023 self->private->failed = i;
1024 } else {
1025 g_assert(IS_DEVICE(kid));
1026 g_object_ref((GObject *)kid);
1027 }
1028
1029 g_ptr_array_add(self->private->children, kid);
1030 }
1031
1032 /* and set the status based on the children */
1033 switch (nfailures) {
1034 case 0:
1035 self->private->status = RAIT_STATUS_COMPLETE;
1036 break;
1037
1038 case 1:
1039 self->private->status = RAIT_STATUS_DEGRADED;
1040 break;
1041
1042 default:
1043 self->private->status = RAIT_STATUS_FAILED;
1044 device_set_error(dself,
1045 _("more than one child device is missing"),
1046 DEVICE_STATUS_DEVICE_ERROR);
1047 break;
1048 }
1049
1050 /* create a name from the children's names and use it to chain up
1051 * to open_device (we skipped this step in rait_device_open_device) */
1052 device_name = child_device_names_to_rait_name(self);
1053
1054 if (parent_class->open_device) {
1055 parent_class->open_device(dself,
1056 device_name, "rait",
1057 device_name+5); /* (+5 skips "rait:") */
1058 }
1059
1060 return dself;
1061 }
1062
1063 /* A GFunc. */
read_label_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1064 static void read_label_do_op(gpointer data,
1065 gpointer user_data G_GNUC_UNUSED) {
1066 GenericOp * op = data;
1067 op->result = GINT_TO_POINTER(device_read_label(op->child));
1068 }
1069
rait_device_read_label(Device * dself)1070 static DeviceStatusFlags rait_device_read_label(Device * dself) {
1071 RaitDevice * self;
1072 GPtrArray * ops;
1073 DeviceStatusFlags failed_result = 0;
1074 char *failed_errmsg = NULL;
1075 unsigned int i;
1076 Device * first_success = NULL;
1077
1078 self = RAIT_DEVICE(dself);
1079
1080 amfree(dself->volume_time);
1081 amfree(dself->volume_label);
1082 dumpfile_free(dself->volume_header);
1083 dself->volume_header = NULL;
1084
1085 if (rait_device_in_error(self))
1086 return dself->status | DEVICE_STATUS_DEVICE_ERROR;
1087
1088 /* nail down our block size, if we haven't already */
1089 if (!fix_block_size(self))
1090 return FALSE;
1091
1092 ops = make_generic_boolean_op_array(self);
1093
1094 do_rait_child_ops(self, read_label_do_op, ops);
1095
1096 for (i = 0; i < ops->len; i ++) {
1097 GenericOp * op = g_ptr_array_index(ops, i);
1098 DeviceStatusFlags result = GPOINTER_TO_INT(op->result);
1099 if (result == DEVICE_STATUS_SUCCESS) {
1100 if (first_success == NULL) {
1101 /* This is the first successful device. */
1102 first_success = op->child;
1103 } else if (!compare_volume_results(first_success, op->child)) {
1104 /* Doesn't match. :-( */
1105 failed_errmsg = vstrallocf("Inconsistent volume labels/datestamps: "
1106 "Got %s/%s on %s against %s/%s on %s.",
1107 first_success->volume_label,
1108 first_success->volume_time,
1109 first_success->device_name,
1110 op->child->volume_label,
1111 op->child->volume_time,
1112 op->child->device_name);
1113 g_warning("%s", failed_errmsg);
1114 failed_result |= DEVICE_STATUS_VOLUME_ERROR;
1115 }
1116 } else {
1117 failed_result |= result;
1118 }
1119 }
1120
1121 if (failed_result != DEVICE_STATUS_SUCCESS) {
1122 /* We had multiple failures or an inconsistency. */
1123 device_set_error(dself, failed_errmsg, failed_result);
1124 } else {
1125 /* Everything peachy. */
1126 amfree(failed_errmsg);
1127
1128 g_assert(first_success != NULL);
1129 if (first_success->volume_label != NULL) {
1130 dself->volume_label = g_strdup(first_success->volume_label);
1131 }
1132 if (first_success->volume_time != NULL) {
1133 dself->volume_time = g_strdup(first_success->volume_time);
1134 }
1135 if (first_success->volume_header != NULL) {
1136 dself->volume_header = dumpfile_copy(first_success->volume_header);
1137 }
1138 dself->header_block_size = first_success->header_block_size;
1139 }
1140
1141 g_ptr_array_free_full(ops);
1142
1143 return dself->status;
1144 }
1145
1146 typedef struct {
1147 GenericOp base;
1148 DeviceAccessMode mode; /* IN */
1149 char * label; /* IN */
1150 char * timestamp; /* IN */
1151 } StartOp;
1152
1153 /* A GFunc. */
start_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1154 static void start_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1155 DeviceClass *klass;
1156 StartOp * param = data;
1157
1158 klass = DEVICE_GET_CLASS(param->base.child);
1159 if (klass->start) {
1160 param->base.result =
1161 GINT_TO_POINTER((klass->start)(param->base.child,
1162 param->mode, param->label,
1163 param->timestamp));
1164 } else {
1165 param->base.result = FALSE;
1166 }
1167 }
1168
1169 static gboolean
rait_device_configure(Device * dself,gboolean use_global_config)1170 rait_device_configure(Device * dself, gboolean use_global_config)
1171 {
1172 RaitDevice *self = RAIT_DEVICE(dself);
1173 guint i;
1174
1175 for (i = 0; i < self->private->children->len; i ++) {
1176 Device *child;
1177
1178 if ((signed)i == self->private->failed)
1179 continue;
1180
1181 child = g_ptr_array_index(self->private->children, i);
1182 /* unconditionally configure the child without the global
1183 * configuration */
1184 if (!device_configure(child, FALSE))
1185 return FALSE;
1186 }
1187
1188 if (parent_class->configure) {
1189 return parent_class->configure(dself, use_global_config);
1190 }
1191
1192 return TRUE;
1193 }
1194
1195 static gboolean
rait_device_start(Device * dself,DeviceAccessMode mode,char * label,char * timestamp)1196 rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
1197 char * timestamp) {
1198 GPtrArray * ops;
1199 guint i;
1200 gboolean success;
1201 RaitDevice * self;
1202 DeviceStatusFlags total_status;
1203 char *failure_errmsgs = NULL;
1204 char * label_from_device = NULL;
1205
1206 self = RAIT_DEVICE(dself);
1207
1208 if (rait_device_in_error(self)) return FALSE;
1209
1210 /* No starting in degraded mode. */
1211 if (self->private->status != RAIT_STATUS_COMPLETE &&
1212 (mode == ACCESS_WRITE || mode == ACCESS_APPEND)) {
1213 device_set_error(dself,
1214 g_strdup_printf(_("RAIT device %s is read-only "
1215 "because it is in degraded mode.\n"),
1216 dself->device_name),
1217 DEVICE_STATUS_DEVICE_ERROR);
1218 return FALSE;
1219 }
1220
1221 /* nail down our block size, if we haven't already */
1222 if (!fix_block_size(self))
1223 return FALSE;
1224
1225 dself->access_mode = mode;
1226 g_mutex_lock(dself->device_mutex);
1227 dself->in_file = FALSE;
1228 g_mutex_unlock(dself->device_mutex);
1229 amfree(dself->volume_label);
1230 amfree(dself->volume_time);
1231 dumpfile_free(dself->volume_header);
1232 dself->volume_header = NULL;
1233
1234 ops = g_ptr_array_sized_new(self->private->children->len);
1235 for (i = 0; i < self->private->children->len; i ++) {
1236 StartOp * op;
1237
1238 if ((signed)i == self->private->failed) {
1239 continue;
1240 }
1241
1242 op = g_new(StartOp, 1);
1243 op->base.child = g_ptr_array_index(self->private->children, i);
1244 op->mode = mode;
1245 op->label = g_strdup(label);
1246 op->timestamp = g_strdup(timestamp);
1247 g_ptr_array_add(ops, op);
1248 }
1249
1250 do_rait_child_ops(self, start_do_op, ops);
1251
1252 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1253
1254 /* Check results of starting devices; this is mostly about the
1255 * VOLUME_UNLABELED flag. */
1256 total_status = 0;
1257 for (i = 0; i < ops->len; i ++) {
1258 StartOp * op = g_ptr_array_index(ops, i);
1259 Device *child = op->base.child;
1260
1261 total_status |= child->status;
1262 if (child->status != DEVICE_STATUS_SUCCESS) {
1263 /* record the error message and move on. */
1264 append_message(&failure_errmsgs,
1265 g_strdup_printf("%s: %s",
1266 child->device_name,
1267 device_error_or_status(child)));
1268 } else {
1269 if (child->volume_label != NULL && child->volume_time != NULL) {
1270 if (label_from_device) {
1271 if (strcmp(child->volume_label, dself->volume_label) != 0 ||
1272 strcmp(child->volume_time, dself->volume_time) != 0) {
1273 /* Mismatch! (Two devices provided different labels) */
1274 char * this_message =
1275 g_strdup_printf("%s: Label (%s/%s) is different "
1276 "from label (%s/%s) found at "
1277 "device %s",
1278 child->device_name,
1279 child->volume_label,
1280 child->volume_time,
1281 dself->volume_label,
1282 dself->volume_time,
1283 label_from_device);
1284 append_message(&failure_errmsgs, this_message);
1285 total_status |= DEVICE_STATUS_DEVICE_ERROR;
1286 g_warning("RAIT device children have different labels or timestamps");
1287 }
1288 } else {
1289 /* First device with a volume. */
1290 dself->volume_label = g_strdup(child->volume_label);
1291 dself->volume_time = g_strdup(child->volume_time);
1292 dself->volume_header = dumpfile_copy(child->volume_header);
1293 label_from_device = g_strdup(child->device_name);
1294 }
1295 } else {
1296 /* Device problem, it says it succeeded but sets no label? */
1297 char * this_message =
1298 g_strdup_printf("%s: Says label read, but no volume "
1299 "label found.", child->device_name);
1300 g_warning("RAIT device child has NULL volume or label");
1301 append_message(&failure_errmsgs, this_message);
1302 total_status |= DEVICE_STATUS_DEVICE_ERROR;
1303 }
1304 }
1305 }
1306
1307 if (total_status == DEVICE_STATUS_SUCCESS) {
1308 StartOp * op = g_ptr_array_index(ops, 0);
1309 Device *child = op->base.child;
1310 dself->header_block_size = child->header_block_size;
1311 }
1312
1313 amfree(label_from_device);
1314 g_ptr_array_free_full(ops);
1315
1316 dself->status = total_status;
1317
1318 if (total_status != DEVICE_STATUS_SUCCESS || !success) {
1319 device_set_error(dself, failure_errmsgs, total_status);
1320 return FALSE;
1321 }
1322 amfree(failure_errmsgs);
1323 return TRUE;
1324 }
1325
1326 typedef struct {
1327 GenericOp base;
1328 dumpfile_t * info; /* IN */
1329 int fileno;
1330 } StartFileOp;
1331
1332 /* a GFunc */
start_file_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1333 static void start_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1334 StartFileOp * op = data;
1335 op->base.result = GINT_TO_POINTER(device_start_file(op->base.child,
1336 op->info));
1337 op->fileno = op->base.child->file;
1338 if (op->fileno < 1) {
1339 op->base.result = FALSE;
1340 }
1341 }
1342
1343 static gboolean
rait_device_start_file(Device * dself,dumpfile_t * info)1344 rait_device_start_file (Device * dself, dumpfile_t * info) {
1345 GPtrArray * ops;
1346 guint i;
1347 gboolean success;
1348 RaitDevice * self;
1349 int actual_file = -1;
1350
1351 self = RAIT_DEVICE(dself);
1352
1353 if (rait_device_in_error(self)) return FALSE;
1354 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1355
1356 ops = g_ptr_array_sized_new(self->private->children->len);
1357 for (i = 0; i < self->private->children->len; i ++) {
1358 StartFileOp * op;
1359 op = g_new(StartFileOp, 1);
1360 op->base.child = g_ptr_array_index(self->private->children, i);
1361 /* each child gets its own copy of the header, to munge as it
1362 * likes (setting blocksize, at least) */
1363 op->info = dumpfile_copy(info);
1364 g_ptr_array_add(ops, op);
1365 }
1366
1367 do_rait_child_ops(self, start_file_do_op, ops);
1368
1369 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1370
1371 for (i = 0; i < self->private->children->len && success; i ++) {
1372 StartFileOp * op = g_ptr_array_index(ops, i);
1373 if (!op->base.result)
1374 continue;
1375 g_assert(op->fileno >= 1);
1376 if (actual_file < 1) {
1377 actual_file = op->fileno;
1378 }
1379 if (actual_file != op->fileno) {
1380 /* File number mismatch! Aah, my hair is on fire! */
1381 device_set_error(dself,
1382 g_strdup_printf("File number mismatch in "
1383 "rait_device_start_file(): "
1384 "Child %s reported file number "
1385 "%d, another child reported "
1386 "file number %d.",
1387 op->base.child->device_name,
1388 op->fileno, actual_file),
1389 DEVICE_STATUS_DEVICE_ERROR);
1390 success = FALSE;
1391 op->base.result = FALSE;
1392 }
1393 }
1394
1395 for (i = 0; i < ops->len && success; i ++) {
1396 StartFileOp * op = g_ptr_array_index(ops, i);
1397 if (op->info) dumpfile_free(op->info);
1398 }
1399 g_ptr_array_free_full(ops);
1400
1401 if (!success) {
1402 if (!device_in_error(dself)) {
1403 device_set_error(dself, stralloc("One or more devices "
1404 "failed to start_file"),
1405 DEVICE_STATUS_DEVICE_ERROR);
1406 }
1407 return FALSE;
1408 }
1409
1410 g_assert(actual_file >= 1);
1411 dself->file = actual_file;
1412 g_mutex_lock(dself->device_mutex);
1413 dself->in_file = TRUE;
1414 dself->bytes_written = 0;
1415 g_mutex_unlock(dself->device_mutex);
1416
1417 return TRUE;
1418 }
1419
find_simple_params(RaitDevice * self,guint * num_children,guint * data_children)1420 static void find_simple_params(RaitDevice * self,
1421 guint * num_children,
1422 guint * data_children) {
1423 int num, data;
1424
1425 num = self->private->children->len;
1426 if (num > 1)
1427 data = num - 1;
1428 else
1429 data = num;
1430 if (num_children != NULL)
1431 *num_children = num;
1432 if (data_children != NULL)
1433 *data_children = data;
1434 }
1435
1436 typedef struct {
1437 GenericOp base;
1438 guint size; /* IN */
1439 gpointer data; /* IN */
1440 gboolean data_needs_free; /* bookkeeping */
1441 } WriteBlockOp;
1442
1443 /* a GFunc. */
write_block_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1444 static void write_block_do_op(gpointer data,
1445 gpointer user_data G_GNUC_UNUSED) {
1446 WriteBlockOp * op = data;
1447
1448 op->base.result =
1449 GINT_TO_POINTER(device_write_block(op->base.child, op->size, op->data));
1450 }
1451
1452 /* Parity block generation. Performance of this function can be improved
1453 considerably by using larger-sized integers or
1454 assembly-coded vector instructions. Parameters are:
1455 % data - All data chunks in series (chunk_size * num_chunks bytes)
1456 % parity - Allocated space for parity block (chunk_size bytes)
1457 */
make_parity_block(char * data,char * parity,guint chunk_size,guint num_chunks)1458 static void make_parity_block(char * data, char * parity,
1459 guint chunk_size, guint num_chunks) {
1460 guint i;
1461 bzero(parity, chunk_size);
1462 for (i = 0; i < num_chunks - 1; i ++) {
1463 guint j;
1464 for (j = 0; j < chunk_size; j ++) {
1465 parity[j] ^= data[chunk_size*i + j];
1466 }
1467 }
1468 }
1469
1470 /* Does the same thing as make_parity_block, but instead of using a
1471 single memory chunk holding all chunks, it takes a GPtrArray of
1472 chunks. */
make_parity_block_extents(GPtrArray * data,char * parity,guint chunk_size)1473 static void make_parity_block_extents(GPtrArray * data, char * parity,
1474 guint chunk_size) {
1475 guint i;
1476 bzero(parity, chunk_size);
1477 for (i = 0; i < data->len; i ++) {
1478 guint j;
1479 char * data_chunk;
1480 data_chunk = g_ptr_array_index(data, i);
1481 for (j = 0; j < chunk_size; j ++) {
1482 parity[j] ^= data_chunk[j];
1483 }
1484 }
1485 }
1486
1487 /* Does the parity creation algorithm. Allocates and returns a single
1488 device block from a larger RAIT block. chunks and chunk are 1-indexed. */
extract_data_block(char * data,guint size,guint chunks,guint chunk)1489 static char * extract_data_block(char * data, guint size,
1490 guint chunks, guint chunk) {
1491 char * rval;
1492 guint chunk_size;
1493
1494 g_assert(chunks > 0 && chunk > 0 && chunk <= chunks);
1495 g_assert(data != NULL);
1496 g_assert(size > 0 && size % (chunks - 1) == 0);
1497
1498 chunk_size = size / (chunks - 1);
1499 rval = g_malloc(chunk_size);
1500 if (chunks != chunk) {
1501 /* data block. */
1502 memcpy(rval, data + chunk_size * (chunk - 1), chunk_size);
1503 } else {
1504 make_parity_block(data, rval, chunk_size, chunks);
1505 }
1506
1507 return rval;
1508 }
1509
1510 static gboolean
rait_device_write_block(Device * dself,guint size,gpointer data)1511 rait_device_write_block (Device * dself, guint size, gpointer data) {
1512 GPtrArray * ops;
1513 guint i;
1514 gboolean success;
1515 guint data_children, num_children;
1516 gsize blocksize = dself->block_size;
1517 RaitDevice * self;
1518 gboolean last_block = (size < blocksize);
1519
1520 self = RAIT_DEVICE(dself);
1521
1522 if (rait_device_in_error(self)) return FALSE;
1523 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1524
1525 find_simple_params(RAIT_DEVICE(self), &num_children, &data_children);
1526 num_children = self->private->children->len;
1527 if (num_children != 1)
1528 data_children = num_children - 1;
1529 else
1530 data_children = num_children;
1531
1532 g_assert(size % data_children == 0 || last_block);
1533
1534 /* zero out to the end of a short block -- tape devices only write
1535 * whole blocks. */
1536 if (last_block) {
1537 char *new_data;
1538
1539 new_data = g_malloc(blocksize);
1540 memcpy(new_data, data, size);
1541 bzero(new_data + size, blocksize - size);
1542
1543 data = new_data;
1544 size = blocksize;
1545 }
1546
1547 ops = g_ptr_array_sized_new(num_children);
1548 for (i = 0; i < self->private->children->len; i ++) {
1549 WriteBlockOp * op;
1550 op = g_malloc(sizeof(*op));
1551 op->base.child = g_ptr_array_index(self->private->children, i);
1552 op->size = size / data_children;
1553 if (num_children <= 2) {
1554 op->data = data;
1555 op->data_needs_free = FALSE;
1556 } else {
1557 op->data_needs_free = TRUE;
1558 op->data = extract_data_block(data, size, num_children, i + 1);
1559 }
1560 g_ptr_array_add(ops, op);
1561 }
1562
1563 do_rait_child_ops(self, write_block_do_op, ops);
1564
1565 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1566
1567 for (i = 0; i < self->private->children->len; i ++) {
1568 WriteBlockOp * op = g_ptr_array_index(ops, i);
1569 if (op->data_needs_free)
1570 free(op->data);
1571 }
1572
1573 if (last_block) {
1574 amfree(data);
1575 }
1576
1577 g_ptr_array_free_full(ops);
1578
1579 if (!success) {
1580 /* TODO be more specific here */
1581 /* TODO: handle EOM here -- if one or more (or two or more??)
1582 * children have is_eom set, then reflect that in our error
1583 * status. What's more fun is when one device fails and must be isolated at
1584 * the same time another hits EOF. */
1585 device_set_error(dself,
1586 stralloc("One or more devices failed to write_block"),
1587 DEVICE_STATUS_DEVICE_ERROR);
1588 /* this is EOM or an error, so call it EOM */
1589 dself->is_eom = TRUE;
1590 return FALSE;
1591 } else {
1592 dself->block ++;
1593 g_mutex_lock(dself->device_mutex);
1594 dself->bytes_written += size;
1595 g_mutex_unlock(dself->device_mutex);
1596
1597 return TRUE;
1598 }
1599 }
1600
1601 /* A GFunc */
finish_file_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1602 static void finish_file_do_op(gpointer data,
1603 gpointer user_data G_GNUC_UNUSED) {
1604 GenericOp * op = data;
1605 if (op->child) {
1606 op->result = GINT_TO_POINTER(device_finish_file(op->child));
1607 } else {
1608 op->result = FALSE;
1609 }
1610 }
1611
1612 static gboolean
rait_device_finish_file(Device * dself)1613 rait_device_finish_file (Device * dself) {
1614 GPtrArray * ops;
1615 gboolean success;
1616 RaitDevice * self = RAIT_DEVICE(dself);
1617
1618 g_assert(self != NULL);
1619 if (!dself->in_file)
1620 return TRUE;
1621
1622 if (rait_device_in_error(dself)) return FALSE;
1623 if (self->private->status != RAIT_STATUS_COMPLETE) return FALSE;
1624
1625 ops = make_generic_boolean_op_array(self);
1626
1627 do_rait_child_ops(self, finish_file_do_op, ops);
1628
1629 success = g_ptr_array_and(ops, extract_boolean_generic_op);
1630
1631 g_ptr_array_free_full(ops);
1632
1633 if (!success) {
1634 /* TODO: be more specific here */
1635 device_set_error(dself,
1636 g_strdup("One or more devices failed to finish_file"),
1637 DEVICE_STATUS_DEVICE_ERROR);
1638 return FALSE;
1639 }
1640
1641 g_mutex_lock(dself->device_mutex);
1642 dself->in_file = FALSE;
1643 g_mutex_unlock(dself->device_mutex);
1644 return TRUE;
1645 }
1646
1647 typedef struct {
1648 GenericOp base;
1649 guint requested_file; /* IN */
1650 guint actual_file; /* OUT */
1651 } SeekFileOp;
1652
1653 /* a GFunc. */
seek_file_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1654 static void seek_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1655 SeekFileOp * op = data;
1656 op->base.result = device_seek_file(op->base.child, op->requested_file);
1657 op->actual_file = op->base.child->file;
1658 }
1659
1660 static dumpfile_t *
rait_device_seek_file(Device * dself,guint file)1661 rait_device_seek_file (Device * dself, guint file) {
1662 GPtrArray * ops;
1663 guint i;
1664 gboolean success;
1665 dumpfile_t * rval;
1666 RaitDevice * self = RAIT_DEVICE(dself);
1667 guint actual_file = 0;
1668 gboolean in_file = FALSE;
1669
1670 if (rait_device_in_error(self)) return NULL;
1671
1672 dself->is_eof = FALSE;
1673 dself->block = 0;
1674 g_mutex_lock(dself->device_mutex);
1675 dself->in_file = FALSE;
1676 dself->bytes_read = 0;
1677 g_mutex_unlock(dself->device_mutex);
1678
1679 ops = g_ptr_array_sized_new(self->private->children->len);
1680 for (i = 0; i < self->private->children->len; i ++) {
1681 SeekFileOp * op;
1682 if ((int)i == self->private->failed)
1683 continue; /* This device is broken. */
1684 op = g_new(SeekFileOp, 1);
1685 op->base.child = g_ptr_array_index(self->private->children, i);
1686 op->base.child_index = i;
1687 op->requested_file = file;
1688 g_ptr_array_add(ops, op);
1689 }
1690
1691 do_rait_child_ops(self, seek_file_do_op, ops);
1692
1693 /* This checks for NULL values, but we still have to check for
1694 consistant headers. */
1695 success = g_ptr_array_union_robust(RAIT_DEVICE(self),
1696 ops, extract_boolean_pointer_op);
1697
1698 rval = NULL;
1699 for (i = 0; i < ops->len; i ++) {
1700 SeekFileOp * this_op;
1701 dumpfile_t * this_result;
1702 guint this_actual_file;
1703 gboolean this_in_file;
1704
1705 this_op = (SeekFileOp*)g_ptr_array_index(ops, i);
1706
1707 if ((signed)this_op->base.child_index == self->private->failed)
1708 continue;
1709
1710 this_result = this_op->base.result;
1711 this_actual_file = this_op->actual_file;
1712 this_in_file = this_op->base.child->in_file;
1713
1714 if (rval == NULL) {
1715 rval = this_result;
1716 actual_file = this_actual_file;
1717 in_file = this_in_file;
1718 } else {
1719 if (headers_are_equal(rval, this_result) &&
1720 actual_file == this_actual_file &&
1721 in_file == this_in_file) {
1722 /* Do nothing. */
1723 } else {
1724 success = FALSE;
1725 }
1726 free(this_result);
1727 }
1728 }
1729
1730 g_ptr_array_free_full(ops);
1731
1732 if (!success) {
1733 amfree(rval);
1734 /* TODO: be more specific here */
1735 device_set_error(dself,
1736 g_strdup("One or more devices failed to seek_file"),
1737 DEVICE_STATUS_DEVICE_ERROR);
1738 return NULL;
1739 }
1740
1741 /* update our state */
1742 g_mutex_lock(dself->device_mutex);
1743 dself->in_file = in_file;
1744 g_mutex_unlock(dself->device_mutex);
1745 dself->file = actual_file;
1746
1747 return rval;
1748 }
1749
1750 typedef struct {
1751 GenericOp base;
1752 guint64 block; /* IN */
1753 } SeekBlockOp;
1754
1755 /* a GFunc. */
seek_block_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1756 static void seek_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
1757 SeekBlockOp * op = data;
1758 op->base.result =
1759 GINT_TO_POINTER(device_seek_block(op->base.child, op->block));
1760 }
1761
1762 static gboolean
rait_device_seek_block(Device * dself,guint64 block)1763 rait_device_seek_block (Device * dself, guint64 block) {
1764 GPtrArray * ops;
1765 guint i;
1766 gboolean success;
1767
1768 RaitDevice * self = RAIT_DEVICE(dself);
1769
1770 if (rait_device_in_error(self)) return FALSE;
1771
1772 ops = g_ptr_array_sized_new(self->private->children->len);
1773 for (i = 0; i < self->private->children->len; i ++) {
1774 SeekBlockOp * op;
1775 if ((int)i == self->private->failed)
1776 continue; /* This device is broken. */
1777 op = g_new(SeekBlockOp, 1);
1778 op->base.child = g_ptr_array_index(self->private->children, i);
1779 op->base.child_index = i;
1780 op->block = block;
1781 g_ptr_array_add(ops, op);
1782 }
1783
1784 do_rait_child_ops(self, seek_block_do_op, ops);
1785
1786 success = g_ptr_array_union_robust(RAIT_DEVICE(self),
1787 ops, extract_boolean_generic_op);
1788
1789 g_ptr_array_free_full(ops);
1790
1791 if (!success) {
1792 /* TODO: be more specific here */
1793 device_set_error(dself,
1794 stralloc("One or more devices failed to seek_block"),
1795 DEVICE_STATUS_DEVICE_ERROR);
1796 return FALSE;
1797 }
1798
1799 dself->block = block;
1800 return TRUE;
1801 }
1802
1803 typedef struct {
1804 GenericOp base;
1805 gpointer buffer; /* IN */
1806 int read_size; /* IN/OUT -- note not a pointer */
1807 int desired_read_size; /* bookkeeping */
1808 } ReadBlockOp;
1809
1810 /* a GFunc. */
read_block_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)1811 static void read_block_do_op(gpointer data,
1812 gpointer user_data G_GNUC_UNUSED) {
1813 ReadBlockOp * op = data;
1814 op->base.result =
1815 GINT_TO_POINTER(device_read_block(op->base.child, op->buffer,
1816 &(op->read_size)));
1817 if (op->read_size > op->desired_read_size) {
1818 g_warning("child device %s tried to return an oversized block, which the RAIT device does not support",
1819 op->base.child->device_name);
1820 }
1821 }
1822
1823 /* A BooleanExtractor. This one checks for a successful read. */
extract_boolean_read_block_op_data(gpointer data)1824 static gboolean extract_boolean_read_block_op_data(gpointer data) {
1825 ReadBlockOp * op = data;
1826 return GPOINTER_TO_INT(op->base.result) == op->desired_read_size;
1827 }
1828
1829 /* A BooleanExtractor. This one checks for EOF. */
extract_boolean_read_block_op_eof(gpointer data)1830 static gboolean extract_boolean_read_block_op_eof(gpointer data) {
1831 ReadBlockOp * op = data;
1832 return op->base.child->is_eof;
1833 }
1834
1835 /* Counts the number of elements in an array matching a given proposition. */
g_ptr_array_count(GPtrArray * array,BooleanExtractor filter)1836 static int g_ptr_array_count(GPtrArray * array, BooleanExtractor filter) {
1837 int rval;
1838 unsigned int i;
1839 rval = 0;
1840 for (i = 0; i < array->len ; i++) {
1841 if (filter(g_ptr_array_index(array, i)))
1842 rval ++;
1843 }
1844 return rval;
1845 }
1846
raid_block_reconstruction(RaitDevice * self,GPtrArray * ops,gpointer buf,size_t bufsize)1847 static gboolean raid_block_reconstruction(RaitDevice * self, GPtrArray * ops,
1848 gpointer buf, size_t bufsize) {
1849 guint num_children, data_children;
1850 gsize blocksize;
1851 gsize child_blocksize;
1852 guint i;
1853 int parity_child;
1854 gpointer parity_block = NULL;
1855 gboolean success;
1856
1857 success = TRUE;
1858
1859 blocksize = DEVICE(self)->block_size;
1860 find_simple_params(self, &num_children, &data_children);
1861
1862 if (num_children > 1)
1863 parity_child = num_children - 1;
1864 else
1865 parity_child = -1;
1866
1867 child_blocksize = blocksize / data_children;
1868
1869 for (i = 0; i < ops->len; i ++) {
1870 ReadBlockOp * op = g_ptr_array_index(ops, i);
1871 if (!extract_boolean_read_block_op_data(op))
1872 continue;
1873 if ((int)(op->base.child_index) == parity_child) {
1874 parity_block = op->buffer;
1875 } else {
1876 g_assert(child_blocksize * (op->base.child_index+1) <= bufsize);
1877 memcpy((char *)buf + child_blocksize * op->base.child_index, op->buffer,
1878 child_blocksize);
1879 }
1880 }
1881 if (self->private->status == RAIT_STATUS_COMPLETE) {
1882 g_assert(parity_block != NULL); /* should have found parity_child */
1883
1884 if (num_children >= 2) {
1885 /* Verify the parity block. This code is inefficient but
1886 does the job for the 2-device case, too. */
1887 gpointer constructed_parity;
1888 GPtrArray * data_extents;
1889
1890 constructed_parity = g_malloc(child_blocksize);
1891 data_extents = g_ptr_array_sized_new(data_children);
1892 for (i = 0; i < data_children; i ++) {
1893 ReadBlockOp * op = g_ptr_array_index(ops, i);
1894 g_assert(extract_boolean_read_block_op_data(op));
1895 if ((int)op->base.child_index == parity_child)
1896 continue;
1897 g_ptr_array_add(data_extents, op->buffer);
1898 }
1899 make_parity_block_extents(data_extents, constructed_parity,
1900 child_blocksize);
1901
1902 if (0 != memcmp(parity_block, constructed_parity,
1903 child_blocksize)) {
1904 device_set_error(DEVICE(self),
1905 stralloc(_("RAIT is inconsistent: Parity block did not match data blocks.")),
1906 DEVICE_STATUS_DEVICE_ERROR);
1907 /* TODO: can't we just isolate the device in this case? */
1908 success = FALSE;
1909 }
1910 g_ptr_array_free(data_extents, TRUE);
1911 amfree(constructed_parity);
1912 } else { /* do nothing. */ }
1913 } else if (self->private->status == RAIT_STATUS_DEGRADED) {
1914 g_assert(self->private->failed >= 0 && self->private->failed < (int)num_children);
1915 /* We are in degraded mode. What's missing? */
1916 if (self->private->failed == parity_child) {
1917 /* do nothing. */
1918 } else if (num_children >= 2) {
1919 /* Reconstruct failed block from parity block. */
1920 GPtrArray * data_extents = g_ptr_array_new();
1921
1922 for (i = 0; i < data_children; i ++) {
1923 ReadBlockOp * op = g_ptr_array_index(ops, i);
1924 if (!extract_boolean_read_block_op_data(op))
1925 continue;
1926 g_ptr_array_add(data_extents, op->buffer);
1927 }
1928
1929 /* Conveniently, the reconstruction is the same procedure
1930 as the parity generation. This even works if there is
1931 only one remaining device! */
1932 make_parity_block_extents(data_extents,
1933 (char *)buf + (child_blocksize *
1934 self->private->failed),
1935 child_blocksize);
1936
1937 /* The array members belong to our ops argument. */
1938 g_ptr_array_free(data_extents, TRUE);
1939 } else {
1940 g_assert_not_reached();
1941 }
1942 } else {
1943 /* device is already in FAILED state -- we shouldn't even be here */
1944 success = FALSE;
1945 }
1946 return success;
1947 }
1948
1949 static int
rait_device_read_block(Device * dself,gpointer buf,int * size)1950 rait_device_read_block (Device * dself, gpointer buf, int * size) {
1951 GPtrArray * ops;
1952 guint i;
1953 gboolean success;
1954 guint num_children, data_children;
1955 gsize blocksize = dself->block_size;
1956 gsize child_blocksize;
1957
1958 RaitDevice * self = RAIT_DEVICE(dself);
1959
1960 if (rait_device_in_error(self)) return -1;
1961
1962 find_simple_params(self, &num_children, &data_children);
1963
1964 /* tell caller they haven't given us a big enough buffer */
1965 if (blocksize > (gsize)*size) {
1966 g_assert(blocksize < INT_MAX);
1967 *size = (int)blocksize;
1968 return 0;
1969 }
1970
1971 g_assert(blocksize % data_children == 0); /* see find_block_size */
1972 child_blocksize = blocksize / data_children;
1973
1974 ops = g_ptr_array_sized_new(num_children);
1975 for (i = 0; i < num_children; i ++) {
1976 ReadBlockOp * op;
1977 if ((int)i == self->private->failed)
1978 continue; /* This device is broken. */
1979 op = g_new(ReadBlockOp, 1);
1980 op->base.child = g_ptr_array_index(self->private->children, i);
1981 op->base.child_index = i;
1982 op->buffer = g_malloc(child_blocksize);
1983 op->desired_read_size = op->read_size = child_blocksize;
1984 g_ptr_array_add(ops, op);
1985 }
1986
1987 do_rait_child_ops(self, read_block_do_op, ops);
1988
1989 if (g_ptr_array_count(ops, extract_boolean_read_block_op_data)) {
1990 if (!g_ptr_array_union_robust(RAIT_DEVICE(self),
1991 ops,
1992 extract_boolean_read_block_op_data)) {
1993 /* TODO: be more specific */
1994 device_set_error(dself,
1995 stralloc(_("Error occurred combining blocks from child devices")),
1996 DEVICE_STATUS_DEVICE_ERROR);
1997 success = FALSE;
1998 } else {
1999 /* raid_block_reconstruction sets the error status if necessary */
2000 success = raid_block_reconstruction(RAIT_DEVICE(self),
2001 ops, buf, (size_t)*size);
2002 }
2003 } else {
2004 success = FALSE;
2005 if (g_ptr_array_union_robust(RAIT_DEVICE(self),
2006 ops,
2007 extract_boolean_read_block_op_eof)) {
2008 device_set_error(dself,
2009 stralloc(_("EOF")),
2010 DEVICE_STATUS_SUCCESS);
2011 dself->is_eof = TRUE;
2012 g_mutex_lock(dself->device_mutex);
2013 dself->in_file = FALSE;
2014 g_mutex_unlock(dself->device_mutex);
2015 } else {
2016 device_set_error(dself,
2017 stralloc(_("All child devices failed to read, but not all are at eof")),
2018 DEVICE_STATUS_DEVICE_ERROR);
2019 }
2020 }
2021
2022 for (i = 0; i < ops->len; i ++) {
2023 ReadBlockOp * op = g_ptr_array_index(ops, i);
2024 amfree(op->buffer);
2025 }
2026 g_ptr_array_free_full(ops);
2027
2028 if (success) {
2029 dself->block++;
2030 *size = blocksize;
2031 g_mutex_lock(dself->device_mutex);
2032 dself->bytes_read += blocksize;
2033 g_mutex_unlock(dself->device_mutex);
2034 return blocksize;
2035 } else {
2036 return -1;
2037 }
2038 }
2039
2040 /* property utility functions */
2041
2042 typedef struct {
2043 GenericOp base;
2044 DevicePropertyId id; /* IN */
2045 GValue value; /* IN/OUT */
2046 PropertySurety surety; /* IN (for set) */
2047 PropertySource source; /* IN (for set) */
2048 } PropertyOp;
2049
2050 /* Creates a GPtrArray of PropertyOf for a get or set operation. */
make_property_op_array(RaitDevice * self,DevicePropertyId id,GValue * value,PropertySurety surety,PropertySource source)2051 static GPtrArray * make_property_op_array(RaitDevice * self,
2052 DevicePropertyId id,
2053 GValue * value,
2054 PropertySurety surety,
2055 PropertySource source) {
2056 guint i;
2057 GPtrArray * ops;
2058 ops = g_ptr_array_sized_new(self->private->children->len);
2059 for (i = 0; i < self->private->children->len; i ++) {
2060 PropertyOp * op;
2061
2062 if ((signed)i == self->private->failed) {
2063 continue;
2064 }
2065
2066 op = g_new(PropertyOp, 1);
2067 op->base.child = g_ptr_array_index(self->private->children, i);
2068 op->id = id;
2069 bzero(&(op->value), sizeof(op->value));
2070 if (value != NULL) {
2071 g_value_unset_copy(value, &(op->value));
2072 }
2073 op->surety = surety;
2074 op->source = source;
2075 g_ptr_array_add(ops, op);
2076 }
2077
2078 return ops;
2079 }
2080
2081 /* A GFunc. */
property_get_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)2082 static void property_get_do_op(gpointer data,
2083 gpointer user_data G_GNUC_UNUSED) {
2084 PropertyOp * op = data;
2085
2086 bzero(&(op->value), sizeof(op->value));
2087 op->base.result =
2088 GINT_TO_POINTER(device_property_get(op->base.child, op->id,
2089 &(op->value)));
2090 }
2091
2092 /* A GFunc. */
property_set_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)2093 static void property_set_do_op(gpointer data,
2094 gpointer user_data G_GNUC_UNUSED) {
2095 PropertyOp * op = data;
2096
2097 op->base.result =
2098 GINT_TO_POINTER(device_property_set_ex(op->base.child, op->id,
2099 &(op->value), op->surety,
2100 op->source));
2101 g_value_unset(&(op->value));
2102 }
2103
2104 /* PropertyGetFns and PropertySetFns */
2105
2106 static gboolean
property_get_block_size_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2107 property_get_block_size_fn(Device *dself,
2108 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2109 PropertySurety *surety, PropertySource *source)
2110 {
2111 RaitDevice *self = RAIT_DEVICE(dself);
2112 gsize my_block_size;
2113
2114 if (dself->block_size_source != PROPERTY_SOURCE_DEFAULT) {
2115 my_block_size = dself->block_size;
2116
2117 if (surety)
2118 *surety = dself->block_size_surety;
2119 } else {
2120 gsize child_block_size;
2121 child_block_size = calculate_block_size_from_children(self,
2122 &my_block_size);
2123 if (child_block_size == 0)
2124 return FALSE;
2125
2126 if (surety)
2127 *surety = PROPERTY_SURETY_BAD; /* may still change */
2128 }
2129
2130 if (val) {
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);
2134 }
2135
2136 if (source)
2137 *source = dself->block_size_source;
2138
2139 return TRUE;
2140 }
2141
2142 static gboolean
property_set_block_size_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety surety,PropertySource source)2143 property_set_block_size_fn(Device *dself,
2144 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2145 PropertySurety surety, PropertySource source)
2146 {
2147 RaitDevice *self = RAIT_DEVICE(dself);
2148 gint my_block_size = g_value_get_int(val);
2149 guint data_children;
2150
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);
2156 return FALSE;
2157 }
2158
2159 dself->block_size = my_block_size;
2160 dself->block_size_source = source;
2161 dself->block_size_surety = surety;
2162
2163 if (!fix_block_size(self))
2164 return FALSE;
2165
2166 return TRUE;
2167 }
2168
2169 static gboolean
property_get_canonical_name_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2170 property_get_canonical_name_fn(Device *dself,
2171 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2172 PropertySurety *surety, PropertySource *source)
2173 {
2174 RaitDevice *self = RAIT_DEVICE(dself);
2175 char *canonical = child_device_names_to_rait_name(self);
2176
2177 if (val) {
2178 g_value_unset_init(val, G_TYPE_STRING);
2179 g_value_set_string(val, canonical);
2180 g_free(canonical);
2181 }
2182
2183 if (surety)
2184 *surety = PROPERTY_SURETY_GOOD;
2185
2186 if (source)
2187 *source = PROPERTY_SOURCE_DETECTED;
2188
2189 return TRUE;
2190 }
2191
2192 static gboolean
property_get_concurrency_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2193 property_get_concurrency_fn(Device *dself,
2194 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2195 PropertySurety *surety, PropertySource *source)
2196 {
2197 RaitDevice *self = RAIT_DEVICE(dself);
2198 ConcurrencyParadigm result;
2199 guint i;
2200 GPtrArray * ops;
2201 gboolean success;
2202
2203 ops = make_property_op_array(self, PROPERTY_CONCURRENCY, NULL, 0, 0);
2204 do_rait_child_ops(self, property_get_do_op, ops);
2205
2206 /* find the most restrictive paradigm acceptable to all
2207 * child devices */
2208 result = CONCURRENCY_PARADIGM_RANDOM_ACCESS;
2209 success = TRUE;
2210 for (i = 0; i < ops->len; i ++) {
2211 ConcurrencyParadigm cur;
2212 PropertyOp * op = g_ptr_array_index(ops, i);
2213
2214 if (!op->base.result
2215 || G_VALUE_TYPE(&(op->value)) != CONCURRENCY_PARADIGM_TYPE) {
2216 success = FALSE;
2217 break;
2218 }
2219
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;
2230 } else {
2231 success = FALSE;
2232 break;
2233 }
2234 }
2235
2236 g_ptr_array_free_full(ops);
2237
2238 if (success) {
2239 if (val) {
2240 g_value_unset_init(val, CONCURRENCY_PARADIGM_TYPE);
2241 g_value_set_enum(val, result);
2242 }
2243
2244 if (surety)
2245 *surety = PROPERTY_SURETY_GOOD;
2246
2247 if (source)
2248 *source = PROPERTY_SOURCE_DETECTED;
2249 }
2250
2251 return success;
2252 }
2253
2254 static gboolean
property_get_streaming_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2255 property_get_streaming_fn(Device *dself,
2256 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2257 PropertySurety *surety, PropertySource *source)
2258 {
2259 RaitDevice *self = RAIT_DEVICE(dself);
2260 StreamingRequirement result;
2261 guint i;
2262 GPtrArray * ops;
2263 gboolean success;
2264
2265 ops = make_property_op_array(self, PROPERTY_STREAMING, NULL, 0, 0);
2266 do_rait_child_ops(self, property_get_do_op, ops);
2267
2268 /* combine the child streaming requirements, selecting the strongest
2269 * requirement of the bunch. */
2270 result = STREAMING_REQUIREMENT_NONE;
2271 success = TRUE;
2272 for (i = 0; i < ops->len; i ++) {
2273 StreamingRequirement cur;
2274 PropertyOp * op = g_ptr_array_index(ops, i);
2275
2276 if (!op->base.result
2277 || G_VALUE_TYPE(&(op->value)) != STREAMING_REQUIREMENT_TYPE) {
2278 success = FALSE;
2279 break;
2280 }
2281
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;
2292 } else {
2293 success = FALSE;
2294 break;
2295 }
2296 }
2297
2298 g_ptr_array_free_full(ops);
2299
2300 if (success) {
2301 if (val) {
2302 g_value_unset_init(val, STREAMING_REQUIREMENT_TYPE);
2303 g_value_set_enum(val, result);
2304 }
2305
2306 if (surety)
2307 *surety = PROPERTY_SURETY_GOOD;
2308
2309 if (source)
2310 *source = PROPERTY_SOURCE_DETECTED;
2311 }
2312
2313 return success;
2314 }
2315
2316 static gboolean
property_get_boolean_and_fn(Device * dself,DevicePropertyBase * base,GValue * val,PropertySurety * surety,PropertySource * source)2317 property_get_boolean_and_fn(Device *dself,
2318 DevicePropertyBase *base, GValue *val,
2319 PropertySurety *surety, PropertySource *source)
2320 {
2321 RaitDevice *self = RAIT_DEVICE(dself);
2322 gboolean result;
2323 guint i;
2324 GPtrArray * ops;
2325 gboolean success;
2326
2327 ops = make_property_op_array(self, base->ID, NULL, 0, 0);
2328 do_rait_child_ops(self, property_get_do_op, ops);
2329
2330 /* combine the child values, applying a simple AND */
2331 result = TRUE;
2332 success = TRUE;
2333 for (i = 0; i < ops->len; i ++) {
2334 PropertyOp * op = g_ptr_array_index(ops, i);
2335
2336 if (!op->base.result || !G_VALUE_HOLDS_BOOLEAN(&(op->value))) {
2337 success = FALSE;
2338 break;
2339 }
2340
2341 if (!g_value_get_boolean(&(op->value))) {
2342 result = FALSE;
2343 break;
2344 }
2345 }
2346
2347 g_ptr_array_free_full(ops);
2348
2349 if (success) {
2350 if (val) {
2351 g_value_unset_init(val, G_TYPE_BOOLEAN);
2352 g_value_set_boolean(val, result);
2353 }
2354
2355 if (surety)
2356 *surety = PROPERTY_SURETY_GOOD;
2357
2358 if (source)
2359 *source = PROPERTY_SOURCE_DETECTED;
2360 }
2361
2362 return success;
2363 }
2364
2365 static gboolean
property_get_medium_access_type_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2366 property_get_medium_access_type_fn(Device *dself,
2367 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2368 PropertySurety *surety, PropertySource *source)
2369 {
2370 RaitDevice *self = RAIT_DEVICE(dself);
2371 MediaAccessMode result;
2372 guint i;
2373 GPtrArray * ops;
2374 gboolean success;
2375
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);
2378
2379 /* combine the modes as best we can */
2380 result = 0;
2381 success = TRUE;
2382 for (i = 0; i < ops->len; i ++) {
2383 MediaAccessMode cur;
2384 PropertyOp * op = g_ptr_array_index(ops, i);
2385
2386 if (!op->base.result || G_VALUE_TYPE(&(op->value)) != MEDIA_ACCESS_MODE_TYPE) {
2387 success = FALSE;
2388 break;
2389 }
2390
2391 cur = g_value_get_enum(&(op->value));
2392
2393 if (i == 0) {
2394 result = cur;
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
2400 can only write. */
2401 success = FALSE;
2402 break;
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;
2415 } else {
2416 success = FALSE;
2417 break;
2418 }
2419 }
2420
2421 g_ptr_array_free_full(ops);
2422
2423 if (success) {
2424 if (val) {
2425 g_value_unset_init(val, MEDIA_ACCESS_MODE_TYPE);
2426 g_value_set_enum(val, result);
2427 }
2428
2429 if (surety)
2430 *surety = PROPERTY_SURETY_GOOD;
2431
2432 if (source)
2433 *source = PROPERTY_SOURCE_DETECTED;
2434 }
2435
2436 return success;
2437 }
2438
2439 static gboolean
property_get_max_volume_usage_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)2440 property_get_max_volume_usage_fn(Device *dself,
2441 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2442 PropertySurety *surety, PropertySource *source)
2443 {
2444 RaitDevice *self = RAIT_DEVICE(dself);
2445 guint64 result;
2446 guint i;
2447 GPtrArray * ops;
2448 guint data_children;
2449
2450 ops = make_property_op_array(self, PROPERTY_MAX_VOLUME_USAGE, NULL, 0, 0);
2451 do_rait_child_ops(self, property_get_do_op, ops);
2452
2453 /* look for the smallest value that is set */
2454 result = 0;
2455 for (i = 0; i < ops->len; i ++) {
2456 guint64 cur;
2457 PropertyOp * op = g_ptr_array_index(ops, i);
2458
2459 if (!op->base.result || !G_VALUE_HOLDS_UINT64(&(op->value))) {
2460 continue; /* ignore children without this property */
2461 }
2462
2463 cur = g_value_get_uint64(&(op->value));
2464
2465 if (!result || (cur && cur < result)) {
2466 result = cur;
2467 }
2468 }
2469
2470 g_ptr_array_free_full(ops);
2471
2472 if (result) {
2473 /* result contains the minimum usage on any child. We can use that space
2474 * on each of our data children, so the total is larger */
2475 find_simple_params(self, NULL, &data_children);
2476 result *= data_children;
2477
2478 if (val) {
2479 g_value_unset_init(val, G_TYPE_UINT64);
2480 g_value_set_uint64(val, result);
2481 }
2482
2483 if (surety)
2484 *surety = PROPERTY_SURETY_GOOD;
2485
2486 if (source)
2487 *source = PROPERTY_SOURCE_DETECTED;
2488
2489 return TRUE;
2490 } else {
2491 /* no result from any children, so we effectively don't have this property */
2492 return FALSE;
2493 }
2494 }
2495
2496 static gboolean
property_set_max_volume_usage_fn(Device * dself,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety surety,PropertySource source)2497 property_set_max_volume_usage_fn(Device *dself,
2498 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
2499 PropertySurety surety, PropertySource source)
2500 {
2501 RaitDevice *self = RAIT_DEVICE(dself);
2502 guint64 parent_usage;
2503 guint64 child_usage;
2504 GValue child_val;
2505 guint i;
2506 gboolean success;
2507 GPtrArray * ops;
2508 guint data_children;
2509
2510 parent_usage = g_value_get_uint64(val);
2511 find_simple_params(self, NULL, &data_children);
2512
2513 child_usage = parent_usage / data_children;
2514
2515 bzero(&child_val, sizeof(child_val));
2516 g_value_init(&child_val, G_TYPE_UINT64);
2517 g_value_set_uint64(&child_val, child_usage);
2518
2519 ops = make_property_op_array(self, PROPERTY_MAX_VOLUME_USAGE,
2520 &child_val, surety, source);
2521 do_rait_child_ops(self, property_set_do_op, ops);
2522
2523 /* if any of the kids succeeded, then we did too */
2524 success = FALSE;
2525 for (i = 0; i < ops->len; i ++) {
2526 PropertyOp * op = g_ptr_array_index(ops, i);
2527
2528 if (op->base.result) {
2529 success = TRUE;
2530 break;
2531 }
2532 }
2533
2534 g_ptr_array_free_full(ops);
2535
2536 return success;
2537 }
2538
2539 typedef struct {
2540 GenericOp base;
2541 guint filenum;
2542 } RecycleFileOp;
2543
2544 /* A GFunc */
recycle_file_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)2545 static void recycle_file_do_op(gpointer data,
2546 gpointer user_data G_GNUC_UNUSED) {
2547 RecycleFileOp * op = data;
2548 op->base.result =
2549 GINT_TO_POINTER(device_recycle_file(op->base.child, op->filenum));
2550 }
2551
2552 static gboolean
rait_device_recycle_file(Device * dself,guint filenum)2553 rait_device_recycle_file (Device * dself, guint filenum) {
2554 GPtrArray * ops;
2555 guint i;
2556 gboolean success;
2557
2558 RaitDevice * self = RAIT_DEVICE(dself);
2559
2560 if (rait_device_in_error(self)) return FALSE;
2561
2562 ops = g_ptr_array_sized_new(self->private->children->len);
2563 for (i = 0; i < self->private->children->len; i ++) {
2564 RecycleFileOp * op;
2565 op = g_new(RecycleFileOp, 1);
2566 op->base.child = g_ptr_array_index(self->private->children, i);
2567 op->filenum = filenum;
2568 g_ptr_array_add(ops, op);
2569 }
2570
2571 do_rait_child_ops(self, recycle_file_do_op, ops);
2572
2573 success = g_ptr_array_and(ops, extract_boolean_generic_op);
2574
2575 g_ptr_array_free_full(ops);
2576
2577 if (!success) {
2578 /* TODO: be more specific here */
2579 device_set_error(dself,
2580 stralloc(_("One or more devices failed to recycle_file")),
2581 DEVICE_STATUS_DEVICE_ERROR);
2582 return FALSE;
2583 }
2584 return TRUE;
2585 }
2586
2587 /* GFunc */
finish_do_op(gpointer data,gpointer user_data G_GNUC_UNUSED)2588 static void finish_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
2589 GenericOp * op = data;
2590 op->result = GINT_TO_POINTER(device_finish(op->child));
2591 }
2592
2593 static gboolean
rait_device_finish(Device * self)2594 rait_device_finish (Device * self) {
2595 GPtrArray * ops;
2596 gboolean success;
2597 gboolean rval = TRUE;
2598
2599 rval = !rait_device_in_error(self);
2600
2601 ops = make_generic_boolean_op_array(RAIT_DEVICE(self));
2602
2603 do_rait_child_ops(RAIT_DEVICE(self), finish_do_op, ops);
2604
2605 success = g_ptr_array_and(ops, extract_boolean_generic_op);
2606 if (!success)
2607 rval = FALSE;
2608
2609 g_ptr_array_free_full(ops);
2610
2611 self->access_mode = ACCESS_NULL;
2612
2613 return rval;
2614 }
2615
2616 static Device *
rait_device_factory(char * device_name,char * device_type,char * device_node)2617 rait_device_factory (char * device_name, char * device_type, char * device_node) {
2618 Device * rval;
2619 g_assert(0 == strcmp(device_type, "rait"));
2620 rval = DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL));
2621 device_open_device(rval, device_name, device_type, device_node);
2622 return rval;
2623 }
2624
2625 void
rait_device_register(void)2626 rait_device_register (void) {
2627 static const char * device_prefix_list[] = {"rait", NULL};
2628 register_device(rait_device_factory, device_prefix_list);
2629 }
2630