From 6ca081d53dde57475600a9ea65856c6fbbdfd9f0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 14:41:08 +0100 Subject: [PATCH 01/12] add list_is_singular Signed-off-by: Sascha Hauer --- include/linux/list.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index 1a4cbc49a..eb1b640e2 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -210,6 +210,15 @@ static inline int list_empty_careful(const struct list_head *head) return (next == head) && (next == head->prev); } +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + static inline void __list_splice(struct list_head *list, struct list_head *head) { From 80b767748b0dca9939315d95326dd76f93ffff88 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 13 Feb 2012 19:42:17 +0100 Subject: [PATCH 02/12] dos partitions: Do not register as fixed partitions A fixed partition means that we can't remove it. This is only suitable for our vital /dev/self0 and /dev/env0 partitions, so remove the fixed flag. Signed-off-by: Sascha Hauer --- common/partitions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/partitions.c b/common/partitions.c index e4f3ad69e..74b4f1201 100644 --- a/common/partitions.c +++ b/common/partitions.c @@ -163,7 +163,7 @@ static int register_one_partition(struct block_device *blk, return devfs_add_partition(blk->cdev.name, part->first_sec * SECTOR_SIZE, part->size * SECTOR_SIZE, - DEVFS_PARTITION_FIXED, partition_name); + 0, partition_name); } /** From 8a81eab8463d1320585e9e1c606636701ddf57db Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 14:29:19 +0100 Subject: [PATCH 03/12] fs: Store mtab entries in list To make the code a bit easier to read. Also, do not allow to umount / when something else is mounted. Signed-off-by: Sascha Hauer --- commands/mount.c | 17 +++++------ fs/fs.c | 76 ++++++++++++++++++++---------------------------- include/fs.h | 6 ++-- 3 files changed, 43 insertions(+), 56 deletions(-) diff --git a/commands/mount.c b/commands/mount.c index 7cefdbea2..926cd3fbf 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -33,18 +33,15 @@ static int do_mount(struct command *cmdtp, int argc, char *argv[]) { int ret = 0; - struct mtab_entry *entry = NULL; + struct mtab_entry *entry; if (argc == 1) { - do { - entry = mtab_next_entry(entry); - if (entry) { - printf("%s on %s type %s\n", - entry->parent_device ? dev_name(entry->parent_device) : "none", - entry->path, - entry->dev->name); - } - } while (entry); + for_each_mtab_entry(entry) { + printf("%s on %s type %s\n", + entry->parent_device ? dev_name(entry->parent_device) : "none", + entry->path, + entry->dev->name); + } return 0; } diff --git a/fs/fs.c b/fs/fs.c index 13df71c92..3dfbaaa36 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -167,11 +167,12 @@ char *normalise_path(const char *pathname) } EXPORT_SYMBOL(normalise_path); -static struct mtab_entry *mtab; +LIST_HEAD(mtab_list); +static struct mtab_entry *mtab_root; struct mtab_entry *get_mtab_entry_by_path(const char *_path) { - struct mtab_entry *match = NULL, *e = mtab; + struct mtab_entry *e = NULL; char *path, *tok; if (*_path != '/') @@ -183,24 +184,15 @@ struct mtab_entry *get_mtab_entry_by_path(const char *_path) if (tok) *tok = 0; - while (e) { - if (!strcmp(path, e->path)) { - match = e; - break; - } - e = e->next; + for_each_mtab_entry(e) { + if (!strcmp(path, e->path)) + goto found; } - + e = mtab_root; +found: free(path); - return match ? match : mtab; -} - -struct mtab_entry *mtab_next_entry(struct mtab_entry *e) -{ - if (!e) - return mtab; - return e->next; + return e; } const char *fsdev_get_mountpoint(struct fs_device_d *fsdev) @@ -248,7 +240,7 @@ static struct device_d *get_fs_device_by_path(char **path) e = get_mtab_entry_by_path(*path); if (!e) return NULL; - if (e != mtab) + if (e != mtab_root) *path += strlen(e->path); dev = e->dev; @@ -751,11 +743,6 @@ int mount(const char *device, const char *fsname, const char *_path) debug("mount: %s on %s type %s\n", device, path, fsname); - if (get_mtab_entry_by_path(path) != mtab) { - errno = -EBUSY; - goto out; - } - if (strchr(path + 1, '/')) { printf("mounting allowed on first directory level only\n"); errno = -EBUSY; @@ -774,7 +761,7 @@ int mount(const char *device, const char *fsname, const char *_path) goto out; } - if (mtab) { + if (mtab_root) { if (path_check_prereq(path, S_IFDIR)) goto out; } else { @@ -825,16 +812,12 @@ int mount(const char *device, const char *fsname, const char *_path) safe_strncpy(entry->path, path, PATH_MAX); entry->dev = dev; entry->parent_device = parent_device; - entry->next = NULL; - if (!mtab) - mtab = entry; - else { - struct mtab_entry *e = mtab; - while (e->next) - e = e->next; - e->next = entry; - } + list_add_tail(&entry->list, &mtab_list); + + if (!mtab_root) + mtab_root = entry; + errno = 0; free(path); @@ -854,27 +837,32 @@ EXPORT_SYMBOL(mount); int umount(const char *pathname) { - struct mtab_entry *entry = mtab; - struct mtab_entry *last = mtab; + struct mtab_entry *entry = NULL, *e; char *p = normalise_path(pathname); struct fs_device_d *fsdev; - while(entry && strcmp(p, entry->path)) { - last = entry; - entry = entry->next; + for_each_mtab_entry(e) { + if (!strcmp(p, e->path)) { + entry = e; + break; + } } free(p); + if (e == mtab_root && !list_is_singular(&mtab_list)) { + errno = -EBUSY; + return errno; + } + if (!entry) { errno = -EFAULT; return errno; } - if (entry == mtab) - mtab = mtab->next; - else - last->next = entry->next; + list_del(&entry->list); + if (entry == mtab_root) + mtab_root = NULL; unregister_device(entry->dev); fsdev = entry->dev->type_data; @@ -951,11 +939,11 @@ int stat(const char *filename, struct stat *s) goto out; } - if (e != mtab && strcmp(f, e->path)) { + if (e != mtab_root && strcmp(f, e->path)) { f += strlen(e->path); dev = e->dev; } else - dev = mtab->dev; + dev = mtab_root->dev; fsdrv = (struct fs_driver_d *)dev->driver->type_data; diff --git a/include/fs.h b/include/fs.h index 97d5995c1..dd106770d 100644 --- a/include/fs.h +++ b/include/fs.h @@ -78,11 +78,14 @@ struct fs_driver_d { struct mtab_entry { char path[PATH_MAX]; - struct mtab_entry *next; struct device_d *dev; struct device_d *parent_device; + struct list_head list; }; +extern struct list_head mtab_list; +#define for_each_mtab_entry(e) list_for_each_entry(e, &mtab_list, list) + struct fs_device_d { char *backingstore; /* the device we are associated with */ struct device_d dev; /* our own device */ @@ -148,7 +151,6 @@ char *mkmodestr(unsigned long mode, char *str); * directly in / and of course the root directory itself */ struct mtab_entry *get_mtab_entry_by_path(const char *path); -struct mtab_entry *mtab_next_entry(struct mtab_entry *entry); const char *fsdev_get_mountpoint(struct fs_device_d *fsdev); /* From 2c2fb6a9478aea297b9458c5c312a502eea060a6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 14:45:17 +0100 Subject: [PATCH 04/12] fs: make locally used function get_mtab_entry_by_path static Signed-off-by: Sascha Hauer --- fs/fs.c | 2 +- include/fs.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 3dfbaaa36..afa0198b6 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -170,7 +170,7 @@ EXPORT_SYMBOL(normalise_path); LIST_HEAD(mtab_list); static struct mtab_entry *mtab_root; -struct mtab_entry *get_mtab_entry_by_path(const char *_path) +static struct mtab_entry *get_mtab_entry_by_path(const char *_path) { struct mtab_entry *e = NULL; char *path, *tok; diff --git a/include/fs.h b/include/fs.h index dd106770d..d31fb2052 100644 --- a/include/fs.h +++ b/include/fs.h @@ -150,7 +150,6 @@ char *mkmodestr(unsigned long mode, char *str); * Note that we only support mounting on directories lying * directly in / and of course the root directory itself */ -struct mtab_entry *get_mtab_entry_by_path(const char *path); const char *fsdev_get_mountpoint(struct fs_device_d *fsdev); /* From ec1d29e61c6d83d3d99bf8bd9ff5d2cee96460c1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 14:42:09 +0100 Subject: [PATCH 05/12] fs: Store mtab path in allocated string Signed-off-by: Sascha Hauer --- fs/fs.c | 5 +++-- include/fs.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index afa0198b6..d65a41fc6 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -808,8 +808,8 @@ int mount(const char *device, const char *fsname, const char *_path) dev = &fsdev->dev; /* add mtab entry */ - entry = &fsdev->mtab; - safe_strncpy(entry->path, path, PATH_MAX); + entry = &fsdev->mtab; + entry->path = xstrdup(path); entry->dev = dev; entry->parent_device = parent_device; @@ -860,6 +860,7 @@ int umount(const char *pathname) return errno; } + free(entry->path); list_del(&entry->list); if (entry == mtab_root) mtab_root = NULL; diff --git a/include/fs.h b/include/fs.h index d31fb2052..f1a193163 100644 --- a/include/fs.h +++ b/include/fs.h @@ -77,7 +77,7 @@ struct fs_driver_d { }; struct mtab_entry { - char path[PATH_MAX]; + char *path; struct device_d *dev; struct device_d *parent_device; struct list_head list; From fcec314b097fc25a0f6bc5f5ea72fe1558f3e6ff Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 14:45:54 +0100 Subject: [PATCH 06/12] fs: remove unused function fsdev_get_mountpoint Signed-off-by: Sascha Hauer --- fs/fs.c | 5 ----- include/fs.h | 7 ------- 2 files changed, 12 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index d65a41fc6..7175e331f 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -195,11 +195,6 @@ found: return e; } -const char *fsdev_get_mountpoint(struct fs_device_d *fsdev) -{ - return fsdev->mtab.path; -} - static FILE files[MAX_FILES]; static FILE *get_file(void) diff --git a/include/fs.h b/include/fs.h index f1a193163..8daa1bcbc 100644 --- a/include/fs.h +++ b/include/fs.h @@ -145,13 +145,6 @@ int ls(const char *path, ulong flags); char *mkmodestr(unsigned long mode, char *str); -/* - * Information about mounted devices. - * Note that we only support mounting on directories lying - * directly in / and of course the root directory itself - */ -const char *fsdev_get_mountpoint(struct fs_device_d *fsdev); - /* * Read a file into memory. Memory is allocated with malloc and must * be freed with free() afterwards. This function allocates one From 336ad5ce68f387e60b8862c709782a3e4cd7ee1e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 11 Feb 2012 15:01:16 +0100 Subject: [PATCH 07/12] fs: simplify get_mtab_entry_by_path Signed-off-by: Sascha Hauer --- fs/fs.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 7175e331f..121bf6fd0 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -170,29 +170,18 @@ EXPORT_SYMBOL(normalise_path); LIST_HEAD(mtab_list); static struct mtab_entry *mtab_root; -static struct mtab_entry *get_mtab_entry_by_path(const char *_path) +static struct mtab_entry *get_mtab_entry_by_path(const char *path) { struct mtab_entry *e = NULL; - char *path, *tok; - - if (*_path != '/') - return NULL; - - path = strdup(_path); - - tok = strchr(path + 1, '/'); - if (tok) - *tok = 0; for_each_mtab_entry(e) { - if (!strcmp(path, e->path)) - goto found; + int len = strlen(e->path); + if (!strncmp(path, e->path, len) && + (path[len] == '/' || path[len] == 0)) + return e; } - e = mtab_root; -found: - free(path); - return e; + return mtab_root; } static FILE files[MAX_FILES]; From b0c22c2f34a6bc51a70bef138f211d30ca085d0b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 14 Feb 2012 19:53:10 +0100 Subject: [PATCH 08/12] fs: remove only once used variable dev is used only once, so make the code a tiny bit simpler by not using an extra variable but dereference it when needed directly. Signed-off-by: Sascha Hauer --- fs/fs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 121bf6fd0..7bb5d8ef0 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -718,7 +718,7 @@ int mount(const char *device, const char *fsname, const char *_path) struct fs_driver_d *fs_drv = NULL, *f; struct mtab_entry *entry; struct fs_device_d *fsdev; - struct device_d *dev, *parent_device = NULL; + struct device_d *parent_device = NULL; struct cdev *cdev = NULL; int ret; char *path = normalise_path(_path); @@ -789,12 +789,10 @@ int mount(const char *device, const char *fsname, const char *_path) if (parent_device) dev_add_child(parent_device, &fsdev->dev); - dev = &fsdev->dev; - /* add mtab entry */ entry = &fsdev->mtab; entry->path = xstrdup(path); - entry->dev = dev; + entry->dev = &fsdev->dev; entry->parent_device = parent_device; list_add_tail(&entry->list, &mtab_list); From 33b5ead7e63a8051805adf38b3c9728283e18f2b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 14 Feb 2012 21:14:25 +0100 Subject: [PATCH 09/12] fs: remove fs devices list We store the fs devices in a list only because we want to check if the fs driver needs a backingstore or not. The driver will bail out anyway if it needs a backingstore and doesn't find one. So we can remove this check and thus remove the list of fs devices. Signed-off-by: Sascha Hauer --- fs/fs.c | 23 +---------------------- include/fs.h | 2 -- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 7bb5d8ef0..3e65c6420 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -701,7 +701,6 @@ static LIST_HEAD(fs_driver_list); int register_fs_driver(struct fs_driver_d *fsdrv) { - list_add_tail(&fsdrv->list, &fs_driver_list); register_driver(&fsdrv->drv); return 0; } @@ -715,7 +714,6 @@ EXPORT_SYMBOL(register_fs_driver); */ int mount(const char *device, const char *fsname, const char *_path) { - struct fs_driver_d *fs_drv = NULL, *f; struct mtab_entry *entry; struct fs_device_d *fsdev; struct device_d *parent_device = NULL; @@ -733,18 +731,6 @@ int mount(const char *device, const char *fsname, const char *_path) goto out; } - list_for_each_entry(f, &fs_driver_list, list) { - if (!strcmp(f->drv.name, fsname)) { - fs_drv = f; - break; - } - } - - if (!fs_drv) { - errno = -EINVAL; - goto out; - } - if (mtab_root) { if (path_check_prereq(path, S_IFDIR)) goto out; @@ -757,14 +743,7 @@ int mount(const char *device, const char *fsname, const char *_path) } fsdev = xzalloc(sizeof(struct fs_device_d)); - if (!(fs_drv->flags & FS_DRIVER_NO_DEV)) { - fsdev->backingstore = strdup(device); - if (!device) { - printf("need a device for driver %s\n", fsname); - errno = -ENODEV; - goto out1; - } - } + fsdev->backingstore = xstrdup(device); safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME); fsdev->dev.type_data = fsdev; fsdev->dev.id = get_free_deviceid(fsdev->dev.name); diff --git a/include/fs.h b/include/fs.h index 8daa1bcbc..fcaef32e2 100644 --- a/include/fs.h +++ b/include/fs.h @@ -72,8 +72,6 @@ struct fs_driver_d { struct driver_d drv; unsigned long flags; - - struct list_head list; }; struct mtab_entry { From 9bf08d582a5016ed7c74bffe23901fa06ed27afa Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 14 Feb 2012 23:07:57 +0100 Subject: [PATCH 10/12] fs: put fs devices on its own bus By putting the fs devices/drivers on a bus on its own we can hook into the bus remove function to cleanup the fs device. This way we can unmount a device by simply unregistering the device which is useful for for example USB mass storage devices. These can now unregister the assoiated filesystems by unregistering their child devices. Signed-off-by: Sascha Hauer --- fs/fs.c | 122 ++++++++++++++++++++++++++++++++------------------- include/fs.h | 1 + 2 files changed, 77 insertions(+), 46 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 3e65c6420..637a01f8c 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -697,11 +697,67 @@ int close(int fd) } EXPORT_SYMBOL(close); -static LIST_HEAD(fs_driver_list); +static int fs_match(struct device_d *dev, struct driver_d *drv) +{ + return strcmp(dev->name, drv->name) ? -1 : 0; +} + +static int fs_probe(struct device_d *dev) +{ + struct fs_device_d *fsdev = container_of(dev, struct fs_device_d, dev); + struct mtab_entry *entry = &fsdev->mtab; + int ret; + + ret = dev->driver->probe(dev); + if (ret) + return ret; + + if (fsdev->cdev) { + dev_add_child(fsdev->cdev->dev, &fsdev->dev); + entry->parent_device = fsdev->cdev->dev; + } + + entry->dev = &fsdev->dev; + + list_add_tail(&entry->list, &mtab_list); + + if (!mtab_root) + mtab_root = entry; + + return 0; +} + +static void fs_remove(struct device_d *dev) +{ + struct fs_device_d *fsdev = container_of(dev, struct fs_device_d, dev); + struct mtab_entry *entry = &fsdev->mtab; + + if (fsdev->dev.driver) { + dev->driver->remove(dev); + list_del(&entry->list); + } + + free(entry->path); + + if (entry == mtab_root) + mtab_root = NULL; + + free(fsdev->backingstore); + free(fsdev); +} + +struct bus_type fs_bus = { + .name = "fs", + .match = fs_match, + .probe = fs_probe, + .remove = fs_remove, +}; int register_fs_driver(struct fs_driver_d *fsdrv) { + fsdrv->drv.bus = &fs_bus; register_driver(&fsdrv->drv); + return 0; } EXPORT_SYMBOL(register_fs_driver); @@ -714,10 +770,7 @@ EXPORT_SYMBOL(register_fs_driver); */ int mount(const char *device, const char *fsname, const char *_path) { - struct mtab_entry *entry; struct fs_device_d *fsdev; - struct device_d *parent_device = NULL; - struct cdev *cdev = NULL; int ret; char *path = normalise_path(_path); @@ -728,17 +781,17 @@ int mount(const char *device, const char *fsname, const char *_path) if (strchr(path + 1, '/')) { printf("mounting allowed on first directory level only\n"); errno = -EBUSY; - goto out; + goto err_free_path; } if (mtab_root) { if (path_check_prereq(path, S_IFDIR)) - goto out; + goto err_free_path; } else { /* no mtab, so we only allow to mount on '/' */ if (*path != '/' || *(path + 1)) { errno = -ENOTDIR; - goto out; + goto err_free_path; } } @@ -747,51 +800,37 @@ int mount(const char *device, const char *fsname, const char *_path) safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME); fsdev->dev.type_data = fsdev; fsdev->dev.id = get_free_deviceid(fsdev->dev.name); + fsdev->mtab.path = xstrdup(path); + fsdev->dev.bus = &fs_bus; + + if (!strncmp(device, "/dev/", 5)) + fsdev->cdev = cdev_by_name(device + 5); if ((ret = register_device(&fsdev->dev))) { errno = ret; - goto out1; + goto err_register; } if (!fsdev->dev.driver) { - /* driver didn't accept the device. Bail out */ + /* + * Driver didn't accept the device or no driver for this + * device. Bail out + */ errno = -EINVAL; - goto out2; + goto err_no_driver; } - if (!strncmp(device, "/dev/", 5)) { - cdev = cdev_by_name(device + 5); - if(cdev) - parent_device = cdev->dev; - } - - if (parent_device) - dev_add_child(parent_device, &fsdev->dev); - - /* add mtab entry */ - entry = &fsdev->mtab; - entry->path = xstrdup(path); - entry->dev = &fsdev->dev; - entry->parent_device = parent_device; - - list_add_tail(&entry->list, &mtab_list); - - if (!mtab_root) - mtab_root = entry; - errno = 0; - free(path); return 0; -out2: +err_no_driver: unregister_device(&fsdev->dev); -out1: - if (fsdev->backingstore) - free(fsdev->backingstore); - free(fsdev); -out: +err_register: + fs_remove(&fsdev->dev); +err_free_path: free(path); + return errno; } EXPORT_SYMBOL(mount); @@ -800,7 +839,6 @@ int umount(const char *pathname) { struct mtab_entry *entry = NULL, *e; char *p = normalise_path(pathname); - struct fs_device_d *fsdev; for_each_mtab_entry(e) { if (!strcmp(p, e->path)) { @@ -821,15 +859,7 @@ int umount(const char *pathname) return errno; } - free(entry->path); - list_del(&entry->list); - if (entry == mtab_root) - mtab_root = NULL; - unregister_device(entry->dev); - fsdev = entry->dev->type_data; - free(fsdev->backingstore); - free(fsdev); return 0; } diff --git a/include/fs.h b/include/fs.h index fcaef32e2..656160dd5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -90,6 +90,7 @@ struct fs_device_d { struct fs_driver_d *driver; + struct cdev *cdev; struct mtab_entry mtab; }; From 62d8b2f8c088f73cf929d6c5be360846c6bfb556 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Feb 2012 08:48:36 +0100 Subject: [PATCH 11/12] fs: allow to mount on subdirectories Since get_mtab_entry_by_path() is a bit more flexible now we no longer have to force the user to mount on the root directory only. Instead, we can allow to mount on subdirectories aswell. Nested mounts are still not possible though. Signed-off-by: Sascha Hauer --- fs/fs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 637a01f8c..3923ec67b 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -778,13 +778,14 @@ int mount(const char *device, const char *fsname, const char *_path) debug("mount: %s on %s type %s\n", device, path, fsname); - if (strchr(path + 1, '/')) { - printf("mounting allowed on first directory level only\n"); - errno = -EBUSY; - goto err_free_path; - } - if (mtab_root) { + struct mtab_entry *entry; + entry = get_mtab_entry_by_path(path); + if (entry != mtab_root) { + printf("sorry, no nested mounts\n"); + errno = -EBUSY; + goto err_free_path; + } if (path_check_prereq(path, S_IFDIR)) goto err_free_path; } else { From 491cc29b0a2cf7c675e94e00eed2d58934a76011 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 13 Feb 2012 19:46:10 +0100 Subject: [PATCH 12/12] devices: unregister children when unregistering a device We currently do not allow to unregister a device when it has children. However, the return value is seldomly checked. Also this breaks for hot pluggable devices like USB which we have to unregister when they disappear. The best way to fix this is to unregister our children and also the partitions on the unregistered device. We unregister the device first and then afterwards the children. We do this because for example network devices have a miidev as child which they unregister themselves. So we only have to unregister the children which are not cleaned up by the drivers, namely fs devices. Also, unregister all partitions on a disappearing device. Signed-off-by: Sascha Hauer --- drivers/base/driver.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 0132e7dcf..3777f82d6 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -137,16 +137,26 @@ EXPORT_SYMBOL(register_device); int unregister_device(struct device_d *old_dev) { - debug("unregister_device: %s\n", dev_name(old_dev)); + struct cdev *cdev, *ct; + struct device_d *child, *dt; - if (!list_empty(&old_dev->children)) { - errno = -EBUSY; - return errno; - } + dev_dbg(old_dev, "unregister\n"); if (old_dev->driver) old_dev->bus->remove(old_dev); + list_for_each_entry_safe(child, dt, &old_dev->children, sibling) { + dev_dbg(old_dev, "unregister child %s\n", dev_name(child)); + unregister_device(child); + } + + list_for_each_entry_safe(cdev, ct, &old_dev->cdevs, devices_list) { + if (cdev->flags & DEVFS_IS_PARTITION) { + dev_dbg(old_dev, "unregister part %s\n", cdev->name); + devfs_del_partition(cdev->name); + } + } + list_del(&old_dev->list); list_del(&old_dev->active);