1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker FUSE: Filesystem in Userspace
3*9e564957SAndroid Build Coastguard Worker Copyright (C) 2001-2007 Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker
5*9e564957SAndroid Build Coastguard Worker Implementation of the multi-threaded FUSE session loop.
6*9e564957SAndroid Build Coastguard Worker
7*9e564957SAndroid Build Coastguard Worker This program can be distributed under the terms of the GNU LGPLv2.
8*9e564957SAndroid Build Coastguard Worker See the file COPYING.LIB.
9*9e564957SAndroid Build Coastguard Worker */
10*9e564957SAndroid Build Coastguard Worker
11*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
12*9e564957SAndroid Build Coastguard Worker #include "fuse_lowlevel.h"
13*9e564957SAndroid Build Coastguard Worker #include "fuse_misc.h"
14*9e564957SAndroid Build Coastguard Worker #include "fuse_kernel.h"
15*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
16*9e564957SAndroid Build Coastguard Worker
17*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
18*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
19*9e564957SAndroid Build Coastguard Worker #include <string.h>
20*9e564957SAndroid Build Coastguard Worker #include <unistd.h>
21*9e564957SAndroid Build Coastguard Worker #include <signal.h>
22*9e564957SAndroid Build Coastguard Worker #include <semaphore.h>
23*9e564957SAndroid Build Coastguard Worker #include <errno.h>
24*9e564957SAndroid Build Coastguard Worker #include <sys/time.h>
25*9e564957SAndroid Build Coastguard Worker #include <sys/ioctl.h>
26*9e564957SAndroid Build Coastguard Worker #include <assert.h>
27*9e564957SAndroid Build Coastguard Worker #include <limits.h>
28*9e564957SAndroid Build Coastguard Worker
29*9e564957SAndroid Build Coastguard Worker /* Environment var controlling the thread stack size */
30*9e564957SAndroid Build Coastguard Worker #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
31*9e564957SAndroid Build Coastguard Worker
32*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_V2_IDENTIFIER INT_MAX - 2
33*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_CLONE_FD 0
34*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_MAX_THREADS 10
35*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled
36*9e564957SAndroid Build Coastguard Worker * by default */
37*9e564957SAndroid Build Coastguard Worker
38*9e564957SAndroid Build Coastguard Worker /* an arbitrary large value that cannot be valid */
39*9e564957SAndroid Build Coastguard Worker #define FUSE_LOOP_MT_MAX_THREADS (100U * 1000)
40*9e564957SAndroid Build Coastguard Worker
41*9e564957SAndroid Build Coastguard Worker struct fuse_worker {
42*9e564957SAndroid Build Coastguard Worker struct fuse_worker *prev;
43*9e564957SAndroid Build Coastguard Worker struct fuse_worker *next;
44*9e564957SAndroid Build Coastguard Worker pthread_t thread_id;
45*9e564957SAndroid Build Coastguard Worker
46*9e564957SAndroid Build Coastguard Worker // We need to include fuse_buf so that we can properly free
47*9e564957SAndroid Build Coastguard Worker // it when a thread is terminated by pthread_cancel().
48*9e564957SAndroid Build Coastguard Worker struct fuse_buf fbuf;
49*9e564957SAndroid Build Coastguard Worker struct fuse_chan *ch;
50*9e564957SAndroid Build Coastguard Worker struct fuse_mt *mt;
51*9e564957SAndroid Build Coastguard Worker };
52*9e564957SAndroid Build Coastguard Worker
53*9e564957SAndroid Build Coastguard Worker struct fuse_mt {
54*9e564957SAndroid Build Coastguard Worker pthread_mutex_t lock;
55*9e564957SAndroid Build Coastguard Worker int numworker;
56*9e564957SAndroid Build Coastguard Worker int numavail;
57*9e564957SAndroid Build Coastguard Worker struct fuse_session *se;
58*9e564957SAndroid Build Coastguard Worker struct fuse_worker main;
59*9e564957SAndroid Build Coastguard Worker sem_t finish;
60*9e564957SAndroid Build Coastguard Worker int exit;
61*9e564957SAndroid Build Coastguard Worker int error;
62*9e564957SAndroid Build Coastguard Worker int clone_fd;
63*9e564957SAndroid Build Coastguard Worker int max_idle;
64*9e564957SAndroid Build Coastguard Worker int max_threads;
65*9e564957SAndroid Build Coastguard Worker };
66*9e564957SAndroid Build Coastguard Worker
fuse_chan_new(int fd)67*9e564957SAndroid Build Coastguard Worker static struct fuse_chan *fuse_chan_new(int fd)
68*9e564957SAndroid Build Coastguard Worker {
69*9e564957SAndroid Build Coastguard Worker struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
70*9e564957SAndroid Build Coastguard Worker if (ch == NULL) {
71*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n");
72*9e564957SAndroid Build Coastguard Worker return NULL;
73*9e564957SAndroid Build Coastguard Worker }
74*9e564957SAndroid Build Coastguard Worker
75*9e564957SAndroid Build Coastguard Worker memset(ch, 0, sizeof(*ch));
76*9e564957SAndroid Build Coastguard Worker ch->fd = fd;
77*9e564957SAndroid Build Coastguard Worker ch->ctr = 1;
78*9e564957SAndroid Build Coastguard Worker pthread_mutex_init(&ch->lock, NULL);
79*9e564957SAndroid Build Coastguard Worker
80*9e564957SAndroid Build Coastguard Worker return ch;
81*9e564957SAndroid Build Coastguard Worker }
82*9e564957SAndroid Build Coastguard Worker
fuse_chan_get(struct fuse_chan * ch)83*9e564957SAndroid Build Coastguard Worker struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
84*9e564957SAndroid Build Coastguard Worker {
85*9e564957SAndroid Build Coastguard Worker assert(ch->ctr > 0);
86*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&ch->lock);
87*9e564957SAndroid Build Coastguard Worker ch->ctr++;
88*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&ch->lock);
89*9e564957SAndroid Build Coastguard Worker
90*9e564957SAndroid Build Coastguard Worker return ch;
91*9e564957SAndroid Build Coastguard Worker }
92*9e564957SAndroid Build Coastguard Worker
fuse_chan_put(struct fuse_chan * ch)93*9e564957SAndroid Build Coastguard Worker void fuse_chan_put(struct fuse_chan *ch)
94*9e564957SAndroid Build Coastguard Worker {
95*9e564957SAndroid Build Coastguard Worker if (ch == NULL)
96*9e564957SAndroid Build Coastguard Worker return;
97*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&ch->lock);
98*9e564957SAndroid Build Coastguard Worker ch->ctr--;
99*9e564957SAndroid Build Coastguard Worker if (!ch->ctr) {
100*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&ch->lock);
101*9e564957SAndroid Build Coastguard Worker close(ch->fd);
102*9e564957SAndroid Build Coastguard Worker pthread_mutex_destroy(&ch->lock);
103*9e564957SAndroid Build Coastguard Worker free(ch);
104*9e564957SAndroid Build Coastguard Worker } else
105*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&ch->lock);
106*9e564957SAndroid Build Coastguard Worker }
107*9e564957SAndroid Build Coastguard Worker
list_add_worker(struct fuse_worker * w,struct fuse_worker * next)108*9e564957SAndroid Build Coastguard Worker static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
109*9e564957SAndroid Build Coastguard Worker {
110*9e564957SAndroid Build Coastguard Worker struct fuse_worker *prev = next->prev;
111*9e564957SAndroid Build Coastguard Worker w->next = next;
112*9e564957SAndroid Build Coastguard Worker w->prev = prev;
113*9e564957SAndroid Build Coastguard Worker prev->next = w;
114*9e564957SAndroid Build Coastguard Worker next->prev = w;
115*9e564957SAndroid Build Coastguard Worker }
116*9e564957SAndroid Build Coastguard Worker
list_del_worker(struct fuse_worker * w)117*9e564957SAndroid Build Coastguard Worker static void list_del_worker(struct fuse_worker *w)
118*9e564957SAndroid Build Coastguard Worker {
119*9e564957SAndroid Build Coastguard Worker struct fuse_worker *prev = w->prev;
120*9e564957SAndroid Build Coastguard Worker struct fuse_worker *next = w->next;
121*9e564957SAndroid Build Coastguard Worker prev->next = next;
122*9e564957SAndroid Build Coastguard Worker next->prev = prev;
123*9e564957SAndroid Build Coastguard Worker }
124*9e564957SAndroid Build Coastguard Worker
125*9e564957SAndroid Build Coastguard Worker static int fuse_loop_start_thread(struct fuse_mt *mt);
126*9e564957SAndroid Build Coastguard Worker
fuse_do_work(void * data)127*9e564957SAndroid Build Coastguard Worker static void *fuse_do_work(void *data)
128*9e564957SAndroid Build Coastguard Worker {
129*9e564957SAndroid Build Coastguard Worker struct fuse_worker *w = (struct fuse_worker *) data;
130*9e564957SAndroid Build Coastguard Worker struct fuse_mt *mt = w->mt;
131*9e564957SAndroid Build Coastguard Worker
132*9e564957SAndroid Build Coastguard Worker while (!fuse_session_exited(mt->se)) {
133*9e564957SAndroid Build Coastguard Worker int isforget = 0;
134*9e564957SAndroid Build Coastguard Worker int res;
135*9e564957SAndroid Build Coastguard Worker
136*9e564957SAndroid Build Coastguard Worker pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
137*9e564957SAndroid Build Coastguard Worker res = fuse_session_receive_buf_int(mt->se, &w->fbuf, w->ch);
138*9e564957SAndroid Build Coastguard Worker pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
139*9e564957SAndroid Build Coastguard Worker if (res == -EINTR)
140*9e564957SAndroid Build Coastguard Worker continue;
141*9e564957SAndroid Build Coastguard Worker if (res <= 0) {
142*9e564957SAndroid Build Coastguard Worker if (res < 0) {
143*9e564957SAndroid Build Coastguard Worker fuse_session_exit(mt->se);
144*9e564957SAndroid Build Coastguard Worker mt->error = res;
145*9e564957SAndroid Build Coastguard Worker }
146*9e564957SAndroid Build Coastguard Worker break;
147*9e564957SAndroid Build Coastguard Worker }
148*9e564957SAndroid Build Coastguard Worker
149*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&mt->lock);
150*9e564957SAndroid Build Coastguard Worker if (mt->exit) {
151*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
152*9e564957SAndroid Build Coastguard Worker return NULL;
153*9e564957SAndroid Build Coastguard Worker }
154*9e564957SAndroid Build Coastguard Worker
155*9e564957SAndroid Build Coastguard Worker /*
156*9e564957SAndroid Build Coastguard Worker * This disgusting hack is needed so that zillions of threads
157*9e564957SAndroid Build Coastguard Worker * are not created on a burst of FORGET messages
158*9e564957SAndroid Build Coastguard Worker */
159*9e564957SAndroid Build Coastguard Worker if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) {
160*9e564957SAndroid Build Coastguard Worker struct fuse_in_header *in = w->fbuf.mem;
161*9e564957SAndroid Build Coastguard Worker
162*9e564957SAndroid Build Coastguard Worker if (in->opcode == FUSE_FORGET ||
163*9e564957SAndroid Build Coastguard Worker in->opcode == FUSE_BATCH_FORGET)
164*9e564957SAndroid Build Coastguard Worker isforget = 1;
165*9e564957SAndroid Build Coastguard Worker }
166*9e564957SAndroid Build Coastguard Worker
167*9e564957SAndroid Build Coastguard Worker if (!isforget)
168*9e564957SAndroid Build Coastguard Worker mt->numavail--;
169*9e564957SAndroid Build Coastguard Worker if (mt->numavail == 0 && mt->numworker < mt->max_threads)
170*9e564957SAndroid Build Coastguard Worker fuse_loop_start_thread(mt);
171*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
172*9e564957SAndroid Build Coastguard Worker
173*9e564957SAndroid Build Coastguard Worker fuse_session_process_buf_int(mt->se, &w->fbuf, w->ch);
174*9e564957SAndroid Build Coastguard Worker
175*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&mt->lock);
176*9e564957SAndroid Build Coastguard Worker if (!isforget)
177*9e564957SAndroid Build Coastguard Worker mt->numavail++;
178*9e564957SAndroid Build Coastguard Worker
179*9e564957SAndroid Build Coastguard Worker /* creating and destroying threads is rather expensive - and there is
180*9e564957SAndroid Build Coastguard Worker * not much gain from destroying existing threads. It is therefore
181*9e564957SAndroid Build Coastguard Worker * discouraged to set max_idle to anything else than -1. If there
182*9e564957SAndroid Build Coastguard Worker * is indeed a good reason to destruct threads it should be done
183*9e564957SAndroid Build Coastguard Worker * delayed, a moving average might be useful for that.
184*9e564957SAndroid Build Coastguard Worker */
185*9e564957SAndroid Build Coastguard Worker if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) {
186*9e564957SAndroid Build Coastguard Worker if (mt->exit) {
187*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
188*9e564957SAndroid Build Coastguard Worker return NULL;
189*9e564957SAndroid Build Coastguard Worker }
190*9e564957SAndroid Build Coastguard Worker list_del_worker(w);
191*9e564957SAndroid Build Coastguard Worker mt->numavail--;
192*9e564957SAndroid Build Coastguard Worker mt->numworker--;
193*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
194*9e564957SAndroid Build Coastguard Worker
195*9e564957SAndroid Build Coastguard Worker pthread_detach(w->thread_id);
196*9e564957SAndroid Build Coastguard Worker free(w->fbuf.mem);
197*9e564957SAndroid Build Coastguard Worker fuse_chan_put(w->ch);
198*9e564957SAndroid Build Coastguard Worker free(w);
199*9e564957SAndroid Build Coastguard Worker return NULL;
200*9e564957SAndroid Build Coastguard Worker }
201*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
202*9e564957SAndroid Build Coastguard Worker }
203*9e564957SAndroid Build Coastguard Worker
204*9e564957SAndroid Build Coastguard Worker sem_post(&mt->finish);
205*9e564957SAndroid Build Coastguard Worker
206*9e564957SAndroid Build Coastguard Worker return NULL;
207*9e564957SAndroid Build Coastguard Worker }
208*9e564957SAndroid Build Coastguard Worker
fuse_start_thread(pthread_t * thread_id,void * (* func)(void *),void * arg)209*9e564957SAndroid Build Coastguard Worker int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
210*9e564957SAndroid Build Coastguard Worker {
211*9e564957SAndroid Build Coastguard Worker sigset_t oldset;
212*9e564957SAndroid Build Coastguard Worker sigset_t newset;
213*9e564957SAndroid Build Coastguard Worker int res;
214*9e564957SAndroid Build Coastguard Worker pthread_attr_t attr;
215*9e564957SAndroid Build Coastguard Worker char *stack_size;
216*9e564957SAndroid Build Coastguard Worker
217*9e564957SAndroid Build Coastguard Worker /* Override default stack size
218*9e564957SAndroid Build Coastguard Worker * XXX: This should ideally be a parameter option. It is rather
219*9e564957SAndroid Build Coastguard Worker * well hidden here.
220*9e564957SAndroid Build Coastguard Worker */
221*9e564957SAndroid Build Coastguard Worker pthread_attr_init(&attr);
222*9e564957SAndroid Build Coastguard Worker stack_size = getenv(ENVNAME_THREAD_STACK);
223*9e564957SAndroid Build Coastguard Worker if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
224*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n", stack_size);
225*9e564957SAndroid Build Coastguard Worker
226*9e564957SAndroid Build Coastguard Worker /* Disallow signal reception in worker threads */
227*9e564957SAndroid Build Coastguard Worker sigemptyset(&newset);
228*9e564957SAndroid Build Coastguard Worker sigaddset(&newset, SIGTERM);
229*9e564957SAndroid Build Coastguard Worker sigaddset(&newset, SIGINT);
230*9e564957SAndroid Build Coastguard Worker sigaddset(&newset, SIGHUP);
231*9e564957SAndroid Build Coastguard Worker sigaddset(&newset, SIGQUIT);
232*9e564957SAndroid Build Coastguard Worker pthread_sigmask(SIG_BLOCK, &newset, &oldset);
233*9e564957SAndroid Build Coastguard Worker res = pthread_create(thread_id, &attr, func, arg);
234*9e564957SAndroid Build Coastguard Worker pthread_sigmask(SIG_SETMASK, &oldset, NULL);
235*9e564957SAndroid Build Coastguard Worker pthread_attr_destroy(&attr);
236*9e564957SAndroid Build Coastguard Worker if (res != 0) {
237*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n",
238*9e564957SAndroid Build Coastguard Worker strerror(res));
239*9e564957SAndroid Build Coastguard Worker return -1;
240*9e564957SAndroid Build Coastguard Worker }
241*9e564957SAndroid Build Coastguard Worker
242*9e564957SAndroid Build Coastguard Worker return 0;
243*9e564957SAndroid Build Coastguard Worker }
244*9e564957SAndroid Build Coastguard Worker
fuse_clone_chan_fd_default(struct fuse_session * se)245*9e564957SAndroid Build Coastguard Worker static int fuse_clone_chan_fd_default(struct fuse_session *se)
246*9e564957SAndroid Build Coastguard Worker {
247*9e564957SAndroid Build Coastguard Worker int res;
248*9e564957SAndroid Build Coastguard Worker int clonefd;
249*9e564957SAndroid Build Coastguard Worker uint32_t masterfd;
250*9e564957SAndroid Build Coastguard Worker const char *devname = "/dev/fuse";
251*9e564957SAndroid Build Coastguard Worker
252*9e564957SAndroid Build Coastguard Worker #ifndef O_CLOEXEC
253*9e564957SAndroid Build Coastguard Worker #define O_CLOEXEC 0
254*9e564957SAndroid Build Coastguard Worker #endif
255*9e564957SAndroid Build Coastguard Worker clonefd = open(devname, O_RDWR | O_CLOEXEC);
256*9e564957SAndroid Build Coastguard Worker if (clonefd == -1) {
257*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname,
258*9e564957SAndroid Build Coastguard Worker strerror(errno));
259*9e564957SAndroid Build Coastguard Worker return -1;
260*9e564957SAndroid Build Coastguard Worker }
261*9e564957SAndroid Build Coastguard Worker #ifndef O_CLOEXEC
262*9e564957SAndroid Build Coastguard Worker fcntl(clonefd, F_SETFD, FD_CLOEXEC);
263*9e564957SAndroid Build Coastguard Worker #endif
264*9e564957SAndroid Build Coastguard Worker
265*9e564957SAndroid Build Coastguard Worker masterfd = se->fd;
266*9e564957SAndroid Build Coastguard Worker res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
267*9e564957SAndroid Build Coastguard Worker if (res == -1) {
268*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n",
269*9e564957SAndroid Build Coastguard Worker strerror(errno));
270*9e564957SAndroid Build Coastguard Worker close(clonefd);
271*9e564957SAndroid Build Coastguard Worker return -1;
272*9e564957SAndroid Build Coastguard Worker }
273*9e564957SAndroid Build Coastguard Worker return clonefd;
274*9e564957SAndroid Build Coastguard Worker }
275*9e564957SAndroid Build Coastguard Worker
fuse_clone_chan(struct fuse_mt * mt)276*9e564957SAndroid Build Coastguard Worker static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt)
277*9e564957SAndroid Build Coastguard Worker {
278*9e564957SAndroid Build Coastguard Worker int clonefd;
279*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = mt->se;
280*9e564957SAndroid Build Coastguard Worker struct fuse_chan *newch;
281*9e564957SAndroid Build Coastguard Worker
282*9e564957SAndroid Build Coastguard Worker if (se->io != NULL) {
283*9e564957SAndroid Build Coastguard Worker if (se->io->clone_fd != NULL)
284*9e564957SAndroid Build Coastguard Worker clonefd = se->io->clone_fd(se->fd);
285*9e564957SAndroid Build Coastguard Worker else
286*9e564957SAndroid Build Coastguard Worker return NULL;
287*9e564957SAndroid Build Coastguard Worker } else {
288*9e564957SAndroid Build Coastguard Worker clonefd = fuse_clone_chan_fd_default(se);
289*9e564957SAndroid Build Coastguard Worker }
290*9e564957SAndroid Build Coastguard Worker if (clonefd < 0)
291*9e564957SAndroid Build Coastguard Worker return NULL;
292*9e564957SAndroid Build Coastguard Worker
293*9e564957SAndroid Build Coastguard Worker newch = fuse_chan_new(clonefd);
294*9e564957SAndroid Build Coastguard Worker if (newch == NULL)
295*9e564957SAndroid Build Coastguard Worker close(clonefd);
296*9e564957SAndroid Build Coastguard Worker
297*9e564957SAndroid Build Coastguard Worker return newch;
298*9e564957SAndroid Build Coastguard Worker }
299*9e564957SAndroid Build Coastguard Worker
fuse_loop_start_thread(struct fuse_mt * mt)300*9e564957SAndroid Build Coastguard Worker static int fuse_loop_start_thread(struct fuse_mt *mt)
301*9e564957SAndroid Build Coastguard Worker {
302*9e564957SAndroid Build Coastguard Worker int res;
303*9e564957SAndroid Build Coastguard Worker
304*9e564957SAndroid Build Coastguard Worker struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
305*9e564957SAndroid Build Coastguard Worker if (!w) {
306*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n");
307*9e564957SAndroid Build Coastguard Worker return -1;
308*9e564957SAndroid Build Coastguard Worker }
309*9e564957SAndroid Build Coastguard Worker memset(w, 0, sizeof(struct fuse_worker));
310*9e564957SAndroid Build Coastguard Worker w->fbuf.mem = NULL;
311*9e564957SAndroid Build Coastguard Worker w->mt = mt;
312*9e564957SAndroid Build Coastguard Worker
313*9e564957SAndroid Build Coastguard Worker w->ch = NULL;
314*9e564957SAndroid Build Coastguard Worker if (mt->clone_fd) {
315*9e564957SAndroid Build Coastguard Worker w->ch = fuse_clone_chan(mt);
316*9e564957SAndroid Build Coastguard Worker if(!w->ch) {
317*9e564957SAndroid Build Coastguard Worker /* Don't attempt this again */
318*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: trying to continue "
319*9e564957SAndroid Build Coastguard Worker "without -o clone_fd.\n");
320*9e564957SAndroid Build Coastguard Worker mt->clone_fd = 0;
321*9e564957SAndroid Build Coastguard Worker }
322*9e564957SAndroid Build Coastguard Worker }
323*9e564957SAndroid Build Coastguard Worker
324*9e564957SAndroid Build Coastguard Worker res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
325*9e564957SAndroid Build Coastguard Worker if (res == -1) {
326*9e564957SAndroid Build Coastguard Worker fuse_chan_put(w->ch);
327*9e564957SAndroid Build Coastguard Worker free(w);
328*9e564957SAndroid Build Coastguard Worker return -1;
329*9e564957SAndroid Build Coastguard Worker }
330*9e564957SAndroid Build Coastguard Worker list_add_worker(w, &mt->main);
331*9e564957SAndroid Build Coastguard Worker mt->numavail ++;
332*9e564957SAndroid Build Coastguard Worker mt->numworker ++;
333*9e564957SAndroid Build Coastguard Worker
334*9e564957SAndroid Build Coastguard Worker return 0;
335*9e564957SAndroid Build Coastguard Worker }
336*9e564957SAndroid Build Coastguard Worker
fuse_join_worker(struct fuse_mt * mt,struct fuse_worker * w)337*9e564957SAndroid Build Coastguard Worker static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
338*9e564957SAndroid Build Coastguard Worker {
339*9e564957SAndroid Build Coastguard Worker pthread_join(w->thread_id, NULL);
340*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&mt->lock);
341*9e564957SAndroid Build Coastguard Worker list_del_worker(w);
342*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt->lock);
343*9e564957SAndroid Build Coastguard Worker free(w->fbuf.mem);
344*9e564957SAndroid Build Coastguard Worker fuse_chan_put(w->ch);
345*9e564957SAndroid Build Coastguard Worker free(w);
346*9e564957SAndroid Build Coastguard Worker }
347*9e564957SAndroid Build Coastguard Worker
348*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config);
349*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12")
fuse_session_loop_mt_312(struct fuse_session * se,struct fuse_loop_config * config)350*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config)
351*9e564957SAndroid Build Coastguard Worker {
352*9e564957SAndroid Build Coastguard Worker int err;
353*9e564957SAndroid Build Coastguard Worker struct fuse_mt mt;
354*9e564957SAndroid Build Coastguard Worker struct fuse_worker *w;
355*9e564957SAndroid Build Coastguard Worker int created_config = 0;
356*9e564957SAndroid Build Coastguard Worker
357*9e564957SAndroid Build Coastguard Worker if (config) {
358*9e564957SAndroid Build Coastguard Worker err = fuse_loop_cfg_verify(config);
359*9e564957SAndroid Build Coastguard Worker if (err)
360*9e564957SAndroid Build Coastguard Worker return err;
361*9e564957SAndroid Build Coastguard Worker } else {
362*9e564957SAndroid Build Coastguard Worker /* The caller does not care about parameters - use the default */
363*9e564957SAndroid Build Coastguard Worker config = fuse_loop_cfg_create();
364*9e564957SAndroid Build Coastguard Worker created_config = 1;
365*9e564957SAndroid Build Coastguard Worker }
366*9e564957SAndroid Build Coastguard Worker
367*9e564957SAndroid Build Coastguard Worker
368*9e564957SAndroid Build Coastguard Worker memset(&mt, 0, sizeof(struct fuse_mt));
369*9e564957SAndroid Build Coastguard Worker mt.se = se;
370*9e564957SAndroid Build Coastguard Worker mt.clone_fd = config->clone_fd;
371*9e564957SAndroid Build Coastguard Worker mt.error = 0;
372*9e564957SAndroid Build Coastguard Worker mt.numworker = 0;
373*9e564957SAndroid Build Coastguard Worker mt.numavail = 0;
374*9e564957SAndroid Build Coastguard Worker mt.max_idle = config->max_idle_threads;
375*9e564957SAndroid Build Coastguard Worker mt.max_threads = config->max_threads;
376*9e564957SAndroid Build Coastguard Worker mt.main.thread_id = pthread_self();
377*9e564957SAndroid Build Coastguard Worker mt.main.prev = mt.main.next = &mt.main;
378*9e564957SAndroid Build Coastguard Worker sem_init(&mt.finish, 0, 0);
379*9e564957SAndroid Build Coastguard Worker pthread_mutex_init(&mt.lock, NULL);
380*9e564957SAndroid Build Coastguard Worker
381*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&mt.lock);
382*9e564957SAndroid Build Coastguard Worker err = fuse_loop_start_thread(&mt);
383*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt.lock);
384*9e564957SAndroid Build Coastguard Worker if (!err) {
385*9e564957SAndroid Build Coastguard Worker /* sem_wait() is interruptible */
386*9e564957SAndroid Build Coastguard Worker while (!fuse_session_exited(se))
387*9e564957SAndroid Build Coastguard Worker sem_wait(&mt.finish);
388*9e564957SAndroid Build Coastguard Worker
389*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&mt.lock);
390*9e564957SAndroid Build Coastguard Worker for (w = mt.main.next; w != &mt.main; w = w->next)
391*9e564957SAndroid Build Coastguard Worker pthread_cancel(w->thread_id);
392*9e564957SAndroid Build Coastguard Worker mt.exit = 1;
393*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&mt.lock);
394*9e564957SAndroid Build Coastguard Worker
395*9e564957SAndroid Build Coastguard Worker while (mt.main.next != &mt.main)
396*9e564957SAndroid Build Coastguard Worker fuse_join_worker(&mt, mt.main.next);
397*9e564957SAndroid Build Coastguard Worker
398*9e564957SAndroid Build Coastguard Worker err = mt.error;
399*9e564957SAndroid Build Coastguard Worker }
400*9e564957SAndroid Build Coastguard Worker
401*9e564957SAndroid Build Coastguard Worker pthread_mutex_destroy(&mt.lock);
402*9e564957SAndroid Build Coastguard Worker sem_destroy(&mt.finish);
403*9e564957SAndroid Build Coastguard Worker if(se->error != 0)
404*9e564957SAndroid Build Coastguard Worker err = se->error;
405*9e564957SAndroid Build Coastguard Worker fuse_session_reset(se);
406*9e564957SAndroid Build Coastguard Worker
407*9e564957SAndroid Build Coastguard Worker if (created_config) {
408*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_destroy(config);
409*9e564957SAndroid Build Coastguard Worker config = NULL;
410*9e564957SAndroid Build Coastguard Worker }
411*9e564957SAndroid Build Coastguard Worker
412*9e564957SAndroid Build Coastguard Worker return err;
413*9e564957SAndroid Build Coastguard Worker }
414*9e564957SAndroid Build Coastguard Worker
415*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1);
416*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2")
fuse_session_loop_mt_32(struct fuse_session * se,struct fuse_loop_config_v1 * config_v1)417*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1)
418*9e564957SAndroid Build Coastguard Worker {
419*9e564957SAndroid Build Coastguard Worker int err;
420*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config *config = NULL;
421*9e564957SAndroid Build Coastguard Worker
422*9e564957SAndroid Build Coastguard Worker if (config_v1 != NULL) {
423*9e564957SAndroid Build Coastguard Worker /* convert the given v1 config */
424*9e564957SAndroid Build Coastguard Worker config = fuse_loop_cfg_create();
425*9e564957SAndroid Build Coastguard Worker if (config == NULL)
426*9e564957SAndroid Build Coastguard Worker return ENOMEM;
427*9e564957SAndroid Build Coastguard Worker
428*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_convert(config, config_v1);
429*9e564957SAndroid Build Coastguard Worker }
430*9e564957SAndroid Build Coastguard Worker
431*9e564957SAndroid Build Coastguard Worker err = fuse_session_loop_mt_312(se, config);
432*9e564957SAndroid Build Coastguard Worker
433*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_destroy(config);
434*9e564957SAndroid Build Coastguard Worker
435*9e564957SAndroid Build Coastguard Worker return err;
436*9e564957SAndroid Build Coastguard Worker }
437*9e564957SAndroid Build Coastguard Worker
438*9e564957SAndroid Build Coastguard Worker
439*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
440*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0")
fuse_session_loop_mt_31(struct fuse_session * se,int clone_fd)441*9e564957SAndroid Build Coastguard Worker int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
442*9e564957SAndroid Build Coastguard Worker {
443*9e564957SAndroid Build Coastguard Worker int err;
444*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config *config = fuse_loop_cfg_create();
445*9e564957SAndroid Build Coastguard Worker if (clone_fd > 0)
446*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_set_clone_fd(config, clone_fd);
447*9e564957SAndroid Build Coastguard Worker err = fuse_session_loop_mt_312(se, config);
448*9e564957SAndroid Build Coastguard Worker
449*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_destroy(config);
450*9e564957SAndroid Build Coastguard Worker
451*9e564957SAndroid Build Coastguard Worker return err;
452*9e564957SAndroid Build Coastguard Worker }
453*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_create(void)454*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config *fuse_loop_cfg_create(void)
455*9e564957SAndroid Build Coastguard Worker {
456*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config *config = calloc(1, sizeof(*config));
457*9e564957SAndroid Build Coastguard Worker if (config == NULL)
458*9e564957SAndroid Build Coastguard Worker return NULL;
459*9e564957SAndroid Build Coastguard Worker
460*9e564957SAndroid Build Coastguard Worker config->version_id = FUSE_LOOP_MT_V2_IDENTIFIER;
461*9e564957SAndroid Build Coastguard Worker config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS;
462*9e564957SAndroid Build Coastguard Worker config->max_threads = FUSE_LOOP_MT_DEF_MAX_THREADS;
463*9e564957SAndroid Build Coastguard Worker config->clone_fd = FUSE_LOOP_MT_DEF_CLONE_FD;
464*9e564957SAndroid Build Coastguard Worker
465*9e564957SAndroid Build Coastguard Worker return config;
466*9e564957SAndroid Build Coastguard Worker }
467*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_destroy(struct fuse_loop_config * config)468*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_destroy(struct fuse_loop_config *config)
469*9e564957SAndroid Build Coastguard Worker {
470*9e564957SAndroid Build Coastguard Worker free(config);
471*9e564957SAndroid Build Coastguard Worker }
472*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_verify(struct fuse_loop_config * config)473*9e564957SAndroid Build Coastguard Worker int fuse_loop_cfg_verify(struct fuse_loop_config *config)
474*9e564957SAndroid Build Coastguard Worker {
475*9e564957SAndroid Build Coastguard Worker if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER)
476*9e564957SAndroid Build Coastguard Worker return -EINVAL;
477*9e564957SAndroid Build Coastguard Worker
478*9e564957SAndroid Build Coastguard Worker return 0;
479*9e564957SAndroid Build Coastguard Worker }
480*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_convert(struct fuse_loop_config * config,struct fuse_loop_config_v1 * v1_conf)481*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_convert(struct fuse_loop_config *config,
482*9e564957SAndroid Build Coastguard Worker struct fuse_loop_config_v1 *v1_conf)
483*9e564957SAndroid Build Coastguard Worker {
484*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads);
485*9e564957SAndroid Build Coastguard Worker
486*9e564957SAndroid Build Coastguard Worker fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd);
487*9e564957SAndroid Build Coastguard Worker }
488*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_set_idle_threads(struct fuse_loop_config * config,unsigned int value)489*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config,
490*9e564957SAndroid Build Coastguard Worker unsigned int value)
491*9e564957SAndroid Build Coastguard Worker {
492*9e564957SAndroid Build Coastguard Worker if (value > FUSE_LOOP_MT_MAX_THREADS) {
493*9e564957SAndroid Build Coastguard Worker if (value != UINT_MAX)
494*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR,
495*9e564957SAndroid Build Coastguard Worker "Ignoring invalid max threads value "
496*9e564957SAndroid Build Coastguard Worker "%u > max (%u).\n", value,
497*9e564957SAndroid Build Coastguard Worker FUSE_LOOP_MT_MAX_THREADS);
498*9e564957SAndroid Build Coastguard Worker return;
499*9e564957SAndroid Build Coastguard Worker }
500*9e564957SAndroid Build Coastguard Worker config->max_idle_threads = value;
501*9e564957SAndroid Build Coastguard Worker }
502*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_set_max_threads(struct fuse_loop_config * config,unsigned int value)503*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config,
504*9e564957SAndroid Build Coastguard Worker unsigned int value)
505*9e564957SAndroid Build Coastguard Worker {
506*9e564957SAndroid Build Coastguard Worker config->max_threads = value;
507*9e564957SAndroid Build Coastguard Worker }
508*9e564957SAndroid Build Coastguard Worker
fuse_loop_cfg_set_clone_fd(struct fuse_loop_config * config,unsigned int value)509*9e564957SAndroid Build Coastguard Worker void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config,
510*9e564957SAndroid Build Coastguard Worker unsigned int value)
511*9e564957SAndroid Build Coastguard Worker {
512*9e564957SAndroid Build Coastguard Worker config->clone_fd = value;
513*9e564957SAndroid Build Coastguard Worker }
514*9e564957SAndroid Build Coastguard Worker
515