fusefs: return ENOTCONN instead of EIO if the daemon dies suddenly

If the daemon dies, return ENOTCONN for all operations that have already
been sent to the daemon, as well as any new ones.

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-05-10 16:41:33 +00:00
parent d5024ba275
commit 7e0aac2408
2 changed files with 62 additions and 1 deletions

View File

@ -1028,7 +1028,15 @@ fdisp_wait_answ(struct fuse_dispatcher *fdip)
}
}
if (fdip->tick->tk_aw_errno) {
if (fdip->tick->tk_aw_errno == ENOTCONN) {
/* The daemon died while we were waiting for a response */
err = ENOTCONN;
goto out;
} else if (fdip->tick->tk_aw_errno) {
/*
* There was some sort of communication error with the daemon
* that the client wouldn't understand.
*/
SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
"IPC: explicit EIO-ing", fdip->tick->tk_aw_errno);
err = EIO;

View File

@ -31,6 +31,7 @@
extern "C" {
#include <sys/param.h>
#include <sys/mount.h>
#include <semaphore.h>
}
#include "mockfs.hh"
@ -76,6 +77,58 @@ TEST_F(Statfs, enotconn)
EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname));
}
static void* statfs_th(void* arg) {
ssize_t r;
struct statfs *sb = (struct statfs*)arg;
r = statfs("mountpoint", sb);
if (r >= 0)
return 0;
else
return (void*)(intptr_t)errno;
}
/*
* Like the enotconn test, but in this case the daemon dies after we send the
* FUSE_STATFS operation but before we get a response.
*/
TEST_F(Statfs, enotconn_while_blocked)
{
struct statfs statbuf;
void *thr0_value;
pthread_t th0;
char mp[PATH_MAX];
sem_t sem;
ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in->header.opcode == FUSE_STATFS);
}, Eq(true)),
_)
).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
sem_post(&sem);
/* Just block until the daemon dies */
}));
ASSERT_NE(NULL, getcwd(mp, PATH_MAX)) << strerror(errno);
strlcat(mp, "/mountpoint", PATH_MAX);
ASSERT_EQ(0, pthread_create(&th0, NULL, statfs_th, (void*)&statbuf))
<< strerror(errno);
ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
m_mock->kill_daemon();
pthread_join(th0, &thr0_value);
ASSERT_EQ(0, (intptr_t)thr0_value);
EXPECT_EQ(getuid(), statbuf.f_owner);
EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename));
EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname));
EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname));
}
TEST_F(Statfs, ok)
{
struct statfs statbuf;