net: nfs: add support for partial downloads from given offset
authorMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 17 Mar 2020 13:03:10 +0000 (14:03 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 16 Nov 2021 10:04:04 +0000 (11:04 +0100)
Add support for downloading file from the given offset (in bytes) and limit the size up to given
bytes.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: I9f442d375d6b37986cb7c10f93c11d265886cceb

cmd/net.c
include/net.h
net/nfs.c

index 651c141..385131f 100644 (file)
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -201,6 +201,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
        ulong addr;
 
        net_boot_file_name_explicit = false;
+       net_boot_file_offset = 0;
+       net_boot_file_size_limit = 0;
 
        /* pre-set image_load_addr */
        s = env_get("loadaddr");
@@ -286,6 +288,45 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
        return rcode;
 }
 
+int netboot_nfs(unsigned long addr, const char *filename,
+               unsigned long offset, unsigned long limit)
+{
+       int   rcode = 0;
+       int   size;
+
+       image_load_addr = addr;
+       net_boot_file_name_explicit = true;
+       net_boot_file_offset = offset;
+       net_boot_file_size_limit = limit;
+
+       copy_filename(net_boot_file_name, filename,
+                     sizeof(net_boot_file_name));
+
+       bootstage_mark(BOOTSTAGE_ID_NET_START);
+
+       size = net_loop(NFS);
+       if (size < 0) {
+               bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
+               return CMD_RET_FAILURE;
+       }
+       bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
+
+       /* done if no file was loaded (no errors though) */
+       if (size == 0) {
+               bootstage_error(BOOTSTAGE_ID_NET_LOADED);
+               return CMD_RET_SUCCESS;
+       }
+
+       bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
+
+       if (rcode == CMD_RET_SUCCESS)
+               bootstage_mark(BOOTSTAGE_ID_NET_DONE);
+       else
+               bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
+       return rcode;
+}
+
+
 #if defined(CONFIG_CMD_PING)
 static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
                   char *const argv[])
index cec8c98..4c4735f 100644 (file)
@@ -570,6 +570,13 @@ extern char        net_boot_file_name[1024];/* Boot File name */
 extern bool    net_boot_file_name_explicit;
 /* The actual transferred size of the bootfile (in bytes) */
 extern u32     net_boot_file_size;
+
+/* Offset/size for partial downloads for nfsdown tool */
+extern u32     net_boot_file_size_limit;
+extern u32     net_boot_file_offset;
+extern int netboot_nfs(unsigned long addr, const char *filename,
+               unsigned long offset, unsigned long size);
+
 /* Boot file size in blocks as reported by the DHCP server */
 extern u32     net_boot_file_expected_size_in_blocks;
 
index 6b81c41..da6fe1f 100644 (file)
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -54,6 +54,8 @@ static unsigned long rpc_id;
 static int nfs_offset = -1;
 static int nfs_len;
 static ulong nfs_timeout = NFS_TIMEOUT;
+u32 net_boot_file_size_limit;
+u32 net_boot_file_offset;
 
 static char dirfh[NFS_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */
 static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
@@ -716,7 +718,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
        if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + rlen) > len)
                        return -9999;
 
-       if (store_block(data_ptr, nfs_offset, rlen))
+       if (store_block(data_ptr, nfs_offset - net_boot_file_offset, rlen))
                        return -9999;
 
        return rlen;
@@ -814,7 +816,7 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
                        nfs_send();
                } else {
                        nfs_state = STATE_READ_REQ;
-                       nfs_offset = 0;
+                       nfs_offset = net_boot_file_offset;
                        nfs_len = NFS_READ_SIZE;
                        nfs_send();
                }
@@ -845,6 +847,11 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
                net_set_timeout_handler(nfs_timeout, nfs_timeout_handler);
                if (rlen > 0) {
                        nfs_offset += rlen;
+                       if (nfs_offset - net_boot_file_offset ==
+                           net_boot_file_size_limit) {
+                               nfs_download_state = NETLOOP_SUCCESS;
+                               nfs_state = STATE_UMOUNT_REQ;
+                       }
                        nfs_send();
                } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) {
                        /* symbolic link */