static void mt_session_exit(void *data, int val) { struct procdata *pd = (struct procdata *) data; if (val) fuse_session_exit(pd->prevse); else fuse_session_reset(pd->prevse); }
/** * internal function that is called from processing a message that has been queued on the /dev/fuse socket. That function is inherited from fuse_kern_chan_receive @param chp : pointer to the channel @param buf: pointer to the buffer where data will be copied @param size : max size of the receive buffer @retval > 0 : number of byte read @retval = 0 : session has been exited @retval < 0 : error */ int rozofs_fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { struct fuse_chan *ch = *chp; int err; ssize_t res; struct fuse_session *se = fuse_chan_session(ch); assert(se != NULL); restart: res = read(fuse_chan_fd(ch), buf, size); if (fuse_session_exited(se)) return 0; if (res == -1) { /* ENOENT means the operation was interrupted, it's safe to restart */ err = errno; if (err == ENOENT) { rozofs_fuse_req_enoent_count++; goto restart; } if (err == ENODEV) { severe("Exit from RozofsMount required!!!"); fuse_session_exit(se); rozofs_exit(); return 0; } /* Errors occurring during normal operation: EINTR (read interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem umounted) */ if (err != EINTR && err != EAGAIN) severe("fuse: reading device"); if ((err == EAGAIN)|| (err == EINTR)) rozofs_fuse_req_eagain_count++; return -err; } #if 0 if ((size_t) res < sizeof(struct fuse_in_header)) { fprintf(stderr, "short read on fuse device\n"); return -EIO; } #endif rozofs_fuse_req_count++; rozofs_fuse_req_byte_in+=res; return res; }
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { struct fuse_chan *ch = *chp; int err; ssize_t res; struct fuse_session *se = fuse_chan_session(ch); assert(se != NULL); restart: res = read(fuse_chan_fd(ch), buf, size); err = errno; if (fuse_session_exited(se)) return 0; if (res == -1) { /* ENOENT means the operation was interrupted, it's safe to restart */ if (err == ENOENT) goto restart; if (err == ENODEV) { fuse_session_exit(se); return 0; } /* Errors occurring during normal operation: EINTR (read interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem umounted) */ if (err != EINTR && err != EAGAIN) perror("fuse: reading device"); return -err; } if ((size_t) res < sizeof(struct fuse_in_header)) { fprintf(stderr, "short read on fuse device\n"); return -EIO; } return res; }
static void exit_handler(int sig) { (void) sig; if (fuse_instance) fuse_session_exit(fuse_instance); }
static void *fuse_do_work(void *data) { struct fuse_worker *w = (struct fuse_worker *) data; struct fuse_mt *mt = w->mt; while (!fuse_session_exited(mt->se)) { int isforget = 0; struct fuse_chan *ch = mt->prevch; struct fuse_buf fbuf = { .mem = w->buf, .size = w->bufsize, }; int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); res = fuse_session_receive_buf(mt->se, &fbuf, &ch); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; if (res <= 0) { if (res < 0) { fuse_session_exit(mt->se); mt->error = -1; } break; } pthread_mutex_lock(&mt->lock); if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } /* * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ if (!(fbuf.flags & FUSE_BUF_IS_FD)) { struct fuse_in_header *in = fbuf.mem; if (in->opcode == FUSE_FORGET || in->opcode == FUSE_BATCH_FORGET) isforget = 1; } if (!isforget) mt->numavail--; if (mt->numavail == 0) fuse_loop_start_thread(mt); pthread_mutex_unlock(&mt->lock); fuse_session_process_buf(mt->se, &fbuf, ch); pthread_mutex_lock(&mt->lock); if (!isforget) mt->numavail++; if (mt->numavail > 10) { if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } list_del_worker(w); mt->numavail--; mt->numworker--; pthread_mutex_unlock(&mt->lock); pthread_detach(w->thread_id); free(w->buf); free(w); return NULL; } pthread_mutex_unlock(&mt->lock); } sem_post(&mt->finish); return NULL; } int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) { sigset_t oldset; sigset_t newset; int res; pthread_attr_t attr; char *stack_size; /* Override default stack size */ pthread_attr_init(&attr); stack_size = getenv(ENVNAME_THREAD_STACK); if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); /* Disallow signal reception in worker threads */ sigemptyset(&newset); sigaddset(&newset, SIGTERM); sigaddset(&newset, SIGINT); sigaddset(&newset, SIGHUP); sigaddset(&newset, SIGQUIT); pthread_sigmask(SIG_BLOCK, &newset, &oldset); res = pthread_create(thread_id, &attr, func, arg); pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_attr_destroy(&attr); if (res != 0) { fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); return -1; } return 0; }
static void *fuse_do_work(void *data) { struct fuse_worker *w = (struct fuse_worker *) data; struct fuse_mt *mt = w->mt; while (!fuse_session_exited(mt->se)) { int isforget = 0; struct fuse_chan *ch = mt->prevch; int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); res = fuse_chan_recv(&ch, w->buf, w->bufsize); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; if (res <= 0) { if (res < 0) { fuse_session_exit(mt->se); mt->error = -1; } break; } pthread_mutex_lock(&mt->lock); if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } /* * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) isforget = 1; if (!isforget) mt->numavail--; if (mt->numavail == 0) fuse_start_thread(mt); pthread_mutex_unlock(&mt->lock); fuse_session_process(mt->se, w->buf, res, ch); pthread_mutex_lock(&mt->lock); if (!isforget) mt->numavail++; if (mt->numavail > 10) { if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; } list_del_worker(w); mt->numavail--; mt->numworker--; pthread_mutex_unlock(&mt->lock); pthread_detach(w->thread_id); free(w->buf); free(w); return NULL; } pthread_mutex_unlock(&mt->lock); } sem_post(&mt->finish); #ifdef __APPLE__ { sigset_t set; (void) sigprocmask(0, NULL, &set); (void) sigsuspend(&set); /* want cancelable */ } #else /* !__APPLE__ */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pause(); #endif /* __APPLE__ */ return NULL; }