prepare HAL for kernel 2.6.16 mount change event replacement
Kay Sievers
kay.sievers at vrfy.org
Sun Nov 20 11:09:55 PST 2005
This will be needed for HAL to work with 2.6.16. It changes the current
mount handling from device matches to dev_t matches. Would be nice, if
someone could try it, if it still works correcly with current kernels.
Thanks,
Kay
-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /cvs/hal/hal/ChangeLog,v
retrieving revision 1.687
diff -u -r1.687 ChangeLog
--- ChangeLog 15 Nov 2005 03:54:28 -0000 1.687
+++ ChangeLog 20 Nov 2005 19:02:21 -0000
@@ -1,3 +1,28 @@
+2005-11-18 Kay Sievers <kay.sievers at vrfy.org>
+
+ Kernel 2.6.15 will have a poll()'able /proc/mounts file, which
+ tells us about mount tree changes. Kernel 2.6.16 will no longer
+ have any netlink event regarding block devices mount/claim.
+
+ We watch /proc/mounts now and disable netlink, if we get events from
+ /proc/mounts. As soon as we depend on 2.6.15, all the netlink
+ code should be removed.
+
+ With every mount event, we update all known devices now, to the
+ current state found in /proc/mounts. The device name in /proc/mounts
+ is ignored, but the dev_t of the underlying block device is
+ looked up to find the hal device. That way, /dev/root and rootdev
+ will also be recognized and the state becomes visible.
+
+ * hald/linux2/blockdev.c: (blockdev_refresh_mount_state),
+ (add_blockdev_probing_helper_done):
+
+ * hald/linux2/blockdev.h:
+
+ * hald/linux2/osspec.c: (hald_helper_data),
+ (netlink_detection_data_ready), (mount_tree_changed_event),
+ (osspec_init):
+
2005-11-15 Kay Sievers <kay.sievers at vrfy.org>
* hald/linux2/osspec.c: (hald_udev_data), (hald_helper_data),
Index: hald/linux2/blockdev.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/blockdev.c,v
retrieving revision 1.27
diff -u -r1.27 blockdev.c
--- hald/linux2/blockdev.c 2 Nov 2005 15:38:13 -0000 1.27
+++ hald/linux2/blockdev.c 20 Nov 2005 19:02:22 -0000
@@ -160,104 +160,84 @@
hotplug_event_end (end_token);
}
-static void
-update_mount_point (HalDevice *d)
+void
+blockdev_refresh_mount_state (HalDevice *d)
{
FILE *f;
struct mntent mnt;
struct mntent *mnte;
- const char *device_file;
- char buf[512];
- unsigned int major, minor;
- gboolean retry = FALSE;
-
- if ((device_file = hal_device_property_get_string (d, "block.device")) == NULL)
- goto out;
-
- major = hal_device_property_get_int (d, "block.major");
- minor = hal_device_property_get_int (d, "block.minor");
-
- HAL_INFO (("Update mount point for %s (device_file %s)", d->udi, device_file));
-
+ char buf[1024];
+ unsigned int major;
+ unsigned int minor;
+ dev_t devt = makedev(0, 0);
+ GSList *volumes = NULL;
+ GSList *volume;
+
+ /* open /proc/mounts */
+ g_snprintf (buf, sizeof (buf), "%s/mounts", get_hal_proc_path ());
+ if ((f = setmntent (buf, "r")) == NULL) {
+ HAL_ERROR (("Could not open /proc/mounts"));
+ return;
+ }
- do {
- snprintf (buf, sizeof (buf), "%s/mounts", get_hal_proc_path ());
- if ((f = setmntent (buf, "r")) == NULL) {
- HAL_ERROR (("Could not open /proc/mounts"));
- goto out;
- }
+ if (d)
+ volumes = g_slist_append (NULL, d);
+ else
+ volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
- while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
- struct stat statbuf;
+ if (!volumes)
+ goto exit;
- if (stat (mnt.mnt_fsname, &statbuf) != 0)
+ /* loop over /proc/mounts */
+ while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
+ struct stat statbuf;
+
+ /* check the underlying device of the mount point */
+ if (stat (mnt.mnt_dir, &statbuf) != 0)
+ continue;
+ if (major(statbuf.st_dev) == 0)
+ continue;
+
+ HAL_INFO (("* found mounts dev %s (%i:%i)", mnt.mnt_fsname, major(statbuf.st_dev), minor(statbuf.st_dev)));
+ /* match against all hal volumes */
+ for (volume = volumes; volume != NULL; volume = g_slist_next (volume)) {
+ HalDevice *dev;
+
+ dev = HAL_DEVICE (volume->data);
+ major = hal_device_property_get_int (dev, "block.major");
+ if (major == 0)
continue;
+ minor = hal_device_property_get_int (dev, "block.minor");
+ devt = makedev(major, minor);
+ HAL_INFO ((" match %s (%i:%i)", hal_device_get_udi (dev), major, minor));
- if ((major (statbuf.st_rdev) == major) && (minor (statbuf.st_rdev) == minor)) {
+ if (statbuf.st_dev == devt) {
+ /* found entry for this device in /proc/mounts */
device_property_atomic_update_begin ();
- hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
- hal_device_property_set_string (d, "volume.mount_point", mnt.mnt_dir);
+ hal_device_property_set_bool (dev, "volume.is_mounted", TRUE);
+ hal_device_property_set_string (dev, "volume.mount_point", mnt.mnt_dir);
device_property_atomic_update_end ();
- HAL_INFO (("Setting mount point %s for %s", mnt.mnt_dir, device_file));
- goto found;
+ HAL_INFO ((" set %s to be mounted at %s", hal_device_get_udi (dev), mnt.mnt_dir));
+ volumes = g_slist_delete_link (volumes, volume);
+ break;
}
}
-
- /* to workaround http://lists.freedesktop.org/archives/hal/2005-October/003634.html
- * If device is not in proc: sleep 0.3 seconds and retry _one time_ to check again.
- *
- * NOTE: This workaround is for voluntary preemption kernel and should be removed if
- * the problem is fixed in the kernel.
- */
- if (retry) {
- HAL_WARNING (("Could not find %s in %s/mounts, no second retry.", device_file, get_hal_proc_path ()));
- retry = FALSE;
- } else {
- retry = TRUE;
- usleep (300000);
- HAL_WARNING (("Could not find %s in %s/mounts retry to find.", device_file, get_hal_proc_path ()));
- }
- } while (retry);
-
- device_property_atomic_update_begin ();
- hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
- hal_device_property_set_string (d, "volume.mount_point", "");
- device_property_atomic_update_end ();
-
- HAL_INFO (("Clearing mount point for %s", device_file));
-
-found:
- endmntent (f);
-out:
- ;
-}
-
-void
-blockdev_mount_status_changed (const gchar *sysfs_path, gboolean is_mounted)
-{
- HalDevice *d;
- HAL_INFO (("mount_status_changed for '%s', is_mounted=%d", sysfs_path, is_mounted));
-
- if ((d = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.sysfs_path", sysfs_path)) == NULL)
- goto error;
-
- if (!hal_device_has_capability (d, "volume")) {
- /* may have a fakevolume */
- d = hal_device_store_match_key_value_string (hald_get_gdl (),
- "info.parent",
- d->udi);
- if (d == NULL || !hal_device_has_capability (d, "volume"))
- goto error;
}
- HAL_INFO (("Applies to %s", d->udi));
-
- update_mount_point (d);
- return;
-
-error:
- HAL_INFO (("Couldn't find hal volume for %s", sysfs_path));
- ;
+ /* all remaining volumes are not mounted */
+ for (volume = volumes; volume != NULL; volume = g_slist_next (volume)) {
+ HalDevice *dev;
+
+ dev = HAL_DEVICE (volume->data);
+ device_property_atomic_update_begin ();
+ hal_device_property_set_bool (dev, "volume.is_mounted", FALSE);
+ hal_device_property_set_string (dev, "volume.mount_point", "");
+ device_property_atomic_update_end ();
+ HAL_INFO (("set %s to unmounted", hal_device_get_udi (dev)));
+ }
+ g_slist_free (volumes);
+exit:
+ endmntent (f);
}
static void
@@ -330,13 +310,13 @@
hal_device_copy_property (d, "info.udi", d, "block.storage_device");
} else {
/* check for mount point */
- update_mount_point (d);
+ blockdev_refresh_mount_state (d);
}
/* Merge properties from .fdi files */
di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
-
+
/* TODO: Merge persistent properties */
/* Run callouts */
Index: hald/linux2/blockdev.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/blockdev.h,v
retrieving revision 1.5
diff -u -r1.5 blockdev.h
--- hald/linux2/blockdev.h 2 Nov 2005 15:38:13 -0000 1.5
+++ hald/linux2/blockdev.h 20 Nov 2005 19:02:22 -0000
@@ -38,6 +38,6 @@
HotplugEvent *blockdev_generate_remove_hotplug_event (HalDevice *d);
-void blockdev_mount_status_changed (const gchar *sysfs_path, gboolean is_mounted);
+void blockdev_refresh_mount_state (HalDevice *d);
#endif /* BLOCKDEV_H */
Index: hald/linux2/osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/osspec.c,v
retrieving revision 1.35
diff -u -r1.35 osspec.c
--- hald/linux2/osspec.c 15 Nov 2005 03:54:28 -0000 1.35
+++ hald/linux2/osspec.c 20 Nov 2005 19:02:22 -0000
@@ -87,8 +87,9 @@
#include "osspec_linux.h"
-char hal_sysfs_path [HAL_PATH_MAX];
-char hal_proc_path [HAL_PATH_MAX];
+static char *hal_sysfs_path;
+static char *hal_proc_path;
+static guint netlink_source_id;
const gchar *
get_hal_sysfs_path (void)
@@ -300,7 +301,6 @@
g_snprintf (hotplug_event->sysfs.sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path), "%s%s",
hal_sysfs_path, msg.sysfs_path);
g_strlcpy (hotplug_event->sysfs.device_file, msg.device_name, sizeof (hotplug_event->sysfs.device_file));
- /* TODO: set wait_for_sysfs_path */
hotplug_event->sysfs.net_ifindex = msg.net_ifindex;
/* queue up and process */
@@ -317,7 +317,6 @@
g_snprintf (hotplug_event->sysfs.sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path), "%s%s",
hal_sysfs_path, msg.sysfs_path);
g_strlcpy (hotplug_event->sysfs.device_file, msg.device_name, sizeof (hotplug_event->sysfs.device_file));
- /* TODO: set wait_for_sysfs_path */
hotplug_event->sysfs.net_ifindex = msg.net_ifindex;
/* queue up and process */
@@ -332,10 +331,9 @@
#define VALID_NLMSG(h, s) ((NLMSG_OK (h, s) && \
s >= sizeof (struct nlmsghdr) && \
s >= h->nlmsg_len))
-
static gboolean
netlink_detection_data_ready (GIOChannel *channel, GIOCondition cond,
- gpointer user_data)
+ gpointer user_data)
{
int fd;
int bytes_read;
@@ -373,20 +371,10 @@
HAL_INFO (("bytes_read=%d buf='%s'", bytes_read, buf));
}
- /* Handle event: "mount@/block/hde" */
- if (g_str_has_prefix (buf, "mount")) {
- gchar sysfs_path[HAL_PATH_MAX];
- g_strlcpy (sysfs_path, get_hal_sysfs_path (), sizeof (sysfs_path));
- g_strlcat (sysfs_path, ((char *) buf) + sizeof ("mount"), sizeof (sysfs_path));
- blockdev_mount_status_changed (sysfs_path, TRUE);
- }
-
- /* Handle event: "umount@/block/hde" */
- if (g_str_has_prefix (buf, "umount")) {
- gchar sysfs_path[HAL_PATH_MAX];
- g_strlcpy (sysfs_path, get_hal_sysfs_path (), sizeof (sysfs_path));
- g_strlcat (sysfs_path, ((char *) buf) + sizeof ("umount"), sizeof (sysfs_path));
- blockdev_mount_status_changed (sysfs_path, FALSE);
+ /* handle mount event, delay, cause /proc/mounts may be not ready */
+ if (g_str_has_prefix (buf, "mount") || g_str_has_prefix (buf, "umount")) {
+ usleep (1000 * 200);
+ blockdev_refresh_mount_state (NULL);
}
} while (bytes_read > 0 || errno == EINTR);
@@ -394,55 +382,30 @@
return TRUE;
}
-static gboolean
-hal_util_get_fs_mnt_path (const gchar *fs_type, gchar *mnt_path, gsize len)
+static gboolean
+mount_tree_changed_event (GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
{
- FILE *mnt;
- struct mntent *mntent;
- gboolean rc;
- gsize dirlen;
-
- rc = FALSE;
- dirlen = 0;
-
- if (fs_type == NULL || mnt_path == NULL || len == 0) {
- HAL_ERROR (("Arguments not sane"));
- return -1;
- }
-
- if ((mnt = setmntent ("/proc/mounts", "r")) == NULL) {
- HAL_ERROR (("Error getting mount information"));
- return -1;
- }
-
- while (rc == FALSE && dirlen == 0 && (mntent = getmntent(mnt)) != NULL) {
- if (strcmp (mntent->mnt_type, fs_type) == 0) {
- dirlen = strlen (mntent->mnt_dir);
- if (dirlen <= (len - 1)) {
- g_strlcpy (mnt_path, mntent->mnt_dir, len);
- rc = TRUE;
- } else {
- HAL_ERROR (("Error - mount path too long"));
- rc = FALSE;
- }
- }
- }
- endmntent (mnt);
-
- if (dirlen == 0 && rc == TRUE) {
- HAL_ERROR (("Filesystem %s not found", fs_type));
- rc = FALSE;
+ if (cond & ~G_IO_ERR)
+ return TRUE;
+
+ HAL_INFO (("/proc/mounts tells, that the mount has tree changed"));
+ blockdev_refresh_mount_state (NULL);
+
+ /* disable netlink events, cause we poll() /proc/mounts */
+ if (netlink_source_id) {
+ HAL_INFO (("/proc/mounts sends events, disable netlink"));
+ g_source_remove (netlink_source_id);
+ netlink_source_id = 0;
}
- if ((!hal_util_remove_trailing_slash (mnt_path)))
- rc = FALSE;
-
- return rc;
+ return TRUE;
}
void
osspec_init (void)
{
+ gchar path[HAL_PATH_MAX];
int udev_socket;
int helper_socket;
struct sockaddr_un saddr;
@@ -450,6 +413,7 @@
GIOChannel *udev_channel;
GIOChannel *helper_channel;
const int on = 1;
+ GIOChannel *mounts_channel;
static int netlink_fd = -1;
struct sockaddr_nl netlink_addr;
GIOChannel *netlink_channel;
@@ -505,25 +469,22 @@
g_io_channel_unref (helper_channel);
/*
- * get mount points for /proc and /sys
+ * set mount points for /proc and /sys, possibly overridden for testing
*/
- if (!hal_util_get_fs_mnt_path ("sysfs", hal_sysfs_path, sizeof (hal_sysfs_path))) {
- HAL_ERROR (("Could not get sysfs mount point"));
- goto error;
- }
- HAL_INFO (("sysfs mount point is '%s'", hal_sysfs_path));
- if (!hal_util_get_fs_mnt_path ("proc", hal_proc_path, sizeof (hal_proc_path))) {
- HAL_ERROR (("Could not get proc mount point"));
- goto error;
- }
- HAL_INFO (("proc mount point is '%s'", hal_proc_path));
+ hal_sysfs_path = getenv ("SYSFS_PATH");
+ if (hal_sysfs_path == NULL)
+ hal_sysfs_path = "/sys";
+
+ hal_proc_path = getenv ("PROC_PATH");
+ if (hal_proc_path == NULL)
+ hal_proc_path = "/proc";
/*
* hook up to netlink socket to receive events from the Kernel Events
- * Layer (available since 2.6.10) - TODO: Don't use the constant 15 but
- * rather the NETLINK_KOBJECT_UEVENT symbol
+ * Layer (available from 2.6.10 - 2.6.15)
+ * FIXME: remove that after as soon as we depend on 2.6.15.
*/
- netlink_fd = socket (PF_NETLINK, SOCK_DGRAM, 15/*NETLINK_KOBJECT_UEVENT*/);
+ netlink_fd = socket (PF_NETLINK, SOCK_DGRAM, 15); /*NETLINK_KOBJECT_UEVENT*/;
if (netlink_fd < 0) {
DIE (("Unable to create netlink socket"));
@@ -539,17 +500,23 @@
}
netlink_channel = g_io_channel_unix_new (netlink_fd);
+ netlink_source_id = g_io_add_watch (netlink_channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL,
+ netlink_detection_data_ready, NULL);
- g_io_add_watch (netlink_channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL,
- netlink_detection_data_ready, NULL);
+ /*
+ * watch /proc/mounts for mount tree changes
+ * kernel 2.6.15 vfs throws a POLLERR event for every change
+ */
+ g_snprintf (path, sizeof (path), "%s/mounts", get_hal_proc_path ());
+ mounts_channel = g_io_channel_new_file (path, "r", NULL);
+ if (mounts_channel == NULL)
+ DIE (("Unable to read /proc/mounts"));
+ g_io_add_watch (mounts_channel, G_IO_ERR, mount_tree_changed_event, NULL);
/*
*Load various hardware id databases
*/
ids_init ();
-
-error:
- ;
}
static void
More information about the hal
mailing list