Beispiel #1
0
static gboolean manage_fuse_st (GIOChannel *source, GIOCondition condition, gpointer data)
{
    int res;
    char *buf;
    gboolean ret;
    size_t bufsize;
    struct fuse *fuse;
    struct fuse_session *se;
    struct fuse_chan *ch;

    fuse = (struct fuse*) data;
    se = fuse_get_session (fuse);
    ch = fuse_session_next_chan (se, NULL);
    bufsize = fuse_chan_bufsize (ch);
    buf = alloca (bufsize);

    ret = TRUE;
    res = fuse_chan_recv (&ch, buf, bufsize);

    if (res == -EINTR)
        ret = TRUE;
    else if (res <= 0)
        ret = FALSE;
    else
        fuse_session_process (se, buf, res, ch);

    return ret;
}
Beispiel #2
0
static Bool
fuseProcessMessages(void *data)
{
   CompDisplay *d = (CompDisplay *)data;
   struct fuse_chan *channel;
   size_t bufferSize;
   int res = 0;

   FUSE_DISPLAY(d);

   channel = fuse_session_next_chan(fd->session, NULL);
   bufferSize = fuse_chan_bufsize(channel);

   if (fuse_session_exited(fd->session))
     return FALSE;

   for (;; )
     {
        struct fuse_chan *tmpch = channel;

        res = fuse_chan_recv(&tmpch, fd->buffer, bufferSize);
        if (res == -EINTR)
          continue;

        if (res > 0)
          fuse_session_process(fd->session, fd->buffer, res, tmpch);

        break;
     }

   return TRUE;
}
Beispiel #3
0
int fuse_session_loop(struct fuse_session *se)
{
	int res = 0;
	struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
	size_t bufsize = fuse_chan_bufsize(ch);
	char *buf = (char *) malloc(bufsize);
	if (!buf) {
		fprintf(stderr, "fuse: failed to allocate read buffer\n");
		return -1;
	}

	while (!fuse_session_exited(se)) {
		struct fuse_chan *tmpch = ch;
		res = fuse_chan_recv(&tmpch, buf, bufsize);
		if (res == -EINTR)
			continue;
		if (res <= 0)
			break;
		fuse_session_process(se, buf, res, tmpch);
	}

	free(buf);
	fuse_session_reset(se);
	return res < 0 ? -1 : 0;
}
Beispiel #4
0
void fuse_session_process_buf(struct fuse_session *se,
			      const struct fuse_buf *buf, struct fuse_chan *ch)
{
	if (se->process_buf) {
		se->process_buf(se->data, buf, ch);
	} else {
		assert(!(buf->flags & FUSE_BUF_IS_FD));
		fuse_session_process(se->data, buf->mem, buf->size, ch);
	}
}
Beispiel #5
0
static void manage_request (gpointer data, gpointer user)
{
    struct fuse *fuse;
    struct fuse_session *se;
    struct fuse_chan *ch;
    ThreadsData *info;

    fuse = (struct fuse*) user;
    info = (ThreadsData*) data;

    se = fuse_get_session (fuse);
    ch = fuse_session_next_chan (se, NULL);
    fuse_session_process (se, info->buf, info->res, ch);

    free_threads_data (info);
}
Beispiel #6
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;
}
Beispiel #7
0
static void *zfsfuse_listener_loop(void *arg)
{
	size_t bufsize = 0;
	char *buf = NULL;

	VERIFY(pthread_mutex_lock(&mtx) == 0);

    fuse_listeners_count++;

	while(!exit_fuse_listener) {
		int ret = poll(fds, nfds, 1000);
		if(ret == 0 || (ret == -1 && errno == EINTR))
			continue;

		if(ret == -1) {
			perror("poll");
			continue;
		}

		int oldfds = nfds;

		for(int i = 0; i < oldfds; i++) {
			short rev = fds[i].revents;

			if(rev == 0)
				continue;

			fds[i].revents = 0;

			if (rev & POLLNVAL) { // already closed
			    // fuse_unmount_all triggers this
			    fds[i].fd = -1;
			    continue;
			}

			if(!(rev & POLLIN) && !(rev & POLLERR) && !(rev & POLLHUP))
				continue;

			if(i == 0) {
				new_fs();
			} else {
				/* Handle request */

				if(fsinfo[i].bufsize > bufsize) {
					char *new_buf = realloc(buf, fsinfo[i].bufsize);
					if(new_buf == NULL) {
						fprintf(stderr, "Warning: out of memory!\n");
						continue;
					}
					buf = new_buf;
					bufsize = fsinfo[i].bufsize;
				}

				if (!fsinfo[i].se) {
				    destroy_fs(i);
				    continue;
				}
				int res = fuse_chan_recv(&fsinfo[i].ch, buf, fsinfo[i].bufsize);
				if(res == -1 || fuse_session_exited(fsinfo[i].se)) {
				    destroy_fs(i);
				    continue;
				}

				if(res == 0)
					continue;

				struct fuse_session *se = fsinfo[i].se;
				struct fuse_chan *ch = fsinfo[i].ch;

				/*
				 * While we process this request, we let another
				 * thread receive new events
				 */
				VERIFY(pthread_mutex_unlock(&mtx) == 0);

				fuse_session_process(se, buf, res, ch);

				/* Acquire the mutex before proceeding */
				VERIFY(pthread_mutex_lock(&mtx) == 0);

				/*
				 * At this point, we can no longer trust oldfds
				 * to be accurate, so we exit this loop
		 *
		 * Also, exit_fuse_listener might have been set in the mean
		 * time
				 */
				break;
			}
		}

		/* Free the closed file descriptors entries */
		int write_ptr = 0;
		for(int read_ptr = 0; read_ptr < nfds; read_ptr++) {
			if(fds[read_ptr].fd == -1)
				continue;
			if(read_ptr != write_ptr) {
				fds[write_ptr] = fds[read_ptr];
				fsinfo[write_ptr] = fsinfo[read_ptr];
				mountpoints[write_ptr] = mountpoints[read_ptr];
			}
			write_ptr++;
		}
		nfds = write_ptr;
	}

    fuse_listeners_count--;
    VERIFY(0 == pthread_cond_signal(&exiting_fuse_listener));
	VERIFY(pthread_mutex_unlock(&mtx) == 0);

	return NULL;
}
Beispiel #8
0
// Return the amount of time to wait between sched_run_callbacks() calls
static struct timeval fuse_serve_timeout(void)
{
	struct timeval tv = { .tv_sec = 0, .tv_usec = 1000000/HZ };
	return tv;
}

struct callback_list {
	unlock_callback_t callback;
	void * data;
	int count;
	struct callback_list * next;
};
static struct callback_list * callbacks;

int fstitchd_unlock_callback(unlock_callback_t callback, void * data)
{
	if(callbacks && callbacks->callback == callback && callbacks->data == data)
		callbacks->count++;
	else
	{
		struct callback_list * list = malloc(sizeof(*list));
		if(!list)
			return -ENOMEM;
		list->callback = callback;
		list->data = data;
		list->count = 1;
		list->next = callbacks;
		callbacks = list;
	}
	return 0;
}

// Adapted from FUSE's lib/fuse_loop.c to support sched callbacks and multiple mounts
int fuse_serve_loop(void)
{
	struct timeval tv;
	mount_t ** mp;
	int r;
	Dprintf("%s()\n", __FUNCTION__);

	if (!root_cfs)
	{
		fprintf(stderr, "%s(): no root cfs was specified; not running.\n", __FUNCTION__);
		return -1;
	}

	if ((r = fuse_serve_mount_load_mounts()) < 0)
	{
		fprintf(stderr, "%s(): fuse_serve_load_mounts: %d\n", __FUNCTION__, r);
		return r;
	}

	serving = 1;
	tv = fuse_serve_timeout();

	while ((mp = fuse_serve_mounts()) && mp && mp[0])
	{
		fd_set rfds;
		int max_fd = 0;
		struct timeval it_start, it_end;

		FD_ZERO(&rfds);

		if (shutdown_pipe[0] != -1)
		{
			FD_SET(shutdown_pipe[0], &rfds);
			if (shutdown_pipe[0] > max_fd)
				max_fd = shutdown_pipe[0];
		}

		FD_SET(remove_activity, &rfds);
		if (remove_activity > max_fd)
			max_fd = remove_activity;

		for (mp = fuse_serve_mounts(); mp && *mp; mp++)
		{
			if ((*mp)->mounted && !fuse_session_exited((*mp)->session))
			{
				//printf("[\"%s\"]", mount->fstitch_path); fflush(stdout); // debug
				int mount_fd = fuse_chan_fd((*mp)->channel);
				FD_SET(mount_fd, &rfds);
				if (mount_fd > max_fd)
					max_fd = mount_fd;
			}
		}

		r = select(max_fd+1, &rfds, NULL, NULL, &tv);

		if (r == 0)
		{
			//printf("."); fflush(stdout); // debugging output
			sched_run_callbacks();
			tv = fuse_serve_timeout();
		}
		else if (r < 0)
		{
			if (errno != EINTR)
				perror("select");
			//printf("!\n"); fflush(stdout); // debugging output
			tv = fuse_serve_timeout(); // tv may have become undefined
		}
		else
		{
			if (gettimeofday(&it_start, NULL) == -1)
			{
				perror("gettimeofday");
				break;
			}

			for (mp = fuse_serve_mounts(); mp && *mp; mp++)
			{
				if ((*mp)->mounted && FD_ISSET((*mp)->channel_fd, &rfds))
				{
					r = fuse_chan_receive((*mp)->channel, channel_buf, channel_buf_len);
					if(r <= 0)
						fprintf(stderr, "fuse_chan_receive() returned %d, ignoring!\n", r);
					//assert(r > 0); // this happens during shutdown on MacFUSE...

					Dprintf("fuse_serve: request for mount \"%s\"\n", (*mp)->fstitch_path);
					fuse_session_process((*mp)->session, channel_buf, r, (*mp)->channel);
					sched_run_cleanup();
				}
			}

			if (shutdown_pipe[0] != -1 && FD_ISSET(shutdown_pipe[0], &rfds))
			{
				// Start unmounting all filesystems
				// Looping will stop once all filesystems are unmounted
				ignore_shutdown_signals();
				if (fuse_serve_mount_start_shutdown() < 0)
				{
					fprintf(stderr, "fuse_serve_mount_start_shutdown() failed, exiting fuse_serve_loop()\n");
					return -1;
				}
			}

			if (FD_ISSET(remove_activity, &rfds))
			{
				if (fuse_serve_mount_step_remove() < 0)
				{
					fprintf(stderr, "fuse_serve_mount_step_remove() failed, exiting fuse_serve_loop()\n");
					return -1;
				}
			}


			if (gettimeofday(&it_end, NULL) == -1)
			{
				perror("gettimeofday");
				break;
			}
			tv = time_subtract(tv, time_elapsed(it_start, it_end));
		}

		while(callbacks)
		{
			struct callback_list * first = callbacks;
			callbacks = first->next;
			first->callback(first->data, first->count);
			free(first);
		}
	}

	serving = 0;

	return 0;
}