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/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); } /** 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); diff --git a/fs/fs.c b/fs/fs.c index 13df71c92..3923ec67b 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -167,45 +167,21 @@ 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) +static struct mtab_entry *get_mtab_entry_by_path(const char *path) { - struct mtab_entry *match = NULL, *e = mtab; - char *path, *tok; + struct mtab_entry *e = NULL; - if (*_path != '/') - return NULL; - - path = strdup(_path); - - tok = strchr(path + 1, '/'); - if (tok) - *tok = 0; - - while (e) { - if (!strcmp(path, e->path)) { - match = e; - break; - } - e = e->next; + for_each_mtab_entry(e) { + int len = strlen(e->path); + if (!strncmp(path, e->path, len) && + (path[len] == '/' || path[len] == 0)) + return e; } - free(path); - - return match ? match : mtab; -} - -struct mtab_entry *mtab_next_entry(struct mtab_entry *e) -{ - if (!e) - return mtab; - return e->next; -} - -const char *fsdev_get_mountpoint(struct fs_device_d *fsdev) -{ - return fsdev->mtab.path; + return mtab_root; } static FILE files[MAX_FILES]; @@ -248,7 +224,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; @@ -721,12 +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) { - list_add_tail(&fsdrv->list, &fs_driver_list); + fsdrv->drv.bus = &fs_bus; register_driver(&fsdrv->drv); + return 0; } EXPORT_SYMBOL(register_fs_driver); @@ -739,11 +770,7 @@ 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 *dev, *parent_device = NULL; - struct cdev *cdev = NULL; int ret; char *path = normalise_path(_path); @@ -751,135 +778,89 @@ 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; - goto out; - } - - list_for_each_entry(f, &fs_driver_list, list) { - if (!strcmp(f->drv.name, fsname)) { - fs_drv = f; - break; + 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 (!fs_drv) { - errno = -EINVAL; - goto out; - } - - if (mtab) { 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; } } 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); + 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); - - dev = &fsdev->dev; - - /* add mtab entry */ - entry = &fsdev->mtab; - 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; - } 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); 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; - unregister_device(entry->dev); - fsdev = entry->dev->type_data; - free(fsdev->backingstore); - free(fsdev); return 0; } @@ -951,11 +932,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..656160dd5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -72,23 +72,25 @@ struct fs_driver_d { struct driver_d drv; unsigned long flags; - - struct list_head list; }; struct mtab_entry { - char path[PATH_MAX]; - struct mtab_entry *next; + char *path; 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 */ struct fs_driver_d *driver; + struct cdev *cdev; struct mtab_entry mtab; }; @@ -142,15 +144,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 - */ -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); - /* * Read a file into memory. Memory is allocated with malloc and must * be freed with free() afterwards. This function allocates one diff --git a/include/linux/list.h b/include/linux/list.h index 15ed499ca..5ae90b43a 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) {