]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[linux] Do not assume that stat() works on sysfs files
authorMichael Brown <mcb30@ipxe.org>
Wed, 3 Mar 2021 02:24:32 +0000 (02:24 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 3 Mar 2021 02:26:42 +0000 (02:26 +0000)
Linux kernel 3.12 and earlier report a zero size via stat() for all
ACPI table files in sysfs.  There is no way to determine the file size
other than by reading the file until EOF.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/interface/linux/linux_sysfs.c

index 463bc2ab92a37bc1b025387917dcad95158dc53a..4f0027cd440278c26df8990cbb05af3d1ede590e 100644 (file)
@@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/** Read blocksize */
+#define LINUX_SYSFS_BLKSIZE 4096
+
 /**
  * Read file from sysfs
  *
@@ -40,9 +43,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @ret len            Length read, or negative error
  */
 int linux_sysfs_read ( const char *filename, userptr_t *data ) {
-       size_t offset;
-       size_t len;
+       userptr_t tmp;
        ssize_t read;
+       size_t len;
        int fd;
        int rc;
 
@@ -55,37 +58,27 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) {
                goto err_open;
        }
 
-       /* Get file length */
-       if ( linux_fstat_size ( fd, &len ) == -1 ) {
-               rc = -ELINUX ( linux_errno );
-               DBGC ( filename, "LINUX could not stat %s: %s\n",
-                      filename, linux_strerror ( linux_errno ) );
-               goto err_stat;
-       }
+       /* Read file */
+       for ( *data = UNULL, len = 0 ; ; len += read ) {
 
-       /* Allocate buffer */
-       *data = umalloc ( len );
-       if ( ! *data ) {
-               rc = -ENOMEM;
-               DBGC ( filename, "LINUX could not allocate %zd bytes for %s\n",
-                      len, filename );
-               goto err_alloc;
-       }
+               /* (Re)allocate space */
+               tmp = urealloc ( *data, ( len + LINUX_SYSFS_BLKSIZE ) );
+               if ( ! tmp ) {
+                       rc = -ENOMEM;
+                       goto err_alloc;
+               }
+               *data = tmp;
 
-       /* Read file */
-       for ( offset = 0 ; offset < len ; offset += read ) {
-               read = linux_read ( fd, user_to_virt ( *data, offset ), len );
+               /* Read from file */
+               read = linux_read ( fd, user_to_virt ( *data, len ),
+                                   LINUX_SYSFS_BLKSIZE );
+               if ( read == 0 )
+                       break;
                if ( read < 0 ) {
                        DBGC ( filename, "LINUX could not read %s: %s\n",
                               filename, linux_strerror ( linux_errno ) );
                        goto err_read;
                }
-               if ( read == 0 ) {
-                       rc = -EIO;
-                       DBGC ( filename, "LINUX read underlength %s\n",
-                              filename );
-                       goto err_eof;
-               }
        }
 
        /* Close file */
@@ -94,11 +87,9 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) {
        DBGC ( filename, "LINUX read %s\n", filename );
        return len;
 
- err_eof:
  err_read:
-       ufree ( *data );
  err_alloc:
- err_stat:
+       ufree ( *data );
        linux_close ( fd );
  err_open:
        return rc;