⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rait-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved. *  * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 as  * published by the Free Software Foundation. *  * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public * License for more details. *  * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA. *  * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com *//* The RAIT device encapsulates some number of other devices into a single * redundant device. */#include "rait-device.h"#include <amanda.h>#include "property.h"#include <util.h>typedef enum {    RAIT_STATUS_COMPLETE, /* All subdevices OK. */    RAIT_STATUS_DEGRADED, /* One subdevice failed. */    RAIT_STATUS_FAILED    /* Two or more subdevices failed. */} RaitStatus;struct RaitDevicePrivate_s {    GPtrArray * children;    /* These flags are only relevant for reading. */    RaitStatus status;    /* If status == RAIT_STATUS_DEGRADED, this holds the index of the       failed node. It holds a negative number otherwise. */    int failed;    guint block_size;};#define PRIVATE(o) (o->private)/* here are local prototypes */static void rait_device_init (RaitDevice * o);static void rait_device_class_init (RaitDeviceClass * c);static gboolean rait_device_open_device (Device * self, char * device_name);static gboolean rait_device_start (Device * self, DeviceAccessMode mode,                                   char * label, char * timestamp);static gboolean rait_device_start_file(Device * self, const dumpfile_t * info);static gboolean rait_device_write_block (Device * self, guint size,                                         gpointer data, gboolean last_block);static gboolean rait_device_finish_file (Device * self);static dumpfile_t * rait_device_seek_file (Device * self, guint file);static gboolean rait_device_seek_block (Device * self, guint64 block);static int      rait_device_read_block (Device * self, gpointer buf,                                        int * size);static gboolean rait_device_property_get (Device * self, DevicePropertyId id,                                          GValue * val);static gboolean rait_device_property_set (Device * self, DevicePropertyId id,                                          GValue * val);static gboolean rait_device_recycle_file (Device * self, guint filenum);static gboolean rait_device_finish (Device * self);static ReadLabelStatusFlags rait_device_read_label(Device * dself);static void find_simple_params(RaitDevice * self, guint * num_children,                               guint * data_children, int * blocksize);/* pointer to the class of our parent */static DeviceClass *parent_class = NULL;/* This function is replicated here in case we have GLib from before 2.4. * It should probably go eventually. */#if !GLIB_CHECK_VERSION(2,4,0)static voidg_ptr_array_foreach (GPtrArray *array,                     GFunc      func,                     gpointer   user_data){  guint i;  g_return_if_fail (array);  for (i = 0; i < array->len; i++)    (*func) (array->pdata[i], user_data);}#endifGTyperait_device_get_type (void){    static GType type = 0;    if G_UNLIKELY(type == 0) {        static const GTypeInfo info = {            sizeof (RaitDeviceClass),            (GBaseInitFunc) NULL,            (GBaseFinalizeFunc) NULL,            (GClassInitFunc) rait_device_class_init,            (GClassFinalizeFunc) NULL,            NULL /* class_data */,            sizeof (RaitDevice),            0 /* n_preallocs */,            (GInstanceInitFunc) rait_device_init,            NULL        };                type = g_type_register_static (TYPE_DEVICE, "RaitDevice", &info,                                       (GTypeFlags)0);	}        return type;}static void g_object_unref_foreach(gpointer data,                                   gpointer user_data G_GNUC_UNUSED) {    g_return_if_fail(G_IS_OBJECT(data));    g_object_unref(data);}static voidrait_device_finalize(GObject *obj_self){    RaitDevice *self G_GNUC_UNUSED = RAIT_DEVICE (obj_self);    if(G_OBJECT_CLASS(parent_class)->finalize) \           (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);    if(self->private->children) {        g_ptr_array_foreach(self->private->children,                            g_object_unref_foreach, NULL);        g_ptr_array_free (self->private->children, TRUE);        self->private->children = NULL;    }    amfree(self->private);}static void rait_device_init (RaitDevice * o G_GNUC_UNUSED){    PRIVATE(o) = malloc(sizeof(RaitDevicePrivate));    PRIVATE(o)->children = g_ptr_array_new();    PRIVATE(o)->status = RAIT_STATUS_COMPLETE;    PRIVATE(o)->failed = -1;}static void rait_device_class_init (RaitDeviceClass * c G_GNUC_UNUSED){    GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;    DeviceClass *device_class = (DeviceClass *)c;    parent_class = g_type_class_ref (TYPE_DEVICE);    device_class->open_device = rait_device_open_device;    device_class->start = rait_device_start;    device_class->start_file = rait_device_start_file;    device_class->write_block = rait_device_write_block;    device_class->finish_file = rait_device_finish_file;    device_class->seek_file = rait_device_seek_file;    device_class->seek_block = rait_device_seek_block;    device_class->read_block = rait_device_read_block;    device_class->property_get = rait_device_property_get;    device_class->property_set = rait_device_property_set;    device_class->recycle_file = rait_device_recycle_file;     device_class->finish = rait_device_finish;    device_class->read_label = rait_device_read_label;    g_object_class->finalize = rait_device_finalize;    g_thread_pool_set_max_unused_threads(-1);}/* This function does something a little clever and a little * complicated. It takes an array of operations and runs the given * function on each element in the array. The trick is that it runs them * all in parallel, in different threads. This is more efficient than it * sounds because we use a GThreadPool, which means calling this function * will probably not start any new threads at all, but rather use * existing ones. The func is called with two gpointer arguments: The * first from the array, the second is the data argument. *  * When it returns, all the operations have been successfully * executed. If you want results from your operations, do it yourself * through the array. */static void do_thread_pool_op(GFunc func, GPtrArray * ops, gpointer data) {    GThreadPool * pool;    guint i;    pool = g_thread_pool_new(func, data, -1, FALSE, NULL);    for (i = 0; i < ops->len; i ++) {        g_thread_pool_push(pool, g_ptr_array_index(ops, i), NULL);    }    g_thread_pool_free(pool, FALSE, TRUE);}/* This does the above, in a serial fashion (and without using threads) */static void do_unthreaded_ops(GFunc func, GPtrArray * ops,                              gpointer data G_GNUC_UNUSED) {    guint i;    for (i = 0; i < ops->len; i ++) {        func(g_ptr_array_index(ops, i), NULL);    }}/* This is the one that code below should call. It switches   automatically between do_thread_pool_op and do_unthreaded_ops,   depending on g_thread_supported(). */static void do_rait_child_ops(GFunc func, GPtrArray * ops, gpointer data) {    if (g_thread_supported()) {        do_thread_pool_op(func, ops, data);    } else {        do_unthreaded_ops(func, ops, data);    }}/* Take a text string user_name, and break it out into an argv-style   array of strings. For example, {foo,{bar,baz},bat} would return the   strings "foo", "{bar,baz}", "bat", and NULL. Returns NULL on   error. */static char ** parse_device_name(char * user_name) {    GPtrArray * rval;    char * cur_end = user_name;    char * cur_begin = user_name;        rval = g_ptr_array_new();        /* Check opening brace. */    if (*cur_begin != '{')        return NULL;    cur_begin ++;        cur_end = cur_begin;    for (;;) {        switch (*cur_end) {        case ',': {            g_ptr_array_add(rval, g_strndup(cur_begin, cur_end - cur_begin));            cur_end ++;            cur_begin = cur_end;            continue;        }        case '{':            /* We read until the matching closing brace. */            while (*cur_end != '}' && *cur_end != '\0')                cur_end ++;            if (*cur_end == '}')                cur_end ++;            continue;                    case '}':            g_ptr_array_add(rval, g_strndup(cur_begin, cur_end - cur_begin));            goto OUTER_END; /* break loop, not switch */        case '\0':            /* Unexpected NULL; abort. */            g_fprintf(stderr, "Invalid RAIT device name %s\n", user_name);            g_ptr_array_free_full(rval);            return NULL;        default:            cur_end ++;            continue;        }        g_assert_not_reached();    } OUTER_END:        if (cur_end[1] != '\0') {        g_fprintf(stderr, "Invalid RAIT device name %s\n", user_name);        g_ptr_array_free_full(rval);        return NULL;    }    g_ptr_array_add(rval, NULL);    return (char**) g_ptr_array_free(rval, FALSE);}/* Find a workable block size. */static gboolean find_block_size(RaitDevice * self) {    uint min = 0;    uint max = G_MAXUINT;    uint result;    GValue val;    gboolean rval;    guint i;    guint data_children;        for (i = 0; i < self->private->children->len; i ++) {        uint child_min, child_max;        GValue property_result;        bzero(&property_result, sizeof(property_result));        if (!device_property_get(g_ptr_array_index(self->private->children, i),                                 PROPERTY_MIN_BLOCK_SIZE, &property_result))            return FALSE;        child_min = g_value_get_uint(&property_result);        g_return_val_if_fail(child_min > 0, FALSE);        if (!device_property_get(g_ptr_array_index(self->private->children, i),                                 PROPERTY_MAX_BLOCK_SIZE, &property_result))            return FALSE;        child_max = g_value_get_uint(&property_result);        g_return_val_if_fail(child_max > 0, FALSE);                if (child_min > max || child_max < min || child_min == 0) {            return FALSE;        } else {            min = MAX(min, child_min);            max = MIN(max, child_max);        }    }    /* Now pick a number. */    g_assert(min <= max);    if (max < MAX_TAPE_BLOCK_BYTES)        result = max;    else if (min > MAX_TAPE_BLOCK_BYTES)        result = min;    else        result = MAX_TAPE_BLOCK_BYTES;    /* User reads and writes bigger blocks. */    find_simple_params(self, NULL, &data_children, NULL);    self->private->block_size = result * data_children;    bzero(&val, sizeof(val));    g_value_init(&val, G_TYPE_INT);    g_value_set_int(&val, result);    /* We can't do device_property_set because it's disallowed       according to the registered property base. */    rval = rait_device_property_set(DEVICE(self), PROPERTY_BLOCK_SIZE, &val);    g_value_unset(&val);    return rval;}/* Register properties that belong to the RAIT device proper, and not   to subdevices. */static void register_rait_properties(RaitDevice * self) {    Device * o = DEVICE(self);    DeviceProperty prop;    prop.access = PROPERTY_ACCESS_GET_MASK;    prop.base = &device_property_min_block_size;    device_add_property(o, &prop, NULL);    prop.base = &device_property_max_block_size;    device_add_property(o, &prop, NULL);      prop.base = &device_property_block_size;    device_add_property(o, &prop, NULL);    prop.base = &device_property_canonical_name;    device_add_property(o, &prop, NULL);}static void property_hash_union(GHashTable * properties,                                DeviceProperty * prop) {    PropertyAccessFlags before, after;    gpointer tmp;    gboolean found;        found = g_hash_table_lookup_extended(properties,                                         GUINT_TO_POINTER(prop->base->ID),                                         NULL, &tmp);    before = GPOINTER_TO_UINT(tmp);        if (!found) {        after = prop->access;    } else {        after = before & prop->access;    }        g_hash_table_insert(properties, GUINT_TO_POINTER(prop->base->ID),                        GUINT_TO_POINTER(after));}/* A GHRFunc. */static gboolean zero_value(gpointer key G_GNUC_UNUSED, gpointer value,                           gpointer user_data G_GNUC_UNUSED) {    return (0 == GPOINTER_TO_UINT(value));}/* A GHFunc */static void register_property_hash(gpointer key, gpointer value,                                   gpointer user_data) {    DevicePropertyId id = GPOINTER_TO_UINT(key);    DeviceProperty prop;    Device * device = (Device*)user_data;    g_assert(IS_DEVICE(device));    prop.access = GPOINTER_TO_UINT(value);    prop.base = device_property_get_by_id(id);    device_add_property(device, &prop, NULL);}/* This function figures out which properties exist for all children, and  * exports the unioned access mask. */static void register_properties(RaitDevice * self) {    GHashTable * properties; /* PropertyID => PropertyAccessFlags */    guint j;        properties = g_hash_table_new(g_direct_hash, g_direct_equal);    /* Iterate the device list, find all properties. */    for (j = 0; j < self->private->children->len; j ++) {        int i;        Device * child = g_ptr_array_index(self->private->children, j);        const DeviceProperty* device_property_list;        device_property_list = device_property_get_list(child);        for (i = 0; device_property_list[i].base != NULL; i ++) {            property_hash_union(properties, (gpointer)&(device_property_list[i]));        }    }    /* Then toss properties that can't be accessed. */    g_hash_table_foreach_remove(properties, zero_value, NULL);    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_BLOCK_SIZE));    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_MIN_BLOCK_SIZE));    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_MAX_BLOCK_SIZE));    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_CANONICAL_NAME));    /* Finally, register the lot. */    g_hash_table_foreach(properties, register_property_hash, self);    g_hash_table_destroy(properties);    /* Then we have some of our own properties to register. */    register_rait_properties(self);}/* This structure contains common fields for many operations. Not all   operations use all fields, however. */typedef struct {    gpointer result; /* May be a pointer; may be an integer or boolean                        stored with GINT_TO_POINTER. */    Device * child;  /* The device in question. Used by all                        operations. */    guint child_index; /* For recoverable operations (read-related                          operations), this field provides the number                          of this child in the self->private->children                          array. */} GenericOp;typedef gboolean (*BooleanExtractor)(gpointer data);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -