/** * remove_lmbs * * @param nr_lmbs * @param lmb_list * @return 0 on success, !0 otherwise */ static int remove_lmbs(struct lmb_list_head *lmb_list) { struct dr_node *lmb_head = lmb_list->lmbs; struct dr_node *lmb; int rc; while (lmb_list->lmbs_modified < usr_drc_count) { if (drmgr_timed_out()) break; lmb = get_available_lmb(lmb_head); if (!lmb) return -1; /* Iterate only over the remaining LMBs */ lmb_head = lmb->next; rc = set_lmb_state(lmb, OFFLINE); if (rc) { lmb->unusable = 1; continue; } rc = remove_device_tree_lmb(lmb, lmb_list); if (rc) { report_unknown_error(__FILE__, __LINE__); set_lmb_state(lmb, ONLINE); lmb->unusable = 1; continue; } while (lmb->lmb_mem_scns) { struct mem_scn *scn = lmb->lmb_mem_scns; lmb->lmb_mem_scns = scn->next; free(scn); } rc = release_drc(lmb->drc_index, 0); if (rc) { report_unknown_error(__FILE__, __LINE__); add_device_tree_lmb(lmb, lmb_list); set_lmb_state(lmb, ONLINE); lmb->unusable = 1; continue; } lmb->is_removable = 0; lmb_list->lmbs_modified++; } return 0; }
int pci_remove_device(struct dr_node *node) { int rc = 0; FILE *file; char path[DR_PATH_MAX]; int wait_time = 0; sprintf(path, "%s/%s", node->sysfs_dev_path, "remove"); file = fopen(path, "w"); if (file == NULL) { say(ERROR, "failed to open %s: %s\n", path, strerror(errno)); return -ENODEV; } rc = fwrite("1", 1, 1, file); if (rc != 1) rc = -EACCES; fclose(file); if (rc == -EACCES) return rc; do { struct stat sb; rc = stat(node->sysfs_dev_path, &sb); if (rc) { rc = -errno; } else { say(DEBUG, "waiting for PCI device driver to quiesce device at %s\n", node->sysfs_dev_path); sleep(1); } } while (rc == 0 && (++wait_time < PCI_REMOVE_TIMEOUT_MAX && !drmgr_timed_out())); if (rc == 0) { say(ERROR, "timeout while quiescing device at %s\n", node->sysfs_dev_path); rc = -EBUSY; } else if (rc == -ENOENT) { /* sysfs entries cleaned up as part of device removal */ rc = 0; } return rc; }
/** * add_lmbs * * Attempt to acquire and online the given number of LMBs. * This function calls itself recursively to simplify recovery * actions in case of an error. This is intended only for the case * where the user does not specify a drc-name. * * @param nr_lmbs number of lmbs to add * @param lmb_list list of lmbs on the partition * @returns 0 on success, !0 otherwise */ static int add_lmbs(struct lmb_list_head *lmb_list) { int rc = 0; struct dr_node *lmb_head = lmb_list->lmbs; struct dr_node *lmb; lmb_list->lmbs_modified = 0; while (lmb_list->lmbs_modified < usr_drc_count) { if (drmgr_timed_out()) break; lmb = get_available_lmb(lmb_head); if (lmb == NULL) return -1; /* Iterate only over the remaining LMBs */ lmb_head = lmb->next; rc = acquire_drc(lmb->drc_index); if (rc) { report_unknown_error(__FILE__, __LINE__); lmb->unusable = 1; continue; } rc = add_device_tree_lmb(lmb, lmb_list); if (rc) { report_unknown_error(__FILE__, __LINE__); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } rc = set_lmb_state(lmb, ONLINE); if (rc) { report_unknown_error(__FILE__, __LINE__); remove_device_tree_lmb(lmb, lmb_list); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } lmb_list->lmbs_modified++; } return rc; }
/** * dr_lock * @brief Attempt to lock a token * * This will attempt to lock a token (either file or directory) and wait * a specified amount of time if the lock cannot be granted. * * @returns lock id if successful, -1 otherwise */ int dr_lock(void) { struct flock dr_lock_info; int rc; mode_t old_mode; int first_try = 1; old_mode = umask(0); dr_lock_fd = open(DR_LOCK_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); if (dr_lock_fd < 0) return -1; umask(old_mode); dr_lock_info.l_type = F_WRLCK; dr_lock_info.l_whence = SEEK_SET; dr_lock_info.l_start = 0; dr_lock_info.l_len = 0; do { if (!first_try) { sleep(1); first_try = 0; } rc = fcntl(dr_lock_fd, F_SETLK, &dr_lock_info); if (rc != -1) return 0; if (drmgr_timed_out()) break; if (rc == -1 && errno == EACCES) continue; } while (1); close(dr_lock_fd); dr_lock_fd = 0; perror(DR_LOCK_FILE); return -1; }
/** * dlpar_io_kernel_op * @brief access kernel interface files * * @param interface_file * @param drc_name * @returns 0 on success, !0 otherwise */ static int dlpar_io_kernel_op(const char *interface_file, const char *drc_name) { int rc = 0, len; FILE *file; len = strlen(drc_name); say(DEBUG, "performing kernel op for %s, file is %s\n", drc_name, interface_file); do { errno = 0; file = fopen(interface_file, "r+"); if (file == NULL) { say(ERROR, "failed to open %s: %s\n", interface_file, strerror(errno)); return -ENODEV; } rc = fwrite(drc_name, 1, len, file); fclose(file); sleep(1); if (drmgr_timed_out()) return -1; } while (errno == EBUSY); if (errno || (rc != len)) { say(ERROR, "kernel I/O op failed, rc = %d len = %d.\n%s\n", rc, len, strerror(errno)); return errno ? errno : rc; } return 0; }