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