16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci Implementation of the multi-threaded FUSE session loop. 66881f68fSopenharmony_ci 76881f68fSopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 86881f68fSopenharmony_ci See the file COPYING.LIB. 96881f68fSopenharmony_ci*/ 106881f68fSopenharmony_ci 116881f68fSopenharmony_ci#include "fuse_config.h" 126881f68fSopenharmony_ci#include "fuse_lowlevel.h" 136881f68fSopenharmony_ci#include "fuse_misc.h" 146881f68fSopenharmony_ci#include "fuse_kernel.h" 156881f68fSopenharmony_ci#include "fuse_i.h" 166881f68fSopenharmony_ci 176881f68fSopenharmony_ci#include <stdio.h> 186881f68fSopenharmony_ci#include <stdlib.h> 196881f68fSopenharmony_ci#include <string.h> 206881f68fSopenharmony_ci#include <unistd.h> 216881f68fSopenharmony_ci#include <signal.h> 226881f68fSopenharmony_ci#include <semaphore.h> 236881f68fSopenharmony_ci#include <errno.h> 246881f68fSopenharmony_ci#include <sys/time.h> 256881f68fSopenharmony_ci#include <sys/ioctl.h> 266881f68fSopenharmony_ci#include <assert.h> 276881f68fSopenharmony_ci#include <limits.h> 286881f68fSopenharmony_ci 296881f68fSopenharmony_ci/* Environment var controlling the thread stack size */ 306881f68fSopenharmony_ci#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" 316881f68fSopenharmony_ci 326881f68fSopenharmony_ci#define FUSE_LOOP_MT_V2_IDENTIFIER INT_MAX - 2 336881f68fSopenharmony_ci#define FUSE_LOOP_MT_DEF_CLONE_FD 0 346881f68fSopenharmony_ci#define FUSE_LOOP_MT_DEF_MAX_THREADS 10 356881f68fSopenharmony_ci#define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled 366881f68fSopenharmony_ci * by default */ 376881f68fSopenharmony_ci 386881f68fSopenharmony_ci/* an arbitrary large value that cannot be valid */ 396881f68fSopenharmony_ci#define FUSE_LOOP_MT_MAX_THREADS (100U * 1000) 406881f68fSopenharmony_ci 416881f68fSopenharmony_cistruct fuse_worker { 426881f68fSopenharmony_ci struct fuse_worker *prev; 436881f68fSopenharmony_ci struct fuse_worker *next; 446881f68fSopenharmony_ci pthread_t thread_id; 456881f68fSopenharmony_ci 466881f68fSopenharmony_ci // We need to include fuse_buf so that we can properly free 476881f68fSopenharmony_ci // it when a thread is terminated by pthread_cancel(). 486881f68fSopenharmony_ci struct fuse_buf fbuf; 496881f68fSopenharmony_ci struct fuse_chan *ch; 506881f68fSopenharmony_ci struct fuse_mt *mt; 516881f68fSopenharmony_ci}; 526881f68fSopenharmony_ci 536881f68fSopenharmony_cistruct fuse_mt { 546881f68fSopenharmony_ci pthread_mutex_t lock; 556881f68fSopenharmony_ci int numworker; 566881f68fSopenharmony_ci int numavail; 576881f68fSopenharmony_ci struct fuse_session *se; 586881f68fSopenharmony_ci struct fuse_worker main; 596881f68fSopenharmony_ci sem_t finish; 606881f68fSopenharmony_ci int exit; 616881f68fSopenharmony_ci int error; 626881f68fSopenharmony_ci int clone_fd; 636881f68fSopenharmony_ci int max_idle; 646881f68fSopenharmony_ci int max_threads; 656881f68fSopenharmony_ci}; 666881f68fSopenharmony_ci 676881f68fSopenharmony_cistatic struct fuse_chan *fuse_chan_new(int fd) 686881f68fSopenharmony_ci{ 696881f68fSopenharmony_ci struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); 706881f68fSopenharmony_ci if (ch == NULL) { 716881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n"); 726881f68fSopenharmony_ci return NULL; 736881f68fSopenharmony_ci } 746881f68fSopenharmony_ci 756881f68fSopenharmony_ci memset(ch, 0, sizeof(*ch)); 766881f68fSopenharmony_ci ch->fd = fd; 776881f68fSopenharmony_ci ch->ctr = 1; 786881f68fSopenharmony_ci pthread_mutex_init(&ch->lock, NULL); 796881f68fSopenharmony_ci 806881f68fSopenharmony_ci return ch; 816881f68fSopenharmony_ci} 826881f68fSopenharmony_ci 836881f68fSopenharmony_cistruct fuse_chan *fuse_chan_get(struct fuse_chan *ch) 846881f68fSopenharmony_ci{ 856881f68fSopenharmony_ci assert(ch->ctr > 0); 866881f68fSopenharmony_ci pthread_mutex_lock(&ch->lock); 876881f68fSopenharmony_ci ch->ctr++; 886881f68fSopenharmony_ci pthread_mutex_unlock(&ch->lock); 896881f68fSopenharmony_ci 906881f68fSopenharmony_ci return ch; 916881f68fSopenharmony_ci} 926881f68fSopenharmony_ci 936881f68fSopenharmony_civoid fuse_chan_put(struct fuse_chan *ch) 946881f68fSopenharmony_ci{ 956881f68fSopenharmony_ci if (ch == NULL) 966881f68fSopenharmony_ci return; 976881f68fSopenharmony_ci pthread_mutex_lock(&ch->lock); 986881f68fSopenharmony_ci ch->ctr--; 996881f68fSopenharmony_ci if (!ch->ctr) { 1006881f68fSopenharmony_ci pthread_mutex_unlock(&ch->lock); 1016881f68fSopenharmony_ci close(ch->fd); 1026881f68fSopenharmony_ci pthread_mutex_destroy(&ch->lock); 1036881f68fSopenharmony_ci free(ch); 1046881f68fSopenharmony_ci } else 1056881f68fSopenharmony_ci pthread_mutex_unlock(&ch->lock); 1066881f68fSopenharmony_ci} 1076881f68fSopenharmony_ci 1086881f68fSopenharmony_cistatic void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) 1096881f68fSopenharmony_ci{ 1106881f68fSopenharmony_ci struct fuse_worker *prev = next->prev; 1116881f68fSopenharmony_ci w->next = next; 1126881f68fSopenharmony_ci w->prev = prev; 1136881f68fSopenharmony_ci prev->next = w; 1146881f68fSopenharmony_ci next->prev = w; 1156881f68fSopenharmony_ci} 1166881f68fSopenharmony_ci 1176881f68fSopenharmony_cistatic void list_del_worker(struct fuse_worker *w) 1186881f68fSopenharmony_ci{ 1196881f68fSopenharmony_ci struct fuse_worker *prev = w->prev; 1206881f68fSopenharmony_ci struct fuse_worker *next = w->next; 1216881f68fSopenharmony_ci prev->next = next; 1226881f68fSopenharmony_ci next->prev = prev; 1236881f68fSopenharmony_ci} 1246881f68fSopenharmony_ci 1256881f68fSopenharmony_cistatic int fuse_loop_start_thread(struct fuse_mt *mt); 1266881f68fSopenharmony_ci 1276881f68fSopenharmony_cistatic void *fuse_do_work(void *data) 1286881f68fSopenharmony_ci{ 1296881f68fSopenharmony_ci struct fuse_worker *w = (struct fuse_worker *) data; 1306881f68fSopenharmony_ci struct fuse_mt *mt = w->mt; 1316881f68fSopenharmony_ci 1326881f68fSopenharmony_ci while (!fuse_session_exited(mt->se)) { 1336881f68fSopenharmony_ci int isforget = 0; 1346881f68fSopenharmony_ci int res; 1356881f68fSopenharmony_ci 1366881f68fSopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 1376881f68fSopenharmony_ci res = fuse_session_receive_buf_int(mt->se, &w->fbuf, w->ch); 1386881f68fSopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 1396881f68fSopenharmony_ci if (res == -EINTR) 1406881f68fSopenharmony_ci continue; 1416881f68fSopenharmony_ci if (res <= 0) { 1426881f68fSopenharmony_ci if (res < 0) { 1436881f68fSopenharmony_ci fuse_session_exit(mt->se); 1446881f68fSopenharmony_ci mt->error = res; 1456881f68fSopenharmony_ci } 1466881f68fSopenharmony_ci break; 1476881f68fSopenharmony_ci } 1486881f68fSopenharmony_ci 1496881f68fSopenharmony_ci pthread_mutex_lock(&mt->lock); 1506881f68fSopenharmony_ci if (mt->exit) { 1516881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 1526881f68fSopenharmony_ci return NULL; 1536881f68fSopenharmony_ci } 1546881f68fSopenharmony_ci 1556881f68fSopenharmony_ci /* 1566881f68fSopenharmony_ci * This disgusting hack is needed so that zillions of threads 1576881f68fSopenharmony_ci * are not created on a burst of FORGET messages 1586881f68fSopenharmony_ci */ 1596881f68fSopenharmony_ci if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) { 1606881f68fSopenharmony_ci struct fuse_in_header *in = w->fbuf.mem; 1616881f68fSopenharmony_ci 1626881f68fSopenharmony_ci if (in->opcode == FUSE_FORGET || 1636881f68fSopenharmony_ci in->opcode == FUSE_BATCH_FORGET) 1646881f68fSopenharmony_ci isforget = 1; 1656881f68fSopenharmony_ci } 1666881f68fSopenharmony_ci 1676881f68fSopenharmony_ci if (!isforget) 1686881f68fSopenharmony_ci mt->numavail--; 1696881f68fSopenharmony_ci if (mt->numavail == 0 && mt->numworker < mt->max_threads) 1706881f68fSopenharmony_ci fuse_loop_start_thread(mt); 1716881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 1726881f68fSopenharmony_ci 1736881f68fSopenharmony_ci fuse_session_process_buf_int(mt->se, &w->fbuf, w->ch); 1746881f68fSopenharmony_ci 1756881f68fSopenharmony_ci pthread_mutex_lock(&mt->lock); 1766881f68fSopenharmony_ci if (!isforget) 1776881f68fSopenharmony_ci mt->numavail++; 1786881f68fSopenharmony_ci 1796881f68fSopenharmony_ci /* creating and destroying threads is rather expensive - and there is 1806881f68fSopenharmony_ci * not much gain from destroying existing threads. It is therefore 1816881f68fSopenharmony_ci * discouraged to set max_idle to anything else than -1. If there 1826881f68fSopenharmony_ci * is indeed a good reason to destruct threads it should be done 1836881f68fSopenharmony_ci * delayed, a moving average might be useful for that. 1846881f68fSopenharmony_ci */ 1856881f68fSopenharmony_ci if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) { 1866881f68fSopenharmony_ci if (mt->exit) { 1876881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 1886881f68fSopenharmony_ci return NULL; 1896881f68fSopenharmony_ci } 1906881f68fSopenharmony_ci list_del_worker(w); 1916881f68fSopenharmony_ci mt->numavail--; 1926881f68fSopenharmony_ci mt->numworker--; 1936881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 1946881f68fSopenharmony_ci 1956881f68fSopenharmony_ci pthread_detach(w->thread_id); 1966881f68fSopenharmony_ci free(w->fbuf.mem); 1976881f68fSopenharmony_ci fuse_chan_put(w->ch); 1986881f68fSopenharmony_ci free(w); 1996881f68fSopenharmony_ci return NULL; 2006881f68fSopenharmony_ci } 2016881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 2026881f68fSopenharmony_ci } 2036881f68fSopenharmony_ci 2046881f68fSopenharmony_ci sem_post(&mt->finish); 2056881f68fSopenharmony_ci 2066881f68fSopenharmony_ci return NULL; 2076881f68fSopenharmony_ci} 2086881f68fSopenharmony_ci 2096881f68fSopenharmony_ciint fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) 2106881f68fSopenharmony_ci{ 2116881f68fSopenharmony_ci sigset_t oldset; 2126881f68fSopenharmony_ci sigset_t newset; 2136881f68fSopenharmony_ci int res; 2146881f68fSopenharmony_ci pthread_attr_t attr; 2156881f68fSopenharmony_ci char *stack_size; 2166881f68fSopenharmony_ci 2176881f68fSopenharmony_ci /* Override default stack size 2186881f68fSopenharmony_ci * XXX: This should ideally be a parameter option. It is rather 2196881f68fSopenharmony_ci * well hidden here. 2206881f68fSopenharmony_ci */ 2216881f68fSopenharmony_ci pthread_attr_init(&attr); 2226881f68fSopenharmony_ci stack_size = getenv(ENVNAME_THREAD_STACK); 2236881f68fSopenharmony_ci if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) 2246881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n", stack_size); 2256881f68fSopenharmony_ci 2266881f68fSopenharmony_ci /* Disallow signal reception in worker threads */ 2276881f68fSopenharmony_ci sigemptyset(&newset); 2286881f68fSopenharmony_ci sigaddset(&newset, SIGTERM); 2296881f68fSopenharmony_ci sigaddset(&newset, SIGINT); 2306881f68fSopenharmony_ci sigaddset(&newset, SIGHUP); 2316881f68fSopenharmony_ci sigaddset(&newset, SIGQUIT); 2326881f68fSopenharmony_ci pthread_sigmask(SIG_BLOCK, &newset, &oldset); 2336881f68fSopenharmony_ci res = pthread_create(thread_id, &attr, func, arg); 2346881f68fSopenharmony_ci pthread_sigmask(SIG_SETMASK, &oldset, NULL); 2356881f68fSopenharmony_ci pthread_attr_destroy(&attr); 2366881f68fSopenharmony_ci if (res != 0) { 2376881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n", 2386881f68fSopenharmony_ci strerror(res)); 2396881f68fSopenharmony_ci return -1; 2406881f68fSopenharmony_ci } 2416881f68fSopenharmony_ci 2426881f68fSopenharmony_ci return 0; 2436881f68fSopenharmony_ci} 2446881f68fSopenharmony_ci 2456881f68fSopenharmony_cistatic struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt) 2466881f68fSopenharmony_ci{ 2476881f68fSopenharmony_ci int res; 2486881f68fSopenharmony_ci int clonefd; 2496881f68fSopenharmony_ci uint32_t masterfd; 2506881f68fSopenharmony_ci struct fuse_chan *newch; 2516881f68fSopenharmony_ci const char *devname = "/dev/fuse"; 2526881f68fSopenharmony_ci 2536881f68fSopenharmony_ci#ifndef O_CLOEXEC 2546881f68fSopenharmony_ci#define O_CLOEXEC 0 2556881f68fSopenharmony_ci#endif 2566881f68fSopenharmony_ci clonefd = open(devname, O_RDWR | O_CLOEXEC); 2576881f68fSopenharmony_ci if (clonefd == -1) { 2586881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname, 2596881f68fSopenharmony_ci strerror(errno)); 2606881f68fSopenharmony_ci return NULL; 2616881f68fSopenharmony_ci } 2626881f68fSopenharmony_ci fcntl(clonefd, F_SETFD, FD_CLOEXEC); 2636881f68fSopenharmony_ci 2646881f68fSopenharmony_ci masterfd = mt->se->fd; 2656881f68fSopenharmony_ci res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd); 2666881f68fSopenharmony_ci if (res == -1) { 2676881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n", 2686881f68fSopenharmony_ci strerror(errno)); 2696881f68fSopenharmony_ci close(clonefd); 2706881f68fSopenharmony_ci return NULL; 2716881f68fSopenharmony_ci } 2726881f68fSopenharmony_ci newch = fuse_chan_new(clonefd); 2736881f68fSopenharmony_ci if (newch == NULL) 2746881f68fSopenharmony_ci close(clonefd); 2756881f68fSopenharmony_ci 2766881f68fSopenharmony_ci return newch; 2776881f68fSopenharmony_ci} 2786881f68fSopenharmony_ci 2796881f68fSopenharmony_cistatic int fuse_loop_start_thread(struct fuse_mt *mt) 2806881f68fSopenharmony_ci{ 2816881f68fSopenharmony_ci int res; 2826881f68fSopenharmony_ci 2836881f68fSopenharmony_ci struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); 2846881f68fSopenharmony_ci if (!w) { 2856881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n"); 2866881f68fSopenharmony_ci return -1; 2876881f68fSopenharmony_ci } 2886881f68fSopenharmony_ci memset(w, 0, sizeof(struct fuse_worker)); 2896881f68fSopenharmony_ci w->fbuf.mem = NULL; 2906881f68fSopenharmony_ci w->mt = mt; 2916881f68fSopenharmony_ci 2926881f68fSopenharmony_ci w->ch = NULL; 2936881f68fSopenharmony_ci if (mt->clone_fd) { 2946881f68fSopenharmony_ci w->ch = fuse_clone_chan(mt); 2956881f68fSopenharmony_ci if(!w->ch) { 2966881f68fSopenharmony_ci /* Don't attempt this again */ 2976881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: trying to continue " 2986881f68fSopenharmony_ci "without -o clone_fd.\n"); 2996881f68fSopenharmony_ci mt->clone_fd = 0; 3006881f68fSopenharmony_ci } 3016881f68fSopenharmony_ci } 3026881f68fSopenharmony_ci 3036881f68fSopenharmony_ci res = fuse_start_thread(&w->thread_id, fuse_do_work, w); 3046881f68fSopenharmony_ci if (res == -1) { 3056881f68fSopenharmony_ci fuse_chan_put(w->ch); 3066881f68fSopenharmony_ci free(w); 3076881f68fSopenharmony_ci return -1; 3086881f68fSopenharmony_ci } 3096881f68fSopenharmony_ci list_add_worker(w, &mt->main); 3106881f68fSopenharmony_ci mt->numavail ++; 3116881f68fSopenharmony_ci mt->numworker ++; 3126881f68fSopenharmony_ci 3136881f68fSopenharmony_ci return 0; 3146881f68fSopenharmony_ci} 3156881f68fSopenharmony_ci 3166881f68fSopenharmony_cistatic void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) 3176881f68fSopenharmony_ci{ 3186881f68fSopenharmony_ci pthread_join(w->thread_id, NULL); 3196881f68fSopenharmony_ci pthread_mutex_lock(&mt->lock); 3206881f68fSopenharmony_ci list_del_worker(w); 3216881f68fSopenharmony_ci pthread_mutex_unlock(&mt->lock); 3226881f68fSopenharmony_ci free(w->fbuf.mem); 3236881f68fSopenharmony_ci fuse_chan_put(w->ch); 3246881f68fSopenharmony_ci free(w); 3256881f68fSopenharmony_ci} 3266881f68fSopenharmony_ci 3276881f68fSopenharmony_ciint fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); 3286881f68fSopenharmony_ciFUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12") 3296881f68fSopenharmony_ciint fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config) 3306881f68fSopenharmony_ci{ 3316881f68fSopenharmony_ciint err; 3326881f68fSopenharmony_ci struct fuse_mt mt; 3336881f68fSopenharmony_ci struct fuse_worker *w; 3346881f68fSopenharmony_ci int created_config = 0; 3356881f68fSopenharmony_ci 3366881f68fSopenharmony_ci if (config) { 3376881f68fSopenharmony_ci err = fuse_loop_cfg_verify(config); 3386881f68fSopenharmony_ci if (err) 3396881f68fSopenharmony_ci return err; 3406881f68fSopenharmony_ci } else { 3416881f68fSopenharmony_ci /* The caller does not care about parameters - use the default */ 3426881f68fSopenharmony_ci config = fuse_loop_cfg_create(); 3436881f68fSopenharmony_ci created_config = 1; 3446881f68fSopenharmony_ci } 3456881f68fSopenharmony_ci 3466881f68fSopenharmony_ci 3476881f68fSopenharmony_ci memset(&mt, 0, sizeof(struct fuse_mt)); 3486881f68fSopenharmony_ci mt.se = se; 3496881f68fSopenharmony_ci mt.clone_fd = config->clone_fd; 3506881f68fSopenharmony_ci mt.error = 0; 3516881f68fSopenharmony_ci mt.numworker = 0; 3526881f68fSopenharmony_ci mt.numavail = 0; 3536881f68fSopenharmony_ci mt.max_idle = config->max_idle_threads; 3546881f68fSopenharmony_ci mt.max_threads = config->max_threads; 3556881f68fSopenharmony_ci mt.main.thread_id = pthread_self(); 3566881f68fSopenharmony_ci mt.main.prev = mt.main.next = &mt.main; 3576881f68fSopenharmony_ci sem_init(&mt.finish, 0, 0); 3586881f68fSopenharmony_ci pthread_mutex_init(&mt.lock, NULL); 3596881f68fSopenharmony_ci 3606881f68fSopenharmony_ci pthread_mutex_lock(&mt.lock); 3616881f68fSopenharmony_ci err = fuse_loop_start_thread(&mt); 3626881f68fSopenharmony_ci pthread_mutex_unlock(&mt.lock); 3636881f68fSopenharmony_ci if (!err) { 3646881f68fSopenharmony_ci /* sem_wait() is interruptible */ 3656881f68fSopenharmony_ci while (!fuse_session_exited(se)) 3666881f68fSopenharmony_ci sem_wait(&mt.finish); 3676881f68fSopenharmony_ci 3686881f68fSopenharmony_ci pthread_mutex_lock(&mt.lock); 3696881f68fSopenharmony_ci for (w = mt.main.next; w != &mt.main; w = w->next) 3706881f68fSopenharmony_ci pthread_cancel(w->thread_id); 3716881f68fSopenharmony_ci mt.exit = 1; 3726881f68fSopenharmony_ci pthread_mutex_unlock(&mt.lock); 3736881f68fSopenharmony_ci 3746881f68fSopenharmony_ci while (mt.main.next != &mt.main) 3756881f68fSopenharmony_ci fuse_join_worker(&mt, mt.main.next); 3766881f68fSopenharmony_ci 3776881f68fSopenharmony_ci err = mt.error; 3786881f68fSopenharmony_ci } 3796881f68fSopenharmony_ci 3806881f68fSopenharmony_ci pthread_mutex_destroy(&mt.lock); 3816881f68fSopenharmony_ci sem_destroy(&mt.finish); 3826881f68fSopenharmony_ci if(se->error != 0) 3836881f68fSopenharmony_ci err = se->error; 3846881f68fSopenharmony_ci fuse_session_reset(se); 3856881f68fSopenharmony_ci 3866881f68fSopenharmony_ci if (created_config) { 3876881f68fSopenharmony_ci fuse_loop_cfg_destroy(config); 3886881f68fSopenharmony_ci config = NULL; 3896881f68fSopenharmony_ci } 3906881f68fSopenharmony_ci 3916881f68fSopenharmony_ci return err; 3926881f68fSopenharmony_ci} 3936881f68fSopenharmony_ci 3946881f68fSopenharmony_ciint fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1); 3956881f68fSopenharmony_ciFUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2") 3966881f68fSopenharmony_ciint fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1) 3976881f68fSopenharmony_ci{ 3986881f68fSopenharmony_ci int err; 3996881f68fSopenharmony_ci struct fuse_loop_config *config = NULL; 4006881f68fSopenharmony_ci 4016881f68fSopenharmony_ci if (config_v1 != NULL) { 4026881f68fSopenharmony_ci /* convert the given v1 config */ 4036881f68fSopenharmony_ci config = fuse_loop_cfg_create(); 4046881f68fSopenharmony_ci if (config == NULL) 4056881f68fSopenharmony_ci return ENOMEM; 4066881f68fSopenharmony_ci 4076881f68fSopenharmony_ci fuse_loop_cfg_convert(config, config_v1); 4086881f68fSopenharmony_ci } 4096881f68fSopenharmony_ci 4106881f68fSopenharmony_ci err = fuse_session_loop_mt_312(se, config); 4116881f68fSopenharmony_ci 4126881f68fSopenharmony_ci fuse_loop_cfg_destroy(config); 4136881f68fSopenharmony_ci 4146881f68fSopenharmony_ci return err; 4156881f68fSopenharmony_ci} 4166881f68fSopenharmony_ci 4176881f68fSopenharmony_ci 4186881f68fSopenharmony_ciint fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); 4196881f68fSopenharmony_ciFUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0") 4206881f68fSopenharmony_ciint fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd) 4216881f68fSopenharmony_ci{ 4226881f68fSopenharmony_ci struct fuse_loop_config *config = fuse_loop_cfg_create(); 4236881f68fSopenharmony_ci if (clone_fd > 0) 4246881f68fSopenharmony_ci fuse_loop_cfg_set_clone_fd(config, clone_fd); 4256881f68fSopenharmony_ci return fuse_session_loop_mt_312(se, config); 4266881f68fSopenharmony_ci} 4276881f68fSopenharmony_ci 4286881f68fSopenharmony_cistruct fuse_loop_config *fuse_loop_cfg_create(void) 4296881f68fSopenharmony_ci{ 4306881f68fSopenharmony_ci struct fuse_loop_config *config = calloc(1, sizeof(*config)); 4316881f68fSopenharmony_ci if (config == NULL) 4326881f68fSopenharmony_ci return NULL; 4336881f68fSopenharmony_ci 4346881f68fSopenharmony_ci config->version_id = FUSE_LOOP_MT_V2_IDENTIFIER; 4356881f68fSopenharmony_ci config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS; 4366881f68fSopenharmony_ci config->max_threads = FUSE_LOOP_MT_DEF_MAX_THREADS; 4376881f68fSopenharmony_ci config->clone_fd = FUSE_LOOP_MT_DEF_CLONE_FD; 4386881f68fSopenharmony_ci 4396881f68fSopenharmony_ci return config; 4406881f68fSopenharmony_ci} 4416881f68fSopenharmony_ci 4426881f68fSopenharmony_civoid fuse_loop_cfg_destroy(struct fuse_loop_config *config) 4436881f68fSopenharmony_ci{ 4446881f68fSopenharmony_ci free(config); 4456881f68fSopenharmony_ci} 4466881f68fSopenharmony_ci 4476881f68fSopenharmony_ciint fuse_loop_cfg_verify(struct fuse_loop_config *config) 4486881f68fSopenharmony_ci{ 4496881f68fSopenharmony_ci if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER) 4506881f68fSopenharmony_ci return -EINVAL; 4516881f68fSopenharmony_ci 4526881f68fSopenharmony_ci return 0; 4536881f68fSopenharmony_ci} 4546881f68fSopenharmony_ci 4556881f68fSopenharmony_civoid fuse_loop_cfg_convert(struct fuse_loop_config *config, 4566881f68fSopenharmony_ci struct fuse_loop_config_v1 *v1_conf) 4576881f68fSopenharmony_ci{ 4586881f68fSopenharmony_ci fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads); 4596881f68fSopenharmony_ci 4606881f68fSopenharmony_ci fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd); 4616881f68fSopenharmony_ci} 4626881f68fSopenharmony_ci 4636881f68fSopenharmony_civoid fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, 4646881f68fSopenharmony_ci unsigned int value) 4656881f68fSopenharmony_ci{ 4666881f68fSopenharmony_ci if (value > FUSE_LOOP_MT_MAX_THREADS) { 4676881f68fSopenharmony_ci if (value != UINT_MAX) 4686881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, 4696881f68fSopenharmony_ci "Ignoring invalid max threads value " 4706881f68fSopenharmony_ci "%u > max (%u).\n", value, 4716881f68fSopenharmony_ci FUSE_LOOP_MT_MAX_THREADS); 4726881f68fSopenharmony_ci return; 4736881f68fSopenharmony_ci } 4746881f68fSopenharmony_ci config->max_idle_threads = value; 4756881f68fSopenharmony_ci} 4766881f68fSopenharmony_ci 4776881f68fSopenharmony_civoid fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config, 4786881f68fSopenharmony_ci unsigned int value) 4796881f68fSopenharmony_ci{ 4806881f68fSopenharmony_ci config->max_threads = value; 4816881f68fSopenharmony_ci} 4826881f68fSopenharmony_ci 4836881f68fSopenharmony_civoid fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, 4846881f68fSopenharmony_ci unsigned int value) 4856881f68fSopenharmony_ci{ 4866881f68fSopenharmony_ci config->clone_fd = value; 4876881f68fSopenharmony_ci} 4886881f68fSopenharmony_ci 489