static int tap_configure(struct mic_info *mic, char *dev) { pid_t pid; char *ifargv[7]; int ret = 0; pid = fork(); if (pid == 0) { ifargv[0] = "ip"; ifargv[1] = "link"; ifargv[2] = "set"; ifargv[3] = dev; ifargv[4] = "up"; ifargv[5] = NULL; ret = execvp("ip", ifargv); if (ret < 0) return ret; } if (pid < 0) { mpsslog(PERROR, "%s fork failed errno %s\n", mic->name, strerror(errno)); return ret; } ret = waitpid(pid, NULL, 0); if (ret < 0) { mpsslog(PERROR, "%s waitpid failed errno %s\n", mic->name, strerror(errno)); return ret; } mpsslog(PINFO, "MIC name %s %s %d DONE!\n", mic->name, __func__, __LINE__); return 0; }
static void wait_for_card_driver(struct mic_info *mic, int fd, int type) { struct pollfd pollfd; int err; struct mic_device_desc *desc = get_device_desc(mic, type); pollfd.fd = fd; mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n", mic->name, __func__, type, desc->status); while (1) { pollfd.events = POLLIN; pollfd.revents = 0; err = poll(&pollfd, 1, -1); if (err < 0) { mpsslog("%s %s poll failed %s\n", mic->name, __func__, strerror(errno)); continue; } if (pollfd.revents) { mpsslog("%s %s Waiting... desc-> type %d status 0x%x\n", mic->name, __func__, type, desc->status); if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { mpsslog("%s %s poll.revents %d\n", mic->name, __func__, pollfd.revents); mpsslog("%s %s desc-> type %d status 0x%x\n", mic->name, __func__, type, desc->status); break; } } } }
void save_oops(struct mic_info *mic) { struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; char buffer[4096]; char oopsname[PATH_MAX]; int headerdone = 0; int rlen; int fd; if (strcmp(mpssdi->state, "resetting")) return; snprintf(oopsname, sizeof(oopsname), "/proc/mic_ramoops/%s_prev", mic->name); if ((fd = open(oopsname, O_RDONLY)) < 0) { mpsslog(PINFO, "%s: open oopsname %s failed %s\n", mic->name, oopsname, strerror(errno)); return; } while ((rlen = read(fd, buffer, 4096))) { if (!headerdone) { mpsslog(PINFO, "%s: Resetting MIC found oops:\n", mic->name); headerdone = 1; } mpsslog_dump(buffer, rlen); } close(fd); }
static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type) { struct mic_device_desc *d; int i; void *dp = get_dp(mic, type); for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE; i += mic_total_desc_size(d)) { d = dp + i; /* End of list */ if (d->type == 0) break; if (d->type == -1) continue; mpsslog("%s %s d-> type %d d %p\n", mic->name, __func__, d->type, d); if (d->type == (__u8)type) return d; } mpsslog("%s %s %d not found\n", mic->name, __func__, type); assert(0); return NULL; }
int autoreboot(struct mic_info *mic) { char value[4096]; int fd, len, ret; char pathname[PATH_MAX] = "/sys/devices/virtual/mic/scif/watchdog_auto_reboot"; if ((fd = open(pathname, O_RDONLY)) < 0) { mpsslog(PINFO, "%s: Failed to open %s %s\n", mic->name, pathname, strerror(errno)); return 0; } if ((len = read(fd, value, sizeof(value) - 1)) < 0) { mpsslog(PINFO, "%s: Failed to read %s: %s\n", mic->name, pathname, strerror(errno)); ret = 0; goto readsys_ret; } value[len] = '\0'; ret = atoi(value); mpsslog(PINFO, "%s: autoreboot %d\n", mic->name, ret); readsys_ret: close(fd); return ret; }
void set_log_buf_info(struct mic_info *mic) { int fd; int err; off_t len; char *map; char *temp; char log_addr[17] = {'\0'}; char log_size[17] = {'\0'}; if (mic->config.boot.systemmap == NULL) { mpsslog(PINFO, "%s: System map not correctly configured in OSimage parameter\n", mic->name); return; } if ((fd = open(mic->config.boot.systemmap, O_RDONLY)) < 0) { mpsslog(PINFO, "%s: Opening System.map failed: %s\n", mic->name, strerror(errno)); return; } if ((len = lseek(fd, 0, SEEK_END)) < 0) { mpsslog(PINFO, "%s: Reading System.map size failed: %s\n", mic->name, strerror(errno)); goto close_return; } if ((map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { mpsslog(PINFO, "%s: mmap of System.map failed: %s\n", mic->name, strerror(errno)); goto close_return; } if (!(temp = strstr(map, "__log_buf"))) { mpsslog(PINFO, "%s: __log_buf not found: %s\n", mic->name, strerror(errno)); goto unmap_return; } strncpy(log_addr, temp - 19, 16); if ((err = mpss_setsysfs(mic->name, "log_buf_addr", log_addr)) != 0) { mpsslog(PINFO, "%s: failed set log_buf_addr sysfs: %s\n", mic->name, strerror(err)); goto unmap_return; } if (!(temp = strstr(map, "log_buf_len"))) { mpsslog(PINFO, "%s: log_buf_len not found: %s\n", mic->name, strerror(errno)); goto unmap_return; } strncpy(log_size, temp - 19, 16); if ((err = mpss_setsysfs(mic->name, "log_buf_len", log_size)) != 0) { mpsslog(PINFO, "%s: failed set log_buf_len sysfs: %s\n", mic->name, strerror(err)); goto unmap_return; } mpsslog(PINFO, "%s: Debug log buffer addr %s len @ %s\n", mic->name, log_addr, log_size); unmap_return: munmap(map, len); close_return: close(fd); }
void segv_handler(int sig, siginfo_t *siginfo, void *context) { struct mic_info *mic; struct mpssd_info *mpssdi; void *addrs[100]; char **funcs; void *joinval; int cnt; int i; cnt = backtrace(addrs, 100); funcs = backtrace_symbols(addrs, cnt); for (mic = miclist; mic != NULL; mic = mic->next) { mpssdi = (struct mpssd_info *)mic->data; if (mpssdi->boot_pth && (mpssdi->boot_pth != pthread_self())) { pthread_cancel(mpssdi->boot_pth); pthread_join(mpssdi->boot_pth, &joinval); } if (mpssdi->monitor_pth && (mpssdi->monitor_pth != pthread_self())) { pthread_cancel(mpssdi->monitor_pth); pthread_join(mpssdi->monitor_pth, &joinval); } if (mpssdi->state_pth && (mpssdi->state_pth != pthread_self())) { pthread_cancel(mpssdi->state_pth); pthread_join(mpssdi->state_pth, &joinval); } if (mpssdi->crash_pth && (mpssdi->crash_pth != pthread_self())) { pthread_cancel(mpssdi->crash_pth); pthread_join(mpssdi->crash_pth, &joinval); } if (mpssdi->stop_pth && (mpssdi->stop_pth != pthread_self())) { pthread_cancel(mpssdi->stop_pth); pthread_join(mpssdi->stop_pth, &joinval); } } mpsslog(PNORM, "<<<<<<<< mpssd: segmentation violation - dumping stack >>>>>>>>\n"); for (i = 0; i < cnt; i++) { mpsslog(PNORM, "%s\n", funcs[i]); } mpsslog(PNORM, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); exit(0); }
/* * This initialization routine requires at least one * vring i.e. vr0. vr1 is optional. */ static void * init_vr(struct mic_info *mic, int fd, int type, struct mic_vring *vr0, struct mic_vring *vr1, int num_vq) { int vr_size; char *va; vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN) + sizeof(struct _mic_vring_info)); va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq, PROT_READ, MAP_SHARED, fd, 0); if (MAP_FAILED == va) { mpsslog("%s %s %d mmap failed errno %s\n", mic->name, __func__, __LINE__, strerror(errno)); goto done; } set_dp(mic, type, va); vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END]; vr0->info = vr0->va + _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN); vring_init(&vr0->vr, MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN); mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ", __func__, mic->name, vr0->va, vr0->info, vr_size, _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN)); mpsslog("magic 0x%x expected 0x%x\n", le32toh(vr0->info->magic), MIC_MAGIC + type); assert(le32toh(vr0->info->magic) == MIC_MAGIC + type); if (vr1) { vr1->va = (struct mic_vring *) &va[MIC_DEVICE_PAGE_END + vr_size]; vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN); vring_init(&vr1->vr, MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN); mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ", __func__, mic->name, vr1->va, vr1->info, vr_size, _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN)); mpsslog("magic 0x%x expected 0x%x\n", le32toh(vr1->info->magic), MIC_MAGIC + type + 1); assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1); } done: return va; }
void start_daemon(void) { struct mic_info *mic; struct mpssd_info *mpssdi; int err; int sc; if ((err = mpssenv_aquire_lockfile(&mpssenv))) { fprintf(stderr, "Error aquiring lockfile %s: %s\n", mpssenv.lockfile, strerror(err)); exit(1); } pthread_create(&mon_pth, NULL, mic_monitor, NULL); pthread_create(&cred_pth, NULL, mic_credentials, NULL); while (pthread_mutex_lock(&start_lock) != 0); for (mic = miclist; mic != NULL; mic = mic->next) { if ((mic->data = malloc(sizeof(struct mpssd_info))) == NULL) { fprintf(stderr, "Catastrophic memory allocation error: %s\n", strerror(err)); exit(1); } memset(mic->data, 0, sizeof(struct mpssd_info)); mpssdi = (struct mpssd_info *)mic->data; if ((mpssdi->state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PERROR, "%s: Ignoring - Critical failure reading state sysfs entry\n", mic->name); continue; } pthread_mutex_init(&mpssdi->pth_lock, NULL); pthread_mutex_init(&mpssdi->reset_lock, NULL); pthread_cond_init(&mpssdi->reset_cond, NULL); start_count++; while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); if (is_upstream_driver()) pthread_create(&mpssdi->state_pth, NULL, init_mic, mic); else pthread_create(&mpssdi->state_pth, NULL, mic_state, mic); pthread_create(&mpssdi->boot_pth, NULL, boot_mic, mic); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); } while (pthread_mutex_unlock(&start_lock) != 0); sc = start_count; while (sc) { while (pthread_mutex_lock(&start_lock) != 0); sc = start_count; while (pthread_mutex_unlock(&start_lock) != 0); sleep(1); } if (start_pid) kill(start_pid, SIGHUP); while (pause()); }
void quit_handler(int sig, siginfo_t *siginfo, void *context) { struct mic_info *mic; struct mpssd_info *mpssdi; struct mpss_elist mpssperr; char *state; shutdown_count = 0; while (pthread_mutex_lock(&shutdown_lock) != 0); mpsslog(PINFO, "MPSS Stack Shutting down\n"); for (mic = miclist; mic != NULL; mic = mic->next) { mpssdi = (struct mpssd_info *)mic->data; if (mic->present == FALSE) { mpsslog(PWARN, "%s: Configured but not present - skipping\n", mic->name); continue; } if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PERROR, "%s: Failed to read state - not waiting for card ready\n", mic->name); while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); pthread_create(&mpssdi->stop_pth, NULL, shutdown_mic, mic); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); continue; } mpss_parse_config(&mpssenv, mic, &brlist, &mpssperr); mpss_clear_elist(&mpssperr); if (strcmp(state, "ready") && strcmp(state, "resetting")) { shutdown_count++; while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); pthread_create(&mpssdi->stop_pth, NULL, shutdown_mic, mic); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); } free(state); } while (pthread_mutex_unlock(&shutdown_lock) != 0); if (shutdown_count == 0) exit(0); else pause(); }
static int tun_alloc(struct mic_info *mic, char *dev) { struct ifreq ifr; int fd, err; #if GSO_ENABLED unsigned offload; #endif fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { mpsslog("Could not open /dev/net/tun %s\n", strerror(errno)); goto done; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; if (*dev) strncpy(ifr.ifr_name, dev, IFNAMSIZ); err = ioctl(fd, TUNSETIFF, (void *)&ifr); if (err < 0) { mpsslog("%s %s %d TUNSETIFF failed %s\n", mic->name, __func__, __LINE__, strerror(errno)); close(fd); return err; } #if GSO_ENABLED offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN | TUN_F_UFO; err = ioctl(fd, TUNSETOFFLOAD, offload); if (err < 0) { mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n", mic->name, __func__, __LINE__, strerror(errno)); close(fd); return err; } #endif strcpy(dev, ifr.ifr_name); mpsslog("Created TAP %s\n", dev); done: return fd; }
static inline void verify_out_len(struct mic_info *mic, struct mic_copy_desc *copy) { if (copy->out_len != sum_iovec_len(copy)) { mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n", mic->name, __func__, __LINE__, copy->out_len, sum_iovec_len(copy)); assert(copy->out_len == sum_iovec_len(copy)); } }
ssize_t get_dir_size(struct mic_info *mic, char *dirpath) { struct dirent *tmp; DIR *dir; char path[PATH_MAX]; struct stat data; size_t result = 0; if ((dir = opendir(dirpath)) == NULL) { mpsslog(PINFO, "%s: Could not open dir %s\n", mic->name, dirpath); return -1; } while ((tmp = readdir(dir))) { if (!strcmp(tmp->d_name, ".") || !strcmp(tmp->d_name, "..")) continue; snprintf(path, PATH_MAX - 1, "%s/%s", dirpath, tmp->d_name); if (lstat(path, &data) < 0) { mpsslog(PINFO, "%s: Couldn't lstat %s: %s\n", mic->name, path, strerror(errno)); continue; } if (S_ISDIR(data.st_mode) && !S_ISLNK(data.st_mode)) { ssize_t dirsize; strcat(path, "/"); if ((dirsize = get_dir_size(mic, path)) < 0) { mpsslog(PINFO, "%s: getting directory size failed %s %s\n", mic->name, path, strerror(errno)); return dirsize; } result += dirsize; } else if (S_ISREG(data.st_mode)) { result += data.st_size; } } closedir(dir); return result; }
/* Display an iovec */ static void disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy, const char *s, int line) { int i; for (i = 0; i < copy->iovcnt; i++) mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n", mic->name, s, line, i, copy->iov[i].iov_base, copy->iov[i].iov_len); }
int main(int argc, char *argv[]) { pid_t pid; mpssenv_init(&mpssenv); parse_cmd_args(argc, argv); setsighandlers(); if (logfp != stderr) { if ((logfp = fopen(LOGFILE_NAME, "a+")) == NULL) { fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME); exit(EBADF); } } mpsslog(PINFO, "MPSS Daemon start\n"); if ((miclist = mpss_get_miclist(&mpssenv, NULL)) == NULL) { mpsslog(PINFO, "MIC module not loaded\n"); exit(2); } if (logfp == stderr) { start_daemon(); } else { start_pid = getpid(); switch ((pid = fork())) { case -1: fprintf(stderr, "cannot fork: %s\n", strerror(errno)); exit(ENOEXEC); case 0: start_daemon(); default: pause(); } } exit(0); }
char * readsysfs(char *dir, char *entry) { char filename[PATH_MAX]; char value[PAGE_SIZE]; char *string = NULL; int fd; int len; if (dir == NULL) snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry); else snprintf(filename, PATH_MAX, "%s/%s/%s", MICSYSFSDIR, dir, entry); fd = open(filename, O_RDONLY); if (fd < 0) { mpsslog("Failed to open sysfs entry '%s': %s\n", filename, strerror(errno)); return NULL; } len = read(fd, value, sizeof(value)); if (len < 0) { mpsslog("Failed to read sysfs entry '%s': %s\n", filename, strerror(errno)); goto readsys_ret; } if (len == 0) goto readsys_ret; value[len - 1] = '\0'; string = malloc(strlen(value) + 1); if (string) strcpy(string, value); readsys_ret: close(fd); return string; }
/* Spin till we have some descriptors */ static void spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr) { __u16 avail_idx = read_avail_idx(vr); while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) { #ifdef DEBUG mpsslog("%s %s waiting for desc avail %d info_avail %d\n", mic->name, __func__, le16toh(vr->vr.avail->idx), vr->info->avail_idx); #endif sched_yield(); } }
/* Central API which triggers the copies */ static int mic_virtio_copy(struct mic_info *mic, int fd, struct mic_vring *vr, struct mic_copy_desc *copy) { int ret; ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy); if (ret) { mpsslog("%s %s %d errno %s ret %d\n", mic->name, __func__, __LINE__, strerror(errno), ret); } return ret; }
static void *get_dp(struct mic_info *mic, int type) { switch (type) { case VIRTIO_ID_CONSOLE: return mic->mic_console.console_dp; case VIRTIO_ID_NET: return mic->mic_net.net_dp; case VIRTIO_ID_BLOCK: return mic->mic_virtblk.block_dp; } mpsslog("%s %s %d not found\n", mic->name, __func__, type); assert(0); return NULL; }
int setsysfs(char *dir, char *entry, char *value) { char filename[PATH_MAX]; char *oldvalue; int fd, ret = 0; if (dir == NULL) snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry); else snprintf(filename, PATH_MAX, "%s/%s/%s", MICSYSFSDIR, dir, entry); oldvalue = readsysfs(dir, entry); fd = open(filename, O_RDWR); if (fd < 0) { ret = errno; mpsslog("Failed to open sysfs entry '%s': %s\n", filename, strerror(errno)); goto done; } if (!oldvalue || strcmp(value, oldvalue)) { if (write(fd, value, strlen(value)) < 0) { ret = errno; mpsslog("Failed to write new sysfs entry '%s': %s\n", filename, strerror(errno)); } } close(fd); done: if (oldvalue) free(oldvalue); return ret; }
static void set_dp(struct mic_info *mic, int type, void *dp) { struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; switch (type) { case VIRTIO_ID_CONSOLE: mpssdi->mic_console.console_dp = dp; return; case VIRTIO_ID_NET: mpssdi->mic_net.net_dp = dp; return; case VIRTIO_ID_BLOCK: mpssdi->mic_virtblk.block_dp = dp; return; } mpsslog(PERROR, "%s %s %d not found\n", mic->name, __func__, type); assert(0); }
int check_fs_params(struct mic_info *mic) { struct stat sbuf; if ((mic->config.filesrc.base.type == SRCTYPE_CPIO) && stat(mic->config.filesrc.base.image, &sbuf) != 0) { mpsslog(PINFO, "%s: Boot aborted - Base image '%s' not found\n", mic->name, mic->config.filesrc.base.image); return 1; } if ((mic->config.filesrc.base.type == SRCTYPE_DIR) && stat(mic->config.filesrc.base.dir, &sbuf) != 0) { mpsslog(PINFO, "%s: Boot aborted - Base directory '%s' not found\n", mic->name, mic->config.filesrc.base.image); return 1; } if (mic->config.filesrc.common.dir == NULL) { mpsslog(PINFO, "%s: Boot aborted - CommonDir not configured\n", mic->name); return 1; } if (stat(mic->config.filesrc.common.dir, &sbuf) != 0) { mpsslog(PINFO, "%s: Boot aborted - CommonDir '%s' not found\n", mic->name, mic->config.filesrc.common.dir); return 1; } if (mic->config.filesrc.mic.dir == NULL) { mpsslog(PINFO, "%s: Boot aborted - MicDir not configured\n", mic->name); return 1; } if (stat(mic->config.filesrc.mic.dir, &sbuf) != 0) { mpsslog(PINFO, "%s: Boot aborted - MicDir '%s' not found\n", mic->name, mic->config.filesrc.mic.dir); return 1; } return 0; }
void * monitor(void *arg) { struct mic_info *mic = (struct mic_info *)arg; struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; unsigned int proto; unsigned int jobid; struct pollfd pfds[1]; struct jobs *jlist; struct jobs *job = NULL; uint16_t stopID; while (1) { pfds[0].fd = mpssdi->recv_ep; pfds[0].events = POLLIN | POLLERR | POLLPRI; poll(pfds, 1, -1); if (scif_recv(mpssdi->recv_ep, &proto, sizeof(proto), SCIF_RECV_BLOCK) < 0) { if (errno == ECONNRESET) { mpsslog(PERROR, "%s: MIC card mpssd daemon disconnect: %s\n", mic->name,strerror(errno)); scif_close(mpssdi->recv_ep); scif_close(mpssdi->send_ep); mpssdi->recv_ep = -1; mpssdi->send_ep = -1; pthread_exit((void *)1); } continue; } switch (proto) { case REQ_CREDENTIAL_ACK: case REQ_CREDENTIAL_NACK: scif_recv(mpssdi->recv_ep, &jobid, sizeof(jobid), SCIF_RECV_BLOCK); while (pthread_mutex_lock(&jobs_lock) != 0); jlist = &gjobs; while (jlist->next) { if (jlist->next->jobid == jobid) { job = jlist->next; if (--job->cnt == 0) { jlist->next = job->next; while (pthread_mutex_unlock(&jobs_lock) != 0); proto = CRED_SUCCESS; scif_send(job->dep, &proto, sizeof(proto), 0); scif_close(job->dep); continue; } break; } jlist = jlist->next; } while (pthread_mutex_unlock(&jobs_lock) != 0); break; case MONITOR_STOPPING: scif_recv(mpssdi->recv_ep, &stopID, sizeof(stopID), SCIF_RECV_BLOCK); mpsslog(PERROR, "%s: card mpssd daemon exiting\n", mic->name); scif_close(mpssdi->recv_ep); scif_close(mpssdi->send_ep); mpssdi->recv_ep = -1; mpssdi->send_ep = -1; pthread_exit((void *)0); } } }
void * mic_monitor(void *arg) { struct mic_info *mic; struct mpssd_info *mpssdi; pthread_attr_t attr; struct scif_portID sendID = {0, MPSSD_MONSEND}; struct scif_portID recvID; scif_epd_t lep; scif_epd_t recv_ep; scif_epd_t send_ep; unsigned int proto; uint16_t send_port; uint16_t remote_port = 0; int err; if ((lep = scif_open()) < 0) { mpsslog(PINFO, "Cannot open mpssd monitor SCIF listen port: %s\n", strerror(errno)); pthread_exit((void *)1); } if (scif_bind(lep, MPSSD_MONRECV) < 0) { mpsslog(PINFO, "Cannot bind to mpssd monitor SCIF PORT: %s\n", strerror(errno)); pthread_exit((void *)1); } if (scif_listen(lep, 16) < 0) { mpsslog(PINFO, "Set Listen on mpssd monitor SCIF PORT fail: %s\n", strerror(errno)); pthread_exit((void *)1); } while (1) { if (scif_accept(lep, &recvID, &recv_ep, SCIF_ACCEPT_SYNC)) { if (errno != EINTR) mpsslog(PINFO, "Wait for card connect failed: %s\n", strerror(errno)); sleep(1); continue; } if ((mic = mpss_find_micid_inlist(miclist, recvID.node - 1)) == NULL) { mpsslog(PINFO, "Cannot configure - node %d does not seem to exist\n", recvID.node - 1); scif_close(recv_ep); continue; } mpssdi = (struct mpssd_info *)mic->data; if ((send_ep = scif_open()) < 0) { fprintf(logfp, "Failed to open SCIF: %s\n", strerror(errno)); scif_close(recv_ep); pthread_exit((void *)1); } mpssdi->send_ep = send_ep; if ((err = scif_recv(recv_ep, &proto, sizeof(proto), SCIF_RECV_BLOCK)) != sizeof(proto)) { mpsslog(PINFO, "%s: MIC card mpssd daemon startup connection error %s\n", mic->name, strerror(errno)); scif_close(recv_ep); mpssdi->recv_ep = -1; continue; } switch (proto) { case MONITOR_START: sendID.node = mic->id + 1; while ((send_port = scif_connect(send_ep, &sendID)) < 0) { fprintf(logfp, "Failed to connect to monitor thread on card: %s\n", strerror(errno)); sleep(1); } // Over reliable connection, mpssd tells us which port number it uses // to talk back to us. If this port matches actual recv_ep remote port // then we know that recv_ep and send_ep reference the same client. // We also know that send_ep, references mpssd on mic, as port we // connect to on that endpoint requires privliges to listen on. if (scif_recv(send_ep, &remote_port, sizeof(remote_port), SCIF_RECV_BLOCK) < 0) { mpsslog(PINFO, "%s: MIC card mpssd daemon handshake error %s\n", mic->name, strerror(errno)); scif_close(send_ep); scif_close(recv_ep); continue; // go back to next iteration of while(1), we cannot break the while loop because hosts mpssd can connect with multiple mic cards } if (remote_port != recvID.port || sendID.node != recvID.node) { mpsslog(PINFO, "%s: Failed to authenticate connection with mic mpssd\n", mic->name); scif_close(send_ep); scif_close(recv_ep); continue; // go back to next iteration of while(1), we cannot break the while loop because hosts mpssd can connect with multiple mic cards } // Similarily, provide info for the client, so that he can also verify // that both connections send_ep & recv_ep belong to us. if (scif_send(recv_ep, &send_port, sizeof(send_port), SCIF_SEND_BLOCK) < 0) { mpsslog(PINFO, "%s: MIC card mpssd daemon handshake error %s\n", mic->name, strerror(errno)); scif_close(send_ep); scif_close(recv_ep); continue; // go back to next iteration of while(1), we cannot break the while loop because hosts mpssd can connect with multiple mic cards } mpssdi->recv_ep = recv_ep; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&mpssdi->monitor_pth, &attr, monitor, mic); proto = MONITOR_START_ACK; scif_send(send_ep, &proto, sizeof(proto), SCIF_RECV_BLOCK); mpsslog(PINFO, "%s: Monitor connection established\n", mic->name); break; } } }
int get_cookie(struct passwd *pass, char *cookie) { char cookiename[PATH_MAX]; struct stat sbuf; int createcookie = TRUE; int len; int fd; int err = -1; snprintf(cookiename, PATH_MAX, "%s/.mpsscookie", pass->pw_dir); if (setegid(pass->pw_gid) < 0) { mpsslog(PERROR, "%s Cannot create: Failed to setegid to gid %d : %s\n", cookiename, pass->pw_gid, strerror(errno)); return -1; } if (seteuid(pass->pw_uid) < 0) { mpsslog(PERROR, "%s Cannot create: Failed to seteuid to uid %d : %s\n", cookiename, pass->pw_uid, strerror(errno)); setegid(0); return -1; } if (lstat(cookiename, &sbuf) == 0) { if (S_ISLNK(sbuf.st_mode)) { if (unlink(cookiename) < 0) { mpsslog(PERROR, "%s Cannot create: is a link and removal failed: %s\n", cookiename, strerror(errno)); goto cookie_done; } mpsslog(PERROR, "%s: Is a link - remove and recreate\n", cookiename); } else if (sbuf.st_nlink != 1) { if (unlink(cookiename) < 0) { mpsslog(PERROR, "%s Cannot create: has more than one hard link and " "removal failed: %s\n", cookiename, strerror(errno)); goto cookie_done; } mpsslog(PERROR, "%s: Too many hard links - remove and recreate\n", cookiename); } else { createcookie = FALSE; } } if (!createcookie) { if ((fd = open(cookiename, O_RDONLY)) < 0) { mpsslog(PERROR, "Failed to open %s: %s\n", cookiename, strerror(errno)); goto cookie_done; } if ((len = read(fd, cookie, MPSS_COOKIE_SIZE)) != MPSS_COOKIE_SIZE) { if (unlink(cookiename) < 0) { mpsslog(PERROR, "Cannot create cookie file %s bad size and removal failed: %s\n", cookiename, strerror(errno)); goto cookie_done; } mpsslog(PERROR, "%s: Bad size remove and recreate\n", cookiename); createcookie = TRUE; } close(fd); } if (createcookie) { if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { mpsslog(PERROR, "Create cookie %s failed to open dev random: %s\n", cookiename, strerror(errno)); goto cookie_done; } len = read(fd, cookie, MPSS_COOKIE_SIZE); close(fd); if ((fd = open(cookiename, O_WRONLY|O_CREAT)) < 0) { mpsslog(PERROR, "Failed to open %s: %s\n", cookiename, strerror(errno)); goto cookie_done; } write(fd, cookie, len); fchmod(fd, S_IRUSR); fchown(fd, pass->pw_uid, pass->pw_gid); close(fd); } err = 0; cookie_done: seteuid(0); setegid(0); return err; }
void * mic_credentials(void *arg) { struct mic_info *mic; struct mpssd_info *mpssdi; struct jobs *job; struct jobs *jlist; struct scif_portID portID; struct passwd *pass; char *username = NULL; char cookie[MPSS_COOKIE_SIZE]; int len; unsigned int proto; scif_epd_t lep; scif_epd_t dep; uid_t uid; int err; if ((lep = scif_open()) < 0) { mpsslog(PINFO, "Cannot open mpssd credentials SCIF listen port: %s\n", strerror(errno)); pthread_exit((void *)1); } if (scif_bind(lep, MPSSD_CRED) < 0) { mpsslog(PINFO, "Cannot bind to mpssd credentials SCIF PORT: %s\n", strerror(errno)); pthread_exit((void *)1); } if (scif_listen(lep, 16) < 0) { mpsslog(PINFO, "Set Listen on mpssd credentials SCIF PORT fail: %s\n", strerror(errno)); pthread_exit((void *)1); } while (1) { if (scif_accept(lep, &portID, &dep, SCIF_ACCEPT_SYNC)) { if (errno != EINTR) { mpsslog(PINFO, "Wait for credentials request fail: %s\n", strerror(errno)); scif_close(dep); } continue; } if ((err = scif_recv(dep, &uid, sizeof(uid), SCIF_RECV_BLOCK)) != sizeof(uid)) { mpsslog(PINFO, "Credential connect recieve error %s\n", strerror(errno)); scif_close(dep); continue; } username = NULL; while ((pass = getpwent()) != NULL) { if (uid == pass->pw_uid) { username = pass->pw_name; break; } } endpwent(); if (username == NULL) { mpsslog(PERROR, "User request unknown UID %d\n", uid); proto = CRED_FAIL_UNKNOWNUID; scif_send(dep, &proto, sizeof(proto), 0); scif_close(dep); continue; }; if (get_cookie(pass, cookie) < 0) { proto = CRED_FAIL_READCOOKIE; scif_send(dep, &proto, sizeof(proto), 0); scif_close(dep); continue; } if ((job = malloc(sizeof(struct jobs))) == NULL) { proto = CRED_FAIL_MALLOC; scif_send(dep, &proto, sizeof(proto), 0); scif_close(dep); continue; } job->jobid = nextjobid++; job->dep = dep; job->cnt = 0; len = strlen(username); while (pthread_mutex_lock(&jobs_lock) != 0); for (mic = miclist; mic != NULL; mic = mic->next) { mpssdi = (struct mpssd_info *)mic->data; if (mpssdi->send_ep != -1) { job->cnt++; proto = REQ_CREDENTIAL; if ((scif_send(mpssdi->send_ep, &proto, sizeof(proto), 0)) < 0) { if (errno == ECONNRESET) { job->cnt--; continue; } } scif_send(mpssdi->send_ep, &job->jobid, sizeof(job->jobid), 0); scif_send(mpssdi->send_ep, &len, sizeof(len), 0); scif_send(mpssdi->send_ep, username, len, 0); len = sizeof(cookie); scif_send(mpssdi->send_ep, &len, sizeof(len), 0); scif_send(mpssdi->send_ep, cookie, len, SCIF_SEND_BLOCK); } } if (job->cnt == 0) { proto = CRED_SUCCESS; scif_send(job->dep, &proto, sizeof(proto), 0); scif_close(job->dep); } else { jlist = &gjobs; while (jlist->next) jlist = jlist->next; jlist->next = job; job->next = NULL; } while (pthread_mutex_unlock(&jobs_lock) != 0); } }
void * shutdown_mic(void *arg) { struct mic_info *mic = (struct mic_info *)arg; struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; int timeout = atoi(mic->config.misc.shutdowntimeout); char *state = mpss_readsysfs(mic->name, "state"); char *mode; int err; struct timespec waittime; struct timeval now; if (is_upstream_driver()) mode = mpss_readsysfs(mic->name, "bootmode"); else mode = mpss_readsysfs(mic->name, "mode"); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); if (mpssdi->boot_pth) pthread_cancel(mpssdi->boot_pth); if (mpssdi->monitor_pth) pthread_cancel(mpssdi->monitor_pth); if (mpssdi->state_pth) pthread_cancel(mpssdi->state_pth); if (mpssdi->crash_pth) pthread_cancel(mpssdi->crash_pth); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); if (state == NULL) { mpsslog(PERROR, "%s: Failed to read state of card - Leaving in current state.\n", mic->name); } else { if (!timeout || strcmp(state, "online")) { mpsslog(PINFO, "%s: Forced Reset\n", mic->name); } else if ((mode == NULL) || (strcmp(mode, "linux"))) { if ((err = mpss_setsysfs(mic->name, "state", "reset")) != 0) { mpsslog(PERROR, "%s: Failed to set state of card - Leaving in current state: %s\n", mic->name, strerror(err)); } else { mpsslog(PINFO, "%s: Resetting online mode %s\n", mic->name, mode); } } else { mpsslog(PINFO, "%s: Shutting down. Timeout %d\n", mic->name, timeout); if ((err = mpss_setsysfs(mic->name, "state", "shutdown")) != 0) { mpsslog(PERROR, "%s: Failed to set state of card - Leaving in current state: %s\n", mic->name, strerror(err)); } else { mpsslog(PINFO, "%s: Shutting down. Timeout %d\n", mic->name, timeout); /* In KNL, mpssd resets the card after a shutdown. This is different from * KNC production stack in which the driver reset the card. * The timedwait here is signaled by the mic_config thread after performing * the reset */ if (is_upstream_driver()) { mpssdi->reset_done = 0; gettimeofday(&now, NULL); waittime.tv_sec = now.tv_sec + timeout; while (pthread_mutex_lock(&mpssdi->reset_lock) != 0); while (!mpssdi->reset_done) { if (!pthread_cond_timedwait(&mpssdi->reset_cond, &mpssdi->reset_lock, &waittime)) break; } while (pthread_mutex_unlock(&mpssdi->reset_lock) != 0); } } } } while (pthread_mutex_lock(&shutdown_lock) != 0); if (--shutdown_count == 0) exit(0); while (pthread_mutex_unlock(&shutdown_lock) != 0); while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); mpssdi->stop_pth = 0; while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); pthread_exit(NULL); }
static int tap_configure(struct mic_info *mic, char *dev) { pid_t pid; char *ifargv[7]; char ipaddr[IFNAMSIZ]; int ret = 0; pid = fork(); if (pid == 0) { ifargv[0] = "ip"; ifargv[1] = "link"; ifargv[2] = "set"; ifargv[3] = dev; ifargv[4] = "up"; ifargv[5] = NULL; mpsslog("Configuring %s\n", dev); ret = execvp("ip", ifargv); if (ret < 0) { mpsslog("%s execvp failed errno %s\n", mic->name, strerror(errno)); return ret; } } if (pid < 0) { mpsslog("%s fork failed errno %s\n", mic->name, strerror(errno)); return ret; } ret = waitpid(pid, NULL, 0); if (ret < 0) { mpsslog("%s waitpid failed errno %s\n", mic->name, strerror(errno)); return ret; } snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id); pid = fork(); if (pid == 0) { ifargv[0] = "ip"; ifargv[1] = "addr"; ifargv[2] = "add"; ifargv[3] = ipaddr; ifargv[4] = "dev"; ifargv[5] = dev; ifargv[6] = NULL; mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr); ret = execvp("ip", ifargv); if (ret < 0) { mpsslog("%s execvp failed errno %s\n", mic->name, strerror(errno)); return ret; } } if (pid < 0) { mpsslog("%s fork failed errno %s\n", mic->name, strerror(errno)); return ret; } ret = waitpid(pid, NULL, 0); if (ret < 0) { mpsslog("%s waitpid failed errno %s\n", mic->name, strerror(errno)); return ret; } mpsslog("MIC name %s %s %d DONE!\n", mic->name, __func__, __LINE__); return 0; }
void * boot_mic(void *arg) { struct mic_info *mic = (struct mic_info *)arg; struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; struct mpss_elist mpssperr; struct stat sbuf; char *initrd = NULL; char *state; char *save; char *errmsg; char boot_string[PATH_MAX]; char cmdline[2048]; int shutdown_wait = 180;// Do not wait for shutdown more than 180 secs. int reset_wait = 180; // Do not wait for reset more than 180 secs. int err = 0; char *shutdown_str; char os_image_path[PATH_MAX]; char kernel[PATH_MAX]; char ramdisk[PATH_MAX]; char efiimage[PATH_MAX]; char *sysfs_rd; if ((err = mpss_parse_config(&mpssenv, mic, &brlist, &mpssperr))) { mpsslog(PINFO, "%s: Boot aborted - no configuation file present: %s\n", mic->name, strerror(err)); goto bootexit; } mpss_print_elist(&mpssperr, PWARN, mpsslog); mpss_clear_elist(&mpssperr); switch(mic->config.family) { case MIC_FAMILY_KNL_VALUE: if (!is_mic_knl(mic)) mpsslog(PWARN, "%s: Family mismatch. Configuration file parameter is %s but MIC family is different\n" "\t Please execute micctrl --cleanconfig and --initdefaults again\n", mic->name, family_to_str(mic->config.family)); break; case MIC_FAMILY_KNC_VALUE: if (!is_mic_knc(mic)) mpsslog(PWARN, "%s: Family mismatch. Configuration file parameter is %s but MIC family is different\n" "\t Please execute micctrl --cleanconfig and --initdefaults again\n", mic->name, family_to_str(mic->config.family)); break; case MIC_FAMILY_UNKNOWN_VALUE: default: mpsslog(PWARN, "%s: Family parameter is %s\n\t Please execute micctrl --cleanconfig and --initdefaults again\n", mic->name, family_to_str(mic->config.family)); } if (check_fs_params(mic)) goto bootexit; if (mic->config.boot.osimage == NULL) { mpsslog(PINFO, "%s: Boot aborted - OsImage parameter not set\n", mic->name); goto bootexit; } if (is_mic_knl(mic) && mic->config.boot.efiimage == NULL) { mpsslog(PINFO, "%s: Boot aborted - EFI Image parameter not set\n", mic->name); goto bootexit; } if (verify_bzImage(&mpssenv, mic->config.boot.osimage, mic->name)) { mpsslog(PINFO, "%s: Boot aborted - %s is not a valid Linux bzImage\n", mic->name, mic->config.boot.osimage); goto bootexit; } if ((errmsg = mpss_set_cmdline(mic, brlist, cmdline, NULL)) != NULL) { mpsslog(PINFO, "%s: Boot aborted - %s\n", mic->name, errmsg); goto bootexit; } mpsslog(PINFO, "%s: Command line: %s\n", mic->name, cmdline); set_log_buf_info(mic); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if (mic->config.boot.onstart != TRUE) { mpsslog(PINFO, "%s: Not set to autoboot\n", mic->name); goto bootmic_done; } switch (mic->config.rootdev.type) { case ROOT_TYPE_RAMFS: if (stat(mic->config.rootdev.target, &sbuf) == 0) unlink(mic->config.rootdev.target); mpsslog(PINFO, "%s: Generate %s\n", mic->name, mic->config.rootdev.target); mpssfs_gen_initrd(&mpssenv, mic, &mpssperr); mpss_print_elist(&mpssperr, PWARN, mpsslog); mpss_clear_elist(&mpssperr); case ROOT_TYPE_STATICRAMFS: initrd = mic->config.rootdev.target; break; case ROOT_TYPE_NFS: case ROOT_TYPE_SPLITNFS: case ROOT_TYPE_PFS: initrd = mic->config.filesrc.base.image; break; } if (initrd == NULL) { mpsslog(PERROR, "%s Boot aborted - initial ramdisk not set", mic->name); goto bootmic_done; } if (is_upstream_driver()) { /* request_firmware() API that is used in the upstream stack * expects the firmware images to be somewhere under /lib/firmware. * We create /lib/firmware/mic/micX/ and place links to micX specific * images under them. */ snprintf(os_image_path, PATH_MAX, "/lib/firmware/mic/%s", mic->name); mpssut_deltree(&mpssenv, os_image_path); if (mpssut_mksubtree(&mpssenv, "", os_image_path, 0, 0, 0755)) { mpsslog(PERROR, "%s Boot aborted - Failed to create boot directory. %s\n", mic->name, strerror(errno)); goto bootmic_done; } snprintf(kernel, PATH_MAX, "%s/uos.img", os_image_path); snprintf(ramdisk, PATH_MAX, "%s/mic.image", os_image_path); if(is_mic_knl(mic)) snprintf(efiimage, PATH_MAX, "%s/efi.image", os_image_path); if (symlink(mic->config.boot.osimage, kernel) < 0) { mpsslog(PERROR, "%s Boot aborted - Failed to create symlink for kernel image. %s", mic->name, strerror(errno)); goto bootmic_done; } if (initrd == NULL || symlink(initrd, ramdisk) < 0) { mpsslog(PERROR, "%s Boot aborted - Failed to create symlink for filesystem. %s", mic->name, strerror(errno)); goto bootmic_done; } if (is_mic_knl(mic) && symlink(mic->config.boot.efiimage, efiimage) < 0) { mpsslog(PERROR, "%s Boot aborted - Failed to create symlink for EFI image. %s", mic->name, strerror(errno)); goto bootmic_done; } if (mpss_setsysfs(mic->name, "bootmode", "linux")) { sysfs_rd = mpss_readsysfs(mic->name, "bootmode"); mpsslog(PERROR, "%s failed to boot. Bootmode = %s\n", mic->name, sysfs_rd); free(sysfs_rd); goto bootmic_done; } /* request_firmware doesn't like absolute paths. */ snprintf(kernel, PATH_MAX, "mic/%s/uos.img", mic->name); snprintf(ramdisk, PATH_MAX, "mic/%s/mic.image", mic->name); if (is_mic_knl(mic)) snprintf(efiimage, PATH_MAX, "mic/%s/efi.image", mic->name); if (mpss_setsysfs(mic->name, "firmware", kernel)) { sysfs_rd = mpss_readsysfs(mic->name, "firmware"); mpsslog(PERROR, "%s failed to boot. Firmware = %s\n", mic->name, sysfs_rd); free(sysfs_rd); goto bootmic_done; } if (mpss_setsysfs(mic->name, "ramdisk", ramdisk)) { sysfs_rd = mpss_readsysfs(mic->name, "ramdisk"); mpsslog(PERROR, "%s failed to boot. Ramdisk = %s\n", mic->name, sysfs_rd); free(sysfs_rd); goto bootmic_done; } if (is_mic_knl(mic) && mpss_setsysfs(mic->name, "efiimage", efiimage)) { sysfs_rd = mpss_readsysfs(mic->name, "efiimage"); mpsslog(PERROR, "%s failed to boot. EFI image = %s\n", mic->name, sysfs_rd); free(sysfs_rd); goto bootmic_done; } snprintf(boot_string, PATH_MAX, "boot"); } else { snprintf(boot_string, PATH_MAX, "boot:linux:%s:%s", mic->config.boot.osimage, initrd); } if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PERROR, "%s: Cannot access state sysfs entry - skipping\n", mic->name); goto bootmic_done; } if (is_upstream_driver()) shutdown_str = "shutting_down"; else shutdown_str = "shutdown"; while (!strcmp(state, shutdown_str)) { save = state; if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PWARN, "%s: Wait for shutdown failed to read state sysfs - try again\n", mic->name); state = save; } else { free(save); } if (!shutdown_wait--) { mpsslog(PWARN, "%s: Wait for shutdown timed out\n", mic->name); goto bootmic_done; } mpsslog(PINFO, "%s: Waiting for shutdown to complete\n", mic->name); sleep(1); } while (!strcmp(state, "resetting")) { save = state; if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PWARN, "%s: Wait for reset failed to read state sysfs - try again\n", mic->name); state = save; } else { free(save); } if (!reset_wait--) { mpsslog(PINFO, "%s: Wait for reset timed out\n", mic->name); goto bootmic_done; } mpsslog(PINFO, "%s: Waiting for reset to complete\n", mic->name); sleep(1); } if (strcmp(state, "ready")) { mpsslog(PINFO, "%s: Current state \"%s\" cannot boot card\n", mic->name, state); free(state); goto bootmic_done; } free(state); if ((err = mpss_setsysfs(mic->name, "state", boot_string)) != 0) { mpsslog(PINFO, "%s: Booting failed - cannot set state: %s\n", mic->name, strerror(err)); } else { mpsslog(PINFO, "%s: Booting %s initrd %s\n", mic->name, mic->config.boot.osimage, initrd); } bootmic_done: while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); mpssdi->boot_pth = 0; while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); bootexit: while (pthread_mutex_lock(&start_lock) != 0); start_count--; while (pthread_mutex_unlock(&start_lock) != 0); pthread_exit(NULL); }
void * save_crashdump(void *arg) { struct mic_info *mic = (struct mic_info *)arg; struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; int cdfd = -1; int procfd = -1; void *addr = NULL; ssize_t bytes; ssize_t total_bytes = 0; ssize_t dirlimit; ssize_t diractual; struct tm *tm = NULL; char pathname[PATH_MAX]; time_t t; pid_t pid1 = 0; char *state; char *save; struct stat sbuf; struct statvfs vbuf; int err; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if ((dirlimit = atoi(CD_LIMIT) * (1024 * 1024 * 1024ULL)) == 0) { mpsslog(PWARN, "%s: [SaveCrashDump] Dump disabled\n", mic->name); goto reboot; } if (stat(CD_DIR, &sbuf) < 0) { if (mkdir(CD_DIR, 0755) < 0) { mpsslog(PWARN, "%s: [SaveCrashDump] Avborted - create directory %s failed: %s\n", mic->name, CD_DIR, strerror(errno)); goto reboot; } diractual = dirlimit; } else { /* Check size of crash directory with configured limits */ if ((diractual = get_dir_size(mic, CD_DIR)) < 0) { mpsslog(PINFO, "%s: [SaveCrashDump] Avborted - get directory %s size failed: %s\n", mic->name, CD_DIR, strerror(errno)); goto reboot; } } if (diractual > dirlimit) { mpsslog(PINFO, "%s: [SaveCrashDump] Avborted - %s current size 0x%lx configured limit 0x%lx\n", mic->name, CD_DIR, diractual, dirlimit); goto reboot; } /* Open core dump file with time details embedded in file name */ time(&t); if ((tm = localtime(&t)) == 0) { mpsslog(PERROR, "%s: [SaveCrashdump] Aborted - get system date failed\n", mic->name); goto reboot; } /* Create crash directories if not done already */ snprintf(pathname, PATH_MAX - 1, "%s/%s", CD_DIR, mic->name); if (mkdir(pathname, 0755) && errno != EEXIST) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - create directory %s failed %s\n", mic->name, pathname, strerror(errno)); goto reboot; } if (statvfs(pathname, &vbuf) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - cannot read free disk size of %s: %s\n", mic->name, pathname, strerror(errno)); goto reboot; } if (CD_MIN_DISK > (vbuf.f_bsize * vbuf.f_bfree)) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - free disk space less than required 32Gb\n", mic->name); goto reboot; } /* Open vmcore entry for crashed card */ snprintf(pathname, PATH_MAX - 1, "/proc/mic_vmcore/%s", mic->name); if ((procfd = open(pathname, O_RDONLY)) < 0) { mpsslog(PERROR, "%s: [SaveCrashdump] Aborted - open %s failed: %s\n", mic->name, pathname, strerror(errno)); goto reboot; } snprintf(pathname, PATH_MAX - 1, "%s/%s/vmcore-%d-%d-%d-%d:%d:%d", CD_DIR, mic->name, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if ((cdfd = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - open %s failed %s\n", mic->name, pathname, strerror(errno)); goto cleanup1; } mpsslog(PINFO, "%s: [SaveCrashDump] Capturing uOS kernel crash dump\n", mic->name); /* Read from the proc entry and write to the core dump file */ do { if (lseek(cdfd, CD_READ_CHUNK, SEEK_CUR) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted lseek failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } bytes = write(cdfd, "", 1); if (bytes != 1) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted write failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } if ((addr = mmap(NULL, CD_READ_CHUNK, PROT_READ|PROT_WRITE, MAP_SHARED, cdfd, total_bytes)) == MAP_FAILED) { mpsslog(PERROR, "%s: [SaveCrasdDump] Aborted mmap failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } if ((bytes = read(procfd, addr, CD_READ_CHUNK)) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted read failed %s\n", mic->name, strerror(errno)); remove(pathname); munmap(addr, CD_READ_CHUNK); goto cleanup2; } total_bytes += bytes; munmap(addr, CD_READ_CHUNK); if (ftruncate(cdfd, total_bytes + 1) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted ftruncate failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } } while (bytes == CD_READ_CHUNK); mpsslog(PNORM, "%s: [SaveCrashDump] Completed raw dump size 0x%lx\n", mic->name, total_bytes); mpsslog(PNORM, "%s: [SaveCrashDump] Gzip started\n", mic->name); pid1 = gzip(pathname); /* Initiate compression of the file and reset MIC in parallel */ cleanup2: close(cdfd); cleanup1: close(procfd); reboot: if ((err = mpss_setsysfs(mic->name, "state", "reset:force")) != 0) { mpsslog(PINFO, "%s: [SaveCrashDump] Failed to set state sysfs - cannot reset: %s\n", mic->name, strerror(err)); goto done; } if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PINFO, "%s: [SaveCrashDump] Failed to read state sysfs - state of reset unknown\n", mic->name); goto done; } while (strcmp(state, "ready") && strcmp(state, "reset failed")) { if (!strcmp(state, "online") || !strcmp(state, "booting")) { mpsslog(PINFO, "%s: [SaveCrashDump] External entity has already rebooted card\n", mic->name); free(state); goto done; } mpsslog(PINFO, "%s: [SaveCrashDump] Waiting for reset\n", mic->name); sleep(2); save = state; if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PWARN, "%s: [SaveCrashDump] wait for ready failed to read state sysfs - try again\n", mic->name); state = save; } else { free(save); } } if (strcmp(state, "ready")) { mpsslog(PERROR, "%s: [SaveCrashDump] Failed to reset card. Aborting reboot\n", mic->name); free(state); goto done; } if (pid1 && (pid1 < 0 || ((waitpid(pid1, NULL, 0)) < 0))) remove(pathname); if (autoreboot(mic)) { while (pthread_mutex_lock(&start_lock) != 0); start_count++; while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); pthread_create(&mpssdi->boot_pth, NULL, boot_mic, mic); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); while (pthread_mutex_unlock(&start_lock) != 0); } done: pthread_exit(NULL); }