// 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; }
/** * Init of the pseudo fuse thread @param ch : initial channel @param se : initial session @param rozofs_fuse_buffer_count : number of request buffers (corresponds to the number of fuse save context) @retval 0 on success @retval -1 on error */ int rozofs_fuse_init(struct fuse_chan *ch,struct fuse_session *se,int rozofs_fuse_buffer_count) { int status = 0; int i; // return 0; fuse_sharemem_init_done = 0; int fileflags; rozofs_fuse_ctx_p = malloc(sizeof (rozofs_fuse_ctx_t)); if (rozofs_fuse_ctx_p == NULL) { /* ** cannot allocate memory for fuse rozofs context */ return -1; } memset(rozofs_fuse_ctx_p,0,sizeof (rozofs_fuse_ctx_t)); /* ** clear read/write merge stats table */ memset(rozofs_write_merge_stats_tab,0,sizeof(uint64_t)*RZ_FUSE_WRITE_MAX); memset (rozofs_write_buf_section_table,0,sizeof(uint64_t)*ROZOFS_FUSE_NB_OF_BUSIZE_SECTION_MAX); memset (rozofs_read_buf_section_table,0,sizeof(uint64_t)*ROZOFS_FUSE_NB_OF_BUSIZE_SECTION_MAX); memset(&rozofs_fuse_read_write_stats_buf,0,sizeof(rozofs_fuse_read_write_stats)); /* ** init of the context */ rozofs_fuse_ctx_p->fuseReqPoolRef = NULL; rozofs_fuse_ctx_p->ch = NULL; rozofs_fuse_ctx_p->se = se; rozofs_fuse_ctx_p->bufsize = 0; rozofs_fuse_ctx_p->buf_fuse_req_p = NULL; rozofs_fuse_ctx_p->dir_attr_invalidate = 0; rozofs_fuse_ctx_p->initBufCount = rozofs_fuse_buffer_count; while (1) { /* ** get the receive buffer size for former channel in order to create the request distributor: ** note: by default the fuse buffer is 4K+128K: for RozoFS the payload can reach 512K (x4) */ int bufsize = fuse_chan_bufsize(ch)*4; rozofs_fuse_ctx_p->bufsize = bufsize; /* ** create the distributor fro receiving data from fuse kernel */ status = rozofs_fuse_init_rcv_buffer_pool(ROZOFS_FUSE_RECV_BUF_COUNT,bufsize); if (status < 0) { severe( "rozofs_fuse_init fuse buffer pool creation error(%d,%d)", (int)ROZOFS_FUSE_RECV_BUF_COUNT, (int)bufsize ) ; status = -1; break; } /* ** create the pool */ rozofs_fuse_ctx_p->fuseReqPoolRef = ruc_buf_poolCreate(rozofs_fuse_buffer_count,sizeof(rozofs_fuse_save_ctx_t)); if (rozofs_fuse_ctx_p->fuseReqPoolRef == NULL) { severe( "rozofs_fuse_init buffer pool creation error(%d,%d)", (int)rozofs_fuse_buffer_count, (int)sizeof(rozofs_fuse_save_ctx_t) ) ; status = -1; break; } ruc_buffer_debug_register_pool("fuseCtx", rozofs_fuse_ctx_p->fuseReqPoolRef); /* ** Allocate a head of list for queueing pending lookup requests */ for (i=0; i< ROZOFS_MAX_LKUP_QUEUE ; i++) { ruc_listHdrInit(&rozofs_lookup_queue[i]); } /* ** allocate a buffer for receiving the fuse request */ rozofs_fuse_ctx_p->buf_fuse_req_p = malloc(bufsize); if (rozofs_fuse_ctx_p == NULL) { severe( "rozofs_fuse_init out of memory %d", bufsize ) ; status = -1; break; } /* ** get the fd of the channel */ rozofs_fuse_ctx_p->fd = fuse_chan_fd(ch); /* ** wait the end of the share memroy init prior providing it to fuse */ while (rozofs_shared_mem_init_done == 0) sleep(1); /* ** create a new channel with the specific operation for rozofs (non-blocking) */ rozofs_fuse_ctx_p->ch = fuse_chan_new(&rozofs_fuse_ch_ops,fuse_chan_fd(ch),bufsize,rozofs_fuse_ctx_p); if (rozofs_fuse_ctx_p->ch == NULL) { severe( "rozofs_fuse_init fuse_chan_new error" ) ; status = -1; break; } /* ** remove the association between the initial session and channel */ fuse_session_remove_chan(ch); /* ** OK, now add the new channel */ fuse_session_add_chan(se,rozofs_fuse_ctx_p->ch ); /* ** set the channel in non blocking mode */ if((fileflags=fcntl(rozofs_fuse_ctx_p->fd,F_GETFL,0))==-1) { RUC_WARNING(errno); status = -1; break; } if((fcntl(rozofs_fuse_ctx_p->fd,F_SETFL,fileflags|O_NDELAY))==-1) { RUC_WARNING(errno); status = -1; break; } /* ** send XON to the fuse channel */ { int ret; rozofs_fuse_ctx_p->ioctl_supported = 1; rozofs_fuse_ctx_p->data_xon = 1; while(1) { ret = ioctl(rozofs_fuse_ctx_p->fd,1,NULL); if (ret < 0) { warning("ioctl error %s",strerror(errno)); rozofs_fuse_ctx_p->ioctl_supported = 0; break; } if (rozofs_fuse_ctx_p->dir_attr_invalidate == 0) { ret = ioctl(rozofs_fuse_ctx_p->fd,3,NULL); if (ret < 0) { warning("ioctl error %s",strerror(errno)); // rozofs_fuse_ctx_p->ioctl_supported = 0; rozofs_fuse_ctx_p->dir_attr_invalidate = 1; break; } } break; } } /* ** perform the connection with the socket controller */ /* ** OK, we are almost done, just need to connect with the socket controller */ rozofs_fuse_ctx_p->connectionId = ruc_sockctl_connect(rozofs_fuse_ctx_p->fd, // Reference of the socket "rozofs_fuse", // name of the socket 3, // Priority within the socket controller (void*)rozofs_fuse_ctx_p, // user param for socketcontroller callback &rozofs_fuse_callBack_sock); // Default callbacks if (rozofs_fuse_ctx_p->connectionId == NULL) { /* ** Fail to connect with the socket controller */ RUC_WARNING(-1); status = -1; break; } rozofs_fuse_get_ticker(); status = 0; break; } /* ** attach the callback on socket controller */ //#warning no poller ruc_sockCtrl_attach_applicative_poller(rozofs_fuse_scheduler_entry_point); for(i = 0; i < 3;i++) fuse_profile[i] = 0; uma_dbg_addTopic("fuse", rozofs_fuse_show); return status; }
static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) { int fd = ch ? fuse_chan_fd(ch) : -1; fuse_kern_unmount(mountpoint, fd); fuse_chan_destroy(ch); }