mtd: UBI: Add support for updating static volumes
Added support to update UBI static volumes in barebox. This is mainly realized with adding the ioctl UBI_IOCVOLUP. Signed-off-by: Teresa Remmet <t.remmet@phytec.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
2c80865bc1
commit
c087e0804f
|
@ -65,7 +65,10 @@ static ssize_t ubi_volume_cdev_write(struct cdev* cdev, const void *buf,
|
||||||
struct ubi_device *ubi = priv->ubi;
|
struct ubi_device *ubi = priv->ubi;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!priv->written) {
|
if (!priv->written && !vol->updating) {
|
||||||
|
if (vol->vol_type == UBI_STATIC_VOLUME)
|
||||||
|
return -EROFS;
|
||||||
|
|
||||||
err = ubi_start_update(ubi, vol, vol->used_bytes);
|
err = ubi_start_update(ubi, vol, vol->used_bytes);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
ubi_err(ubi, "Cannot start volume update");
|
ubi_err(ubi, "Cannot start volume update");
|
||||||
|
@ -104,7 +107,7 @@ static int ubi_volume_cdev_close(struct cdev *cdev)
|
||||||
int remaining = vol->usable_leb_size -
|
int remaining = vol->usable_leb_size -
|
||||||
(priv->written % vol->usable_leb_size);
|
(priv->written % vol->usable_leb_size);
|
||||||
|
|
||||||
if (remaining) {
|
if (remaining && vol->vol_type == UBI_DYNAMIC_VOLUME) {
|
||||||
void *buf = kmalloc(remaining, GFP_KERNEL);
|
void *buf = kmalloc(remaining, GFP_KERNEL);
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
|
@ -122,6 +125,9 @@ static int ubi_volume_cdev_close(struct cdev *cdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vol->vol_type == UBI_STATIC_VOLUME)
|
||||||
|
cdev->size = priv->written;
|
||||||
|
|
||||||
err = ubi_finish_update(ubi, vol);
|
err = ubi_finish_update(ubi, vol);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -156,12 +162,54 @@ static loff_t ubi_volume_cdev_lseek(struct cdev *cdev, loff_t ofs)
|
||||||
return ofs;
|
return ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ubi_volume_cdev_ioctl(struct cdev *cdev, int cmd, void *buf)
|
||||||
|
{
|
||||||
|
struct ubi_volume_cdev_priv *priv = cdev->priv;
|
||||||
|
struct ubi_device *ubi = priv->ubi;
|
||||||
|
struct ubi_volume *vol = priv->vol;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
/* Volume update command */
|
||||||
|
case UBI_IOCVOLUP:
|
||||||
|
{
|
||||||
|
int64_t bytes, rsvd_bytes;
|
||||||
|
|
||||||
|
err = copy_from_user(&bytes, buf, sizeof(int64_t));
|
||||||
|
if (err) {
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsvd_bytes = (long long)vol->reserved_pebs *
|
||||||
|
ubi->leb_size - vol->data_pad;
|
||||||
|
|
||||||
|
if (bytes < 0 || bytes > rsvd_bytes) {
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ubi_start_update(ubi, vol, bytes);
|
||||||
|
if (bytes == 0)
|
||||||
|
ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = -ENOTTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static struct file_operations ubi_volume_fops = {
|
static struct file_operations ubi_volume_fops = {
|
||||||
.open = ubi_volume_cdev_open,
|
.open = ubi_volume_cdev_open,
|
||||||
.close = ubi_volume_cdev_close,
|
.close = ubi_volume_cdev_close,
|
||||||
.read = ubi_volume_cdev_read,
|
.read = ubi_volume_cdev_read,
|
||||||
.write = ubi_volume_cdev_write,
|
.write = ubi_volume_cdev_write,
|
||||||
.lseek = ubi_volume_cdev_lseek,
|
.lseek = ubi_volume_cdev_lseek,
|
||||||
|
.ioctl = ubi_volume_cdev_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol)
|
int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol)
|
||||||
|
@ -179,6 +227,10 @@ int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol)
|
||||||
cdev->name = basprintf("%s.%s", ubi->cdev.name, vol->name);
|
cdev->name = basprintf("%s.%s", ubi->cdev.name, vol->name);
|
||||||
cdev->priv = priv;
|
cdev->priv = priv;
|
||||||
cdev->size = vol->used_bytes;
|
cdev->size = vol->used_bytes;
|
||||||
|
|
||||||
|
if (vol->vol_type == UBI_STATIC_VOLUME)
|
||||||
|
cdev->flags = DEVFS_IS_CHARACTER_DEV;
|
||||||
|
|
||||||
cdev->dev = &vol->dev;
|
cdev->dev = &vol->dev;
|
||||||
ubi_msg(ubi, "registering %s as /dev/%s", vol->name, cdev->name);
|
ubi_msg(ubi, "registering %s as /dev/%s", vol->name, cdev->name);
|
||||||
ret = devfs_create(cdev);
|
ret = devfs_create(cdev);
|
||||||
|
|
|
@ -368,18 +368,6 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||||
}
|
}
|
||||||
|
|
||||||
ubi_assert(vol->upd_received <= vol->upd_bytes);
|
ubi_assert(vol->upd_received <= vol->upd_bytes);
|
||||||
if (vol->upd_received == vol->upd_bytes) {
|
|
||||||
err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
/* The update is finished, clear the update marker */
|
|
||||||
err = clear_update_marker(ubi, vol, vol->upd_bytes);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
vol->updating = 0;
|
|
||||||
err = to_write;
|
|
||||||
vfree(vol->upd_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue