Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Aug 2001 11:27:20 -0700 (PDT)
From:      John Polstra <jdp@polstra.com>
To:        hackers@freebsd.org
Subject:   PLEASE REVIEW: loader fix for gzipped kernels
Message-ID:  <XFMail.010829112720.jdp@polstra.com>

next in thread | raw e-mail | index | archive | help
This message is in MIME format
--_=XFMail.1.3.p0.FreeBSD:010829112720:295=_
Content-Type: text/plain; charset=us-ascii

I would appreciate another pair of eyes on the attached patch before
I commit it.

I have been working with gzipped kernels a lot lately, and have
noticed that when the loader tries to load certain kernels, it fails
with the message "elf_loadexec: cannot seek".  I tracked this down to
a bug in "src/lib/libstand/lseek.c", which is fixed by this patch.

Here is the bug that it fixed.  Libstand maintains a read-ahead buffer
for each open file, so that it can read in chunks of 512 bytes for
greater efficiency.  When the loader tries to lseek forward in a file
by a small amount, it sometimes happens that the target file offset is
already in the read-ahead buffer.  But the existing code in lseek.c
simply discards the contents of that buffer and does a seek directly
on the underlying file.  This results in an attempt to seek backwards
in the file, since some of the data has already been read into the
read-ahead buffer.  Gzipped data streams cannot seek backwards, so an
error is returned.

The code added by the patch checks to see if the desired file offset
is already in the read-ahead buffer.  If it is, the code simply
adjusts the buffer pointer and length, thereby avoiding a reverse seek
on the gzipped data stream.

The bug is present in both -current and -stable.  This patch is
relative to -stable, but it applies cleanly to -current too.

John
--
  John Polstra                                               jdp@polstra.com
  John D. Polstra & Co., Inc.                        Seattle, Washington USA
  "Disappointment is a good sign of basic intelligence."  -- Chögyam Trungpa


--_=XFMail.1.3.p0.FreeBSD:010829112720:295=_
Content-Disposition: attachment; filename="libstand.patch"
Content-Type: text/plain; charset=us-ascii; name=libstand.patch; SizeOnDisk=1410
Content-Transfer-Encoding: 7bit

Index: lseek.c
===================================================================
RCS file: /home/ncvs/src/lib/libstand/lseek.c,v
retrieving revision 1.1.1.1.6.1
diff -u -r1.1.1.1.6.1 lseek.c
--- lseek.c	2000/09/10 01:32:06	1.1.1.1.6.1
+++ lseek.c	2001/08/29 17:45:21
@@ -70,6 +70,8 @@
 off_t
 lseek(int fd, off_t offset, int where)
 {
+    struct stat sb;
+    off_t bufpos, filepos, target;
     struct open_file *f = &files[fd];
 
     if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
@@ -94,6 +96,39 @@
 	    return (-1);
 	}
 	return (f->f_offset);
+    }
+
+    /*
+     * If there is some unconsumed data in the readahead buffer and it
+     * contains the desired offset, simply adjust the buffer pointers.
+     */
+    if (f->f_ralen != 0) {
+	if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1)
+	    return (-1);
+	bufpos = filepos - f->f_ralen;
+	switch (where) {
+	case SEEK_SET:
+	    target = offset;
+	    break;
+	case SEEK_CUR:
+	    target = bufpos + offset;
+	    break;
+	case SEEK_END:
+	    if ((f->f_ops->fo_stat)(f, &sb) == -1 || sb.st_size == -1) {
+		errno = EOFFSET;
+		return (-1);
+	    }
+	    target = sb.st_size + offset;
+	    break;
+	default:
+	    errno = EINVAL;
+	    return (-1);
+	}
+	if (bufpos <= target && target < filepos) {
+	    f->f_raoffset += target - bufpos;
+	    f->f_ralen -= target - bufpos;
+	    return (target);
+	}
     }
 
     /*

--_=XFMail.1.3.p0.FreeBSD:010829112720:295=_--
End of MIME message

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?XFMail.010829112720.jdp>