package:busybox
version:1.34.1
kernel:linux 5.10
When using tar to decompress an xz-compressed file stored in memory to nor
flash, the execution time occasionally doubles.(6 out of 50 times, with
kernel-mode execution time nearly doubling from 13.32s to 20.80)
time tar Jxf /tmp/a.tar.xz -C /nor_flash
Normal case:
real 0m 53.14s
user 0m 0.75s
sys 0m 13.32s
Abnormal case:
real 1m 2.79s
user 0m 0.77s
sys 0m 20.80s
Through debugging, it was found that the issue occurs when the count parameter
passed to the first write() system call for decompressing a single file is not
4096 bytes.
Normal case:
write(fd, buf, count=4096) -- first
… -- All intermediate writes with count parameter value 4096
write(fd, buf, count=4096)
Abnormal case:
write(fd, buf, count=2414) -- first
… -- All intermediate writes with count parameter value 4096
write(fd, buf, count=1682)
Function call path:
archival/tar.c : get_header_tar
archival/libarchive/data_extract_all.c : data_extract_all
libbb/copyfd.c : bb_copyfd_size
libbb/copyfd.c : bb_full_fd_action
libbb/full_write.c : full_write
libbb/safe_write.c : safe_write
write
Further analysis shows that the count parameter in the write() system call
originates from the return value of safe_read() in the bb_full_fd_action()
function. In abnormal case, the first safe_read() does not return 4096 because
there was not enough data ready in the input fd(the output fd of
unpack_xz_stream() function).
Fault injection attempts showed that by modifying bb_full_fd_action() to force
the first safe_read() to read only 2414 bytes, the issue could be reproduced
consistently.
@@ -84,8 +84,15 @@ static off_t bb_full_fd_action(int src_f
}
}
#endif
- rd = safe_read(src_fd, buffer,
- size > buffer_size ? buffer_size : size);
+ static bool first = true;
+ if(first) {
+ rd = safe_read(src_fd, buffer,
+ size > 2414 ? 2414 : size);
+ first = false;
+ } else {
+ rd = safe_read(src_fd, buffer,
+ size > buffer_size ? buffer_size : size);
+ }
if (rd < 0) {
bb_simple_perror_msg(bb_msg_read_error);
break;
As a workaround, replacing safe_read() with full_read() in the
bb_full_fd_action() function eliminated the issue (no performance degradation
observed over 200 runs).
@@ -84,7 +84,7 @@ static off_t bb_full_fd_action(int src_f
}
}
#endif
- rd = safe_read(src_fd, buffer,
+ rd = full_read(src_fd, buffer,
size > buffer_size ? buffer_size : size);
if (rd < 0) {
bb_simple_perror_msg(bb_msg_read_error);
Questions:
The bb_full_fd_action() function is used in many places. Is it feasible to
replace safe_read() with full_read()? What impacts need to be evaluated?
If replacement is not feasible, are there any recommended alternative
approaches to ensure that each write() system call during tar decompression
passes a count parameter value of 4096 when writing to flash?_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox