git: 3eb019000c9e - main - loader: tftp: Add preload method

From: Emmanuel Vadot <manu_at_FreeBSD.org>
Date: Thu, 16 Dec 2021 10:53:24 UTC
The branch main has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=3eb019000c9eba6dafad6741a88f627b4d4fcd8a

commit 3eb019000c9eba6dafad6741a88f627b4d4fcd8a
Author:     Emmanuel Vadot <manu@FreeBSD.org>
AuthorDate: 2021-12-10 09:37:01 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2021-12-16 10:50:41 +0000

    loader: tftp: Add preload method
    
    The preload method will transfer the whole file in a buffer and cache it
    so read/lseek operations are faster.
    
    Reviewed by:    imp, tsoome
    MFC after:      2 weeks
    Sponsored by:   Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D33410
---
 stand/libsa/tftp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/stand/libsa/tftp.c b/stand/libsa/tftp.c
index dcfce29a9968..9d1c70236925 100644
--- a/stand/libsa/tftp.c
+++ b/stand/libsa/tftp.c
@@ -73,6 +73,7 @@ static int tftp_read(struct open_file *, void *, size_t, size_t *);
 static off_t tftp_seek(struct open_file *, off_t, int);
 static int tftp_set_blksize(struct tftp_handle *, const char *);
 static int tftp_stat(struct open_file *, struct stat *);
+static int tftp_preload(struct open_file *);
 
 struct fs_ops tftp_fsops = {
 	.fs_name = "tftp",
@@ -82,6 +83,7 @@ struct fs_ops tftp_fsops = {
 	.fo_write = null_write,
 	.fo_seek = tftp_seek,
 	.fo_stat = tftp_stat,
+	.fo_preload = tftp_preload,
 	.fo_readdir = null_readdir
 };
 
@@ -521,6 +523,16 @@ tftp_read(struct open_file *f, void *addr, size_t size,
 		size = tftpfile->tftp_tsize - tftpfile->off;
 	}
 
+	if (tftpfile->tftp_cache != NULL) {
+		bcopy(tftpfile->tftp_cache + tftpfile->off,
+		    addr, size);
+
+		addr = (char *)addr + size;
+		tftpfile->off += size;
+		res -= size;
+		goto out;
+	}
+
 	while (size > 0) {
 		int needblock, count;
 
@@ -586,6 +598,7 @@ tftp_read(struct open_file *f, void *addr, size_t size,
 
 	}
 
+out:
 	if (resid != NULL)
 		*resid = res;
 	return (rc);
@@ -603,6 +616,7 @@ tftp_close(struct open_file *f)
 	if (tftpfile) {
 		free(tftpfile->path);
 		free(tftpfile->pkt);
+		free(tftpfile->tftp_cache);
 		free(tftpfile);
 	}
 	is_open = 0;
@@ -643,6 +657,52 @@ tftp_seek(struct open_file *f, off_t offset, int where)
 	return (tftpfile->off);
 }
 
+static int
+tftp_preload(struct open_file *f)
+{
+	struct tftp_handle *tftpfile;
+	char *cache;
+	int rc;
+#ifdef TFTP_DEBUG
+	time_t start, end;
+#endif
+
+	tftpfile = f->f_fsdata;
+	cache = malloc(sizeof(char) * tftpfile->tftp_tsize);
+	if (cache == NULL) {
+		printf("Couldn't allocate %ju bytes for preload caching"
+		    ", disabling caching\n",
+		    (uintmax_t)sizeof(char) * tftpfile->tftp_tsize);
+		return (-1);
+	}
+
+#ifdef TFTP_DEBUG
+	start = getsecs();
+	printf("Preloading %s ", tftpfile->path);
+#endif
+	while (tftpfile->islastblock == 0) {
+		twiddle(32);
+		rc = tftp_getnextblock(tftpfile);
+		if (rc) {
+			free(cache);
+			printf("Got TFTP error %d, disabling caching\n", rc);
+			return (rc);
+		}
+		bcopy(tftpfile->tftp_hdr->th_data,
+		    cache + (tftpfile->tftp_blksize * (tftpfile->currblock - 1)),
+		    tftpfile->validsize);
+	}
+#ifdef TFTP_DEBUG
+	end = getsecs();
+	printf("\nPreloaded %s (%ju bytes) during %jd seconds\n",
+	    tftpfile->path, (intmax_t)tftpfile->tftp_tsize,
+	    (intmax_t)end - start);
+#endif
+
+	tftpfile->tftp_cache = cache;
+	return (0);
+}
+
 static int
 tftp_set_blksize(struct tftp_handle *h, const char *str)
 {