Skip to contentSkip to conversation

fs/fat: cleanups + readdir implementation

PATCH Superseded Rob Clark 4 participants 34 messages Sep 9, 2017 – Sep 17, 2017

Subsystems (2)
lore
Share & tools
lore

Rob Clark

author
#0 lore raw

v3 cover fs/fat: cleanups + readdir implementation

Introduce directory traversal iterators, and implement fs_readdir() which is needed by EFI_LOADER.

The part re-working fat.c to use the directory iterators itself is nearly a 2:1 negative diffstat, and a pretty big cleanup. I fixed one or two other small issues along the way.

v2: fix a couple issues (partition is whole disk, and traversing ".."
up to root directory)
v3: mostly addition of comments plus cleaning up open-coded sector <->
cluster conversions, and some FAT32 fixes for large directories

Rob Clark (9):
fs/fat: split out helper to init fsdata
fs/fat: introduce new director iterators
fat/fs: convert to directory iterators
fs: add fs_readdir()
fs/fat: implement opendir/readdir/closedir fat/fs: remove a bunch of dead code
fat/fs: move ls to generic implementation fs/fat: fix case for FAT shortnames
fs/fat: Clean up open-coded sector <-> cluster conversions

 disk/part.c        |   31 +-
 fs/fat/Makefile    |    4 -
 fs/fat/fat.c       | 1062 ++++++++++++++++++++++------------------------------
 fs/fat/fat_write.c |   12 +-
 fs/fat/file.c      |  183 ---------
 fs/fs.c            |  137 ++++++-
 include/fat.h      |   49 ++-
 include/fs.h       |   67 ++++
 include/part.h     |    9 +
 9 files changed, 700 insertions(+), 854 deletions(-)
 delete mode 100644 fs/fat/file.c
Signature · 1 line
2.13.5
author
#1 lore raw

PATCH v3 1/9 fs/fat: split out helper to init fsdata

Want to re-use this in fat dirent iterator in next patch.

---
 fs/fat/fat.c  | 73 +++++++++++++++++++++++++++++++++++------------------------
 include/fat.h |  1 +
 2 files changed, 44 insertions(+), 30 deletions(-)
fs/fat/fat.c +43 -30
index 465a6875ed..e1c0a15dc7 100644
@@ -808,35 +808,17 @@ exit:
 	return ret;
 }
 
-__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
-	__aligned(ARCH_DMA_MINALIGN);
-
-int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
-		   loff_t maxsize, int dols, int dogetsize, loff_t *size)
+static int get_fs_info(fsdata *mydata)
 {
-	char fnamecopy[2048];
 	boot_sector bs;
 	volume_info volinfo;
-	fsdata datablock;
-	fsdata *mydata = &datablock;
-	dir_entry *dentptr = NULL;
-	__u16 prevcksum = 0xffff;
-	char *subname = "";
-	__u32 cursect;
-	int idx, isdir = 0;
-	int files = 0, dirs = 0;
-	int ret = -1;
-	int firsttime;
 	__u32 root_cluster = 0;
-	__u32 read_blk;
-	int rootdir_size = 0;
-	int buffer_blk_cnt;
-	int do_read;
-	__u8 *dir_ptr;
+	int ret;
 
-	if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
+	ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize);
+	if (ret) {
 		debug("Error: reading boot sector\n");
-		return -1;
+		return ret;
 	}
 
 	if (mydata->fatsize == 32) {
@@ -848,8 +830,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
 
 	mydata->fat_sect = bs.reserved;
 
-	cursect = mydata->rootdir_sect
-		= mydata->fat_sect + mydata->fatlength * bs.fats;
+	mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats;
 
 	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
 	mydata->clust_size = bs.cluster_size;
@@ -863,12 +844,12 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
 		mydata->data_begin = mydata->rootdir_sect -
 					(mydata->clust_size * 2);
 	} else {
-		rootdir_size = ((bs.dir_entries[1]  * (int)256 +
-				 bs.dir_entries[0]) *
-				 sizeof(dir_entry)) /
-				 mydata->sect_size;
+		mydata->rootdir_size = ((bs.dir_entries[1]  * (int)256 +
+					 bs.dir_entries[0]) *
+					 sizeof(dir_entry)) /
+					 mydata->sect_size;
 		mydata->data_begin = mydata->rootdir_sect +
-					rootdir_size -
+					mydata->rootdir_size -
 					(mydata->clust_size * 2);
 	}
 
@@ -893,6 +874,38 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
 	debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
 	      mydata->clust_size);
 
+	return 0;
+}
+
+__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
+	__aligned(ARCH_DMA_MINALIGN);
+
+int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
+		   loff_t maxsize, int dols, int dogetsize, loff_t *size)
+{
+	char fnamecopy[2048];
+	fsdata datablock;
+	fsdata *mydata = &datablock;
+	dir_entry *dentptr = NULL;
+	__u16 prevcksum = 0xffff;
+	char *subname = "";
+	__u32 cursect;
+	int idx, isdir = 0;
+	int files = 0, dirs = 0;
+	int ret = -1;
+	int firsttime;
+	__u32 root_cluster = 0;
+	__u32 read_blk;
+	int rootdir_size = 0;
+	int buffer_blk_cnt;
+	int do_read;
+	__u8 *dir_ptr;
+
+	if (get_fs_info(mydata))
+		return -1;
+
+	cursect = mydata->rootdir_sect;
+
 	/* "cwd" is always the root... */
 	while (ISDIRDELIM(*filename))
 		filename++;
include/fat.h +1 -0
index 71879f01ca..b671ee8f81 100644
@@ -174,6 +174,7 @@ typedef struct {
 	__u16	clust_size;	/* Size of clusters in sectors */
 	int	data_begin;	/* The sector of the first cluster, can be negative */
 	int	fatbufnum;	/* Used by get_fatent, init to -1 */
+	int	rootdir_size;	/* Size of root dir for non-FAT32 */
 } fsdata;
 
 typedef int	(file_detectfs_func)(void);
Signature · 1 line
2.13.5
#2 lore raw

PATCH v3 1/9 fs/fat: split out helper to init fsdata

Quoted 5 lines · Rob Clark

Want to re-use this in fat dirent iterator in next patch.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/12f6d4e3/attachment.sig>
author
#3 lore raw

PATCH v3 2/9 fs/fat: introduce new director iterators

In reply to Rob Clark

Untangle directory traversal into a simple iterator, to replace the existing multi-purpose do_fat_read_at() + get_dentfromdir().

---
 fs/fat/fat.c  | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/fat.h |   7 ++
 2 files changed, 360 insertions(+), 3 deletions(-)
fs/fat/fat.c +353 -3
index e1c0a15dc7..ee2bbe38f1 100644
@@ -812,7 +812,6 @@ static int get_fs_info(fsdata *mydata)
 {
 	boot_sector bs;
 	volume_info volinfo;
-	__u32 root_cluster = 0;
 	int ret;
 
 	ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize);
@@ -822,7 +821,6 @@ static int get_fs_info(fsdata *mydata)
 	}
 
 	if (mydata->fatsize == 32) {
-		root_cluster = bs.root_cluster;
 		mydata->fatlength = bs.fat32_length;
 	} else {
 		mydata->fatlength = bs.fat_length;
@@ -843,6 +841,7 @@ static int get_fs_info(fsdata *mydata)
 	if (mydata->fatsize == 32) {
 		mydata->data_begin = mydata->rootdir_sect -
 					(mydata->clust_size * 2);
+		mydata->root_cluster = bs.root_cluster;
 	} else {
 		mydata->rootdir_size = ((bs.dir_entries[1]  * (int)256 +
 					 bs.dir_entries[0]) *
@@ -851,6 +850,9 @@ static int get_fs_info(fsdata *mydata)
 		mydata->data_begin = mydata->rootdir_sect +
 					mydata->rootdir_size -
 					(mydata->clust_size * 2);
+		mydata->root_cluster = (mydata->rootdir_sect -
+					mydata->data_begin) /
+					mydata->clust_size;
 	}
 
 	mydata->fatbufnum = -1;
@@ -868,7 +870,7 @@ static int get_fs_info(fsdata *mydata)
 	       mydata->fatsize, mydata->fat_sect, mydata->fatlength);
 	debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n"
 	       "Data begins at: %d\n",
-	       root_cluster,
+	       mydata->root_cluster,
 	       mydata->rootdir_sect,
 	       mydata->rootdir_sect * mydata->sect_size, mydata->data_begin);
 	debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
@@ -1245,6 +1247,354 @@ exit:
 	return ret;
 }
 
+
+/*
+ * Directory iterator, to simplify filesystem traversal
+ *
+ * Implements an iterator pattern to traverse directory tables,
+ * transparently handling directory tables split across multiple
+ * clusters, and the difference between FAT12/FAT16 root directory
+ * (contiguous) and subdirectories + FAT32 root (chained).
+ *
+ * Rough usage:
+ *
+ *   for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) {
+ *      // to traverse down to a subdirectory pointed to by
+ *      // current iterator position:
+ *      fat_itr_child(&itr, &itr);
+ *   }
+ *
+ * For more complete example, see fat_itr_resolve()
+ */
+
+typedef struct {
+	fsdata    *fsdata;        /* filesystem parameters */
+	unsigned   clust;         /* current cluster */
+	int        last_cluster;  /* set once we've read last cluster */
+	int        is_root;       /* is iterator at root directory */
+	int        remaining;     /* remaining dent's in current cluster */
+
+	/* current iterator position values: */
+	dir_entry *dent;          /* current directory entry */
+	char       l_name[VFAT_MAXLEN_BYTES];    /* long (vfat) name */
+	char       s_name[14];    /* short 8.3 name */
+	char      *name;          /* l_name if there is one, else s_name */
+
+	/* storage for current cluster in memory: */
+	u8         block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
+} fat_itr;
+
+static int fat_itr_isdir(fat_itr *itr);
+
+/**
+ * fat_itr_root() - initialize an iterator to start at the root
+ * directory
+ *
+ * @itr: iterator to initialize
+ * @fsdata: filesystem data for the partition
+ * @return 0 on success, else -errno
+ */
+static int fat_itr_root(fat_itr *itr, fsdata *fsdata)
+{
+	if (get_fs_info(fsdata))
+		return -ENXIO;
+
+	itr->fsdata = fsdata;
+	itr->clust = fsdata->root_cluster;
+	itr->dent = NULL;
+	itr->remaining = 0;
+	itr->last_cluster = 0;
+	itr->is_root = 1;
+
+	return 0;
+}
+
+/**
+ * fat_itr_child() - initialize an iterator to descend into a sub-
+ * directory
+ *
+ * Initializes 'itr' to iterate the contents of the directory at
+ * the current cursor position of 'parent'.  It is an error to
+ * call this if the current cursor of 'parent' is pointing at a
+ * regular file.
+ *
+ * Note that 'itr' and 'parent' can be the same pointer if you do
+ * not need to preserve 'parent' after this call, which is useful
+ * for traversing directory structure to resolve a file/directory.
+ *
+ * @itr: iterator to initialize
+ * @parent: the iterator pointing at a directory entry in the
+ *    parent directory of the directory to iterate
+ */
+static void fat_itr_child(fat_itr *itr, fat_itr *parent)
+{
+	fsdata *mydata = parent->fsdata;  /* for silly macros */
+	unsigned clustnum = START(parent->dent);
+
+	assert(fat_itr_isdir(parent));
+
+	itr->fsdata = parent->fsdata;
+	if (clustnum > 0) {
+		itr->clust = clustnum;
+	} else {
+		itr->clust = parent->fsdata->root_cluster;
+	}
+	itr->dent = NULL;
+	itr->remaining = 0;
+	itr->last_cluster = 0;
+	itr->is_root = 0;
+}
+
+static void *next_cluster(fat_itr *itr)
+{
+	fsdata *mydata = itr->fsdata;  /* for silly macros */
+	int ret;
+	u32 sect;
+
+	/* have we reached the end? */
+	if (itr->last_cluster)
+		return NULL;
+
+	sect = clust_to_sect(itr->fsdata, itr->clust);
+
+	debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
+	      sect, itr->fsdata->clust_size, DIRENTSPERBLOCK);
+
+	/*
+	 * NOTE: do_fat_read_at() had complicated logic to deal w/
+	 * vfat names that span multiple clusters in the fat16 case,
+	 * which get_dentfromdir() probably also needed (and was
+	 * missing).  And not entirely sure what fat32 didn't have
+	 * the same issue..  We solve that by only caring about one
+	 * dent at a time and iteratively constructing the vfat long
+	 * name.
+	 */
+	ret = disk_read(sect, itr->fsdata->clust_size,
+			itr->block);
+	if (ret < 0) {
+		debug("Error: reading block\n");
+		return NULL;
+	}
+
+	if (itr->is_root && itr->fsdata->fatsize != 32) {
+		itr->clust++;
+		sect = clust_to_sect(itr->fsdata, itr->clust);
+		if (sect - itr->fsdata->rootdir_sect >=
+		    itr->fsdata->rootdir_size) {
+			debug("cursect: 0x%x\n", itr->clust);
+			itr->last_cluster = 1;
+		}
+	} else {
+		itr->clust = get_fatent(itr->fsdata, itr->clust);
+		if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) {
+			debug("cursect: 0x%x\n", itr->clust);
+			itr->last_cluster = 1;
+		}
+	}
+
+	return itr->block;
+}
+
+static dir_entry *next_dent(fat_itr *itr)
+{
+	if (itr->remaining == 0) {
+		struct dir_entry *dent = next_cluster(itr);
+		unsigned nbytes = itr->fsdata->sect_size *
+			itr->fsdata->clust_size;
+
+		/* have we reached the last cluster? */
+		if (!dent)
+			return NULL;
+
+		itr->remaining = nbytes / sizeof(dir_entry) - 1;
+		itr->dent = dent;
+	} else {
+		itr->remaining--;
+		itr->dent++;
+	}
+
+	/* have we reached the last valid entry? */
+	if (itr->dent->name[0] == 0)
+		return NULL;
+
+	return itr->dent;
+}
+
+static dir_entry *extract_vfat_name(fat_itr *itr)
+{
+	struct dir_entry *dent = itr->dent;
+	int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK;
+	u8 chksum, alias_checksum = ((dir_slot *)dent)->alias_checksum;
+	int n = 0;
+
+	while (seqn--) {
+		char buf[13];
+		int idx = 0;
+
+		slot2str((dir_slot *)dent, buf, &idx);
+
+		/* shift accumulated long-name up and copy new part in: */
+		memmove(itr->l_name + idx, itr->l_name, n);
+		memcpy(itr->l_name, buf, idx);
+		n += idx;
+
+		dent = next_dent(itr);
+		if (!dent)
+			return NULL;
+	}
+
+	itr->l_name[n] = '\0';
+
+	chksum = mkcksum(dent->name, dent->ext);
+
+	/* checksum mismatch could mean deleted file, etc.. skip it: */
+	if (chksum != alias_checksum) {
+		debug("** chksum=%x, alias_checksum=%x, l_name=%s, s_name=%8s.%3s\n",
+		      chksum, alias_checksum, itr->l_name, dent->name, dent->ext);
+		return NULL;
+	}
+
+	return dent;
+}
+
+/**
+ * fat_itr_next() - step to the next entry in a directory
+ *
+ * Must be called once on a new iterator before the cursor is valid.
+ *
+ * @itr: the iterator to iterate
+ * @return boolean, 1 if success or 0 if no more entries in the
+ *    current directory
+ */
+static int fat_itr_next(fat_itr *itr)
+{
+	dir_entry *dent;
+
+	itr->name = NULL;
+
+	while (1) {
+		dent = next_dent(itr);
+		if (!dent)
+			return 0;
+
+		if (dent->name[0] == DELETED_FLAG ||
+		    dent->name[0] == aRING)
+			continue;
+
+		if (dent->attr & ATTR_VOLUME) {
+			if (vfat_enabled &&
+			    (dent->attr & ATTR_VFAT) == ATTR_VFAT &&
+			    (dent->name[0] & LAST_LONG_ENTRY_MASK)) {
+				dent = extract_vfat_name(itr);
+				if (!dent)
+					continue;
+				itr->name = itr->l_name;
+				break;
+			} else {
+				/* Volume label or VFAT entry, skip */
+				continue;
+			}
+		}
+
+		break;
+	}
+
+	get_name(dent, itr->s_name);
+	if (!itr->name)
+		itr->name = itr->s_name;
+
+	return 1;
+}
+
+/**
+ * fat_itr_isdir() - is current cursor position pointing to a directory
+ *
+ * @itr: the iterator
+ * @return true if cursor is at a directory
+ */
+static int fat_itr_isdir(fat_itr *itr)
+{
+	return !!(itr->dent->attr & ATTR_DIR);
+}
+
+/*
+ * Helpers:
+ */
+
+#define TYPE_FILE 0x1
+#define TYPE_DIR  0x2
+#define TYPE_ANY  (TYPE_FILE | TYPE_DIR)
+
+/**
+ * fat_itr_resolve() - traverse directory structure to resolve the
+ * requested path.
+ *
+ * Traverse directory structure to the requested path.  If the specified
+ * path is to a directory, this will descend into the directory and
+ * leave it iterator at the start of the directory.  If the path is to a
+ * file, it will leave the iterator in the parent directory with current
+ * cursor at file's entry in the directory.
+ *
+ * @itr: iterator initialized to root
+ * @path: the requested path
+ * @type: bitmask of allowable file types
+ * @return 0 on success or -errno
+ */
+static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
+{
+	const char *next;
+
+	/* chomp any extra leading slashes: */
+	while (path[0] && ISDIRDELIM(path[0]))
+		path++;
+
+	/* are we at the end? */
+	if (strlen(path) == 0) {
+		if (!(type & TYPE_DIR))
+			return -ENOENT;
+		return 0;
+	}
+
+	/* find length of next path entry: */
+	next = path;
+	while (next[0] && !ISDIRDELIM(next[0]))
+		next++;
+
+	while (fat_itr_next(itr)) {
+		int match = 0;
+		unsigned n = max(strlen(itr->name), (size_t)(next - path));
+
+		/* check both long and short name: */
+		if (!strncasecmp(path, itr->name, n))
+			match = 1;
+		else if (itr->name != itr->s_name &&
+			 !strncasecmp(path, itr->s_name, n))
+			match = 1;
+
+		if (!match)
+			continue;
+
+		if (fat_itr_isdir(itr)) {
+			/* recurse into directory: */
+			fat_itr_child(itr, itr);
+			return fat_itr_resolve(itr, next, type);
+		} else if (next[0]) {
+			/*
+			 * If next is not empty then we have a case
+			 * like: /path/to/realfile/nonsense
+			 */
+			debug("bad trailing path: %s\n", next);
+			return -ENOENT;
+		} else if (!(type & TYPE_FILE)) {
+			return -ENOTDIR;
+		} else {
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
 int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols,
 		loff_t *actread)
 {
include/fat.h +7 -0
index b671ee8f81..21bb6666cf 100644
@@ -175,8 +175,15 @@ typedef struct {
 	int	data_begin;	/* The sector of the first cluster, can be negative */
 	int	fatbufnum;	/* Used by get_fatent, init to -1 */
 	int	rootdir_size;	/* Size of root dir for non-FAT32 */
+	__u32	root_cluster;	/* First cluster of root dir for FAT32 */
 } fsdata;
 
+/* TODO clean up places that are open-coding this: */
+static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
+{
+	return fsdata->data_begin + clust * fsdata->clust_size;
+}
+
 typedef int	(file_detectfs_func)(void);
 typedef int	(file_ls_func)(const char *dir);
 typedef int	(file_read_func)(const char *filename, void *buffer,
Signature · 1 line
2.13.5
#4 lore raw

PATCH v3 2/9 fs/fat: introduce new director iterators

Quoted 5 lines · Rob Clark

Untangle directory traversal into a simple iterator, to replace the existing multi-purpose do_fat_read_at() + get_dentfromdir().

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/eda978e3/attachment.sig>
author
#5 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

In reply to Rob Clark

And drop a whole lot of ugly code!

---
 fs/fat/fat.c  | 722 +++++++---------------------------------------------------
 include/fat.h |   6 -
 2 files changed, 76 insertions(+), 652 deletions(-)
fs/fat/fat.c +76 -646
index ee2bbe38f1..bbba7947ee 100644
@@ -119,22 +119,6 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no)
 }
 
 /*
- * Get the first occurence of a directory delimiter ('/' or '\') in a string.
- * Return index into string if found, -1 otherwise.
- */
-static int dirdelim(char *str)
-{
-	char *start = str;
-
-	while (*str != '\0') {
-		if (ISDIRDELIM(*str))
-			return str - start;
-		str++;
-	}
-	return -1;
-}
-
-/*
  * Extract zero terminated short name from a directory entry.
  */
 static void get_name(dir_entry *dirent, char *s_name)
@@ -468,95 +452,6 @@ static int slot2str(dir_slot *slotptr, char *l_name, int *idx)
 	return 0;
 }
 
-/*
- * Extract the full long filename starting at 'retdent' (which is really
- * a slot) into 'l_name'. If successful also copy the real directory entry
- * into 'retdent'
- * Return 0 on success, -1 otherwise.
- */
-static int
-get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
-	     dir_entry *retdent, char *l_name)
-{
-	dir_entry *realdent;
-	dir_slot *slotptr = (dir_slot *)retdent;
-	__u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
-							PREFETCH_BLOCKS :
-							mydata->clust_size);
-	__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
-	int idx = 0;
-
-	if (counter > VFAT_MAXSEQ) {
-		debug("Error: VFAT name is too long\n");
-		return -1;
-	}
-
-	while ((__u8 *)slotptr < buflimit) {
-		if (counter == 0)
-			break;
-		if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
-			return -1;
-		slotptr++;
-		counter--;
-	}
-
-	if ((__u8 *)slotptr >= buflimit) {
-		dir_slot *slotptr2;
-
-		if (curclust == 0)
-			return -1;
-		curclust = get_fatent(mydata, curclust);
-		if (CHECK_CLUST(curclust, mydata->fatsize)) {
-			debug("curclust: 0x%x\n", curclust);
-			printf("Invalid FAT entry\n");
-			return -1;
-		}
-
-		if (get_cluster(mydata, curclust, get_contents_vfatname_block,
-				mydata->clust_size * mydata->sect_size) != 0) {
-			debug("Error: reading directory block\n");
-			return -1;
-		}
-
-		slotptr2 = (dir_slot *)get_contents_vfatname_block;
-		while (counter > 0) {
-			if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
-			    & 0xff) != counter)
-				return -1;
-			slotptr2++;
-			counter--;
-		}
-
-		/* Save the real directory entry */
-		realdent = (dir_entry *)slotptr2;
-		while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
-			slotptr2--;
-			slot2str(slotptr2, l_name, &idx);
-		}
-	} else {
-		/* Save the real directory entry */
-		realdent = (dir_entry *)slotptr;
-	}
-
-	do {
-		slotptr--;
-		if (slot2str(slotptr, l_name, &idx))
-			break;
-	} while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
-
-	l_name[idx] = '\0';
-	if (*l_name == DELETED_FLAG)
-		*l_name = '\0';
-	else if (*l_name == aRING)
-		*l_name = DELETED_FLAG;
-	downcase(l_name);
-
-	/* Return the real directory entry */
-	memcpy(retdent, realdent, sizeof(dir_entry));
-
-	return 0;
-}
-
 /* Calculate short name checksum */
 static __u8 mkcksum(const char name[8], const char ext[3])
 {
@@ -573,169 +468,13 @@ static __u8 mkcksum(const char name[8], const char ext[3])
 }
 
 /*
- * Get the directory entry associated with 'filename' from the directory
- * starting at 'startsect'
+ * TODO these should go away once fat_write is reworked to use the
+ * directory iterator
  */
 __u8 get_dentfromdir_block[MAX_CLUSTSIZE]
 	__aligned(ARCH_DMA_MINALIGN);
-
-static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
-				  char *filename, dir_entry *retdent,
-				  int dols)
-{
-	__u16 prevcksum = 0xffff;
-	__u32 curclust = START(retdent);
-	int files = 0, dirs = 0;
-
-	debug("get_dentfromdir: %s\n", filename);
-
-	while (1) {
-		dir_entry *dentptr;
-
-		int i;
-
-		if (get_cluster(mydata, curclust, get_dentfromdir_block,
-				mydata->clust_size * mydata->sect_size) != 0) {
-			debug("Error: reading directory block\n");
-			return NULL;
-		}
-
-		dentptr = (dir_entry *)get_dentfromdir_block;
-
-		for (i = 0; i < DIRENTSPERCLUST; i++) {
-			char s_name[14], l_name[VFAT_MAXLEN_BYTES];
-
-			l_name[0] = '\0';
-			if (dentptr->name[0] == DELETED_FLAG) {
-				dentptr++;
-				continue;
-			}
-			if ((dentptr->attr & ATTR_VOLUME)) {
-				if (vfat_enabled &&
-				    (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
-				    (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
-					prevcksum = ((dir_slot *)dentptr)->alias_checksum;
-					get_vfatname(mydata, curclust,
-						     get_dentfromdir_block,
-						     dentptr, l_name);
-					if (dols) {
-						int isdir;
-						char dirc;
-						int doit = 0;
-
-						isdir = (dentptr->attr & ATTR_DIR);
-
-						if (isdir) {
-							dirs++;
-							dirc = '/';
-							doit = 1;
-						} else {
-							dirc = ' ';
-							if (l_name[0] != 0) {
-								files++;
-								doit = 1;
-							}
-						}
-						if (doit) {
-							if (dirc == ' ') {
-								printf(" %8u   %s%c\n",
-								       FAT2CPU32(dentptr->size),
-									l_name,
-									dirc);
-							} else {
-								printf("            %s%c\n",
-									l_name,
-									dirc);
-							}
-						}
-						dentptr++;
-						continue;
-					}
-					debug("vfatname: |%s|\n", l_name);
-				} else {
-					/* Volume label or VFAT entry */
-					dentptr++;
-					continue;
-				}
-			}
-			if (dentptr->name[0] == 0) {
-				if (dols) {
-					printf("\n%d file(s), %d dir(s)\n\n",
-						files, dirs);
-				}
-				debug("Dentname == NULL - %d\n", i);
-				return NULL;
-			}
-			if (vfat_enabled) {
-				__u8 csum = mkcksum(dentptr->name, dentptr->ext);
-				if (dols && csum == prevcksum) {
-					prevcksum = 0xffff;
-					dentptr++;
-					continue;
-				}
-			}
-
-			get_name(dentptr, s_name);
-			if (dols) {
-				int isdir = (dentptr->attr & ATTR_DIR);
-				char dirc;
-				int doit = 0;
-
-				if (isdir) {
-					dirs++;
-					dirc = '/';
-					doit = 1;
-				} else {
-					dirc = ' ';
-					if (s_name[0] != 0) {
-						files++;
-						doit = 1;
-					}
-				}
-
-				if (doit) {
-					if (dirc == ' ') {
-						printf(" %8u   %s%c\n",
-						       FAT2CPU32(dentptr->size),
-							s_name, dirc);
-					} else {
-						printf("            %s%c\n",
-							s_name, dirc);
-					}
-				}
-
-				dentptr++;
-				continue;
-			}
-
-			if (strcmp(filename, s_name)
-			    && strcmp(filename, l_name)) {
-				debug("Mismatch: |%s|%s|\n", s_name, l_name);
-				dentptr++;
-				continue;
-			}
-
-			memcpy(retdent, dentptr, sizeof(dir_entry));
-
-			debug("DentName: %s", s_name);
-			debug(", start: 0x%x", START(dentptr));
-			debug(", size:  0x%x %s\n",
-			      FAT2CPU32(dentptr->size),
-			      (dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
-
-			return retdent;
-		}
-
-		curclust = get_fatent(mydata, curclust);
-		if (CHECK_CLUST(curclust, mydata->fatsize)) {
-			debug("curclust: 0x%x\n", curclust);
-			printf("Invalid FAT entry\n");
-			return NULL;
-		}
-	}
-
-	return NULL;
-}
+__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
+	__aligned(ARCH_DMA_MINALIGN);
 
 /*
  * Read boot sector and volume info from a FAT filesystem
@@ -879,374 +618,6 @@ static int get_fs_info(fsdata *mydata)
 	return 0;
 }
 
-__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
-	__aligned(ARCH_DMA_MINALIGN);
-
-int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
-		   loff_t maxsize, int dols, int dogetsize, loff_t *size)
-{
-	char fnamecopy[2048];
-	fsdata datablock;
-	fsdata *mydata = &datablock;
-	dir_entry *dentptr = NULL;
-	__u16 prevcksum = 0xffff;
-	char *subname = "";
-	__u32 cursect;
-	int idx, isdir = 0;
-	int files = 0, dirs = 0;
-	int ret = -1;
-	int firsttime;
-	__u32 root_cluster = 0;
-	__u32 read_blk;
-	int rootdir_size = 0;
-	int buffer_blk_cnt;
-	int do_read;
-	__u8 *dir_ptr;
-
-	if (get_fs_info(mydata))
-		return -1;
-
-	cursect = mydata->rootdir_sect;
-
-	/* "cwd" is always the root... */
-	while (ISDIRDELIM(*filename))
-		filename++;
-
-	/* Make a copy of the filename and convert it to lowercase */
-	strcpy(fnamecopy, filename);
-	downcase(fnamecopy);
-
-root_reparse:
-	if (*fnamecopy == '\0') {
-		if (!dols)
-			goto exit;
-
-		dols = LS_ROOT;
-	} else if ((idx = dirdelim(fnamecopy)) >= 0) {
-		isdir = 1;
-		fnamecopy[idx] = '\0';
-		subname = fnamecopy + idx + 1;
-
-		/* Handle multiple delimiters */
-		while (ISDIRDELIM(*subname))
-			subname++;
-	} else if (dols) {
-		isdir = 1;
-	}
-
-	buffer_blk_cnt = 0;
-	firsttime = 1;
-	while (1) {
-		int i;
-
-		if (mydata->fatsize == 32 || firsttime) {
-			dir_ptr = do_fat_read_at_block;
-			firsttime = 0;
-		} else {
-			/**
-			 * FAT16 sector buffer modification:
-			 * Each loop, the second buffered block is moved to
-			 * the buffer begin, and two next sectors are read
-			 * next to the previously moved one. So the sector
-			 * buffer keeps always 3 sectors for fat16.
-			 * And the current sector is the buffer second sector
-			 * beside the "firsttime" read, when it is the first one.
-			 *
-			 * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1]
-			 * n = computed root dir sector
-			 * loop |  cursect-1  | cursect    | cursect+1  |
-			 *   0  |  sector n+0 | sector n+1 | none       |
-			 *   1  |  none       | sector n+0 | sector n+1 |
-			 *   0  |  sector n+1 | sector n+2 | sector n+3 |
-			 *   1  |  sector n+3 | ...
-			*/
-			dir_ptr = (do_fat_read_at_block + mydata->sect_size);
-			memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size);
-		}
-
-		do_read = 1;
-
-		if (mydata->fatsize == 32 && buffer_blk_cnt)
-			do_read = 0;
-
-		if (do_read) {
-			read_blk = (mydata->fatsize == 32) ?
-				    mydata->clust_size : PREFETCH_BLOCKS;
-
-			debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
-				cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK);
-
-			if (disk_read(cursect, read_blk, dir_ptr) < 0) {
-				debug("Error: reading rootdir block\n");
-				goto exit;
-			}
-
-			dentptr = (dir_entry *)dir_ptr;
-		}
-
-		for (i = 0; i < DIRENTSPERBLOCK; i++) {
-			char s_name[14], l_name[VFAT_MAXLEN_BYTES];
-			__u8 csum;
-
-			l_name[0] = '\0';
-			if (dentptr->name[0] == DELETED_FLAG) {
-				dentptr++;
-				continue;
-			}
-
-			if (vfat_enabled)
-				csum = mkcksum(dentptr->name, dentptr->ext);
-
-			if (dentptr->attr & ATTR_VOLUME) {
-				if (vfat_enabled &&
-				    (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
-				    (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
-					prevcksum =
-						((dir_slot *)dentptr)->alias_checksum;
-
-					get_vfatname(mydata,
-						     root_cluster,
-						     dir_ptr,
-						     dentptr, l_name);
-
-					if (dols == LS_ROOT) {
-						char dirc;
-						int doit = 0;
-						int isdir =
-							(dentptr->attr & ATTR_DIR);
-
-						if (isdir) {
-							dirs++;
-							dirc = '/';
-							doit = 1;
-						} else {
-							dirc = ' ';
-							if (l_name[0] != 0) {
-								files++;
-								doit = 1;
-							}
-						}
-						if (doit) {
-							if (dirc == ' ') {
-								printf(" %8u   %s%c\n",
-								       FAT2CPU32(dentptr->size),
-									l_name,
-									dirc);
-							} else {
-								printf("            %s%c\n",
-									l_name,
-									dirc);
-							}
-						}
-						dentptr++;
-						continue;
-					}
-					debug("Rootvfatname: |%s|\n",
-					       l_name);
-				} else {
-					/* Volume label or VFAT entry */
-					dentptr++;
-					continue;
-				}
-			} else if (dentptr->name[0] == 0) {
-				debug("RootDentname == NULL - %d\n", i);
-				if (dols == LS_ROOT) {
-					printf("\n%d file(s), %d dir(s)\n\n",
-						files, dirs);
-					ret = 0;
-				}
-				goto exit;
-			}
-			else if (vfat_enabled &&
-				 dols == LS_ROOT && csum == prevcksum) {
-				prevcksum = 0xffff;
-				dentptr++;
-				continue;
-			}
-
-			get_name(dentptr, s_name);
-
-			if (dols == LS_ROOT) {
-				int isdir = (dentptr->attr & ATTR_DIR);
-				char dirc;
-				int doit = 0;
-
-				if (isdir) {
-					dirc = '/';
-					if (s_name[0] != 0) {
-						dirs++;
-						doit = 1;
-					}
-				} else {
-					dirc = ' ';
-					if (s_name[0] != 0) {
-						files++;
-						doit = 1;
-					}
-				}
-				if (doit) {
-					if (dirc == ' ') {
-						printf(" %8u   %s%c\n",
-						       FAT2CPU32(dentptr->size),
-							s_name, dirc);
-					} else {
-						printf("            %s%c\n",
-							s_name, dirc);
-					}
-				}
-				dentptr++;
-				continue;
-			}
-
-			if (strcmp(fnamecopy, s_name)
-			    && strcmp(fnamecopy, l_name)) {
-				debug("RootMismatch: |%s|%s|\n", s_name,
-				       l_name);
-				dentptr++;
-				continue;
-			}
-
-			if (isdir && !(dentptr->attr & ATTR_DIR))
-				goto exit;
-
-			debug("RootName: %s", s_name);
-			debug(", start: 0x%x", START(dentptr));
-			debug(", size:  0x%x %s\n",
-			       FAT2CPU32(dentptr->size),
-			       isdir ? "(DIR)" : "");
-
-			goto rootdir_done;	/* We got a match */
-		}
-		debug("END LOOP: buffer_blk_cnt=%d   clust_size=%d\n", buffer_blk_cnt,
-		       mydata->clust_size);
-
-		/*
-		 * On FAT32 we must fetch the FAT entries for the next
-		 * root directory clusters when a cluster has been
-		 * completely processed.
-		 */
-		++buffer_blk_cnt;
-		int rootdir_end = 0;
-		if (mydata->fatsize == 32) {
-			if (buffer_blk_cnt == mydata->clust_size) {
-				int nxtsect = 0;
-				int nxt_clust = 0;
-
-				nxt_clust = get_fatent(mydata, root_cluster);
-				rootdir_end = CHECK_CLUST(nxt_clust, 32);
-
-				nxtsect = mydata->data_begin +
-					(nxt_clust * mydata->clust_size);
-
-				root_cluster = nxt_clust;
-
-				cursect = nxtsect;
-				buffer_blk_cnt = 0;
-			}
-		} else {
-			if (buffer_blk_cnt == PREFETCH_BLOCKS)
-				buffer_blk_cnt = 0;
-
-			rootdir_end = (++cursect - mydata->rootdir_sect >=
-				       rootdir_size);
-		}
-
-		/* If end of rootdir reached */
-		if (rootdir_end) {
-			if (dols == LS_ROOT) {
-				printf("\n%d file(s), %d dir(s)\n\n",
-				       files, dirs);
-				*size = 0;
-			}
-			goto exit;
-		}
-	}
-rootdir_done:
-
-	firsttime = 1;
-
-	while (isdir) {
-		int startsect = mydata->data_begin
-			+ START(dentptr) * mydata->clust_size;
-		dir_entry dent;
-		char *nextname = NULL;
-
-		dent = *dentptr;
-		dentptr = &dent;
-
-		idx = dirdelim(subname);
-
-		if (idx >= 0) {
-			subname[idx] = '\0';
-			nextname = subname + idx + 1;
-			/* Handle multiple delimiters */
-			while (ISDIRDELIM(*nextname))
-				nextname++;
-			if (dols && *nextname == '\0')
-				firsttime = 0;
-		} else {
-			if (dols && firsttime) {
-				firsttime = 0;
-			} else {
-				isdir = 0;
-			}
-		}
-
-		if (get_dentfromdir(mydata, startsect, subname, dentptr,
-				     isdir ? 0 : dols) == NULL) {
-			if (dols && !isdir)
-				*size = 0;
-			goto exit;
-		}
-
-		if (isdir && !(dentptr->attr & ATTR_DIR))
-			goto exit;
-
-		/*
-		 * If we are looking for a directory, and found a directory
-		 * type entry, and the entry is for the root directory (as
-		 * denoted by a cluster number of 0), jump back to the start
-		 * of the function, since at least on FAT12/16, the root dir
-		 * lives in a hard-coded location and needs special handling
-		 * to parse, rather than simply following the cluster linked
-		 * list in the FAT, like other directories.
-		 */
-		if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) {
-			/*
-			 * Modify the filename to remove the prefix that gets
-			 * back to the root directory, so the initial root dir
-			 * parsing code can continue from where we are without
-			 * confusion.
-			 */
-			strcpy(fnamecopy, nextname ?: "");
-			/*
-			 * Set up state the same way as the function does when
-			 * first started. This is required for the root dir
-			 * parsing code operates in its expected environment.
-			 */
-			subname = "";
-			cursect = mydata->rootdir_sect;
-			isdir = 0;
-			goto root_reparse;
-		}
-
-		if (idx >= 0)
-			subname = nextname;
-	}
-
-	if (dogetsize) {
-		*size = FAT2CPU32(dentptr->size);
-		ret = 0;
-	} else {
-		ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size);
-	}
-	debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size);
-
-exit:
-	free(mydata->fatbuf);
-	return ret;
-}
-
 
 /*
  * Directory iterator, to simplify filesystem traversal
@@ -1595,12 +966,6 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
 	return -ENOENT;
 }
 
-int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols,
-		loff_t *actread)
-{
-	return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread);
-}
-
 int file_fat_detectfs(void)
 {
 	boot_sector bs;
@@ -1665,31 +1030,96 @@ int file_fat_detectfs(void)
 
 int file_fat_ls(const char *dir)
 {
-	loff_t size;
+	fsdata fsdata;
+	fat_itr itrblock, *itr = &itrblock;
+	int files = 0, dirs = 0;
+	int ret;
+
+	ret = fat_itr_root(itr, &fsdata);
+	if (ret)
+		return ret;
+
+	ret = fat_itr_resolve(itr, dir, TYPE_DIR);
+	if (ret)
+		return ret;
+
+	while (fat_itr_next(itr)) {
+		if (fat_itr_isdir(itr)) {
+			printf("            %s/\n", itr->name);
+			dirs++;
+		} else {
+			printf(" %8u   %s\n",
+			       FAT2CPU32(itr->dent->size),
+			       itr->name);
+			files++;
+		}
+	}
 
-	return do_fat_read(dir, NULL, 0, LS_YES, &size);
+	printf("\n%d file(s), %d dir(s)\n\n", files, dirs);
+
+	return 0;
 }
 
 int fat_exists(const char *filename)
 {
+	fsdata fsdata;
+	fat_itr itrblock, *itr = &itrblock;
 	int ret;
-	loff_t size;
 
-	ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size);
+	ret = fat_itr_root(itr, &fsdata);
+	if (ret)
+		return 0;
+
+	ret = fat_itr_resolve(itr, filename, TYPE_ANY);
 	return ret == 0;
 }
 
 int fat_size(const char *filename, loff_t *size)
 {
-	return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size);
+	fsdata fsdata;
+	fat_itr itrblock, *itr = &itrblock;
+	int ret;
+
+	ret = fat_itr_root(itr, &fsdata);
+	if (ret)
+		return ret;
+
+	ret = fat_itr_resolve(itr, filename, TYPE_FILE);
+	if (ret) {
+		/*
+		 * Directories don't have size, but fs_size() is not
+		 * expected to fail if passed a directory path:
+		 */
+		fat_itr_root(itr, &fsdata);
+		if (!fat_itr_resolve(itr, filename, TYPE_DIR)) {
+			*size = 0;
+			return 0;
+		}
+		return ret;
+	}
+
+	*size = FAT2CPU32(itr->dent->size);
+
+	return 0;
 }
 
 int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
 		     loff_t maxsize, loff_t *actread)
 {
+	fsdata fsdata;
+	fat_itr itrblock, *itr = &itrblock;
+	int ret;
+
+	ret = fat_itr_root(itr, &fsdata);
+	if (ret)
+		return ret;
+
+	ret = fat_itr_resolve(itr, filename, TYPE_FILE);
+	if (ret)
+		return ret;
+
 	printf("reading %s\n", filename);
-	return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0,
-			      actread);
+	return get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread);
 }
 
 int file_fat_read(const char *filename, void *buffer, int maxsize)
include/fat.h +0 -6
index 21bb6666cf..18d8981c48 100644
@@ -58,12 +58,6 @@
  */
 #define LAST_LONG_ENTRY_MASK	0x40
 
-/* Flags telling whether we should read a file or list a directory */
-#define LS_NO		0
-#define LS_YES		1
-#define LS_DIR		1
-#define LS_ROOT		2
-
 #define ISDIRDELIM(c)	((c) == '/' || (c) == '\\')
 
 #define FSTYPE_NONE	(-1)
Signature · 1 line
2.13.5
#7 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

In reply to Rob Clark
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/c6a16238/attachment.sig>
#8 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 11 lines · Tom Rini
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

According to git bisect, this patch seems to break the booting of am3517_evm

It just displays:

U-Boot SPL 2017.09-00135-g8eafae2 (Sep 16 2017 - 15:23:16) Trying to boot from MMC1

Then hangs.

It does, however the same patch boots just fine on omap3_logic_defconfig which is an OMAP3630/DM3730 board.

da850evm_defconfig (OMAP-L138) is also booting just fine.

I'm going to investigate it further to see why just 1/3 boards seems impacted.

adam

Quoted 9 lines

--
Tom

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://lists.denx.de/listinfo/u-boot

author
#9 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 20 lines · Adam Ford
Quoted 11 lines · Tom Rini
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

According to git bisect, this patch seems to break the booting of am3517_evm

It just displays:

U-Boot SPL 2017.09-00135-g8eafae2 (Sep 16 2017 - 15:23:16) Trying to boot from MMC1

Quoted 9 lines

Then hangs.

It does, however the same patch boots just fine on omap3_logic_defconfig which is an OMAP3630/DM3730 board.

da850evm_defconfig (OMAP-L138) is also booting just fine.

I'm going to investigate it further to see why just 1/3 boards seems impacted.

Tom reported a similar fail.. although I am failing to reproduce it in sandbox w/ a copy of his partition, so maybe it is somehow hw specific? If you could, debug logs w/
https://hastebin.com/raw/fijazebiso applied in before/after case would be useful.. maybe I could spot something from that?

BR,
-R

#10 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 28 lines · Rob Clark
Quoted 27 lines · Adam Ford
Quoted 11 lines · Tom Rini
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

According to git bisect, this patch seems to break the booting of am3517_evm

It just displays:

U-Boot SPL 2017.09-00135-g8eafae2 (Sep 16 2017 - 15:23:16) Trying to boot from MMC1

Then hangs.

It does, however the same patch boots just fine on omap3_logic_defconfig which is an OMAP3630/DM3730 board.

da850evm_defconfig (OMAP-L138) is also booting just fine.

Quoted 9 lines
Quoted 2 lines

I'm going to investigate it further to see why just 1/3 boards seems impacted.

Tom reported a similar fail.. although I am failing to reproduce it in sandbox w/ a copy of his partition, so maybe it is somehow hw specific? If you could, debug logs w/
https://hastebin.com/raw/fijazebiso applied in before/after case would be useful.. maybe I could spot something from that?

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

Could there a be some memory overflow somewhere?

Adding the debug to the last working commit, yielded the following:

U-Boot SPL 2017.09-00134-ge71f88d-dirty (Sep 17 2017 - 06:03:28) Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes
gc - clustnum: 152, startsect: 1633
Size: 538376, got: u
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes

I truncated it, because after that, it seems to just be showing entries and offsets over and over again.

adam

Quoted 2 lines

BR,
-R

author
#11 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 81 lines · Adam Ford
Quoted 28 lines · Rob Clark
Quoted 27 lines · Adam Ford
Quoted 11 lines · Tom Rini
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

According to git bisect, this patch seems to break the booting of am3517_evm

It just displays:

U-Boot SPL 2017.09-00135-g8eafae2 (Sep 16 2017 - 15:23:16) Trying to boot from MMC1

Then hangs.

It does, however the same patch boots just fine on omap3_logic_defconfig which is an OMAP3630/DM3730 board.

da850evm_defconfig (OMAP-L138) is also booting just fine.

Quoted 9 lines
Quoted 2 lines

I'm going to investigate it further to see why just 1/3 boards seems impacted.

Tom reported a similar fail.. although I am failing to reproduce it in sandbox w/ a copy of his partition, so maybe it is somehow hw specific? If you could, debug logs w/
https://hastebin.com/raw/fijazebiso applied in before/after case would be useful.. maybe I could spot something from that?

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

Could there a be some memory overflow somewhere?

Adding the debug to the last working commit, yielded the following:

U-Boot SPL 2017.09-00134-ge71f88d-dirty (Sep 17 2017 - 06:03:28) Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes
gc - clustnum: 152, startsect: 1633
Size: 538376, got: u
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes

Quoted 3 lines

I truncated it, because after that, it seems to just be showing entries and offsets over and over again.

Thanks, this first part is what I was looking for.

Not sure why DEBUG would make it hang on master. I don't know much about spl, but is there a way you can get it to just do 'ls mmc 1:1' instead of loading u-boot.img? ls should give me the same information about the partition, without so many repeating entries/offsets. Alternately, is it possible to boot w/ old spl image but new u-boot.img to debug this once we get into main u-boot image??

BR,
-R

author
#12 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 86 lines · Rob Clark
Quoted 81 lines · Adam Ford
Quoted 28 lines · Rob Clark
Quoted 27 lines · Adam Ford
Quoted 11 lines · Tom Rini
Quoted 5 lines · Rob Clark

And drop a whole lot of ugly code!

Applied to u-boot/master, thanks!

According to git bisect, this patch seems to break the booting of am3517_evm

It just displays:

U-Boot SPL 2017.09-00135-g8eafae2 (Sep 16 2017 - 15:23:16) Trying to boot from MMC1

Then hangs.

It does, however the same patch boots just fine on omap3_logic_defconfig which is an OMAP3630/DM3730 board.

da850evm_defconfig (OMAP-L138) is also booting just fine.

Quoted 9 lines
Quoted 2 lines

I'm going to investigate it further to see why just 1/3 boards seems impacted.

Tom reported a similar fail.. although I am failing to reproduce it in sandbox w/ a copy of his partition, so maybe it is somehow hw specific? If you could, debug logs w/
https://hastebin.com/raw/fijazebiso applied in before/after case would be useful.. maybe I could spot something from that?

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

Could there a be some memory overflow somewhere?

Adding the debug to the last working commit, yielded the following:

U-Boot SPL 2017.09-00134-ge71f88d-dirty (Sep 17 2017 - 06:03:28) Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes
gc - clustnum: 152, startsect: 1633
Size: 538376, got: u
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=d
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x98, size: 0x83708
Filesize: u bytes
u bytes

Quoted 3 lines

I truncated it, because after that, it seems to just be showing entries and offsets over and over again.

Quoted 8 lines

Thanks, this first part is what I was looking for.

Not sure why DEBUG would make it hang on master. I don't know much about spl, but is there a way you can get it to just do 'ls mmc 1:1' instead of loading u-boot.img? ls should give me the same information about the partition, without so many repeating entries/offsets. Alternately, is it possible to boot w/ old spl image but new u-boot.img to debug this once we get into main u-boot image??

I suppose another benefit if it is possible to use old spl and new u-boot.img is the presumably u-boot.img isn't using TINY_PRINTF so the debug prints about the partition parameters would be more complete..

BR,
-R

author
#13 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

In reply to Adam Ford
Quoted 10 lines · Adam Ford

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

hmm, one thing I noticed in doc/README.SPL:

"When building SPL with DEBUG set you may also need to set CONFIG_PANIC_HANG as in most cases do_reset is not defined within SPL."

not sure if that would help.

Also, it has a section about estimating stack usage.. not sure if this implies that stack size is constrained in spl? If so, maybe that is related. The new directory iterators do move the buffer for current block of dir_entry's to the stack. Reducing CONFIG_FS_FAT_MAX_CLUSTSIZE might help.

BR,
-R

#14 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 17 lines · Rob Clark
Quoted 10 lines · Adam Ford

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

hmm, one thing I noticed in doc/README.SPL:

"When building SPL with DEBUG set you may also need to set CONFIG_PANIC_HANG as in most cases do_reset is not defined within SPL."

Quoted 7 lines

not sure if that would help.

Also, it has a section about estimating stack usage.. not sure if this implies that stack size is constrained in spl? If so, maybe that is related. The new directory iterators do move the buffer for current block of dir_entry's to the stack. Reducing CONFIG_FS_FAT_MAX_CLUSTSIZE might help.

Yes, in SPL we don't require stack being in SDRAM and unless SPL_STACK_R is set we have a very limited stack available. And that looks to be the common thread between functional and non-functional platforms. In the case of what Adam and I both have, we could move to SPL_STACK_R easily enough. What needs to be done next 'tho would be to see if making SPL_FAT_SUPPORT depend on SPL_STACK_R, migrating the various TI platforms (and possibly others) that could butdon't use SPL_STACK_R, and seeing if we have platforms that have now lost FAT support.

Or, how hard would it be to make that code not use the stack so much?

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170917/d0f21981/attachment.sig>
#15 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

In reply to Rob Clark
Quoted 6 lines · Rob Clark
Quoted 5 lines · Adam Ford

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

Quoted 6 lines
Quoted 5 lines

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

With the TINY_PRINTF disabled (except in SPL), the log looks better:

Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes
64 bytes
gc - clustnum: 18, startsect: 561
Size: 538376, got: 64
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes

Quoted 7 lines

hmm, one thing I noticed in doc/README.SPL:

"When building SPL with DEBUG set you may also need to set CONFIG_PANIC_HANG as in most cases do_reset is not defined within SPL."

not sure if that would help.

I did try your experiment with keeping the working SPL and using the newer u-boot.img file and that worked, so I am guessing it's probably related to tight memory in SPL.
I looked up the mapping in doc/SPL/README.omap3 and it shows:

0x40200800 - 0x4020BBFF: Area for SPL text, data and rodata 0x4020E000 - 0x4020FFFC: Area for the SPL stack. 0x80000000 - 0x8007FFFF: Area for the SPL BSS. 0x80100000: CONFIG_SYS_TEXT_BASE of U-Boot 0x80208000 - 0x80307FFF: malloc() pool available to SPL.

For this board, CONFIG_SYS_SPL_MALLOC_SIZE is set to 0x100000

I don't know if any of this is helpful information to you or not.

Quoted 5 lines

Also, it has a section about estimating stack usage.. not sure if this implies that stack size is constrained in spl? If so, maybe that is related. The new directory iterators do move the buffer for current block of dir_entry's to the stack. Reducing CONFIG_FS_FAT_MAX_CLUSTSIZE might help.

Any recommendations on how small this can go and still operate reliably? I don't want to just arbitrarily choose something.

Quoted 3 lines

BR,
-R

adam

author
#16 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 64 lines · Adam Ford
Quoted 6 lines · Rob Clark
Quoted 5 lines · Adam Ford

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

Quoted 6 lines
Quoted 5 lines

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

With the TINY_PRINTF disabled (except in SPL), the log looks better:

Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes
64 bytes
gc - clustnum: 18, startsect: 561
Size: 538376, got: 64
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes

Quoted 7 lines

hmm, one thing I noticed in doc/README.SPL:

"When building SPL with DEBUG set you may also need to set CONFIG_PANIC_HANG as in most cases do_reset is not defined within SPL."

not sure if that would help.

I did try your experiment with keeping the working SPL and using the newer u-boot.img file and that worked, so I am guessing it's probably related to tight memory in SPL.
I looked up the mapping in doc/SPL/README.omap3 and it shows:

0x40200800 - 0x4020BBFF: Area for SPL text, data and rodata 0x4020E000 - 0x4020FFFC: Area for the SPL stack. 0x80000000 - 0x8007FFFF: Area for the SPL BSS. 0x80100000: CONFIG_SYS_TEXT_BASE of U-Boot 0x80208000 - 0x80307FFF: malloc() pool available to SPL.

Quoted 3 lines

For this board, CONFIG_SYS_SPL_MALLOC_SIZE is set to 0x100000

I don't know if any of this is helpful information to you or not.

I think we narrowed it down to stack usage.. Tom tested the "please test" patch I just sent and it works for him.

If reducing SPL_MALLOC_SIZE increases available stack size, that might also work. But I think for next release we can just go with my patch that moves itrblock off the stack.

Quoted 8 lines
Quoted 5 lines

Also, it has a section about estimating stack usage.. not sure if this implies that stack size is constrained in spl? If so, maybe that is related. The new directory iterators do move the buffer for current block of dir_entry's to the stack. Reducing CONFIG_FS_FAT_MAX_CLUSTSIZE might help.

Any recommendations on how small this can go and still operate reliably? I don't want to just arbitrarily choose something.

Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16

So I think 512 * 8 = 4096 would work for your filesys.. what I'm not entirely sure is what range of sector sizes and cluster sizes are possible. 64k seems *way* too much. Maybe in the end I should switch to malloc() so we can allocate just what is needed.

I'll give it some thought for my next batch of fs/fat work.. but suggestions welcome.

BR,
-R

#17 lore raw

PATCH v3 3/9 fat/fs: convert to directory iterators

Quoted 89 lines · Rob Clark
Quoted 64 lines · Adam Ford
Quoted 6 lines · Rob Clark
Quoted 5 lines · Adam Ford

Adding the debug to master made no difference. No debug messages appeared. Interestingly enough, some junk appeard, and the name of U-Boot name wasn't correctly displayed:

Quoted 6 lines
Quoted 5 lines

**Sș017.09-00178-g08cebee-dirty (Sep 17 2017 - 06:01:07) Trying to boot from MMC1

(hang)

With the TINY_PRINTF disabled (except in SPL), the log looks better:

Trying to boot from MMC1
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes
64 bytes
gc - clustnum: 18, startsect: 561
Size: 538376, got: 64
reading u-boot.img
VFAT Support enabled
FAT16, fat_sect: 1, fatlength: 200
Rootdir begins at cluster: 536870910, sector: 401, offset: 32200 Data begins at: 417
Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16
RootMismatch: |mlo||
Rootvfatname: |u-boot.img|
RootName: u-boot.img, start: 0x12, size: 0x83708
Filesize: 538376 bytes

Quoted 7 lines

hmm, one thing I noticed in doc/README.SPL:

"When building SPL with DEBUG set you may also need to set CONFIG_PANIC_HANG as in most cases do_reset is not defined within SPL."

not sure if that would help.

I did try your experiment with keeping the working SPL and using the newer u-boot.img file and that worked, so I am guessing it's probably related to tight memory in SPL.
I looked up the mapping in doc/SPL/README.omap3 and it shows:

0x40200800 - 0x4020BBFF: Area for SPL text, data and rodata 0x4020E000 - 0x4020FFFC: Area for the SPL stack. 0x80000000 - 0x8007FFFF: Area for the SPL BSS. 0x80100000: CONFIG_SYS_TEXT_BASE of U-Boot 0x80208000 - 0x80307FFF: malloc() pool available to SPL.

Quoted 3 lines

For this board, CONFIG_SYS_SPL_MALLOC_SIZE is set to 0x100000

I don't know if any of this is helpful information to you or not.

I think we narrowed it down to stack usage.. Tom tested the "please test" patch I just sent and it works for him.

If reducing SPL_MALLOC_SIZE increases available stack size, that might also work. But I think for next release we can just go with my patch that moves itrblock off the stack.

Quoted 8 lines
Quoted 5 lines

Also, it has a section about estimating stack usage.. not sure if this implies that stack size is constrained in spl? If so, maybe that is related. The new directory iterators do move the buffer for current block of dir_entry's to the stack. Reducing CONFIG_FS_FAT_MAX_CLUSTSIZE might help.

Any recommendations on how small this can go and still operate reliably? I don't want to just arbitrarily choose something.

Sector size: 512, cluster size: 8
FAT read(sect=401, cnt:2), clust_size=8, DIRENTSPERBLOCK=16

Quoted 8 lines

So I think 512 * 8 = 4096 would work for your filesys.. what I'm not entirely sure is what range of sector sizes and cluster sizes are possible. 64k seems *way* too much. Maybe in the end I should switch to malloc() so we can allocate just what is needed.

I'll give it some thought for my next batch of fs/fat work.. but suggestions welcome.

When I wrote that, I didn't see either Tom's comments or you updated patch yet, but you can go ahead and add my tested-by because I'm satisfied with that.

adam

Quoted 2 lines

BR,
-R

author
#18 lore raw

PATCH v3 4/9 fs: add fs_readdir()

In reply to Rob Clark

Needed to support efi file protocol. The fallback.efi loader wants to be able to read the contents of the /EFI directory to find an OS to boot.

Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other fs APIs, this is stateful (ie. state is held in the FS_DIR "directory stream"), to avoid re-traversing of the directory structure at each step. The directory stream must be released with closedir() when it is no longer needed.

---
 disk/part.c    |  31 ++++++++++-------
 fs/fs.c        | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/fs.h   |  67 +++++++++++++++++++++++++++++++++++++
 include/part.h |   9 +++++
 4 files changed, 199 insertions(+), 12 deletions(-)
disk/part.c +19 -12
index c67fdacc79..aa9183d696 100644
@@ -331,6 +331,24 @@ int part_get_info(struct blk_desc *dev_desc, int part,
 	return -1;
 }
 
+int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
+{
+	info->start = 0;
+	info->size = dev_desc->lba;
+	info->blksz = dev_desc->blksz;
+	info->bootable = 0;
+	strcpy((char *)info->type, BOOT_PART_TYPE);
+	strcpy((char *)info->name, "Whole Disk");
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+	info->uuid[0] = 0;
+#endif
+#ifdef CONFIG_PARTITION_TYPE_GUID
+	info->type_guid[0] = 0;
+#endif
+
+	return 0;
+}
+
 int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
 			  struct blk_desc **dev_desc)
 {
@@ -523,18 +541,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 
 		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 
-		info->start = 0;
-		info->size = (*dev_desc)->lba;
-		info->blksz = (*dev_desc)->blksz;
-		info->bootable = 0;
-		strcpy((char *)info->type, BOOT_PART_TYPE);
-		strcpy((char *)info->name, "Whole Disk");
-#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-		info->uuid[0] = 0;
-#endif
-#ifdef CONFIG_PARTITION_TYPE_GUID
-		info->type_guid[0] = 0;
-#endif
+		part_get_info_whole_disk(*dev_desc, info);
 
 		ret = 0;
 		goto cleanup;
fs/fs.c +104 -0

164 lines not on this page · raw message

include/fs.h +67 -0

79 lines not on this page · raw message

include/part.h +9 -0
index 0d5c99836b..86117a7ce5 100644
@@ -98,6 +98,12 @@ int host_get_dev_err(int dev, struct blk_desc **blk_devp);
 
 /* disk/part.c */
 int part_get_info(struct blk_desc *dev_desc, int part, disk_partition_t *info);
+/**
+ * part_get_info_whole_disk() - get partition info for the special case of
+ * a partition occupying the entire disk.
+ */
+int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info);
+
 void part_print(struct blk_desc *dev_desc);
 void part_init(struct blk_desc *dev_desc);
 void dev_print(struct blk_desc *dev_desc);
@@ -203,6 +209,9 @@ static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }
 
 static inline int part_get_info(struct blk_desc *dev_desc, int part,
 				disk_partition_t *info) { return -1; }
+static inline int part_get_info_whole_disk(struct blk_desc *dev_desc,
+					   disk_partition_t *info)
+{ return -1; }
 static inline void part_print(struct blk_desc *dev_desc) {}
 static inline void part_init(struct blk_desc *dev_desc) {}
 static inline void dev_print(struct blk_desc *dev_desc) {}
Signature · 1 line
2.13.5
#19 lore raw

PATCH v3 4/9 fs: add fs_readdir()

Quoted 10 lines · Rob Clark

Needed to support efi file protocol. The fallback.efi loader wants to be able to read the contents of the /EFI directory to find an OS to boot.

Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other fs APIs, this is stateful (ie. state is held in the FS_DIR "directory stream"), to avoid re-traversing of the directory structure at each step. The directory stream must be released with closedir() when it is no longer needed.

Quoted 8 lines
---
 disk/part.c    |  31 ++++++++++-------
 fs/fs.c        | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/fs.h   |  67 +++++++++++++++++++++++++++++++++++++
 include/part.h |   9 +++++
 4 files changed, 199 insertions(+), 12 deletions(-)

I do think it is useful to see a change log on each patch.

#20 lore raw

PATCH v3 4/9 fs: add fs_readdir()

In reply to Rob Clark
Quoted 10 lines · Rob Clark

Needed to support efi file protocol. The fallback.efi loader wants to be able to read the contents of the /EFI directory to find an OS to boot.

Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other fs APIs, this is stateful (ie. state is held in the FS_DIR "directory stream"), to avoid re-traversing of the directory structure at each step. The directory stream must be released with closedir() when it is no longer needed.

Quoted 3 lines

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/5c52e9bd/attachment.sig>
author
#21 lore raw

PATCH v3 5/9 fs/fat: implement opendir/readdir/closedir

In reply to Rob Clark

Implement the readdir interface using the directory iterators.

---
 fs/fat/fat.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
fs/fat/fat.c +61 -0
index bbba7947ee..82ddb7eab1 100644
@@ -14,6 +14,7 @@
 #include <config.h>
 #include <exports.h>
 #include <fat.h>
+#include <fs.h>
 #include <asm/byteorder.h>
 #include <part.h>
 #include <malloc.h>
@@ -1146,6 +1147,66 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
 	return ret;
 }
 
+typedef struct {
+	struct fs_dir_stream parent;
+	struct fs_dirent dirent;
+	fsdata fsdata;
+	fat_itr itr;
+} fat_dir;
+
+int fat_opendir(const char *filename, struct fs_dir_stream **dirsp)
+{
+	fat_dir *dir = malloc(sizeof(*dir));
+	int ret;
+
+	if (!dir)
+		return -ENOMEM;
+
+	ret = fat_itr_root(&dir->itr, &dir->fsdata);
+	if (ret)
+		goto fail;
+
+	ret = fat_itr_resolve(&dir->itr, filename, TYPE_DIR);
+	if (ret)
+		goto fail;
+
+	*dirsp = (struct fs_dir_stream *)dir;
+	return 0;
+
+fail:
+	free(dir);
+	return ret;
+}
+
+int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp)
+{
+	fat_dir *dir = (fat_dir *)dirs;
+	struct fs_dirent *dent = &dir->dirent;
+
+	if (!fat_itr_next(&dir->itr))
+		return -ENOENT;
+
+	memset(dent, 0, sizeof(*dent));
+	strcpy(dent->name, dir->itr.name);
+
+	if (fat_itr_isdir(&dir->itr)) {
+		dent->type = FS_DT_DIR;
+	} else {
+		dent->type = FS_DT_REG;
+		dent->size = FAT2CPU32(dir->itr.dent->size);
+	}
+
+	*dentp = dent;
+
+	return 0;
+}
+
+void fat_closedir(struct fs_dir_stream *dirs)
+{
+	fat_dir *dir = (fat_dir *)dirs;
+	free(dir);
+}
+
 void fat_close(void)
 {
 }
Signature · 1 line
2.13.5
#22 lore raw

PATCH v3 5/9 fs/fat: implement opendir/readdir/closedir

Quoted 7 lines · Rob Clark

Implement the readdir interface using the directory iterators.

---
 fs/fat/fat.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

But I still feel unconvinced that you need to add the typedef.

#23 lore raw

PATCH v3 5/9 fs/fat: implement opendir/readdir/closedir

In reply to Rob Clark
Quoted 5 lines · Rob Clark

Implement the readdir interface using the directory iterators.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/dc75005d/attachment.sig>
author
#24 lore raw

PATCH v3 6/9 fat/fs: remove a bunch of dead code

In reply to Rob Clark

Spotted by chance, when trying to remove file_fat_ls(), I noticed there were some dead users of the API.

---
 fs/fat/Makefile |   4 --
 fs/fat/file.c   | 183 --------------------------------------------------------
 include/fat.h   |  20 -------
 3 files changed, 207 deletions(-)
 delete mode 100644 fs/fat/file.c
fs/fat/Makefile +0 -4
index b60e8486c4..3e2a6b01a8 100644
@@ -5,7 +5,3 @@
 
 obj-$(CONFIG_FS_FAT)	:= fat.o
 obj-$(CONFIG_FAT_WRITE):= fat_write.o
-
-ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_FS_FAT)	+= file.o
-endif
fs/fat/file.c deleted +0 -183

183 lines not on this page · raw message

include/fat.h +0 -20
index 18d8981c48..b255ce5337 100644
@@ -178,25 +178,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
 	return fsdata->data_begin + clust * fsdata->clust_size;
 }
 
-typedef int	(file_detectfs_func)(void);
-typedef int	(file_ls_func)(const char *dir);
-typedef int	(file_read_func)(const char *filename, void *buffer,
-				 int maxsize);
-
-struct filesystem {
-	file_detectfs_func	*detect;
-	file_ls_func		*ls;
-	file_read_func		*read;
-	const char		name[12];
-};
-
-/* FAT tables */
-file_detectfs_func	file_fat_detectfs;
-file_ls_func		file_fat_ls;
-file_read_func		file_fat_read;
-
-/* Currently this doesn't check if the dir exists or is valid... */
-int file_cd(const char *path);
 int file_fat_detectfs(void);
 int file_fat_ls(const char *dir);
 int fat_exists(const char *filename);
@@ -204,7 +185,6 @@ int fat_size(const char *filename, loff_t *size);
 int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
 		     loff_t maxsize, loff_t *actread);
 int file_fat_read(const char *filename, void *buffer, int maxsize);
-const char *file_getfsname(int idx);
 int fat_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info);
 int fat_register_device(struct blk_desc *dev_desc, int part_no);
 
Signature · 1 line
2.13.5
#25 lore raw

PATCH v3 6/9 fat/fs: remove a bunch of dead code

Quoted 6 lines · Rob Clark

Spotted by chance, when trying to remove file_fat_ls(), I noticed there were some dead users of the API.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/56288c2f/attachment.sig>
author
#26 lore raw

PATCH v3 7/9 fat/fs: move ls to generic implementation

In reply to Rob Clark

Add a generic implementation of 'ls' using opendir/readdir/closedir, and replace fat's custom implementation. Other filesystems should move to the generic implementation after they add opendir/readdir/closedir support.

---
 fs/fat/fat.c  | 32 --------------------------------
 fs/fs.c       | 35 +++++++++++++++++++++++++++++++++--
 include/fat.h |  5 ++++-
 3 files changed, 37 insertions(+), 35 deletions(-)
fs/fat/fat.c +0 -32
index 82ddb7eab1..c951d84f57 100644
@@ -1029,38 +1029,6 @@ int file_fat_detectfs(void)
 	return 0;
 }
 
-int file_fat_ls(const char *dir)
-{
-	fsdata fsdata;
-	fat_itr itrblock, *itr = &itrblock;
-	int files = 0, dirs = 0;
-	int ret;
-
-	ret = fat_itr_root(itr, &fsdata);
-	if (ret)
-		return ret;
-
-	ret = fat_itr_resolve(itr, dir, TYPE_DIR);
-	if (ret)
-		return ret;
-
-	while (fat_itr_next(itr)) {
-		if (fat_itr_isdir(itr)) {
-			printf("            %s/\n", itr->name);
-			dirs++;
-		} else {
-			printf(" %8u   %s\n",
-			       FAT2CPU32(itr->dent->size),
-			       itr->name);
-			files++;
-		}
-	}
-
-	printf("\n%d file(s), %d dir(s)\n\n", files, dirs);
-
-	return 0;
-}
-
 int fat_exists(const char *filename)
 {
 	fsdata fsdata;
fs/fs.c +33 -2
index fc0c953fcb..3481229aa6 100644
@@ -37,6 +37,35 @@ static inline int fs_ls_unsupported(const char *dirname)
 	return -1;
 }
 
+/* generic implementation of ls in terms of opendir/readdir/closedir */
+__maybe_unused
+static int fs_ls_generic(const char *dirname)
+{
+	struct fs_dir_stream *dirs;
+	struct fs_dirent *dent;
+	int nfiles = 0, ndirs = 0;
+
+	dirs = fs_opendir(dirname);
+	if (!dirs)
+		return -errno;
+
+	while ((dent = fs_readdir(dirs))) {
+		if (dent->type == FS_DT_DIR) {
+			printf("            %s/\n", dent->name);
+			ndirs++;
+		} else {
+			printf(" %8lld   %s\n", dent->size, dent->name);
+			nfiles++;
+		}
+	}
+
+	fs_closedir(dirs);
+
+	printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
+
+	return 0;
+}
+
 static inline int fs_exists_unsupported(const char *filename)
 {
 	return 0;
@@ -123,7 +152,7 @@ static struct fstype_info fstypes[] = {
 		.null_dev_desc_ok = false,
 		.probe = fat_set_blk_dev,
 		.close = fat_close,
-		.ls = file_fat_ls,
+		.ls = fs_ls_generic,
 		.exists = fat_exists,
 		.size = fat_size,
 		.read = fat_read_file,
@@ -133,7 +162,9 @@ static struct fstype_info fstypes[] = {
 		.write = fs_write_unsupported,
 #endif
 		.uuid = fs_uuid_unsupported,
-		.opendir = fs_opendir_unsupported,
+		.opendir = fat_opendir,
+		.readdir = fat_readdir,
+		.closedir = fat_closedir,
 	},
 #endif
 #ifdef CONFIG_FS_EXT4
include/fat.h +4 -1
index b255ce5337..83cd90017e 100644
@@ -11,6 +11,7 @@
 #define _FAT_H_
 
 #include <asm/byteorder.h>
+#include <fs.h>
 
 #define CONFIG_SUPPORT_VFAT
 /* Maximum Long File Name length supported here is 128 UTF-16 code units */
@@ -179,7 +180,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
 }
 
 int file_fat_detectfs(void);
-int file_fat_ls(const char *dir);
 int fat_exists(const char *filename);
 int fat_size(const char *filename, loff_t *size);
 int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
@@ -192,5 +192,8 @@ int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len,
 		   loff_t *actwrite);
 int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
 		  loff_t *actread);
+int fat_opendir(const char *filename, struct fs_dir_stream **dirsp);
+int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
+void fat_closedir(struct fs_dir_stream *dirs);
 void fat_close(void);
 #endif /* _FAT_H_ */
Signature · 1 line
2.13.5
#27 lore raw

PATCH v3 7/9 fat/fs: move ls to generic implementation

Quoted 8 lines · Rob Clark

Add a generic implementation of 'ls' using opendir/readdir/closedir, and replace fat's custom implementation. Other filesystems should move to the generic implementation after they add opendir/readdir/closedir support.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/9a6878e5/attachment.sig>
author
#28 lore raw

PATCH v3 8/9 fs/fat: fix case for FAT shortnames

In reply to Rob Clark

Noticed when comparing our output to linux. There are some lcase bits which control whether filename and/or extension should be downcase'd.

---
 fs/fat/fat.c       | 16 ++++++++++------
 fs/fat/fat_write.c |  4 ++--
 include/fat.h      |  6 +++++-
 3 files changed, 17 insertions(+), 9 deletions(-)
fs/fat/fat.c +10 -6
index c951d84f57..65873a2c2a 100644
@@ -29,11 +29,13 @@ static const int vfat_enabled = 0;
 #endif
 
 /*
- * Convert a string to lowercase.
+ * Convert a string to lowercase.  Converts at most 'len' characters,
+ * 'len' may be larger than the length of 'str' if 'str' is NULL
+ * terminated.
  */
-static void downcase(char *str)
+static void downcase(char *str, size_t len)
 {
-	while (*str != '\0') {
+	while (*str != '\0' && len--) {
 		*str = tolower(*str);
 		str++;
 	}
@@ -131,10 +133,13 @@ static void get_name(dir_entry *dirent, char *s_name)
 	ptr = s_name;
 	while (*ptr && *ptr != ' ')
 		ptr++;
+	if (dirent->lcase & CASE_LOWER_BASE)
+		downcase(s_name, (unsigned)(ptr - s_name));
 	if (dirent->ext[0] && dirent->ext[0] != ' ') {
-		*ptr = '.';
-		ptr++;
+		*ptr++ = '.';
 		memcpy(ptr, dirent->ext, 3);
+		if (dirent->lcase & CASE_LOWER_EXT)
+			downcase(ptr, 3);
 		ptr[3] = '\0';
 		while (*ptr && *ptr != ' ')
 			ptr++;
@@ -144,7 +149,6 @@ static void get_name(dir_entry *dirent, char *s_name)
 		*s_name = '\0';
 	else if (*s_name == aRING)
 		*s_name = DELETED_FLAG;
-	downcase(s_name);
 }
 
 static int flush_dirty_fat_buffer(fsdata *mydata);
fs/fat/fat_write.c +2 -2
index 4ca024c208..d0468baf8f 100644
@@ -345,7 +345,7 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
 		*l_name = '\0';
 	else if (*l_name == aRING)
 		*l_name = DELETED_FLAG;
-	downcase(l_name);
+	downcase(l_name, INT_MAX);
 
 	/* Return the real directory entry */
 	*retdent = realdent;
@@ -981,7 +981,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,
 
 	memcpy(l_filename, filename, name_len);
 	l_filename[name_len] = 0; /* terminate the string */
-	downcase(l_filename);
+	downcase(l_filename, INT_MAX);
 
 	startsect = mydata->rootdir_sect;
 	retdent = find_directory_entry(mydata, startsect,
include/fat.h +5 -1
index 83cd90017e..0f58939124 100644
@@ -128,10 +128,14 @@ typedef struct volume_info
 	/* Boot sign comes last, 2 bytes */
 } volume_info;
 
+/* see dir_entry::lcase: */
+#define CASE_LOWER_BASE	8	/* base (name) is lower case */
+#define CASE_LOWER_EXT	16	/* extension is lower case */
+
 typedef struct dir_entry {
 	char	name[8],ext[3];	/* Name and extension */
 	__u8	attr;		/* Attribute bits */
-	__u8	lcase;		/* Case for base and extension */
+	__u8	lcase;		/* Case for name and ext (CASE_LOWER_x) */
 	__u8	ctime_ms;	/* Creation time, milliseconds */
 	__u16	ctime;		/* Creation time */
 	__u16	cdate;		/* Creation date */
Signature · 1 line
2.13.5
#29 lore raw

PATCH v3 8/9 fs/fat: fix case for FAT shortnames

Quoted 10 lines · Rob Clark

Noticed when comparing our output to linux. There are some lcase bits which control whether filename and/or extension should be downcase'd.

---
 fs/fat/fat.c       | 16 ++++++++++------
 fs/fat/fat_write.c |  4 ++--
 include/fat.h      |  6 +++++-
 3 files changed, 17 insertions(+), 9 deletions(-)
#30 lore raw

PATCH v3 8/9 fs/fat: fix case for FAT shortnames

In reply to Rob Clark
Quoted 6 lines · Rob Clark

Noticed when comparing our output to linux. There are some lcase bits which control whether filename and/or extension should be downcase'd.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/4249a109/attachment.sig>
author
#31 lore raw

PATCH v3 9/9 fs/fat: Clean up open-coded sector <-> cluster conversions

In reply to Rob Clark

Use the clust_to_sect() helper that was introduced earlier, and add an inverse sect_to_clust(), plus update the various spots that open-coded this conversion previously.

---
 fs/fat/fat.c       | 8 +++-----
 fs/fat/fat_write.c | 8 +++-----
 include/fat.h      | 6 +++++-
 3 files changed, 11 insertions(+), 11 deletions(-)
fs/fat/fat.c +3 -5
index 65873a2c2a..f5f74c12ff 100644
@@ -257,8 +257,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
 	int ret;
 
 	if (clustnum > 0) {
-		startsect = mydata->data_begin +
-				clustnum * mydata->clust_size;
+		startsect = clust_to_sect(mydata, clustnum);
 	} else {
 		startsect = mydata->rootdir_sect;
 	}
@@ -594,9 +593,8 @@ static int get_fs_info(fsdata *mydata)
 		mydata->data_begin = mydata->rootdir_sect +
 					mydata->rootdir_size -
 					(mydata->clust_size * 2);
-		mydata->root_cluster = (mydata->rootdir_sect -
-					mydata->data_begin) /
-					mydata->clust_size;
+		mydata->root_cluster =
+			sect_to_clust(mydata, mydata->rootdir_sect);
 	}
 
 	mydata->fatbufnum = -1;
fs/fat/fat_write.c +3 -5
index d0468baf8f..9d2e0ed74c 100644
@@ -502,8 +502,7 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
 	int ret;
 
 	if (clustnum > 0)
-		startsect = mydata->data_begin +
-				clustnum * mydata->clust_size;
+		startsect = clust_to_sect(mydata, clustnum);
 	else
 		startsect = mydata->rootdir_sect;
 
@@ -751,8 +750,7 @@ static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
 	__u32 startsect, sect_num, offset;
 
 	if (clustnum > 0) {
-		startsect = mydata->data_begin +
-				clustnum * mydata->clust_size;
+		startsect = clust_to_sect(mydata, clustnum);
 	} else {
 		startsect = mydata->rootdir_sect;
 	}
@@ -791,7 +789,7 @@ static dir_entry *empty_dentptr;
 static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
 	char *filename, dir_entry *retdent, __u32 start)
 {
-	__u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size;
+	__u32 curclust = sect_to_clust(mydata, startsect);
 
 	debug("get_dentfromdir: %s\n", filename);
 
include/fat.h +5 -1
index 0f58939124..bdeda95e6d 100644
@@ -177,12 +177,16 @@ typedef struct {
 	__u32	root_cluster;	/* First cluster of root dir for FAT32 */
 } fsdata;
 
-/* TODO clean up places that are open-coding this: */
 static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
 {
 	return fsdata->data_begin + clust * fsdata->clust_size;
 }
 
+static inline u32 sect_to_clust(fsdata *fsdata, u32 sect)
+{
+	return (sect - fsdata->data_begin) / fsdata->clust_size;
+}
+
 int file_fat_detectfs(void);
 int fat_exists(const char *filename);
 int fat_size(const char *filename, loff_t *size);
Signature · 1 line
2.13.5
#32 lore raw

PATCH v3 9/9 fs/fat: Clean up open-coded sector <-> cluster conversions

Quoted 10 lines · Rob Clark

Use the clust_to_sect() helper that was introduced earlier, and add an inverse sect_to_clust(), plus update the various spots that open-coded this conversion previously.

---
 fs/fat/fat.c       | 8 +++-----
 fs/fat/fat_write.c | 8 +++-----
 include/fat.h      | 6 +++++-
 3 files changed, 11 insertions(+), 11 deletions(-)
#33 lore raw

PATCH v3 9/9 fs/fat: Clean up open-coded sector <-> cluster conversions

In reply to Rob Clark
Quoted 6 lines · Rob Clark

Use the clust_to_sect() helper that was introduced earlier, and add an inverse sect_to_clust(), plus update the various spots that open-coded this conversion previously.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170915/bdde36af/attachment.sig>