Never deliver signals during stat(2), readlink(2), open(2), and truncate(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2022-04-14 18:48:20 +02:00
parent 4698562f64
commit 5eb34b4a00
1 changed files with 78 additions and 51 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012-2017, 2021 Jonas 'Sortie' Termansen. * Copyright (c) 2012-2017, 2021-2022 Jonas 'Sortie' Termansen.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,6 +22,7 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -802,19 +803,25 @@ int Unode::sync(ioctx_t* ctx)
int Unode::stat(ioctx_t* ctx, struct stat* st) int Unode::stat(ioctx_t* ctx, struct stat* st)
{ {
Channel* channel = server->Connect(ctx); // stat(2) isn't allowed to fail with EINTR.
if ( !channel ) sigset_t set, oldset;
return -1; sigfillset(&set);
Signal::UpdateMask(SIG_SETMASK, &set, &oldset);
int ret = -1; int ret = -1;
struct fsm_req_stat msg; Channel* channel = server->Connect(ctx);
struct fsm_resp_stat resp; if ( channel )
msg.ino = ino; {
if ( SendMessage(channel, FSM_REQ_STAT, &msg, sizeof(msg)) && struct fsm_req_stat msg;
RecvMessage(channel, FSM_RESP_STAT, &resp, sizeof(resp)) && struct fsm_resp_stat resp;
(resp.st.st_dev = (dev_t) server.Get(), true) && msg.ino = ino;
ctx->copy_to_dest(st, &resp.st, sizeof(*st)) ) if ( SendMessage(channel, FSM_REQ_STAT, &msg, sizeof(msg)) &&
ret = 0; RecvMessage(channel, FSM_RESP_STAT, &resp, sizeof(resp)) &&
channel->KernelClose(); (resp.st.st_dev = (dev_t) server.Get(), true) &&
ctx->copy_to_dest(st, &resp.st, sizeof(*st)) )
ret = 0;
channel->KernelClose();
}
Signal::UpdateMask(SIG_SETMASK, &oldset, NULL);
return ret; return ret;
} }
@ -872,17 +879,24 @@ int Unode::chown(ioctx_t* ctx, uid_t owner, gid_t group)
int Unode::truncate(ioctx_t* ctx, off_t length) int Unode::truncate(ioctx_t* ctx, off_t length)
{ {
Channel* channel = server->Connect(ctx); // truncate(2) is allowed to EINTR but may be used by open(2) O_TRUNC which
if ( !channel ) // should not fail with EINTR.
return -1; sigset_t set, oldset;
sigfillset(&set);
Signal::UpdateMask(SIG_SETMASK, &set, &oldset);
int ret = -1; int ret = -1;
struct fsm_req_truncate msg; Channel* channel = server->Connect(ctx);
msg.ino = ino; if ( channel )
msg.size = length; {
if ( SendMessage(channel, FSM_REQ_TRUNCATE, &msg, sizeof(msg)) && struct fsm_req_truncate msg;
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) ) msg.ino = ino;
ret = 0; msg.size = length;
channel->KernelClose(); if ( SendMessage(channel, FSM_REQ_TRUNCATE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
}
Signal::UpdateMask(SIG_SETMASK, &oldset, NULL);
return ret; return ret;
} }
@ -1191,22 +1205,29 @@ ssize_t Unode::readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
Ref<Inode> Unode::open(ioctx_t* ctx, const char* filename, int flags, Ref<Inode> Unode::open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode) mode_t mode)
{ {
Channel* channel = server->Connect(ctx); // open(2) may EINTR on slow devices but is used by stat(2) and readlink(2)
if ( !channel ) // wnich aren't allowed to EINTR.
return Ref<Inode>(NULL); sigset_t set, oldset;
size_t filenamelen = strlen(filename); sigfillset(&set);
Signal::UpdateMask(SIG_SETMASK, &set, &oldset);
Ref<Inode> ret; Ref<Inode> ret;
struct fsm_req_open msg; Channel* channel = server->Connect(ctx);
msg.dirino = ino; if ( channel )
msg.flags = flags; {
msg.mode = mode; size_t filenamelen = strlen(filename);
msg.namelen = filenamelen; struct fsm_req_open msg;
struct fsm_resp_open resp; msg.dirino = ino;
if ( SendMessage(channel, FSM_REQ_OPEN, &msg, sizeof(msg), filenamelen) && msg.flags = flags;
channel->KernelSend(&kctx, filename, filenamelen) && msg.mode = mode;
RecvMessage(channel, FSM_RESP_OPEN, &resp, sizeof(resp)) ) msg.namelen = filenamelen;
ret = server->OpenNode(resp.ino, resp.type); struct fsm_resp_open resp;
channel->KernelClose(); if ( SendMessage(channel, FSM_REQ_OPEN, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_OPEN, &resp, sizeof(resp)) )
ret = server->OpenNode(resp.ino, resp.type);
channel->KernelClose();
}
Signal::UpdateMask(SIG_SETMASK, &oldset, NULL);
return ret; return ret;
} }
@ -1334,22 +1355,28 @@ int Unode::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
ssize_t Unode::readlink(ioctx_t* ctx, char* buf, size_t bufsiz) ssize_t Unode::readlink(ioctx_t* ctx, char* buf, size_t bufsiz)
{ {
Channel* channel = server->Connect(ctx); // readlink(2) isn't allowed to fail with EINTR.
if ( !channel ) sigset_t set, oldset;
return -1; sigfillset(&set);
Signal::UpdateMask(SIG_SETMASK, &set, &oldset);
ssize_t ret = -1; ssize_t ret = -1;
struct fsm_req_readlink msg; Channel* channel = server->Connect(ctx);
struct fsm_resp_readlink resp; if ( channel )
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_READLINK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READLINK, &resp, sizeof(resp)) )
{ {
if ( resp.targetlen < bufsiz ) struct fsm_req_readlink msg;
bufsiz = resp.targetlen; struct fsm_resp_readlink resp;
if ( channel->KernelRecv(ctx, buf, bufsiz) ) msg.ino = ino;
ret = (ssize_t) bufsiz; if ( SendMessage(channel, FSM_REQ_READLINK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READLINK, &resp, sizeof(resp)) )
{
if ( resp.targetlen < bufsiz )
bufsiz = resp.targetlen;
if ( channel->KernelRecv(ctx, buf, bufsiz) )
ret = (ssize_t) bufsiz;
}
channel->KernelClose();
} }
channel->KernelClose(); Signal::UpdateMask(SIG_SETMASK, &oldset, NULL);
return ret; return ret;
} }