13#include "fuse_config.h" 
   14#include "fuse_lowlevel.h" 
   16#include "fuse_kernel.h" 
   33#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" 
   35#define FUSE_LOOP_MT_V2_IDENTIFIER       INT_MAX - 2 
   36#define FUSE_LOOP_MT_DEF_CLONE_FD        0 
   37#define FUSE_LOOP_MT_DEF_MAX_THREADS 10 
   38#define FUSE_LOOP_MT_DEF_IDLE_THREADS -1  
   42#define FUSE_LOOP_MT_MAX_THREADS      (100U * 1000) 
   45        struct fuse_worker *prev;
 
   46        struct fuse_worker *next;
 
   60        struct fuse_session *se;
 
   61        struct fuse_worker main;
 
   70static struct fuse_chan *fuse_chan_new(
int fd)
 
   72        struct fuse_chan *ch = (
struct fuse_chan *) malloc(
sizeof(*ch));
 
   74                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate channel\n");
 
   78        memset(ch, 0, 
sizeof(*ch));
 
   81        pthread_mutex_init(&ch->lock, NULL);
 
   86struct fuse_chan *fuse_chan_get(
struct fuse_chan *ch)
 
   89        pthread_mutex_lock(&ch->lock);
 
   91        pthread_mutex_unlock(&ch->lock);
 
   96void fuse_chan_put(
struct fuse_chan *ch)
 
  100        pthread_mutex_lock(&ch->lock);
 
  103                pthread_mutex_unlock(&ch->lock);
 
  105                pthread_mutex_destroy(&ch->lock);
 
  108                pthread_mutex_unlock(&ch->lock);
 
  111static void list_add_worker(
struct fuse_worker *w, 
struct fuse_worker *next)
 
  113        struct fuse_worker *prev = next->prev;
 
  120static void list_del_worker(
struct fuse_worker *w)
 
  122        struct fuse_worker *prev = w->prev;
 
  123        struct fuse_worker *next = w->next;
 
  128static int fuse_loop_start_thread(
struct fuse_mt *mt);
 
  130static void *fuse_do_work(
void *data)
 
  132        struct fuse_worker *w = (
struct fuse_worker *) data;
 
  133        struct fuse_mt *mt = w->mt;
 
  135#ifdef HAVE_PTHREAD_SETNAME_NP 
  136        pthread_setname_np(pthread_self(), 
"fuse_worker");
 
  143                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 
  144                res = fuse_session_receive_buf_internal(mt->se, &w->fbuf,
 
  146                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
  157                pthread_mutex_lock(&mt->lock);
 
  159                        pthread_mutex_unlock(&mt->lock);
 
  168                        struct fuse_in_header *in = w->fbuf.mem;
 
  170                        if (in->opcode == FUSE_FORGET ||
 
  171                            in->opcode == FUSE_BATCH_FORGET)
 
  177                if (mt->numavail == 0 && mt->numworker < mt->max_threads)
 
  178                        fuse_loop_start_thread(mt);
 
  179                pthread_mutex_unlock(&mt->lock);
 
  181                fuse_session_process_buf_internal(mt->se, &w->fbuf, w->ch);
 
  183                pthread_mutex_lock(&mt->lock);
 
  193                if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) {
 
  195                                pthread_mutex_unlock(&mt->lock);
 
  201                        pthread_mutex_unlock(&mt->lock);
 
  203                        pthread_detach(w->thread_id);
 
  204                        fuse_buf_free(&w->fbuf);
 
  205                        fuse_chan_put(w->ch);
 
  209                pthread_mutex_unlock(&mt->lock);
 
  212        sem_post(&mt->finish);
 
  217int fuse_start_thread(pthread_t *thread_id, 
void *(*func)(
void *), 
void *arg)
 
  229        pthread_attr_init(&attr);
 
  230        stack_size = getenv(ENVNAME_THREAD_STACK);
 
  234                res = libfuse_strtol(stack_size, &size);
 
  236                        fuse_log(FUSE_LOG_ERR, 
"fuse: invalid stack size: %s\n",
 
  238                else if (pthread_attr_setstacksize(&attr, size))
 
  239                        fuse_log(FUSE_LOG_ERR, 
"fuse: could not set stack size: %ld\n",
 
  244        sigemptyset(&newset);
 
  245        sigaddset(&newset, SIGTERM);
 
  246        sigaddset(&newset, SIGINT);
 
  247        sigaddset(&newset, SIGHUP);
 
  248        sigaddset(&newset, SIGQUIT);
 
  249        pthread_sigmask(SIG_BLOCK, &newset, &oldset);
 
  250        res = pthread_create(thread_id, &attr, func, arg);
 
  251        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
 
  252        pthread_attr_destroy(&attr);
 
  254                fuse_log(FUSE_LOG_ERR, 
"fuse: error creating thread: %s\n",
 
  262static int fuse_clone_chan_fd_default(
struct fuse_session *se)
 
  267        const char *devname = 
"/dev/fuse";
 
  272        clonefd = open(devname, O_RDWR | O_CLOEXEC);
 
  274                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n", devname,
 
  279        fcntl(clonefd, F_SETFD, FD_CLOEXEC);
 
  283        res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
 
  285                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to clone device fd: %s\n",
 
  293static struct fuse_chan *fuse_clone_chan(
struct fuse_mt *mt)
 
  296        struct fuse_session *se = mt->se;
 
  297        struct fuse_chan *newch;
 
  299        if (se->io != NULL) {
 
  300                if (se->io->clone_fd != NULL)
 
  301                        clonefd = se->io->clone_fd(se->fd);
 
  305                clonefd = fuse_clone_chan_fd_default(se);
 
  310        newch = fuse_chan_new(clonefd);
 
  317static int fuse_loop_start_thread(
struct fuse_mt *mt)
 
  321        struct fuse_worker *w = malloc(
sizeof(
struct fuse_worker));
 
  323                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate worker structure\n");
 
  326        memset(w, 0, 
sizeof(
struct fuse_worker));
 
  332                w->ch = fuse_clone_chan(mt);
 
  335                        fuse_log(FUSE_LOG_ERR, 
"fuse: trying to continue " 
  336                                "without -o clone_fd.\n");
 
  341        res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
 
  343                fuse_chan_put(w->ch);
 
  347        list_add_worker(w, &mt->main);
 
  354static void fuse_join_worker(
struct fuse_mt *mt, 
struct fuse_worker *w)
 
  356        pthread_join(w->thread_id, NULL);
 
  357        pthread_mutex_lock(&mt->lock);
 
  359        pthread_mutex_unlock(&mt->lock);
 
  360        fuse_buf_free(&w->fbuf);
 
  361        fuse_chan_put(w->ch);
 
  365int fuse_session_loop_mt_312(
struct fuse_session *se, 
struct fuse_loop_config *config);
 
  366FUSE_SYMVER(
"fuse_session_loop_mt_312", 
"fuse_session_loop_mt@@FUSE_3.12")
 
  367int fuse_session_loop_mt_312(struct fuse_session *se, struct 
fuse_loop_config *config)
 
  371        struct fuse_worker *w;
 
  372        int created_config = 0;
 
  375                err = fuse_loop_cfg_verify(config);
 
  380                config = fuse_loop_cfg_create();
 
  385        memset(&mt, 0, 
sizeof(
struct fuse_mt));
 
  387        mt.clone_fd = config->clone_fd;
 
  391        mt.max_idle = config->max_idle_threads;
 
  392        mt.max_threads = config->max_threads;
 
  393        mt.main.thread_id = pthread_self();
 
  394        mt.main.prev = mt.main.next = &mt.main;
 
  395        sem_init(&mt.finish, 0, 0);
 
  396        pthread_mutex_init(&mt.lock, NULL);
 
  398        pthread_mutex_lock(&mt.lock);
 
  399        err = fuse_loop_start_thread(&mt);
 
  400        pthread_mutex_unlock(&mt.lock);
 
  404                        sem_wait(&mt.finish);
 
  406                pthread_mutex_lock(&mt.lock);
 
  407                for (w = mt.main.next; w != &mt.main; w = w->next)
 
  408                        pthread_cancel(w->thread_id);
 
  410                pthread_mutex_unlock(&mt.lock);
 
  412                while (mt.main.next != &mt.main)
 
  413                        fuse_join_worker(&mt, mt.main.next);
 
  418        pthread_mutex_destroy(&mt.lock);
 
  419        sem_destroy(&mt.finish);
 
  424        if (created_config) {
 
  425                fuse_loop_cfg_destroy(config);
 
  432int fuse_session_loop_mt_32(
struct fuse_session *se, 
struct fuse_loop_config_v1 *config_v1);
 
  433FUSE_SYMVER(
"fuse_session_loop_mt_32", 
"fuse_session_loop_mt@FUSE_3.2")
 
  434int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1)
 
  439        if (config_v1 != NULL) {
 
  441                config = fuse_loop_cfg_create();
 
  445                fuse_loop_cfg_convert(config, config_v1);
 
  448        err = fuse_session_loop_mt_312(se, config);
 
  450        fuse_loop_cfg_destroy(config);
 
  456int fuse_session_loop_mt_31(
struct fuse_session *se, 
int clone_fd);
 
  457FUSE_SYMVER(
"fuse_session_loop_mt_31", 
"fuse_session_loop_mt@FUSE_3.0")
 
  458int fuse_session_loop_mt_31(struct fuse_session *se, 
int clone_fd)
 
  463                 fuse_loop_cfg_set_clone_fd(config, 
clone_fd);
 
  464        err = fuse_session_loop_mt_312(se, config);
 
  466        fuse_loop_cfg_destroy(config);
 
  477        config->version_id       = FUSE_LOOP_MT_V2_IDENTIFIER;
 
  479        config->
max_threads      = FUSE_LOOP_MT_DEF_MAX_THREADS;
 
  480        config->
clone_fd         = FUSE_LOOP_MT_DEF_CLONE_FD;
 
  492        if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER)
 
  499                           struct fuse_loop_config_v1 *v1_conf)
 
  501        fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads);
 
  503        fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd);
 
  509        if (value > FUSE_LOOP_MT_MAX_THREADS) {
 
  510                if (value != UINT_MAX)
 
  512                                 "Ignoring invalid max threads value " 
  513                                 "%u > max (%u).\n", value,
 
  514                                 FUSE_LOOP_MT_MAX_THREADS);
 
void fuse_log(enum fuse_log_level level, const char *fmt,...)
void fuse_session_exit(struct fuse_session *se)
int fuse_session_exited(struct fuse_session *se)
void fuse_session_reset(struct fuse_session *se)
unsigned int max_idle_threads