1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <glib/gi18n-lib.h>
28
#include "udiskslogging.h"
29
#include "udisksdaemon.h"
30
#include "udisksdaemonutil.h"
31
#include "udiskslinuxprovider.h"
32
#include "udiskslinuxmdraidobject.h"
33
#include "udiskslinuxmdraid.h"
34
#include "udiskslinuxblockobject.h"
35
#include "udiskslinuxdevice.h"
38
* SECTION:udiskslinuxmdraidobject
39
* @title: UDisksLinuxMDRaidObject
40
* @short_description: Object representing a Linux Software RAID array
42
* Object corresponding to a Linux Software RAID array.
45
typedef struct _UDisksLinuxMDRaidObjectClass UDisksLinuxMDRaidObjectClass;
48
* UDisksLinuxMDRaidObject:
50
* The #UDisksLinuxMDRaidObject structure contains only private data and
51
* should only be accessed using the provided API.
53
struct _UDisksLinuxMDRaidObject
55
UDisksObjectSkeleton parent_instance;
59
/* The UUID for the object */
62
/* The UDisksLinuxDevice for the RAID device (e.g. /dev/md0), if any */
63
UDisksLinuxDevice *raid_device;
65
/* list of UDisksLinuxDevice objects for detected member devices */
66
GList *member_devices;
69
UDisksMDRaid *iface_mdraid;
71
/* watches for sysfs attr changes */
72
GSource *sync_action_source;
73
GSource *degraded_source;
76
struct _UDisksLinuxMDRaidObjectClass
78
UDisksObjectSkeletonClass parent_class;
89
remove_watches (UDisksLinuxMDRaidObject *object)
91
if (object->sync_action_source != NULL)
93
g_source_destroy (object->sync_action_source);
94
object->sync_action_source = NULL;
96
if (object->degraded_source != NULL)
98
g_source_destroy (object->degraded_source);
99
object->degraded_source = NULL;
103
G_DEFINE_TYPE (UDisksLinuxMDRaidObject, udisks_linux_mdraid_object, UDISKS_TYPE_OBJECT_SKELETON);
106
udisks_linux_mdraid_object_finalize (GObject *_object)
108
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (_object);
110
/* note: we don't hold a ref to object->daemon */
112
remove_watches (object);
114
if (object->iface_mdraid != NULL)
115
g_object_unref (object->iface_mdraid);
117
g_clear_object (&object->raid_device);
119
g_list_foreach (object->member_devices, (GFunc) g_object_unref, NULL);
120
g_list_free (object->member_devices);
122
g_free (object->uuid);
124
if (G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->finalize != NULL)
125
G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->finalize (_object);
129
udisks_linux_mdraid_object_get_property (GObject *__object,
134
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (__object);
139
g_value_set_object (value, udisks_linux_mdraid_object_get_daemon (object));
143
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149
udisks_linux_mdraid_object_set_property (GObject *__object,
154
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (__object);
159
g_assert (object->daemon == NULL);
160
/* we don't take a reference to the daemon */
161
object->daemon = g_value_get_object (value);
165
object->uuid = g_value_dup_string (value);
169
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176
udisks_linux_mdraid_object_init (UDisksLinuxMDRaidObject *object)
181
strip_and_replace_with_uscore (gchar *s)
190
for (n = 0; s != NULL && s[n] != '\0'; n++)
192
if (s[n] == ' ' || s[n] == '-' || s[n] == ':')
201
udisks_linux_mdraid_object_constructed (GObject *_object)
203
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (_object);
207
/* compute the object path */
208
uuid = g_strdup (object->uuid);
209
strip_and_replace_with_uscore (uuid);
210
s = g_strdup_printf ("/org/freedesktop/UDisks2/mdraid/%s", uuid);
212
g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), s);
215
if (G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->constructed != NULL)
216
G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->constructed (_object);
220
udisks_linux_mdraid_object_class_init (UDisksLinuxMDRaidObjectClass *klass)
222
GObjectClass *gobject_class;
224
gobject_class = G_OBJECT_CLASS (klass);
225
gobject_class->finalize = udisks_linux_mdraid_object_finalize;
226
gobject_class->constructed = udisks_linux_mdraid_object_constructed;
227
gobject_class->set_property = udisks_linux_mdraid_object_set_property;
228
gobject_class->get_property = udisks_linux_mdraid_object_get_property;
231
* UDisksLinuxMDRaidObject:daemon:
233
* The #UDisksDaemon the object is for.
235
g_object_class_install_property (gobject_class,
237
g_param_spec_object ("daemon",
239
"The daemon the object is for",
243
G_PARAM_CONSTRUCT_ONLY |
244
G_PARAM_STATIC_STRINGS));
247
* UDisksLinuxMDRaidObject:uuid:
249
* The UUID for the array.
251
g_object_class_install_property (gobject_class,
253
g_param_spec_string ("uuid",
255
"The UUID for the array",
258
G_PARAM_CONSTRUCT_ONLY |
259
G_PARAM_STATIC_STRINGS));
263
* udisks_linux_mdraid_object_new:
264
* @daemon: A #UDisksDaemon.
265
* @uuid: The UUID for the array.
267
* Create a new MDRaid object.
269
* Returns: A #UDisksLinuxMDRaidObject object. Free with g_object_unref().
271
UDisksLinuxMDRaidObject *
272
udisks_linux_mdraid_object_new (UDisksDaemon *daemon,
275
g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
276
g_return_val_if_fail (uuid != NULL, NULL);
277
return UDISKS_LINUX_MDRAID_OBJECT (g_object_new (UDISKS_TYPE_LINUX_MDRAID_OBJECT,
284
* udisks_linux_mdraid_object_get_daemon:
285
* @object: A #UDisksLinuxMDRaidObject.
287
* Gets the daemon used by @object.
289
* Returns: A #UDisksDaemon. Do not free, the object is owned by @object.
292
udisks_linux_mdraid_object_get_daemon (UDisksLinuxMDRaidObject *object)
294
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
295
return object->daemon;
299
* udisks_linux_mdraid_object_get_members:
300
* @object: A #UDisksLinuxMDRaidObject.
302
* Gets the current #UDisksLinuxDevice objects for the RAID members associated with @object.
304
* Returns: A list of #UDisksLinuxDevice objects. Free each element with
305
* g_object_unref(), then free the list with g_list_free().
308
udisks_linux_mdraid_object_get_members (UDisksLinuxMDRaidObject *object)
312
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
314
ret = g_list_copy (object->member_devices);
315
g_list_foreach (ret, (GFunc) g_object_ref, NULL);
321
* udisks_linux_mdraid_object_get_device:
322
* @object: A #UDisksLinuxMDRaidObject.
324
* Gets the current #UDisksLinuxDevice object for the RAID device
325
* (e.g. /dev/md0) associated with @object, if any.
327
* Returns: (transfer full): A #UDisksLinuxDevice or %NULL. Free with g_object_unref().
330
udisks_linux_mdraid_object_get_device (UDisksLinuxMDRaidObject *object)
332
UDisksLinuxDevice *ret = NULL;
334
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
336
ret = object->raid_device != NULL ? g_object_ref (object->raid_device) : NULL;
341
/* ---------------------------------------------------------------------------------------------------- */
343
typedef gboolean (*HasInterfaceFunc) (UDisksLinuxMDRaidObject *object);
344
typedef void (*ConnectInterfaceFunc) (UDisksLinuxMDRaidObject *object);
345
typedef gboolean (*UpdateInterfaceFunc) (UDisksLinuxMDRaidObject *object,
346
const gchar *uevent_action,
347
GDBusInterface *interface);
350
update_iface (UDisksLinuxMDRaidObject *object,
351
const gchar *uevent_action,
352
HasInterfaceFunc has_func,
353
ConnectInterfaceFunc connect_func,
354
UpdateInterfaceFunc update_func,
356
gpointer _interface_pointer)
358
gboolean ret = FALSE;
361
GDBusInterface **interface_pointer = _interface_pointer;
363
g_return_val_if_fail (object != NULL, FALSE);
364
g_return_val_if_fail (has_func != NULL, FALSE);
365
g_return_val_if_fail (update_func != NULL, FALSE);
366
g_return_val_if_fail (g_type_is_a (skeleton_type, G_TYPE_OBJECT), FALSE);
367
g_return_val_if_fail (g_type_is_a (skeleton_type, G_TYPE_DBUS_INTERFACE), FALSE);
368
g_return_val_if_fail (interface_pointer != NULL, FALSE);
369
g_return_val_if_fail (*interface_pointer == NULL || G_IS_DBUS_INTERFACE (*interface_pointer), FALSE);
372
has = has_func (object);
373
if (*interface_pointer == NULL)
377
*interface_pointer = g_object_new (skeleton_type, NULL);
378
if (connect_func != NULL)
379
connect_func (object);
387
g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (object),
388
G_DBUS_INTERFACE_SKELETON (*interface_pointer));
389
g_object_unref (*interface_pointer);
390
*interface_pointer = NULL;
394
if (*interface_pointer != NULL)
396
if (update_func (object, uevent_action, G_DBUS_INTERFACE (*interface_pointer)))
399
g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object),
400
G_DBUS_INTERFACE_SKELETON (*interface_pointer));
406
/* ---------------------------------------------------------------------------------------------------- */
409
mdraid_check (UDisksLinuxMDRaidObject *object)
415
mdraid_connect (UDisksLinuxMDRaidObject *object)
420
mdraid_update (UDisksLinuxMDRaidObject *object,
421
const gchar *uevent_action,
422
GDBusInterface *_iface)
424
return udisks_linux_mdraid_update (UDISKS_LINUX_MDRAID (object->iface_mdraid), object);
427
/* ---------------------------------------------------------------------------------------------------- */
430
find_link_for_sysfs_path_for_member (UDisksLinuxMDRaidObject *object,
431
const gchar *sysfs_path)
437
for (l = object->member_devices; l != NULL; l = l->next)
439
UDisksLinuxDevice *device = UDISKS_LINUX_DEVICE (l->data);
440
if (g_strcmp0 (g_udev_device_get_sysfs_path (device->udev_device), sysfs_path) == 0)
450
/* ---------------------------------------------------------------------------------------------------- */
453
watch_attr (UDisksLinuxDevice *device,
455
GSourceFunc callback,
458
GError *error = NULL;
460
GIOChannel *channel = NULL;
461
GSource *ret = NULL;;
463
g_return_val_if_fail (UDISKS_IS_LINUX_DEVICE (device), NULL);
465
path = g_strdup_printf ("%s/%s", g_udev_device_get_sysfs_path (device->udev_device), attr);
466
channel = g_io_channel_new_file (path, "r", &error);
469
ret = g_io_create_watch (channel, G_IO_ERR);
470
g_source_set_callback (ret, callback, user_data, NULL);
471
g_source_attach (ret, g_main_context_get_thread_default ());
472
g_source_unref (ret);
473
g_io_channel_unref (channel); /* the keeps a reference to this object */
477
udisks_warning ("Error creating watch for file %s: %s (%s, %d)",
478
path, error->message, g_quark_to_string (error->domain), error->code);
479
g_clear_error (&error);
486
/* ---------------------------------------------------------------------------------------------------- */
489
attr_changed (GIOChannel *channel,
493
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (user_data);
494
gboolean bail = FALSE;
495
GError *error = NULL;
499
if (cond & ~G_IO_ERR)
502
if (g_io_channel_seek_position (channel, 0, G_SEEK_SET, &error) != G_IO_STATUS_NORMAL)
504
udisks_debug ("Error seeking in channel (uuid %s): %s (%s, %d)",
505
object->uuid, error->message, g_quark_to_string (error->domain), error->code);
506
g_clear_error (&error);
511
if (g_io_channel_read_to_end (channel, &str, &len, &error) != G_IO_STATUS_NORMAL)
513
udisks_debug ("Error reading (uuid %s): %s (%s, %d)",
514
object->uuid, error->message, g_quark_to_string (error->domain), error->code);
515
g_clear_error (&error);
522
/* synthesize uevent */
523
if (object->raid_device != NULL)
524
udisks_linux_mdraid_object_uevent (object, "change", object->raid_device, FALSE);
528
remove_watches (object);
529
return TRUE; /* keep event source around */
532
/* ---------------------------------------------------------------------------------------------------- */
534
/* The md(4) driver does not use the usual uevent 'change' mechanism
535
* for notification - instead it excepts user-space to select(2)-ish
536
* on a fd for the sysfs attribute. Annoying. See
538
* http://www.kernel.org/doc/Documentation/md.txt
544
raid_device_added (UDisksLinuxMDRaidObject *object,
545
UDisksLinuxDevice *device)
547
g_assert (object->sync_action_source == NULL);
548
g_assert (object->degraded_source == NULL);
550
/* udisks_debug ("start watching %s", g_udev_device_get_sysfs_path (device->udev_device)); */
551
object->sync_action_source = watch_attr (device,
553
(GSourceFunc) attr_changed,
555
object->degraded_source = watch_attr (device,
557
(GSourceFunc) attr_changed,
562
raid_device_removed (UDisksLinuxMDRaidObject *object,
563
UDisksLinuxDevice *device)
565
/* udisks_debug ("stop watching %s", g_udev_device_get_sysfs_path (device->udev_device)); */
566
remove_watches (object);
569
/* ---------------------------------------------------------------------------------------------------- */
572
* udisks_linux_mdraid_object_uevent:
573
* @object: A #UDisksLinuxMDRaidObject.
574
* @action: Uevent action or %NULL
575
* @device: A #UDisksLinuxDevice device object or %NULL if the device hasn't changed.
576
* @is_member: %TRUE if @device is a member, %FALSE if it's the raid device.
578
* Updates all information on interfaces on @mdraid.
581
udisks_linux_mdraid_object_uevent (UDisksLinuxMDRaidObject *object,
583
UDisksLinuxDevice *device,
586
gboolean conf_changed = FALSE;
588
g_return_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object));
589
g_return_if_fail (UDISKS_IS_LINUX_DEVICE (device));
591
/* udisks_debug ("is_member=%d for uuid %s and device %s", is_member, object->uuid, g_udev_device_get_device_file (device->udev_device)); */
598
link = find_link_for_sysfs_path_for_member (object, g_udev_device_get_sysfs_path (device->udev_device));
600
if (g_strcmp0 (action, "remove") == 0)
604
g_object_unref (UDISKS_LINUX_DEVICE (link->data));
605
object->member_devices = g_list_delete_link (object->member_devices, link);
609
udisks_warning ("MDRaid with UUID %s doesn't have member device with sysfs path %s on remove event",
611
g_udev_device_get_sysfs_path (device->udev_device));
618
if (device != link->data)
620
g_object_unref (UDISKS_LINUX_DEVICE (link->data));
621
link->data = g_object_ref (device);
628
object->member_devices = g_list_append (object->member_devices, g_object_ref (device));
635
/* Skip partitions of raid devices */
636
if (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") != 0)
639
if (g_strcmp0 (action, "remove") == 0)
641
if (object->raid_device != NULL)
642
if (g_strcmp0 (g_udev_device_get_sysfs_path (object->raid_device->udev_device),
643
g_udev_device_get_sysfs_path (device->udev_device)) == 0)
645
g_clear_object (&object->raid_device);
646
raid_device_removed (object, object->raid_device);
650
udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event (it has %s)",
652
g_udev_device_get_sysfs_path (device->udev_device),
653
g_udev_device_get_sysfs_path (object->raid_device->udev_device));
657
udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event",
659
g_udev_device_get_sysfs_path (device->udev_device));
664
if (object->raid_device == NULL)
666
object->raid_device = g_object_ref (device);
667
raid_device_added (object, object->raid_device);
671
if (device != object->raid_device)
673
g_clear_object (&object->raid_device);
674
object->raid_device = g_object_ref (device);
680
/* if we don't have any devices, no point in updating (we should get nuked soon anyway) */
681
if (udisks_linux_mdraid_object_have_devices (object))
683
conf_changed = FALSE;
684
conf_changed |= update_iface (object, action, mdraid_check, mdraid_connect, mdraid_update,
685
UDISKS_TYPE_LINUX_MDRAID, &object->iface_mdraid);
691
/* ---------------------------------------------------------------------------------------------------- */
694
* udisks_linux_mdraid_object_have_devices:
695
* @object: A #UDisksLinuxMDRaidObject.
697
* Checks if there are any devices associated with @object at
698
* all. This includes both member devices and the raid device.
700
* Returns: %TRUE if at least one device is associated with @object, %FALSE otherwise.
703
udisks_linux_mdraid_object_have_devices (UDisksLinuxMDRaidObject *object)
705
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), FALSE);
707
return g_list_length (object->member_devices) > 0 || object->raid_device != NULL;
711
* udisks_linux_mdraid_object_get_uuid:
712
* @object: A #UDisksLinuxMDRaidObject.
714
* Gets the UUID for @object.
716
* Returns: (transfer none): The UUID for object. Do not free, the string belongs to @object.
719
udisks_linux_mdraid_object_get_uuid (UDisksLinuxMDRaidObject *object)
721
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);