/* * update_replica_header -- (internal) update field values in the first header * in the replica */ static void update_replica_header(struct pool_set *set, unsigned repn) { LOG(3, "set %p, repn %u", set, repn); struct pool_replica *rep = REP(set, repn); struct pool_set_part *part = PART(REP(set, repn), 0); struct pool_hdr *hdr = (struct pool_hdr *)part->hdr; if (set->options & OPTION_SINGLEHDR) { hdr->incompat_features |= POOL_FEAT_SINGLEHDR; memcpy(hdr->next_part_uuid, hdr->uuid, POOL_HDR_UUID_LEN); memcpy(hdr->prev_part_uuid, hdr->uuid, POOL_HDR_UUID_LEN); } else { hdr->incompat_features &= (uint32_t)(~POOL_FEAT_SINGLEHDR); } util_checksum(hdr, sizeof(*hdr), &hdr->checksum, 1, POOL_HDR_CSUM_END_OFF); util_persist_auto(rep->is_pmem, hdr, sizeof(*hdr)); }
/* * pool_write -- write to pool set file or regular file * * 'buff' has to be a buffer at least 'nbytes' long * 'off' is an offset from the beginning of the pool */ int pool_write(struct pool_data *pool, const void *buff, size_t nbytes, uint64_t off) { if (off + nbytes > pool->set_file->size) return -1; if (pool->params.type != POOL_TYPE_BTT) { memcpy((char *)pool->set_file->addr + off, buff, nbytes); util_persist_auto(pool->params.is_dev_dax, (char *)pool->set_file->addr + off, nbytes); } else { if (pool_btt_lseek(pool, (off_t)off, SEEK_SET) == -1) return -1; if ((size_t)pool_btt_write(pool, buff, nbytes) != nbytes) return -1; } return 0; }
int main(int argc, char *argv[]) { int fd; size_t mapped_len; char *dest; char *dest1; char *ret; START(argc, argv, "pmem_memset"); if (argc != 4) UT_FATAL("usage: %s file offset length", argv[0]); fd = OPEN(argv[1], O_RDWR); /* open a pmem file and memory map it */ if ((dest = pmem_map_file(argv[1], 0, 0, 0, &mapped_len, NULL)) == NULL) UT_FATAL("!Could not mmap %s\n", argv[1]); int dest_off = atoi(argv[2]); size_t bytes = strtoul(argv[3], NULL, 0); char *buf = MALLOC(bytes); memset(dest, 0, bytes); util_persist_auto(util_fd_is_device_dax(fd), dest, bytes); dest1 = MALLOC(bytes); memset(dest1, 0, bytes); /* * This is used to verify that the value of what a non persistent * memset matches the outcome of the persistent memset. The * persistent memset will match the file but may not be the * correct or expected value. */ memset(dest1 + dest_off, 0x5A, bytes / 4); memset(dest1 + dest_off + (bytes / 4), 0x46, bytes / 4); /* Test the corner cases */ ret = pmem_memset_persist(dest + dest_off, 0x5A, 0); UT_ASSERTeq(ret, dest + dest_off); UT_ASSERTeq(*(char *)(dest + dest_off), 0); /* * Do the actual memset with persistence. */ ret = pmem_memset_persist(dest + dest_off, 0x5A, bytes / 4); UT_ASSERTeq(ret, dest + dest_off); ret = pmem_memset_persist(dest + dest_off + (bytes / 4), 0x46, bytes / 4); UT_ASSERTeq(ret, dest + dest_off + (bytes / 4)); if (memcmp(dest, dest1, bytes / 2)) UT_ERR("%s: first %zu bytes do not match", argv[1], bytes / 2); LSEEK(fd, (off_t)0, SEEK_SET); if (READ(fd, buf, bytes / 2) == bytes / 2) { if (memcmp(buf, dest, bytes / 2)) UT_ERR("%s: first %zu bytes do not match", argv[1], bytes / 2); } UT_ASSERTeq(pmem_unmap(dest, mapped_len), 0); FREE(dest1); FREE(buf); CLOSE(fd); DONE(NULL); }
/* * do_memmove: Worker function for memmove. * * Always work within the boundary of bytes. Fill in 1/2 of the src * memory with the pattern we want to write. This allows us to check * that we did not overwrite anything we were not supposed to in the * dest. Use the non pmem version of the memset/memcpy commands * so as not to introduce any possible side affects. */ static void do_memmove(int fd, char *dest, char *src, char *file_name, off_t dest_off, off_t src_off, off_t off, off_t bytes) { void *ret; char *src1 = MALLOC(bytes); char *buf = MALLOC(bytes); char old; memset(buf, 0, bytes); memset(src1, 0, bytes); memset(src, 0x5A, bytes / 4); util_persist_auto(util_fd_is_device_dax(fd), src, bytes / 4); memset(src + bytes / 4, 0x54, bytes / 4); util_persist_auto(util_fd_is_device_dax(fd), src + bytes / 4, bytes / 4); /* dest == src */ old = *(char *)(dest + dest_off); ret = pmem_memmove_persist(dest + dest_off, dest + dest_off, bytes / 2); UT_ASSERTeq(ret, dest + dest_off); UT_ASSERTeq(*(char *)(dest + dest_off), old); /* len == 0 */ old = *(char *)(dest + dest_off); ret = pmem_memmove_persist(dest + dest_off, src + src_off, 0); UT_ASSERTeq(ret, dest + dest_off); UT_ASSERTeq(*(char *)(dest + dest_off), old); /* * A side affect of the memmove call is that * src contents will be changed in the case of overlapping * addresses. */ memcpy(src1, src, bytes / 2); ret = pmem_memmove_persist(dest + dest_off, src + src_off, bytes / 2); UT_ASSERTeq(ret, dest + dest_off); /* memcmp will validate that what I expect in memory. */ if (memcmp(src1 + src_off, dest + dest_off, bytes / 2)) UT_ERR("%s: %zu bytes do not match with memcmp", file_name, bytes / 2); /* * This is a special case. An overlapping dest means that * src is a pointer to the file, and destination is src + dest_off + * overlap. This is the basis for the comparison. The use of ERR * here is deliberate. This will force a failure of the test but allow * it to continue until its done. The idea is that allowing some * to succeed and others to fail gives more information about what * went wrong. */ if (dest > src && off != 0) { LSEEK(fd, (off_t)dest_off + off, SEEK_SET); if (READ(fd, buf, bytes / 2) == bytes / 2) { if (memcmp(src1 + src_off, buf, bytes / 2)) UT_ERR("%s: first %zu bytes do not match", file_name, bytes / 2); } } else { LSEEK(fd, (off_t)dest_off, SEEK_SET); if (READ(fd, buf, bytes / 2) == bytes / 2) { if (memcmp(src1 + src_off, buf, bytes / 2)) UT_ERR("%s: first %zu bytes do not match", file_name, bytes / 2); } } FREE(src1); FREE(buf); }
int main(int argc, char *argv[]) { int fd; char *dest; char *src; off_t dest_off = 0; off_t src_off = 0; uint64_t bytes = 0; int who = 0; off_t overlap = 0; size_t mapped_len; START(argc, argv, "pmem_memmove"); fd = OPEN(argv[1], O_RDWR); if (argc < 3) USAGE(); for (int arg = 2; arg < argc; arg++) { if (strchr("dsboS", argv[arg][0]) == NULL || argv[arg][1] != ':') UT_FATAL("op must be d: or s: or b: or o: or S:"); off_t val = strtoul(&argv[arg][2], NULL, 0); switch (argv[arg][0]) { case 'd': if (val <= 0) UT_FATAL("bad offset (%lu) with d: option", val); dest_off = val; break; case 's': if (val <= 0) UT_FATAL("bad offset (%lu) with s: option", val); src_off = val; break; case 'b': if (val <= 0) UT_FATAL("bad length (%lu) with b: option", val); bytes = val; break; case 'o': if (val != 1 && val != 2) UT_FATAL("bad val (%lu) with o: option", val); who = (int)val; break; case 'S': overlap = val; break; } } if (who == 0 && overlap != 0) USAGE(); /* for overlap the src and dest must be created differently */ if (who == 0) { /* src > dest */ dest = pmem_map_file(argv[1], 0, 0, 0, &mapped_len, NULL); if (dest == NULL) UT_FATAL("!could not mmap dest file %s", argv[1]); src = MMAP(dest + mapped_len, mapped_len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); /* * Its very unlikely that src would not be > dest. pmem_map_file * chooses the first unused address >= 1TB, large * enough to hold the give range, and 1GB aligned. Log * the error if the mapped addresses cannot be swapped * but allow the test to continue. */ if (src <= dest) { swap_mappings(&dest, &src, mapped_len, fd); if (src <= dest) UT_ERR("cannot map files in memory order"); } do_memmove(fd, dest, src, argv[1], dest_off, src_off, 0, bytes); /* dest > src */ swap_mappings(&dest, &src, mapped_len, fd); if (dest <= src) UT_ERR("cannot map files in memory order"); do_memmove(fd, dest, src, argv[1], dest_off, src_off, 0, bytes); MUNMAP(dest, mapped_len); MUNMAP(src, mapped_len); } else if (who == 1) { /* src overlap with dest */ dest = pmem_map_file(argv[1], 0, 0, 0, &mapped_len, NULL); if (dest == NULL) UT_FATAL("!Could not mmap %s: \n", argv[1]); src = dest + overlap; memset(dest, 0, bytes); util_persist_auto(util_fd_is_device_dax(fd), dest, bytes); do_memmove(fd, dest, src, argv[1], dest_off, src_off, overlap, bytes); MUNMAP(dest, mapped_len); } else { /* dest overlap with src */ dest = pmem_map_file(argv[1], 0, 0, 0, &mapped_len, NULL); if (dest == NULL) { UT_FATAL("!Could not mmap %s: \n", argv[1]); } src = dest; dest = src + overlap; memset(src, 0, bytes); util_persist_auto(util_fd_is_device_dax(fd), src, bytes); do_memmove(fd, dest, src, argv[1], dest_off, src_off, overlap, bytes); MUNMAP(src, mapped_len); } CLOSE(fd); DONE(NULL); }