diff --git a/configure.ac b/configure.ac
index d0e5f8e2164b7cfa9a43f8412bd8f2678a6535e9..33a66b2122167b62ac4f48b5eaca067d995f6369 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1081,6 +1081,59 @@ PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [
 ])
 AM_CONDITIONAL([HAVE_SYSTEMD], [test "${have_systemd}" = "yes"])
 
+dnl Check for dbus
+AC_ARG_ENABLE([sddbus],
+  AS_HELP_STRING([--enable-dbus],
+    [compile D-Bus message bus support via sd-bus (default auto)]))
+AC_ARG_VAR([SDBUS_CFLAGS], [C compiler flags for sd-bus])
+AC_ARG_VAR([SDBUS_LIBS], [linker flags flags for sd-bus])
+
+have_sdbus="no"
+AS_IF([test "${enable_sdbus}" != "no"], [
+      AS_IF([test "${have_systemd}" = "yes"], [
+        SDBUS_CFLAGS="${SYSTEMD_CFLAGS} -DHAVE_SYSTEMD"
+          SDBUS_LIBS="${SYSTEMD_LIBS}"
+          have_sdbus="yes"
+        ])
+      dnl Check for elogind
+      AS_IF([test "${have_sdbus}" != "yes"], [
+        PKG_CHECK_MODULES([ELOGIND], [libelogind], [
+          have_elogind="yes"
+        ], [
+          AC_MSG_WARN([${ELOGIND_PKG_ERRORS}.])
+        ])
+
+        AS_IF([test "${have_elogind}" = "yes" ], [
+          SDBUS_CFLAGS="${ELOGIND_CFLAGS} -DHAVE_ELOGIND"
+          SDBUS_LIBS="${ELOGIND_LIBS}"
+          have_sdbus="yes"
+        ])
+      ])
+
+      dnl Check for basu
+      AS_IF([test "${have_sdbus}" != "yes"], [
+        PKG_CHECK_MODULES([BASU], [basu], [
+          have_basu="yes"
+        ], [
+          AC_MSG_WARN([${BASU_PKG_ERRORS}.])
+        ])
+
+        AS_IF([test "${have_basu}" = "yes" ], [
+          SDBUS_CFLAGS="${BASU_CFLAGS} -DHAVE_BASU"
+          SDBUS_LIBS="${BASU_LIBS}"
+          have_sdbus="yes"
+        ])
+      ])
+
+      AS_IF([test "$have_sdbus" = "yes" ], [
+          AC_SUBST([SDBUS_CFLAGS])
+          AC_SUBST([SDBUS_LIBS])
+        ], [
+          AC_MSG_WARN([no sd-bus provider found.])
+      ])
+])
+
+
 
 EXTEND_HELP_STRING([Optimization options:])
 dnl
@@ -4166,6 +4219,19 @@ dnl mDNS using libmicrodns
 dnl
 PKG_ENABLE_MODULES_VLC([MICRODNS], [], [microdns >= 0.1.2], [mDNS services discovery], [auto])
 
+dnl
+dnl UDisks services discovery
+dnl
+AC_ARG_ENABLE([udisks],
+  AS_HELP_STRING([--enable-udisks], [Local Drives service discovery plugin (default auto)]))
+AS_IF([test "${enable_udisks}" != "no"],
+  [
+    AS_IF([test "${have_sdbus}" != "no"], [
+      VLC_ADD_PLUGIN([udisks]) ], [
+      AC_MSG_WARN([UDisks plugins requires sd-dbus.])
+  ])
+])
+
 
 EXTEND_HELP_STRING([Misc options:])
 
diff --git a/modules/services_discovery/Makefile.am b/modules/services_discovery/Makefile.am
index bb06e4170fa99e3ada21efe3245c4b2080269ec4..a7d762b603e2af09cd1978f80d074ae40bfd726a 100644
--- a/modules/services_discovery/Makefile.am
+++ b/modules/services_discovery/Makefile.am
@@ -89,3 +89,10 @@ libbonjour_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)' -Wl,-framework,Fo
 if HAVE_DARWIN
 sd_LTLIBRARIES += libbonjour_plugin.la
 endif
+
+libudisks_plugin_la_SOURCES = services_discovery/udisks.c
+libudisks_plugin_la_CFLAGS = $(AM_CFLAGS) $(SDBUS_CFLAGS)
+libudisks_plugin_la_LIBADD = $(SDBUS_LIBS)
+libudisks_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
+EXTRA_LTLIBRARIES += libudisks_plugin.la
+sd_LTLIBRARIES += $(LTLIBudisks)
diff --git a/modules/services_discovery/udisks.c b/modules/services_discovery/udisks.c
new file mode 100644
index 0000000000000000000000000000000000000000..2d29a81137e3d59d442b1878b49cbbd8e0291c72
--- /dev/null
+++ b/modules/services_discovery/udisks.c
@@ -0,0 +1,587 @@
+/*****************************************************************************
+ * udisks.c: file system services discovery module
+ *****************************************************************************
+ * Copyright © 2022 VLC authors, VideoLAN and VideoLabs
+ *
+ * Authors: Juliane de Sartiges <jill@videolabs.io>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_modules.h>
+#include <vlc_configuration.h>
+#include <vlc_services_discovery.h>
+#include <vlc_xml.h>
+#include <vlc_stream.h>
+#include <vlc_interrupt.h>
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-bus.h>
+#elif HAVE_ELOGIND
+#include <elogind/sd-bus.h>
+#elif HAVE_BASU
+#include <basu/sd-bus.h>
+#endif
+
+#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
+
+#define DBUS_INTERFACE_UDISKS2 "org.freedesktop.UDisks2"
+#define DBUS_INTERFACE_UDISKS2_BLOCKS DBUS_INTERFACE_UDISKS2".Block"
+#define DBUS_INTERFACE_UDISKS2_BLOCKS DBUS_INTERFACE_UDISKS2".Block"
+#define DBUS_INTERFACE_UDISKS2_DRIVE DBUS_INTERFACE_UDISKS2".Drive"
+#define DBUS_INTERFACE_UDISKS2_FILESYSTEM DBUS_INTERFACE_UDISKS2".Filesystem"
+#define DBUS_INTERFACE_UDISKS2_MANAGER DBUS_INTERFACE_UDISKS2".Manager"
+#define DBUS_INTERFACE_UDISKS2_PARTITION DBUS_INTERFACE_UDISKS2".Partition"
+
+#define DBUS_PATH_UDISKS2 "/org/freedesktop/UDisks2"
+#define DBUS_PATH_UDISKS2_DRIVES DBUS_PATH_UDISKS2"/drives"
+#define DBUS_PATH_UDISKS2_BLOCK_DEV DBUS_PATH_UDISKS2"/block_devices"
+#define DBUS_PATH_UDISKS2_MANAGER DBUS_PATH_UDISKS2"/Manager"
+
+struct fs_properties_changed_param
+{
+    services_discovery_t *sd;
+    char *object_path;
+};
+
+struct device_info
+{
+    sd_bus_slot* slot;
+    input_item_t* item;
+    char *label;
+    uint64_t size;
+    bool removable;
+    struct fs_properties_changed_param* param;
+};
+
+struct discovery_sys
+{
+    sd_bus* bus;
+    sd_bus_slot *interface_added_slot;
+    sd_bus_slot *interface_removed_slot;
+    vlc_thread_t thread;
+    vlc_dictionary_t entries;
+    int event;
+};
+
+const char *binary_prefixes[] = { N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB") };
+
+static int human(uint64_t *i)
+{
+    int exp = 0;
+    while(*i > 1024 || exp > 5)
+    {
+        *i = *i >> 10;
+        exp++;
+    }
+    return exp;
+}
+static const char *print_label(const char *drive_label, bool removable)
+{
+    if(drive_label == NULL || drive_label[0] == '\0')
+    {
+        if(removable)
+            return _("Removable Drive");
+        else
+            return _("Internal Drive");
+    }
+    return drive_label;
+}
+static input_item_t *input_item_NewDrive(const char *drive_label, const char *path, uint64_t size, bool removable)
+{
+    int r = 0;
+    input_item_t* ret = NULL;
+    char *mrl = NULL;
+    char *label = NULL;
+
+    if(asprintf(&mrl, "file://%s", path) == -1)
+        return NULL;
+
+    int prefix = human(&size);
+    r = asprintf(&label, "%s (%ld %s)", print_label(drive_label, removable), size, vlc_gettext(binary_prefixes[prefix]));
+    if(r == -1)
+        goto end;
+    ret = input_item_NewDirectory(mrl, label, ITEM_LOCAL);
+end:
+    free(mrl);
+    free(label);
+    return ret;
+}
+
+static int fs_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *err)
+{
+    VLC_UNUSED(err);
+    int r;
+    struct fs_properties_changed_param* param = (struct fs_properties_changed_param*) userdata;
+    services_discovery_t *sd = (services_discovery_t *) param->sd;
+    struct discovery_sys *p_sys = (struct discovery_sys*) sd->p_sys;
+
+    const char *interface_name;
+    r = sd_bus_message_read(m, "s", &interface_name);
+    if(r < 0)
+        return r;
+    if(strcmp(interface_name, DBUS_INTERFACE_UDISKS2_FILESYSTEM) != 0)
+        return 0;
+
+    size_t mount_path_len;
+    const char *mount_path = NULL;
+
+    char *property_name = NULL;
+
+    r = sd_bus_message_enter_container(m, 'a', "{sv}");
+    if(r < 0)
+        return r;
+    for(;;)
+    {
+        r = sd_bus_message_enter_container(m, 'e', "sv");
+        r = sd_bus_message_read(m, "s", &property_name);
+        if(r < 0)
+            return r;
+        if (r == 0)
+            return 0;
+        if(strcmp(property_name, "MountPoints") == 0)
+            break;
+    }
+    r = sd_bus_message_enter_container(m, 'v', "aay");
+    if(r < 0)
+        return r;
+    r = sd_bus_message_enter_container(m, 'a', "ay");
+    if(r < 0)
+        return r;
+    const void *path;
+    r = sd_bus_message_read_array(m, 'y', &path, &mount_path_len);
+    mount_path = path;
+    if(r < 0)
+        return r;
+    struct device_info* info = vlc_dictionary_value_for_key(&p_sys->entries, param->object_path);
+    if(!info)
+        return -1;
+    if(mount_path_len)
+    {
+        info->item = input_item_NewDrive(info->label, mount_path, info->size, info->removable);
+        services_discovery_AddItem(sd, info->item);
+    }
+    else
+        services_discovery_RemoveItem(sd, info->item);
+    return 1;
+}
+
+static int is_filesystem(services_discovery_t *sd, const char *block_path)
+{
+    struct discovery_sys *p_sys = (struct discovery_sys*) sd->p_sys;
+    sd_bus* bus = p_sys->bus;
+    sd_bus_error err = SD_BUS_ERROR_NULL;
+    sd_bus_message *reply = NULL;
+    char *xml = NULL;
+    const char *val = NULL;
+    xml_reader_t *xmlreader = NULL;
+    stream_t *xmlstream = NULL;
+    int r;
+    int ret = 0;
+
+    r = sd_bus_call_method(bus, DBUS_INTERFACE_UDISKS2, block_path,
+                                DBUS_INTERFACE_INTROSPECTABLE, "Introspect", &err, &reply, NULL);
+    if(r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        sd_bus_error_free(&err);
+        return -1;
+    }
+
+    r = sd_bus_message_read(reply, "s", &xml);
+    if(r < 0)
+        return -1;
+    xmlstream = vlc_stream_MemoryNew(sd, (uint8_t *) xml, strlen(xml), true);
+    xmlreader = xml_ReaderCreate(sd, xmlstream);
+    while((r = xml_ReaderNextNode(xmlreader, &val)) > 0)
+    {
+        if(r == XML_READER_NONE)
+            break;
+        if(strcmp(val, "interface") != 0)
+            continue;
+        xml_ReaderNextAttr(xmlreader, &val);
+        if(strcmp(val, DBUS_INTERFACE_UDISKS2_FILESYSTEM) != 0)
+            continue;
+        ret = 1;
+        break;
+    }
+    xml_ReaderDelete(xmlreader);
+    vlc_stream_Delete(xmlstream);
+    sd_bus_message_unref(reply);
+    return ret;
+}
+
+static int get_info_from_block_device(services_discovery_t *sd, const char *block_path, struct device_info **info_ret)
+{
+    struct discovery_sys *p_sys = (struct discovery_sys*) sd->p_sys;
+    sd_bus* bus = p_sys->bus;
+    sd_bus_error err = SD_BUS_ERROR_NULL;
+    int r = 0;
+
+    struct device_info *info = NULL;
+    size_t mount_path_len;
+    const char *drive_path = NULL;
+    const char *mount_path = NULL;
+
+    sd_bus_message *drive_reply = NULL;
+    sd_bus_message *mounts_reply = NULL;
+
+
+    if(!is_filesystem(sd, block_path))
+        return 0;
+    info = calloc(1, sizeof(struct device_info));
+    if(!info)
+    {
+        r = -1;
+        goto error;
+    }
+
+    info->param = malloc(sizeof(struct fs_properties_changed_param));
+    if(!info->param)
+    {
+        r = -1;
+        goto error;
+    }
+
+    info->param->sd = sd;
+    info->param->object_path = strdup(block_path);
+
+    r = sd_bus_match_signal(bus, &info->slot,
+                            NULL, block_path,
+                            "org.freedesktop.DBus.Properties", "PropertiesChanged",
+                            fs_properties_changed, (void *) info->param);
+    if(r < 0)
+        goto error;
+
+    r = sd_bus_get_property_trivial(bus, DBUS_INTERFACE_UDISKS2,
+                                      block_path,
+                                      DBUS_INTERFACE_UDISKS2_BLOCKS, "Size",
+                                      &err, 't', &info->size);
+    if(r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        goto error;
+    }
+
+    r = sd_bus_get_property(bus, DBUS_INTERFACE_UDISKS2,
+                                block_path, DBUS_INTERFACE_UDISKS2_BLOCKS,
+                                "Drive", &err, &drive_reply, "o");
+    if(r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        goto error;
+    }
+
+    r = sd_bus_message_read(drive_reply, "o", &drive_path);
+    if(r < 0)
+        goto error;
+
+    if(strcmp(drive_path, "/") != 0)
+    {
+        r = sd_bus_get_property_trivial(bus, DBUS_INTERFACE_UDISKS2,
+                                          drive_path,
+                                          DBUS_INTERFACE_UDISKS2_DRIVE, "Removable",
+                                          &err, 'b', &info->removable);
+        if(r < 0)
+        {
+            msg_Err(sd, "%s: %s\n", err.name, err.message);
+            goto error;
+        }
+    }
+
+    r = sd_bus_get_property_string(bus, DBUS_INTERFACE_UDISKS2,
+                                      block_path,
+                                      DBUS_INTERFACE_UDISKS2_BLOCKS, "IdLabel",
+                                      &err, &info->label);
+    if(r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        goto error;
+    }
+
+    r = sd_bus_get_property(bus, DBUS_INTERFACE_UDISKS2,
+                            block_path, DBUS_INTERFACE_UDISKS2_FILESYSTEM,
+                            "MountPoints", &err, &mounts_reply, "aay");
+    if(r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        goto error;
+    }
+
+    r = sd_bus_message_enter_container(mounts_reply, 'a', "ay");
+    if(r < 0)
+        goto error;
+
+    const void *path;
+    r = sd_bus_message_read_array(mounts_reply, 'y', &path, &mount_path_len);
+    path = mount_path;
+    if(r < 0)
+        goto error;
+    if(r)
+        info->item = input_item_NewDrive(info->label, mount_path, info->size, info->removable);
+    sd_bus_message_unref(drive_reply);
+    sd_bus_error_free(&err);
+    *info_ret = info;
+    return 1;
+error:
+    sd_bus_error_free(&err);
+    if(drive_reply)
+        sd_bus_message_unref(drive_reply);
+    if(mounts_reply)
+        sd_bus_message_unref(mounts_reply);
+    if(info)
+    {
+        if(info->param)
+        {
+            free(info->param->object_path);
+            free(info->param);
+        }
+        if(info->item)
+            input_item_Release(info->item);
+        free(info);
+    }
+    return r;
+}
+
+static void FreeEntries(void *p_value, void *p_obj)
+{
+    services_discovery_t *sd = (services_discovery_t *)p_obj;
+    struct device_info *info = (struct device_info *) p_value;
+    if(!info)
+        return;
+    if(info->param)
+    {
+        free(info->param->object_path);
+        free(info->param);
+    }
+    if(info->slot)
+        sd_bus_slot_unref(info->slot);
+    free(info->label);
+    if(info->item)
+    {
+        services_discovery_RemoveItem(sd, info->item);
+        input_item_Release(info->item);
+    }
+    free(info);
+}
+
+static int interfaces_added_cb(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+    VLC_UNUSED(ret_error);
+    int r;
+    services_discovery_t *sd = (services_discovery_t *)userdata;
+    struct discovery_sys *p_sys = (struct discovery_sys *)sd->p_sys;
+    const char *path;
+    r = sd_bus_message_read(m, "o", &path);
+    if(r < 0)
+        goto error;
+    if(strncmp(path, DBUS_PATH_UDISKS2_BLOCK_DEV, strlen(DBUS_PATH_UDISKS2_BLOCK_DEV)) != 0)
+        return 0;
+    struct device_info *info = NULL;
+    r = get_info_from_block_device(sd, path, &info);
+    if(r < 0)
+        goto error;
+    if(!info)
+        return 0;
+    vlc_dictionary_insert(&p_sys->entries, path, info);
+    if(info->item)
+        services_discovery_AddItem(sd, info->item);
+    return 1;
+error:
+    return r;
+}
+
+static int interfaces_removed_cb(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+    VLC_UNUSED(ret_error);
+    int r;
+    services_discovery_t *sd = (services_discovery_t *)userdata;
+    struct discovery_sys *p_sys = (struct discovery_sys *)sd->p_sys;
+    const char *path;
+    r = sd_bus_message_read(m, "o", &path);
+    if(r < 0)
+        goto error;
+    if(strncmp(path, DBUS_PATH_UDISKS2_BLOCK_DEV, strlen(DBUS_PATH_UDISKS2_BLOCK_DEV)) != 0)
+        return 0;
+    struct device_info* info = vlc_dictionary_value_for_key(&p_sys->entries, path);
+    if(!info)
+        return 0;
+    vlc_dictionary_remove_value_for_key(&p_sys->entries, path, FreeEntries, sd);
+    return 1;
+error:
+    return r;
+}
+
+static void *Run(void *p_obj)
+{
+    int r;
+    services_discovery_t *sd = (services_discovery_t *)p_obj;
+    struct discovery_sys *p_sys = (struct discovery_sys *)sd->p_sys;
+    sd_bus* bus = p_sys->bus;
+
+    r = sd_bus_match_signal(bus, &p_sys->interface_added_slot,
+                            DBUS_INTERFACE_UDISKS2, DBUS_PATH_UDISKS2,
+                            "org.freedesktop.DBus.ObjectManager", "InterfacesAdded",
+                            interfaces_added_cb, (void *) sd);
+    if(r < 0)
+    {
+        return NULL;
+    }
+
+    r = sd_bus_match_signal(bus, &p_sys->interface_removed_slot,
+                            DBUS_INTERFACE_UDISKS2, DBUS_PATH_UDISKS2,
+                            "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved",
+                            interfaces_removed_cb, (void *) sd);
+    if(r < 0)
+    {
+        sd_bus_slot_unref(p_sys->interface_added_slot);
+        return NULL;
+    }
+
+    int canc = vlc_savecancel();
+
+    struct pollfd ufd[1];
+    ufd[0].fd = sd_bus_get_fd(bus);
+    ufd[0].events = POLLIN;
+
+    for(;;)
+    {
+        vlc_restorecancel(canc);
+
+        while(poll(ufd, 1, -1) < 0);
+
+        canc = vlc_savecancel();
+
+        sd_bus_message *msg = NULL;
+        r = sd_bus_process(bus, &msg);
+        if(r < 0)
+        {
+            msg_Err(sd, "Couldn't process new d-bus event : %d", -r);
+            break;
+        }
+        sd_bus_message_unref(msg);
+    }
+    vlc_restorecancel(canc);
+    if(p_sys->interface_added_slot)
+        sd_bus_slot_unref(p_sys->interface_added_slot);
+    if(p_sys->interface_removed_slot)
+        sd_bus_slot_unref(p_sys->interface_removed_slot);
+    return NULL;
+}
+
+static int Open(vlc_object_t *p_obj)
+{
+    services_discovery_t *sd = (services_discovery_t *)p_obj;
+    struct discovery_sys *p_sys = vlc_alloc(1, sizeof(struct discovery_sys));
+    if (!p_sys)
+        return VLC_ENOMEM;
+    sd->p_sys = p_sys;
+
+    sd->description = _("UDisks2 Discovery");
+    vlc_dictionary_init(&p_sys->entries, 0);
+
+    int r;
+
+    /* connect to the session bus */
+    r =  sd_bus_open_system(&p_sys->bus);
+    if(r < 0)
+        goto error;
+   sd_bus* bus = p_sys->bus;
+   sd_bus_message *reply = NULL;
+   sd_bus_error err = SD_BUS_ERROR_NULL;
+   r = sd_bus_call_method(bus, DBUS_INTERFACE_UDISKS2, DBUS_PATH_UDISKS2_MANAGER,
+                          DBUS_INTERFACE_UDISKS2_MANAGER, "GetBlockDevices",
+                          &err, &reply, "a{sv}", NULL);
+    if (r < 0)
+    {
+        msg_Err(sd, "%s: %s\n", err.name, err.message);
+        goto error;
+    }
+
+    r = sd_bus_message_enter_container(reply, 'a', "o");
+    if (r < 0)
+        goto error;
+
+    char *block_path = NULL;
+    while ((r = sd_bus_message_read(reply, "o", &block_path)) != 0)
+    {
+        if(r < 0)
+            goto error;
+        struct device_info *info = NULL;
+        r = get_info_from_block_device(sd, block_path, &info);
+        if(r < 0)
+            goto error;
+        if(!info)
+            continue;
+        vlc_dictionary_insert(&p_sys->entries, block_path, info);
+        if(info->item)
+            services_discovery_AddItem(sd, info->item);
+    }
+    sd_bus_message_unref(reply);
+
+    if (vlc_clone(&p_sys->thread, Run, sd))
+        goto error;
+    sd_bus_error_free(&err);
+    return VLC_SUCCESS;
+error:
+    if(p_sys->bus)
+        sd_bus_close(bus);
+    if(p_sys->event)
+        close(p_sys->event);
+    sd_bus_error_free(&err);
+    free(p_sys);
+    return VLC_EGENERIC;
+}
+
+static void Close(vlc_object_t *p_obj)
+{
+    services_discovery_t *sd = (services_discovery_t *)p_obj;
+    struct discovery_sys *p_sys = (struct discovery_sys *)sd->p_sys;
+    if(p_sys->interface_added_slot)
+        sd_bus_slot_unref(p_sys->interface_added_slot);
+    sd_bus_close(p_sys->bus);
+    const uint64_t notify = 1;
+    write(p_sys->event, &notify, sizeof(notify));
+    vlc_cancel(p_sys->thread);
+    vlc_join(p_sys->thread, NULL);
+    close(p_sys->event);
+    vlc_dictionary_clear(&p_sys->entries, FreeEntries, sd);
+    free(p_sys);
+}
+
+VLC_SD_PROBE_HELPER("udisks", N_("UDisks2"), SD_CAT_DEVICES)
+
+/*
+ * Module descriptor
+ */
+vlc_module_begin()
+    set_shortname( "UDisks" )
+    set_description( N_( "Local Drives (UDisks)" ) )
+    set_subcategory( SUBCAT_PLAYLIST_SD )
+    set_capability( "services_discovery", 0 )
+    set_callbacks( Open, Close )
+    add_shortcut( "udisks" )
+    VLC_SD_PROBE_SUBMODULE
+vlc_module_end ()
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0fabfc2ce3a9f5a79b2a032608b1fa322573efb7..e77ab187a6996d3f5a6354dc383caaaf888d51e0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1226,6 +1226,7 @@ modules/services_discovery/podcast.c
 modules/services_discovery/pulse.c
 modules/services_discovery/sap.c
 modules/services_discovery/udev.c
+modules/services_discovery/udisks.c
 modules/services_discovery/upnp.cpp
 modules/services_discovery/windrive.c
 modules/services_discovery/xcb_apps.c