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>
This commit is contained in:
parent
14d0355d7c
commit
2a644bed63
|
@ -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 (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 (offset + size > cdev->size)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -491,6 +491,39 @@ struct cdev *devfs_add_partition(const char *devname, loff_t offset,
|
|||
loff_t size, unsigned int flags, const char *name);
|
||||
int devfs_del_partition(const char *name);
|
||||
|
||||
#define DEVFS_PARTITION_APPEND 0
|
||||
|
||||
/**
|
||||
* struct devfs_partition - defines parameters for a single partition
|
||||
* @offset: start of partition
|
||||
* a negative offset requests to start the partition relative to the
|
||||
* device's end. DEVFS_PARTITION_APPEND (i.e. 0) means start directly at
|
||||
* the end of the previous partition.
|
||||
* @size: size of partition
|
||||
* a non-positive value requests to use a size that keeps -size free space
|
||||
* after the current partition. A special case of this is passing 0, which
|
||||
* means "until end of device".
|
||||
* @flags: flags passed to devfs_add_partition
|
||||
* @name: name passed to devfs_add_partition
|
||||
* @bbname: if non-NULL also dev_add_bb_dev() is called for the partition during
|
||||
* devfs_create_partitions().
|
||||
*/
|
||||
struct devfs_partition {
|
||||
loff_t offset;
|
||||
loff_t size;
|
||||
unsigned int flags;
|
||||
const char *name;
|
||||
const char *bbname;
|
||||
};
|
||||
/**
|
||||
* devfs_create_partitions - create a set of partitions for a device
|
||||
* @devname: name of the device to partition
|
||||
* @partinfo: array of partition parameters
|
||||
* The array is processed until an entry with .name = NULL is found.
|
||||
*/
|
||||
int devfs_create_partitions(const char *devname,
|
||||
const struct devfs_partition partinfo[]);
|
||||
|
||||
#define DRV_OF_COMPAT(compat) \
|
||||
IS_ENABLED(CONFIG_OFDEVICE) ? (compat) : NULL
|
||||
|
||||
|
|
Loading…
Reference in New Issue