block(d): always call hotplug.d "mount" scripts from blockd
authorRafał Miłecki <rafal@milecki.pl>
Wed, 6 May 2020 14:48:06 +0000 (16:48 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Wed, 6 May 2020 15:48:00 +0000 (17:48 +0200)
This resolves problem on boot with "mount" scripts being called too
early to get blockd info. With this change "mount" scripts won't get
called until blockd starts. On startup it requests all devices info and
calls relevant scripts.

This fixes samba36-hotplug package hotplug.d script.

One downside of this change is handling "mount" evens on block restart
or crash. On restart "add" actions will get executed for mounted /
available (autofs) devices. On crash no events will be generated.

Ref: http://lists.infradead.org/pipermail/openwrt-devel/2019-December/020886.html
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
block.c
blockd.c

diff --git a/block.c b/block.c
index ac9546431d4b7735378c44013f9a4dcaf00c9c00..9458d52ba6ee0123b897412d175cba8944a9da23 100644 (file)
--- a/block.c
+++ b/block.c
@@ -886,35 +886,6 @@ static int exec_mount(const char *source, const char *target,
        return err;
 }
 
-static int hotplug_call_mount(const char *action, const char *device)
-{
-       pid_t pid;
-       int err = 0;
-
-       pid = fork();
-       if (!pid) {
-               char * const argv[] = { "hotplug-call", "mount", NULL };
-
-               setenv("ACTION", action, 1);
-               setenv("DEVICE", device, 1);
-
-               execv("/sbin/hotplug-call", argv);
-               exit(-1);
-       } else if (pid > 0) {
-               int status;
-
-               pid = waitpid(pid, &status, 0);
-               if (pid <= 0 || !WIFEXITED(status) || WEXITSTATUS(status)) {
-                       err = -ENOEXEC;
-                       ULOG_ERR("hotplug-call call failed\n");
-               }
-       } else {
-               err = -errno;
-       }
-
-       return err;
-}
-
 static int handle_mount(const char *source, const char *target,
                         const char *fstype, struct mount *m)
 {
@@ -966,7 +937,8 @@ static int handle_mount(const char *source, const char *target,
        return err;
 }
 
-static int blockd_notify(char *device, struct mount *m, struct probe_info *pr)
+static int blockd_notify(const char *method, char *device, struct mount *m,
+                        struct probe_info *pr)
 {
        struct ubus_context *ctx = ubus_connect(NULL);
        uint32_t id;
@@ -1019,7 +991,7 @@ static int blockd_notify(char *device, struct mount *m, struct probe_info *pr)
                        blobmsg_add_u32(&buf, "remove", 1);
                }
 
-               err = ubus_invoke(ctx, id, "hotplug", buf.head, NULL, NULL, 3000);
+               err = ubus_invoke(ctx, id, method, buf.head, NULL, NULL, 3000);
        } else {
                err = -ENOENT;
        }
@@ -1070,7 +1042,7 @@ static int mount_device(struct probe_info *pr, int type)
        }
 
        if (type == TYPE_HOTPLUG)
-               blockd_notify(device, m, pr);
+               blockd_notify("hotplug", device, m, pr);
 
        /* Check if device should be mounted & set the target directory */
        if (m) {
@@ -1127,7 +1099,7 @@ static int mount_device(struct probe_info *pr, int type)
        handle_swapfiles(true);
 
        if (type != TYPE_AUTOFS)
-               hotplug_call_mount("add", device);
+               blockd_notify("mount", device, NULL, NULL);
 
        return 0;
 }
@@ -1144,7 +1116,7 @@ static int umount_device(char *path, int type, bool all)
                return 0;
 
        if (type != TYPE_AUTOFS)
-               hotplug_call_mount("remove", basename(path));
+               blockd_notify("umount", basename(path), NULL, NULL);
 
        err = umount2(mp, MNT_DETACH);
        if (err) {
@@ -1169,7 +1141,7 @@ static int mount_action(char *action, char *device, int type)
 
        if (!strcmp(action, "remove")) {
                if (type == TYPE_HOTPLUG)
-                       blockd_notify(device, NULL, NULL);
+                       blockd_notify("hotplug", device, NULL, NULL);
 
                umount_device(path, type, true);
 
@@ -1208,6 +1180,7 @@ static int main_autofs(int argc, char **argv)
                cache_load(0);
                list_for_each_entry(pr, &devices, list) {
                        struct mount *m;
+                       char *mp;
 
                        if (!strcmp(pr->type, "swap"))
                                continue;
@@ -1216,7 +1189,11 @@ static int main_autofs(int argc, char **argv)
                        if (m && m->extroot)
                                continue;
 
-                       blockd_notify(pr->dev, m, pr);
+                       blockd_notify("hotplug", pr->dev, m, pr);
+                       if (!m->autofs && (mp = find_mount_point(pr->dev))) {
+                               blockd_notify("mount", pr->dev, NULL, NULL);
+                               free(mp);
+                       }
                }
        } else {
                if (argc < 4)
index d283f24c0af9cdc5a3522d7ca1196abfbe4fb8c2..5c7fc897a783aacac9d9a1c31c387f5ac735bf92 100644 (file)
--- a/blockd.c
+++ b/blockd.c
@@ -305,6 +305,78 @@ block_hotplug(struct ubus_context *ctx, struct ubus_object *obj,
        return 0;
 }
 
+static int blockd_mount(struct ubus_context *ctx, struct ubus_object *obj,
+                       struct ubus_request_data *req, const char *method,
+                       struct blob_attr *msg)
+{
+       struct blob_attr *data[__MOUNT_MAX];
+       struct device *device;
+       char *devname;
+
+       blobmsg_parse(mount_policy, __MOUNT_MAX, data, blob_data(msg), blob_len(msg));
+
+       if (!data[MOUNT_DEVICE])
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       devname = blobmsg_get_string(data[MOUNT_DEVICE]);
+
+       device = vlist_find(&devices, devname, device, node);
+       if (!device)
+               return UBUS_STATUS_UNKNOWN_ERROR;
+
+       hotplug_call_mount("add", device->name, NULL, NULL);
+
+       return 0;
+}
+
+struct blockd_umount_context {
+       struct ubus_context *ctx;
+       struct ubus_request_data req;
+};
+
+static void blockd_umount_hotplug_cb(struct uloop_process *p, int stat)
+{
+       struct hotplug_context *hctx = container_of(p, struct hotplug_context, process);
+       struct blockd_umount_context *c = hctx->priv;
+
+       ubus_complete_deferred_request(c->ctx, &c->req, 0);
+
+       free(c);
+       free(hctx);
+}
+
+static int blockd_umount(struct ubus_context *ctx, struct ubus_object *obj,
+                        struct ubus_request_data *req, const char *method,
+                        struct blob_attr *msg)
+{
+       struct blob_attr *data[__MOUNT_MAX];
+       struct blockd_umount_context *c;
+       char *devname;
+       int err;
+
+       blobmsg_parse(mount_policy, __MOUNT_MAX, data, blob_data(msg), blob_len(msg));
+
+       if (!data[MOUNT_DEVICE])
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       devname = blobmsg_get_string(data[MOUNT_DEVICE]);
+
+       c = calloc(1, sizeof(*c));
+       if (!c)
+               return UBUS_STATUS_UNKNOWN_ERROR;
+
+       c->ctx = ctx;
+       ubus_defer_request(ctx, req, &c->req);
+
+       err = hotplug_call_mount("remove", devname, blockd_umount_hotplug_cb, c);
+       if (err) {
+               free(c);
+               return UBUS_STATUS_UNKNOWN_ERROR;
+       }
+
+       return 0;
+}
+
 static int
 block_info(struct ubus_context *ctx, struct ubus_object *obj,
           struct ubus_request_data *req, const char *method,
@@ -341,6 +413,8 @@ block_info(struct ubus_context *ctx, struct ubus_object *obj,
 
 static const struct ubus_method block_methods[] = {
        UBUS_METHOD("hotplug", block_hotplug, mount_policy),
+       UBUS_METHOD("mount", blockd_mount, mount_policy),
+       UBUS_METHOD("umount", blockd_umount, mount_policy),
        UBUS_METHOD_NOARG("info", block_info),
 };