discover: Allow for already-mounted devices
authorJeremy Kerr <jk@ozlabs.org>
Tue, 1 Oct 2013 02:42:04 +0000 (10:42 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Tue, 1 Oct 2013 04:51:55 +0000 (12:51 +0800)
When we start the discover server, we may find that devices are already
mounted. In this case, mount_device will fail, and we'll abort the
parse.

This change uses /proc/self/mounts to check if new devices are already
mounted, and uses the existing mount point.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/device-handler.c
discover/device-handler.h
test/parser/utils.c

index 251c517f884aaa0c2212898b2e71dd3ad37a8e9e..cd9c41386ea07bdaa9762f75ac3ec81648c5b280 100644 (file)
@@ -1,9 +1,11 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <mntent.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 
@@ -677,6 +679,58 @@ void device_handler_cancel_default(struct device_handler *handler)
 }
 
 #ifndef PETITBOOT_TEST
+static bool check_existing_mount(struct discover_device *dev)
+{
+       struct stat devstat, mntstat;
+       struct mntent *mnt;
+       FILE *fp;
+       int rc;
+
+       rc = stat(dev->device_path, &devstat);
+       if (rc) {
+               pb_debug("%s: stat failed: %s\n", __func__, strerror(errno));
+               return false;
+       }
+
+       if (!S_ISBLK(devstat.st_mode)) {
+               pb_debug("%s: %s isn't a block device?\n", __func__,
+                               dev->device_path);
+               return false;
+       }
+
+       fp = fopen("/proc/self/mounts", "r");
+
+       for (;;) {
+               mnt = getmntent(fp);
+               if (!mnt)
+                       break;
+
+               if (!mnt->mnt_fsname || mnt->mnt_fsname[0] != '/')
+                       continue;
+
+               rc = stat(mnt->mnt_fsname, &mntstat);
+               if (rc)
+                       continue;
+
+               if (!S_ISBLK(mntstat.st_mode))
+                       continue;
+
+               if (mntstat.st_rdev == devstat.st_rdev) {
+                       pb_debug("%s: %s is already mounted at %s\n"
+                                       __func__, dev->device_path,
+                                       mnt->mnt_dir);
+                       dev->mount_path = talloc_strdup(dev, mnt->mnt_dir);
+                       dev->mounted = true;
+                       dev->unmount = false;
+                       break;
+               }
+       }
+
+       fclose(fp);
+
+       return mnt != NULL;
+}
+
 static int mount_device(struct discover_device *dev)
 {
        int rc;
@@ -684,29 +738,44 @@ static int mount_device(struct discover_device *dev)
        if (!dev->device_path)
                return -1;
 
-       if (!dev->mount_path)
-               dev->mount_path = join_paths(dev, mount_base(),
-                                               dev->device_path);
+       if (dev->mounted)
+               return 0;
+
+       if (check_existing_mount(dev))
+               return 0;
+
+       dev->mount_path = join_paths(dev, mount_base(),
+                                       dev->device_path);
 
-       if (pb_mkdir_recursive(dev->mount_path))
+       if (pb_mkdir_recursive(dev->mount_path)) {
                pb_log("couldn't create mount directory %s: %s\n",
                                dev->mount_path, strerror(errno));
+               goto err_free;
+       }
 
        rc = process_run_simple(dev, pb_system_apps.mount,
                        dev->device_path, dev->mount_path,
                        "-o", "ro", NULL);
-
-       if (!rc)
+       if (!rc) {
+               dev->mounted = true;
+               dev->unmount = true;
                return 0;
+       }
 
        /* Retry mount without ro option. */
        rc = process_run_simple(dev, pb_system_apps.mount,
                        dev->device_path, dev->mount_path, NULL);
 
-       if (!rc)
+       if (!rc) {
+               dev->mounted = true;
+               dev->unmount = true;
                return 0;
+       }
 
        pb_rmdir_recursive(mount_base(), dev->mount_path);
+err_free:
+       talloc_free(dev->mount_path);
+       dev->mount_path = NULL;
        return -1;
 }
 
@@ -714,7 +783,7 @@ static int umount_device(struct discover_device *dev)
 {
        int status;
 
-       if (!dev->mount_path)
+       if (!dev->mounted || !dev->unmount)
                return 0;
 
        status = process_run_simple(dev, pb_system_apps.umount,
@@ -723,6 +792,10 @@ static int umount_device(struct discover_device *dev)
        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
                return -1;
 
+       dev->mounted = false;
+       talloc_free(dev->mount_path);
+       dev->mount_path = NULL;
+
        pb_rmdir_recursive(mount_base(), dev->mount_path);
 
        return 0;
index 854be48dab48176e925e985eb56cf0a936fe48c6..9d477db9979dc249841ff52822d53c8d6fae7024 100644 (file)
@@ -33,8 +33,10 @@ struct discover_device {
        const char              *uuid;
        const char              *label;
 
-       const char              *mount_path;
+       char                    *mount_path;
        const char              *device_path;
+       bool                    mounted;
+       bool                    unmount;
 
        bool                    notified;
 
index f6939828337cfde8aa3ce31b8f1687cea2542e34..7af4df7397970e6b97c0794b64cb6f647434cab6 100644 (file)
@@ -61,6 +61,7 @@ struct discover_device *test_create_device(struct parser_test *test,
        dev->device->id = talloc_strdup(dev, name);
        dev->device_path = talloc_asprintf(dev, "/dev/%s", name);
        dev->mount_path = talloc_asprintf(dev, "/test/mount/%s", name);
+       dev->mounted = true;
 
        return dev;
 }