[PATCH] usb: kbd: Also accept keyboards with Interrupt OUT endpoint
The OUT endpoint can just be ignored as it is not used, just as the corresponding Set_Report request for IN-only interfaces. E.g. the Linux gadget hid keyboard also provides an interrupt endpoint. Also cleanup confusing debug messages like "found set protocol", which is printed when a keyboard device is found, while the Set_Protocol request is issued quite some time later. Signed-off-by: Stefan Brüns --- common/usb_kbd.c | 23 ++- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 60c6027e04..afad260d3d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -443,6 +443,7 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) struct usb_interface *iface; struct usb_endpoint_descriptor *ep; struct usb_kbd_pdata *data; + int epNum; if (dev->descriptor.bNumConfigurations != 1) return 0; @@ -458,19 +459,21 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD) return 0; - if (iface->desc.bNumEndpoints != 1) - return 0; + for (epNum = 0; epNum < iface->desc.bNumEndpoints; epNum++) { + ep = >ep_desc[epNum]; - ep = >ep_desc[0]; + /* Check if endpoint is interrupt IN endpoint */ + if ((ep->bmAttributes & 3) != 3) + continue; - /* Check if endpoint 1 is interrupt endpoint */ - if (!(ep->bEndpointAddress & 0x80)) - return 0; + if (ep->bEndpointAddress & 0x80) + break; + } - if ((ep->bmAttributes & 3) != 3) + if (epNum == iface->desc.bNumEndpoints) return 0; - debug("USB KBD: found set protocol...\n"); + debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress); data = malloc(sizeof(struct usb_kbd_pdata)); if (!data) { @@ -498,13 +501,15 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) data->last_report = -1; /* We found a USB Keyboard, install it. */ + debug("USB KBD: set boot protocol\n"); usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); - debug("USB KBD: found set idle...\n"); #if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \ !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) + debug("USB KBD: set idle interval...\n"); usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0); #else + debug("USB KBD: set idle interval=0...\n"); usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0); #endif -- 2.30.1
[U-Boot] [PATCH] patman: Unquote output from get_maintainer.pl
get_maintainer.pl quotes names which it considers unsafe, i.e. anything containing [^a-zA-Z0-9_ \-]. This confuses patman, it will duplicate addresses which are also in Series-to/cc. Strip the quotes. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- tools/patman/get_maintainer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/patman/get_maintainer.py b/tools/patman/get_maintainer.py index 2deb5db6ec..22b091808a 100644 --- a/tools/patman/get_maintainer.py +++ b/tools/patman/get_maintainer.py @@ -44,4 +44,5 @@ def GetMaintainer(fname, verbose=False): return [] stdout = command.Output(get_maintainer, '--norolestats', fname) -return stdout.splitlines() +lines = stdout.splitlines() +return [ x.replace('"', '') for x in lines ] -- 2.15.1 ___ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot
Re: [U-Boot] [linux-sunxi] Re: [PATCH 12/16] configs: sun50i: enable ums on bananapi-m64
On Wednesday, December 13, 2017 2:36:26 AM CET Icenowy Zheng wrote: > 在 2017年12月12日星期二 CST 下午4:12:13,Maxime Ripard 写道: > > > Hi, > > > > On Tue, Dec 12, 2017 at 12:28:27PM +0530, Jagan Teki wrote: > > > This patch enable ums through CMD_USB_MASS_STORAGE. > > > > > > Signed-off-by: Jagan Teki <ja...@amarulasolutions.com> > > > --- > > > > > > configs/bananapi_m64_defconfig | 1 + > > > 1 file changed, 1 insertion(+) > > > > > > diff --git a/configs/bananapi_m64_defconfig > > > b/configs/bananapi_m64_defconfig index 55feafe..d4aade5 100644 > > > --- a/configs/bananapi_m64_defconfig > > > +++ b/configs/bananapi_m64_defconfig > > > @@ -11,6 +11,7 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-bananapi-m64" > > > > > > CONFIG_SPL=y > > > # CONFIG_CMD_FLASH is not set > > > # CONFIG_CMD_FPGA is not set > > > > > > +CONFIG_CMD_USB_MASS_STORAGE=y > > > > How does that work with the current over-size issue we have on the > > A64? > > > > And I'd also like to keep the way we did things for several years now, > > which is to *not* have board-specific options selected besides the > > hardware-related ones. > > > > If you want to enable a general feature, do it for all the boards so > > that our users will have a consistent experience across boards, and we > > will not have to always chase all the defconfigs to provide it. > > I think there's a problem on A64 -- the Pine series are all designed to be > host-only, and it's the most popular A64 board series. No, it just means the *initial* role of the Pine will be Host, but the roles can be swapped using HNP (Host Negotiation Protocol) afterwards, which is pure software. Regards, Stefan -- Stefan Brüns / Bergstraße 21 / 52062 Aachen home: +49 241 53809034 mobile: +49 151 50412019 signature.asc Description: This is a digitally signed message part. ___ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot
[U-Boot] [PATCH v1] Document padding between GPT header and partition entries
Commit 02e43537b322 ("part_efi: support padding between the GPT header and partition entries") added support for deviating from the typical GPT layout. Explicitly state deviations are allowed/possible, and mention when (SoC SPL) and when not (compatibility) deviations are useful. Also mention support for non-standard layouts in gdisk 1.0.3. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- doc/README.gpt | 33 + 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/doc/README.gpt b/doc/README.gpt index d3db8bce1c..7134f3b3cf 100644 --- a/doc/README.gpt +++ b/doc/README.gpt @@ -44,8 +44,8 @@ uuid command line tool). GPT brief explanation: == - Layout: - --- + Default layout: + --- -- LBA 0 |Protective MBR | @@ -82,7 +82,29 @@ For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called Its first partition entry ID has 0xEE value, and disk software, which is not handling the GPT sees it as a storage device without free space. -It is possible to define 128 linearly placed partition entries. +By default, the first partition entry of the primary GPT is stored in LBA 2, +although this is not explicitly mandated by the UEFI specification. The +start LBAs of the partition entries are given in the corresponding GPT +headers (Primary/Backup) (offset 72 bytes). + +The UEFI specification mandates at least 128 contigously stored partition +entries, the number is specified in the GPT headers (offset 80). + +As several SoCs require the SPL to be located at a fixed position, often +below LBA 34 (17 kByte for 512 byte blocks), it is possible to deviate +from the standard layout: + +1. Lower the number of partition entries. This violates the UEFI/GPT + specification, but usually works. +2. Insert a gap between Primary GPT Header and partition entries. This + is in line with the specification, but may cause problems with tools + or operating systems hardcoding the partition entries LBA to 2. + +There is limited support for both variants in U-Boot - reading is fully +supported, while the "gpt write" command always creates a GPT with 128 +entries. A gap is created when CONFIG_EFI_PARTITION_ENTRIES_OFF is set +or when the device tree "/config" node contains a property +"u-boot,efi-partition-entries-offset". "LBA -1" means the last addressable block (in the mmc subsystem: "dev_desc->lba - 1") @@ -103,7 +125,7 @@ Offset SizeDescription LBA + 1) 48 8 B Last usable LBA (secondary partition table first LBA - 1) 56 16 BDisk GUID (also referred as UUID on UNIXes) -72 8 B Partition entries starting LBA (always 2 in primary copy) +72 8 B Partition entries starting LBA (usually 2 in primary copy) 80 4 B Number of partition entries 84 4 B Size of a partition entry (usually 128) 88 4 B CRC32 of partition array @@ -283,6 +305,9 @@ Two programs, namely: 'gdisk' and 'parted' are recommended to work with GPT recovery. Both are able to handle GUID partitions. Please, pay attention at -l switch for parted. +'gdisk' as of version 1.0.3 is able to create tables with a number of partition +entries different to 128, and insert padding after the GPT header. + "uuid" program is recommended to generate UUID string. Moreover it can decode (-d switch) passed in UUID string. It can be used to generate partitions UUID passed to u-boot environment variables. -- 2.14.2 ___ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot
[U-Boot] [PATCH] fs/ext4: Initialize group descriptor size for revision level 0 filesystems
genext2fs creates revision level 0 filesystems, which are not readable by u-boot due to the initialized group descriptor size field. f798b1dda1c5de818b806189e523d1b75db7e72d Reported-by: Kever Yang <kever.y...@rock-chips.com> Reported-by: frostyby...@protonmail.com Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index bfebe7e379..621c61e5c7 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -2334,6 +2334,7 @@ int ext4fs_mount(unsigned part_length) if (le32_to_cpu(data->sblock.revision_level) == 0) { fs->inodesz = 128; + fs->gdsize = 32; } else { debug("EXT4 features COMPAT: %08x INCOMPAT: %08x RO_COMPAT: %08x\n", __le32_to_cpu(data->sblock.feature_compatibility), -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH] fs/fat: simplify get_fatent for FAT12
From: Stefan Brüns <stefan.bru...@rwth-aachen.de> Instead of shuffling bits from two adjacent 16 bit words, use one 16 bit word with the appropriate byte offset in the buffer. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat.c | 34 +- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 73c3dd7f85..fe899d0442 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -181,7 +181,6 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) __u32 bufnum; __u32 off16, offset; __u32 ret = 0x00; - __u16 val1, val2; if (CHECK_CLUST(entry, mydata->fatsize)) { printf("Error: Invalid FAT entry: 0x%08x\n", entry); @@ -243,35 +242,12 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); break; case 12: - off16 = (offset * 3) / 4; + off16 = (offset * 3) / 2; + ret = FAT2CPU16(*(__u16 *)(mydata->fatbuf + off16)); - switch (offset & 0x3) { - case 0: - ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); - ret &= 0xfff; - break; - case 1: - val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); - val1 &= 0xf000; - val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); - val2 &= 0x00ff; - ret = (val2 << 4) | (val1 >> 12); - break; - case 2: - val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); - val1 &= 0xff00; - val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); - val2 &= 0x000f; - ret = (val2 << 8) | (val1 >> 8); - break; - case 3: - ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); - ret = (ret & 0xfff0) >> 4; - break; - default: - break; - } - break; + if (offset & 0x1) + ret >>= 4; + ret &= 0xfff; } debug("FAT%d: ret: 0x%08x, entry: 0x%08x, offset: 0x%04x\n", mydata->fatsize, ret, entry, offset); -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 2/2] fs/fat: merge readwrite get_fatent_value() with readonly get_fatent()
get_fatent_value(...) flushes changed FAT entries to disk when fetching the next FAT blocks, in every other aspect it is identical to get_fatent(...). Provide a stub implementation for flush_dirty_fat_buffer if CONFIG_FAT_WRITE is not set. Calling flush_dirty_fat_buffer during read only operation is fine as it checks if any buffers needs flushing. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Benoît Thébaudeau <benoit.thebaudeau@gmail.com> --- fs/fat/fat.c | 25 ++-- fs/fat/fat_write.c | 118 +++-- 2 files changed, 27 insertions(+), 116 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 6319581406..73c3dd7f85 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -162,6 +162,16 @@ static void get_name(dir_entry *dirent, char *s_name) downcase(s_name); } +static int flush_dirty_fat_buffer(fsdata *mydata); +#if !defined(CONFIG_FAT_WRITE) +/* Stub for read only operation */ +int flush_dirty_fat_buffer(fsdata *mydata) +{ + (void)(mydata); + return 0; +} +#endif + /* * Get the entry at index 'entry' in a FAT (12/16/32) table. * On failure 0x00 is returned. @@ -173,6 +183,11 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) __u32 ret = 0x00; __u16 val1, val2; + if (CHECK_CLUST(entry, mydata->fatsize)) { + printf("Error: Invalid FAT entry: 0x%08x\n", entry); + return ret; + } + switch (mydata->fatsize) { case 32: bufnum = entry / FAT32BUFSIZE; @@ -192,7 +207,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) return ret; } - debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", + debug("FAT%d: entry: 0x%08x = %d, offset: 0x%04x = %d\n", mydata->fatsize, entry, entry, offset, offset); /* Read a new block of FAT entries into the cache. */ @@ -208,6 +223,10 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) startblock += mydata->fat_sect; /* Offset from start of disk */ + /* Write back the fatbuf to the disk */ + if (flush_dirty_fat_buffer(mydata) < 0) + return -1; + if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); return ret; @@ -254,8 +273,8 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) } break; } - debug("FAT%d: ret: %08x, offset: %04x\n", - mydata->fatsize, ret, offset); + debug("FAT%d: ret: 0x%08x, entry: 0x%08x, offset: 0x%04x\n", + mydata->fatsize, ret, entry, offset); return ret; } diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 0be60ecd99..c05fc7f099 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -143,114 +143,6 @@ static int flush_dirty_fat_buffer(fsdata *mydata) } /* - * Get the entry at index 'entry' in a FAT (12/16/32) table. - * On failure 0x00 is returned. - * When bufnum is changed, write back the previous fatbuf to the disk. - */ -static __u32 get_fatent_value(fsdata *mydata, __u32 entry) -{ - __u32 bufnum; - __u32 off16, offset; - __u32 ret = 0x00; - __u16 val1, val2; - - if (CHECK_CLUST(entry, mydata->fatsize)) { - printf("Error: Invalid FAT entry: 0x%08x\n", entry); - return ret; - } - - switch (mydata->fatsize) { - case 32: - bufnum = entry / FAT32BUFSIZE; - offset = entry - bufnum * FAT32BUFSIZE; - break; - case 16: - bufnum = entry / FAT16BUFSIZE; - offset = entry - bufnum * FAT16BUFSIZE; - break; - case 12: - bufnum = entry / FAT12BUFSIZE; - offset = entry - bufnum * FAT12BUFSIZE; - break; - - default: - /* Unsupported FAT size */ - return ret; - } - - debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", - mydata->fatsize, entry, entry, offset, offset); - - /* Read a new block of FAT entries into the cache. */ - if (bufnum != mydata->fatbufnum) { - int getsize = FATBUFBLOCKS; - __u8 *bufptr = mydata->fatbuf; - __u32 fatlength = mydata->fatlength; - __u32 startblock = bufnum * FATBUFBLOCKS; - - /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ - if (startblock + getsize > fatlength) - getsize = fatlength - startblock; - - startblock += mydata->fat_sect; /* Offset from start of disk */ - - /* Write back the fatbuf to the disk */ -
[U-Boot] [PATCH v2 1/2] fs/fat: Avoid corruption of sectors following the FAT
The FAT is read/flushed in segments of 6 (FATBUFBLOCKS) disk sectors. The last segment may be less than 6 sectors, cap the length. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Benoît Thébaudeau <benoit.thebaudeau@gmail.com> --- fs/fat/fat.c | 1 + fs/fat/fat_write.c | 22 -- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index df9f2b5656..6319581406 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -202,6 +202,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ if (startblock + getsize > fatlength) getsize = fatlength - startblock; diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 40a3860e47..0be60ecd99 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -117,10 +117,11 @@ static int flush_dirty_fat_buffer(fsdata *mydata) if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1)) return 0; - startblock += mydata->fat_sect; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; - if (getsize > fatlength) - getsize = fatlength; + startblock += mydata->fat_sect; /* Write FAT buf */ if (disk_write(startblock, getsize, bufptr) < 0) { @@ -187,8 +188,9 @@ static __u32 get_fatent_value(fsdata *mydata, __u32 entry) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; - if (getsize > fatlength) - getsize = fatlength; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; startblock += mydata->fat_sect; /* Offset from start of disk */ @@ -494,15 +496,15 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; - fatlength *= mydata->sect_size; - startblock += mydata->fat_sect; - - if (getsize > fatlength) - getsize = fatlength; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; if (flush_dirty_fat_buffer(mydata) < 0) return -1; + startblock += mydata->fat_sect; + if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); return -1; -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 0/2] fs/fat: more bugfixes, cleanups
Fix a possible filesystem corruption if the FS is almost full, and remove some duplicate code. Stefan Brüns (2): fs/fat: Avoid corruption of sectors following the FAT fs/fat: merge readwrite get_fatent_value() with readonly get_fatent() fs/fat/fat.c | 26 +-- fs/fat/fat_write.c | 134 ++--- 2 files changed, 37 insertions(+), 123 deletions(-) v2: fixed author tag encoding use consistent debut output formatting added rb: Benoît Thébaudeau <benoit.thebaudeau@gmail.com> -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 1/2] test/py: Pass u_boot_log instead of console for run_and_log
From: Stefan Brüns <stefan.bru...@rwth-aachen.de> The runner actually has no console dependency, only on the log provided by the console. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- Alternate approach to the previous patch, always pass the logfile, change all callers accordingly. test/py/tests/test_dfu.py | 2 +- test/py/tests/test_ums.py | 10 +- test/py/tests/test_vboot.py | 18 +- test/py/u_boot_utils.py | 12 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/test/py/tests/test_dfu.py b/test/py/tests/test_dfu.py index 585e6b29d7..b4f9a32abc 100644 --- a/test/py/tests/test_dfu.py +++ b/test/py/tests/test_dfu.py @@ -206,7 +206,7 @@ def test_dfu(u_boot_console, env__usb_dev_port, env__dfu_config): cmd = ['dfu-util', '-a', alt_setting, up_dn_load_arg, fn] if 'host_usb_port_path' in env__usb_dev_port: cmd += ['-p', env__usb_dev_port['host_usb_port_path']] -u_boot_utils.run_and_log(u_boot_console, cmd) +u_boot_utils.run_and_log(u_boot_console.log, cmd) u_boot_console.wait_for('Ctrl+C to exit ...') def dfu_write(alt_setting, fn): diff --git a/test/py/tests/test_ums.py b/test/py/tests/test_ums.py index 8c3ee2b053..54c47b0aee 100644 --- a/test/py/tests/test_ums.py +++ b/test/py/tests/test_ums.py @@ -156,7 +156,7 @@ def test_ums(u_boot_console, env__usb_dev_port, env__block_devs): u_boot_console.log.action('Mounting exported UMS device') cmd = ('/bin/mount', host_ums_part_node) -u_boot_utils.run_and_log(u_boot_console, cmd) +u_boot_utils.run_and_log(u_boot_console.log, cmd) def umount(ignore_errors): """Unmount the block device that U-Boot exports. @@ -173,7 +173,7 @@ def test_ums(u_boot_console, env__usb_dev_port, env__block_devs): u_boot_console.log.action('Unmounting UMS device') cmd = ('/bin/umount', host_ums_part_node) -u_boot_utils.run_and_log(u_boot_console, cmd, ignore_errors) +u_boot_utils.run_and_log(u_boot_console.log, cmd, ignore_errors) def stop_ums(ignore_errors): """Stop U-Boot's ums shell command from executing. @@ -207,11 +207,11 @@ def test_ums(u_boot_console, env__usb_dev_port, env__block_devs): mount() u_boot_console.log.action('Writing test file via UMS') cmd = ('rm', '-f', mounted_test_fn) -u_boot_utils.run_and_log(u_boot_console, cmd) +u_boot_utils.run_and_log(u_boot_console.log, cmd) if os.path.exists(mounted_test_fn): raise Exception('Could not rm target UMS test file') cmd = ('cp', test_f.abs_fn, mounted_test_fn) -u_boot_utils.run_and_log(u_boot_console, cmd) +u_boot_utils.run_and_log(u_boot_console.log, cmd) ignore_cleanup_errors = False finally: umount(ignore_errors=ignore_cleanup_errors) @@ -226,7 +226,7 @@ def test_ums(u_boot_console, env__usb_dev_port, env__block_devs): u_boot_console.log.action('Reading test file back via UMS') read_back_hash = u_boot_utils.md5sum_file(mounted_test_fn) cmd = ('rm', '-f', mounted_test_fn) -u_boot_utils.run_and_log(u_boot_console, cmd) +u_boot_utils.run_and_log(u_boot_console.log, cmd) ignore_cleanup_errors = False finally: umount(ignore_errors=ignore_cleanup_errors) diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index 6e62820743..0f893f1e91 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -50,7 +50,7 @@ def test_vboot(u_boot_console): dts: Device tree file to compile. """ dtb = dts.replace('.dts', '.dtb') -util.run_and_log(cons, 'dtc %s %s%s -O dtb ' +util.run_and_log(cons.log, 'dtc %s %s%s -O dtb ' '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) def run_bootm(sha_algo, test_type, expect_string, boots): @@ -85,7 +85,7 @@ def test_vboot(u_boot_console): Args: its: Filename containing .its source. """ -util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', +util.run_and_log(cons.log, [mkimage, '-D', dtc_args, '-f', '%s%s' % (datadir, its), fit]) def sign_fit(sha_algo): @@ -99,7 +99,7 @@ def test_vboot(u_boot_console): use. """ cons.log.action('%s: Sign images' % sha_algo) -util.run_and_log(cons, [mkimage, '-F', '-k', tmpdir, '-K', dtb, +util.run_and_log(cons.log, [mkimage, '-F', '-k', tmpdir, '-K', dtb, '-r', fit]) def test_with_algo(sha_algo): @@ -140,23 +140,23 @@ def test_vboot(u_boot_console): cons.log.action('%s: Check signed
[U-Boot] [PATCH 0/2] fs/fat: more bugfixes, cleanups
Fix a possible filesystem corruption if the FS is almost full, and remove some duplicate code. Stefan Brüns (1): fs/fat: Avoid corruption of sectors following the FAT Stefan Brüns (1): fs/fat: merge readwrite get_fatent_value() with readonly get_fatent() fs/fat/fat.c | 20 fs/fat/fat_write.c | 134 ++--- 2 files changed, 34 insertions(+), 120 deletions(-) -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/2] fs/fat: merge readwrite get_fatent_value() with readonly get_fatent()
get_fatent_value(...) flushes changed FAT entries to disk when fetching the next FAT blocks, in every other aspect it is identical to get_fatent(...). Provide a stub implementation for flush_dirty_fat_buffer if CONFIG_FAT_WRITE is not set. Calling flush_dirty_fat_buffer during read only operation is fine as it checks if any buffers needs flushing. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat.c | 19 + fs/fat/fat_write.c | 118 +++-- 2 files changed, 24 insertions(+), 113 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 6319581406..554e811587 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -162,6 +162,16 @@ static void get_name(dir_entry *dirent, char *s_name) downcase(s_name); } +static int flush_dirty_fat_buffer(fsdata *mydata); +#if !defined(CONFIG_FAT_WRITE) +/* Stub for read only operation */ +int flush_dirty_fat_buffer(fsdata *mydata) +{ + (void)(mydata); + return 0; +} +#endif + /* * Get the entry at index 'entry' in a FAT (12/16/32) table. * On failure 0x00 is returned. @@ -173,6 +183,11 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) __u32 ret = 0x00; __u16 val1, val2; + if (CHECK_CLUST(entry, mydata->fatsize)) { + printf("Error: Invalid FAT entry: 0x%08x\n", entry); + return ret; + } + switch (mydata->fatsize) { case 32: bufnum = entry / FAT32BUFSIZE; @@ -208,6 +223,10 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) startblock += mydata->fat_sect; /* Offset from start of disk */ + /* Write back the fatbuf to the disk */ + if (flush_dirty_fat_buffer(mydata) < 0) + return -1; + if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); return ret; diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 0be60ecd99..c05fc7f099 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -143,114 +143,6 @@ static int flush_dirty_fat_buffer(fsdata *mydata) } /* - * Get the entry at index 'entry' in a FAT (12/16/32) table. - * On failure 0x00 is returned. - * When bufnum is changed, write back the previous fatbuf to the disk. - */ -static __u32 get_fatent_value(fsdata *mydata, __u32 entry) -{ - __u32 bufnum; - __u32 off16, offset; - __u32 ret = 0x00; - __u16 val1, val2; - - if (CHECK_CLUST(entry, mydata->fatsize)) { - printf("Error: Invalid FAT entry: 0x%08x\n", entry); - return ret; - } - - switch (mydata->fatsize) { - case 32: - bufnum = entry / FAT32BUFSIZE; - offset = entry - bufnum * FAT32BUFSIZE; - break; - case 16: - bufnum = entry / FAT16BUFSIZE; - offset = entry - bufnum * FAT16BUFSIZE; - break; - case 12: - bufnum = entry / FAT12BUFSIZE; - offset = entry - bufnum * FAT12BUFSIZE; - break; - - default: - /* Unsupported FAT size */ - return ret; - } - - debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", - mydata->fatsize, entry, entry, offset, offset); - - /* Read a new block of FAT entries into the cache. */ - if (bufnum != mydata->fatbufnum) { - int getsize = FATBUFBLOCKS; - __u8 *bufptr = mydata->fatbuf; - __u32 fatlength = mydata->fatlength; - __u32 startblock = bufnum * FATBUFBLOCKS; - - /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ - if (startblock + getsize > fatlength) - getsize = fatlength - startblock; - - startblock += mydata->fat_sect; /* Offset from start of disk */ - - /* Write back the fatbuf to the disk */ - if (flush_dirty_fat_buffer(mydata) < 0) - return -1; - - if (disk_read(startblock, getsize, bufptr) < 0) { - debug("Error reading FAT blocks\n"); - return ret; - } - mydata->fatbufnum = bufnum; - } - - /* Get the actual entry from the table */ - switch (mydata->fatsize) { - case 32: - ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); - break; - case 16: - ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); - break; - case 12: - off16 = (offset * 3) / 4; - - switch (offset & 0x3) { - case 0: - ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); -
[U-Boot] [PATCH 1/2] fs/fat: Avoid corruption of sectors following the FAT
From: Stefan Brüns <stefan.bru...@rwth-aachen.de> The FAT is read/flushed in segments of 6 (FATBUFBLOCKS) disk sectors. The last segment may be less than 6 sectors, cap the length. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat.c | 1 + fs/fat/fat_write.c | 22 -- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index df9f2b5656..6319581406 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -202,6 +202,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ if (startblock + getsize > fatlength) getsize = fatlength - startblock; diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 40a3860e47..0be60ecd99 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -117,10 +117,11 @@ static int flush_dirty_fat_buffer(fsdata *mydata) if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1)) return 0; - startblock += mydata->fat_sect; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; - if (getsize > fatlength) - getsize = fatlength; + startblock += mydata->fat_sect; /* Write FAT buf */ if (disk_write(startblock, getsize, bufptr) < 0) { @@ -187,8 +188,9 @@ static __u32 get_fatent_value(fsdata *mydata, __u32 entry) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; - if (getsize > fatlength) - getsize = fatlength; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; startblock += mydata->fat_sect; /* Offset from start of disk */ @@ -494,15 +496,15 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; - fatlength *= mydata->sect_size; - startblock += mydata->fat_sect; - - if (getsize > fatlength) - getsize = fatlength; + /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ + if (startblock + getsize > fatlength) + getsize = fatlength - startblock; if (flush_dirty_fat_buffer(mydata) < 0) return -1; + startblock += mydata->fat_sect; + if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); return -1; -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 2/2] test/py: Create tests for ext4 and fat testing on sandbox
From: Stefan Brüns <stefan.bru...@rwth-aachen.de> The following checks are currently implemented: 1. listing a directory 2. verifying size of a file 3. veryfying md5sum for a file region 4. reading the beginning of a file Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/tests/test_fs.py | 357 +++ 1 file changed, 357 insertions(+) create mode 100644 test/py/tests/test_fs.py diff --git a/test/py/tests/test_fs.py b/test/py/tests/test_fs.py new file mode 100644 index 00..7aaf8debaf --- /dev/null +++ b/test/py/tests/test_fs.py @@ -0,0 +1,357 @@ +# Copyright (c) 2016, Stefan Bruens <stefan.bru...@rwth-aachen.de> +# +# SPDX-License-Identifier: GPL-2.0 + +# Test U-Boot's filesystem implementations +# +# The tests are currently covering the ext4 and fat filesystem implementations. +# +# Following functionality is currently checked: +# - Listing a directory and checking for a set of files +# - Verifying the size of a file +# - Reading sparse and non-sparse files +# - File content verification using md5sums + + +from distutils.spawn import find_executable +import hashlib +import pytest +import os +import random +import re +import u_boot_utils as util + +@pytest.fixture(scope='session') +def prereq_commands(): +"""Detect required commands to run file system tests.""" +for command in ['mkfs', 'mount', 'umount']: +if find_executable(command) is None: +pytest.skip('Filesystem tests, "{0}" not in PATH'.format(command)) + +""" +Scenarios: +hostfs: access image contents through the sandbox hostfs +facility, using the filesytem implementation of +the sandbox host, e.g. Linux kernel +generic: test u-boots native filesystem implementations, +using the 'generic' command names, e.g. 'load' +TODO - +fscommands: test u-boots native filesystem implementations, +using the fs specific commands, e.g. 'ext4load' +""" +@pytest.fixture(scope='class', params=['generic', 'hostfs']) +def scenario(request): +request.cls.scenario = request.param +return request.param + + +""" +Dictionary of files to use during filesystem tests. The files +are keyed by the filenames. The value is an array of strides, each tuple +contains the the start offset (inclusive) and end offset (exclusive). +""" +files = { +'empty.file' : [(0, 0)], +'1MB.file' : [(0, 1e6)], +'1MB.sparse.file' : [(1e6-1, 1e6)], +'32MB.sparse.file' : [(0, 1e6), (4e6, 5e6), (31e6, 32e6)], +# Creating a 2.5 GB file on FAT is exceptionally slow, disable it for now +# '2_5GB.sparse.file' : [(0, 1e6), (1e9, 1e9+1e6), (2.5e9-1e6, 2.5e9)], +} + +"""Options to pass to mkfs.""" +mkfs_opts = { + 'fat' :'-t vfat', + 'ext4' : '-t ext4 -F', +} + +class FsImage: +def __init__(self, fstype, imagepath, mountpath): +"""Create a new filesystem image. + +Args: +fstype: filesystem type (string) +imagepath: full path to image file +mountpath: mountpoint directory +""" +self.fstype = fstype +self.imagepath = imagepath +self.mountpath = mountpath +self.md5s = {} +with open(self.imagepath, 'w') as fd: +fd.truncate(0) +fd.seek(3e9) +fd.write(bytes([0])) + +def mkfs(self, log): +mkfsopts = mkfs_opts.get(self.fstype) +util.run_and_log(log, +'mkfs {0} {1}'.format(mkfsopts, self.imagepath)) + +def create_file(self, log, filename, strides): +"""Create a single file in the filesystem. Each file +is defined by one or more strides, which is filled with +random data. For each stride, the md5sum is calculated +and stored. +""" +md5sums = [] +with open(self.mountpath + '/' + filename, 'w') as fd: +for stride in strides: +length = int(stride[1] - stride[0]) +data = bytearray(random.getrandbits(8) for _ in xrange(length)) +md5 = hashlib.md5(data).hexdigest() +md5sums.append(md5) +log.info('{0}: write {1} bytes @ {2} : {3}'.format( +filename, int(stride[1] - stride[0]), +int(stride[0]), md5)) +fd.seek(stride[0]) +fd.write(data); +self.md5s[filename] = md5sums + +def create_files(self, log): +with log.section('Create initial files'): +for filename in files: +self.create_file(log, filename, files[filename]) +log.info('Created test files in "{0}"'.format(self.mountpath)) +util.run_and_log(log, 'ls -la {0}'.format(self.mountpath)) +
[U-Boot] [PATCH v2 1/2] test/py: Allow to pass u_boot_log instead of console for run_and_log
The runner actually has no console dependency, only on the log provided by the console. Accept both u_boot_console or a multiplexed_log. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/u_boot_utils.py | 20 ++-- 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py index 2ba4baed07..b9a72ab1de 100644 --- a/test/py/u_boot_utils.py +++ b/test/py/u_boot_utils.py @@ -153,11 +153,11 @@ def wait_until_file_open_fails(fn, ignore_errors): return raise Exception('File can still be opened') -def run_and_log(u_boot_console, cmd, ignore_errors=False): +def run_and_log(u_boot_console_or_log, cmd, ignore_errors=False): """Run a command and log its output. Args: -u_boot_console: A console connection to U-Boot. +u_boot_console_or_log: A console connection to U-Boot, or a LogFile. cmd: The command to run, as an array of argv[], or a string. If a string, note that it is split up so that quoted spaces will not be preserved. E.g. "fred and" becomes ['"fred', 'and"'] @@ -171,25 +171,33 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False): """ if isinstance(cmd, str): cmd = cmd.split() -runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) +if hasattr(u_boot_console_or_log, 'get_runner'): +get_runner = u_boot_console_or_log.get_runner +else: +get_runner = u_boot_console_or_log.log.get_runner +runner = get_runner(cmd[0], sys.stdout) output = runner.run(cmd, ignore_errors=ignore_errors) runner.close() return output -def run_and_log_expect_exception(u_boot_console, cmd, retcode, msg): +def run_and_log_expect_exception(u_boot_console_or_log, cmd, retcode, msg): """Run a command that is expected to fail. This runs a command and checks that it fails with the expected return code and exception method. If not, an exception is raised. Args: -u_boot_console: A console connection to U-Boot. +u_boot_console_or_log: A console connection to U-Boot, or a LogFile. cmd: The command to run, as an array of argv[]. retcode: Expected non-zero return code from the command. msg: String that should be contained within the command's output. """ +if hasattr(u_boot_console_or_log, 'get_runner'): +get_runner = u_boot_console_or_log.get_runner +else: +get_runner = u_boot_console_or_log.log.get_runner +runner = get_runner(cmd[0], sys.stdout) try: -runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) runner.run(cmd) except Exception as e: assert(retcode == runner.exit_status) -- 2.11.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 1/2] ext4: Allow reading files with non-zero offset, clamp read len
Support was already implemented, but not hooked up. This fixes several fails in the test cases. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- v2: - update ext4fs_read(...) calls from spl_ext.c - move clamping to ext4fs_read_file(...), i.e. correct the check for offset != 0 common/spl/spl_ext.c | 8 fs/ext4/ext4fs.c | 17 ++--- include/ext4fs.h | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c index b93e1ea..1b8e15e 100644 --- a/common/spl/spl_ext.c +++ b/common/spl/spl_ext.c @@ -42,7 +42,7 @@ int spl_load_image_ext(struct spl_image_info *spl_image, puts("spl: ext4fs_open failed\n"); goto end; } - err = ext4fs_read((char *)header, sizeof(struct image_header), ); + err = ext4fs_read((char *)header, 0, sizeof(struct image_header), ); if (err < 0) { puts("spl: ext4fs_read failed\n"); goto end; @@ -54,7 +54,7 @@ int spl_load_image_ext(struct spl_image_info *spl_image, goto end; } - err = ext4fs_read((char *)spl_image->load_addr, filelen, ); + err = ext4fs_read((char *)spl_image->load_addr, 0, filelen, ); end: #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT @@ -97,7 +97,7 @@ int spl_load_image_ext_os(struct spl_image_info *spl_image, puts("spl: ext4fs_open failed\n"); goto defaults; } - err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, filelen, ); + err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, 0, filelen, ); if (err < 0) { printf("spl: error reading image %s, err - %d, falling back to default\n", file, err); @@ -127,7 +127,7 @@ defaults: if (err < 0) puts("spl: ext4fs_open failed\n"); - err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, filelen, ); + err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, 0, filelen, ); if (err < 0) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT printf("%s: error reading image %s, err - %d\n", diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 3078737..7187dcf 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -65,8 +65,8 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, short status; /* Adjust len so it we can't read past the end of the file. */ - if (len > filesize) - len = filesize; + if (len + pos > filesize) + len = (filesize - pos); blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize); @@ -190,12 +190,12 @@ int ext4fs_size(const char *filename, loff_t *size) return ext4fs_open(filename, size); } -int ext4fs_read(char *buf, loff_t len, loff_t *actread) +int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread) { if (ext4fs_root == NULL || ext4fs_file == NULL) - return 0; + return -1; - return ext4fs_read_file(ext4fs_file, 0, len, buf, actread); + return ext4fs_read_file(ext4fs_file, offset, len, buf, actread); } int ext4fs_probe(struct blk_desc *fs_dev_desc, @@ -217,11 +217,6 @@ int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t file_len; int ret; - if (offset != 0) { - printf("** Cannot support non-zero offset **\n"); - return -1; - } - ret = ext4fs_open(filename, _len); if (ret < 0) { printf("** File not found %s **\n", filename); @@ -231,7 +226,7 @@ int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, if (len == 0) len = file_len; - return ext4fs_read(buf, len, len_read); + return ext4fs_read(buf, offset, len, len_read); } int ext4fs_uuid(char *uuid_str) diff --git a/include/ext4fs.h b/include/ext4fs.h index 965cd9e..bb55639 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -135,7 +135,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset, loff_t len, struct ext_filesystem *get_fs(void); int ext4fs_open(const char *filename, loff_t *len); -int ext4fs_read(char *buf, loff_t len, loff_t *actread); +int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread); int ext4fs_mount(unsigned part_length); void ext4fs_close(void); void ext4fs_reinit_global(void); -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/2] fs-test.sh: Update expected results
After the latest changes, ext4 no longer has any fails. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 6e71b61..b194864 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -10,13 +10,13 @@ # Expected results are as follows: # EXT4 tests: # fs-test.sb.ext4.out: Summary: PASS: 23 FAIL: 0 -# fs-test.ext4.out: Summary: PASS: 14 FAIL: 9 -# fs-test.fs.ext4.out: Summary: PASS: 14 FAIL: 9 +# fs-test.ext4.out: Summary: PASS: 23 FAIL: 0 +# fs-test.fs.ext4.out: Summary: PASS: 23 FAIL: 0 # FAT tests: # fs-test.sb.fat.out: Summary: PASS: 23 FAIL: 0 # fs-test.fat.out: Summary: PASS: 20 FAIL: 3 # fs-test.fs.fat.out: Summary: PASS: 20 FAIL: 3 -# Total Summary: TOTAL PASS: 114 TOTAL FAIL: 24 +# Total Summary: TOTAL PASS: 132 TOTAL FAIL: 6 # pre-requisite binaries list. PREREQ_BINS="md5sum mkfs mount umount dd fallocate mkdir" -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/2] ext4: Allow reading files with non-zero offset, clamp read len
Support was already implemented, but not hooked up. This fixes several fails in the test cases. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4fs.c | 15 +-- include/ext4fs.h | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 3078737..f8cf6cd 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -190,12 +190,12 @@ int ext4fs_size(const char *filename, loff_t *size) return ext4fs_open(filename, size); } -int ext4fs_read(char *buf, loff_t len, loff_t *actread) +int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread) { if (ext4fs_root == NULL || ext4fs_file == NULL) return 0; - return ext4fs_read_file(ext4fs_file, 0, len, buf, actread); + return ext4fs_read_file(ext4fs_file, offset, len, buf, actread); } int ext4fs_probe(struct blk_desc *fs_dev_desc, @@ -217,21 +217,16 @@ int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t file_len; int ret; - if (offset != 0) { - printf("** Cannot support non-zero offset **\n"); - return -1; - } - ret = ext4fs_open(filename, _len); if (ret < 0) { printf("** File not found %s **\n", filename); return -1; } - if (len == 0) - len = file_len; + if ((len == 0) || (offset + len > file_len)) + len = (file_len - offset); - return ext4fs_read(buf, len, len_read); + return ext4fs_read(buf, offset, len, len_read); } int ext4fs_uuid(char *uuid_str) diff --git a/include/ext4fs.h b/include/ext4fs.h index 965cd9e..bb55639 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -135,7 +135,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset, loff_t len, struct ext_filesystem *get_fs(void); int ext4fs_open(const char *filename, loff_t *len); -int ext4fs_read(char *buf, loff_t len, loff_t *actread); +int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread); int ext4fs_mount(unsigned part_length); void ext4fs_close(void); void ext4fs_reinit_global(void); -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH] ext4: Fix handling of sparse files
A sparse file may have regions not mapped by any extents, at the start or at the end of the file, or anywhere between, thus not finding a matching extent region is never an error. Found by python filesystem tests. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 31 +++ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 4248ac1..bfebe7e 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -1617,12 +1617,13 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) - get_fs()->dev_desc->log2blksz; if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { + long int startblock, endblock; char *buf = zalloc(blksz); if (!buf) return -ENOMEM; struct ext4_extent_header *ext_block; struct ext4_extent *extent; - int i = -1; + int i; ext_block = ext4fs_get_extent_block(ext4fs_root, buf, (struct ext4_extent_header *) @@ -1636,28 +1637,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) extent = (struct ext4_extent *)(ext_block + 1); - do { - i++; - if (i >= le16_to_cpu(ext_block->eh_entries)) - break; - } while (fileblock >= le32_to_cpu(extent[i].ee_block)); - if (--i >= 0) { - fileblock -= le32_to_cpu(extent[i].ee_block); - if (fileblock >= le16_to_cpu(extent[i].ee_len)) { + for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) { + startblock = le32_to_cpu(extent[i].ee_block); + endblock = startblock + le16_to_cpu(extent[i].ee_len); + + if (startblock > fileblock) { + /* Sparse file */ free(buf); return 0; - } - start = le16_to_cpu(extent[i].ee_start_hi); - start = (start << 32) + + } else if (fileblock < endblock) { + start = le16_to_cpu(extent[i].ee_start_hi); + start = (start << 32) + le32_to_cpu(extent[i].ee_start_lo); - free(buf); - return fileblock + start; + free(buf); + return (fileblock - startblock) + start; + } } - printf("Extent Error\n"); free(buf); - return -1; + return 0; } /* Direct blocks. */ -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/3] test/py: expose config and log as session scoped fixture
If a test uses a fixture which is expensive to setup, the fixture can possibly created with session or module scope. As u_boot_console has function scope, it can not be used in this case. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/conftest.py | 26 ++ 1 file changed, 26 insertions(+) diff --git a/test/py/conftest.py b/test/py/conftest.py index 1f15e3e..65e1d75 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -298,6 +298,32 @@ def pytest_generate_tests(metafunc): continue generate_config(metafunc, fn) +@pytest.fixture(scope='session') +def u_boot_log(request): + """Generate the value of a test's log fixture. + + Args: + request: The pytest request. + + Returns: + The fixture value. + """ + + return console.log + +@pytest.fixture(scope='session') +def u_boot_config(request): + """Generate the value of a test's u_boot_config fixture. + + Args: + request: The pytest request. + + Returns: + The fixture value. + """ + + return console.config + @pytest.fixture(scope='function') def u_boot_console(request): """Generate the value of a test's u_boot_console fixture. -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/3] test/py: Allow to pass u_boot_log instead of console for run_and_log
The runner actually has no console dependency, only on the log provided by the console. Accept both u_boot_console or a multiplexed_log. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/u_boot_utils.py | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py index 2ba4bae..c80cf07 100644 --- a/test/py/u_boot_utils.py +++ b/test/py/u_boot_utils.py @@ -153,7 +153,7 @@ def wait_until_file_open_fails(fn, ignore_errors): return raise Exception('File can still be opened') -def run_and_log(u_boot_console, cmd, ignore_errors=False): +def run_and_log(u_boot_console_or_log, cmd, ignore_errors=False): """Run a command and log its output. Args: @@ -171,7 +171,10 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False): """ if isinstance(cmd, str): cmd = cmd.split() -runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) +try: +runner = u_boot_console_or_log.get_runner(cmd[0], sys.stdout) +except: +runner = u_boot_console_or_log.log.get_runner(cmd[0], sys.stdout) output = runner.run(cmd, ignore_errors=ignore_errors) runner.close() return output @@ -189,7 +192,10 @@ def run_and_log_expect_exception(u_boot_console, cmd, retcode, msg): msg: String that should be contained within the command's output. """ try: +runner = u_boot_console.get_runner(cmd[0], sys.stdout) +except: runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) +try: runner.run(cmd) except Exception as e: assert(retcode == runner.exit_status) -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 3/3] test/py: Create tests for ext4 and fat testing on sandbox
The following checks are currently implemented: 1. listing a directory 2. verifying size of a file 3. veryfying md5sum for a file region 4. reading the beginning of a file Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/tests/test_fs.py | 298 +++ 1 file changed, 298 insertions(+) create mode 100644 test/py/tests/test_fs.py diff --git a/test/py/tests/test_fs.py b/test/py/tests/test_fs.py new file mode 100644 index 000..5ac91e4 --- /dev/null +++ b/test/py/tests/test_fs.py @@ -0,0 +1,298 @@ +# Copyright (c) 2016, Stefan Bruens <stefan.bru...@rwth-aachen.de> +# +# SPDX-License-Identifier: GPL-2.0 + +# Test U-Boot's filesystem implementations + +import hashlib +import pytest +import os +import random +import re +import u_boot_utils as util + + +mkfs_opts = { + "fat" :'-t vfat', + "ext4" : '-t ext4 -F', +} + +fs_commands = { + "fat" : { + 'listcmd' : 'ls', + 'readcmd' : 'load', + 'sizecmd' : 'size', + 'writecmd' : 'size', + }, + "ext4" : { + 'listcmd' : 'ls', + 'readcmd' : 'load', + 'sizecmd' : 'size', + 'writecmd' : 'size', + }, +} + +cmd_parameters = { + "hostfs" : { + 'prefix': 'host ', + 'interface' : 'hostfs -', + }, + "generic" : { + 'prefix': '', + 'interface' : 'host 0:0', + }, +} + +files = { +"empty.file" : [(0, 0)], +"1MB.file" : [(0, 1e6)], +"1MB.sparse.file" : [(1e6-1, 1e6)], +} +# "2_5GB.sparse.file" : [(0, 1e6), (1e9, 1e9+1e6), (2.5e9-1e6, 2.5e9)], + +@pytest.fixture(scope="session") +def prereq_commands(): +from distutils.spawn import find_executable +for command in ["mkfs", "mount", "umount"]: +if find_executable(command) is None: +pytest.skip('Filesystem tests, "{0}" not in PATH'.format(command)) + +class FsImage: +def __init__(self, fstype, imagename, mountpath): +self.fstype = fstype +self.imagename = imagename +self.mountpath = mountpath +self.md5s = {} +with open(self.imagename, 'w') as fd: +fd.truncate(0) +fd.seek(3e9) +fd.write(bytes([0])) + +def mkfs(self, log): +mkfsopts = mkfs_opts.get(self.fstype) +util.run_and_log(log, +'mkfs {0} {1}'.format(mkfsopts, self.imagename)) + +def create_file(self, log, filename): +md5sums = [] +with open(self.mountpath + "/" + filename, 'w') as fd: +for stride in files[filename]: +length = int(stride[1] - stride[0]) +data = bytearray(random.getrandbits(8) for _ in xrange(length)) +md5 = hashlib.md5(data).hexdigest() +md5sums.append(md5) +log.info("{0}: write {1} bytes @ {2} : {3}".format( +filename, int(stride[1] - stride[0]), +int(stride[0]), md5)) +fd.seek(stride[0]) +fd.write(data); +self.md5s[filename] = md5sums + +def create_files(self, log): +with log.section("Create initial files"): +for filename in files: +self.create_file(log, filename) +log.info("Created test files in {0}".format(self.mountpath)) +util.run_and_log(log, 'ls -la {0}'.format(self.mountpath)) +util.run_and_log(log, 'sync {0}'.format(self.mountpath)) + +def mount(self, log): +if not os.path.exists(self.mountpath): +os.mkdir(self.mountpath) +log.info("Mounting {0} at {1}".format(self.imagename, self.mountpath)) +if self.fstype == "ext4": +cmd = 'sudo -n mount -o loop,rw {0} {1}'.format(self.imagename, self.mountpath) +else: +cmd = 'sudo -n mount -o loop,rw,umask=000 {0} {1}'.format(self.imagename, self.mountpath) +util.run_and_log(log, cmd) +if self.fstype == "ext4": +cmd = 'sudo -n chmod og+rw {0}'.format(self.mountpath) +return util.run_and_log(log, cmd) + +def unmount(self, log): +log.info("Unmounting {0}".format(self.imagename)) +cmd = 'sudo -n umount -l {0}'.format(self.mountpath) +util.run_and_log(log, cmd, ignore_errors=True) + + +@pytest.fixture(scope="module", params=["fat", "ext4"]) +def fsimage(prereq_commands, u_boot_config, u_boot_log, request): +datadir = u_boot_config.result_dir + '/' +fstype = request.param +imagename = datadir + "3GB." + fstype + ".img" +mountpath = datadir + &q
[U-Boot] [PATCH 0/3] Create python filesystem tests
This is a first attempt to create filesystem tests in python. It is currently targetting sandbox, although it should be possible to make it work with e.g. the qemu based testruns. First two patches are prep work, first patch is copied verbatim from a mail from Stephen Warren. The actual tests are in patch 3. CUrrently it is a subset of what can be tested with the old shell script, most importantly no write tests. The following tests are currently implemented: 1. Listing a directory and checking for a set of files 2. Verifying the size of a file 3. Verifying the md5sums of specified regions of a file 4. Reading the head of a file 3. and 4. have some overlap, but the latter will also read sparse file regions. As the old test, some parts need root privileges to mount the image. Stefan Brüns (3): test/py: expose config and log as session scoped fixture test/py: Allow to pass u_boot_log instead of console for run_and_log test/py: Create tests for ext4 and fat testing on sandbox test/py/conftest.py | 26 + test/py/tests/test_fs.py | 298 +++ test/py/u_boot_utils.py | 10 +- 3 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 test/py/tests/test_fs.py -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH] tools: add mksunxiboot to tools-all target
mksunxiboot is useful outside of u-boot, it is e.g. used by sunxi-tools. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- tools/Makefile | 1 + tools/mksunxiboot.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/Makefile b/tools/Makefile index e6f7993..8e6dede 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -13,6 +13,7 @@ CONFIG_CMD_NET = y CONFIG_XWAY_SWAP_BYTES = y CONFIG_NETCONSOLE = y CONFIG_SHA1_CHECK_UB_IMG = y +CONFIG_SUNXI = y endif subdir-$(HOST_TOOLS_ALL) += easylogo diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c index 9c1c5b7..0f0b003 100644 --- a/tools/mksunxiboot.c +++ b/tools/mksunxiboot.c @@ -15,7 +15,7 @@ #include #include #include -#include "asm/arch/spl.h" +#include "../arch/arm/include/asm/arch-sunxi/spl.h" #define STAMP_VALUE 0x5F0A6C39 -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH] test/py: Fix exception, do not parametrize with empty set
If the parameter set is empty, the pytest setup fails: --- call: --- This aborts pytest_runtest_makereport and later leads to an exception during the report generation, as the call to log.start_section(...) is never executed: --- Exception: Block nesting mismatch: "test_dfu[env__usb_dev_port0-env__dfu_config0]" "" --- Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/py/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/py/conftest.py b/test/py/conftest.py index 5b3a923..ebef40d 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -270,6 +270,8 @@ def generate_config(metafunc, fixture_name): # ... otherwise, see if there's a key that contains a list of # values to use instead. vals = subconfig.get(fixture_name+ 's', []) +if len(vals) == 0: +return def fixture_id(index, val): try: return val['fixture_id'] -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH] cmd/tpm_test: Fix misleading code indentation
GCC 6.2 reasonably complains about the current code: ../cmd/tpm_test.c: In function ‘do_tpmtest’: ../cmd/tpm_test.c:540:3: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation] for (i = 0; i < argc; i++) ^~~ ../cmd/tpm_test.c:542:4: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘for’ printf("\n--\n"); ^~ Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- cmd/tpm_test.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index 65332d1..4af4d71 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -534,13 +534,12 @@ static int do_tpmtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) cmd_tbl_t *c; printf("argc = %d, argv = ", argc); - do { - int i = 0; - for (i = 0; i < argc; i++) - printf(" %s", argv[i]); - printf("\n--\n"); - } while (0); + for (int i = 0; i < argc; i++) + printf(" %s", argv[i]); + + printf("\n--\n"); + argc--; argv++; c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub, -- 2.10.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v4 2/7] efi_loader: Fix memory map size check to avoid out-of-bounds access
The current efi_get_memory_map() function overwrites the map_size property before reading its value. That way the sanity check whether our memory map fits into the given array always succeeds, potentially overwriting arbitrary payload memory. This patch moves the property update write after its sanity check, so that the check actually verifies the correct value. So far this has not triggered any known bugs, but we're better off safe than sorry. If the buffer is to small, the returned memory_map_size indicates the required size to the caller. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ebe8e94..1d23783 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -336,6 +336,7 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, ulong map_size = 0; int map_entries = 0; struct list_head *lhandle; + unsigned long provided_map_size = *memory_map_size; list_for_each(lhandle, _mem) map_entries++; @@ -350,7 +351,7 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (*memory_map_size < map_size) + if (provided_map_size < map_size) return EFI_BUFFER_TOO_SMALL; /* Copy list into array */ -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v4 4/7] efi_loader: Track size of pool allocations to allow freeing
We need a functional free_pool implementation, as otherwise each allocate_pool causes growth of the memory descriptor table. Different to free_pages, free_pool does not provide the size for the to be freed allocation, thus we have to track the size ourselves. As the only EFI requirement for pool allocation is an alignment of 8 bytes, we can keep allocating a range using the page allocator, reserve the first 8 bytes for our bookkeeping and hand out the remainder to the caller. This saves us from having to use any independent data structures for tracking. To simplify the conversion between pool allocations and the corresponding page allocation, we create an auxiliary struct efi_pool_allocation. Given the allocation size free_pool size can handoff freeing the page range, which was indirectly allocated by a call to allocate_pool, to free_pages. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 6 +++--- lib/efi_loader/efi_memory.c | 42 +++--- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index f0473ab..3dad24e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -122,6 +122,8 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); /* EFI memory allocator for small allocations */ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer); +/* EFI pool memory free function. */ +efi_status_t efi_free_pool(void *buffer); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index eb74cb0..8274d8e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -141,12 +141,12 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, return EFI_EXIT(r); } -static efi_status_t EFIAPI efi_free_pool(void *buffer) +static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) { efi_status_t r; EFI_ENTRY("%p", buffer); - r = efi_free_pages((ulong)buffer, 0); + r = efi_free_pool(buffer); return EFI_EXIT(r); } @@ -736,7 +736,7 @@ static const struct efi_boot_services efi_boot_services = { .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, - .free_pool = efi_free_pool, + .free_pool = efi_free_pool_ext, .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index be642f1..de28db6 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -34,6 +34,19 @@ void *efi_bounce_buffer; #endif /* + * U-Boot services each EFI AllocatePool request as a separate + * (multiple) page allocation. We have to track the number of pages + * to be able to free the correct amount later. + * EFI requires 8 byte alignment for pool allocations, so we can + * prepend each allocation with an 64 bit header tracking the + * allocation size, and hand out the remainder to the caller. + */ +struct efi_pool_allocation { + u64 num_pages; + char data[]; +}; + +/* * Sorts the memory list from highest address to lowest address * * When allocating memory we should always start from the highest @@ -332,11 +345,34 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, { efi_status_t r; efi_physical_addr_t t; - u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + if (size == 0) { + *buffer = NULL; + return EFI_SUCCESS; + } r = efi_allocate_pages(0, pool_type, num_pages, ); - if (r == EFI_SUCCESS) - *buffer = (void *)(uintptr_t)t; + + if (r == EFI_SUCCESS) { + struct efi_pool_allocation *alloc = (void *)(uintptr_t)t; + alloc->num_pages = num_pages; + *buffer = alloc->data; + } + + return r; +} + +efi_status_t efi_free_pool(void *buffer) +{ + efi_status_t r; + struct efi_pool_allocation *alloc; + + alloc = container_of(buffer, struct efi_pool_allocation, data); + /* Sanity check, was the supplied address returned by allocate_pool */ + assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); + + r = efi_free_pages((uintptr_t)alloc, alloc->num_pages); return r; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v4 3/7] efi_loader: Move efi_allocate_pool implementation to efi_memory.c
We currently handle efi_allocate_pool() in our boot time service file. In the following patch, pool allocation will receive additional internal semantics that we should preserve inside efi_memory.c instead. As foundation for those changes, split the function into an externally facing efi_allocate_pool_ext() for use by payloads and an internal helper efi_allocate_pool() in efi_memory.c that handles the actual allocation. While at it, change the magic 0xfff / 12 constants to the more obvious EFI_PAGE_MASK/SHIFT defines. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 11 +-- lib/efi_loader/efi_memory.c | 14 ++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 9738835..f0473ab 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -119,6 +119,9 @@ efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages, uint64_t *memory); /* EFI memory free function. Not implemented today */ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); +/* EFI memory allocator for small allocations */ +efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + void **buffer); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 784891b..eb74cb0 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -130,15 +130,14 @@ efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size, return EFI_EXIT(r); } -static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, -void **buffer) +static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, +unsigned long size, +void **buffer) { efi_status_t r; - efi_physical_addr_t t; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, ); - *buffer = (void *)(uintptr_t)t; + r = efi_allocate_pool(pool_type, size, buffer); return EFI_EXIT(r); } @@ -736,7 +735,7 @@ static const struct efi_boot_services efi_boot_services = { .allocate_pages = efi_allocate_pages_ext, .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, - .allocate_pool = efi_allocate_pool, + .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool, .create_event = efi_create_event, .set_timer = efi_set_timer, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 1d23783..be642f1 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -327,6 +327,20 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) return EFI_SUCCESS; } +efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + void **buffer) +{ + efi_status_t r; + efi_physical_addr_t t; + u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + r = efi_allocate_pages(0, pool_type, num_pages, ); + if (r == EFI_SUCCESS) + *buffer = (void *)(uintptr_t)t; + + return r; +} + efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, unsigned long *map_key, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/3] ext4: cleanup unlink_filename function
Use the same variable names as in search_dir, to make purpose of variables more obvious. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 29 +++-- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index e78185b..699a640 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -854,34 +854,35 @@ fail: static int unlink_filename(char *filename, unsigned int blknr) { - int totalbytes = 0; int templength = 0; int status, inodeno; int found = 0; - char *root_first_block_buffer = NULL; + int offset; + char *block_buffer = NULL; struct ext2_dirent *dir = NULL; struct ext2_dirent *previous_dir = NULL; char *ptr = NULL; struct ext_filesystem *fs = get_fs(); int ret = -1; - /* get the first block of root */ - root_first_block_buffer = zalloc(fs->blksz); - if (!root_first_block_buffer) + block_buffer = zalloc(fs->blksz); + if (!block_buffer) return -ENOMEM; + + /* read the directory block */ status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, - fs->blksz, root_first_block_buffer); + fs->blksz, block_buffer); if (status == 0) goto fail; - if (ext4fs_log_journal(root_first_block_buffer, blknr)) + if (ext4fs_log_journal(block_buffer, blknr)) goto fail; - dir = (struct ext2_dirent *)root_first_block_buffer; + dir = (struct ext2_dirent *)block_buffer; ptr = (char *)dir; - totalbytes = 0; + offset = 0; while (le16_to_cpu(dir->direntlen) >= 0) { /* -* blocksize-totalbytes because last +* blocksize-offset because last * directory length i.e., *dir->direntlen * is free availble space in the block that * means it is a last entry of directory entry @@ -903,12 +904,12 @@ static int unlink_filename(char *filename, unsigned int blknr) break; } - if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) + if (fs->blksz - offset == le16_to_cpu(dir->direntlen)) break; /* traversing the each directory entry */ templength = le16_to_cpu(dir->direntlen); - totalbytes = totalbytes + templength; + offset = offset + templength; previous_dir = dir; dir = (struct ext2_dirent *)((char *)dir + templength); ptr = (char *)dir; @@ -916,12 +917,12 @@ static int unlink_filename(char *filename, unsigned int blknr) if (found == 1) { - if (ext4fs_put_metadata(root_first_block_buffer, blknr)) + if (ext4fs_put_metadata(block_buffer, blknr)) goto fail; ret = inodeno; } fail: - free(root_first_block_buffer); + free(block_buffer); return ret; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/3] ext4: Fix handling of direntlen in unlink_filename
The direntlen checks were quite bogus, i.e. the loop termination used "len + offset == blocksize" (exact match only), and checked for a direntlen less than 0. The latter can never happen as the len is unsigned, this has been reported by Coverity, CID 153384. Use the same code as in search_dir for directory traversal. This code has the correct checks for direntlen >= sizeof(struct dirent), and offset < blocksize. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 45 + 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 699a640..11be0b7 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -854,16 +854,15 @@ fail: static int unlink_filename(char *filename, unsigned int blknr) { - int templength = 0; - int status, inodeno; - int found = 0; + int status; + int inodeno = 0; int offset; char *block_buffer = NULL; struct ext2_dirent *dir = NULL; - struct ext2_dirent *previous_dir = NULL; - char *ptr = NULL; + struct ext2_dirent *previous_dir; struct ext_filesystem *fs = get_fs(); int ret = -1; + char *direntname; block_buffer = zalloc(fs->blksz); if (!block_buffer) @@ -877,20 +876,18 @@ static int unlink_filename(char *filename, unsigned int blknr) if (ext4fs_log_journal(block_buffer, blknr)) goto fail; - dir = (struct ext2_dirent *)block_buffer; - ptr = (char *)dir; offset = 0; - while (le16_to_cpu(dir->direntlen) >= 0) { - /* -* blocksize-offset because last -* directory length i.e., *dir->direntlen -* is free availble space in the block that -* means it is a last entry of directory entry -*/ + do { + previous_dir = dir; + dir = (struct ext2_dirent *)(block_buffer + offset); + direntname = (char *)(dir) + sizeof(struct ext2_dirent); + + int direntlen = le16_to_cpu(dir->direntlen); + if (direntlen < sizeof(struct ext2_dirent)) + break; + if (dir->inode && (strlen(filename) == dir->namelen) && - (strncmp(ptr + sizeof(struct ext2_dirent), -filename, dir->namelen) == 0)) { - printf("file found, deleting\n"); + (strncmp(direntname, filename, dir->namelen) == 0)) { inodeno = le32_to_cpu(dir->inode); if (previous_dir) { uint16_t new_len; @@ -900,23 +897,15 @@ static int unlink_filename(char *filename, unsigned int blknr) } else { dir->inode = 0; } - found = 1; break; } - if (fs->blksz - offset == le16_to_cpu(dir->direntlen)) - break; + offset += direntlen; - /* traversing the each directory entry */ - templength = le16_to_cpu(dir->direntlen); - offset = offset + templength; - previous_dir = dir; - dir = (struct ext2_dirent *)((char *)dir + templength); - ptr = (char *)dir; - } + } while (offset < fs->blksz); + if (inodeno > 0) { - if (found == 1) { if (ext4fs_put_metadata(block_buffer, blknr)) goto fail; ret = inodeno; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/3] ext4: cleanup/fix unlink_filename function
This patch series addresses Coverity defects CID 153383/153384. The first patch is a preparation patch, the second addresses the actual issue. The last patch corrects the journal handling in the same function. Stefan Brüns (3): ext4: cleanup unlink_filename function ext4: Fix handling of direntlen in unlink_filename ext4: Only write journal entries for modified blocks in unlink_filename fs/ext4/ext4_common.c | 87 +++ 1 file changed, 40 insertions(+), 47 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 3/3] ext4: Only write journal entries for modified blocks in unlink_filename
Instead of creating a journal entry for each directory block, even if the block is unmodified, only log the modified block. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 11be0b7..ec02eec 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -874,8 +874,6 @@ static int unlink_filename(char *filename, unsigned int blknr) if (status == 0) goto fail; - if (ext4fs_log_journal(block_buffer, blknr)) - goto fail; offset = 0; do { previous_dir = dir; @@ -889,14 +887,6 @@ static int unlink_filename(char *filename, unsigned int blknr) if (dir->inode && (strlen(filename) == dir->namelen) && (strncmp(direntname, filename, dir->namelen) == 0)) { inodeno = le32_to_cpu(dir->inode); - if (previous_dir) { - uint16_t new_len; - new_len = le16_to_cpu(previous_dir->direntlen); - new_len += le16_to_cpu(dir->direntlen); - previous_dir->direntlen = cpu_to_le16(new_len); - } else { - dir->inode = 0; - } break; } @@ -905,7 +895,20 @@ static int unlink_filename(char *filename, unsigned int blknr) } while (offset < fs->blksz); if (inodeno > 0) { + printf("file found, deleting\n"); + if (ext4fs_log_journal(block_buffer, blknr)) + goto fail; + if (previous_dir) { + /* merge dir entry with predecessor */ + uint16_t new_len; + new_len = le16_to_cpu(previous_dir->direntlen); + new_len += le16_to_cpu(dir->direntlen); + previous_dir->direntlen = cpu_to_le16(new_len); + } else { + /* invalidate dir entry */ + dir->inode = 0; + } if (ext4fs_put_metadata(block_buffer, blknr)) goto fail; ret = inodeno; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 4/5] sandbox/fs: Set correct filetype for unknown filetype
The "hostfs ls" command prefixes each directory entry with either DIR, LNK or " " if it is a directory, symlink resp. regular file, or "???" for any other or unknown type. The latter only works if the type is set correctly, as the entry defaults to OS_FILET_REG and e.g. socket files show up as regular files. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Acked-by: Simon Glass <s...@chromium.org> --- arch/sandbox/cpu/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 16af3f5..df2bd4c 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -363,6 +363,8 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) case DT_LNK: next->type = OS_FILET_LNK; break; + default: + next->type = OS_FILET_UNKNOWN; } next->size = 0; snprintf(fname, len, "%s/%s", dirname, next->name); -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 5/7] efi_loader: Readd freed pages to memory pool
Currently each allocation creates a new mapping. Readding the mapping as free memory (EFI_CONVENTIONAL_MEMORY) potentially allows to hand out an existing mapping, thus limiting the number of mapping descriptors in the memory map. Mitigates a problem with current (4.8rc7) linux kernels when doing an efi_get_memory map, resulting in an infinite loop. Space for the memory map is reserved with allocate_pool (implicitly creating a new mapping) and filled. If there is insufficient slack space (8 entries) in the map, the space is freed and a new round is started, with space for one more entry. As each round increases requirement and allocation by exactly one, there is never enough slack space. (At least 32 entries are allocated, so as long as there are less than 24 entries, there is enough slack). Earlier kernels reserved no slack, and did less allocations, so this problem was not visible. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- include/efi_loader.h| 2 +- lib/efi_loader/efi_memory.c | 11 +-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 341d4a4..6d64f4b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -117,7 +117,7 @@ void *efi_alloc(uint64_t len, int memory_type); /* More specific EFI memory allocator, called by EFI payloads */ efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages, uint64_t *memory); -/* EFI memory free function. Not implemented today */ +/* EFI memory free function. */ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); /* EFI memory allocator for small allocations, called by EFI payloads */ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index fa5c639..7051948 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -335,8 +335,15 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) { - /* We don't free, let's cross our fingers we have plenty RAM */ - return EFI_SUCCESS; + uint64_t r = 0; + + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + /* Merging of adjacent free regions is missing */ + + if (r == memory) + return EFI_SUCCESS; + + return EFI_NOT_FOUND; } efi_status_t efi_allocate_pool(int pool_type, unsigned long size, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 7/7] efi_loader: Do not leak memory when unlinking a mapping
As soon as a mapping is unlinked from the list, there are no further references to it, so it should be freed. If it not unlinked, update the start address and length. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- lib/efi_loader/efi_memory.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 2bbf8eb..7e4ee01 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -115,10 +115,13 @@ static int efi_mem_carve_out(struct efi_mem_list *map, if (map_end == carve_end) { /* Full overlap, just remove map */ list_del(>link); + free(map); + } else { + map->desc.physical_start = carve_end; + map->desc.num_pages = (map_end - carve_end) + >> EFI_PAGE_SHIFT; } - map_desc->physical_start = carve_end; - map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; return (carve_end - carve_start) >> EFI_PAGE_SHIFT; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 0/6] efi_loader: implement BS.FreePages()/BS.FreePool, some cleanup
Linux 4.8 no longer boots, as it runs out of descriptor space. Readding the mapping allows reuse, and the next AllocatePool will likely not add a new mapping. Also fix some small issues found while debugging. v2, updated: efi_loader: Fix memory map size check to avoid out-of-bounds access - (Hopefully) clarified commit message efi_loader: Track size of pool allocations to allow freeing - rebased on top of 'efi_loader: Fix crash on 32-bit systems' - assert correct address in efi_free_pool - use EFI_PAGE_MASK instead of 0xfff, EFI_PAGE_SHIFT likewise v3, added: efi_loader: Move efi_allocate_pool implementation to efi_memory.c v3, updated: efi_loader: Fix memory map size check to avoid out-of-bounds access - set descriptor_size/_version even if EFI_BUFFER_TOO_SMALL efi_loader: Track size of pool allocations to allow freeing - use a struct instead of pointer arithmetic, add some comments Stefan Brüns (7): efi_loader: Update description of internal efi_mem_carve_out efi_loader: Fix memory map size check to avoid out-of-bounds access efi_loader: Move efi_allocate_pool implementation to efi_memory.c efi_loader: Track size of pool allocations to allow freeing efi_loader: Readd freed pages to memory pool efi_loader: Keep memory mapping sorted when splitting an entry efi_loader: Do not leak memory when unlinking a mapping include/efi_loader.h | 7 +++- lib/efi_loader/efi_boottime.c | 17 lib/efi_loader/efi_memory.c | 92 +-- 3 files changed, 95 insertions(+), 21 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 3/7] efi_loader: Move efi_allocate_pool implementation to efi_memory.c
Implementation essentially unchanged, but use EFI_PAGE_MASK/SHIFT instead of numeric constants. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 11 +-- lib/efi_loader/efi_memory.c | 11 +++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 9738835..40e7beb 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -119,6 +119,9 @@ efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages, uint64_t *memory); /* EFI memory free function. Not implemented today */ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); +/* EFI memory allocator for small allocations, called by EFI payloads */ +efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + void **buffer); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 784891b..eb74cb0 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -130,15 +130,14 @@ efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size, return EFI_EXIT(r); } -static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, -void **buffer) +static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, +unsigned long size, +void **buffer) { efi_status_t r; - efi_physical_addr_t t; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, ); - *buffer = (void *)(uintptr_t)t; + r = efi_allocate_pool(pool_type, size, buffer); return EFI_EXIT(r); } @@ -736,7 +735,7 @@ static const struct efi_boot_services efi_boot_services = { .allocate_pages = efi_allocate_pages_ext, .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, - .allocate_pool = efi_allocate_pool, + .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool, .create_event = efi_create_event, .set_timer = efi_set_timer, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5d71fdf..045558d 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -327,6 +327,17 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) return EFI_SUCCESS; } +efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + void **buffer) +{ + efi_status_t r; + efi_physical_addr_t t; + u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + r = efi_allocate_pages(0, pool_type, num_pages, ); + return EFI_EXIT(r); +} + efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, unsigned long *map_key, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 4/7] efi_loader: Track size of pool allocations to allow freeing
allocate_pool has to return a buffer which is 8-byte aligned. Shift the region returned by allocate_pages by 8 byte and store the size in the headroom. The 8 byte overhead is neglegible, but provides the required size when freeing the allocation later. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 6 +++--- lib/efi_loader/efi_memory.c | 40 +++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 40e7beb..341d4a4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -122,6 +122,8 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); /* EFI memory allocator for small allocations, called by EFI payloads */ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer); +/* EFI pool memory free function. */ +efi_status_t efi_free_pool(void *buffer); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index eb74cb0..8274d8e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -141,12 +141,12 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, return EFI_EXIT(r); } -static efi_status_t EFIAPI efi_free_pool(void *buffer) +static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) { efi_status_t r; EFI_ENTRY("%p", buffer); - r = efi_free_pages((ulong)buffer, 0); + r = efi_free_pool(buffer); return EFI_EXIT(r); } @@ -736,7 +736,7 @@ static const struct efi_boot_services efi_boot_services = { .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, - .free_pool = efi_free_pool, + .free_pool = efi_free_pool_ext, .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 045558d..fa5c639 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -34,6 +34,18 @@ void *efi_bounce_buffer; #endif /* + * U-Boot services each EFI AllocatePool request as a separate + * (multiple) page allocation. We have to track the number of pages + * to be able to free the correct amount later. + * EFI requires 8 byte alignement for pool allocations, so it is + * possible to reserve some headroom and serve the remainder. + */ +struct efi_pool_allocation { + u64 num_pages; + char data[]; +}; + +/* * Sorts the memory list from highest address to lowest address * * When allocating memory we should always start from the highest @@ -332,9 +344,35 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, { efi_status_t r; efi_physical_addr_t t; - u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + if (size == 0) { + *buffer = NULL; + return EFI_EXIT(EFI_SUCCESS); + } r = efi_allocate_pages(0, pool_type, num_pages, ); + + if (r == EFI_SUCCESS) { + struct efi_pool_allocation *alloc = (void *)(uintptr_t)t; + alloc->num_pages = num_pages; + *buffer = &(alloc->data); + assert(((uintptr_t)(*buffer) & 0x7) == 0); + } + + return EFI_EXIT(r); +} + +efi_status_t efi_free_pool(void *buffer) +{ + efi_status_t r; + struct efi_pool_allocation *alloc; + + alloc = container_of(buffer, struct efi_pool_allocation, data); + assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); + + r = efi_free_pages((uintptr_t)alloc, alloc->num_pages); + return EFI_EXIT(r); } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 1/7] efi_loader: Update description of internal efi_mem_carve_out
In 74c16acce30bb882ad5951829d8dafef8eea564c the return values where changed, but the description was kept. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 80e4e26..ebe8e94 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -62,9 +62,17 @@ static void efi_mem_sort(void) * Unmaps all memory occupied by the carve_desc region from the * list entry pointed to by map. * - * Returns 1 if carving was performed or 0 if the regions don't overlap. - * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set. - * Carving is only guaranteed to complete when all regions return 0. + * Returns EFI_CARVE_NO_OVERLAP if the regions don't overlap. + * Returns EFI_CARVE_OVERLAPS_NONRAM if the carve and map overlap, + *and the map contains anything but free ram. + *(only when overlap_only_ram is true) + * Returns EFI_CARVE_LOOP_AGAIN if the mapping list should be traversed + *again, as it has been altered + * Returns the number of overlapping pages. The pages are removed from + * the mapping list. + * + * In case of EFI_CARVE_OVERLAPS_NONRAM it is the callers responsibility + * to readd the already carved out pages to the mapping. */ static int efi_mem_carve_out(struct efi_mem_list *map, struct efi_mem_desc *carve_desc, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 6/7] efi_loader: Keep memory mapping sorted when splitting an entry
The code assumes sorted mappings in descending address order. When splitting a mapping, insert the new part next to the current mapping. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- lib/efi_loader/efi_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 7051948..2bbf8eb 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -134,7 +134,8 @@ static int efi_mem_carve_out(struct efi_mem_list *map, newmap->desc = map->desc; newmap->desc.physical_start = carve_start; newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT; -list_add_tail(>link, _mem); + /* Insert before current entry (descending address order) */ + list_add_tail(>link, >link); /* Shrink the map to [ map_start ... carve_start ] */ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v3 2/7] efi_loader: Fix memory map size check to avoid out-of-bounds access
Do not overwrite the specified size of the provided buffer without having checked it is sufficient. If the buffer is to small, memory_map_size is updated to indicate the required size, and an error code is returned. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ebe8e94..5d71fdf 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -342,16 +342,18 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, map_size = map_entries * sizeof(struct efi_mem_desc); - *memory_map_size = map_size; - if (descriptor_size) *descriptor_size = sizeof(struct efi_mem_desc); if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (*memory_map_size < map_size) + if (*memory_map_size < map_size) { + *memory_map_size = map_size; return EFI_BUFFER_TOO_SMALL; + } + + *memory_map_size = map_size; /* Copy list into array */ if (memory_map) { -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 4/5] sandbox/fs: Set correct filetype for unknown filetype
Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- arch/sandbox/cpu/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 16af3f5..df2bd4c 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -363,6 +363,8 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) case DT_LNK: next->type = OS_FILET_LNK; break; + default: + next->type = OS_FILET_UNKNOWN; } next->size = 0; snprintf(fname, len, "%s/%s", dirname, next->name); -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 5/5] sandbox/fs: Use readdir instead of deprecated readdir_r
Using readdir_r limits the maximum file name length and may even be unsafe, and is thus deprecated in since glibc 2.24. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- arch/sandbox/cpu/os.c | 19 +++ 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index df2bd4c..35ea00c 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -313,7 +313,7 @@ void os_dirent_free(struct os_dirent_node *node) int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) { - struct dirent entry, *result; + struct dirent *entry; struct os_dirent_node *head, *node, *next; struct stat buf; DIR *dir; @@ -337,12 +337,15 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) } for (node = head = NULL;; node = next) { - ret = readdir_r(dir, , ); - if (ret || !result) + errno = 0; + entry = readdir(dir); + if (!entry) { + ret = errno; break; - next = malloc(sizeof(*node) + strlen(entry.d_name) + 1); - if (dirlen + strlen(entry.d_name) > len) { - len = dirlen + strlen(entry.d_name); + } + next = malloc(sizeof(*node) + strlen(entry->d_name) + 1); + if (dirlen + strlen(entry->d_name) > len) { + len = dirlen + strlen(entry->d_name); fname = realloc(fname, len); } if (!next || !fname) { @@ -352,8 +355,8 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) goto done; } next->next = NULL; - strcpy(next->name, entry.d_name); - switch (entry.d_type) { + strcpy(next->name, entry->d_name); + switch (entry->d_type) { case DT_REG: next->type = OS_FILET_REG; break; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/5] Fix some trivial issues in sandbox/fs
Stefan Brüns (5): sandbox/fs: Free memory allocated by os_dirent_ls sandbox/fs: Make linking of nodes in os_dirent_ls more obvious sandbox/fs: Use correct size path name buffer sandbox/fs: Set correct filetype for unknown filetype sandbox/fs: Use readdir instead of deprecated readdir_r arch/sandbox/cpu/os.c | 34 +++--- fs/sandbox/sandboxfs.c | 1 + include/os.h | 11 ++- 3 files changed, 34 insertions(+), 12 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 3/5] sandbox/fs: Use correct size path name buffer
The readdir linux manpage explicitly states (quoting POSIX.1) that sizeof(d_name) is not correct for determining the required size, but to always use strlen. Grow the buffer if needed. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- arch/sandbox/cpu/os.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index c71882a..16af3f5 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -320,14 +320,16 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) int ret; char *fname; int len; + int dirlen; *headp = NULL; dir = opendir(dirname); if (!dir) return -1; - /* Create a buffer for the maximum filename length */ - len = sizeof(entry.d_name) + strlen(dirname) + 2; + /* Create a buffer upfront, with typically sufficient size */ + dirlen = strlen(dirname) + 2; + len = dirlen + 256; fname = malloc(len); if (!fname) { ret = -ENOMEM; @@ -339,7 +341,12 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) if (ret || !result) break; next = malloc(sizeof(*node) + strlen(entry.d_name) + 1); - if (!next) { + if (dirlen + strlen(entry.d_name) > len) { + len = dirlen + strlen(entry.d_name); + fname = realloc(fname, len); + } + if (!next || !fname) { + free(next); os_dirent_free(head); ret = -ENOMEM; goto done; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/5] sandbox/fs: Make linking of nodes in os_dirent_ls more obvious
Previously, after reading/creating the second dirent, the second entry would be chained to the first entry and the first entry would be linked to head. Instead, immediately link the first entry to head. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- arch/sandbox/cpu/os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 2d63dd8..c71882a 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -363,8 +363,8 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) next->size = buf.st_size; if (node) node->next = next; - if (!head) - head = node; + else + head = next; } *headp = head; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/5] sandbox/fs: Free memory allocated by os_dirent_ls
Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/sandbox/sandboxfs.c | 1 + include/os.h | 11 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/sandbox/sandboxfs.c b/fs/sandbox/sandboxfs.c index 2703eed..cd10fd6 100644 --- a/fs/sandbox/sandboxfs.c +++ b/fs/sandbox/sandboxfs.c @@ -94,6 +94,7 @@ int sandbox_fs_ls(const char *dirname) printf("%s %10lu %s\n", os_dirent_get_typename(node->type), node->size, node->name); } + os_dirent_free(head); return 0; } diff --git a/include/os.h b/include/os.h index 1782e50..049b248 100644 --- a/include/os.h +++ b/include/os.h @@ -215,9 +215,18 @@ struct os_dirent_node { int os_dirent_ls(const char *dirname, struct os_dirent_node **headp); /** + * Free directory list + * + * This frees a linked list containing a directory listing. + * + * @param node Pointer to head of linked list + */ +void os_dirent_free(struct os_dirent_node *node); + +/** * Get the name of a directory entry type * - * @param type Type to cehck + * @param type Type to check * @return string containing the name of that type, or "???" if none/invalid */ const char *os_dirent_get_typename(enum os_dirent_t type); -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 5/6] efi_loader: Keep memory mapping sorted when splitting an entry
The code assumes sorted mappings in descending address order. When splitting a mapping, insert the new part next to the current mapping. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- lib/efi_loader/efi_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 9c785dd..26a5d50 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -122,7 +122,8 @@ static int efi_mem_carve_out(struct efi_mem_list *map, newmap->desc = map->desc; newmap->desc.physical_start = carve_start; newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT; -list_add_tail(>link, _mem); + /* Insert before current entry (descending address order) */ + list_add_tail(>link, >link); /* Shrink the map to [ map_start ... carve_start ] */ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 3/6] efi_loader: Track size of pool allocations to allow freeing
allocate_pool has to return a buffer which is 8-byte aligned. Shift the region returned by allocate_pages by 8 byte and store the size in the headroom. The 8 byte overhead is neglegible, but provides the required size when freeing the allocation later. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_boottime.c | 24 +--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 784891b..c413ecb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -135,19 +135,37 @@ static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, { efi_status_t r; efi_physical_addr_t t; + u64 num_pages = (size + 8 + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, ); - *buffer = (void *)(uintptr_t)t; + + if (size == 0) { + *buffer = NULL; + return EFI_EXIT(EFI_SUCCESS); + } + + r = efi_allocate_pages(0, pool_type, num_pages, ); + + if (r == EFI_SUCCESS) { + *(u64 *)(uintptr_t)t = num_pages; + *buffer = (void *)(uintptr_t)(t + 8); + } + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_free_pool(void *buffer) { efi_status_t r; + u64 num_pages; EFI_ENTRY("%p", buffer); - r = efi_free_pages((ulong)buffer, 0); + + buffer = (char *)(buffer) - 8; + assert(((ulong)buffer & EFI_PAGE_MASK) == 0); + num_pages = *(u64 *)buffer; + + r = efi_free_pages((ulong)buffer, num_pages); return EFI_EXIT(r); } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 1/6] efi_loader: Update description of internal efi_mem_carve_out
In 74c16acce30bb882ad5951829d8dafef8eea564c the return values where changed, but the description was kept. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 80e4e26..ebe8e94 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -62,9 +62,17 @@ static void efi_mem_sort(void) * Unmaps all memory occupied by the carve_desc region from the * list entry pointed to by map. * - * Returns 1 if carving was performed or 0 if the regions don't overlap. - * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set. - * Carving is only guaranteed to complete when all regions return 0. + * Returns EFI_CARVE_NO_OVERLAP if the regions don't overlap. + * Returns EFI_CARVE_OVERLAPS_NONRAM if the carve and map overlap, + *and the map contains anything but free ram. + *(only when overlap_only_ram is true) + * Returns EFI_CARVE_LOOP_AGAIN if the mapping list should be traversed + *again, as it has been altered + * Returns the number of overlapping pages. The pages are removed from + * the mapping list. + * + * In case of EFI_CARVE_OVERLAPS_NONRAM it is the callers responsibility + * to readd the already carved out pages to the mapping. */ static int efi_mem_carve_out(struct efi_mem_list *map, struct efi_mem_desc *carve_desc, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 2/6] efi_loader: Fix memory map size check to avoid out-of-bounds access
Do not overwrite the specified size of the provided buffer without having checked it is sufficient. If the buffer is to small, memory_map_size is updated to indicate the required size, and an error code is returned. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ebe8e94..72a5870 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -342,6 +342,11 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, map_size = map_entries * sizeof(struct efi_mem_desc); + if (*memory_map_size < map_size) { + *memory_map_size = map_size; + return EFI_BUFFER_TOO_SMALL; + } + *memory_map_size = map_size; if (descriptor_size) @@ -350,9 +355,6 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (*memory_map_size < map_size) - return EFI_BUFFER_TOO_SMALL; - /* Copy list into array */ if (memory_map) { /* Return the list in ascending order */ -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 4/6] efi_loader: Readd freed pages to memory pool
Currently each allocation creates a new mapping. Readding the mapping as free memory (EFI_CONVENTIONAL_MEMORY) potentially allows to hand out an existing mapping, thus limiting the number of mapping descriptors in the memory map. Mitigates a problem with current (4.8rc7) linux kernels when doing an efi_get_memory map, resulting in an infinite loop. Space for the memory map is reserved with allocate_pool (implicitly creating a new mapping) and filled. If there is insufficient slack space (8 entries) in the map, the space is freed and a new round is started, with space for one more entry. As each round increases requirement and allocation by exactly one, there is never enough slack space. (At least 32 entries are allocated, so as long as there are less than 24 entries, there is enough slack). Earlier kernels reserved no slack, and did less allocations, so this problem was not visible. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- lib/efi_loader/efi_memory.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 72a5870..9c785dd 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -323,8 +323,15 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) { - /* We don't free, let's cross our fingers we have plenty RAM */ - return EFI_SUCCESS; + uint64_t r = 0; + + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + /* Merging of adjacent free regions is missing */ + + if (r == memory) + return EFI_SUCCESS; + + return EFI_NOT_FOUND; } efi_status_t efi_get_memory_map(unsigned long *memory_map_size, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 6/6] efi_loader: Do not leak memory when unlinking a mapping
As soon as a mapping is unlinked from the list, there are no further references to it, so it should be freed. If it not unlinked, update the start address and length. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Alexander Graf <ag...@suse.de> --- lib/efi_loader/efi_memory.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 26a5d50..000e776 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -103,10 +103,13 @@ static int efi_mem_carve_out(struct efi_mem_list *map, if (map_end == carve_end) { /* Full overlap, just remove map */ list_del(>link); + free(map); + } else { + map->desc.physical_start = carve_end; + map->desc.num_pages = (map_end - carve_end) + >> EFI_PAGE_SHIFT; } - map_desc->physical_start = carve_end; - map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; return (carve_end - carve_start) >> EFI_PAGE_SHIFT; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 0/6] efi_loader: implement BS.FreePages()/BS.FreePool, some cleanup
Linux 4.8 no longer boots, as it runs out of descriptor space. Readding the mapping allows reuse, and the next AllocatePool will likely not add a new mapping. Also fix some small issues found while debugging. v2, updated: efi_loader: Fix memory map size check to avoid out-of-bounds access - (Hopefully) clarified commit message efi_loader: Track size of pool allocations to allow freeing - rebased on top of 'efi_loader: Fix crash on 32-bit systems' - assert correct address in efi_free_pool - use EFI_PAGE_MASK instead of 0xfff, EFI_PAGE_SHIFT likewise Stefan Brüns (6): efi_loader: Update description of internal efi_mem_carve_out efi_loader: Fix memory map size check to avoid out-of-bounds access efi_loader: Track size of pool allocations to allow freeing efi_loader: Readd freed pages to memory pool efi_loader: Keep memory mapping sorted when splitting an entry efi_loader: Do not leak memory when unlinking a mapping lib/efi_loader/efi_boottime.c | 24 +--- lib/efi_loader/efi_memory.c | 43 --- 2 files changed, 53 insertions(+), 14 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 6/6] efi_loader: Do not leak memory when unlinking a mapping
As soon as a mapping is unlinked from the list, there are no further references to it, so it should be freed. If it not unlinked, update the start address and length. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 0fcfb7a..6d8fae4 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -103,10 +103,13 @@ static int efi_mem_carve_out(struct efi_mem_list *map, if (map_end == carve_end) { /* Full overlap, just remove map */ list_del(>link); + free(map); + } else { + map->desc.physical_start = carve_end; + map->desc.num_pages = (map_end - carve_end) + >> EFI_PAGE_SHIFT; } - map_desc->physical_start = carve_end; - map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; return (carve_end - carve_start) >> EFI_PAGE_SHIFT; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/6] efi_loader: Fix memory map size check to avoid out-of-bounds access
memory_map_size as IN parameter specifies the size of the provided buffer. If the buffer is to small, memory_map_size is updated to indicate the required size, and an error code is returned. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ebe8e94..5d71fdf 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -342,16 +342,18 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, map_size = map_entries * sizeof(struct efi_mem_desc); - *memory_map_size = map_size; - if (descriptor_size) *descriptor_size = sizeof(struct efi_mem_desc); if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (*memory_map_size < map_size) + if (*memory_map_size < map_size) { + *memory_map_size = map_size; return EFI_BUFFER_TOO_SMALL; + } + + *memory_map_size = map_size; /* Copy list into array */ if (memory_map) { -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/6] efi_loader: Update description of internal efi_mem_carve_out
In 74c16acce30bb882ad5951829d8dafef8eea564c the return values where changed, but the description was kept. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 80e4e26..ebe8e94 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -62,9 +62,17 @@ static void efi_mem_sort(void) * Unmaps all memory occupied by the carve_desc region from the * list entry pointed to by map. * - * Returns 1 if carving was performed or 0 if the regions don't overlap. - * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set. - * Carving is only guaranteed to complete when all regions return 0. + * Returns EFI_CARVE_NO_OVERLAP if the regions don't overlap. + * Returns EFI_CARVE_OVERLAPS_NONRAM if the carve and map overlap, + *and the map contains anything but free ram. + *(only when overlap_only_ram is true) + * Returns EFI_CARVE_LOOP_AGAIN if the mapping list should be traversed + *again, as it has been altered + * Returns the number of overlapping pages. The pages are removed from + * the mapping list. + * + * In case of EFI_CARVE_OVERLAPS_NONRAM it is the callers responsibility + * to readd the already carved out pages to the mapping. */ static int efi_mem_carve_out(struct efi_mem_list *map, struct efi_mem_desc *carve_desc, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 5/6] efi_loader: Keep memory mapping sorted when splitting an entry
The code assumes sorted mappings in descending address order. When splitting a mapping, insert the new part next to the current mapping. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 763b79f..0fcfb7a 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -122,7 +122,8 @@ static int efi_mem_carve_out(struct efi_mem_list *map, newmap->desc = map->desc; newmap->desc.physical_start = carve_start; newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT; -list_add_tail(>link, _mem); + /* Insert before current entry (descending address order) */ + list_add_tail(>link, >link); /* Shrink the map to [ map_start ... carve_start ] */ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/6] efi_loader: implement BS.FreePages()/BS.FreePool, some cleanup
Linux 4.8 no longer boots, as it runs out of descriptor space. Readding the mapping allows reuse, and the next AllocatePool will likely not add a new mapping. Also fix some small issues found while debugging. Stefan Brüns (6): efi_loader: Update description of internal efi_mem_carve_out efi_loader: Fix memory map size check to avoid out-of-bounds access efi_loader: Track size of pool allocations to allow freeing efi_loader: Readd freed pages to memory pool efi_loader: Keep memory mapping sorted when splitting an entry efi_loader: Do not leak memory when unlinking a mapping lib/efi_loader/efi_boottime.c | 21 +++-- lib/efi_loader/efi_memory.c | 43 --- 2 files changed, 51 insertions(+), 13 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 3/6] efi_loader: Track size of pool allocations to allow freeing
allocate_pool has to return a buffer which is 8-byte aligned. Shift the region returned by allocate_pages by 8 byte and store the size in the headroom. The 8 byte overhead is neglegible, but provides the required size when freeing the allocation later. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_boottime.c | 21 +++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index be6f5e8..3e526eb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -134,18 +134,35 @@ static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, void **buffer) { efi_status_t r; + u64 num_pages = (size + 8 + 0xfff) >> 12; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer); + + if (size == 0) { + *buffer = NULL; + return EFI_EXIT(EFI_SUCCESS); + } + + r = efi_allocate_pages(0, pool_type, num_pages, (void *)buffer); + if (r == EFI_SUCCESS) { + *(u64 *)(*buffer) = num_pages; + *buffer = (char *)(*buffer) + 8; + } + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_free_pool(void *buffer) { efi_status_t r; + u64 num_pages; EFI_ENTRY("%p", buffer); - r = efi_free_pages((ulong)buffer, 0); + + buffer = (char *)(buffer) - 8; + num_pages = *(u64 *)buffer; + + r = efi_free_pages((ulong)buffer, num_pages); return EFI_EXIT(r); } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 4/6] efi_loader: Readd freed pages to memory pool
Currently each allocation creates a new mapping. Readding the mapping as free memory (EFI_CONVENTIONAL_MEMORY) potentially allows to hand out an existing mapping, thus limiting the number of mapping descriptors in the memory map. Mitigates a problem with current (4.8rc7) linux kernels when doing an efi_get_memory map, resulting in an infinite loop. Space for the memory map is reserved with allocate_pool (implicitly creating a new mapping) and filled. If there is insufficient slack space (8 entries) in the map, the space is freed and a new round is started, with space for one more entry. As each round increases requirement and allocation by exactly one, there is never enough slack space. (At least 32 entries are allocated, so as long as there are less than 24 entries, there is enough slack). Earlier kernels reserved no slack, and did less allocations, so this problem was not visible. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- lib/efi_loader/efi_memory.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5d71fdf..763b79f 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -323,8 +323,15 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) { - /* We don't free, let's cross our fingers we have plenty RAM */ - return EFI_SUCCESS; + uint64_t r = 0; + + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + /* Merging of adjacent free regions is missing */ + + if (r == memory) + return EFI_SUCCESS; + + return EFI_NOT_FOUND; } efi_status_t efi_get_memory_map(unsigned long *memory_map_size, -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 6/7] ext4: Respect group descriptor size when adjusting free counts
Also adjust high 16/32 bits when free inode/block counts are modified. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- v2: rebase on last version of ext4 endian fixes fs/ext4/ext4_common.c | 53 +++ fs/ext4/ext4_write.c | 40 ++ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 90e7602..1336068 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -60,22 +60,51 @@ static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb) static inline void ext4fs_sb_free_blocks_dec(struct ext2_sblock *sb) { - sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) - 1); + uint64_t free_blocks = le32_to_cpu(sb->free_blocks); + free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32; + free_blocks--; + + sb->free_blocks = cpu_to_le32(free_blocks & 0x); + sb->free_blocks_high = cpu_to_le16(free_blocks >> 32); } -static inline void ext4fs_bg_free_inodes_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_free_inodes_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) - 1); + uint32_t free_inodes = le16_to_cpu(bg->free_inodes); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->free_inodes_high) << 16; + free_inodes--; + + bg->free_inodes = cpu_to_le16(free_inodes & 0x); + if (fs->gdsize == 64) + bg->free_inodes_high = cpu_to_le16(free_inodes >> 16); } -static inline void ext4fs_bg_free_blocks_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_free_blocks_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) - 1); + uint32_t free_blocks = le16_to_cpu(bg->free_blocks); + if (fs->gdsize == 64) + free_blocks += le16_to_cpu(bg->free_blocks_high) << 16; + free_blocks--; + + bg->free_blocks = cpu_to_le16(free_blocks & 0x); + if (fs->gdsize == 64) + bg->free_blocks_high = cpu_to_le16(free_blocks >> 16); } -static inline void ext4fs_bg_itable_unused_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_itable_unused_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->bg_itable_unused = cpu_to_le16(le16_to_cpu(bg->bg_itable_unused) - 1); + uint32_t free_inodes = le16_to_cpu(bg->bg_itable_unused); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->bg_itable_unused_high) << 16; + free_inodes--; + + bg->bg_itable_unused = cpu_to_le16(free_inodes & 0x); + if (fs->gdsize == 64) + bg->bg_itable_unused_high = cpu_to_le16(free_inodes >> 16); } uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb) @@ -958,7 +987,7 @@ uint32_t ext4fs_get_new_blk_no(void) fs->curr_blkno = fs->curr_blkno + (i * fs->blksz * 8); fs->first_pass_bbmap++; - ext4fs_bg_free_blocks_dec(bgd); + ext4fs_bg_free_blocks_dec(bgd, fs); ext4fs_sb_free_blocks_dec(fs->sb); status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk, @@ -1033,7 +1062,7 @@ restart: prev_bg_bitmap_index = bg_idx; } - ext4fs_bg_free_blocks_dec(bgd); + ext4fs_bg_free_blocks_dec(bgd, fs); ext4fs_sb_free_blocks_dec(fs->sb); goto success; } @@ -1092,9 +1121,9 @@ int ext4fs_get_new_inode_no(void) fs->curr_inode_no = fs->curr_inode_no + (i * inodes_per_grp); fs->first_pass_ibmap++; - ext4fs_bg_free_inodes_dec(bgd); + ext4fs_bg_free_inodes_dec(bgd, fs); if (has_gdt_chksum) - ext4fs_bg_itable_unused_dec(bgd); + ext4fs_bg_itable_unused_dec(bgd, fs); ext4fs_sb_free_inodes_dec(fs->sb); status = ext4fs_devread(i_bitmap_blk * fs->sect_perblk, @@ -1148,7 +1177,7 @@ restart:
[U-Boot] [PATCH v2 3/7] ext4: Add helper functions for block group descriptor field access
The helper functions encapsulate access of the block group descriptors, independent of group descriptor size. The helpers also deal with the endianess of the fields, and with split fields like free_blocks/ free_blocks_high. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- v2: include ext4fs_bg_get_inode_table_id(...) even if CONFIG_EXT4_WRITE is not defined fs/ext4/ext4_common.c | 82 +++ fs/ext4/ext4_common.h | 12 2 files changed, 94 insertions(+) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 2df4f8b..81740f8 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -47,6 +47,12 @@ struct ext2_inode *g_parent_inode; static int symlinknest; #if defined(CONFIG_EXT4_WRITE) +struct ext2_block_group *ext4fs_get_group_descriptor + (const struct ext_filesystem *fs, uint32_t bg_idx) +{ + return (struct ext2_block_group *)(fs->gdtable + (bg_idx * fs->gdsize)); +} + static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb) { sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) - 1); @@ -72,6 +78,82 @@ static inline void ext4fs_bg_itable_unused_dec(struct ext2_block_group *bg) bg->bg_itable_unused = cpu_to_le16(le16_to_cpu(bg->bg_itable_unused) - 1); } +uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb) +{ + uint64_t free_blocks = le32_to_cpu(sb->free_blocks); + free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32; + return free_blocks; +} + +void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks) +{ + sb->free_blocks = cpu_to_le32(free_blocks & 0x); + sb->free_blocks_high = cpu_to_le16(free_blocks >> 32); +} + +uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint32_t free_blocks = le16_to_cpu(bg->free_blocks); + if (fs->gdsize == 64) + free_blocks += le16_to_cpu(bg->free_blocks_high) << 16; + return free_blocks; +} + +static inline +uint32_t ext4fs_bg_get_free_inodes(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint32_t free_inodes = le16_to_cpu(bg->free_inodes); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->free_inodes_high) << 16; + return free_inodes; +} + +static inline uint16_t ext4fs_bg_get_flags(const struct ext2_block_group *bg) +{ + return le16_to_cpu(bg->bg_flags); +} + +static inline void ext4fs_bg_set_flags(struct ext2_block_group *bg, + uint16_t flags) +{ + bg->bg_flags = cpu_to_le16(flags); +} + +/* Block number of the block bitmap */ +uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->block_id); + if (fs->gdsize == 64) + block_nr += (uint64_t)le32_to_cpu(bg->block_id_high) << 32; + return block_nr; +} + +/* Block number of the inode bitmap */ +uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->inode_id); + if (fs->gdsize == 64) + block_nr += (uint64_t)le32_to_cpu(bg->inode_id_high) << 32; + return block_nr; +} +#endif + +/* Block number of the inode table */ +uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->inode_table_id); + if (fs->gdsize == 64) + block_nr += + (uint64_t)le32_to_cpu(bg->inode_table_id_high) << 32; + return block_nr; +} + +#if defined(CONFIG_EXT4_WRITE) uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) { uint32_t res = size / n; diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h index cc9d0c5..99d49e6 100644 --- a/fs/ext4/ext4_common.h +++ b/fs/ext4/ext4_common.h @@ -74,5 +74,17 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, unsigned int total_remaining_blocks, unsigned int *total_no_of_block); void put_ext4(uint64_t off, void *buf, uint32_t size); +struct ext2_block_group *ext4fs_get_group_descriptor + (const struct ext_filesystem *fs, uint32_t bg_idx); +uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs); +uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs); +uint64_t ext4fs_bg_get_inode_table_id(const struct ext
[U-Boot] [PATCH 7/7] ext4: Revert rejection of 64bit enabled ext4 fs
Enable mounting of ext4 fs with 64bit feature, as it is supported now. These had been disabled in 6f94ab6656ceffb3f2a972c8de4c554502b6f2b7. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 9 - 1 file changed, 9 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 61c4d19..bd81744 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -2337,15 +2337,6 @@ int ext4fs_mount(unsigned part_length) if (le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) goto fail; - /* -* The 64bit feature was enabled when metadata_csum was enabled -* and we do not support metadata_csum (and cannot reliably find -* files when it is set. Refuse to mount. -*/ - if (le32_to_cpu(data->sblock.feature_incompat) & EXT4_FEATURE_INCOMPAT_64BIT) { - printf("Unsupported feature found (64bit, possibly metadata_csum), not mounting\n"); - goto fail; - } if (le32_to_cpu(data->sblock.revision_level) == 0) { fs->inodesz = 128; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 5/7] ext4: Use helper function to access group descriptor and its fields
The descriptor size is variable, thus array indices are not generically applicable. The larger group descriptors also contain e.g. high parts of block numbers, which have to be read and written. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 125 -- fs/ext4/ext4_write.c | 165 +++--- include/ext4fs.h | 1 - 3 files changed, 154 insertions(+), 137 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 24610ca..0c2ac47 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -391,7 +391,7 @@ uint16_t ext4fs_checksum_update(uint32_t i) uint16_t crc = 0; __le32 le32_i = cpu_to_le32(i); - desc = (struct ext2_block_group *)>bgd[i]; + desc = ext4fs_get_group_descriptor(fs, i); if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { int offset = offsetof(struct ext2_block_group, bg_checksum); @@ -931,39 +931,41 @@ uint32_t ext4fs_get_new_blk_no(void) char *zero_buffer = zalloc(fs->blksz); if (!journal_buffer || !zero_buffer) goto fail; - struct ext2_block_group *bgd = (struct ext2_block_group *)fs->gdtable; if (fs->first_pass_bbmap == 0) { for (i = 0; i < fs->no_blkgrp; i++) { - if (le16_to_cpu(bgd[i].free_blocks)) { - if (le16_to_cpu(bgd[i].bg_flags) & EXT4_BG_BLOCK_UNINIT) { - uint16_t new_flags; - put_ext4((uint64_t)le32_to_cpu(bgd[i].block_id) * fs->blksz, -zero_buffer, fs->blksz); - new_flags = le16_to_cpu(bgd[i].bg_flags) & ~EXT4_BG_BLOCK_UNINIT; - bgd[i].bg_flags = cpu_to_le16(new_flags); + struct ext2_block_group *bgd = NULL; + bgd = ext4fs_get_group_descriptor(fs, i); + if (ext4fs_bg_get_free_blocks(bgd, fs)) { + uint16_t bg_flags = ext4fs_bg_get_flags(bgd); + uint64_t b_bitmap_blk = + ext4fs_bg_get_block_id(bgd, fs); + if (bg_flags & EXT4_BG_BLOCK_UNINIT) { memcpy(fs->blk_bmaps[i], zero_buffer, fs->blksz); + put_ext4(b_bitmap_blk * fs->blksz, +fs->blk_bmaps[i], fs->blksz); + bg_flags &= ~EXT4_BG_BLOCK_UNINIT; + ext4fs_bg_set_flags(bgd, bg_flags); } fs->curr_blkno = _get_new_blk_no(fs->blk_bmaps[i]); if (fs->curr_blkno == -1) - /* if block bitmap is completely fill */ + /* block bitmap is completely filled */ continue; fs->curr_blkno = fs->curr_blkno + (i * fs->blksz * 8); fs->first_pass_bbmap++; - ext4fs_bg_free_blocks_dec([i]); + ext4fs_bg_free_blocks_dec(bgd); ext4fs_sb_free_blocks_dec(fs->sb); - status = ext4fs_devread( - (lbaint_t)le32_to_cpu(bgd[i].block_id) * - fs->sect_perblk, 0, - fs->blksz, + status = ext4fs_devread(b_bitmap_blk * + fs->sect_perblk, + 0, fs->blksz, journal_buffer); if (status == 0) goto fail; if (ext4fs_log_journal(journal_buffer, - le32_to_cpu(bgd[i].block_id))) + b_bitmap_blk)) goto fail; goto success; } else { @@ -990,7 +992,9 @@ restart: if (bg_idx >= fs->no_blkgrp) goto fail; -
[U-Boot] [PATCH 1/7] ext4: Update ext2/3/4 superblock, group descriptor and inode structures
Most importantly, the superblock provides the used group descriptor size, which is required for the EXT4_FEATURE_INCOMPAT_64BIT. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- include/ext_common.h | 50 ++ 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/include/ext_common.h b/include/ext_common.h index 25216ca..07b61fa 100644 --- a/include/ext_common.h +++ b/include/ext_common.h @@ -99,6 +99,33 @@ struct ext2_sblock { char volume_name[16]; char last_mounted_on[64]; __le32 compression_info; + uint8_t prealloc_blocks; + uint8_t prealloc_dir_blocks; + __le16 reserved_gdt_blocks; + uint8_t journal_uuid[16]; + __le32 journal_inode; + __le32 journal_dev; + __le32 last_orphan; + __le32 hash_seed[4]; + uint8_t default_hash_version; + uint8_t journal_backup_type; + __le16 descriptor_size; + __le32 default_mount_options; + __le32 first_meta_block_group; + __le32 mkfs_time; + __le32 journal_blocks[17]; + __le32 total_blocks_high; + __le32 reserved_blocks_high; + __le32 free_blocks_high; + __le16 min_extra_inode_size; + __le16 want_extra_inode_size; + __le32 flags; + __le16 raid_stride; + __le16 mmp_interval; + __le64 mmp_block; + __le32 raid_stripe_width; + uint8_t log2_groups_per_flex; + uint8_t checksum_type; }; struct ext2_block_group { @@ -109,9 +136,23 @@ struct ext2_block_group { __le16 free_inodes; /* Free inodes count */ __le16 used_dir_cnt;/* Directories count */ __le16 bg_flags; - __le32 bg_reserved[2]; + __le32 bg_exclude_bitmap; + __le16 bg_block_id_csum; + __le16 bg_inode_id_csum; __le16 bg_itable_unused; /* Unused inodes count */ - __le16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/ + __le16 bg_checksum; /* crc16(s_uuid+group_num+group_desc)*/ + /* following fields only exist if descriptor size is 64 */ + __le32 block_id_high; + __le32 inode_id_high; + __le32 inode_table_id_high; + __le16 free_blocks_high; + __le16 free_inodes_high; + __le16 used_dir_cnt_high; + __le16 bg_itable_unused_high; + __le32 bg_exclude_bitmap_high; + __le16 bg_block_id_csum_high; + __le16 bg_inode_id_csum_high; + __le32 bg_reserved; }; /* The ext2 inode. */ @@ -125,7 +166,7 @@ struct ext2_inode { __le32 dtime; __le16 gid; __le16 nlinks; - __le32 blockcnt;/* Blocks of 512 bytes!! */ + __le32 blockcnt;/* Blocks of either 512 or block_size bytes */ __le32 flags; __le32 osd1; union { @@ -136,10 +177,11 @@ struct ext2_inode { __le32 triple_indir_block; } blocks; char symlink[60]; + char inline_data[60]; } b; __le32 version; __le32 acl; - __le32 dir_acl; + __le32 size_high; /* previously dir_acl, but never used */ __le32 fragment_addr; __le32 osd2[3]; }; -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 6/7] ext4: Respect group descriptor size when adjusting free counts
Also adjust high 16/32 bits when free inode/block counts are modified. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 53 +++ fs/ext4/ext4_write.c | 40 ++ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 0c2ac47..61c4d19 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -58,24 +58,53 @@ static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb) sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) - 1); } -static inline void ext4fs_bg_free_inodes_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_free_inodes_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) - 1); + uint32_t free_inodes = le16_to_cpu(bg->free_inodes); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->free_inodes_high) << 16; + free_inodes--; + + bg->free_inodes = cpu_to_le16(free_inodes & 0x); + if (fs->gdsize == 64) + bg->free_inodes_high = cpu_to_le16(free_inodes >> 16); } -static inline void ext4fs_bg_free_blocks_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_free_blocks_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) - 1); + uint32_t free_blocks = le16_to_cpu(bg->free_blocks); + if (fs->gdsize == 64) + free_blocks += le16_to_cpu(bg->free_blocks_high) << 16; + free_blocks--; + + bg->free_blocks = cpu_to_le16(free_blocks & 0x); + if (fs->gdsize == 64) + bg->free_blocks_high = cpu_to_le16(free_blocks >> 16); } static inline void ext4fs_sb_free_blocks_dec(struct ext2_sblock *sb) { - sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) - 1); + uint64_t free_blocks = le32_to_cpu(sb->free_blocks); + free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32; + free_blocks--; + + sb->free_blocks = cpu_to_le32(free_blocks & 0x); + sb->free_blocks_high = cpu_to_le16(free_blocks >> 32); } -static inline void ext4fs_bg_itable_unused_dec(struct ext2_block_group *bg) +static inline void ext4fs_bg_itable_unused_dec + (struct ext2_block_group *bg, const struct ext_filesystem *fs) { - bg->bg_itable_unused = cpu_to_le16(le16_to_cpu(bg->bg_itable_unused) - 1); + uint32_t free_inodes = le16_to_cpu(bg->bg_itable_unused); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->bg_itable_unused_high) << 16; + free_inodes--; + + bg->bg_itable_unused = cpu_to_le16(free_inodes & 0x); + if (fs->gdsize == 64) + bg->bg_itable_unused_high = cpu_to_le16(free_inodes >> 16); } uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb) @@ -956,7 +985,7 @@ uint32_t ext4fs_get_new_blk_no(void) fs->curr_blkno = fs->curr_blkno + (i * fs->blksz * 8); fs->first_pass_bbmap++; - ext4fs_bg_free_blocks_dec(bgd); + ext4fs_bg_free_blocks_dec(bgd, fs); ext4fs_sb_free_blocks_dec(fs->sb); status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk, @@ -1031,7 +1060,7 @@ restart: prev_bg_bitmap_index = bg_idx; } - ext4fs_bg_free_blocks_dec(bgd); + ext4fs_bg_free_blocks_dec(bgd, fs); ext4fs_sb_free_blocks_dec(fs->sb); goto success; } @@ -1090,9 +1119,9 @@ int ext4fs_get_new_inode_no(void) fs->curr_inode_no = fs->curr_inode_no + (i * inodes_per_grp); fs->first_pass_ibmap++; - ext4fs_bg_free_inodes_dec(bgd); + ext4fs_bg_free_inodes_dec(bgd, fs); if (has_gdt_chksum) - ext4fs_bg_itable_unused_dec(bgd); + ext4fs_bg_itable_unused_dec(bgd, fs); ext4fs_sb_free_inodes_dec(fs->sb); status = ext4fs_devread(i_bitmap_blk * fs->sect_perblk, @@ -1146,7 +1175,7 @@ restart:
[U-Boot] [PATCH 3/7] ext4: Add helper functions for block group descriptor field access
The helper functions encapsulate access of the block group descriptors, independent of group descriptor size. The helpers also deal with the endianess of the fields, and with split fields like free_blocks/ free_blocks_high. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 80 +++ fs/ext4/ext4_common.h | 12 2 files changed, 92 insertions(+) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 416a9db..9e5bca0 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -47,6 +47,12 @@ struct ext2_inode *g_parent_inode; static int symlinknest; #if defined(CONFIG_EXT4_WRITE) +struct ext2_block_group *ext4fs_get_group_descriptor + (const struct ext_filesystem *fs, uint32_t bg_idx) +{ + return (struct ext2_block_group *)(fs->gdtable + (bg_idx * fs->gdsize)); +} + static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb) { sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) - 1); @@ -72,6 +78,80 @@ static inline void ext4fs_bg_itable_unused_dec(struct ext2_block_group *bg) bg->bg_itable_unused = cpu_to_le16(le16_to_cpu(bg->bg_itable_unused) - 1); } +uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb) +{ + uint64_t free_blocks = le32_to_cpu(sb->free_blocks); + free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32; + return free_blocks; +} + +void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks) +{ + sb->free_blocks = cpu_to_le32(free_blocks & 0x); + sb->free_blocks_high = cpu_to_le16(free_blocks >> 32); +} + +uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint32_t free_blocks = le16_to_cpu(bg->free_blocks); + if (fs->gdsize == 64) + free_blocks += le16_to_cpu(bg->free_blocks_high) << 16; + return free_blocks; +} + +static inline +uint32_t ext4fs_bg_get_free_inodes(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint32_t free_inodes = le16_to_cpu(bg->free_inodes); + if (fs->gdsize == 64) + free_inodes += le16_to_cpu(bg->free_inodes_high) << 16; + return free_inodes; +} + +static inline uint16_t ext4fs_bg_get_flags(const struct ext2_block_group *bg) +{ + return le16_to_cpu(bg->bg_flags); +} + +static inline void ext4fs_bg_set_flags(struct ext2_block_group *bg, + uint16_t flags) +{ + bg->bg_flags = cpu_to_le16(flags); +} + +/* Block number of the block bitmap */ +uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->block_id); + if (fs->gdsize == 64) + block_nr += (uint64_t)le32_to_cpu(bg->block_id_high) << 32; + return block_nr; +} + +/* Block number of the inode bitmap */ +uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->inode_id); + if (fs->gdsize == 64) + block_nr += (uint64_t)le32_to_cpu(bg->inode_id_high) << 32; + return block_nr; +} + +/* Block number of the inode table */ +uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs) +{ + uint64_t block_nr = le32_to_cpu(bg->inode_table_id); + if (fs->gdsize == 64) + block_nr += + (uint64_t)le32_to_cpu(bg->inode_table_id_high) << 32; + return block_nr; +} + uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) { uint32_t res = size / n; diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h index cc9d0c5..99d49e6 100644 --- a/fs/ext4/ext4_common.h +++ b/fs/ext4/ext4_common.h @@ -74,5 +74,17 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, unsigned int total_remaining_blocks, unsigned int *total_no_of_block); void put_ext4(uint64_t off, void *buf, uint32_t size); +struct ext2_block_group *ext4fs_get_group_descriptor + (const struct ext_filesystem *fs, uint32_t bg_idx); +uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs); +uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs); +uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg, + const struct ext_filesystem *fs); +uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb); +void ext4fs_sb
[U-Boot] [PATCH 0/7] Add support for ext4 with enabled 64bit feature
The EXT4_FEATURE_INCOMPAT_64BIT changes the on disk layout. Use the correct structure sizes/offsets and respect split high/low free inode/block counts. Stefan Brüns (7): ext4: Update ext2/3/4 superblock, group descriptor and inode structures ext4: determine group descriptor size for 64bit feature ext4: Add helper functions for block group descriptor field access ext4: Use correct descriptor size when reading the block group descriptor ext4: Use helper function to access group descriptor and its fields ext4: Respect group descriptor size when adjusting free counts ext4: Revert rejection of 64bit enabled ext4 fs fs/ext4/ext4_common.c | 283 +++--- fs/ext4/ext4_common.h | 12 +++ fs/ext4/ext4_write.c | 189 +++-- include/ext4fs.h | 3 +- include/ext_common.h | 50 - 5 files changed, 368 insertions(+), 169 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/7] ext4: determine group descriptor size for 64bit feature
If EXT4_FEATURE_INCOMPAT_64BIT is set, the descriptor can be read from the superblocks, otherwise it defaults to 32. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 18 ++ include/ext4fs.h | 2 ++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index a78b0b8..416a9db 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -2233,13 +2233,23 @@ int ext4fs_mount(unsigned part_length) goto fail; } - if (le32_to_cpu(data->sblock.revision_level) == 0) + if (le32_to_cpu(data->sblock.revision_level) == 0) { fs->inodesz = 128; - else + } else { + debug("EXT4 features COMPAT: %08x INCOMPAT: %08x RO_COMPAT: %08x\n", + __le32_to_cpu(data->sblock.feature_compatibility), + __le32_to_cpu(data->sblock.feature_incompat), + __le32_to_cpu(data->sblock.feature_ro_compat)); + fs->inodesz = le16_to_cpu(data->sblock.inode_size); + fs->gdsize = le32_to_cpu(data->sblock.feature_incompat) & + EXT4_FEATURE_INCOMPAT_64BIT ? + le16_to_cpu(data->sblock.descriptor_size) : 32; + } - debug("EXT2 rev %d, inode_size %d\n", - le32_to_cpu(data->sblock.revision_level), fs->inodesz); + debug("EXT2 rev %d, inode_size %d, descriptor size %d\n", + le32_to_cpu(data->sblock.revision_level), + fs->inodesz, fs->gdsize); data->diropen.data = data; data->diropen.ino = 2; diff --git a/include/ext4fs.h b/include/ext4fs.h index 6e31c73..7e1ee6c 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -87,6 +87,8 @@ struct ext_filesystem { uint32_t inodesz; /* Sectors per Block */ uint32_t sect_perblk; + /* Group Descriptor size */ + uint16_t gdsize; /* Group Descriptor Block Number */ uint32_t gdtable_blkno; /* Total block groups of partition */ -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 4/7] ext4: Use correct descriptor size when reading the block group descriptor
The correct descriptor size must be used when calculating offsets, and also to read the correct amount of data. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 9e5bca0..24610ca 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -1525,20 +1525,20 @@ static int ext4fs_blockgroup long int blkno; unsigned int blkoff, desc_per_blk; int log2blksz = get_fs()->dev_desc->log2blksz; + int desc_size = get_fs()->gdsize; - desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group); + desc_per_blk = EXT2_BLOCK_SIZE(data) / desc_size; blkno = le32_to_cpu(data->sblock.first_data_block) + 1 + group / desc_per_blk; - blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group); + blkoff = (group % desc_per_blk) * desc_size; debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n", group, blkno, blkoff); return ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) - log2blksz), - blkoff, sizeof(struct ext2_block_group), - (char *)blkgrp); + blkoff, desc_size, (char *)blkgrp); } int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 1/5] test/fs: Restructure file path specification to allow some flexibility
Instead of providing the full path, specify directory and filename separately. This allows to specify intermediate directories, required for some additional tests. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 58 +- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 93679cb..f95350b 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -135,22 +135,6 @@ function create_image() { fi } -# 1st parameter is the FS type: fat/ext4 -# 2nd parameter is the name of small file -# Returns filename which can be used for fat or ext4 for writing -function fname_for_write() { - case $1 in - ext4) - # ext4 needs absolute path name of file - echo /${2}.w - ;; - - *) - echo ${2}.w - ;; - esac -} - # 1st parameter is image file # 2nd parameter is file system type - fat/ext4 # 3rd parameter is name of small file @@ -166,11 +150,14 @@ function test_image() { case "$2" in fat) + FPATH="" PREFIX="fat" WRITE="write" ;; ext4) + # ext4 needs absolute path + FPATH="/" PREFIX="ext4" WRITE="write" ;; @@ -205,16 +192,15 @@ function test_image() { esac - if [ -z "$6" ]; then - FILE_WRITE=`fname_for_write $2 $3` - FILE_SMALL=$3 - FILE_BIG=$4 - else - FILE_WRITE=$6/`fname_for_write $2 $3` - FILE_SMALL=$6/$3 - FILE_BIG=$6/$4 + # sb always uses full path to mointpoint, irrespective of filesystem + if [ "$5" = "sb" ]; then + FPATH=${6}/ fi + FILE_WRITE=${3}.w + FILE_SMALL=$3 + FILE_BIG=$4 + # In u-boot commands, stands for host or hostfs # hostfs maps to the host fs. # host maps to the "sb bind" that we do @@ -230,13 +216,13 @@ ${PREFIX}ls host${SUFFIX} $6 # sb size hostfs - $3 for hostfs commands. # 1MB is 0x0010 # Test Case 2 - size of small file -${PREFIX}size host${SUFFIX} $FILE_SMALL +${PREFIX}size host${SUFFIX} ${FPATH}$FILE_SMALL printenv filesize setenv filesize # 2.5GB (1024*1024*2500) is 0x9C40 # Test Case 3 - size of big file -${PREFIX}size host${SUFFIX} $FILE_BIG +${PREFIX}size host${SUFFIX} ${FPATH}$FILE_BIG printenv filesize setenv filesize @@ -245,14 +231,14 @@ setenv filesize # Last two parameters are size and offset. # Test Case 4a - Read full 1MB of small file -${PREFIX}load host${SUFFIX} $addr $FILE_SMALL +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_SMALL printenv filesize # Test Case 4b - Read full 1MB of small file md5sum $addr \$filesize setenv filesize # Test Case 5a - First 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x0 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x0 printenv filesize # Test Case 5b - First 1MB of big file md5sum $addr \$filesize @@ -260,7 +246,7 @@ setenv filesize # fails for ext as no offset support # Test Case 6a - Last 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x9C30 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x9C30 printenv filesize # Test Case 6b - Last 1MB of big file md5sum $addr \$filesize @@ -268,7 +254,7 @@ setenv filesize # fails for ext as no offset support # Test Case 7a - One from the last 1MB chunk of 2GB -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x7FF0 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x7FF0 printenv filesize # Test Case 7b - One from the last 1MB chunk of 2GB md5sum $addr \$filesize @@ -276,7 +262,7 @@ setenv filesize # fails for ext as no offset support # Test Case 8a - One from the start 1MB chunk from 2GB -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x8000 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x8000 printenv filesize # Test Case 8b - One from the start 1MB chunk from 2GB md5sum $addr \$filesize @@ -284,7 +270,7 @@ setenv filesize # fails for ext as no offset support # Test Case 9a - One 1MB chunk crossing the 2GB boundary -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x7FF8 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x7FF8 printenv filesize # Test Case 9b - One 1MB chunk crossing the 2GB boundary md5sum $addr \$filesize @@ -292,17 +278,17 @@ setenv filesize # Generic failure case # Test Case 10 - 2MB chunk from the last 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG 0x0020 0x9C30
[U-Boot] [PATCH v2 3/5] test/fs: strip noise from filesystem code prior to checking results
ext4 and fat code emit some diagnostic messages during command execution. These additional lines force a match window size which strictly is not necessary. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 26 +++--- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 9615898..b9c2306 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -386,7 +386,7 @@ check_md5() { # md5sum in u-boot has output of form: # md5 for 0108 ... 0117 ==> # the 7th field is the actual md5 - md5_src=`grep -A3 "$1" "$2" | grep "md5 for" | tr -d '\r'` + md5_src=`grep -A2 "$1" "$2" | grep "md5 for" | tr -d '\r'` md5_src=($md5_src) md5_src=${md5_src[6]} @@ -431,45 +431,44 @@ function check_results() { pass_fail "TC3: size of $4" # Check read full mb of 1MB.file - grep -A6 "Test Case 4a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 4a " "$1" | grep -q "filesize=10" pass_fail "TC4: load of $3 size" check_md5 "Test Case 4b " "$1" "$2" 1 "TC4: load from $3" # Check first mb of 2.5GB.file - grep -A6 "Test Case 5a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 5a " "$1" | grep -q "filesize=10" pass_fail "TC5: load of 1st MB from $4 size" check_md5 "Test Case 5b " "$1" "$2" 2 "TC5: load of 1st MB from $4" # Check last mb of 2.5GB.file - grep -A6 "Test Case 6a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 6a " "$1" | grep -q "filesize=10" pass_fail "TC6: load of last MB from $4 size" check_md5 "Test Case 6b " "$1" "$2" 3 "TC6: load of last MB from $4" # Check last 1mb chunk of 2gb from 2.5GB file - grep -A6 "Test Case 7a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 7a " "$1" | grep -q "filesize=10" pass_fail "TC7: load of last 1mb chunk of 2GB from $4 size" check_md5 "Test Case 7b " "$1" "$2" 4 \ "TC7: load of last 1mb chunk of 2GB from $4" # Check first 1mb chunk after 2gb from 2.5GB file - grep -A6 "Test Case 8a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 8a " "$1" | grep -q "filesize=10" pass_fail "TC8: load 1st MB chunk after 2GB from $4 size" check_md5 "Test Case 8b " "$1" "$2" 5 \ "TC8: load 1st MB chunk after 2GB from $4" # Check 1mb chunk crossing the 2gb boundary from 2.5GB file - grep -A6 "Test Case 9a " "$1" | grep -q "filesize=10" + grep -A4 "Test Case 9a " "$1" | grep -q "filesize=10" pass_fail "TC9: load 1MB chunk crossing 2GB boundary from $4 size" check_md5 "Test Case 9b " "$1" "$2" 6 \ "TC9: load 1MB chunk crossing 2GB boundary from $4" # Check 2mb chunk from the last 1MB of 2.5GB file loads 1MB - grep -A6 "Test Case 10 " "$1" | grep -q "filesize=10" + grep -A5 "Test Case 10 " "$1" | grep -q "filesize=10" pass_fail "TC10: load 2MB from the last 1MB of $4 loads 1MB" # Check 1mb chunk write - grep -A3 "Test Case 11a " "$1" | \ - egrep -q '1048576 bytes written|update journal' + grep -A2 "Test Case 11a " "$1" | grep -q '1048576 bytes written' pass_fail "TC11: 1MB write to $3.w - write succeeded" check_md5 "Test Case 11b " "$1" "$2" 1 \ "TC11: 1MB write to $3.w - content verified" @@ -486,7 +485,12 @@ function test_fs_nonfs() { OUT_FILE="${OUT}.$1.${fs}.out" test_image $IMAGE $fs $SMALL_FILE $BIG_FILE $1 "" \ > ${OUT_FILE} 2>&1 - check_results $OUT_FILE $MD5_FILE_FS $SMALL_FILE $BIG_FILE + # strip out noise from fs code + grep -v -e "File System is consistent\|update journal finished" \ + -e "reading .*\.file\|writing .*\.file.w" \ + < ${OUT_FILE} > ${OUT_FILE}_clean + check_results ${OUT_FILE}_clean $MD5_FILE_FS $SMALL_FILE \ + $BIG_FILE TOTAL_FAIL=$((TOTAL_FAIL + FAIL)) TOTAL_PASS=$((TOTAL_PASS + PASS)) echo "Summary: PASS: $PASS FAIL: $FAIL" -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 5/5] test/fs: Check writes using "." (same dir) relative path
/ and /./ should reference the same file. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 29 - 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 69abdab..520344b 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -299,6 +299,23 @@ setenv filesize # The write should fail, but the lookup should work # Test Case 12 - Check directory traversal ${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}. 0x10 + +# Read 1MB from small file +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_SMALL +# Write it via "same directory", i.e. "." dirent +# Test Case 13a - Check directory traversal +${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}./${FILE_WRITE}2 \$filesize +mw.b $addr 00 100 +${PREFIX}load host${SUFFIX} $addr ${FPATH}./${FILE_WRITE}2 +# Test Case 13b - Check md5 of written to is same as the one read from +md5sum $addr \$filesize +setenv filesize +mw.b $addr 00 100 +${PREFIX}load host${SUFFIX} $addr ${FPATH}${FILE_WRITE}2 +# Test Case 13c - Check md5 of written to is same as the one read from +md5sum $addr \$filesize +setenv filesize +# reset EOF @@ -335,9 +352,10 @@ function create_files() { &> /dev/null fi - # Delete the small file which possibly is written as part of a + # Delete the small file copies which possibly are written as part of a # previous test. sudo rm -f "${MB1}.w" + sudo rm -f "${MB1}.w2" # Generate the md5sums of reads that we will test against small file dd if="${MB1}" bs=1M skip=0 count=1 2> /dev/null | md5sum > "$2" @@ -482,6 +500,15 @@ function check_results() { # Check lookup of 'dot' directory grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' pass_fail "TC12: 1MB write to . - write denied" + + # Check directory traversal + grep -A2 "Test Case 13a " "$1" | grep -q '1048576 bytes written' + pass_fail "TC13: 1MB write to ./$3.w2 - write succeeded" + check_md5 "Test Case 13b " "$1" "$2" 1 \ + "TC13: 1MB read from ./$3.w2 - content verified" + check_md5 "Test Case 13c " "$1" "$2" 1 \ + "TC13: 1MB read from $3.w2 - content verified" + echo "** End $1" } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 4/5] test/fs: Check ext4 behaviour if dirent is first entry in directory block
This is a regression test for a crash happening if the first dirent in the block matches. Code tried to access a predecessor entry which does not exist. The crash happened for any block, but "." is always the first entry in the first directory block and thus easy to check for. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 10 ++ 1 file changed, 10 insertions(+) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index b9c2306..69abdab 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -293,6 +293,12 @@ ${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_WRITE md5sum $addr \$filesize setenv filesize # + +# Next test case checks writing a file whose dirent +# is the first in the block, which is always true for "." +# The write should fail, but the lookup should work +# Test Case 12 - Check directory traversal +${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}. 0x10 reset EOF @@ -472,6 +478,10 @@ function check_results() { pass_fail "TC11: 1MB write to $3.w - write succeeded" check_md5 "Test Case 11b " "$1" "$2" 1 \ "TC11: 1MB write to $3.w - content verified" + + # Check lookup of 'dot' directory + grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' + pass_fail "TC12: 1MB write to . - write denied" echo "** End $1" } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 0/5] Enhance fs tests
The first 3 patches do some cleanups for the current test, especially TC11 had some issues (strange match for expected output, use of unitialized variable). The last two patches add test cases for handling ".". Ext4 used to crash, as a match on the first entry of a directory block was not handled correctly. v2: Updated: test/fs: Restructure file path specification to allow some flexibility * avoid creation of paths with double slashes test/fs: Check writes using "." (same dir) relative path * fix issues copied from TC11 * delete written file in cleanup Added: test/fs: remove use of undefined WRITE_FILE variable test/fs: strip noise from filesystem code prior to checking results Stefan Brüns (5): test/fs: Restructure file path specification to allow some flexibility test/fs: remove use of undefined WRITE_FILE variable test/fs: strip noise from filesystem code prior to checking results test/fs: Check ext4 behaviour if dirent is first entry in directory block test/fs: Check writes using "." (same dir) relative path test/fs/fs-test.sh | 131 +++-- 1 file changed, 78 insertions(+), 53 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 2/5] test/fs: remove use of undefined WRITE_FILE variable
The write file is created from $SMALL_FILE by appending ".w" on all other occurences in the code. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index f95350b..9615898 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -470,9 +470,9 @@ function check_results() { # Check 1mb chunk write grep -A3 "Test Case 11a " "$1" | \ egrep -q '1048576 bytes written|update journal' - pass_fail "TC11: 1MB write to $5 - write succeeded" + pass_fail "TC11: 1MB write to $3.w - write succeeded" check_md5 "Test Case 11b " "$1" "$2" 1 \ - "TC11: 1MB write to $5 - content verified" + "TC11: 1MB write to $3.w - content verified" echo "** End $1" } @@ -486,8 +486,7 @@ function test_fs_nonfs() { OUT_FILE="${OUT}.$1.${fs}.out" test_image $IMAGE $fs $SMALL_FILE $BIG_FILE $1 "" \ > ${OUT_FILE} 2>&1 - check_results $OUT_FILE $MD5_FILE_FS $SMALL_FILE $BIG_FILE \ - $WRITE_FILE + check_results $OUT_FILE $MD5_FILE_FS $SMALL_FILE $BIG_FILE TOTAL_FAIL=$((TOTAL_FAIL + FAIL)) TOTAL_PASS=$((TOTAL_PASS + PASS)) echo "Summary: PASS: $PASS FAIL: $FAIL" @@ -537,8 +536,7 @@ for fs in ext4 fat; do sudo umount "$MOUNT_DIR" rmdir "$MOUNT_DIR" - check_results $OUT_FILE $MD5_FILE_FS $SMALL_FILE $BIG_FILE \ - $WRITE_FILE + check_results $OUT_FILE $MD5_FILE_FS $SMALL_FILE $BIG_FILE TOTAL_FAIL=$((TOTAL_FAIL + FAIL)) TOTAL_PASS=$((TOTAL_PASS + PASS)) echo "Summary: PASS: $PASS FAIL: $FAIL" -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 4/4] cmd/fat: Do not crash on write when is not specified
argc is checked, but is off by one. In case is not specified, create an empty file, which is identical to the ext4write behaviour. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- cmd/fat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/fat.c b/cmd/fat.c index 4e20746..ad1dc2a 100644 --- a/cmd/fat.c +++ b/cmd/fat.c @@ -126,7 +126,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, return 1; } addr = simple_strtoul(argv[3], NULL, 16); - count = simple_strtoul(argv[5], NULL, 16); + count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16); buf = map_sysmem(addr, count); ret = file_fat_write(argv[4], buf, 0, count, ); @@ -145,7 +145,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, U_BOOT_CMD( fatwrite, 6, 0, do_fat_fswrite, "write file into a dos filesystem", - " <dev[:part]> \n" + " <dev[:part]> []\n" "- write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" ); -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 3/4] fs/fat: Correct description of determine_fatent function
Current description does not match the function behaviour. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat_write.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index babe9c8..0583af3 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -528,7 +528,8 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) } /* - * Determine the entry value at index 'entry' in a FAT (16/32) table + * Determine the next free cluster after 'entry' in a FAT (16/32) table + * and link it to 'entry'. EOC marker is not set on returned entry. */ static __u32 determine_fatent(fsdata *mydata, __u32 entry) { @@ -537,6 +538,7 @@ static __u32 determine_fatent(fsdata *mydata, __u32 entry) while (1) { next_fat = get_fatent_value(mydata, next_entry); if (next_fat == 0) { + /* found free entry, link to entry */ set_fatent_value(mydata, entry, next_entry); break; } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/4] fs/fat: Do not write unmodified fat entries to disk
The code caches 6 sectors of the FAT. On FAT traversal, the old contents needs to be flushed to disk, but only if any FAT entries had been modified. Explicitly flag the buffer on modification. Currently, creating a new file traverses the whole FAT up to the first free cluster and rewrites the on-disk blocks. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat.c | 1 + fs/fat/fat_write.c | 31 +++ include/fat.h | 1 + 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 826bd85..df9f2b5 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -876,6 +876,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, } mydata->fatbufnum = -1; + mydata->fat_dirty = 0; mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); if (mydata->fatbuf == NULL) { debug("Error: allocating memory\n"); diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 961ccd8..babe9c8 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -104,13 +104,19 @@ static __u8 num_of_fats; /* * Write fat buffer into block device */ -static int flush_fat_buffer(fsdata *mydata) +static int flush_dirty_fat_buffer(fsdata *mydata) { int getsize = FATBUFBLOCKS; __u32 fatlength = mydata->fatlength; __u8 *bufptr = mydata->fatbuf; __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS; + debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum, + (int)mydata->fat_dirty); + + if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1)) + return 0; + startblock += mydata->fat_sect; if (getsize > fatlength) @@ -130,6 +136,7 @@ static int flush_fat_buffer(fsdata *mydata) return -1; } } + mydata->fat_dirty = 0; return 0; } @@ -186,10 +193,8 @@ static __u32 get_fatent_value(fsdata *mydata, __u32 entry) startblock += mydata->fat_sect; /* Offset from start of disk */ /* Write back the fatbuf to the disk */ - if (mydata->fatbufnum != -1) { - if (flush_fat_buffer(mydata) < 0) - return -1; - } + if (flush_dirty_fat_buffer(mydata) < 0) + return -1; if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); @@ -494,10 +499,8 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) if (getsize > fatlength) getsize = fatlength; - if (mydata->fatbufnum != -1) { - if (flush_fat_buffer(mydata) < 0) - return -1; - } + if (flush_dirty_fat_buffer(mydata) < 0) + return -1; if (disk_read(startblock, getsize, bufptr) < 0) { debug("Error reading FAT blocks\n"); @@ -506,6 +509,9 @@ static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) mydata->fatbufnum = bufnum; } + /* Mark as dirty */ + mydata->fat_dirty = 1; + /* Set the actual entry */ switch (mydata->fatsize) { case 32: @@ -645,7 +651,7 @@ static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) dir_curclust = dir_newclust; - if (flush_fat_buffer(mydata) < 0) + if (flush_dirty_fat_buffer(mydata) < 0) return; memset(get_dentfromdir_block, 0x00, @@ -675,7 +681,7 @@ static int clear_fatent(fsdata *mydata, __u32 entry) } /* Flush fat buffer */ - if (flush_fat_buffer(mydata) < 0) + if (flush_dirty_fat_buffer(mydata) < 0) return -1; return 0; @@ -1011,6 +1017,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, } mydata->fatbufnum = -1; + mydata->fat_dirty = 0; mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); if (mydata->fatbuf == NULL) { debug("Error: allocating memory\n"); @@ -,7 +1118,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, debug("attempt to write 0x%llx bytes\n", *actwrite); /* Flush fat buffer */ - ret = flush_fat_buffer(mydata); + ret = flush_dirty_fat_buffer(mydata); if (ret) { printf("Error: flush fat buffer\n"); goto exit; diff --git a/include/fat.h b/include/fat.h index 9d053e6..8ec91cd 100644 --- a/include/fat.h +++ b/include/fat.h @@ -169,6 +169,7 @@ typedef struct {
[U-Boot] [PATCH 1/4] fs/fat: Remove two statements without effect
fatlength is a local variable which is no more used after the assignment. s_name is not used in the function, save the strncpy. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/fat/fat_write.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index eb3a916..961ccd8 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -183,7 +183,6 @@ static __u32 get_fatent_value(fsdata *mydata, __u32 entry) if (getsize > fatlength) getsize = fatlength; - fatlength *= mydata->sect_size; /* We want it in bytes now */ startblock += mydata->fat_sect; /* Offset from start of disk */ /* Write back the fatbuf to the disk */ @@ -326,10 +325,8 @@ fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block; __u8 counter = 0, checksum; int idx = 0, ret; - char s_name[16]; - /* Get short file name and checksum value */ - strncpy(s_name, (*dentptr)->name, 16); + /* Get short file name checksum value */ checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); do { -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/4] Fat filesystem enhancements
Start cleanup of fat filesystem. Stefan Brüns (4): fs/fat: Remove two statements without effect fs/fat: Do not write unmodified fat entries to disk fs/fat: Correct description of determine_fatent function cmd/fat: Do not crash on write when is not specified cmd/fat.c | 4 ++-- fs/fat/fat.c | 1 + fs/fat/fat_write.c | 40 +++- include/fat.h | 1 + 4 files changed, 27 insertions(+), 19 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/3] Enhance fs tests
Test for two corner cases in ext4 directory traversal. Stefan Brüns (3): test/fs: Restructure file path specification to allow some flexibility test/fs: Check ext4 behaviour if dirent is first entry in directory block test/fs: Check writes using "." (same dir) relative path test/fs/fs-test.sh | 94 +- 1 file changed, 58 insertions(+), 36 deletions(-) -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/3] test/fs: Restructure file path specification to allow some flexibility
Instead of providing the full path, specify directory and filename separately. This allows to specify intermediate directories, required for some additional tests. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 56 +++--- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 93679cb..12450ed 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -135,22 +135,6 @@ function create_image() { fi } -# 1st parameter is the FS type: fat/ext4 -# 2nd parameter is the name of small file -# Returns filename which can be used for fat or ext4 for writing -function fname_for_write() { - case $1 in - ext4) - # ext4 needs absolute path name of file - echo /${2}.w - ;; - - *) - echo ${2}.w - ;; - esac -} - # 1st parameter is image file # 2nd parameter is file system type - fat/ext4 # 3rd parameter is name of small file @@ -166,11 +150,14 @@ function test_image() { case "$2" in fat) + FPATH="" PREFIX="fat" WRITE="write" ;; ext4) + # ext4 needs absolute path + FPATH="/" PREFIX="ext4" WRITE="write" ;; @@ -205,15 +192,12 @@ function test_image() { esac - if [ -z "$6" ]; then - FILE_WRITE=`fname_for_write $2 $3` - FILE_SMALL=$3 - FILE_BIG=$4 - else - FILE_WRITE=$6/`fname_for_write $2 $3` - FILE_SMALL=$6/$3 - FILE_BIG=$6/$4 + if [ ! -z "$6" ]; then + FPATH=${6}/${FPATH} fi + FILE_WRITE=${3}.w + FILE_SMALL=$3 + FILE_BIG=$4 # In u-boot commands, stands for host or hostfs # hostfs maps to the host fs. @@ -230,13 +214,13 @@ ${PREFIX}ls host${SUFFIX} $6 # sb size hostfs - $3 for hostfs commands. # 1MB is 0x0010 # Test Case 2 - size of small file -${PREFIX}size host${SUFFIX} $FILE_SMALL +${PREFIX}size host${SUFFIX} ${FPATH}$FILE_SMALL printenv filesize setenv filesize # 2.5GB (1024*1024*2500) is 0x9C40 # Test Case 3 - size of big file -${PREFIX}size host${SUFFIX} $FILE_BIG +${PREFIX}size host${SUFFIX} ${FPATH}$FILE_BIG printenv filesize setenv filesize @@ -245,14 +229,14 @@ setenv filesize # Last two parameters are size and offset. # Test Case 4a - Read full 1MB of small file -${PREFIX}load host${SUFFIX} $addr $FILE_SMALL +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_SMALL printenv filesize # Test Case 4b - Read full 1MB of small file md5sum $addr \$filesize setenv filesize # Test Case 5a - First 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x0 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x0 printenv filesize # Test Case 5b - First 1MB of big file md5sum $addr \$filesize @@ -260,7 +244,7 @@ setenv filesize # fails for ext as no offset support # Test Case 6a - Last 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x9C30 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x9C30 printenv filesize # Test Case 6b - Last 1MB of big file md5sum $addr \$filesize @@ -268,7 +252,7 @@ setenv filesize # fails for ext as no offset support # Test Case 7a - One from the last 1MB chunk of 2GB -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x7FF0 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x7FF0 printenv filesize # Test Case 7b - One from the last 1MB chunk of 2GB md5sum $addr \$filesize @@ -276,7 +260,7 @@ setenv filesize # fails for ext as no offset support # Test Case 8a - One from the start 1MB chunk from 2GB -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x8000 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x8000 printenv filesize # Test Case 8b - One from the start 1MB chunk from 2GB md5sum $addr \$filesize @@ -284,7 +268,7 @@ setenv filesize # fails for ext as no offset support # Test Case 9a - One 1MB chunk crossing the 2GB boundary -${PREFIX}load host${SUFFIX} $addr $FILE_BIG $length 0x7FF8 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG $length 0x7FF8 printenv filesize # Test Case 9b - One 1MB chunk crossing the 2GB boundary md5sum $addr \$filesize @@ -292,17 +276,17 @@ setenv filesize # Generic failure case # Test Case 10 - 2MB chunk from the last 1MB of big file -${PREFIX}load host${SUFFIX} $addr $FILE_BIG 0x0020 0x9C30 +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_BIG 0x0020 0x9C30 printenv filesize # # Read 1MB from small file -${PREFIX}load
[U-Boot] [PATCH 3/3] test/fs: Check writes using "." (same dir) relative path
/ and /./ should reference the same file. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 27 +++ 1 file changed, 27 insertions(+) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index cb2a765..46975ec 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -297,6 +297,23 @@ setenv filesize # The write should fail, but the lookup should work # Test Case 12 - Check directory traversal ${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}. 0x10 + +# Read 1MB from small file +${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_SMALL +# Write it via "same directory", i.e. "." dirent +# Test Case 13a - Check directory traversal +${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}./${FILE_WRITE}2 \$filesize +mw.b $addr 00 100 +${PREFIX}load host${SUFFIX} $addr ${FPATH}./${FILE_WRITE}2 +# Test Case 13b - Check md5 of written to is same as the one read from +md5sum $addr \$filesize +setenv filesize +mw.b $addr 00 100 +${PREFIX}load host${SUFFIX} $addr ${FPATH}${FILE_WRITE}2 +# Test Case 13c - Check md5 of written to is same as the one read from +md5sum $addr \$filesize +setenv filesize +# reset EOF @@ -482,6 +499,16 @@ function check_results() { grep -A5 "Test Case 12 " "$1" | \ egrep -q 'Unable to write file' pass_fail "TC12: 1MB write to . - write denied" + + # Check directory traversal + grep -A6 "Test Case 13a " "$1" | \ + egrep -q '1048576 bytes written|update journal' + pass_fail "TC13: 1MB write to ./$5 - write succeeded" + check_md5 "Test Case 13b " "$1" "$2" 1 \ + "TC13: 1MB read from ./$5 - content verified" + check_md5 "Test Case 13c " "$1" "$2" 1 \ + "TC13: 1MB read from $5 - content verified" + echo "** End $1" } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/3] test/fs: Check ext4 behaviour if dirent is first entry in directory block
This is a regression test for a crash happening if the first dirent in the block matches. Code tried to access a predecessor entry which does not exist. The crash happened for any block, but "." is always the first entry in the first directory block and thus easy to check for. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- test/fs/fs-test.sh | 11 +++ 1 file changed, 11 insertions(+) diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh index 12450ed..cb2a765 100755 --- a/test/fs/fs-test.sh +++ b/test/fs/fs-test.sh @@ -291,6 +291,12 @@ ${PREFIX}load host${SUFFIX} $addr ${FPATH}$FILE_WRITE md5sum $addr \$filesize setenv filesize # + +# Next test case checks writing a file whose dirent +# is the first in the block, which is always true for "." +# The write should fail, but the lookup should work +# Test Case 12 - Check directory traversal +${PREFIX}${WRITE} host${SUFFIX} $addr ${FPATH}. 0x10 reset EOF @@ -471,6 +477,11 @@ function check_results() { pass_fail "TC11: 1MB write to $5 - write succeeded" check_md5 "Test Case 11b " "$1" "$2" 1 \ "TC11: 1MB write to $5 - content verified" + + # Check lookup of 'dot' directory + grep -A5 "Test Case 12 " "$1" | \ + egrep -q 'Unable to write file' + pass_fail "TC12: 1MB write to . - write denied" echo "** End $1" } -- 2.10.0 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 07/16] ext4: Only update number of of unused inodes if GDT_CSUM feature is set
e2fsck warns about "Group descriptor 0 marked uninitialized without feature set." The bg_itable_unused field is only defined if FEATURE_RO_COMPAT_GDT_CSUM is set, and should be set (kept) zero otherwise. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index e8e6c00..e58ba36 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -988,12 +988,13 @@ int ext4fs_get_new_inode_no(void) if (!journal_buffer || !zero_buffer) goto fail; struct ext2_block_group *bgd = (struct ext2_block_group *)fs->gdtable; + int has_gdt_chksum = le32_to_cpu(fs->sb->feature_ro_compat) & + EXT4_FEATURE_RO_COMPAT_GDT_CSUM ? 1 : 0; if (fs->first_pass_ibmap == 0) { for (i = 0; i < fs->no_blkgrp; i++) { if (bgd[i].free_inodes) { - if (bgd[i].bg_itable_unused != - bgd[i].free_inodes) + if (has_gdt_chksum) bgd[i].bg_itable_unused = bgd[i].free_inodes; if (le16_to_cpu(bgd[i].bg_flags) & EXT4_BG_INODE_UNINIT) { @@ -1014,7 +1015,8 @@ int ext4fs_get_new_inode_no(void) (i * inodes_per_grp); fs->first_pass_ibmap++; ext4fs_bg_free_inodes_dec([i]); - ext4fs_bg_itable_unused_dec([i]); + if (has_gdt_chksum) + ext4fs_bg_itable_unused_dec([i]); ext4fs_sb_free_inodes_dec(fs->sb); status = ext4fs_devread( (lbaint_t)le32_to_cpu(bgd[i].inode_id) * @@ -1069,12 +1071,10 @@ restart: goto fail; prev_inode_bitmap_index = ibmap_idx; } - if (bgd[ibmap_idx].bg_itable_unused != - bgd[ibmap_idx].free_inodes) + ext4fs_bg_free_inodes_dec([ibmap_idx]); + if (has_gdt_chksum) bgd[ibmap_idx].bg_itable_unused = bgd[ibmap_idx].free_inodes; - ext4fs_bg_free_inodes_dec([ibmap_idx]); - ext4fs_bg_itable_unused_dec([ibmap_idx]); ext4fs_sb_free_inodes_dec(fs->sb); goto success; } -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 10/16] ext4: Avoid out-of-bounds access of block bitmap
If the blocksize is 1024, count is initialized with 1. Incrementing count by 8 will never match (count == fs->blksz * 8), and ptr may be incremented beyond the buffer end if the bitmap is filled. Add the startblock offset after the loop. Remove the second loop, as only the first iteration will be done. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 34 -- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 8fc7559..72fc4af 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -163,18 +163,12 @@ static int _get_new_inode_no(unsigned char *buffer) static int _get_new_blk_no(unsigned char *buffer) { - unsigned char input; - int operand, status; + int operand; int count = 0; - int j = 0; + int i; unsigned char *ptr = buffer; struct ext_filesystem *fs = get_fs(); - if (fs->blksz != 1024) - count = 0; - else - count = 1; - while (*ptr == 255) { ptr++; count += 8; @@ -182,21 +176,17 @@ static int _get_new_blk_no(unsigned char *buffer) return -1; } - for (j = 0; j < fs->blksz; j++) { - input = *ptr; - int i = 0; - while (i <= 7) { - operand = 1 << i; - status = input & operand; - if (status) { - i++; - count++; - } else { - *ptr |= operand; - return count; - } + if (fs->blksz == 1024) + count += 1; + + for (i = 0; i <= 7; i++) { + operand = 1 << i; + if (*ptr & operand) { + count++; + } else { + *ptr |= operand; + return count; } - ptr = ptr + 1; } return -1; -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 15/16] ext4: Correct block number handling, empty block vs. error code
read_allocated block may return block number 0, which is just an indicator a chunk of the file is not backed by a block, i.e. it is sparse. During file deletions, just continue with the next logical block, for other operations treat blocknumber <= 0 as an error. For writes, blocknumber 0 should never happen, as U-Boot always allocates blocks for the whole file. Reading already handles this correctly, i.e. the read buffer is 0-fillled. Not treating block 0 as sparse block leads to FS corruption, e.g. ./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ; ext4write host 0 0 /2.5GB.file 1 ' The 2.5GB.file from the fs test is actually a sparse file. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_common.c | 6 +++--- fs/ext4/ext4_write.c | 11 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 72fc4af..a78b0b8 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -534,7 +534,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { blknr = read_allocated_block(parent_inode, blk_idx); - if (blknr == 0) + if (blknr <= 0) goto fail; /* read the directory block */ @@ -828,7 +828,7 @@ int ext4fs_filename_unlink(char *filename) /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { blknr = read_allocated_block(g_parent_inode, blk_idx); - if (blknr == 0) + if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); if (inodeno != -1) @@ -1590,7 +1590,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (status == 0) { printf("** SI ext2fs read block (indir 1)" "failed. **\n"); - return 0; + return -1; } ext4fs_indir1_blkno = le32_to_cpu(inode->b.blocks. diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 20005f5..b3ea07b 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -461,6 +461,10 @@ static int ext4fs_delete_file(int inodeno) /* release data blocks */ for (i = 0; i < no_blocks; i++) { blknr = read_allocated_block(, i); + if (blknr == 0) + continue; + if (blknr < 0) + goto fail; bg_idx = blknr / blk_per_grp; if (fs->blksz == 1024) { remainder = blknr % blk_per_grp; @@ -718,6 +722,10 @@ void ext4fs_deinit(void) fs->curr_blkno = 0; } +/* + * Write data to filesystem blocks. Uses same optimization for + * contigous sectors as ext4fs_read_file + */ static int ext4fs_write_file(struct ext2_inode *file_inode, int pos, unsigned int len, char *buf) { @@ -744,7 +752,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, int blockend = fs->blksz; int skipfirst = 0; blknr = read_allocated_block(file_inode, i); - if (blknr < 0) + if (blknr <= 0) return -1; blknr = blknr << log2_fs_blocksize; @@ -910,6 +918,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, /* copy the file content into data blocks */ if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { printf("Error in copying content\n"); + /* FIXME: Deallocate data blocks */ goto fail; } ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 14/16] ext4: remove duplicated block release code for extents
The data blocks are identical for files using traditional direct/indirect block allocation scheme and extent trees, thus this code part can be common. Only the code to deallocate the indirect blocks to record the used blocks has to be seperate, respectively the code to release extent tree index blocks. Actually the code to release the extent tree index blocks is still missing, but at least add a FIXME at the appropriate place. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_write.c | 110 --- 1 file changed, 33 insertions(+), 77 deletions(-) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 5b518ed..20005f5 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -447,92 +447,48 @@ static int ext4fs_delete_file(int inodeno) no_blocks++; if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { - struct ext2fs_node *node_inode = - zalloc(sizeof(struct ext2fs_node)); - if (!node_inode) - goto fail; - node_inode->data = ext4fs_root; - node_inode->ino = inodeno; - node_inode->inode_read = 0; - memcpy(&(node_inode->inode), , sizeof(struct ext2_inode)); - - for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&(node_inode->inode), i); - bg_idx = blknr / blk_per_grp; - if (fs->blksz == 1024) { - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], - bg_idx); - debug("EXT4_EXTENTS Block releasing %ld: %d\n", - blknr, bg_idx); - - ext4fs_bg_free_blocks_inc([bg_idx]); - ext4fs_sb_free_blocks_inc(fs->sb); - - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - status = - ext4fs_devread( - (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) * - fs->sect_perblk, 0, - fs->blksz, journal_buffer); - if (status == 0) - goto fail; - if (ext4fs_log_journal(journal_buffer, - le32_to_cpu(bgd[bg_idx].block_id))) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - if (node_inode) { - free(node_inode); - node_inode = NULL; - } + /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */ + struct ext4_extent_header *eh = + (struct ext4_extent_header *) + inode.b.blocks.dir_blocks; + debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries); } else { - delete_single_indirect_block(); delete_double_indirect_block(); delete_triple_indirect_block(); + } - /* read the block no allocated to a file */ - no_blocks = le32_to_cpu(inode.size) / fs->blksz; - if (le32_to_cpu(inode.size) % fs->blksz) - no_blocks++; - for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(, i); - bg_idx = blknr / blk_per_grp; - if (fs->blksz == 1024) { - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], - bg_idx); - debug("ActualB releasing %ld: %d\n", blknr, bg_idx); + /* release data blocks */ + for (i = 0; i < no_blocks; i++) { + blknr = read_allocated_block(, i); + bg_idx = blknr / blk_per_grp; + if (fs->blksz == 1024) { + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], +
[U-Boot] [PATCH v5 03/16] ext4: Do not crash when trying to grow a directory using extents
The following command crashes u-boot: ./sandbox/u-boot -c 'i=0; host bind 0 ./sandbox/test/fs/3GB.ext4.img ; while test $i -lt 200 ; do echo $i; setexpr i $i + 1; ext4write host 0 0 /foobar${i} 0; done' Previously, the code updated the direct_block even for extents, and fortunately crashed before pushing garbage to the disk. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 5799bee..dff03fe 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -453,8 +453,13 @@ restart: sizeof(struct ext2_dirent) + padding_factor; if ((fs->blksz - totalbytes - last_entry_dirlen) < new_entry_byte_reqd) { - printf("1st Block Full:Allocate new block\n"); + printf("Last Block Full:Allocate new block\n"); + if (le32_to_cpu(g_parent_inode->flags) & + EXT4_EXTENTS_FL) { + printf("Directory uses extents\n"); + goto fail; + } if (direct_blk_idx == INDIRECT_BLOCKS - 1) { printf("Directory exceeds limit\n"); goto fail; -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 05/16] ext4: Avoid corruption of directories with hash tree indexes
While directories can be read using the old linear scan method, adding a new file would require updating the index tree (alternatively, the whole tree could be removed). Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_write.c | 5 + include/ext4fs.h | 1 + 2 files changed, 6 insertions(+) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 42abd8d..50c8415 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -881,6 +881,11 @@ int ext4fs_write(const char *fname, unsigned char *buffer, goto fail; if (ext4fs_iget(parent_inodeno, g_parent_inode)) goto fail; + /* do not mess up a directory using hash trees */ + if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) { + printf("hash tree directory\n"); + goto fail; + } /* check if the filename is already present in root */ existing_file_inodeno = ext4fs_filename_unlink(filename); if (existing_file_inodeno != -1) { diff --git a/include/ext4fs.h b/include/ext4fs.h index e3f6216..6e31c73 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -28,6 +28,7 @@ #define __EXT4__ #include +#define EXT4_INDEX_FL 0x1000 /* Inode uses hash tree index */ #define EXT4_EXTENTS_FL0x0008 /* Inode uses extents */ #define EXT4_EXT_MAGIC 0xf30a #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM0x0010 -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 13/16] ext4: initialize full inode for inodes bigger than 128 bytes
Make sure the the extra_isize field (offset 128) is initialized to 0, to mark any extra data as invalid. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_write.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 81a750b..5b518ed 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -560,7 +560,7 @@ static int ext4fs_delete_file(int inodeno) read_buffer = read_buffer + blkoff; inode_buffer = (struct ext2_inode *)read_buffer; - memset(inode_buffer, '\0', sizeof(struct ext2_inode)); + memset(inode_buffer, '\0', fs->inodesz); /* write the inode to original position in inode table */ if (ext4fs_put_metadata(start_block_address, blkno)) @@ -866,7 +866,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); memset(filename, 0x00, 256); - g_parent_inode = zalloc(sizeof(struct ext2_inode)); + g_parent_inode = zalloc(fs->inodesz); if (!g_parent_inode) goto fail; @@ -969,8 +969,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) goto fail; - memcpy(temp_ptr + blkoff, g_parent_inode, - sizeof(struct ext2_inode)); + memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) goto fail; } else { @@ -978,8 +977,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, * If parent and child fall in same inode table block * both should be kept in 1 buffer */ - memcpy(temp_ptr + blkoff, g_parent_inode, - sizeof(struct ext2_inode)); + memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); gd_index--; if (ext4fs_put_metadata(temp_ptr, itable_blkno)) goto fail; -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 04/16] ext4: Scan all directory blocks for space when inserting a new entry
Previously, only the last directory block was scanned for available space. Instead, scan all blocks back to front, and if no sufficient space is found, eventually append a new block. Blocks are only appended if the directory does not use extents or the new block would require insertion of indirect blocks, as the old code does. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 74 +-- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index dff03fe..062ea93 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -370,14 +370,10 @@ int ext4fs_update_parent_dentry(char *filename, int file_type) { unsigned int *zero_buffer = NULL; char *root_first_block_buffer = NULL; - int direct_blk_idx; - long int root_blknr; + int blk_idx; long int first_block_no_of_root = 0; - long int previous_blknr = -1; int totalbytes = 0; - short int padding_factor = 0; unsigned int new_entry_byte_reqd; - unsigned int last_entry_dirlen; int sizeof_void_space = 0; int templength = 0; int inodeno = -1; @@ -389,6 +385,7 @@ int ext4fs_update_parent_dentry(char *filename, int file_type) uint32_t new_blk_no; uint32_t new_size; uint32_t new_blockcnt; + uint32_t directory_blocks; zero_buffer = zalloc(fs->blksz); if (!zero_buffer) { @@ -401,19 +398,18 @@ int ext4fs_update_parent_dentry(char *filename, int file_type) printf("No Memory\n"); return -1; } + new_entry_byte_reqd = ROUND(strlen(filename) + + sizeof(struct ext2_dirent), 4); restart: + directory_blocks = le32_to_cpu(g_parent_inode->size) >> + LOG2_BLOCK_SIZE(ext4fs_root); + blk_idx = directory_blocks - 1; +restart_read: /* read the block no allocated to a file */ - for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS; -direct_blk_idx++) { - root_blknr = read_allocated_block(g_parent_inode, - direct_blk_idx); - if (root_blknr == 0) { - first_block_no_of_root = previous_blknr; - break; - } - previous_blknr = root_blknr; - } + first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx); + if (first_block_no_of_root <= 0) + goto fail; status = ext4fs_devread((lbaint_t)first_block_no_of_root * fs->sect_perblk, @@ -425,42 +421,33 @@ restart: goto fail; dir = (struct ext2_dirent *)root_first_block_buffer; totalbytes = 0; + while (le16_to_cpu(dir->direntlen) > 0) { - /* -* blocksize-totalbytes because last directory length -* i.e. dir->direntlen is free availble space in the -* block that means it is a last entry of directory -* entry -*/ + unsigned short used_len = ROUND(dir->namelen + + sizeof(struct ext2_dirent), 4); - /* traversing the each directory entry */ + /* last entry of block */ if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) { - if (strlen(filename) % 4 != 0) - padding_factor = 4 - (strlen(filename) % 4); - - new_entry_byte_reqd = strlen(filename) + - sizeof(struct ext2_dirent) + padding_factor; - padding_factor = 0; - /* -* update last directory entry length to its -* length because we are creating new directory -* entry -*/ - if (dir->namelen % 4 != 0) - padding_factor = 4 - (dir->namelen % 4); - last_entry_dirlen = dir->namelen + - sizeof(struct ext2_dirent) + padding_factor; - if ((fs->blksz - totalbytes - last_entry_dirlen) < - new_entry_byte_reqd) { - printf("Last Block Full:Allocate new block\n"); + /* check if new entry fits */ + if ((used_len + new_entry_byte_reqd) <= + le16_to_cpu(dir->direntlen)) { + dir->direntlen = cpu_to_le16(used_len); + break; + } else { +
[U-Boot] [PATCH v5 16/16] ext4: Fix memory leak of journal buffer if block is updated multiple times
If the same block is updated multiple times in a row during a single file system operation, gd_index is decremented to use the same journal entry again. Avoid loosing the already allocated buffer. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> --- fs/ext4/ext4_journal.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c index cf14049..5a25be4 100644 --- a/fs/ext4/ext4_journal.c +++ b/fs/ext4/ext4_journal.c @@ -190,7 +190,11 @@ int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr) printf("Invalid input arguments %s\n", __func__); return -EINVAL; } - dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz); + if (dirty_block_ptr[gd_index]->buf) + assert(dirty_block_ptr[gd_index]->blknr == blknr); + else + dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz); + if (!dirty_block_ptr[gd_index]->buf) return -ENOMEM; memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz); -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 00/16] Fix several possible crashes/corruptions in ext4
The U-Boot ext4 support has some bugs which either cause U-Boot crashes or lead to filesystem corruption. This series goes on top of the endian patch series by Michael Walle. It has been rebased against v4 of the series. The first 13 patches have already been reviewed, last 3 patches are new. Revieved-by has been added as appropriate. Stefan Brüns (16): ext4: fix possible crash on directory traversal, ignore deleted entries ext4: propagate error if creation of directory entry fails ext4: Do not crash when trying to grow a directory using extents ext4: Scan all directory blocks for space when inserting a new entry ext4: Avoid corruption of directories with hash tree indexes ext4: Scan all directory blocks when looking up an entry ext4: Only update number of of unused inodes if GDT_CSUM feature is set ext4: Do not clear zalloc'ed buffers a second time ext4: After completely filled group, scan next group from the beginning ext4: Avoid out-of-bounds access of block bitmap ext4: Fix memory leak in case of failure ext4: Use correct value for inode size even on revision 0 filesystems ext4: initialize full inode for inodes bigger than 128 bytes ext4: remove duplicated block release code for extents ext4: Correct block number handling, empty block vs. error code ext4: Fix memory leak of journal buffer if block is updated multiple times fs/ext4/ext4_common.c | 288 + fs/ext4/ext4_common.h | 2 +- fs/ext4/ext4_journal.c | 6 +- fs/ext4/ext4_write.c | 147 ++--- include/ext4fs.h | 3 +- include/ext_common.h | 2 - 6 files changed, 190 insertions(+), 258 deletions(-) v2: Updated: ext4: fix possible crash on directory traversal, ignore deleted entries - Fix bad filename compare on delete, used substring only v3: Added: ext4: Scan all directory blocks for space when inserting a new entry ext4: Only update number of of unused inodes if GDT_CSUM feature is set ext4: Do not clear zalloc'ed buffers a second time ext4: After completely filled group, scan next group from the beginning ext4: Avoid out-of-bounds access of block bitmap ext4: Fix memory leak in case of failure ext4: Use correct value for inode size even on revision 0 filesystems ext4: initialize full inode for inodes bigger than 128 bytes ext4: remove duplicated block release code for extents Updated: ext4: Scan all directory blocks when looking up an entry - use parent_inode instead of g_parent_inode when determining directory size v4: Updated: ext4: Scan all directory blocks when looking up an entry - fix directory scan, direntname was advanced by offset instead of direntlen Problem reported by Thomas Schaefer <thomas.schae...@kontron.com> v5: Added: ext4: remove duplicated block release code for extents ext4: Correct block number handling, empty block vs. error code ext4: Fix memory leak of journal buffer if block is updated multiple times Updated: ext4: initialize full inode for inodes bigger than 128 bytes - fix memory corruption if sizeof(struct ext2_inode) != fs->inodesz Problem reported by Thomas Schaefer <thomas.schae...@kontron.com> -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 09/16] ext4: After completely filled group, scan next group from the beginning
The last free block of a block group may be in its middle. After it has been allocated, the next block group should be scanned from its beginning. The following command triggers the bad behaviour (on a blocksize 1024 fs): ./sandbox/u-boot -c 'i=0; host bind 0 ./disk.raw ; while test $i -lt 260 ; do echo $i; setexpr i $i + 1; ext4write host 0:2 0 /X${i} 0x1450; done ; ext4write host 0:2 0 /X240 0x2000 ; ' When 'X240' is extended from 5200 byte to 8192 byte, the new blocks should start from the first free block (8811), but it uses the blocks 8098-8103 and 16296-16297 -- 8103 + 1 + 8192 = 16296. This can be shown with debugfs, commands 'ffb' and 'stat X240'. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 539d622..8fc7559 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -903,8 +903,8 @@ uint32_t ext4fs_get_new_blk_no(void) goto fail; } else { -restart: fs->curr_blkno++; +restart: /* get the blockbitmap index respective to blockno */ bg_idx = fs->curr_blkno / blk_per_grp; if (fs->blksz == 1024) { @@ -922,8 +922,9 @@ restart: if (bgd[bg_idx].free_blocks == 0) { debug("block group %u is full. Skipping\n", bg_idx); - fs->curr_blkno = fs->curr_blkno + blk_per_grp; - fs->curr_blkno--; + fs->curr_blkno = (bg_idx + 1) * blk_per_grp; + if (fs->blksz == 1024) + fs->curr_blkno += 1; goto restart; } @@ -940,6 +941,7 @@ restart: bg_idx) != 0) { debug("going for restart for the block no %ld %u\n", fs->curr_blkno, bg_idx); + fs->curr_blkno++; goto restart; } -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 11/16] ext4: Fix memory leak in case of failure
temp_ptr should always be freed, even if the function is left via goto fail. Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 50c8415..5e208ef 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -974,7 +974,6 @@ int ext4fs_write(const char *fname, unsigned char *buffer, sizeof(struct ext2_inode)); if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) goto fail; - free(temp_ptr); } else { /* * If parent and child fall in same inode table block @@ -985,7 +984,6 @@ int ext4fs_write(const char *fname, unsigned char *buffer, gd_index--; if (ext4fs_put_metadata(temp_ptr, itable_blkno)) goto fail; - free(temp_ptr); } ext4fs_update(); ext4fs_deinit(); @@ -996,6 +994,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, fs->curr_inode_no = 0; free(inode_buffer); free(g_parent_inode); + free(temp_ptr); g_parent_inode = NULL; return 0; @@ -1003,6 +1002,7 @@ fail: ext4fs_deinit(); free(inode_buffer); free(g_parent_inode); + free(temp_ptr); g_parent_inode = NULL; return -1; -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v5 08/16] ext4: Do not clear zalloc'ed buffers a second time
zero_buffer is never written, thus clearing it is pointless. journal_buffer is completely initialized by ext4fs_devread (or in case of failure, not used). Signed-off-by: Stefan Brüns <stefan.bru...@rwth-aachen.de> Reviewed-by: Lukasz Majewski <l.majew...@samsung.com> --- fs/ext4/ext4_common.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index e58ba36..539d622 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -929,7 +929,6 @@ restart: if (le16_to_cpu(bgd[bg_idx].bg_flags) & EXT4_BG_BLOCK_UNINIT) { uint16_t new_flags; - memset(zero_buffer, '\0', fs->blksz); put_ext4((uint64_t)le32_to_cpu(bgd[bg_idx].block_id) * fs->blksz, zero_buffer, fs->blksz); memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz); @@ -946,7 +945,6 @@ restart: /* journal backup */ if (prev_bg_bitmap_index != bg_idx) { - memset(journal_buffer, '\0', fs->blksz); status = ext4fs_devread( (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) * fs->sect_perblk, @@ -1040,7 +1038,6 @@ restart: ibmap_idx = fs->curr_inode_no / inodes_per_grp; if (le16_to_cpu(bgd[ibmap_idx].bg_flags) & EXT4_BG_INODE_UNINIT) { int new_flags; - memset(zero_buffer, '\0', fs->blksz); put_ext4((uint64_t)le32_to_cpu(bgd[ibmap_idx].inode_id) * fs->blksz, zero_buffer, fs->blksz); new_flags = le16_to_cpu(bgd[ibmap_idx].bg_flags) & ~EXT4_BG_INODE_UNINIT; -- 2.9.3 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot