Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 106071
b: refs/heads/master
c: f40ac9c
h: refs/heads/master
i:
  106069: 7a62b38
  106067: c6e49c1
  106063: 44741cb
v: v3
  • Loading branch information
Artem Bityutskiy authored and Artem Bityutskiy committed Jul 24, 2008
1 parent dd7f26f commit 370da32
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c8566350a3229ca505b84313c65d1403b4d0cbfc
refs/heads/master: f40ac9cdf6991287f19bdafe9b0752ee40137908
1 change: 1 addition & 0 deletions trunk/drivers/mtd/ubi/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)

mutex_init(&ubi->buf_mutex);
mutex_init(&ubi->ckvol_mutex);
mutex_init(&ubi->mult_mutex);
mutex_init(&ubi->volumes_mutex);
spin_lock_init(&ubi->volumes_lock);

Expand Down
188 changes: 187 additions & 1 deletion trunk/drivers/mtd/ubi/cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,166 @@ static int verify_rsvol_req(const struct ubi_device *ubi,
return 0;
}

/**
* rename_volumes - rename UBI volumes.
* @ubi: UBI device description object
* @req: volumes re-name request
*
* This is a helper function for the volume re-name IOCTL which validates the
* the request, opens the volume and calls corresponding volumes management
* function. Returns zero in case of success and a negative error code in case
* of failure.
*/
static int rename_volumes(struct ubi_device *ubi,
struct ubi_rnvol_req *req)
{
int i, n, err;
struct list_head rename_list;
struct ubi_rename_entry *re, *re1;

if (req->count < 0 || req->count > UBI_MAX_RNVOL)
return -EINVAL;

if (req->count == 0)
return 0;

/* Validate volume IDs and names in the request */
for (i = 0; i < req->count; i++) {
if (req->ents[i].vol_id < 0 ||
req->ents[i].vol_id >= ubi->vtbl_slots)
return -EINVAL;
if (req->ents[i].name_len < 0)
return -EINVAL;
if (req->ents[i].name_len > UBI_VOL_NAME_MAX)
return -ENAMETOOLONG;
req->ents[i].name[req->ents[i].name_len] = '\0';
n = strlen(req->ents[i].name);
if (n != req->ents[i].name_len)
err = -EINVAL;
}

/* Make sure volume IDs and names are unique */
for (i = 0; i < req->count - 1; i++) {
for (n = i + 1; n < req->count; n++) {
if (req->ents[i].vol_id == req->ents[n].vol_id) {
dbg_err("duplicated volume id %d",
req->ents[i].vol_id);
return -EINVAL;
}
if (!strcmp(req->ents[i].name, req->ents[n].name)) {
dbg_err("duplicated volume name \"%s\"",
req->ents[i].name);
return -EINVAL;
}
}
}

/* Create the re-name list */
INIT_LIST_HEAD(&rename_list);
for (i = 0; i < req->count; i++) {
int vol_id = req->ents[i].vol_id;
int name_len = req->ents[i].name_len;
const char *name = req->ents[i].name;

re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
if (!re) {
err = -ENOMEM;
goto out_free;
}

re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc);
dbg_err("cannot open volume %d, error %d", vol_id, err);
kfree(re);
goto out_free;
}

/* Skip this re-naming if the name does not really change */
if (re->desc->vol->name_len == name_len &&
!memcmp(re->desc->vol->name, name, name_len)) {
ubi_close_volume(re->desc);
kfree(re);
continue;
}

re->new_name_len = name_len;
memcpy(re->new_name, name, name_len);
list_add_tail(&re->list, &rename_list);
dbg_msg("will rename volume %d from \"%s\" to \"%s\"",
vol_id, re->desc->vol->name, name);
}

if (list_empty(&rename_list))
return 0;

/* Find out the volumes which have to be removed */
list_for_each_entry(re, &rename_list, list) {
struct ubi_volume_desc *desc;
int no_remove_needed = 0;

/*
* Volume @re->vol_id is going to be re-named to
* @re->new_name, while its current name is @name. If a volume
* with name @re->new_name currently exists, it has to be
* removed, unless it is also re-named in the request (@req).
*/
list_for_each_entry(re1, &rename_list, list) {
if (re->new_name_len == re1->desc->vol->name_len &&
!memcmp(re->new_name, re1->desc->vol->name,
re1->desc->vol->name_len)) {
no_remove_needed = 1;
break;
}
}

if (no_remove_needed)
continue;

/*
* It seems we need to remove volume with name @re->new_name,
* if it exists.
*/
desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, UBI_EXCLUSIVE);
if (IS_ERR(desc)) {
err = PTR_ERR(desc);
if (err == -ENODEV)
/* Re-naming into a non-existing volume name */
continue;

/* The volume exists but busy, or an error occurred */
dbg_err("cannot open volume \"%s\", error %d",
re->new_name, err);
goto out_free;
}

re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
if (!re) {
err = -ENOMEM;
ubi_close_volume(desc);
goto out_free;
}

re->remove = 1;
re->desc = desc;
list_add(&re->list, &rename_list);
dbg_msg("will remove volume %d, name \"%s\"",
re->desc->vol->vol_id, re->desc->vol->name);
}

mutex_lock(&ubi->volumes_mutex);
err = ubi_rename_volumes(ubi, &rename_list);
mutex_unlock(&ubi->volumes_mutex);

out_free:
list_for_each_entry_safe(re, re1, &rename_list, list) {
ubi_close_volume(re->desc);
list_del(&re->list);
kfree(re);
}
return err;
}

static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
Expand Down Expand Up @@ -670,7 +830,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
}

mutex_lock(&ubi->volumes_mutex);
err = ubi_remove_volume(desc);
err = ubi_remove_volume(desc, 0);
mutex_unlock(&ubi->volumes_mutex);

/*
Expand Down Expand Up @@ -717,6 +877,32 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
break;
}

/* Re-name volumes command */
case UBI_IOCRNVOL:
{
struct ubi_rnvol_req *req;

dbg_msg("re-name volumes");
req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL);
if (!req) {
err = -ENOMEM;
break;
};

err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
if (err) {
err = -EFAULT;
kfree(req);
break;
}

mutex_lock(&ubi->mult_mutex);
err = rename_volumes(ubi, req);
mutex_unlock(&ubi->mult_mutex);
kfree(req);
break;
}

default:
err = -ENOTTY;
break;
Expand Down
33 changes: 30 additions & 3 deletions trunk/drivers/mtd/ubi/ubi.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,27 @@ struct ubi_ltree_entry {
struct rw_semaphore mutex;
};

/**
* struct ubi_rename_entry - volume re-name description data structure.
* @new_name_len: new volume name length
* @new_name: new volume name
* @remove: if not zero, this volume should be removed, not re-named
* @desc: descriptor of the volume
* @list: links re-name entries into a list
*
* This data structure is utilized in the multiple volume re-name code. Namely,
* UBI first creates a list of &struct ubi_rename_entry objects from the
* &struct ubi_rnvol_req request object, and then utilizes this list to do all
* the job.
*/
struct ubi_rename_entry {
int new_name_len;
char new_name[UBI_VOL_NAME_MAX + 1];
int remove;
struct ubi_volume_desc *desc;
struct list_head list;
};

struct ubi_volume_desc;

/**
Expand Down Expand Up @@ -206,7 +227,7 @@ struct ubi_volume {
int alignment;
int data_pad;
int name_len;
char name[UBI_VOL_NAME_MAX+1];
char name[UBI_VOL_NAME_MAX + 1];

int upd_ebs;
int ch_lnum;
Expand Down Expand Up @@ -272,7 +293,7 @@ struct ubi_wl_entry;
* @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy
* @volumes_mutex: protects on-flash volume table and serializes volume
* changes, like creation, deletion, update, resize
* changes, like creation, deletion, update, re-size and re-name
*
* @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value
Expand Down Expand Up @@ -330,6 +351,8 @@ struct ubi_wl_entry;
* @peb_buf1: a buffer of PEB size used for different purposes
* @peb_buf2: another buffer of PEB size used for different purposes
* @buf_mutex: proptects @peb_buf1 and @peb_buf2
* @ckvol_mutex: serializes static volume checking when opening
* @mult_mutex: serializes operations on multiple volumes, like re-nameing
* @dbg_peb_buf: buffer of PEB size used for debugging
* @dbg_buf_mutex: proptects @dbg_peb_buf
*/
Expand Down Expand Up @@ -410,6 +433,7 @@ struct ubi_device {
void *peb_buf2;
struct mutex buf_mutex;
struct mutex ckvol_mutex;
struct mutex mult_mutex;
#ifdef CONFIG_MTD_UBI_DEBUG
void *dbg_peb_buf;
struct mutex dbg_buf_mutex;
Expand All @@ -426,12 +450,15 @@ extern struct mutex ubi_devices_mutex;
/* vtbl.c */
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec);
int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list);
int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);

/* vmt.c */
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
int ubi_remove_volume(struct ubi_volume_desc *desc);
int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl);
int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs);
int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list);
int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol);
void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol);

Expand Down
57 changes: 49 additions & 8 deletions trunk/drivers/mtd/ubi/vmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,13 +402,14 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/**
* ubi_remove_volume - remove volume.
* @desc: volume descriptor
* @no_vtbl: do not change volume table if not zero
*
* This function removes volume described by @desc. The volume has to be opened
* in "exclusive" mode. Returns zero in case of success and a negative error
* code in case of failure. The caller has to have the @ubi->volumes_mutex
* locked.
*/
int ubi_remove_volume(struct ubi_volume_desc *desc)
int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
Expand Down Expand Up @@ -437,9 +438,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
if (err)
goto out_err;

err = ubi_change_vtbl_record(ubi, vol_id, NULL);
if (err)
goto out_err;
if (!no_vtbl) {
err = ubi_change_vtbl_record(ubi, vol_id, NULL);
if (err)
goto out_err;
}

for (i = 0; i < vol->reserved_pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, i);
Expand All @@ -465,7 +468,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
ubi->vol_count -= 1;
spin_unlock(&ubi->volumes_lock);

err = paranoid_check_volumes(ubi);
if (!no_vtbl)
err = paranoid_check_volumes(ubi);
return err;

out_err:
Expand Down Expand Up @@ -601,6 +605,44 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
return err;
}

/**
* ubi_rename_volumes - re-name UBI volumes.
* @ubi: UBI device description object
* @renam_list: list of &struct ubi_rename_entry objects
*
* This function re-names or removes volumes specified in the re-name list.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
{
int err;
struct ubi_rename_entry *re;

err = ubi_vtbl_rename_volumes(ubi, rename_list);
if (err)
return err;

list_for_each_entry(re, rename_list, list) {
if (re->remove) {
err = ubi_remove_volume(re->desc, 1);
if (err)
break;
} else {
struct ubi_volume *vol = re->desc->vol;

spin_lock(&ubi->volumes_lock);
vol->name_len = re->new_name_len;
memcpy(vol->name, re->new_name, re->new_name_len + 1);
spin_unlock(&ubi->volumes_lock);
}
}

if (!err)
paranoid_check_volumes(ubi);
return err;
}

/**
* ubi_add_volume - add volume.
* @ubi: UBI device description object
Expand Down Expand Up @@ -826,10 +868,9 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)

fail:
ubi_err("paranoid check failed for volume %d", vol_id);
if (vol) {
if (vol)
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
}
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
spin_unlock(&ubi->volumes_lock);
return -EINVAL;
}
Expand Down
Loading

0 comments on commit 370da32

Please sign in to comment.