Improve status reporting

There are some user complaints that Imager hangs at "writing 0%"
Mention in the progress status what it is actually doing prior
to writing (e.g. opening storage, blkdiscarding,
zero'ing out MBR, starting download) to help diagnose
potential issues.
This commit is contained in:
Floris Bos 2020-11-19 18:10:05 +01:00
parent 8a44c6b3ca
commit 6b178731c7
7 changed files with 91 additions and 28 deletions

View file

@ -91,8 +91,24 @@ size_t DownloadThread::_curl_header_callback( void *ptr, size_t size, size_t nme
return len; return len;
} }
QByteArray DownloadThread::_fileGetContentsTrimmed(const QString &filename)
{
QByteArray result;
QFile f(filename);
if (f.exists() && f.open(f.ReadOnly))
{
result = f.readAll().trimmed();
f.close();
}
return result;
}
bool DownloadThread::_openAndPrepareDevice() bool DownloadThread::_openAndPrepareDevice()
{ {
emit preparationStatusUpdate(tr("opening drive"));
if (_filename.startsWith("/dev/")) if (_filename.startsWith("/dev/"))
{ {
unmount_disk(_filename.constData()); unmount_disk(_filename.constData());
@ -203,11 +219,65 @@ bool DownloadThread::_openAndPrepareDevice()
} }
#endif #endif
#ifdef Q_OS_LINUX
/* Optional optimizations for Linux */
if (_filename.startsWith("/dev/"))
{
QString devname = _filename.mid(5);
/* On some internal SD card readers CID/CSD is available, print it for debugging purposes */
QByteArray cid = _fileGetContentsTrimmed("/sys/block/"+devname+"/device/cid");
QByteArray csd = _fileGetContentsTrimmed("/sys/block/"+devname+"/device/csd");
if (!cid.isEmpty())
qDebug() << "SD card CID:" << cid;
if (!csd.isEmpty())
qDebug() << "SD card CSD:" << csd;
QByteArray discardmax = _fileGetContentsTrimmed("/sys/block/"+devname+"/queue/discard_max_bytes");
if (discardmax.isEmpty() || discardmax == "0")
{
qDebug() << "BLKDISCARD not supported";
}
else
{
/* DISCARD/TRIM the SD card */
uint64_t devsize, range[2];
int fd = _file.handle();
if (::ioctl(fd, BLKGETSIZE64, &devsize) == -1) {
qDebug() << "Error getting device/sector size with BLKGETSIZE64 ioctl():" << strerror(errno);
}
else
{
qDebug() << "Try to perform TRIM/DISCARD on device";
range[0] = 0;
range[1] = devsize;
emit preparationStatusUpdate(tr("discarding existing data on drive"));
_timer.start();
if (::ioctl(fd, BLKDISCARD, &range) == -1)
{
qDebug() << "BLKDISCARD failed.";
}
else
{
qDebug() << "BLKDISCARD successful. Discarding took" << _timer.elapsed() / 1000 << "seconds";
}
}
}
}
#endif
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
// Zero out MBR // Zero out MBR
qint64 knownsize = _file.size(); qint64 knownsize = _file.size();
QByteArray emptyMB(1024*1024, 0); QByteArray emptyMB(1024*1024, 0);
emit preparationStatusUpdate(tr("zeroing out first and last MB of drive"));
qDebug() << "Zeroing out first and last MB of drive";
_timer.start();
if (!_file.write(emptyMB.data(), emptyMB.size()) || !_file.flush()) if (!_file.write(emptyMB.data(), emptyMB.size()) || !_file.flush())
{ {
emit error(tr("Write error while zero'ing out MBR")); emit error(tr("Write error while zero'ing out MBR"));
@ -229,36 +299,10 @@ bool DownloadThread::_openAndPrepareDevice()
} }
emptyMB.clear(); emptyMB.clear();
_file.seek(0); _file.seek(0);
qDebug() << "Done zeroing out start and end of drive. Took" << _timer.elapsed() / 1000 << "seconds";
#endif #endif
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
/* Optional optimizations for Linux */
/* See if we can DISCARD/TRIM the SD card */
uint64_t devsize, range[2];
int fd = _file.handle();
if (::ioctl(fd, BLKGETSIZE64, &devsize) == -1) {
qDebug() << "Error getting device/sector size with BLKGETSIZE64 ioctl():" << strerror(errno);
}
else
{
int secsize;
::ioctl(fd, BLKSSZGET, &secsize);
qDebug() << "Sector size:" << secsize << "Device size:" << devsize;
qDebug() << "Try to perform TRIM/DISCARD on device";
range[0] = 0;
range[1] = devsize;
if (::ioctl(fd, BLKDISCARD, &range) == -1)
{
qDebug() << "BLKDISCARD not supported";
}
else
{
qDebug() << "BLKDISCARD successful";
}
}
_sectorsStart = _sectorsWritten(); _sectorsStart = _sectorsWritten();
#endif #endif
@ -303,6 +347,7 @@ void DownloadThread::run()
if (!_proxy.isEmpty()) if (!_proxy.isEmpty())
curl_easy_setopt(_c, CURLOPT_PROXY, _proxy.constData()); curl_easy_setopt(_c, CURLOPT_PROXY, _proxy.constData());
emit preparationStatusUpdate(tr("starting download"));
_timer.start(); _timer.start();
CURLcode ret = curl_easy_perform(_c); CURLcode ret = curl_easy_perform(_c);

View file

@ -126,6 +126,7 @@ signals:
void error(QString msg); void error(QString msg);
void cacheFileUpdated(QByteArray sha256); void cacheFileUpdated(QByteArray sha256);
void finalizing(); void finalizing();
void preparationStatusUpdate(QString msg);
protected: protected:
virtual void run(); virtual void run();
@ -140,6 +141,7 @@ protected:
void _writeCache(const char *buf, size_t len); void _writeCache(const char *buf, size_t len);
qint64 _sectorsWritten(); qint64 _sectorsWritten();
void _closeFiles(); void _closeFiles();
QByteArray _fileGetContentsTrimmed(const QString &filename);
/* /*
* libcurl callbacks * libcurl callbacks

View file

@ -201,6 +201,8 @@ void ImageWriter::startWrite()
connect(_thread, SIGNAL(success()), SLOT(onSuccess())); connect(_thread, SIGNAL(success()), SLOT(onSuccess()));
connect(_thread, SIGNAL(error(QString)), SLOT(onError(QString))); connect(_thread, SIGNAL(error(QString)), SLOT(onError(QString)));
connect(_thread, SIGNAL(finalizing()), SLOT(onFinalizing()));
connect(_thread, SIGNAL(preparationStatusUpdate(QString)), SLOT(onPreparationStatusUpdate(QString)));
_thread->setVerifyEnabled(_verifyEnabled); _thread->setVerifyEnabled(_verifyEnabled);
_thread->setUserAgent(QString("Mozilla/5.0 rpi-imager/%1").arg(constantVersion()).toUtf8()); _thread->setUserAgent(QString("Mozilla/5.0 rpi-imager/%1").arg(constantVersion()).toUtf8());
@ -252,6 +254,7 @@ void ImageWriter::startWrite()
_thread->start(); _thread->start();
} }
_dlnow = 0; _verifynow = 0;
_polltimer.start(PROGRESS_UPDATE_INTERVAL); _polltimer.start(PROGRESS_UPDATE_INTERVAL);
} }
@ -403,6 +406,11 @@ void ImageWriter::onFinalizing()
emit finalizing(); emit finalizing();
} }
void ImageWriter::onPreparationStatusUpdate(QString msg)
{
emit preparationStatusUpdate(msg);
}
void ImageWriter::openFileDialog() void ImageWriter::openFileDialog()
{ {
#ifndef QT_NO_WIDGETS #ifndef QT_NO_WIDGETS

View file

@ -99,6 +99,7 @@ signals:
void cancelled(); void cancelled();
void finalizing(); void finalizing();
void networkOnline(); void networkOnline();
void preparationStatusUpdate(QVariant msg);
protected slots: protected slots:
@ -112,6 +113,7 @@ protected slots:
void onCacheFileUpdated(QByteArray sha256); void onCacheFileUpdated(QByteArray sha256);
void onFinalizing(); void onFinalizing();
void onTimeSyncReply(QNetworkReply *reply); void onTimeSyncReply(QNetworkReply *reply);
void onPreparationStatusUpdate(QString msg);
protected: protected:
QUrl _src, _repo; QUrl _src, _repo;

View file

@ -31,6 +31,7 @@ void LocalFileExtractThread::run()
if (isImage() && !_openAndPrepareDevice()) if (isImage() && !_openAndPrepareDevice())
return; return;
emit preparationStatusUpdate(tr("opening image file"));
_timer.start(); _timer.start();
_inputfile.setFileName( QUrl(_url).toLocalFile() ); _inputfile.setFileName( QUrl(_url).toLocalFile() );
if (!_inputfile.open(_inputfile.ReadOnly)) if (!_inputfile.open(_inputfile.ReadOnly))

View file

@ -158,6 +158,7 @@ int main(int argc, char *argv[])
QObject *qmlwindow = engine.rootObjects().value(0); QObject *qmlwindow = engine.rootObjects().value(0);
qmlwindow->connect(&imageWriter, SIGNAL(downloadProgress(QVariant,QVariant)), qmlwindow, SLOT(onDownloadProgress(QVariant,QVariant))); qmlwindow->connect(&imageWriter, SIGNAL(downloadProgress(QVariant,QVariant)), qmlwindow, SLOT(onDownloadProgress(QVariant,QVariant)));
qmlwindow->connect(&imageWriter, SIGNAL(verifyProgress(QVariant,QVariant)), qmlwindow, SLOT(onVerifyProgress(QVariant,QVariant))); qmlwindow->connect(&imageWriter, SIGNAL(verifyProgress(QVariant,QVariant)), qmlwindow, SLOT(onVerifyProgress(QVariant,QVariant)));
qmlwindow->connect(&imageWriter, SIGNAL(preparationStatusUpdate(QVariant)), qmlwindow, SLOT(onPreparationStatusUpdate(QVariant)));
qmlwindow->connect(&imageWriter, SIGNAL(error(QVariant)), qmlwindow, SLOT(onError(QVariant))); qmlwindow->connect(&imageWriter, SIGNAL(error(QVariant)), qmlwindow, SLOT(onError(QVariant)));
qmlwindow->connect(&imageWriter, SIGNAL(success()), qmlwindow, SLOT(onSuccess())); qmlwindow->connect(&imageWriter, SIGNAL(success()), qmlwindow, SLOT(onSuccess()));
qmlwindow->connect(&imageWriter, SIGNAL(fileSelected(QVariant)), qmlwindow, SLOT(onFileSelected(QVariant))); qmlwindow->connect(&imageWriter, SIGNAL(fileSelected(QVariant)), qmlwindow, SLOT(onFileSelected(QVariant)));

View file

@ -749,7 +749,7 @@ ApplicationWindow {
cancelwritebutton.enabled = true cancelwritebutton.enabled = true
cancelwritebutton.visible = true cancelwritebutton.visible = true
cancelverifybutton.enabled = true cancelverifybutton.enabled = true
progressText.text = qsTr("Writing... %1%").arg("0") progressText.text = qsTr("Preparing to write...");
progressText.visible = true progressText.visible = true
progressBar.visible = true progressBar.visible = true
progressBar.indeterminate = true progressBar.indeterminate = true
@ -831,6 +831,10 @@ ApplicationWindow {
} }
} }
function onPreparationStatusUpdate(msg) {
progressText.text = qsTr("Preparing to write... (%1)").arg(msg)
}
function resetWriteButton() { function resetWriteButton() {
progressText.visible = false progressText.visible = false
progressBar.visible = false progressBar.visible = false