Skip to content

Commit

Permalink
Merge pull request #594 from mihalicyn/fuse_interrupt
Browse files Browse the repository at this point in the history
Partial support for FUSE_INTERRUPT
  • Loading branch information
stgraber authored Aug 1, 2023
2 parents b56e0ae + ecb1040 commit b41a414
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 3 deletions.
19 changes: 19 additions & 0 deletions src/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,25 @@ static inline void store_unlock(void)
mutex_unlock(&pidns_store_mutex);
}

#define define_interruptible_lock(type, lockname, lockfn) \
int lockname##_interruptible(type *l) \
{ \
int ret = ETIMEDOUT; \
while (!fuse_interrupted() && (ret == ETIMEDOUT)) { \
struct timespec deadline; \
clock_gettime(CLOCK_REALTIME, &deadline); \
deadline.tv_sec += 1; \
ret = lockfn(l, &deadline); \
} \
return -ret; \
}

define_interruptible_lock(pthread_mutex_t, mutex_lock, pthread_mutex_timedlock)
define_interruptible_lock(pthread_rwlock_t, rwlock_rdlock, pthread_rwlock_timedrdlock)
define_interruptible_lock(pthread_rwlock_t, rwlock_wrlock, pthread_rwlock_timedwrlock)

#undef define_interruptible_lock

/* /proc/ = 6
* +
* <pid-as-str> = INTTYPE_TO_STRLEN(pid_t)
Expand Down
18 changes: 18 additions & 0 deletions src/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ enum lxcfs_virt_t {
#define LXCFS_TYPE_SYS(type) (type >= LXC_TYPE_SYS && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE)
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_CGDIR && type < LXC_TYPE_MAX)

/*
* This signal will be used to signal fuse request processing thread that
* request was interrupted (FUSE_INTERRUPT came from the kernel).
*
* It's not imporant which signal num is used, but it should not intersect with
* any signals those are already handled and used somewhere.
* Since, SIGUSR1 and SIGUSR2 are already utilized by lxcfs, let it be SIGTTOU.
*
* See also:
* ("interrupt support")
* https://github.com/libfuse/libfuse/commit/288ed4ebcea335c77793ee3d207c7466d55c4f71
*/
#define LXCFS_INTR_SIGNAL SIGTTOU

extern int mutex_lock_interruptible(pthread_mutex_t *l);
extern int rwlock_rdlock_interruptible(pthread_rwlock_t *l);
extern int rwlock_wrlock_interruptible(pthread_rwlock_t *l);

struct file_info {
char *controller;
char *cgroup;
Expand Down
45 changes: 45 additions & 0 deletions src/lxcfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,42 @@ int lxcfs_chmod(const char *path, mode_t mode)
return -ENOENT;
}

#if HAVE_FUSE3
static void fuse_intr_sighandler(int sig)
{
(void) sig;
/* Nothing to do */
}

static int fuse_init_intr_signal(int signum)
{
struct sigaction old_sa;
struct sigaction sa;

if (sigaction(signum, NULL, &old_sa) == -1)
return log_error(-1, "cannot get old signal handler\n");

if (old_sa.sa_handler != SIG_DFL)
return log_error(-1, "%d has non-default handler\n", signum);

memset(&sa, 0, sizeof(struct sigaction));

/*
* We *must* enable SA_RESTART, otherwise we may accidentally
* break some code which is not ready to signals/fuse interrupt.
*/
sa.sa_flags = SA_RESTART;

sa.sa_handler = fuse_intr_sighandler;
sigemptyset(&sa.sa_mask);

if (sigaction(signum, &sa, NULL) == -1)
return log_error(-1, "cannot set interrupt signal handler\n");

return 0;
}
#endif

#if HAVE_FUSE3
static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
#else
Expand All @@ -1062,6 +1098,8 @@ static void *lxcfs_init(struct fuse_conn_info *conn)

#if HAVE_FUSE3
cfg->direct_io = 1;
cfg->intr = 1;
cfg->intr_signal = LXCFS_INTR_SIGNAL;
#endif

return fuse_get_context()->private_data;
Expand Down Expand Up @@ -1402,6 +1440,13 @@ int main(int argc, char *argv[])
goto out;
}

#if HAVE_FUSE3
if (fuse_init_intr_signal(LXCFS_INTR_SIGNAL)) {
lxcfs_error("Failed to install fuse interrupt signal handler");
goto out;
}
#endif

if (!pidfile) {
snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
pidfile = pidfile_buf;
Expand Down
18 changes: 15 additions & 3 deletions src/proc_cpuview.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ static void prune_proc_stat_history(void)
time_t now = time(NULL);

for (int i = 0; i < CPUVIEW_HASH_SIZE; i++) {
pthread_rwlock_wrlock(&proc_stat_history[i]->lock);
if (rwlock_wrlock_interruptible(&proc_stat_history[i]->lock))
continue;

if ((proc_stat_history[i]->lastcheck + PROC_STAT_PRUNE_INTERVAL) > now) {
pthread_rwlock_unlock(&proc_stat_history[i]->lock);
Expand All @@ -308,7 +309,8 @@ static struct cg_proc_stat *find_proc_stat_node(struct cg_proc_stat_head *head,
struct cg_proc_stat *node;

prune_proc_stat_history();
pthread_rwlock_rdlock(&head->lock);
if (rwlock_rdlock_interruptible(&head->lock))
return NULL;

if (!head->next) {
pthread_rwlock_unlock(&head->lock);
Expand All @@ -319,7 +321,13 @@ static struct cg_proc_stat *find_proc_stat_node(struct cg_proc_stat_head *head,

do {
if (strcmp(cg, node->cg) == 0) {
pthread_mutex_lock(&node->lock);
/*
* If we are failed to take a lock OR
* fuse request was interrupted then
* just return NULL and exit gracefully.
*/
if (mutex_lock_interruptible(&node->lock))
node = NULL;
goto out;
}
} while ((node = node->next));
Expand All @@ -340,6 +348,10 @@ static struct cg_proc_stat *find_or_create_proc_stat_node(struct cpuacct_usage *

node = find_proc_stat_node(head, cg);
if (!node) {
/* safe place to exit */
if (fuse_interrupted())
return NULL;

node = new_proc_stat_node(usage, cpu_count, cg);
if (!node)
return NULL;
Expand Down

0 comments on commit b41a414

Please sign in to comment.