diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2014-02-27 21:39:05 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-02-28 11:19:07 +0100 |
commit | 2a644bed634bdf8afdd79e672fd67306a0e5dc3c (patch) | |
tree | 4e470c1fdc30b405d32ddab0586a8394be4226d9 /fs/devfs-core.c | |
parent | 14d0355d7c1b55bc4713b8c7768ae012840bbc85 (diff) | |
download | barebox-2a644bed634bdf8afdd79e672fd67306a0e5dc3c.tar.gz |
devfs: partitioning: add new helper devfs_create_partitions
Compared to devfs_add_partition which adds a single partition
devfs_create_partitions creates several partitions at once. One nice
benefit is that this simplifies appending partitions because the start
of the latter partition doesn't need to be specified explicitly.
Also dev_add_bb_dev() is called by the new helper if the bbname is
specified for a partition.
Note that adding partitions is also more flexible now (also via
devfs_add_partition) because negative values for offset and size now
have a proper meaning instead of creating broken partitions.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'fs/devfs-core.c')
-rw-r--r-- | fs/devfs-core.c | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/fs/devfs-core.c b/fs/devfs-core.c index f92a07c43d..193cd10234 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -22,6 +22,7 @@ #include <errno.h> #include <malloc.h> #include <ioctl.h> +#include <nand.h> #include <linux/err.h> #include <linux/mtd/mtd.h> @@ -260,36 +261,57 @@ int devfs_remove(struct cdev *cdev) return 0; } -struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size, - unsigned int flags, const char *name) +static struct cdev *__devfs_add_partition(struct cdev *cdev, + const struct devfs_partition *partinfo, loff_t *end) { - struct cdev *cdev, *new; + loff_t offset, size; + static struct cdev *new; - cdev = cdev_by_name(name); - if (cdev) + if (cdev_by_name(partinfo->name)) return ERR_PTR(-EEXIST); - cdev = cdev_by_name(devname); - if (!cdev) - return ERR_PTR(-ENOENT); - - if (offset + size > cdev->size) + if (partinfo->offset > 0) + offset = partinfo->offset; + else if (partinfo->offset == 0) + /* append to previous partition */ + offset = *end; + else + /* relative to end of cdev */ + offset = cdev->size + partinfo->offset; + + if (partinfo->size > 0) + size = partinfo->size; + else + size = cdev->size + partinfo->size - offset; + + if (offset >= 0 && offset < *end) + pr_debug("partition %s not after previous partition\n", + partinfo->name); + + *end = offset + size; + + if (offset < 0 || *end > cdev->size) { + pr_warn("partition %s not completely inside device %s\n", + partinfo->name, cdev->name); return ERR_PTR(-EINVAL); + } - new = xzalloc(sizeof (*new)); - new->name = strdup(name); - if (!strncmp(devname, name, strlen(devname))) - new->partname = xstrdup(name + strlen(devname) + 1); + new = xzalloc(sizeof(*new)); + new->name = strdup(partinfo->name); + if (!strncmp(cdev->name, partinfo->name, strlen(cdev->name))) + new->partname = xstrdup(partinfo->name + strlen(cdev->name) + 1); new->ops = cdev->ops; new->priv = cdev->priv; new->size = size; - new->offset = offset + cdev->offset; + new->offset = cdev->offset + offset; + new->dev = cdev->dev; - new->flags = flags | DEVFS_IS_PARTITION; + new->flags = partinfo->flags | DEVFS_IS_PARTITION; #ifdef CONFIG_PARTITION_NEED_MTD if (cdev->mtd) { - new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); + new->mtd = mtd_add_partition(cdev->mtd, offset, size, + partinfo->flags, partinfo->name); if (IS_ERR(new->mtd)) { int ret = PTR_ERR(new->mtd); free(new->partname); @@ -304,6 +326,25 @@ struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size return new; } +struct cdev *devfs_add_partition(const char *devname, loff_t offset, + loff_t size, unsigned int flags, const char *name) +{ + struct cdev *cdev; + loff_t end = 0; + const struct devfs_partition partinfo = { + .offset = offset, + .size = size, + .flags = flags, + .name = name, + }; + + cdev = cdev_by_name(devname); + if (!cdev) + return ERR_PTR(-ENOENT); + + return __devfs_add_partition(cdev, &partinfo, &end); +} + int devfs_del_partition(const char *name) { struct cdev *cdev; @@ -333,3 +374,27 @@ int devfs_del_partition(const char *name) return 0; } + +int devfs_create_partitions(const char *devname, + const struct devfs_partition partinfo[]) +{ + loff_t offset = 0; + struct cdev *cdev; + + cdev = cdev_by_name(devname); + if (!cdev) + return -ENOENT; + + for (; partinfo->name; ++partinfo) { + struct cdev *new; + + new = __devfs_add_partition(cdev, partinfo, &offset); + if (IS_ERR(new)) + return PTR_ERR(new); + + if (partinfo->bbname) + dev_add_bb_dev(partinfo->name, partinfo->bbname); + } + + return 0; +} |