Imported Upstream version 3.3.2
[debian/amanda] / device-src / rait-device.c
index daeb5c8855f09c7a1b33870df25e610f453e590d..fa174580e35c2b5b0834c7c761064c50e50a6e69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007,2008,2009 Zmanda, Inc.  All Rights Reserved.
+ * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
 /* The RAIT device encapsulates some number of other devices into a single
  * redundant device. */
 
-#include <amanda.h>
+#include "amanda.h"
 #include "property.h"
 #include "util.h"
 #include <glib.h>
 #include "glib-util.h"
 #include "device.h"
 #include "fileheader.h"
-#include "semaphore.h"
+#include "amsemaphore.h"
 
 /* Just a note about the failure mode of different operations:
    - Recovers from a failure (enters degraded mode)
@@ -115,7 +115,7 @@ typedef struct RaitDevicePrivate_s {
 
     /* value of this semaphore is the number of threaded operations
      * in progress */
-    semaphore_t *threads_sem;
+    amsemaphore_t *threads_sem;
 #endif
 } RaitDevicePrivate;
 
@@ -199,10 +199,6 @@ static gboolean property_get_medium_access_type_fn(Device *self,
     DevicePropertyBase *base, GValue *val,
     PropertySurety *surety, PropertySource *source);
 
-static gboolean property_get_free_space_fn(Device *self,
-    DevicePropertyBase *base, GValue *val,
-    PropertySurety *surety, PropertySource *source);
-
 static gboolean property_get_max_volume_usage_fn(Device *self,
     DevicePropertyBase *base, GValue *val,
     PropertySurety *surety, PropertySource *source);
@@ -290,7 +286,7 @@ rait_device_finalize(GObject *obj_self)
     }
 
     if (PRIVATE(self)->threads_sem)
-       semaphore_free(PRIVATE(self)->threads_sem);
+       amsemaphore_free(PRIVATE(self)->threads_sem);
 #endif
     amfree(self->private);
 }
@@ -383,16 +379,16 @@ rait_device_base_init (RaitDeviceClass * c)
            PROPERTY_ACCESS_GET_MASK,
            property_get_boolean_and_fn, NULL);
 
-    device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
+    device_class_register_property(device_class, PROPERTY_LEOM,
            PROPERTY_ACCESS_GET_MASK,
-           property_get_medium_access_type_fn, NULL);
+           property_get_boolean_and_fn, NULL);
 
-    device_class_register_property(device_class, PROPERTY_FREE_SPACE,
+    device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
            PROPERTY_ACCESS_GET_MASK,
-           property_get_free_space_fn, NULL);
+           property_get_medium_access_type_fn, NULL);
 
     device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
-           PROPERTY_ACCESS_GET_MASK,
+           PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
            property_get_max_volume_usage_fn,
            property_set_max_volume_usage_fn);
 }
@@ -430,7 +426,7 @@ static gpointer rait_thread_pool_func(gpointer data) {
            inf->data = NULL;
 
             /* indicate that we're finished; will not block */
-           semaphore_down(inf->private->threads_sem);
+           amsemaphore_down(inf->private->threads_sem);
        }
     }
     g_mutex_unlock(inf->mutex);
@@ -441,7 +437,7 @@ static void do_thread_pool_op(RaitDevice *self, GFunc func, GPtrArray * ops) {
     guint i;
 
     if (PRIVATE(self)->threads_sem == NULL)
-       PRIVATE(self)->threads_sem = semaphore_new_with_value(0);
+       PRIVATE(self)->threads_sem = amsemaphore_new_with_value(0);
 
     if (PRIVATE(self)->threads == NULL)
        PRIVATE(self)->threads = g_array_sized_new(FALSE, TRUE,
@@ -453,7 +449,7 @@ static void do_thread_pool_op(RaitDevice *self, GFunc func, GPtrArray * ops) {
        g_array_set_size(PRIVATE(self)->threads, ops->len);
 
     /* the semaphore will hit zero when each thread has decremented it */
-    semaphore_force_set(PRIVATE(self)->threads_sem, ops->len);
+    amsemaphore_force_set(PRIVATE(self)->threads_sem, ops->len);
 
     for (i = 0; i < ops->len; i++) {
        ThreadInfo *inf = &g_array_index(PRIVATE(self)->threads, ThreadInfo, i);
@@ -473,7 +469,7 @@ static void do_thread_pool_op(RaitDevice *self, GFunc func, GPtrArray * ops) {
     }
 
     /* wait until semaphore hits zero */
-    semaphore_wait_empty(PRIVATE(self)->threads_sem);
+    amsemaphore_wait_empty(PRIVATE(self)->threads_sem);
 }
 
 #else /* USE_INTERNAL_THREADPOOL */
@@ -1138,6 +1134,7 @@ static DeviceStatusFlags rait_device_read_label(Device * dself) {
         if (first_success->volume_header != NULL) {
             dself->volume_header = dumpfile_copy(first_success->volume_header);
         }
+       dself->header_block_size = first_success->header_block_size;
     }
 
     g_ptr_array_free_full(ops);
@@ -1225,7 +1222,9 @@ rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
        return FALSE;
 
     dself->access_mode = mode;
+    g_mutex_lock(dself->device_mutex);
     dself->in_file = FALSE;
+    g_mutex_unlock(dself->device_mutex);
     amfree(dself->volume_label);
     amfree(dself->volume_time);
     dumpfile_free(dself->volume_header);
@@ -1304,6 +1303,12 @@ rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
        }
     }
 
+    if (total_status == DEVICE_STATUS_SUCCESS) {
+       StartOp * op = g_ptr_array_index(ops, 0);
+       Device *child = op->base.child;
+       dself->header_block_size = child->header_block_size;
+    }
+
     amfree(label_from_device);
     g_ptr_array_free_full(ops);
 
@@ -1313,7 +1318,6 @@ rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
        device_set_error(dself, failure_errmsgs, total_status);
         return FALSE;
     }
-
     amfree(failure_errmsgs);
     return TRUE;
 }
@@ -1402,9 +1406,12 @@ rait_device_start_file (Device * dself, dumpfile_t * info) {
         return FALSE;
     }
 
-    dself->in_file = TRUE;
     g_assert(actual_file >= 1);
     dself->file = actual_file;
+    g_mutex_lock(dself->device_mutex);
+    dself->in_file = TRUE;
+    dself->bytes_written = 0;
+    g_mutex_unlock(dself->device_mutex);
 
     return TRUE;
 }
@@ -1582,6 +1589,9 @@ rait_device_write_block (Device * dself, guint size, gpointer data) {
         return FALSE;
     } else {
         dself->block ++;
+       g_mutex_lock(dself->device_mutex);
+       dself->bytes_written += size;
+       g_mutex_unlock(dself->device_mutex);
 
         return TRUE;
     }
@@ -1624,7 +1634,9 @@ rait_device_finish_file (Device * dself) {
         return FALSE;
     }
 
+    g_mutex_lock(dself->device_mutex);
     dself->in_file = FALSE;
+    g_mutex_unlock(dself->device_mutex);
     return TRUE;
 }
 
@@ -1653,9 +1665,12 @@ rait_device_seek_file (Device * dself, guint file) {
 
     if (rait_device_in_error(self)) return NULL;
 
-    dself->in_file = FALSE;
     dself->is_eof = FALSE;
     dself->block = 0;
+    g_mutex_lock(dself->device_mutex);
+    dself->in_file = FALSE;
+    dself->bytes_read = 0;
+    g_mutex_unlock(dself->device_mutex);
 
     ops = g_ptr_array_sized_new(self->private->children->len);
     for (i = 0; i < self->private->children->len; i ++) {
@@ -1720,7 +1735,9 @@ rait_device_seek_file (Device * dself, guint file) {
     }
 
     /* update our state */
+    g_mutex_lock(dself->device_mutex);
     dself->in_file = in_file;
+    g_mutex_unlock(dself->device_mutex);
     dself->file = actual_file;
 
     return rval;
@@ -1988,7 +2005,9 @@ rait_device_read_block (Device * dself, gpointer buf, int * size) {
                stralloc(_("EOF")),
                DEVICE_STATUS_SUCCESS);
             dself->is_eof = TRUE;
+           g_mutex_lock(dself->device_mutex);
            dself->in_file = FALSE;
+           g_mutex_unlock(dself->device_mutex);
         } else {
            device_set_error(dself,
                stralloc(_("All child devices failed to read, but not all are at eof")),
@@ -2005,6 +2024,9 @@ rait_device_read_block (Device * dself, gpointer buf, int * size) {
     if (success) {
        dself->block++;
        *size = blocksize;
+       g_mutex_lock(dself->device_mutex);
+       dself->bytes_read += blocksize;
+       g_mutex_unlock(dself->device_mutex);
         return blocksize;
     } else {
         return -1;
@@ -2410,76 +2432,6 @@ property_get_medium_access_type_fn(Device *dself,
     return success;
 }
 
-static gboolean
-property_get_free_space_fn(Device *dself,
-    DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
-    PropertySurety *surety, PropertySource *source)
-{
-    RaitDevice *self = RAIT_DEVICE(dself);
-    QualifiedSize result;
-    guint i;
-    GPtrArray * ops;
-    guint data_children;
-
-    ops = make_property_op_array(self, PROPERTY_MEDIUM_ACCESS_TYPE, NULL, 0, 0);
-    do_rait_child_ops(self, property_get_do_op, ops);
-
-    /* Find the minimal available space of any child, with some funny business
-     * to deal with varying degrees of accuracy. */
-    result.accuracy = SIZE_ACCURACY_UNKNOWN;
-    result.bytes = 0;
-    for (i = 0; i < ops->len; i ++) {
-        QualifiedSize cur;
-        PropertyOp * op = g_ptr_array_index(ops, i);
-
-        if (!op->base.result || G_VALUE_TYPE(&(op->value)) != QUALIFIED_SIZE_TYPE) {
-           /* maybe this child can't tell us .. so this is just an estimate */
-           if (result.accuracy == SIZE_ACCURACY_REAL)
-               result.accuracy = SIZE_ACCURACY_ESTIMATE;
-
-           continue;
-       }
-
-        cur = *(QualifiedSize*)(g_value_get_boxed(&(op->value)));
-
-        if (result.accuracy != cur.accuracy) {
-            result.accuracy = SIZE_ACCURACY_ESTIMATE;
-        }
-
-        if (result.accuracy == SIZE_ACCURACY_UNKNOWN &&
-            cur.accuracy != SIZE_ACCURACY_UNKNOWN) {
-            result.bytes = cur.bytes;
-        } else if (result.accuracy != SIZE_ACCURACY_UNKNOWN &&
-                   cur.accuracy == SIZE_ACCURACY_UNKNOWN) {
-            /* result.bytes unchanged. */
-        } else {
-            result.bytes = MIN(result.bytes, cur.bytes);
-        }
-    }
-
-    g_ptr_array_free_full(ops);
-
-    /* result contains the minimum size available on any child.  We
-     * can use that space on each of our data children, so the total
-     * is larger */
-    find_simple_params(self, NULL, &data_children);
-    result.bytes *= data_children;
-
-    if (val) {
-       g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
-       g_value_set_boxed(val, &result);
-    }
-
-    if (surety)
-       *surety = (result.accuracy == SIZE_ACCURACY_UNKNOWN)?
-                   PROPERTY_SURETY_BAD : PROPERTY_SURETY_GOOD;
-
-    if (source)
-       *source = PROPERTY_SOURCE_DETECTED;
-
-    return TRUE;
-}
-
 static gboolean
 property_get_max_volume_usage_fn(Device *dself,
     DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
@@ -2506,7 +2458,9 @@ property_get_max_volume_usage_fn(Device *dself,
 
         cur = g_value_get_uint64(&(op->value));
 
-       result = MIN(cur, result);
+       if (!result || (cur && cur < result)) {
+           result = cur;
+       }
     }
 
     g_ptr_array_free_full(ops);
@@ -2636,23 +2590,23 @@ static gboolean
 rait_device_finish (Device * self) {
     GPtrArray * ops;
     gboolean success;
+    gboolean rval = TRUE;
 
-    if (rait_device_in_error(self)) return FALSE;
+    rval = !rait_device_in_error(self);
 
     ops = make_generic_boolean_op_array(RAIT_DEVICE(self));
 
     do_rait_child_ops(RAIT_DEVICE(self), finish_do_op, ops);
 
     success = g_ptr_array_and(ops, extract_boolean_generic_op);
+    if (!success)
+       rval = FALSE;
 
     g_ptr_array_free_full(ops);
 
     self->access_mode = ACCESS_NULL;
 
-    if (!success)
-        return FALSE;
-
-    return TRUE;
+    return rval;
 }
 
 static Device *