[PATCH 2/2] ubi-utils: ubinize: Add fastmap suport to image creation

Richard Weinberger richard at nod.at
Wed Mar 18 03:22:01 PDT 2015


Hi!

Am 18.03.2015 um 09:52 schrieb Tanya Brokhman:
> While generating ubi image with ubinize, all UBI data required for
> Fastmap is present. If we generate the Fastmap data as part of the
> image, the first boot after flash won't require full scan of the UBI
> device.
> In order to be able to generate the Fastmap data number of device
> PEBs is required. If this input parameter was not provided - Fastmap
> will not be generated.
> 
> Note: In order for this to work properly change is required in flasher
> as well:
> If while flashing the image bad blocks were discovered, Fastmap
> should be invalidated in the flashed image. Fastmap superblock
> (if present) will be in PEB#2 in the image.

I didn't look at the implementation in detail as I'm still recovering from a flu.

NAND is allowed to have bad blocks, therefore a lot of freshly flashed
UBI images won't be able to use fastmap.
What also puzzles me is that it will just work with a non-fastmap aware flasher.
But boards with bad blocks will blow up at (much) later and Joe random user will curse UBI. :)

Maybe it would make sense to but the whole fastmap creation logic into the flasher.
We could create a libfastmap (LGPLv2) such that everyone is allowed to use it in his custom
flasher.

Thanks,
//richard

> Signed-off-by: Tanya Brokhman <tlinder at codeaurora.org>
> ---
>  Makefile                        |   2 +-
>  include/linux/list.h            | 599 ++++++++++++++++++++++++++++++++++++++++
>  include/mtd/ubi-media.h         |   4 +
>  ubi-utils/include/libubigen.h   |  25 +-
>  ubi-utils/include/ubi-fastmap.h | 217 +++++++++++++++
>  ubi-utils/libubigen.c           |  80 ++++--
>  ubi-utils/mtdinfo.c             |   2 +-
>  ubi-utils/ubi-fastmap.c         | 358 ++++++++++++++++++++++++
>  ubi-utils/ubiformat.c           |   6 +-
>  ubi-utils/ubinize.c             |  71 ++++-
>  10 files changed, 1324 insertions(+), 40 deletions(-)
>  create mode 100644 include/linux/list.h
>  create mode 100644 ubi-utils/include/ubi-fastmap.h
>  create mode 100644 ubi-utils/ubi-fastmap.c
> 
> diff --git a/Makefile b/Makefile
> index eade234..bf0ada7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -117,7 +117,7 @@ obj-libubi.a       = libubi.o
>  obj-libubigen.a    = libubigen.o
>  
>  obj-mtdinfo   = libubigen.a
> -obj-ubinize   = libubigen.a libiniparser.a
> +obj-ubinize   = libubigen.a libiniparser.a ubi-fastmap.o
>  obj-ubiformat = libubigen.a libscan.a
>  
>  $(foreach v,libubi.a libubigen.a libiniparser.a libscan.a,$(eval $(call _mkdep,ubi-utils/,$(v))))
> diff --git a/include/linux/list.h b/include/linux/list.h
> new file mode 100644
> index 0000000..afcc469
> --- /dev/null
> +++ b/include/linux/list.h
> @@ -0,0 +1,599 @@
> +/*
> + *
> + * Simple doubly linked list implementation.
> + *
> + * This file was (partly) imported from kernel/include/linux/list.h
> + *
> + * Some of the internal functions ("__xxx") are useful when
> + * manipulating whole lists rather than single entries, as
> + * sometimes we already know the next/prev entries and we can
> + * generate better code by using them directly rather than
> + * using the generic single-entry routines.
> + */
> +
> +#ifndef _LINUX_LIST_H
> +#define _LINUX_LIST_H
> +
> +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
> +
> +/**
> + * container_of - cast a member of a structure out to the containing structure
> + * @ptr:	the pointer to the member.
> + * @type:	the type of the container struct this is embedded in.
> + * @member:	the name of the member within the struct.
> + *
> + */
> +#define container_of(ptr, type, member) ({			\
> +	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> +	(type *)( (char *)__mptr - offsetof(type,member) );})
> +
> +struct list_head {
> +	struct list_head *next, *prev;
> +};
> +
> +#define LIST_HEAD_INIT(name) { &(name), &(name) }
> +
> +#define LIST_HEAD(name) \
> +	struct list_head name = LIST_HEAD_INIT(name)
> +
> +static inline void INIT_LIST_HEAD(struct list_head *list)
> +{
> +	list->next = list;
> +	list->prev = list;
> +}
> +
> +/*
> + * Insert a new entry between two known consecutive entries.
> + *
> + * This is only for internal list manipulation where we know
> + * the prev/next entries already!
> + */
> +static inline void __list_add(struct list_head *new,
> +			      struct list_head *prev,
> +			      struct list_head *next)
> +{
> +	next->prev = new;
> +	new->next = next;
> +	new->prev = prev;
> +	prev->next = new;
> +}
> +
> +/**
> + * list_add - add a new entry
> + * @new: new entry to be added
> + * @head: list head to add it after
> + *
> + * Insert a new entry after the specified head.
> + * This is good for implementing stacks.
> + */
> +static inline void list_add(struct list_head *new, struct list_head *head)
> +{
> +	__list_add(new, head, head->next);
> +}
> +
> +
> +/**
> + * list_add_tail - add a new entry
> + * @new: new entry to be added
> + * @head: list head to add it before
> + *
> + * Insert a new entry before the specified head.
> + * This is useful for implementing queues.
> + */
> +static inline void list_add_tail(struct list_head *new, struct list_head *head)
> +{
> +	__list_add(new, head->prev, head);
> +}
> +
> +/*
> + * Delete a list entry by making the prev/next entries
> + * point to each other.
> + *
> + * This is only for internal list manipulation where we know
> + * the prev/next entries already!
> + */
> +static inline void __list_del(struct list_head *prev, struct list_head *next)
> +{
> +	next->prev = prev;
> +	prev->next = next;
> +}
> +
> +/**
> + * list_del - deletes entry from list.
> + * @entry: the element to delete from the list.
> + * Note: list_empty() on entry does not return true after this, the entry is
> + * in an undefined state.
> + */
> +static inline void __list_del_entry(struct list_head *entry)
> +{
> +	__list_del(entry->prev, entry->next);
> +}
> +
> +/*
> + * These are non-NULL pointers that will result in page faults
> + * under normal circumstances, used to verify that nobody uses
> + * non-initialized list entries.
> + */
> +#define LIST_POISON1  ((void *) 0x00100100)
> +#define LIST_POISON2  ((void *) 0x00200200)
> +
> +static inline void list_del(struct list_head *entry)
> +{
> +	__list_del(entry->prev, entry->next);
> +	entry->next = LIST_POISON1;
> +	entry->prev = LIST_POISON2;
> +}
> +
> +/**
> + * list_replace - replace old entry by new one
> + * @old : the element to be replaced
> + * @new : the new element to insert
> + *
> + * If @old was empty, it will be overwritten.
> + */
> +static inline void list_replace(struct list_head *old,
> +				struct list_head *new)
> +{
> +	new->next = old->next;
> +	new->next->prev = new;
> +	new->prev = old->prev;
> +	new->prev->next = new;
> +}
> +
> +static inline void list_replace_init(struct list_head *old,
> +					struct list_head *new)
> +{
> +	list_replace(old, new);
> +	INIT_LIST_HEAD(old);
> +}
> +
> +/**
> + * list_del_init - deletes entry from list and reinitialize it.
> + * @entry: the element to delete from the list.
> + */
> +static inline void list_del_init(struct list_head *entry)
> +{
> +	__list_del_entry(entry);
> +	INIT_LIST_HEAD(entry);
> +}
> +
> +/**
> + * list_move - delete from one list and add as another's head
> + * @list: the entry to move
> + * @head: the head that will precede our entry
> + */
> +static inline void list_move(struct list_head *list, struct list_head *head)
> +{
> +	__list_del_entry(list);
> +	list_add(list, head);
> +}
> +
> +/**
> + * list_move_tail - delete from one list and add as another's tail
> + * @list: the entry to move
> + * @head: the head that will follow our entry
> + */
> +static inline void list_move_tail(struct list_head *list,
> +				  struct list_head *head)
> +{
> +	__list_del_entry(list);
> +	list_add_tail(list, head);
> +}
> +
> +/**
> + * list_is_last - tests whether @list is the last entry in list @head
> + * @list: the entry to test
> + * @head: the head of the list
> + */
> +static inline int list_is_last(const struct list_head *list,
> +				const struct list_head *head)
> +{
> +	return list->next == head;
> +}
> +
> +/**
> + * list_empty - tests whether a list is empty
> + * @head: the list to test.
> + */
> +static inline int list_empty(const struct list_head *head)
> +{
> +	return head->next == head;
> +}
> +
> +/**
> + * list_empty_careful - tests whether a list is empty and not being modified
> + * @head: the list to test
> + *
> + * Description:
> + * tests whether a list is empty _and_ checks that no other CPU might be
> + * in the process of modifying either member (next or prev)
> + *
> + * NOTE: using list_empty_careful() without synchronization
> + * can only be safe if the only activity that can happen
> + * to the list entry is list_del_init(). Eg. it cannot be used
> + * if another CPU could re-list_add() it.
> + */
> +static inline int list_empty_careful(const struct list_head *head)
> +{
> +	struct list_head *next = head->next;
> +	return (next == head) && (next == head->prev);
> +}
> +
> +/**
> + * list_rotate_left - rotate the list to the left
> + * @head: the head of the list
> + */
> +static inline void list_rotate_left(struct list_head *head)
> +{
> +	struct list_head *first;
> +
> +	if (!list_empty(head)) {
> +		first = head->next;
> +		list_move_tail(first, head);
> +	}
> +}
> +
> +/**
> + * list_is_singular - tests whether a list has just one entry.
> + * @head: the list to test.
> + */
> +static inline int list_is_singular(const struct list_head *head)
> +{
> +	return !list_empty(head) && (head->next == head->prev);
> +}
> +
> +static inline void __list_cut_position(struct list_head *list,
> +		struct list_head *head, struct list_head *entry)
> +{
> +	struct list_head *new_first = entry->next;
> +	list->next = head->next;
> +	list->next->prev = list;
> +	list->prev = entry;
> +	entry->next = list;
> +	head->next = new_first;
> +	new_first->prev = head;
> +}
> +
> +/**
> + * list_cut_position - cut a list into two
> + * @list: a new list to add all removed entries
> + * @head: a list with entries
> + * @entry: an entry within head, could be the head itself
> + *	and if so we won't cut the list
> + *
> + * This helper moves the initial part of @head, up to and
> + * including @entry, from @head to @list. You should
> + * pass on @entry an element you know is on @head. @list
> + * should be an empty list or a list you do not care about
> + * losing its data.
> + *
> + */
> +static inline void list_cut_position(struct list_head *list,
> +		struct list_head *head, struct list_head *entry)
> +{
> +	if (list_empty(head))
> +		return;
> +	if (list_is_singular(head) &&
> +		(head->next != entry && head != entry))
> +		return;
> +	if (entry == head)
> +		INIT_LIST_HEAD(list);
> +	else
> +		__list_cut_position(list, head, entry);
> +}
> +
> +static inline void __list_splice(const struct list_head *list,
> +				 struct list_head *prev,
> +				 struct list_head *next)
> +{
> +	struct list_head *first = list->next;
> +	struct list_head *last = list->prev;
> +
> +	first->prev = prev;
> +	prev->next = first;
> +
> +	last->next = next;
> +	next->prev = last;
> +}
> +
> +/**
> + * list_splice - join two lists, this is designed for stacks
> + * @list: the new list to add.
> + * @head: the place to add it in the first list.
> + */
> +static inline void list_splice(const struct list_head *list,
> +				struct list_head *head)
> +{
> +	if (!list_empty(list))
> +		__list_splice(list, head, head->next);
> +}
> +
> +/**
> + * list_splice_tail - join two lists, each list being a queue
> + * @list: the new list to add.
> + * @head: the place to add it in the first list.
> + */
> +static inline void list_splice_tail(struct list_head *list,
> +				struct list_head *head)
> +{
> +	if (!list_empty(list))
> +		__list_splice(list, head->prev, head);
> +}
> +
> +/**
> + * list_splice_init - join two lists and reinitialise the emptied list.
> + * @list: the new list to add.
> + * @head: the place to add it in the first list.
> + *
> + * The list at @list is reinitialised
> + */
> +static inline void list_splice_init(struct list_head *list,
> +				    struct list_head *head)
> +{
> +	if (!list_empty(list)) {
> +		__list_splice(list, head, head->next);
> +		INIT_LIST_HEAD(list);
> +	}
> +}
> +
> +/**
> + * list_splice_tail_init - join two lists and reinitialise the emptied list
> + * @list: the new list to add.
> + * @head: the place to add it in the first list.
> + *
> + * Each of the lists is a queue.
> + * The list at @list is reinitialised
> + */
> +static inline void list_splice_tail_init(struct list_head *list,
> +					 struct list_head *head)
> +{
> +	if (!list_empty(list)) {
> +		__list_splice(list, head->prev, head);
> +		INIT_LIST_HEAD(list);
> +	}
> +}
> +
> +/**
> + * list_entry - get the struct for this entry
> + * @ptr:	the &struct list_head pointer.
> + * @type:	the type of the struct this is embedded in.
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_entry(ptr, type, member) \
> +	container_of(ptr, type, member)
> +
> +/**
> + * list_first_entry - get the first element from a list
> + * @ptr:	the list head to take the element from.
> + * @type:	the type of the struct this is embedded in.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Note, that list is expected to be not empty.
> + */
> +#define list_first_entry(ptr, type, member) \
> +	list_entry((ptr)->next, type, member)
> +
> +/**
> + * list_last_entry - get the last element from a list
> + * @ptr:	the list head to take the element from.
> + * @type:	the type of the struct this is embedded in.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Note, that list is expected to be not empty.
> + */
> +#define list_last_entry(ptr, type, member) \
> +	list_entry((ptr)->prev, type, member)
> +
> +/**
> + * list_first_entry_or_null - get the first element from a list
> + * @ptr:	the list head to take the element from.
> + * @type:	the type of the struct this is embedded in.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Note that if the list is empty, it returns NULL.
> + */
> +#define list_first_entry_or_null(ptr, type, member) \
> +	(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
> +
> +/**
> + * list_next_entry - get the next element in list
> + * @pos:	the type * to cursor
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_next_entry(pos, member) \
> +	list_entry((pos)->member.next, typeof(*(pos)), member)
> +
> +/**
> + * list_prev_entry - get the prev element in list
> + * @pos:	the type * to cursor
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_prev_entry(pos, member) \
> +	list_entry((pos)->member.prev, typeof(*(pos)), member)
> +
> +/**
> + * list_for_each	-	iterate over a list
> + * @pos:	the &struct list_head to use as a loop cursor.
> + * @head:	the head for your list.
> + */
> +#define list_for_each(pos, head) \
> +	for (pos = (head)->next; pos != (head); pos = pos->next)
> +
> +/**
> + * list_for_each_prev	-	iterate over a list backwards
> + * @pos:	the &struct list_head to use as a loop cursor.
> + * @head:	the head for your list.
> + */
> +#define list_for_each_prev(pos, head) \
> +	for (pos = (head)->prev; pos != (head); pos = pos->prev)
> +
> +/**
> + * list_for_each_safe - iterate over a list safe against removal of list entry
> + * @pos:	the &struct list_head to use as a loop cursor.
> + * @n:		another &struct list_head to use as temporary storage
> + * @head:	the head for your list.
> + */
> +#define list_for_each_safe(pos, n, head) \
> +	for (pos = (head)->next, n = pos->next; pos != (head); \
> +		pos = n, n = pos->next)
> +
> +/**
> + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
> + * @pos:	the &struct list_head to use as a loop cursor.
> + * @n:		another &struct list_head to use as temporary storage
> + * @head:	the head for your list.
> + */
> +#define list_for_each_prev_safe(pos, n, head) \
> +	for (pos = (head)->prev, n = pos->prev; \
> +	     pos != (head); \
> +	     pos = n, n = pos->prev)
> +
> +/**
> + * list_for_each_entry	-	iterate over list of given type
> + * @pos:	the type * to use as a loop cursor.
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_for_each_entry(pos, head, member)				\
> +	for (pos = list_first_entry(head, typeof(*pos), member);	\
> +	     &pos->member != (head);					\
> +	     pos = list_next_entry(pos, member))
> +
> +/**
> + * list_for_each_entry_reverse - iterate backwards over list of given type.
> + * @pos:	the type * to use as a loop cursor.
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_for_each_entry_reverse(pos, head, member)			\
> +	for (pos = list_last_entry(head, typeof(*pos), member);		\
> +		&pos->member != (head); 					\
> +		pos = list_prev_entry(pos, member))
> +
> +/**
> + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
> + * @pos:	the type * to use as a start point
> + * @head:	the head of the list
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
> + */
> +#define list_prepare_entry(pos, head, member) \
> +	((pos) ? : list_entry(head, typeof(*pos), member))
> +
> +/**
> + * list_for_each_entry_continue - continue iteration over list of given type
> + * @pos:	the type * to use as a loop cursor.
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Continue to iterate over list of given type, continuing after
> + * the current position.
> + */
> +#define list_for_each_entry_continue(pos, head, member) 		\
> +	for (pos = list_next_entry(pos, member);			\
> +		&pos->member != (head);					\
> +		pos = list_next_entry(pos, member))
> +
> +/**
> + * list_for_each_entry_continue_reverse - iterate backwards from the given point
> + * @pos:	the type * to use as a loop cursor.
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Start to iterate over list of given type backwards, continuing after
> + * the current position.
> + */
> +#define list_for_each_entry_continue_reverse(pos, head, member)		\
> +	for (pos = list_prev_entry(pos, member);			\
> +		&pos->member != (head);					\
> +		pos = list_prev_entry(pos, member))
> +
> +/**
> + * list_for_each_entry_from - iterate over list of given type from the current point
> + * @pos:	the type * to use as a loop cursor.
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Iterate over list of given type, continuing from current position.
> + */
> +#define list_for_each_entry_from(pos, head, member) 			\
> +	for (; &pos->member != (head);					\
> +		pos = list_next_entry(pos, member))
> +
> +/**
> + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
> + * @pos:	the type * to use as a loop cursor.
> + * @n:		another type * to use as temporary storage
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + */
> +#define list_for_each_entry_safe(pos, n, head, member)			\
> +	for (pos = list_first_entry(head, typeof(*pos), member),	\
> +		n = list_next_entry(pos, member);			\
> +		&pos->member != (head); 					\
> +		pos = n, n = list_next_entry(n, member))
> +
> +/**
> + * list_for_each_entry_safe_continue - continue list iteration safe against removal
> + * @pos:	the type * to use as a loop cursor.
> + * @n:		another type * to use as temporary storage
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Iterate over list of given type, continuing after current point,
> + * safe against removal of list entry.
> + */
> +#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
> +	for (pos = list_next_entry(pos, member), 				\
> +		n = list_next_entry(pos, member);				\
> +		&pos->member != (head);						\
> +		pos = n, n = list_next_entry(n, member))
> +
> +/**
> + * list_for_each_entry_safe_from - iterate over list from current point safe against removal
> + * @pos:	the type * to use as a loop cursor.
> + * @n:		another type * to use as temporary storage
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Iterate over list of given type from current point, safe against
> + * removal of list entry.
> + */
> +#define list_for_each_entry_safe_from(pos, n, head, member) 			\
> +	for (n = list_next_entry(pos, member);					\
> +		&pos->member != (head);						\
> +		pos = n, n = list_next_entry(n, member))
> +
> +/**
> + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
> + * @pos:	the type * to use as a loop cursor.
> + * @n:		another type * to use as temporary storage
> + * @head:	the head for your list.
> + * @member:	the name of the list_struct within the struct.
> + *
> + * Iterate backwards over list of given type, safe against removal
> + * of list entry.
> + */
> +#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
> +	for (pos = list_last_entry(head, typeof(*pos), member),		\
> +		n = list_prev_entry(pos, member);			\
> +		&pos->member != (head); 					\
> +		pos = n, n = list_prev_entry(n, member))
> +
> +/**
> + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
> + * @pos:	the loop cursor used in the list_for_each_entry_safe loop
> + * @n:		temporary storage used in list_for_each_entry_safe
> + * @member:	the name of the list_struct within the struct.
> + *
> + * list_safe_reset_next is not safe to use in general if the list may be
> + * modified concurrently (eg. the lock is dropped in the loop body). An
> + * exception to this is if the cursor element (pos) is pinned in the list,
> + * and list_safe_reset_next is called after re-taking the lock and before
> + * completing the current iteration of the loop body.
> + */
> +#define list_safe_reset_next(pos, n, member)				\
> +	n = list_next_entry(pos, member)
> +
> +#endif
> diff --git a/include/mtd/ubi-media.h b/include/mtd/ubi-media.h
> index 08bec3e..ccd5b6e 100644
> --- a/include/mtd/ubi-media.h
> +++ b/include/mtd/ubi-media.h
> @@ -312,6 +312,10 @@ struct ubi_vid_hdr {
>  #define UBI_LAYOUT_VOLUME_NAME   "layout volume"
>  #define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
>  
> +/* UBI fastmap on-flash data structures */
> +#define UBI_FM_SB_VOLUME_ID	(UBI_LAYOUT_VOLUME_ID + 1)
> +#define UBI_FM_DATA_VOLUME_ID	(UBI_LAYOUT_VOLUME_ID + 2)
> +
>  /* The maximum number of volumes per one UBI device */
>  #define UBI_MAX_VOLUMES 128
>  
> diff --git a/ubi-utils/include/libubigen.h b/ubi-utils/include/libubigen.h
> index c25ac20..f7d7212 100644
> --- a/ubi-utils/include/libubigen.h
> +++ b/ubi-utils/include/libubigen.h
> @@ -27,6 +27,7 @@
>  
>  #include <stdint.h>
>  #include <mtd/ubi-media.h>
> +#include <linux/list.h>
>  
>  #ifdef __cplusplus
>  extern "C" {
> @@ -43,6 +44,7 @@ extern "C" {
>   * @vtbl_size: volume table size
>   * @max_volumes: maximum amount of volumes
>   * @image_seq: UBI image sequence number
> + * @max_leb_count: maximum logical erase block count
>   */
>  struct ubigen_info
>  {
> @@ -55,6 +57,7 @@ struct ubigen_info
>  	int vtbl_size;
>  	int max_volumes;
>  	uint32_t image_seq;
> +	uint32_t max_leb_count;
>  };
>  
>  /**
> @@ -74,6 +77,9 @@ struct ubigen_info
>   * @bytes: size of the volume contents in bytes (relevant for static volumes
>   *         only)
>   * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
> + * @pebs: array of PEBs assigned to the volume luns. Index of the array
> + *         is the lun
> + * @reserved_pebs: number of PEBs required for this volume
>   */
>  struct ubigen_vol_info
>  {
> @@ -88,6 +94,8 @@ struct ubigen_vol_info
>  	int used_ebs;
>  	long long bytes;
>  	uint8_t flags;
> +	int *pebs;
> +	int reserved_pebs;
>  };
>  
>  /**
> @@ -100,10 +108,11 @@ struct ubigen_vol_info
>   * @vid_hdr_offs: offset of the VID header
>   * @ubi_ver: UBI version
>   * @image_seq: UBI image sequence number
> + * @max_leb_count: maximum logical erase block count
>   */
>  void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
>  		      int subpage_size, int vid_hdr_offs, int ubi_ver,
> -		      uint32_t image_seq);
> +		      uint32_t image_seq, int max_leb_count);
>  
>  /**
>   * ubigen_create_empty_vtbl - creates empty volume table.
> @@ -151,7 +160,7 @@ void ubigen_init_vid_hdr(const struct ubigen_info *ui,
>   * @vtbl.
>   */
>  int ubigen_add_volume(const struct ubigen_info *ui,
> -		      const struct ubigen_vol_info *vi,
> +		      struct ubigen_vol_info *vi,
>  		      struct ubi_vtbl_record *vtbl);
>  
>  /**
> @@ -162,14 +171,18 @@ int ubigen_add_volume(const struct ubigen_info *ui,
>   * @bytes: volume size in bytes
>   * @in: input file descriptor (has to be properly seeked)
>   * @out: output file descriptor
> + * @used: linked list of used PEBs for writing the volume.
> + *      To be filled in by this function
> + * @used_cnt: number of PEBs used to write this volume
>   *
>   * This function reads the contents of the volume from the input file @in and
>   * writes the UBI volume to the output file @out. Returns zero on success and
>   * %-1 on failure.
>   */
>  int ubigen_write_volume(const struct ubigen_info *ui,
> -			const struct ubigen_vol_info *vi, long long ec,
> -			long long bytes, int in, int out);
> +		struct ubigen_vol_info *vi, long long ec,
> +		long long bytes, int in, int out, struct list_head *used,
> +		int *used_cnt);
>  
>  /**
>   * ubigen_write_layout_vol - write UBI layout volume
> @@ -180,13 +193,15 @@ int ubigen_write_volume(const struct ubigen_info *ui,
>   * @ec2: erase counter value for @peb1
>   * @vtbl: volume table
>   * @fd: output file descriptor seeked to the proper position
> + * @vi_layout: information about the layout volume
>   *
>   * This function creates the UBI layout volume which contains 2 copies of the
>   * volume table. Returns zero in case of success and %-1 in case of failure.
>   */
>  int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
>  			    long long ec1, long long ec2,
> -			    struct ubi_vtbl_record *vtbl, int fd);
> +			    struct ubi_vtbl_record *vtbl, int fd,
> +			    struct ubigen_vol_info *vi_layout);
>  
>  #ifdef __cplusplus
>  }
> diff --git a/ubi-utils/include/ubi-fastmap.h b/ubi-utils/include/ubi-fastmap.h
> new file mode 100644
> index 0000000..3947eef
> --- /dev/null
> +++ b/ubi-utils/include/ubi-fastmap.h
> @@ -0,0 +1,217 @@
> +/*
> + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * Copyright (c) International Business Machines Corp., 2006
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
> + * the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + * Authors: Artem Bityutskiy (Битюцкий Артём)
> + *          Thomas Gleixner
> + *          Frank Haverkamp
> + *          Oliver Lohmann
> + *          Andreas Arnez
> + */
> +
> +#ifndef __UBI_FASTMAP_H__
> +#define __UBI_FASTMAP_H__
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <asm/byteorder.h>
> +#include <libubigen.h>
> +#include <linux/list.h>
> +
> +/* A fastmap can use up to UBI_FM_MAX_BLOCKS PEBs */
> +#define UBI_FM_MAX_BLOCKS	32
> +
> +/* fastmap on-flash data structure format version */
> +#define UBI_FM_FMT_VERSION	1
> +
> +#define UBI_FM_SB_MAGIC		0x7B11D69F
> +#define UBI_FM_HDR_MAGIC	0xD4B82EF7
> +#define UBI_FM_VHDR_MAGIC	0xFA370ED1
> +#define UBI_FM_POOL_MAGIC	0x67AF4D08
> +#define UBI_FM_EBA_MAGIC	0xf0c040a8
> +
> +/**
> + * struct ubi_fm_sb - UBI fastmap super block
> + * @magic: fastmap super block magic number (%UBI_FM_SB_MAGIC)
> + * @version: format version of this fastmap
> + * @data_crc: CRC over the fastmap data
> + * @used_blocks: number of PEBs used by this fastmap
> + * @block_loc: an array containing the location of all PEBs of the fastmap
> + * @block_ec: the erase counter of each used PEB
> + * @sqnum: highest sequence number value at the time while taking the fastmap
> + *
> + */
> +struct ubi_fm_sb {
> +	__be32 magic;
> +	__u8 version;
> +	__u8 padding1[3];
> +	__be32 data_crc;
> +	__be32 used_blocks;
> +	__be32 block_loc[UBI_FM_MAX_BLOCKS];
> +	__be32 block_ec[UBI_FM_MAX_BLOCKS];
> +	__be64 sqnum;
> +	__u8 padding2[32];
> +}  __attribute__ ((packed));
> +
> +/**
> + * struct ubi_fm_hdr - header of the fastmap data set
> + * @magic: fastmap header magic number (%UBI_FM_HDR_MAGIC)
> + * @free_peb_count: number of free PEBs known by this fastmap
> + * @used_peb_count: number of used PEBs known by this fastmap
> + * @scrub_peb_count: number of to be scrubbed PEBs known by this fastmap
> + * @bad_peb_count: number of bad PEBs known by this fastmap
> + * @erase_peb_count: number of bad PEBs which have to be erased
> + * @vol_count: number of UBI volumes known by this fastmap
> + */
> +struct ubi_fm_hdr {
> +	__be32 magic;
> +	__be32 free_peb_count;
> +	__be32 used_peb_count;
> +	__be32 scrub_peb_count;
> +	__be32 bad_peb_count;
> +	__be32 erase_peb_count;
> +	__be32 vol_count;
> +	__u8 padding[4];
> +}  __attribute__ ((packed));
> +
> +/* struct ubi_fm_hdr is followed by two struct ubi_fm_scan_pool */
> +
> +/*
> + * 5% of the total number of PEBs have to be scanned while attaching
> + * from a fastmap.
> + * But the size of this pool is limited to be between UBI_FM_MIN_POOL_SIZE and
> + * UBI_FM_MAX_POOL_SIZE
> + */
> +#define UBI_FM_MIN_POOL_SIZE	8
> +#define UBI_FM_MAX_POOL_SIZE	256
> +
> +#define UBI_FM_WL_POOL_SIZE	25
> +
> +/**
> + * struct ubi_fm_scan_pool - Fastmap pool PEBs to be scanned while attaching
> + * @magic: pool magic numer (%UBI_FM_POOL_MAGIC)
> + * @size: current pool size
> + * @max_size: maximal pool size
> + * @pebs: an array containing the location of all PEBs in this pool
> + */
> +struct ubi_fm_scan_pool {
> +	__be32 magic;
> +	__be16 size;
> +	__be16 max_size;
> +	__be32 pebs[UBI_FM_MAX_POOL_SIZE];
> +	__be32 padding[4];
> +}  __attribute__ ((packed));
> +
> +/* ubi_fm_scan_pool is followed by nfree+nused struct ubi_fm_ec records */
> +
> +/**
> + * struct ubi_fm_ec - stores the erase counter of a PEB
> + * @pnum: PEB number
> + * @ec: ec of this PEB
> + */
> +struct ubi_fm_ec {
> +	__be32 pnum;
> +	__be32 ec;
> +}  __attribute__ ((packed));
> +
> +/**
> + * struct ubi_wl_peb - in-memory representation of a used PEB
> + * @pnum: PEB number
> + * @ec: ec of this PEB
> + * @used: link to the used list
> + */
> +struct ubi_wl_peb {
> +	int pnum;
> +	int ec;
> +	struct list_head list;
> +};
> +
> +/**
> + * struct ubi_fastmap_layout - in-memory fastmap data structure.
> + * @e: PEBs used by the current fastmap
> + * @to_be_tortured: if non-zero tortured this PEB
> + * @used_blocks: number of used PEBs
> + * @max_pool_size: maximal size of the user pool
> + * @max_wl_pool_size: maximal size of the pool used by the WL sub-system
> + */
> +struct ubi_fastmap_layout {
> +	struct ubi_wl_peb e[UBI_FM_MAX_BLOCKS];
> +	int used_blocks;
> +	int max_pool_size;
> +	int max_wl_pool_size;
> +};
> +
> +/**
> + * struct ubi_fm_volhdr - Fastmap volume header
> + * it identifies the start of an eba table
> + * @magic: Fastmap volume header magic number (%UBI_FM_VHDR_MAGIC)
> + * @vol_id: volume id of the fastmapped volume
> + * @vol_type: type of the fastmapped volume
> + * @data_pad: data_pad value of the fastmapped volume
> + * @used_ebs: number of used LEBs within this volume
> + * @last_eb_bytes: number of bytes used in the last LEB
> + */
> +struct ubi_fm_volhdr {
> +	__be32 magic;
> +	__be32 vol_id;
> +	__u8 vol_type;
> +	__u8 padding1[3];
> +	__be32 data_pad;
> +	__be32 used_ebs;
> +	__be32 last_eb_bytes;
> +	__u8 padding2[8];
> +}  __attribute__ ((packed));
> +
> +/* struct ubi_fm_volhdr is followed by one struct ubi_fm_eba records */
> +
> +/**
> + * struct ubi_fm_eba - denotes an association beween a PEB and LEB
> + * @magic: EBA table magic number
> + * @reserved_pebs: number of table entries
> + * @pnum: PEB number of LEB (LEB is the index)
> + */
> +struct ubi_fm_eba {
> +	__be32 magic;
> +	__be32 reserved_pebs;
> +	__be32 pnum[0];
> +}  __attribute__ ((packed));
> +
> +void dump_fs_data(struct list_head *used, int used_cnt,
> +		struct ubigen_vol_info *vi, int nsects, int peb_cnt);
> +
> +int add_fastmap_data(struct ubigen_info *ui, int anchor_peb,
> +		int fs_start_peb, int ec, struct list_head *used,
> +		struct ubigen_vol_info *vi, int nsects, int out);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* !__UBI_FASTMAP_H__ */
> +
> diff --git a/ubi-utils/libubigen.c b/ubi-utils/libubigen.c
> index d2a949b..7500334 100644
> --- a/ubi-utils/libubigen.c
> +++ b/ubi-utils/libubigen.c
> @@ -36,10 +36,11 @@
>  #include <libubigen.h>
>  #include <crc32.h>
>  #include "common.h"
> +#include "include/ubi-fastmap.h"
>  
>  void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
>  		      int subpage_size, int vid_hdr_offs, int ubi_ver,
> -		      uint32_t image_seq)
> +		      uint32_t image_seq, int max_leb_count)
>  {
>  	if (!vid_hdr_offs) {
>  		vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
> @@ -61,6 +62,7 @@ void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
>  	if (ui->max_volumes > UBI_MAX_VOLUMES)
>  		ui->max_volumes = UBI_MAX_VOLUMES;
>  	ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
> +	ui->max_leb_count = (max_leb_count > 0 ? max_leb_count : 0);
>  }
>  
>  struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
> @@ -84,7 +86,7 @@ struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
>  }
>  
>  int ubigen_add_volume(const struct ubigen_info *ui,
> -		      const struct ubigen_vol_info *vi,
> +		      struct ubigen_vol_info *vi,
>  		      struct ubi_vtbl_record *vtbl)
>  {
>  	struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
> @@ -103,7 +105,6 @@ int ubigen_add_volume(const struct ubigen_info *ui,
>  		errno = EINVAL;
>  		return -1;
>  	}
> -
>  	memset(vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
>  	tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
>  	vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
> @@ -119,6 +120,7 @@ int ubigen_add_volume(const struct ubigen_info *ui,
>  
>  	tmp = mtd_crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
>  	vtbl_rec->crc =	 cpu_to_be32(tmp);
> +	vi->reserved_pebs = 0;
>  	return 0;
>  }
>  
> @@ -169,11 +171,13 @@ void ubigen_init_vid_hdr(const struct ubigen_info *ui,
>  }
>  
>  int ubigen_write_volume(const struct ubigen_info *ui,
> -			const struct ubigen_vol_info *vi, long long ec,
> -			long long bytes, int in, int out)
> +			struct ubigen_vol_info *vi, long long ec,
> +			long long bytes, int in, int out, struct list_head *used,
> +			int *used_cnt)
>  {
>  	int len = vi->usable_leb_size, rd, lnum = 0;
>  	char *inbuf, *outbuf;
> +	struct ubi_wl_peb *new_peb;
>  
>  	if (vi->id >= ui->max_volumes) {
>  		errmsg("too high volume id %d, max. volumes is %d",
> @@ -228,6 +232,17 @@ int ubigen_write_volume(const struct ubigen_info *ui,
>  		memset(outbuf + ui->data_offs + len, 0xFF,
>  		       ui->peb_size - ui->data_offs - len);
>  
> +		new_peb = malloc(sizeof(*new_peb));
> +		if (!new_peb) {
> +			sys_errmsg("mem allocation failed");
> +			goto out_free1;
> +		}
> +		new_peb->pnum = (*used_cnt)++;
> +		new_peb->ec = ec;
> +		list_add_tail(&new_peb->list, used);
> +		if (vi->pebs)
> +			vi->pebs[lnum] = new_peb->pnum;
> +		vi->reserved_pebs++;
>  		if (write(out, outbuf, ui->peb_size) != ui->peb_size) {
>  			sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
>  			goto out_free1;
> @@ -235,7 +250,6 @@ int ubigen_write_volume(const struct ubigen_info *ui,
>  
>  		lnum += 1;
>  	}
> -
>  	free(outbuf);
>  	free(inbuf);
>  	return 0;
> @@ -249,29 +263,41 @@ out_free:
>  
>  int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
>  			    long long ec1, long long ec2,
> -			    struct ubi_vtbl_record *vtbl, int fd)
> +			    struct ubi_vtbl_record *vtbl, int fd,
> +			    struct ubigen_vol_info *vi_layout)
>  {
>  	int ret;
> -	struct ubigen_vol_info vi;
> +	struct ubigen_vol_info *vi;
>  	char *outbuf;
>  	struct ubi_vid_hdr *vid_hdr;
>  	off_t seek;
>  
> -	vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
> -	vi.id = UBI_LAYOUT_VOLUME_ID;
> -	vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
> -	vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
> -	vi.usable_leb_size = ui->leb_size - vi.data_pad;
> -	vi.data_pad = ui->leb_size - vi.usable_leb_size;
> -	vi.type = UBI_LAYOUT_VOLUME_TYPE;
> -	vi.name = UBI_LAYOUT_VOLUME_NAME;
> -	vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
> -	vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
> +	if (vi_layout) {
> +		vi = vi_layout;
> +	} else {
> +		vi = malloc(sizeof(*vi));
> +		if (!vi)
> +			return sys_errmsg("failed to allocate %lu bytes",
> +					sizeof(*vi));
> +	}
> +	vi->bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
> +	vi->id = UBI_LAYOUT_VOLUME_ID;
> +	vi->alignment = UBI_LAYOUT_VOLUME_ALIGN;
> +	vi->data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
> +	vi->usable_leb_size = ui->leb_size - vi->data_pad;
> +	vi->data_pad = ui->leb_size - vi->usable_leb_size;
> +	vi->type = UBI_LAYOUT_VOLUME_TYPE;
> +	vi->name = UBI_LAYOUT_VOLUME_NAME;
> +	vi->name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
> +	vi->compat = UBI_LAYOUT_VOLUME_COMPAT;
>  
>  	outbuf = malloc(ui->peb_size);
> -	if (!outbuf)
> +	if (!outbuf) {
> +		if (!vi_layout)
> +			free(vi);
>  		return sys_errmsg("failed to allocate %d bytes",
>  				  ui->peb_size);
> +	}
>  
>  	memset(outbuf, 0xFF, ui->data_offs);
>  	vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
> @@ -282,34 +308,38 @@ int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
>  	seek = (off_t) peb1 * ui->peb_size;
>  	if (lseek(fd, seek, SEEK_SET) != seek) {
>  		sys_errmsg("cannot seek output file");
> +		ret = -1;
>  		goto out_free;
>  	}
>  
>  	ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
> -	ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
> +	ubigen_init_vid_hdr(ui, vi, vid_hdr, 0, NULL, 0);
>  	ret = write(fd, outbuf, ui->peb_size);
>  	if (ret != ui->peb_size) {
>  		sys_errmsg("cannot write %d bytes", ui->peb_size);
> +		ret = -1;
>  		goto out_free;
>  	}
>  
>  	seek = (off_t) peb2 * ui->peb_size;
>  	if (lseek(fd, seek, SEEK_SET) != seek) {
>  		sys_errmsg("cannot seek output file");
> +		ret = -1;
>  		goto out_free;
>  	}
>  	ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
> -	ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
> +	ubigen_init_vid_hdr(ui, vi, vid_hdr, 1, NULL, 0);
>  	ret = write(fd, outbuf, ui->peb_size);
>  	if (ret != ui->peb_size) {
>  		sys_errmsg("cannot write %d bytes", ui->peb_size);
> +		ret = -1;
>  		goto out_free;
>  	}
>  
> -	free(outbuf);
> -	return 0;
> -
> +	ret = 0;
>  out_free:
> +	if (!vi_layout)
> +		free(vi);
>  	free(outbuf);
> -	return -1;
> +	return ret;
>  }
> diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c
> index a86abd1..7c5c21c 100644
> --- a/ubi-utils/mtdinfo.c
> +++ b/ubi-utils/mtdinfo.c
> @@ -168,7 +168,7 @@ static void print_ubi_info(const struct mtd_info *mtd_info,
>  	}
>  
>  	ubigen_info_init(&ui, mtd->eb_size, mtd->min_io_size, mtd->subpage_size,
> -			 0, 1, 0);
> +			 0, 1, 0, 0);
>  	printf("Default UBI VID header offset:  %d\n", ui.vid_hdr_offs);
>  	printf("Default UBI data offset:        %d\n", ui.data_offs);
>  	printf("Default UBI LEB size:           ");
> diff --git a/ubi-utils/ubi-fastmap.c b/ubi-utils/ubi-fastmap.c
> new file mode 100644
> index 0000000..a824dba
> --- /dev/null
> +++ b/ubi-utils/ubi-fastmap.c
> @@ -0,0 +1,358 @@
> +/*
> + * Copyright (c) 2014-2015, Linux Foundation.  All Rights Reserved.
> + *
> + * Copyright (c) 2012 Linutronix GmbH
> + * Author: Richard Weinberger <richard at nod.at>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
> + * the GNU General Public License for more details.
> + *
> + */
> +
> +#define PROGRAM_NAME	"ubi-fastmap"
> +
> +#include <sys/stat.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <getopt.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <mtd_swab.h>
> +#include <crc32.h>
> +
> +#include <mtd/ubi-media.h>
> +#include <mtd/ubi-user.h>
> +#include <libubigen.h>
> +#include "common.h"
> +#include "ubiutils-common.h"
> +
> +#include <linux/list.h>
> +
> +#include "include/ubi-fastmap.h"
> +
> +/* Used only for dbg. Will be removed later. */
> +void dbg_dump_fs_data(struct list_head *used, int used_cnt,
> +		struct ubigen_vol_info *vi, int nsects, int peb_cnt)
> +{
> +	int i, j;
> +	struct ubi_wl_peb *peb;
> +	printf("--------------Collected FM data-----------------\n");
> +	printf("Used lst (cnt = %d)\n", used_cnt);
> +	list_for_each_entry(peb, used, list)
> +		printf("[%d,%d], ", peb->pnum, peb->ec);
> +	printf("\n\nGo Over volumes (nsects = %d)", nsects);
> +	for (i = 0; i < nsects; i++){
> +		printf("\nVol-%d:\n", vi[i].id);
> +		for (j = 0; j < peb_cnt; j++)
> +			if (vi[i].pebs && vi[i].pebs[j] != -1)
> +				printf("[%d,%d], ", j, vi[i].pebs[j]);
> +	}
> +	printf("\n");
> +}
> +
> +#define roundup(x, y) (					\
> +{							\
> +	const typeof(y) __y = y;			\
> +	(((x) + (__y - 1)) / __y) * __y;		\
> +}							\
> +)
> +
> +/**
> + * ubi_calc_fm_size - calculates the fastmap size in bytes
> + * @ui: libubigen information (device description object)
> + *
> + * The calculated size is rounded up to LEB size.
> + */
> +static size_t ubi_calc_fm_size(struct ubigen_info *ui)
> +{
> +	size_t size;
> +
> +	size = sizeof(struct ubi_fm_sb) + \
> +		sizeof(struct ubi_fm_hdr) + \
> +		sizeof(struct ubi_fm_scan_pool) + \
> +		sizeof(struct ubi_fm_scan_pool) + \
> +		(ui->max_leb_count * sizeof(struct ubi_fm_ec)) + \
> +		(sizeof(struct ubi_fm_eba) + \
> +		(ui->max_leb_count * sizeof(__be32))) + \
> +		sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES;
> +	return roundup(size, ui->leb_size);
> +}
> +
> +static void init_vid_hdr(const struct ubigen_info *ui,
> +			 struct ubi_vid_hdr *hdr, uint32_t vol_id)
> +{
> +	uint32_t crc;
> +
> +	hdr->vol_type = UBI_VID_DYNAMIC;
> +	hdr->vol_id = cpu_to_be32(vol_id);
> +	hdr->compat = UBI_COMPAT_DELETE;
> +	hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
> +	hdr->version = ui->ubi_ver;
> +
> +	crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
> +	hdr->hdr_crc = cpu_to_be32(crc);
> +}
> +
> +static int write_new_fm_to_file(struct ubigen_info *ui,
> +		struct ubi_fastmap_layout *new_fm,
> +		void *fm_raw, int fm_size, int out)
> +{
> +	struct ubi_vid_hdr *avhdr;
> +	char *outbuf;
> +	int ret, i;
> +
> +	outbuf = malloc(ui->peb_size);
> +	if (!outbuf) {
> +		sys_errmsg("cannot allocate %d bytes of memory", ui->peb_size);
> +		ret = -ENOMEM;
> +		goto out_free;
> +	}
> +
> +	avhdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
> +	for (i = 0; i < new_fm->used_blocks; i++) {
> +		memset(outbuf, 0xFF, ui->data_offs);
> +		ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf,
> +				new_fm->e[0].ec);
> +
> +		memset(avhdr, 0, sizeof(struct ubi_vid_hdr));
> +		avhdr->sqnum = cpu_to_be32(1);
> +		avhdr->lnum = cpu_to_be32(i);
> +		init_vid_hdr(ui, avhdr, UBI_FM_SB_VOLUME_ID);
> +
> +		if (i * ui->leb_size > fm_size) {
> +			sys_errmsg("memory leak!");
> +			ret = -ENOMEM;
> +			goto out_free;
> +		}
> +		memcpy(outbuf + ui->data_offs,
> +				fm_raw + i * ui->leb_size, ui->leb_size);
> +
> +		if (lseek(out, (off_t)(new_fm->e[i].pnum * ui->peb_size),
> +				SEEK_SET) != (off_t)(new_fm->e[i].pnum * ui->peb_size)) {
> +			sys_errmsg("cannot seek output file");
> +			ret = -EPERM;
> +			goto out_free;
> +		}
> +		if (write(out, outbuf, ui->peb_size) != ui->peb_size) {
> +			sys_errmsg("cannot write %d bytes to the output file",
> +					ui->peb_size);
> +			ret = -EPERM;
> +			goto out_free;
> +		}
> +	}
> +	ret = 0;
> +
> +out_free:
> +	free(outbuf);
> +	return ret;
> +}
> +
> +static void *generate_fm_raw_data(struct ubigen_info *ui, int fm_size,
> +		struct list_head *used, int fs_start_peb, int ec,
> +		struct ubigen_vol_info *vi, int nsects)
> +{
> +	size_t fm_pos = 0;
> +	void *fm_raw;
> +	struct ubi_fm_sb *fmsb;
> +	struct ubi_fm_hdr *fmh;
> +	struct ubi_fm_scan_pool *fmpl1, *fmpl2;
> +	struct ubi_fm_ec *fec;
> +	struct ubi_fm_volhdr *fvh;
> +	struct ubi_fm_eba *feba;
> +	int i, j, free_peb_count, used_peb_count, vol_count;
> +	int max_pool_size;
> +	struct ubi_wl_peb *used_peb;
> +
> +	fm_raw = malloc(fm_size);
> +	if (!fm_raw)
> +		return NULL;
> +
> +	memset(fm_raw, 0, fm_size);
> +	fmsb = (struct ubi_fm_sb *)fm_raw;
> +	fm_pos += sizeof(*fmsb);
> +	if (fm_pos > fm_size)
> +		goto out_free;
> +
> +	fmh = (struct ubi_fm_hdr *)(fm_raw + fm_pos);
> +	fm_pos += sizeof(*fmh);
> +	if (fm_pos > fm_size)
> +			goto out_free;
> +
> +	fmsb->magic = cpu_to_be32(UBI_FM_SB_MAGIC);
> +	fmsb->version = UBI_FM_FMT_VERSION;
> +	fmsb->used_blocks = cpu_to_be32(fm_size / ui->leb_size);
> +	/* the max sqnum will be filled in while *reading* the fastmap */
> +	fmsb->sqnum = cpu_to_be32(1);
> +
> +	fmh->magic = cpu_to_be32(UBI_FM_HDR_MAGIC);
> +	free_peb_count = 0;
> +	used_peb_count = 0;
> +	vol_count = 0;
> +
> +	fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
> +	fm_pos += sizeof(*fmpl1);
> +	fmpl1->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
> +	fmpl1->size = 0;
> +	/*
> +	 * fm_pool.max_size is 5% of the total number of PEBs but it's also
> +	 * between UBI_FM_MAX_POOL_SIZE and UBI_FM_MIN_POOL_SIZE.
> +	 */
> +	max_pool_size = min((ui->max_leb_count / 100) * 5,
> +						UBI_FM_MAX_POOL_SIZE);
> +	if (max_pool_size < UBI_FM_MIN_POOL_SIZE)
> +		max_pool_size = UBI_FM_MIN_POOL_SIZE;
> +
> +	fmpl1->max_size = cpu_to_be16(max_pool_size);
> +
> +	fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
> +	fm_pos += sizeof(*fmpl2);
> +	fmpl2->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
> +	fmpl2->size = 0;
> +	fmpl2->max_size = cpu_to_be16(UBI_FM_WL_POOL_SIZE);
> +
> +	/* free list */
> +	for (i = fs_start_peb + fm_size / ui->leb_size;
> +			i < ui->max_leb_count; i++) {
> +		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> +		fec->pnum = cpu_to_be32(i);
> +		fec->ec = cpu_to_be32(ec);
> +		free_peb_count++;
> +		fm_pos += sizeof(*fec);
> +		if (fm_pos > fm_size)
> +			goto out_free;
> +	}
> +	fmh->free_peb_count = cpu_to_be32(free_peb_count);
> +	/* go over used */
> +	list_for_each_entry(used_peb, used, list) {
> +		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> +		fec->pnum = cpu_to_be32(used_peb->pnum);
> +		fec->ec = cpu_to_be32(used_peb->ec);
> +		used_peb_count++;
> +		fm_pos += sizeof(*fec);
> +		if (fm_pos > fm_size)
> +			goto out_free;
> +	}
> +	fmh->used_peb_count = cpu_to_be32(used_peb_count);
> +
> +	fmh->scrub_peb_count = 0;
> +	fmh->erase_peb_count = 0;
> +
> +	/* Go over all the volumes */
> +	for (i = 0; i < nsects; i++) {
> +		vol_count++;
> +		fvh = (struct ubi_fm_volhdr *)(fm_raw + fm_pos);
> +		fm_pos += sizeof(*fvh);
> +		if (fm_pos > fm_size)
> +			goto out_free;
> +
> +		fvh->magic = cpu_to_be32(UBI_FM_VHDR_MAGIC);
> +		fvh->vol_id = cpu_to_be32(vi[i].id);
> +		if (vi[i].type != UBI_VID_DYNAMIC &&
> +				vi[i].type != UBI_VID_STATIC)
> +			goto out_free;
> +
> +		fvh->vol_type = (vi[i].type == UBI_VID_DYNAMIC ?
> +				UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME);
> +		fvh->used_ebs = cpu_to_be32(vi[i].used_ebs);
> +		fvh->data_pad = cpu_to_be32(vi[i].data_pad);
> +		fvh->last_eb_bytes = cpu_to_be32(vi[i].usable_leb_size);
> +
> +		feba = (struct ubi_fm_eba *)(fm_raw + fm_pos);
> +		fm_pos += sizeof(*feba) +
> +				(sizeof(__be32) * vi[i].reserved_pebs);
> +		if (fm_pos > fm_size)
> +			goto out_free;
> +
> +		if (!vi[i].pebs)
> +			goto out_free;
> +		for (j = 0; j < vi[i].reserved_pebs; j++)
> +			feba->pnum[j] = cpu_to_be32(vi[i].pebs[j]);
> +
> +		feba->reserved_pebs = cpu_to_be32(j);
> +		feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC);
> +	}
> +	fmh->vol_count = cpu_to_be32(vol_count);
> +	fmh->bad_peb_count = 0;
> +
> +	return fm_raw;
> +
> +out_free:
> +	free(fm_raw);
> +	return NULL;
> +}
> +
> +/**
> + * add_fastmap_data - Adds fastmap data to the generated image file
> + * @ui: UBI device description object
> + * @anchor_peb: number of PEB to write the fastmap anchor to
> + * @fs_start_peb: number of the first free PEB that can be used
> + * 		for fastmap data
> + * @ec: erase counter value to set for fastmap PEBs
> + * @used: list of used PEBs
> + * @vi: Volumes info
> + * @nsects: number of volumes at @vi
> + * @out: output image file handler
> + *
> + * Returns 0 on success, < 0 indicates an internal error.
> + */
> +int add_fastmap_data(struct ubigen_info *ui, int anchor_peb,
> +		int fs_start_peb, int ec, struct list_head *used,
> +		struct ubigen_vol_info *vi, int nsects, int out)
> +{
> +	void *fm_raw = NULL;
> +	struct ubi_fastmap_layout *new_fm;
> +	int ret, i;
> +	int fm_size = ubi_calc_fm_size(ui);
> +	struct ubi_fm_sb *fmsb;
> +
> +	new_fm = malloc(sizeof(*new_fm));
> +	if (!new_fm) {
> +		ret = -ENOMEM;
> +		goto out_free;
> +	}
> +
> +	new_fm->used_blocks = fm_size / ui->leb_size;
> +
> +	if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) {
> +		sys_errmsg("fastmap too large");
> +		ret = -ENOSPC;
> +		goto out_free;
> +	}
> +	fm_raw = generate_fm_raw_data(ui, fm_size, used, fs_start_peb, ec,
> +			vi, nsects);
> +	if (!fm_raw) {
> +		sys_errmsg("fastmap too large");
> +		ret = -ENOSPC;
> +		goto out_free;
> +	}
> +
> +	for (i = 1; i < new_fm->used_blocks - 1; i++) {
> +		new_fm->e[i].pnum = fs_start_peb + i - 1;
> +		new_fm->e[i].ec = ec;
> +	}
> +	new_fm->e[0].pnum = anchor_peb;
> +	new_fm->e[0].ec = ec;
> +
> +	fmsb = (struct ubi_fm_sb *)fm_raw;
> +	for (i = 0; i < new_fm->used_blocks; i++) {
> +		fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i].pnum);
> +		fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i].ec);
> +	}
> +
> +	fmsb->data_crc = 0;
> +	fmsb->data_crc = cpu_to_be32(mtd_crc32(UBI_CRC32_INIT,
> +						fm_raw, fm_size));
> +	ret = write_new_fm_to_file(ui, new_fm, fm_raw, fm_size, out);
> +
> +out_free:
> +	free(fm_raw);
> +	free(new_fm);
> +	return ret;
> +}
> diff --git a/ubi-utils/ubiformat.c b/ubi-utils/ubiformat.c
> index 21409ca..7bb8272 100644
> --- a/ubi-utils/ubiformat.c
> +++ b/ubi-utils/ubiformat.c
> @@ -663,7 +663,7 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd,
>  			goto out_free;
>  
>  		err = ubigen_write_layout_vol(ui, eb1, eb2, ec1,  ec2, vtbl,
> -					      args.node_fd);
> +					      args.node_fd, NULL);
>  		free(vtbl);
>  		if (err) {
>  			errmsg("cannot write layout volume");
> @@ -884,7 +884,7 @@ int main(int argc, char * const argv[])
>  		normsg("use erase counter %lld for all eraseblocks", args.ec);
>  
>  	ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size,
> -			 args.vid_hdr_offs, args.ubi_ver, args.image_seq);
> +			 args.vid_hdr_offs, args.ubi_ver, args.image_seq, 0);
>  
>  	if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
>  		/*
> @@ -905,7 +905,7 @@ int main(int argc, char * const argv[])
>  		} else
>  			ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, 0,
>  					 si->vid_hdr_offs, args.ubi_ver,
> -					 args.image_seq);
> +					 args.image_seq, 0);
>  		normsg("use offsets %d and %d",  ui.vid_hdr_offs, ui.data_offs);
>  	}
>  
> diff --git a/ubi-utils/ubinize.c b/ubi-utils/ubinize.c
> index eccf41f..7d33731 100644
> --- a/ubi-utils/ubinize.c
> +++ b/ubi-utils/ubinize.c
> @@ -31,6 +31,7 @@
>  #include <getopt.h>
>  #include <string.h>
>  #include <fcntl.h>
> +#include <linux/list.h>
>  
>  #include <mtd/ubi-media.h>
>  #include <libubigen.h>
> @@ -38,6 +39,7 @@
>  #include <libubi.h>
>  #include "common.h"
>  #include "ubiutils-common.h"
> +#include "include/ubi-fastmap.h"
>  
>  static const char doc[] = PROGRAM_NAME " version " VERSION
>  " - a tool to generate UBI images. An UBI image may contain one or more UBI "
> @@ -455,6 +457,14 @@ static int read_section(const struct ubigen_info *ui, const char *sname,
>  	else
>  		vi->used_ebs = (st->st_size + vi->usable_leb_size - 1) / vi->usable_leb_size;
>  	vi->compat = 0;
> +	if (ui->max_leb_count > 0) {
> +		vi->pebs = calloc(sizeof(int), ui->max_leb_count);
> +		if (!vi->pebs) {
> +			sys_errmsg("cannot allocate memory for vi->peb\n");
> +			return -1;
> +		}
> +		memset(vi->pebs, -1, sizeof(int)*ui->max_leb_count);
> +	}
>  	return 0;
>  }
>  
> @@ -464,6 +474,10 @@ int main(int argc, char * const argv[])
>  	struct ubigen_info ui;
>  	struct ubi_vtbl_record *vtbl;
>  	struct ubigen_vol_info *vi;
> +	int used_cnt = 0;
> +	struct list_head used;
> +	struct ubi_wl_peb *new_peb;
> +
>  	off_t seek;
>  
>  	err = parse_opt(argc, argv);
> @@ -472,7 +486,7 @@ int main(int argc, char * const argv[])
>  
>  	ubigen_info_init(&ui, args.peb_size, args.min_io_size,
>  			 args.subpage_size, args.vid_hdr_offs,
> -			 args.ubi_ver, args.image_seq);
> +			 args.ubi_ver, args.image_seq, args.max_leb_count);
>  
>  	verbose(args.verbose, "LEB size:                  %d", ui.leb_size);
>  	verbose(args.verbose, "PEB size:                  %d", ui.peb_size);
> @@ -517,7 +531,8 @@ int main(int argc, char * const argv[])
>  		goto out_dict;
>  	}
>  
> -	vi = calloc(sizeof(struct ubigen_vol_info), sects);
> +	/* Save vi[0] for layout volume */
> +	vi = calloc(sizeof(struct ubigen_vol_info), sects + 1);
>  	if (!vi) {
>  		errmsg("cannot allocate memory");
>  		goto out_dict;
> @@ -528,11 +543,23 @@ int main(int argc, char * const argv[])
>  	 * will be written later.
>  	 */
>  	seek = ui.peb_size * 2;
> +	used_cnt += 2;
>  	if (lseek(args.out_fd, seek, SEEK_SET) != seek) {
>  		sys_errmsg("cannot seek file \"%s\"", args.f_out);
>  		goto out_free;
>  	}
>  
> +	/* If max_leb_count was provided, leave one PEB for FM superblock */
> +	if (ui.max_leb_count > 0) {
> +		seek = ui.peb_size * 3;
> +		used_cnt++;
> +		if (lseek(args.out_fd, seek, SEEK_SET) != seek) {
> +			sys_errmsg("cannot seek file \"%s\"", args.f_out);
> +			goto out_free;
> +		}
> +	}
> +
> +	INIT_LIST_HEAD(&used);
>  	for (i = 0; i < sects; i++) {
>  		const char *sname = iniparser_getsecname(args.dict, i);
>  		const char *img = NULL;
> @@ -597,7 +624,9 @@ int main(int argc, char * const argv[])
>  			verbose(args.verbose, "writing volume %d", vi[i].id);
>  			verbose(args.verbose, "image file: %s", img);
>  
> -			err = ubigen_write_volume(&ui, &vi[i], args.ec, st.st_size, fd, args.out_fd);
> +			err = ubigen_write_volume(&ui, &vi[i], args.ec,
> +					st.st_size, fd, args.out_fd,
> +					&used, &used_cnt);
>  			close(fd);
>  			if (err) {
>  				errmsg("cannot write volume for section \"%s\"", sname);
> @@ -611,14 +640,42 @@ int main(int argc, char * const argv[])
>  
>  	verbose(args.verbose, "writing layout volume");
>  
> -	err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd);
> +	err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl,
> +			args.out_fd, &vi[sects]);
>  	if (err) {
>  		errmsg("cannot write layout volume");
>  		goto out_free;
> +	} else
> +		verbose(args.verbose, "writing layout volume - done");
> +
> +	if (ui.max_leb_count > 0) {
> +		vi[sects].pebs = calloc(sizeof(int), ui.max_leb_count);
> +		if (!vi[sects].pebs) {
> +			sys_errmsg("cannot allocate memory for vi->peb\n");
> +			goto out_free;
> +		}
> +		memset(vi[sects].pebs, -1, sizeof(int)*ui.max_leb_count);
> +		/* Add layout volume PEBs to used list */
> +		for (i = 0; i < 2; i++) {
> +			new_peb = malloc(sizeof(*new_peb));
> +			if (!new_peb) {
> +				sys_errmsg("mem allocation failed");
> +				goto out_free;
> +			}
> +			new_peb->pnum = i;
> +			new_peb->ec = args.ec;
> +			vi[sects].pebs[i] = i;
> +		}
> +		vi[sects].reserved_pebs = 2;
> +		add_fastmap_data(&ui, 2, used_cnt-1, args.ec, &used,
> +				vi, sects+1, args.out_fd);
> +		list_for_each_entry(new_peb, &used, list)
> +			free(new_peb);
> +		for (i = 0; i < sects; i++)
> +			free(vi[i].pebs);
>  	}
>  
>  	verbose(args.verbose, "done");
> -
>  	free(vi);
>  	iniparser_freedict(args.dict);
>  	free(vtbl);
> @@ -626,6 +683,10 @@ int main(int argc, char * const argv[])
>  	return 0;
>  
>  out_free:
> +	list_for_each_entry(new_peb, &used, list)
> +		free(new_peb);
> +	for (i = 0; i < sects; i++)
> +		free(vi[i].pebs);
>  	free(vi);
>  out_dict:
>  	iniparser_freedict(args.dict);
> 



More information about the linux-mtd mailing list