Skip to content

Commit

Permalink
Merge pull request #1289 from tbzatek/mpath-1
Browse files Browse the repository at this point in the history
udiskslinuxdevice: Fix dm-multipath ATA drives handling
  • Loading branch information
tbzatek authored Jun 25, 2024
2 parents cb33496 + 4279c5e commit cd8314b
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 32 deletions.
2 changes: 2 additions & 0 deletions doc/udisks2-sections.txt.daemon.sections.in
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ udisks_linux_device_read_sysfs_attr_as_int
udisks_linux_device_read_sysfs_attr_as_uint64
udisks_linux_device_subsystem_is_nvme
udisks_linux_device_nvme_is_fabrics
udisks_linux_device_is_dm_multipath
udisks_linux_device_is_mpath_device_path
<SUBSECTION Standard>
UDISKS_TYPE_LINUX_DEVICE
UDISKS_LINUX_DEVICE
Expand Down
73 changes: 70 additions & 3 deletions src/udiskslinuxdevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static gboolean probe_ata (UDisksLinuxDevice *device,
/**
* udisks_linux_device_new_sync:
* @udev_device: A #GUdevDevice.
* @udev_client: A #GUdevClient.
*
* Creates a new #UDisksLinuxDevice from @udev_device which includes
* probing the device for more information, if applicable.
Expand All @@ -109,7 +110,7 @@ static gboolean probe_ata (UDisksLinuxDevice *device,
* Returns: A #UDisksLinuxDevice.
*/
UDisksLinuxDevice *
udisks_linux_device_new_sync (GUdevDevice *udev_device)
udisks_linux_device_new_sync (GUdevDevice *udev_device, GUdevClient *udev_client)
{
UDisksLinuxDevice *device;
GError *error = NULL;
Expand All @@ -122,7 +123,7 @@ udisks_linux_device_new_sync (GUdevDevice *udev_device)
/* No point in probing on remove events */
if (!(g_strcmp0 (g_udev_device_get_action (udev_device), "remove") == 0))
{
if (!udisks_linux_device_reprobe_sync (device, NULL, &error))
if (!udisks_linux_device_reprobe_sync (device, udev_client, NULL, &error))
goto out;
}

Expand All @@ -142,17 +143,22 @@ udisks_linux_device_new_sync (GUdevDevice *udev_device)
/**
* udisks_linux_device_reprobe_sync:
* @device: A #UDisksLinuxDevice.
* @udev_client: A #GUdevClient.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
* Forcibly reprobe information on @device. The calling thread may be
* blocked for a non-trivial amount of time while the probing is
* underway.
*
* Probing is dm-multipath aware in which case an active path
* is looked up and udev attributes are fetched from there.
*
* Returns: %TRUE if reprobing succeeded, %FALSE otherwise.
*/
gboolean
udisks_linux_device_reprobe_sync (UDisksLinuxDevice *device,
GUdevClient *udev_client,
GCancellable *cancellable,
GError **error)
{
Expand All @@ -167,7 +173,8 @@ udisks_linux_device_reprobe_sync (UDisksLinuxDevice *device,
g_udev_device_get_property_as_boolean (device->udev_device, "ID_ATA") &&
!g_udev_device_has_property (device->udev_device, "ID_USB_TYPE") &&
!g_udev_device_has_property (device->udev_device, "ID_USB_DRIVER") &&
!g_udev_device_has_property (device->udev_device, "ID_USB_MODEL"))
!g_udev_device_has_property (device->udev_device, "ID_USB_MODEL") &&
!udisks_linux_device_is_mpath_device_path (device))
{
if (!probe_ata (device, cancellable, error))
goto out;
Expand Down Expand Up @@ -218,6 +225,34 @@ udisks_linux_device_reprobe_sync (UDisksLinuxDevice *device,
if (!device->nvme_ns_info)
goto out;
}
else
/* Probe the dm-multipath devices */
if (g_strcmp0 (g_udev_device_get_subsystem (device->udev_device), "block") == 0 &&
g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") == 0 &&
udisks_linux_device_is_dm_multipath (device))
{
gboolean is_ata = FALSE;
gchar **slaves;
guint n;

slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device->udev_device), "slaves");
for (n = 0; slaves[n] != NULL; n++)
{
GUdevDevice *slave;

slave = g_udev_client_query_by_sysfs_path (udev_client, slaves[n]);
if (slave != NULL)
{
is_ata |= g_udev_device_get_property_as_boolean (slave, "ID_ATA");
g_object_unref (slave);
}
if (is_ata)
break;
}
g_strfreev (slaves);
if (is_ata && !probe_ata (device, cancellable, error))
goto out;
}

ret = TRUE;

Expand Down Expand Up @@ -463,3 +498,35 @@ udisks_linux_device_nvme_is_fabrics (UDisksLinuxDevice *device)

return FALSE;
}

/**
* udisks_linux_device_is_dm_multipath:
* @device: A #UDisksLinuxDevice.
*
* Returns: %TRUE if @device represents a dm-multipath block device,
* %FALSE otherwise.
*/
gboolean
udisks_linux_device_is_dm_multipath (UDisksLinuxDevice *device)
{
const gchar *dm_uuid;

if (g_udev_device_get_property_as_int (device->udev_device, "MPATH_DEVICE_READY") == 1)
return TRUE;

dm_uuid = g_udev_device_get_sysfs_attr (device->udev_device, "dm/uuid");
return dm_uuid != NULL && g_str_has_prefix (dm_uuid, "mpath-");
}

/**
* udisks_linux_device_is_mpath_device_path:
* @device: A #UDisksLinuxDevice.
*
* Returns: %TRUE if @device is an I/O path that is part of a dm-multipath
* device, %FALSE otherwise.
*/
gboolean
udisks_linux_device_is_mpath_device_path (UDisksLinuxDevice *device)
{
return g_udev_device_get_property_as_int (device->udev_device, "DM_MULTIPATH_DEVICE_PATH") == 1;
}
7 changes: 6 additions & 1 deletion src/udiskslinuxdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ struct _UDisksLinuxDevice
};

GType udisks_linux_device_get_type (void) G_GNUC_CONST;
UDisksLinuxDevice *udisks_linux_device_new_sync (GUdevDevice *udev_device);
UDisksLinuxDevice *udisks_linux_device_new_sync (GUdevDevice *udev_device,
GUdevClient *udev_client);
gboolean udisks_linux_device_reprobe_sync (UDisksLinuxDevice *device,
GUdevClient *udev_client,
GCancellable *cancellable,
GError **error);

Expand All @@ -75,6 +77,9 @@ guint64 udisks_linux_device_read_sysfs_attr_as_uint64 (UDisksLinuxDev
gboolean udisks_linux_device_subsystem_is_nvme (UDisksLinuxDevice *device);
gboolean udisks_linux_device_nvme_is_fabrics (UDisksLinuxDevice *device);

gboolean udisks_linux_device_is_dm_multipath (UDisksLinuxDevice *device);
gboolean udisks_linux_device_is_mpath_device_path (UDisksLinuxDevice *device);

G_END_DECLS

#endif /* __UDISKS_LINUX_DEVICE_H__ */
2 changes: 1 addition & 1 deletion src/udiskslinuxdrive.c
Original file line number Diff line number Diff line change
Expand Up @@ -1630,7 +1630,7 @@ handle_power_off (UDisksDrive *_drive,
}
fd = -1;

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_dbus_method_invocation_return_error (invocation,
Expand Down
61 changes: 48 additions & 13 deletions src/udiskslinuxdriveata.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ udisks_linux_drive_ata_update (UDisksLinuxDriveAta *drive,
UDisksLinuxDriveObject *object)
{
UDisksLinuxDevice *device;
device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
goto out;

Expand Down Expand Up @@ -423,6 +423,24 @@ static gboolean update_io_stats (UDisksLinuxDriveAta *drive, UDisksLinuxDevice *
return noio;
}

static BDExtraArg **
build_smart_extra_args (UDisksLinuxDevice *device)
{
BDExtraArg **extra;

if (!udisks_linux_device_is_dm_multipath (device))
return NULL;

/* Now that we're in UDisksLinuxDriveAta it means the device already passed
* earlier selection for hardware type. The most likely scenario here are
* SATA drives connected to a SAS HBA, so hardcode the SCSI to ATA Translation (SAT)
* protocol for ATA PASS THROUGH SCSI.
*/
extra = g_new0 (BDExtraArg *, 2);
extra[0] = bd_extra_arg_new ("--device=sat,auto", NULL);
return extra;
}

/**
* udisks_linux_drive_ata_refresh_smart_sync:
* @drive: The #UDisksLinuxDriveAta to refresh.
Expand Down Expand Up @@ -469,7 +487,7 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive,
goto out;
}

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_set_error_literal (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand Down Expand Up @@ -499,6 +517,7 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive,
}
else
{
BDExtraArg **extra;
guchar count;
gboolean noio = FALSE;
gboolean awake;
Expand All @@ -518,8 +537,11 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive,
goto out_io;
}

extra = build_smart_extra_args (device);
data = bd_smart_ata_get_info (g_udev_device_get_device_file (device->udev_device),
(const BDExtraArg **) extra,
&l_error);
bd_extra_arg_list_free (extra);
}

if (data == NULL)
Expand Down Expand Up @@ -583,12 +605,13 @@ udisks_linux_drive_ata_smart_selftest_sync (UDisksLinuxDriveAta *drive,
GError *l_error = NULL;
gboolean ret = FALSE;
BDSmartSelfTestOp op;
BDExtraArg **extra = NULL;

object = udisks_daemon_util_dup_object (drive, error);
if (object == NULL)
goto out;

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_set_error_literal (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand All @@ -615,8 +638,11 @@ udisks_linux_drive_ata_smart_selftest_sync (UDisksLinuxDriveAta *drive,
goto out;
}

extra = build_smart_extra_args (device);
if (!bd_smart_device_self_test (g_udev_device_get_device_file (device->udev_device),
op, &l_error))
op,
(const BDExtraArg **) extra,
&l_error))
{
g_set_error_literal (error,
UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand All @@ -628,6 +654,7 @@ udisks_linux_drive_ata_smart_selftest_sync (UDisksLinuxDriveAta *drive,
ret = TRUE;

out:
bd_extra_arg_list_free (extra);
g_clear_object (&device);
g_clear_object (&object);
return ret;
Expand Down Expand Up @@ -661,7 +688,7 @@ handle_smart_update (UDisksDriveAta *_drive,
}

daemon = udisks_linux_drive_object_get_daemon (object);
block_object = udisks_linux_drive_object_get_block (object, TRUE);
block_object = udisks_linux_drive_object_get_block (object, FALSE);
if (block_object == NULL)
{
g_dbus_method_invocation_return_error (invocation,
Expand Down Expand Up @@ -818,7 +845,7 @@ handle_smart_selftest_abort (UDisksDriveAta *_drive,
}

daemon = udisks_linux_drive_object_get_daemon (object);
block_object = udisks_linux_drive_object_get_block (object, TRUE);
block_object = udisks_linux_drive_object_get_block (object, FALSE);
if (block_object == NULL)
{
g_dbus_method_invocation_return_error (invocation,
Expand Down Expand Up @@ -1042,7 +1069,7 @@ handle_smart_selftest_start (UDisksDriveAta *_drive,
}

daemon = udisks_linux_drive_object_get_daemon (object);
block_object = udisks_linux_drive_object_get_block (object, TRUE);
block_object = udisks_linux_drive_object_get_block (object, FALSE);
if (block_object == NULL)
{
g_dbus_method_invocation_return_error (invocation,
Expand Down Expand Up @@ -1145,11 +1172,13 @@ handle_smart_set_enabled (UDisksDriveAta *_drive,
UDisksLinuxDriveObject *object = NULL;
UDisksLinuxBlockObject *block_object = NULL;
UDisksDaemon *daemon;
UDisksLinuxProvider *provider;
GError *error = NULL;
UDisksLinuxDevice *device = NULL;
const gchar *message;
const gchar *action_id;
uid_t caller_uid;
BDExtraArg **extra = NULL;

object = udisks_daemon_util_dup_object (drive, &error);
if (object == NULL)
Expand All @@ -1169,6 +1198,7 @@ handle_smart_set_enabled (UDisksDriveAta *_drive,
}

daemon = udisks_linux_drive_object_get_daemon (object);
provider = udisks_daemon_get_linux_provider (daemon);
if (!udisks_daemon_util_get_caller_uid_sync (daemon,
invocation,
NULL /* GCancellable */,
Expand Down Expand Up @@ -1219,8 +1249,11 @@ handle_smart_set_enabled (UDisksDriveAta *_drive,
goto out;
}

extra = build_smart_extra_args (device);
if (!bd_smart_set_enabled (g_udev_device_get_device_file (device->udev_device),
value, &error))
value,
(const BDExtraArg **) extra,
&error))
{
if (g_error_matches (error, BD_SMART_ERROR, BD_SMART_ERROR_TECH_UNAVAIL))
{
Expand Down Expand Up @@ -1274,7 +1307,9 @@ handle_smart_set_enabled (UDisksDriveAta *_drive,
}

/* Reread new IDENTIFY data */
if (!udisks_linux_device_reprobe_sync (device, NULL, &error))
if (!udisks_linux_device_reprobe_sync (device,
udisks_linux_provider_get_udev_client (provider),
NULL, &error))
{
g_prefix_error (&error, "Error reprobing device: ");
g_dbus_method_invocation_take_error (invocation, error);
Expand Down Expand Up @@ -1305,6 +1340,7 @@ handle_smart_set_enabled (UDisksDriveAta *_drive,
udisks_drive_ata_complete_smart_set_enabled (_drive, invocation);

out:
bd_extra_arg_list_free (extra);
g_clear_object (&device);
g_clear_object (&block_object);
g_clear_object (&object);
Expand Down Expand Up @@ -1369,7 +1405,7 @@ udisks_linux_drive_ata_get_pm_state (UDisksLinuxDriveAta *drive,

/* TODO: some SSD controllers may block for considerable time when trimming large amount of blocks */

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_set_error_literal (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand Down Expand Up @@ -1529,7 +1565,7 @@ handle_pm_standby_wakeup (UDisksDriveAta *_drive,
invocation))
goto out;

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand Down Expand Up @@ -2030,7 +2066,7 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive,

daemon = udisks_linux_drive_object_get_daemon (object);

device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
device = udisks_linux_drive_object_get_device (object, FALSE /* get_hw */);
if (device == NULL)
{
g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
Expand Down Expand Up @@ -2405,7 +2441,6 @@ handle_security_erase_unit (UDisksDriveAta *_drive,

/* ---------------------------------------------------------------------------------------------------- */


static void
drive_ata_iface_init (UDisksDriveAtaIface *iface)
{
Expand Down
Loading

0 comments on commit cd8314b

Please sign in to comment.