Plasmashell freezes when trying to get free space info from mounted remote filesystem after losing connection to it

Summary:
BUG: 397537

Earlier plasmashell assumed that you'll get free space info immediately (which is not true in case of losing connection to server containing a mounted filesystem - statfs will wait for response forever and freeze everything since it's happening in main thread)

I moved obtaining that info into different thread so that case won't freeze anything anymore.
It creates exactly one thread per one path. If a path is already being processed, new thread won't be created.
Also I implemented a timer used to notify about broken connection after 15 seconds.

Reviewers: broulik, ngraham, davidedmundson

Reviewed By: broulik

Subscribers: ngraham, anthonyfieroni, davidedmundson, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D14895
wilder-5.14
Oleg Solovyov 8 years ago committed by Nathaniel Graham
parent 2949e7c432
commit e1c19ce4da
  1. 1
      dataengines/soliddevice/CMakeLists.txt
  2. 43
      dataengines/soliddevice/soliddeviceengine.cpp
  3. 3
      dataengines/soliddevice/soliddeviceengine.h

@ -18,6 +18,7 @@ target_link_libraries(plasma_engine_soliddevice
KF5::Plasma
KF5::Solid
KF5::CoreAddons
KF5::Notifications
)
kcoreaddons_desktop_to_json(plasma_engine_soliddevice plasma-dataengine-soliddevice.desktop)

@ -24,9 +24,11 @@
#include <Solid/GenericInterface>
#include <klocalizedstring.h>
#include <QApplication>
#include <QDebug>
#include <KDiskFreeSpaceInfo>
#include <KFormat>
#include <KIO/FileSystemFreeSpaceJob>
#include <KNotification>
#include <Plasma/DataContainer>
@ -547,12 +549,39 @@ bool SolidDeviceEngine::updateStorageSpace(const QString &udi)
return false;
}
KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(storageaccess->filePath());
if (info.isValid()) {
setData(udi, I18N_NOOP("Free Space"), QVariant(info.available()));
setData(udi, I18N_NOOP("Free Space Text"), KFormat().formatByteSize(info.available()));
setData(udi, I18N_NOOP("Size"), QVariant(info.size()));
return true;
QString path = storageaccess->filePath();
if (!m_paths.contains(path)) {
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [path]() {
KNotification::event(KNotification::Error, i18n("Filesystem is not responding", path),
i18n("Filesystem mounted at '%1' is not responding", path));
});
m_paths.insert(path);
// create job
KIO::FileSystemFreeSpaceJob *job = KIO::fileSystemFreeSpace(QUrl::fromLocalFile(path));
// delete later timer
connect(job, &KIO::FileSystemFreeSpaceJob::result, timer, &QTimer::deleteLater);
// collect and process info
connect(job, &KIO::FileSystemFreeSpaceJob::result, this,
[this, timer, path, udi](KIO::Job *job, KIO::filesize_t size, KIO::filesize_t available) {
timer->stop();
if (!job->error()) {
setData(udi, I18N_NOOP("Free Space"), QVariant(available));
setData(udi, I18N_NOOP("Free Space Text"), KFormat().formatByteSize(available));
setData(udi, I18N_NOOP("Size"), QVariant(size));
}
m_paths.remove(path);
});
// start timer: after 15 seconds we will get an error
timer->start(15000);
}
return false;

@ -35,6 +35,7 @@
#include "devicesignalmapmanager.h"
#include "devicesignalmapper.h"
#include "hddtemp.h"
#include <KIO/FileSystemFreeSpaceJob>
enum State {
Idle = 0,
@ -80,6 +81,8 @@ private:
QMap<QString, Solid::Device> m_devicemap;
//udi, corresponding encrypted container udi;
QMap<QString, QString> m_encryptedContainerMap;
//path, corresponding timer
QSet<QString> m_paths;
DeviceSignalMapManager *m_signalmanager;
HddTemp *m_temperature;

Loading…
Cancel
Save