[PATCH] fstools: block: allow multiple mount points for a single device

沈ビ shinkosame at gmail.com
Sun Mar 22 18:24:54 PDT 2026


Hi Paul

Thanks for the review!

> Small remark,: code after "return" is dead code, consequently an "else" after "return" is useless.

You are right, the 'else' is redundant here. I will clean this up and
submit a v3 (version 3) shortly.

Best regards,
Shen Wei

2026年3月18日(水) 1:40 <por at oranjevos.nl>:
>
> Small remark,: code after "return" is dead code, consequently an "else" after "return" is useless.
> See suggestions below.
>
> Not reviewed otherwise.
> Good luck
> Paul
>
> Op 11 mrt 2026, om 01:39 heeft Shen Wei <shinkosame at gmail.com> het volgende geschreven:
> >
> > From: shinkosame <shinkosame at gmail.com>
> >
> > Previously, if multiple 'mount' sections in /etc/config/fstab referred
> > to the same physical device (via UUID, Label, or device path), the
> > latter configuration would override the previous ones, resulting in
> > only one active mount point.
> >
> > This patch modifies the device matching logic to allow a single
> > source device to be mounted to multiple target paths. This is
> > particularly useful for users who need to expose the same partition
> > in different directory structures.
> >
> > Signed-off-by: Shen Wei <shinkosame at gmail.com>
> > ---
> > block.c | 409 +++++++++++++++++++++++++++++++++++---------------------
> > 1 file changed, 260 insertions(+), 149 deletions(-)
> >
> > diff --git a/block.c b/block.c
> > index 37f5bfb..64a8af3 100644
> > --- a/block.c
> > +++ b/block.c
> > @@ -47,6 +47,7 @@
> > #include "probe.h"
> >
> > #define AUTOFS_MOUNT_PATH       "/tmp/run/blockd/"
> > +#define MAX_MOUNT_POINT_COUNT   10
> >
> > #ifdef UBIFS_EXTROOT
> > #include "libubi/libubi.h"
> > @@ -253,6 +254,22 @@ static void parse_mount_options(struct mount *m, char *optstr)
> >       free(optstr);
> > }
> >
> > +static char* _concat_key(char *key1, char *key2)
> > +{
> > +     if (key2) {
> > +             int klen1 = strlen(key1);
> > +             int klen2 = strlen(key2);
> > +             char *nkey = (char *) malloc(klen1 + klen2 + 2);
> > +             memcpy(nkey, key1, klen1);
> > +             nkey[klen1] = ',';
> > +             memcpy(nkey + klen1 + 1, key2, klen2);
> > +             nkey[klen1 + klen2 + 1] = '\0';
> > +             return nkey;
> > +     }
> better:
> +       return nkey;
> +}
> > else {
> > +             return strdup(key1);
> > +     }
> > +}
> > +
> > static int mount_add(struct uci_section *s)
> > {
> >       struct blob_attr *tb[__MOUNT_MAX] = { 0 };
> > @@ -294,11 +311,11 @@ static int mount_add(struct uci_section *s)
> >       }
> >
> >       if (m->uuid)
> > -             vlist_add(&mounts, &m->node, m->uuid);
> > +             vlist_add(&mounts, &m->node, _concat_key(m->uuid, m->target));
> >       else if (m->label)
> > -             vlist_add(&mounts, &m->node, m->label);
> > +             vlist_add(&mounts, &m->node, _concat_key(m->label, m->target));
> >       else if (m->device)
> > -             vlist_add(&mounts, &m->node, m->device);
> > +             vlist_add(&mounts, &m->node, _concat_key(m->device, m->target));
> >
> >       return 0;
> > }
> > @@ -387,25 +404,44 @@ static struct mount* find_swap(const char *uuid, const char *label, const char *
> >       return NULL;
> > }
> >
> > -static struct mount* find_block(const char *uuid, const char *label, const char *device,
> > +static struct mount** find_block(const char *uuid, const char *label, const char *device,
> >                               const char *target)
> > {
> > +     int msi = 0;
> > +     static struct mount *ms[MAX_MOUNT_POINT_COUNT + 1];
> >       struct mount *m;
> >
> >       vlist_for_each_element(&mounts, m, node) {
> >               if (m->type != TYPE_MOUNT)
> >                       continue;
> > -             if (m->uuid && uuid && !strcasecmp(m->uuid, uuid))
> > -                     return m;
> > -             if (m->label && label && !strcmp(m->label, label))
> > -                     return m;
> > -             if (m->target && target && !strcmp(m->target, target))
> > -                     return m;
> > -             if (m->device && device && !strcmp(m->device, device))
> > -                     return m;
> > +             if (m->uuid && uuid && !strcasecmp(m->uuid, uuid)) {
> > +                     if (msi < MAX_MOUNT_POINT_COUNT)
> > +                             ms[msi++] = m;
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +             }
> > +             if (m->label && label && !strcmp(m->label, label)) {
> > +                     if (msi < MAX_MOUNT_POINT_COUNT)
> > +                             ms[msi++] = m;
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +             }
> > +             if (m->target && target && !strcmp(m->target, target)) {
> > +                     if (msi < MAX_MOUNT_POINT_COUNT)
> > +                             ms[msi++] = m;
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +             }
> > +             if (m->device && device && !strcmp(m->device, device)) {
> > +                     if (msi < MAX_MOUNT_POINT_COUNT)
> > +                             ms[msi++] = m;
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +             }
> >       }
> >
> > -     return NULL;
> > +     ms[msi] = NULL;
> > +     return ms;
> > }
> >
> > static void mounts_update(struct vlist_tree *tree, struct vlist_node *node_new,
> > @@ -619,11 +655,13 @@ static struct probe_info* find_block_info(char *uuid, char *label, char *path)
> >       return NULL;
> > }
> >
> > -static char* find_mount_point(char *block)
> > +static char** find_mount_point(char *block)
> > {
> >       FILE *fp = fopen("/proc/self/mountinfo", "r");
> >       static char line[256];
> > -     char *point = NULL, *pos, *tmp, *cpoint, *devname;
> > +     static char *points[MAX_MOUNT_POINT_COUNT + 1];
> > +     char *pos, *tmp, *cpoint, *devname;
> > +     int point_idx = 0;
> >       struct stat s;
> >       int rstat;
> >       unsigned int minor, major;
> > @@ -687,8 +725,11 @@ static char* find_mount_point(char *block)
> >               *pos = '\0';
> >               devname = tmp;
> >               if (!strcmp(block, devname)) {
> > -                     point = strdup(cpoint);
> > -                     break;
> > +                     if (point_idx < MAX_MOUNT_POINT_COUNT)
> > +                             points[point_idx++] = strdup(cpoint);
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +                     continue;;
> >               }
> >
> >               if (rstat)
> > @@ -699,36 +740,54 @@ static char* find_mount_point(char *block)
> >
> >               if (major == major(s.st_rdev) &&
> >                   minor == minor(s.st_rdev)) {
> > -                     point = strdup(cpoint);
> > -                     break;
> > +                     if (point_idx < MAX_MOUNT_POINT_COUNT)
> > +                             points[point_idx++] = strdup(cpoint);
> > +                     else
> > +                             ULOG_WARN("Max mount point limit reached, skipping remaining objects\n");
> > +                     continue;;
> >               }
> >       }
> >
> >       fclose(fp);
> >
> > -     return point;
> > +     points[point_idx] = NULL;
> > +     return points;
> > }
> >
> > static int print_block_uci(struct probe_info *pr)
> > {
> > +     char *mp;
> >       if (!strcmp(pr->type, "swap")) {
> >               printf("config 'swap'\n");
> > +             if (pr->uuid)
> > +                     printf("\toption\tuuid\t'%s'\n", pr->uuid);
> > +             else
> > +                     printf("\toption\tdevice\t'%s'\n", pr->dev);
> > +             printf("\toption\tenabled\t'0'\n\n");
> >       } else {
> > -             char *mp = find_mount_point(pr->dev);
> > -
> > -             printf("config 'mount'\n");
> > -             if (mp) {
> > -                     printf("\toption\ttarget\t'%s'\n", mp);
> > -                     free(mp);
> > +             char **mps = find_mount_point(pr->dev);
> > +
> > +             if (*mps) {
> > +                     while ((mp = *mps++)) {
> > +                             printf("config 'mount'\n");
> > +                             printf("\toption\ttarget\t'%s'\n", mp);
> > +                             if (pr->uuid)
> > +                                     printf("\toption\tuuid\t'%s'\n", pr->uuid);
> > +                             else
> > +                                     printf("\toption\tdevice\t'%s'\n", pr->dev);
> > +                             printf("\toption\tenabled\t'0'\n\n");
> > +                             free(mp);
> > +                     }
> >               } else {
> > +                     printf("config 'mount'\n");
> >                       printf("\toption\ttarget\t'/mnt/%s'\n", basename(pr->dev));
> > +                     if (pr->uuid)
> > +                             printf("\toption\tuuid\t'%s'\n", pr->uuid);
> > +                     else
> > +                             printf("\toption\tdevice\t'%s'\n", pr->dev);
> > +                     printf("\toption\tenabled\t'0'\n\n");
> >               }
> >       }
> > -     if (pr->uuid)
> > -             printf("\toption\tuuid\t'%s'\n", pr->uuid);
> > -     else
> > -             printf("\toption\tdevice\t'%s'\n", pr->dev);
> > -     printf("\toption\tenabled\t'0'\n\n");
> >
> >       return 0;
> > }
> > @@ -737,23 +796,37 @@ static int print_block_info(struct probe_info *pr)
> > {
> >       static char *mp;
> >
> > -     mp = find_mount_point(pr->dev);
> > -     printf("%s:", pr->dev);
> > -     if (pr->uuid)
> > -             printf(" UUID=\"%s\"", pr->uuid);
> > +     char **mps = find_mount_point(pr->dev);
> > +     if (*mps) {
> > +             while ((mp = *mps++)) {
> > +                     printf("%s:", pr->dev);
> > +                     if (pr->uuid)
> > +                             printf(" UUID=\"%s\"", pr->uuid);
> >
> > -     if (pr->label)
> > -             printf(" LABEL=\"%s\"", pr->label);
> > +                     if (pr->label)
> > +                             printf(" LABEL=\"%s\"", pr->label);
> >
> > -     if (pr->version)
> > -             printf(" VERSION=\"%s\"", pr->version);
> > +                     if (pr->version)
> > +                             printf(" VERSION=\"%s\"", pr->version);
> >
> > -     if (mp) {
> > -             printf(" MOUNT=\"%s\"", mp);
> > -             free(mp);
> > -     }
> > +                     printf(" MOUNT=\"%s\"", mp);
> > +                     free(mp);
> > +
> > +                     printf(" TYPE=\"%s\"\n", pr->type);
> > +             }
> > +     } else {
> > +             printf("%s:", pr->dev);
> > +             if (pr->uuid)
> > +                     printf(" UUID=\"%s\"", pr->uuid);
> > +
> > +             if (pr->label)
> > +                     printf(" LABEL=\"%s\"", pr->label);
> >
> > -     printf(" TYPE=\"%s\"\n", pr->type);
> > +             if (pr->version)
> > +                     printf(" VERSION=\"%s\"", pr->version);
> > +
> > +             printf(" TYPE=\"%s\"\n", pr->type);
> > +     }
> >
> >       return 0;
> > }
> > @@ -1080,12 +1153,16 @@ static int blockd_notify(const char *method, char *device, struct mount *m,
> > static int mount_device(struct probe_info *pr, int type)
> > {
> >       struct mount *m;
> > +     struct mount **ms;
> >       struct stat st;
> >       char *_target = NULL;
> >       char *target;
> >       char *device;
> >       char *mp;
> > -     int err;
> > +     char **mps;
> > +     bool is_mounted;
> > +     int err = 0, err2;
> > +     int is_mnt_exist = 0;
> >
> >       if (!pr)
> >               return -1;
> > @@ -1102,131 +1179,155 @@ static int mount_device(struct probe_info *pr, int type)
> >               return 0;
> >       }
> >
> > -     m = find_block(pr->uuid, pr->label, device, NULL);
> > -     if (m && m->extroot)
> > -             return -1;
> > +     ms = find_block(pr->uuid, pr->label, device, NULL);
> > +     while ((m = *ms++)) {
> > +             if (m && m->extroot)
> > +                     continue;
> >
> > -     mp = find_mount_point(pr->dev);
> > -     if (mp) {
> > -             if (m && m->type == TYPE_MOUNT && m->target && strcmp(m->target, mp)) {
> > -                     ULOG_ERR("%s is already mounted on %s\n", pr->dev, mp);
> > -                     err = -1;
> > -             } else
> > -                     err = 0;
> > -             free(mp);
> > -             return err;
> > -     }
> > +             is_mounted = false;
> > +             mps = find_mount_point(pr->dev);
> > +             while ((mp = *mps++)) {
> > +                     if (!is_mounted && m && m->type == TYPE_MOUNT && m->target && !strcmp(m->target, mp)) {
> > +                             is_mounted = true;
> > +                     }
> > +                     free(mp);
> > +             }
> > +             if (is_mounted) {
> > +                     continue;
> > +             }
> >
> > -     if (type == TYPE_HOTPLUG)
> > -             blockd_notify("hotplug", device, m, pr);
> > +             if (type == TYPE_HOTPLUG)
> > +                     blockd_notify("hotplug", device, m, pr);
> >
> > -     /* Check if device should be mounted & set the target directory */
> > -     if (m) {
> > -             switch (type) {
> > -             case TYPE_HOTPLUG:
> > -                     if (m->autofs)
> > -                             return 0;
> > -                     if (!auto_mount)
> > -                             return -1;
> > -                     break;
> > -             case TYPE_AUTOFS:
> > -                     if (!m->autofs)
> > -                             return -1;
> > -                     break;
> > -             case TYPE_DEV:
> > -                     if (m->autofs)
> > -                             return -1;
> > -                     break;
> > -             }
> > +             /* Check if device should be mounted & set the target directory */
> > +             if (m) {
> > +                     switch (type) {
> > +                     case TYPE_HOTPLUG:
> > +                             if (m->autofs)
> > +                                     continue;;
> > +                             if (!auto_mount) {
> > +                                     err = -1;
> > +                                     continue;
> > +                             }
> > +                             break;
> > +                     case TYPE_AUTOFS:
> > +                             if (!m->autofs) {
> > +                                     err = -1;
> > +                                     continue;
> > +                             }
> > +                             break;
> > +                     case TYPE_DEV:
> > +                             if (m->autofs) {
> > +                                     err = -1;
> > +                                     continue;
> > +                             }
> > +                             break;
> > +                     }
> >
> > -             if (m->autofs) {
> > -                     if (asprintf(&_target, "/tmp/run/blockd/%s", device) == -1)
> > -                             exit(ENOMEM);
> > +                     if (m->autofs) {
> > +                             if (asprintf(&_target, "/tmp/run/blockd/%s", device) == -1)
> > +                                     exit(ENOMEM);
> >
> > -                     target = _target;
> > -             } else if (m->target) {
> > -                     target = m->target;
> > -             } else {
> > +                             target = _target;
> > +                     } else if (m->target) {
> > +                             target = m->target;
> > +                     } else {
> > +                             if (asprintf(&_target, "/mnt/%s", device) == -1)
> > +                                     exit(ENOMEM);
> > +
> > +                             target = _target;
> > +                     }
> > +             } else if (anon_mount) {
> >                       if (asprintf(&_target, "/mnt/%s", device) == -1)
> >                               exit(ENOMEM);
> >
> >                       target = _target;
> > +             } else {
> > +                     /* No reason to mount this device */
> > +                     continue;
> >               }
> > -     } else if (anon_mount) {
> > -             if (asprintf(&_target, "/mnt/%s", device) == -1)
> > -                     exit(ENOMEM);
> >
> > -             target = _target;
> > -     } else {
> > -             /* No reason to mount this device */
> > -             return 0;
> > -     }
> > +             /* Mount the device */
> >
> > -     /* Mount the device */
> > +             if (check_fs)
> > +                     check_filesystem(pr);
> >
> > -     if (check_fs)
> > -             check_filesystem(pr);
> > +             mkdir_p(target, 0755);
> > +             if (!lstat(target, &st) && S_ISLNK(st.st_mode))
> > +                     unlink(target);
> >
> > -     mkdir_p(target, 0755);
> > -     if (!lstat(target, &st) && S_ISLNK(st.st_mode))
> > -             unlink(target);
> > +             err2 = handle_mount(pr->dev, target, pr->type, m);
> > +             if (err2) {
> > +                     ULOG_ERR("mounting %s (%s) as %s failed (%d) - %m\n",
> > +                                     pr->dev, pr->type, target, errno);
> >
> > -     err = handle_mount(pr->dev, target, pr->type, m);
> > -     if (err) {
> > -             ULOG_ERR("mounting %s (%s) as %s failed (%d) - %m\n",
> > -                             pr->dev, pr->type, target, errno);
> > +                     if (_target)
> > +                             free(_target);
> > +
> > +                     err = err2;
> > +                     continue;
> > +             }
> >
> >               if (_target)
> >                       free(_target);
> >
> > -             return err;
> > -     }
> > -
> > -     if (_target)
> > -             free(_target);
> > +             handle_swapfiles(true);
> >
> > -     handle_swapfiles(true);
> > -
> > -     if (type != TYPE_AUTOFS)
> > -             blockd_notify("mount", device, NULL, NULL);
> > +             if (type != TYPE_AUTOFS)
> > +                     blockd_notify("mount", device, NULL, NULL);
> > +
> > +             is_mnt_exist = 1;
> > +     }
> >
> > -     return 0;
> > +     if (!is_mnt_exist)
> > +             return -1;
> again no "else" needed, better:
> +       return err;
> +}
> > +     else
> > +             return err;
> > }
> >
> > -static int umount_device(char *path, int type, bool all)
> > +static int umount_device(char *path, int type, bool all, bool skip_extroot)
> > {
> >       char *mp, *devpath;
> > -     int err;
> > +     char **mps;
> > +     int err = 0, err2;
> >
> >       if (strlen(path) > 5 && !strncmp("/dev/", path, 5)) {
> > -             mp = find_mount_point(path);
> > +             mps = find_mount_point(path);
> >       } else {
> >               devpath = malloc(strlen(path) + 6);
> >               strcpy(devpath, "/dev/");
> >               strcat(devpath, path);
> > -             mp = find_mount_point(devpath);
> > +             mps = find_mount_point(devpath);
> >               free(devpath);
> >       }
> >
> > -     if (!mp)
> > +     if (!mps[0])
> >               return -1;
> > -     if (!strcmp(mp, "/") && !all) {
> > -             free(mp);
> > -             return 0;
> > -     }
> > -     if (type != TYPE_AUTOFS)
> > -             blockd_notify("umount", basename(path), NULL, NULL);
> > +     while ((mp = *mps++)) {
> > +             if (skip_extroot && (!strcmp(mp, "/") || !strcmp(mp, "/overlay"))) {
> > +                     free(mp);
> > +                     continue;
> > +             }
> >
> > -     err = umount2(mp, MNT_DETACH);
> > -     if (err) {
> > -             ULOG_ERR("unmounting %s (%s) failed (%d) - %m\n", path, mp,
> > -                      errno);
> > -     } else {
> > -             ULOG_INFO("unmounted %s (%s)\n", path, mp);
> > -             rmdir(mp);
> > -     }
> > +             if (!strcmp(mp, "/") && !all) {
> > +                     free(mp);
> > +                     continue;
> > +             }
> > +             if (type != TYPE_AUTOFS)
> > +                     blockd_notify("umount", basename(path), NULL, NULL);
> > +
> > +             err2 = umount2(mp, MNT_DETACH);
> > +             if (err2) {
> > +                     ULOG_ERR("unmounting %s (%s) failed (%d) - %m\n", path, mp,
> > +                             errno);
> > +                     err = err2;
> > +             } else {
> > +                     ULOG_INFO("unmounted %s (%s)\n", path, mp);
> > +                     rmdir(mp);
> > +             }
> >
> > -     free(mp);
> > +             free(mp);
> > +     }
> >       return err;
> > }
> >
> > @@ -1242,7 +1343,7 @@ static int mount_action(char *action, char *device, int type)
> >               if (type == TYPE_HOTPLUG)
> >                       blockd_notify("hotplug", device, NULL, NULL);
> >
> > -             umount_device(device, type, true);
> > +             umount_device(device, type, true, false);
> >
> >               return 0;
> >       } else if (strcmp(action, "add")) {
> > @@ -1287,19 +1388,25 @@ static int main_autofs(int argc, char **argv)
> >               cache_load(1);
> >               list_for_each_entry(pr, &devices, list) {
> >                       struct mount *m;
> > +                     struct mount **ms;
> >                       char *mp;
> > +                     char **mps;
> >
> >                       if (!strcmp(pr->type, "swap"))
> >                               continue;
> >
> > -                     m = find_block(pr->uuid, pr->label, NULL, NULL);
> > -                     if (m && m->extroot)
> > -                             continue;
> > +                     ms = find_block(pr->uuid, pr->label, NULL, NULL);
> > +                     while ((m = *ms++)) {
> > +
> > +                             if (m && m->extroot)
> > +                                     continue;
> >
> > -                     blockd_notify("hotplug", pr->dev, m, pr);
> > -                     if ((!m || !m->autofs) && (mp = find_mount_point(pr->dev))) {
> > -                             blockd_notify("mount", pr->dev, NULL, NULL);
> > -                             free(mp);
> > +                             blockd_notify("hotplug", pr->dev, m, pr);
> > +                             if ((!m || !m->autofs) && *(mps = find_mount_point(pr->dev))) {
> > +                                     blockd_notify("mount", pr->dev, NULL, NULL);
> > +                                     while ((mp = *mps++))
> > +                                             free(mp);
> > +                             }
> >                       }
> >               }
> >       } else {
> > @@ -1561,6 +1668,7 @@ static int mount_extroot(char *cfg)
> >       char *path = mnt;
> >       struct probe_info *pr;
> >       struct mount *m;
> > +     struct mount **ms;
> >       int err = -1;
> >
> >       /* Load @cfg/etc/config/fstab */
> > @@ -1568,9 +1676,12 @@ static int mount_extroot(char *cfg)
> >               return -2;
> >
> >       /* See if there is extroot-specific mount config */
> > -     m = find_block(NULL, NULL, NULL, "/");
> > -     if (!m)
> > -             m = find_block(NULL, NULL, NULL, "/overlay");
> > +     ms = find_block(NULL, NULL, NULL, "/");
> > +     m = ms[0];
> > +     if (!m) {
> > +             ms = find_block(NULL, NULL, NULL, "/overlay");
> > +             m = ms[0];
> > +     }
> >
> >       if (!m || !m->extroot)
> >       {
> > @@ -1750,16 +1861,16 @@ static int main_umount(int argc, char **argv)
> >               all = !strcmp(argv[2], "-a");
> >
> >       list_for_each_entry(pr, &devices, list) {
> > -             struct mount *m;
> > +             // struct mount *m;
> >
> >               if (!strcmp(pr->type, "swap"))
> >                       continue;
> >
> > -             m = find_block(pr->uuid, pr->label, basename(pr->dev), NULL);
> > -             if (m && m->extroot)
> > -                     continue;
> > +             // m = find_block(pr->uuid, pr->label, basename(pr->dev), NULL);
> > +             // if (m && m->extroot)
> > +             //      continue;
> >
> > -             umount_device(pr->dev, TYPE_DEV, all);
> > +             umount_device(pr->dev, TYPE_DEV, all, true);
> >       }
> >
> >       return 0;
> > --
> > 2.51.0
> >
> >
> > _______________________________________________
> > openwrt-devel mailing list
> > openwrt-devel at lists.openwrt.org
> > https://lists.openwrt.org/mailman/listinfo/openwrt-devel
>



More information about the openwrt-devel mailing list