/*---------------------------------------------------------------------------*/ cfs_offset_t cfs_seek(int fd, cfs_offset_t offset, int whence) { struct file_desc *fdp; cfs_offset_t new_offset; if(!FD_VALID(fd)) { return -1; } fdp = &coffee_fd_set[fd]; if(whence == CFS_SEEK_SET) { new_offset = offset; } else if(whence == CFS_SEEK_END) { new_offset = fdp->file->end + offset; } else if(whence == CFS_SEEK_CUR) { new_offset = fdp->offset + offset; } else { return (cfs_offset_t)-1; } if(new_offset < 0 || new_offset > fdp->file->max_pages * COFFEE_PAGE_SIZE) { return -1; } if(fdp->file->end < new_offset) { fdp->file->end = new_offset; } return fdp->offset = new_offset; }
/*---------------------------------------------------------------------------*/ void cfs_close(int fd) { if(FD_VALID(fd)) { coffee_fd_set[fd].flags = COFFEE_FD_FREE; coffee_fd_set[fd].file->references--; coffee_fd_set[fd].file = NULL; } }
void *get_data_by_fd(int fd, int dir) { if ( !FD_VALID(fd) ) { log_message(LOG_INFO, "get_data_by_fd: fd %d out of range.", fd); return NULL; } return epfd_set[fd].data[dir]; }
/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS struct file_header hdr; struct log_param lp; unsigned bytes_left; int r; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } /* If the file is allocated, read directly in the file. */ if(!FILE_MODIFIED(file)) { COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; return size; } #if COFFEE_MICRO_LOGS read_header(&hdr, file->page); /* * Fill the buffer by copying from the log in first hand, or the * ordinary file if the page has no log record. */ for(bytes_left = size; bytes_left > 0; bytes_left -= r) { r = -1; lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { COFFEE_READ(buf, lp.size, absolute_offset(file->page, fdp->offset)); r = lp.size; } fdp->offset += r; buf = (char *)buf + r; } #endif /* COFFEE_MICRO_LOGS */ return size; }
/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS struct file_header hdr; struct log_param lp; unsigned bytes_left; int r; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } /* If the file is not modified, read directly from the file extent. */ if(!FILE_MODIFIED(file)) { COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; return size; } #if COFFEE_MICRO_LOGS read_header(&hdr, file->page); /* * Copy the contents of the most recent log record. If there is * no log record for the file area to read from, we simply read * from the original file extent. */ for(bytes_left = size; bytes_left > 0; bytes_left -= r) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { COFFEE_READ(buf, lp.size, absolute_offset(file->page, fdp->offset)); r = lp.size; } fdp->offset += r; buf = (char *)buf + r; } #endif /* COFFEE_MICRO_LOGS */ return size; }
int cfs_coffee_set_io_semantics(int fd, unsigned flags) { if(!FD_VALID(fd)) { return -1; } coffee_fd_set[fd].io_flags |= flags; return 0; }
/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_header hdr; struct file_desc *fdp; struct file *file; unsigned bytes_left; int r; #if COFFEE_MICRO_LOGS struct log_param lp; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } bytes_left = size; if(FILE_MODIFIED(file)) { read_header(&hdr, file->page); } /* * Fill the buffer by copying from the log in first hand, or the * ordinary file if the page has no log record. */ while(bytes_left) { watchdog_periodic(); r = -1; #if COFFEE_MICRO_LOGS if(FILE_MODIFIED(file)) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); } #endif /* COFFEE_MICRO_LOGS */ /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { r = bytes_left; COFFEE_READ(buf, r, absolute_offset(file->page, fdp->offset)); } bytes_left -= r; fdp->offset += r; buf += r; } return size; }
/* if fd is in epoll fdset, return 1, else return 0 */ int epoll_fdisset(int fd, int dir) { if ( !FD_VALID(fd) ) { log_message(LOG_INFO, "epoll_fdisset: fd %d out of range.", fd); return 0; } if (((dir == DIR_RD) && ((epfd_set[fd].events & EPOLLIN) == EPOLLIN)) || ((dir == DIR_WR) && ((epfd_set[fd].events & EPOLLOUT) == EPOLLOUT))) return 1; return 0; }
/** * Doesn't support timeout other than 0 or infinite (negative) timeout */ int rte_netmap_poll(struct pollfd *fds, nfds_t nfds, int timeout) { int32_t count_it, ret; uint32_t i, idx, port; uint32_t want_rx, want_tx; if (timeout > 0) return -1; ret = 0; do { for (i = 0; i < nfds; i++) { count_it = 0; if (!FD_VALID(fds[i].fd) || fds[i].events == 0) { fds[i].revents = 0; continue; } idx = FD_TO_IDX(fds[i].fd); if ((port = fd_port[idx].port) >= RTE_DIM(ports) || ports[port].fd != idx) { fds[i].revents |= POLLERR; ret++; continue; } want_rx = fds[i].events & (POLLIN | POLLRDNORM); want_tx = fds[i].events & (POLLOUT | POLLWRNORM); if (want_rx && rx_sync_if(port) > 0) { fds[i].revents = (uint16_t) (fds[i].revents | want_rx); count_it = 1; } if (want_tx && tx_sync_if(port) > 0) { fds[i].revents = (uint16_t) (fds[i].revents | want_tx); count_it = 1; } ret += count_it; } } while ((ret == 0 && timeout < 0) || timeout); return ret; }
void * rte_netmap_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { static const int cprot = PROT_WRITE | PROT_READ; if (!FD_VALID(fd) || length + offset > netmap.mem_sz || (prot & cprot) != cprot || ((flags & MAP_FIXED) != 0 && addr != NULL)) { errno = EINVAL; return (MAP_FAILED); } return ((void *)((uintptr_t)netmap.mem + offset)); }
static int32_t fd_release(int32_t fd) { uint32_t idx, port; idx = FD_TO_IDX(fd); if (!FD_VALID(fd) || (port = fd_port[idx].port) == FD_PORT_FREE) return (-EINVAL); /* if we still have a valid port attached, release the port */ if (port < RTE_DIM(ports) && ports[port].fd == idx) { netmap_unregif(idx, port); } fd_port[idx].port = FD_PORT_FREE; return (0); }
int rte_netmap_ioctl(int fd, int op, void *param) { int ret; if (!FD_VALID(fd)) { errno = EBADF; return (-1); } switch (op) { case NIOCGINFO: ret = ioctl_niocginfo(fd, param); break; case NIOCREGIF: ret = ioctl_niocregif(fd, param); break; case NIOCUNREGIF: ret = ioctl_niocunregif(fd); break; case NIOCRXSYNC: ret = ioctl_niocrxsync(fd); break; case NIOCTXSYNC: ret = ioctl_nioctxsync(fd); break; default: ret = -ENOTTY; } if (ret < 0) { errno = -ret; ret = -1; } else { ret = 0; } return (ret); }
/* epoll clear fd */ int epoll_clear_fd(int epfd, int dir, int fd) { int opcode; struct epoll_event ev; if ( !FD_VALID(fd) ) { log_message(LOG_INFO, "epoll_clear_fd: fd %d out of range.", fd); return -1; } if (epfd_set[fd].events == 0) { log_message(LOG_INFO, "epoll_clear_fd: fd %d is not in fdset.", fd); return -1; } if (dir == DIR_RD) epfd_set[fd].events &= ~EPOLLIN; else if (dir == DIR_WR) epfd_set[fd].events &= ~EPOLLOUT; /* clear default ERR/HUP events */ // epfd_set[fd].events &= ~(EPOLLERR | EPOLLHUP); if (epfd_set[fd].events == 0) { opcode = EPOLL_CTL_DEL; epfd_set[fd].data[dir] = NULL; } else { opcode = EPOLL_CTL_MOD; } ev.events = epfd_set[fd].events; ev.data.fd = fd; if (epoll_ctl(epfd, opcode, fd, &ev) != 0) { log_message(LOG_INFO, "epoll_clear_fd: %s fd %d failure.", (opcode == EPOLL_CTL_DEL) ? "DEL":"MOD", fd); return -1; } return 0; }
/* epoll set fd */ int epoll_set_fd(int epfd, int dir, int fd, void *data) { int opcode; struct epoll_event ev; if ( !FD_VALID(fd) ) { log_message(LOG_INFO, "epoll_set_fd: fd %d out of range.", fd); return -1; } memset(&ev, 0, sizeof(struct epoll_event)); ev.data.fd = fd; if (dir == DIR_RD) ev.events |= EPOLLIN; else if (dir == DIR_WR) ev.events |= EPOLLOUT; if (epfd_set[fd].events == 0) { opcode = EPOLL_CTL_ADD; } else if( epfd_set[fd].events != ev.events) { opcode = EPOLL_CTL_MOD; } else { /* already exists */ epfd_set[fd].data[dir] = data; return 0; } if (epoll_ctl(epfd, opcode, fd, &ev) != 0) { log_message(LOG_INFO, "epoll_set_fd: %s fd %d failure.", (opcode == EPOLL_CTL_ADD) ? "ADD":"MOD", fd); return -1; } epfd_set[fd].events = ev.events; epfd_set[fd].data[dir] = data; return 0; }
/*---------------------------------------------------------------------------*/ cfs_offset_t cfs_seek(int fd, cfs_offset_t offset, int whence) { struct file_desc *fdp; cfs_offset_t new_offset; if(!FD_VALID(fd)) { return -1; } fdp = &coffee_fd_set[fd]; if(whence == CFS_SEEK_SET) { new_offset = offset; } else if(whence == CFS_SEEK_END) { new_offset = fdp->file->end + offset; } else if(whence == CFS_SEEK_CUR) { new_offset = fdp->offset + offset; } else { return (cfs_offset_t)-1; } if(new_offset < 0 || new_offset > fdp->file->max_pages * COFFEE_PAGE_SIZE) { return -1; } if(fdp->file->end < new_offset) { if(FD_WRITABLE(fd)) { fdp->file->end = new_offset; } else { /* Disallow seeking past the end of the file for read only FDs */ return (cfs_offset_t)-1; } } return fdp->offset = new_offset; }
/*---------------------------------------------------------------------------*/ int cfs_write(int fd, const void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS int i; struct log_param lp; cfs_offset_t bytes_left; const char dummy[1] = { 0xff }; #endif if(!(FD_VALID(fd) && FD_WRITABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; /* Attempt to extend the file if we try to write past the end. */ #if COFFEE_IO_SEMANTICS if(!(fdp->io_flags & CFS_COFFEE_IO_FIRM_SIZE)) { #endif while(size + fdp->offset + sizeof(struct file_header) > (file->max_pages * COFFEE_PAGE_SIZE)) { if(merge_log(file->page, 1) < 0) { return -1; } file = fdp->file; PRINTF(("Extended the file at page %u\n", (unsigned)file->page)); } #if COFFEE_IO_SEMANTICS } #endif #if COFFEE_MICRO_LOGS #if COFFEE_IO_SEMANTICS if(!(fdp->io_flags & CFS_COFFEE_IO_FLASH_AWARE) && (FILE_MODIFIED(file) || fdp->offset < file->end)) { #else if(FILE_MODIFIED(file) || fdp->offset < file->end) { #endif for(bytes_left = size; bytes_left > 0;) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; i = write_log_page(file, &lp); if(i < 0) { /* Return -1 if we wrote nothing because the log write failed. */ if(size == bytes_left) { return -1; } break; } else if(i == 0) { /* The file was merged with the log. */ file = fdp->file; } else { /* A log record was written. */ bytes_left -= i; fdp->offset += i; buf = (char *)buf + i; /* Update the file end for a potential log merge that might occur while writing log records. */ if(fdp->offset > file->end) { file->end = fdp->offset; } } } if(fdp->offset > file->end) { /* Update the original file's end with a dummy write. */ COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset)); } } else { #endif /* COFFEE_MICRO_LOGS */ #if COFFEE_APPEND_ONLY if(fdp->offset < file->end) { return -1; } #endif /* COFFEE_APPEND_ONLY */ COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; #if COFFEE_MICRO_LOGS } #endif /* COFFEE_MICRO_LOGS */ if(fdp->offset > file->end) { file->end = fdp->offset; } return size; } /*---------------------------------------------------------------------------*/ int cfs_opendir(struct cfs_dir *dir, const char *name) { /* * Coffee is only guaranteed to support "/" and ".", but it does not * currently enforce this. */ memset(dir->dummy_space, 0, sizeof(coffee_page_t)); return 0; }
/*---------------------------------------------------------------------------*/ int cfs_write(int fd, const void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS int i; struct log_param lp; cfs_offset_t bytes_left; const char dummy[1] = { 0xff }; #endif if(!(FD_VALID(fd) && FD_WRITABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; /* Attempt to extend the file if we try to write past the end. */ while(size + fdp->offset + sizeof(struct file_header) > (file->max_pages * COFFEE_PAGE_SIZE)) { if(merge_log(file->page, 1) < 0) { return -1; } file = fdp->file; PRINTF("Extended the file at page %u\n", (unsigned)file->page); } #if COFFEE_MICRO_LOGS if(FILE_MODIFIED(file) || fdp->offset < file->end) { bytes_left = size; while(bytes_left) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; i = write_log_page(file, &lp); if(i < 0) { /* Return -1 if we wrote nothing because the log write failed. */ if(size == bytes_left) { return -1; } break; } else if(i == 0) { /* The file was merged with the log. */ file = fdp->file; } else { /* A log record was written. */ bytes_left -= i; fdp->offset += i; buf += i; } } if(fdp->offset > file->end) { /* Update the original file's end with a dummy write. */ COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset)); } } else { #endif /* COFFEE_MICRO_LOGS */ #if COFFEE_APPEND_ONLY if(fdp->offset < file->end) { return -1; } #endif /* COFFEE_APPEND_ONLY */ COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; #if COFFEE_MICRO_LOGS } #endif /* COFFEE_MICRO_LOGS */ if(fdp->offset > file->end) { file->end = fdp->offset; } return size; }