int pmix_path_df(const char *path, uint64_t *out_avail) { int rc = -1; int trials = 5; int err = 0; #if defined(USE_STATFS) struct statfs buf; #elif defined(HAVE_STATVFS) struct statvfs buf; #endif if (NULL == path || NULL == out_avail) { return PMIX_ERROR; } *out_avail = 0; do { #if defined(USE_STATFS) rc = statfs(path, &buf); #elif defined(HAVE_STATVFS) rc = statvfs(path, &buf); #endif err = errno; } while (-1 == rc && ESTALE == err && (--trials > 0)); if (-1 == rc) { PMIX_OUTPUT_VERBOSE((10, 2, "pmix_path_df: stat(v)fs on " "path: %s failed with errno: %d (%s)\n", path, err, strerror(err))); return PMIX_ERROR; } /* now set the amount of free space available on path */ /* sometimes buf.f_bavail is negative */ *out_avail = buf.f_bsize * ((int)buf.f_bavail < 0 ? 0 : buf.f_bavail); PMIX_OUTPUT_VERBOSE((10, 2, "pmix_path_df: stat(v)fs states " "path: %s has %"PRIu64 " B of free space.", path, *out_avail)); return PMIX_SUCCESS; }
/* * Parse one or more ranges in a set * * @param base The base text of the value name * @param *ranges A pointer to a range. This can contain multiple ranges * (i.e. "1-3,10" or "5" or "9,0100-0130,250") * @param ***names An argv array to add the newly discovered values to */ static pmix_status_t regex_parse_value_ranges(char *base, char *ranges, int num_digits, char *suffix, char ***names) { int i, len; pmix_status_t ret; char *start, *orig; /* Look for commas, the separator between ranges */ len = strlen(ranges); for (orig = start = ranges, i = 0; i < len; ++i) { if (',' == ranges[i]) { ranges[i] = '\0'; ret = regex_parse_value_range(base, start, num_digits, suffix, names); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } start = ranges + i + 1; } } /* Pick up the last range, if it exists */ if (start < orig + len) { PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output, "regex:parse:ranges: parse range %s (2)", start)); ret = regex_parse_value_range(base, start, num_digits, suffix, names); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } /* All done */ return PMIX_SUCCESS; }
static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names) { int i, j, k, len; pmix_status_t ret; char *base; char *orig, *suffix; bool found_range = false; bool more_to_come = false; int num_digits; /* set the default */ *names = NULL; if (NULL == regexp) { return PMIX_SUCCESS; } orig = base = strdup(regexp); if (NULL == base) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output, "pmix:extract:nodes: checking list: %s", regexp)); do { /* Find the base */ len = strlen(base); for (i = 0; i <= len; ++i) { if (base[i] == '[') { /* we found a range. this gets dealt with below */ base[i] = '\0'; found_range = true; break; } if (base[i] == ',') { /* we found a singleton value, and there are more to come */ base[i] = '\0'; found_range = false; more_to_come = true; break; } if (base[i] == '\0') { /* we found a singleton value */ found_range = false; more_to_come = false; break; } } if (i == 0 && !found_range) { /* we found a special character at the beginning of the string */ free(orig); return PMIX_ERR_BAD_PARAM; } if (found_range) { /* If we found a range, get the number of digits in the numbers */ i++; /* step over the [ */ for (j=i; j < len; j++) { if (base[j] == ':') { base[j] = '\0'; break; } } if (j >= len) { /* we didn't find the number of digits */ free(orig); return PMIX_ERR_BAD_PARAM; } num_digits = strtol(&base[i], NULL, 10); i = j + 1; /* step over the : */ /* now find the end of the range */ for (j = i; j < len; ++j) { if (base[j] == ']') { base[j] = '\0'; break; } } if (j >= len) { /* we didn't find the end of the range */ free(orig); return PMIX_ERR_BAD_PARAM; } /* check for a suffix */ if (j+1 < len && base[j+1] != ',') { /* find the next comma, if present */ for (k=j+1; k < len && base[k] != ','; k++); if (k < len) { base[k] = '\0'; } suffix = strdup(&base[j+1]); if (k < len) { base[k] = ','; } j = k-1; } else { suffix = NULL; } PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output, "regex:extract:nodes: parsing range %s %s %s", base, base + i, suffix)); ret = regex_parse_value_ranges(base, base + i, num_digits, suffix, names); if (NULL != suffix) { free(suffix); } if (PMIX_SUCCESS != ret) { free(orig); return ret; } if (j+1 < len && base[j + 1] == ',') { more_to_come = true; base = &base[j + 2]; } else { more_to_come = false; } } else { /* If we didn't find a range, just add the value */ if(PMIX_SUCCESS != (ret = pmix_argv_append_nosize(names, base))) { PMIX_ERROR_LOG(ret); free(orig); return ret; } /* step over the comma */ i++; /* set base equal to the (possible) next base to look at */ base = &base[i]; } } while(more_to_come); free(orig); /* All done */ return ret; }
pmix_status_t pmix_gds_ds12_lock_init(pmix_common_dstor_lock_ctx_t *ctx, const char *base_path, const char * name, uint32_t local_size, uid_t uid, bool setuid) { size_t size = pmix_common_dstor_getpagesize(); pmix_status_t rc = PMIX_SUCCESS; pthread_rwlockattr_t attr; ds12_lock_pthread_ctx_t *lock_ctx = (ds12_lock_pthread_ctx_t*)ctx; if (*ctx != NULL) { return PMIX_SUCCESS; } lock_ctx = (ds12_lock_pthread_ctx_t*)malloc(sizeof(ds12_lock_pthread_ctx_t)); if (NULL == lock_ctx) { rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } memset(lock_ctx, 0, sizeof(ds12_lock_pthread_ctx_t)); *ctx = (pmix_common_dstor_lock_ctx_t*)lock_ctx; lock_ctx->segment = (pmix_pshmem_seg_t *)malloc(sizeof(pmix_pshmem_seg_t)); if (NULL == lock_ctx->segment) { rc = PMIX_ERR_OUT_OF_RESOURCE; PMIX_ERROR_LOG(rc); goto error; } /* create a lock file to prevent clients from reading while server is writing * to the shared memory. This situation is quite often, especially in case of * direct modex when clients might ask for data simultaneously. */ if(0 > asprintf(&lock_ctx->lockfile, "%s/dstore_sm.lock", base_path)) { rc = PMIX_ERR_OUT_OF_RESOURCE; PMIX_ERROR_LOG(rc); goto error; } PMIX_OUTPUT_VERBOSE((10, pmix_gds_base_framework.framework_output, "%s:%d:%s _lockfile_name: %s", __FILE__, __LINE__, __func__, lock_ctx->lockfile)); if (PMIX_PROC_IS_SERVER(pmix_globals.mypeer)) { if (PMIX_SUCCESS != (rc = pmix_pshmem.segment_create(lock_ctx->segment, lock_ctx->lockfile, size))) { PMIX_ERROR_LOG(rc); goto error; } memset(lock_ctx->segment->seg_base_addr, 0, size); if (0 != setuid) { if (0 > chown(lock_ctx->lockfile, (uid_t) uid, (gid_t) -1)){ rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); goto error; } /* set the mode as required */ if (0 > chmod(lock_ctx->lockfile, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP )) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); goto error; } } lock_ctx->rwlock = (pthread_rwlock_t *)lock_ctx->segment->seg_base_addr; if (0 != pthread_rwlockattr_init(&attr)) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); goto error; } if (0 != pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { pthread_rwlockattr_destroy(&attr); rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } #ifdef HAVE_PTHREAD_SETKIND if (0 != pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) { pthread_rwlockattr_destroy(&attr); PMIX_ERROR_LOG(PMIX_ERR_INIT); goto error; } #endif if (0 != pthread_rwlock_init(lock_ctx->rwlock, &attr)) { pthread_rwlockattr_destroy(&attr); PMIX_ERROR_LOG(PMIX_ERR_INIT); goto error; } if (0 != pthread_rwlockattr_destroy(&attr)) { PMIX_ERROR_LOG(PMIX_ERR_INIT); goto error; } } else { lock_ctx->segment->seg_size = size; snprintf(lock_ctx->segment->seg_name, PMIX_PATH_MAX, "%s", lock_ctx->lockfile); if (PMIX_SUCCESS != (rc = pmix_pshmem.segment_attach(lock_ctx->segment, PMIX_PSHMEM_RW))) { PMIX_ERROR_LOG(rc); goto error; } lock_ctx->rwlock = (pthread_rwlock_t *)lock_ctx->segment->seg_base_addr; } return PMIX_SUCCESS; error: if (NULL != lock_ctx) { if (lock_ctx->segment) { /* detach & unlink from current desc */ if (lock_ctx->segment->seg_cpid == getpid()) { pmix_pshmem.segment_unlink(lock_ctx->segment); } pmix_pshmem.segment_detach(lock_ctx->segment); lock_ctx->rwlock = NULL; } if (NULL != lock_ctx->lockfile) { free(lock_ctx->lockfile); } free(lock_ctx); *ctx = (pmix_common_dstor_lock_ctx_t*)NULL; } return rc; }
pmix_status_t pmix_gds_ds21_lock_init(pmix_common_dstor_lock_ctx_t *ctx, const char *base_path, const char * name, uint32_t local_size, uid_t uid, bool setuid) { pthread_mutexattr_t attr; size_t size; uint32_t i; int page_size = pmix_common_dstor_getpagesize(); segment_hdr_t *seg_hdr; lock_item_t *lock_item = NULL; lock_ctx_t *lock_ctx = (lock_ctx_t*)*ctx; pmix_list_t *lock_tracker; pmix_status_t rc = PMIX_SUCCESS; if (NULL == *ctx) { lock_ctx = (lock_ctx_t*)malloc(sizeof(lock_ctx_t)); if (NULL == lock_ctx) { rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } memset(lock_ctx, 0, sizeof(lock_ctx_t)); PMIX_CONSTRUCT(&lock_ctx->lock_traker, pmix_list_t); *ctx = lock_ctx; } lock_tracker = &lock_ctx->lock_traker; lock_item = PMIX_NEW(lock_item_t); if (NULL == lock_item) { rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } pmix_list_append(lock_tracker, &lock_item->super); PMIX_OUTPUT_VERBOSE((10, pmix_gds_base_framework.framework_output, "%s:%d:%s local_size %d", __FILE__, __LINE__, __func__, local_size)); if (PMIX_PROC_IS_SERVER(pmix_globals.mypeer)) { size_t seg_align_size; size_t seg_hdr_size; if (0 != (seg_align_size = pmix_common_dstor_getcacheblocksize())) { seg_align_size = (sizeof(pthread_mutex_t) / seg_align_size + 1) * seg_align_size; } else { seg_align_size = sizeof(pthread_mutex_t); } seg_hdr_size = ((sizeof(segment_hdr_t) + sizeof(int32_t) * local_size) / seg_align_size + 1) * seg_align_size; size = ((seg_hdr_size + 2 * local_size * seg_align_size) /* array of mutexes */ / page_size + 1) * page_size; lock_item->seg_desc = pmix_common_dstor_create_new_lock_seg(base_path, size, name, 0, uid, setuid); if (NULL == lock_item->seg_desc) { rc = PMIX_ERR_OUT_OF_RESOURCE; PMIX_ERROR_LOG(rc); goto error; } if (0 != pthread_mutexattr_init(&attr)) { rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } if (0 != pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { pthread_mutexattr_destroy(&attr); rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } segment_hdr_t *seg_hdr = (segment_hdr_t*)lock_item->seg_desc->seg_info.seg_base_addr; seg_hdr->num_locks = local_size; seg_hdr->seg_size = size; seg_hdr->align_size = seg_align_size; seg_hdr->mutex_offs = seg_hdr_size; lock_item->lockfile = strdup(lock_item->seg_desc->seg_info.seg_name); lock_item->num_locks = local_size; lock_item->mutex = _GET_MUTEX_ARR_PTR(seg_hdr); for(i = 0; i < local_size * 2; i++) { pthread_mutex_t *mutex = _GET_MUTEX_PTR(seg_hdr, i); if (0 != pthread_mutex_init(mutex, &attr)) { pthread_mutexattr_destroy(&attr); rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(rc); goto error; } } if (0 != pthread_mutexattr_destroy(&attr)) { rc = PMIX_ERR_INIT; PMIX_ERROR_LOG(PMIX_ERR_INIT); goto error; } } else { int32_t *lock_idx_ptr; bool idx_found = false; size = pmix_common_dstor_getpagesize(); lock_item->seg_desc = pmix_common_dstor_attach_new_lock_seg(base_path, size, name, 0); if (NULL == lock_item->seg_desc) { rc = PMIX_ERR_NOT_FOUND; goto error; } seg_hdr = (segment_hdr_t*)lock_item->seg_desc->seg_info.seg_base_addr; if (seg_hdr->seg_size > size) { size = seg_hdr->seg_size; pmix_common_dstor_delete_sm_desc(lock_item->seg_desc); lock_item->seg_desc = pmix_common_dstor_attach_new_lock_seg(base_path, size, name, 0); if (NULL == lock_item->seg_desc) { rc = PMIX_ERR_NOT_FOUND; goto error; } } lock_item->num_locks = seg_hdr->num_locks; lock_idx_ptr = _GET_IDX_ARR_PTR(seg_hdr); lock_item->mutex = _GET_MUTEX_ARR_PTR(seg_hdr); for (i = 0; i < lock_item->num_locks; i++) { int32_t expected = 0; if (pmix_atomic_compare_exchange_strong_32(&lock_idx_ptr[i], &expected, 1)) { lock_item->lock_idx = i; lock_item->lockfile = strdup(lock_item->seg_desc->seg_info.seg_name); idx_found = true; break; } } if (false == idx_found) { rc = PMIX_ERR_NOT_FOUND; goto error; } } return rc; error: if (NULL != lock_item) { pmix_list_remove_item(lock_tracker, &lock_item->super); PMIX_RELEASE(lock_item); lock_item = NULL; } *ctx = NULL; return rc; }
bool pmix_path_nfs(char *fname, char **ret_fstype) { int i; int fsrc = -1; int vfsrc = -1; int trials; char * file = strdup (fname); #if defined(USE_STATFS) struct statfs fsbuf; #endif #if defined(HAVE_STATVFS) struct statvfs vfsbuf; #endif /* * Be sure to update the test (test/util/pmix_path_nfs.c) * while adding a new Network/Cluster Filesystem here */ static struct fs_types_t { unsigned long long f_fsid; unsigned long long f_mask; const char * f_fsname; } fs_types[] = { {LL_SUPER_MAGIC, MASK4, "lustre"}, {NFS_SUPER_MAGIC, MASK2, "nfs"}, {AUTOFS_SUPER_MAGIC, MASK2, "autofs"}, {PAN_KERNEL_FS_CLIENT_SUPER_MAGIC, MASK4, "panfs"}, {GPFS_SUPER_MAGIC, MASK4, "gpfs"}, {PVFS2_SUPER_MAGIC, MASK4, "pvfs2"} }; #define FS_TYPES_NUM (int)(sizeof (fs_types)/sizeof (fs_types[0])) /* * First, get the OS-dependent struct stat(v)fs buf. This may * return the ESTALE error on NFS, if the underlying file/path has * changed. */ again: #if defined(USE_STATFS) trials = 5; do { fsrc = statfs(file, &fsbuf); } while (-1 == fsrc && ESTALE == errno && (0 < --trials)); #endif #if defined(HAVE_STATVFS) trials = 5; do { vfsrc = statvfs(file, &vfsbuf); } while (-1 == vfsrc && ESTALE == errno && (0 < --trials)); #endif /* In case some error with the current filename, try the parent directory */ if (-1 == fsrc && -1 == vfsrc) { char * last_sep; PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: stat(v)fs on file:%s failed errno:%d directory:%s\n", fname, errno, file)); if (EPERM == errno) { free(file); if ( NULL != ret_fstype ) { *ret_fstype = NULL; } return false; } last_sep = strrchr(file, PMIX_PATH_SEP[0]); /* Stop the search, when we have searched past root '/' */ if (NULL == last_sep || (1 == strlen(last_sep) && PMIX_PATH_SEP[0] == *last_sep)) { free (file); if ( NULL != ret_fstype ) { *ret_fstype=NULL; } return false; } *last_sep = '\0'; goto again; } /* Next, extract the magic value */ for (i = 0; i < FS_TYPES_NUM; i++) { #if defined(USE_STATFS) /* These are uses of struct statfs */ # if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) if (0 == fsrc && 0 == strncasecmp(fs_types[i].f_fsname, fsbuf.f_fstypename, sizeof(fsbuf.f_fstypename))) { goto found; } # endif # if defined(HAVE_STRUCT_STATFS_F_TYPE) if (0 == fsrc && fs_types[i].f_fsid == (fsbuf.f_type & fs_types[i].f_mask)) { goto found; } # endif #endif #if defined(HAVE_STATVFS) /* These are uses of struct statvfs */ # if defined(HAVE_STRUCT_STATVFS_F_BASETYPE) if (0 == vfsrc && 0 == strncasecmp(fs_types[i].f_fsname, vfsbuf.f_basetype, sizeof(vfsbuf.f_basetype))) { goto found; } # endif # if defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) if (0 == vfsrc && 0 == strncasecmp(fs_types[i].f_fsname, vfsbuf.f_fstypename, sizeof(vfsbuf.f_fstypename))) { goto found; } # endif #endif } free (file); if ( NULL != ret_fstype ) { *ret_fstype=NULL; } return false; #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || \ defined(HAVE_STRUCT_STATFS_F_TYPE) || \ defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || \ defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) found: #endif free (file); if (AUTOFS_SUPER_MAGIC == fs_types[i].f_fsid) { char *fs_type = pmix_check_mtab(fname); int x; if (NULL != fs_type) { for (x = 0; x < FS_TYPES_NUM; x++) { if (AUTOFS_SUPER_MAGIC == fs_types[x].f_fsid) { continue; } if (0 == strcasecmp(fs_types[x].f_fsname, fs_type)) { PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: file:%s on fs:%s\n", fname, fs_type)); free(fs_type); if ( NULL != ret_fstype ) { *ret_fstype = strdup(fs_types[x].f_fsname); } return true; } } free(fs_type); if ( NULL != ret_fstype ) { *ret_fstype=NULL; } return false; } } PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: file:%s on fs:%s\n", fname, fs_types[i].f_fsname)); if ( NULL != ret_fstype ) { *ret_fstype = strdup (fs_types[i].f_fsname); } return true; #undef FS_TYPES_NUM }