Dear Kyungmin Park,

Some more comments after testing your patches.

2008/10/28 Kyungmin Park <[EMAIL PROTECTED]>:
> UBI (Latin: "where?") stands for "Unsorted Block Images". It is a volume 
> management system for flash devices which manages multiple logical volumes on 
> a single physical flash device and spreads the I/O load (i.e, wear-leveling) 
> across the whole flash chip.
>
> In a sense, UBI may be compared to the Logical Volume Manager (LVM). Whereas 
> LVM maps logical sectors to physical sectors, UBI maps logical eraseblocks to 
> physical eraseblocks. But besides the mapping, UBI implements global 
> wear-leveling and I/O errors handling.
>
> For more details, Please visit the following URL.
> http://www.linux-mtd.infradead.org/doc/ubi.html
>
> Signed-off-by: Kyungmin Park <[EMAIL PROTECTED]>
> ---
> diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
> new file mode 100644
> index 0000000..b6f8699
> --- /dev/null
> +++ b/drivers/mtd/ubi/build.c
> +static int io_init(struct ubi_device *ubi)
> +{
> +       if (ubi->mtd->numeraseregions != 0) {
> +               /*
> +                * Some flashes have several erase regions. Different regions
> +                * may have different eraseblock size and other
> +                * characteristics. It looks like mostly multi-region flashes
> +                * have one "main" region and one or more small regions to
> +                * store boot loader code or boot parameters or whatever. I
> +                * guess we should just pick the largest region. But this is
> +                * not implemented.
> +                */
> +               ubi_err("multiple regions, not implemented");
> +               return -EINVAL;
> +       }
> +
> +       if (ubi->vid_hdr_offset < 0)
> +               return -EINVAL;
> +
> +       /*
> +        * Note, in this implementation we support MTD devices with 0x7FFFFFFF
> +        * physical eraseblocks maximum.
> +        */
> +
> +       ubi->peb_size   = ubi->mtd->erasesize;
> +       ubi->peb_count  = ubi->mtd->size / ubi->mtd->erasesize;
> +       ubi->flash_size = ubi->mtd->size;
> +
> +       if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
> +               ubi->bad_allowed = 1;
> +
> +       ubi->min_io_size = ubi->mtd->writesize;
> +       ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
> +
> +       /*
> +        * Make sure minimal I/O unit is power of 2. Note, there is no
> +        * fundamental reason for this assumption. It is just an optimization
> +        * which allows us to avoid costly division operations.
> +        */
> +       if (!is_power_of_2(ubi->min_io_size)) {
> +               ubi_err("min. I/O unit (%d) is not power of 2",
> +                       ubi->min_io_size);
> +               return -EINVAL;
> +       }
> +
> +       ubi_assert(ubi->hdrs_min_io_size > 0);
> +       ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
> +       ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
> +
> +       /* Calculate default aligned sizes of EC and VID headers */
> +       ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
> +       ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
> +
> +       dbg_msg("min_io_size      %d", ubi->min_io_size);
> +       dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
> +       dbg_msg("ec_hdr_alsize    %d", ubi->ec_hdr_alsize);
> +       dbg_msg("vid_hdr_alsize   %d", ubi->vid_hdr_alsize);
> +
> +       if (ubi->vid_hdr_offset == 0)
> +               /* Default offset */
> +               ubi->vid_hdr_offset = ubi->vid_hdr_aloffset =
> +                                     ubi->ec_hdr_alsize;
> +       else {
> +               ubi->vid_hdr_aloffset = ubi->vid_hdr_offset &
> +                                               ~(ubi->hdrs_min_io_size - 1);
> +               ubi->vid_hdr_shift = ubi->vid_hdr_offset -
> +                                               ubi->vid_hdr_aloffset;
> +       }
> +
> +       /* Similar for the data offset */
> +       ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
> +       ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
> +
> +       dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
> +       dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
> +       dbg_msg("vid_hdr_shift    %d", ubi->vid_hdr_shift);
> +       dbg_msg("leb_start        %d", ubi->leb_start);
> +
> +       /* The shift must be aligned to 32-bit boundary */
> +       if (ubi->vid_hdr_shift % 4) {
> +               ubi_err("unaligned VID header shift %d",
> +                       ubi->vid_hdr_shift);
> +               return -EINVAL;
> +       }
> +
> +       /* Check sanity */
> +       if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
> +           ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
> +           ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
> +           ubi->leb_start & (ubi->min_io_size - 1)) {
> +               ubi_err("bad VID header (%d) or data offsets (%d)",
> +                       ubi->vid_hdr_offset, ubi->leb_start);
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * It may happen that EC and VID headers are situated in one minimal
> +        * I/O unit. In this case we can only accept this UBI image in
> +        * read-only mode.
> +        */
> +       if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {
> +               ubi_warn("EC and VID headers are in the same minimal I/O 
> unit, "
> +                        "switch to read-only mode");
> +               ubi->ro_mode = 1;
> +       }
> +
> +       ubi->leb_size = ubi->peb_size - ubi->leb_start;
> +
> +       if (!(ubi->mtd->flags & MTD_WRITEABLE)) {
> +               ubi_msg("MTD device %d is write-protected, attach in "
> +                       "read-only mode", ubi->mtd->index);
> +               ubi->ro_mode = 1;
> +       }
> +
> +       ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
> +               ubi->peb_size, ubi->peb_size >> 10);
> +       ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
> +       ubi_msg("smallest flash I/O unit:    %d", ubi->min_io_size);
> +       if (ubi->hdrs_min_io_size != ubi->min_io_size)
> +               ubi_msg("sub-page size:              %d",
> +                       ubi->hdrs_min_io_size);
> +       ubi_msg("VID header offset:          %d (aligned %d)",
> +               ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
> +       ubi_msg("data offset:                %d", ubi->leb_start);

I got these messages on my console, my suggestion is that (almost) all
of the standard info messages are off by default.

> +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
> +{
> +       struct ubi_device *ubi;
> +       int i, err;
> +
> +       /*
> +        * Check if we already have the same MTD device attached.
> +        *
> +        * Note, this function assumes that UBI devices creations and 
> deletions
> +        * are serialized, so it does not take the &ubi_devices_lock.
> +        */
> +       for (i = 0; i < UBI_MAX_DEVICES; i++) {
> +               ubi = ubi_devices[i];
> +               if (ubi && mtd->index == ubi->mtd->index) {
> +                       dbg_err("mtd%d is already attached to ubi%d",
> +                               mtd->index, i);
> +                       return -EEXIST;
> +               }
> +       }
> +
> +       /*
> +        * Make sure this MTD device is not emulated on top of an UBI volume
> +        * already. Well, generally this recursion works fine, but there are
> +        * different problems like the UBI module takes a reference to itself
> +        * by attaching (and thus, opening) the emulated MTD device. This
> +        * results in inability to unload the module. And in general it makes
> +        * no sense to attach emulated MTD devices, so we prohibit this.
> +        */
> +       if (mtd->type == MTD_UBIVOLUME) {
> +               ubi_err("refuse attaching mtd%d - it is already emulated on "
> +                       "top of UBI", mtd->index);
> +               return -EINVAL;
> +       }
> +
> +       if (ubi_num == UBI_DEV_NUM_AUTO) {
> +               /* Search for an empty slot in the @ubi_devices array */
> +               for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
> +                       if (!ubi_devices[ubi_num])
> +                               break;
> +               if (ubi_num == UBI_MAX_DEVICES) {
> +                       dbg_err("only %d UBI devices may be created", 
> UBI_MAX_DEVICES);
> +                       return -ENFILE;
> +               }
> +       } else {
> +               if (ubi_num >= UBI_MAX_DEVICES)
> +                       return -EINVAL;
> +
> +               /* Make sure ubi_num is not busy */
> +               if (ubi_devices[ubi_num]) {
> +                       dbg_err("ubi%d already exists", ubi_num);
> +                       return -EEXIST;
> +               }
> +       }
> +
> +       ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
> +       if (!ubi)
> +               return -ENOMEM;
> +
> +       ubi->mtd = mtd;
> +       ubi->ubi_num = ubi_num;
> +       ubi->vid_hdr_offset = vid_hdr_offset;
> +       ubi->autoresize_vol_id = -1;
> +
> +       mutex_init(&ubi->buf_mutex);
> +       mutex_init(&ubi->ckvol_mutex);
> +       mutex_init(&ubi->volumes_mutex);
> +       spin_lock_init(&ubi->volumes_lock);
> +
> +       ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
> +
> +       err = io_init(ubi);
> +       if (err)
> +               goto out_free;
> +
> +       ubi->peb_buf1 = vmalloc(ubi->peb_size);
> +       if (!ubi->peb_buf1)
> +               goto out_free;
> +
> +       ubi->peb_buf2 = vmalloc(ubi->peb_size);
> +       if (!ubi->peb_buf2)
> +                goto out_free;
> +
> +#ifdef CONFIG_MTD_UBI_DEBUG
> +       mutex_init(&ubi->dbg_buf_mutex);
> +       ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
> +       if (!ubi->dbg_peb_buf)
> +                goto out_free;
> +#endif
> +
> +       err = attach_by_scanning(ubi);
> +       if (err) {
> +               dbg_err("failed to attach by scanning, error %d", err);
> +               goto out_free;
> +       }
> +
> +       if (ubi->autoresize_vol_id != -1) {
> +               err = autoresize(ubi, ubi->autoresize_vol_id);
> +               if (err)
> +                       goto out_detach;
> +       }
> +
> +       err = uif_init(ubi);
> +       if (err)
> +               goto out_detach;
> +
> +       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
> +       if (IS_ERR(ubi->bgt_thread)) {
> +               err = PTR_ERR(ubi->bgt_thread);
> +               ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
> +                       err);
> +               goto out_uif;
> +       }
> +
> +       ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
> +       ubi_msg("MTD device name:            \"%s\"", mtd->name);
> +       ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 
> 20);
> +       ubi_msg("number of good PEBs:        %d", ubi->good_peb_count);
> +       ubi_msg("number of bad PEBs:         %d", ubi->bad_peb_count);
> +       ubi_msg("max. allowed volumes:       %d", ubi->vtbl_slots);
> +       ubi_msg("wear-leveling threshold:    %d", 
> CONFIG_MTD_UBI_WL_THRESHOLD);
> +       ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
> +       ubi_msg("number of user volumes:     %d",
> +               ubi->vol_count - UBI_INT_VOL_COUNT);
> +       ubi_msg("available PEBs:             %d", ubi->avail_pebs);
> +       ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
> +       ubi_msg("number of PEBs reserved for bad PEB handling: %d",
> +               ubi->beb_rsvd_pebs);
> +       ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);

All these should also be off by default IMO.

Regards, Magnus
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to