Ejemplo n.º 1
0
/*
 * status_push -- (internal) push single status object
 */
static int
status_push(PMEMpoolcheck *ppc, struct check_status *st, uint32_t question)
{
	if (st->status.type == PMEMPOOL_CHECK_MSG_TYPE_ERROR) {
		ASSERTeq(ppc->data->error, NULL);
		ppc->data->error = st;
		return -1;
	} else if (st->status.type == PMEMPOOL_CHECK_MSG_TYPE_INFO) {
		if (CHECK_IS(ppc, VERBOSE))
			TAILQ_INSERT_TAIL(&ppc->data->infos, st, next);
		else
			check_status_release(ppc, st);
		return 0;
	}

	/* st->status.type == PMEMPOOL_CHECK_MSG_TYPE_QUESTION */
	if (CHECK_IS_NOT(ppc, REPAIR)) {
		/* error status */
		if (status_msg_info_only(st->msg)) {
			ERR("no error message for the user");
			st->msg[0] = '\0';
		}
		st->status.type = PMEMPOOL_CHECK_MSG_TYPE_ERROR;
		return status_push(ppc, st, question);
	}

	if (CHECK_IS(ppc, ALWAYS_YES)) {
		if (!status_msg_info_only(st->msg)) {
			/* information status */
			st->status.type = PMEMPOOL_CHECK_MSG_TYPE_INFO;
			status_push(ppc, st, question);
			st = status_alloc();
		}

		/* answer status */
		ppc->result = CHECK_RESULT_PROCESS_ANSWERS;
		st->question = question;
		st->answer = PMEMPOOL_CHECK_ANSWER_YES;
		st->status.type = PMEMPOOL_CHECK_MSG_TYPE_QUESTION;
		TAILQ_INSERT_TAIL(&ppc->data->answers, st, next);
	} else {
		/* question message */
		status_msg_info_and_question(st->msg);
		st->question = question;
		ppc->result = CHECK_RESULT_ASK_QUESTIONS;
		st->answer = PMEMPOOL_CHECK_ANSWER_EMPTY;
		TAILQ_INSERT_TAIL(&ppc->data->questions, st, next);
	}

	return 0;
}
Ejemplo n.º 2
0
/*
 * check_status_create -- create single status, push it to proper queue
 *
 * MSG_SEPARATOR character in fmt is treated as message separator. If creating
 * question but check arguments do not allow to make any changes (asking any
 * question is pointless) it takes part of message before MSG_SEPARATOR
 * character and use it to create error message. Character just before separator
 * must be a MSG_PLACE_OF_SEPARATION character. Return non 0 value if error
 * status would be created.
 */
int
check_status_create(PMEMpoolcheck *ppc, enum pmempool_check_msg_type type,
	uint32_t question, const char *fmt, ...)
{
	if (CHECK_IS_NOT(ppc, VERBOSE) && type == PMEMPOOL_CHECK_MSG_TYPE_INFO)
		return 0;

	struct check_status *st = status_alloc();

	if (CHECK_IS(ppc, FORMAT_STR)) {
		va_list ap;
		va_start(ap, fmt);
		int p = vsnprintf(st->msg, MAX_MSG_STR_SIZE, fmt, ap);
		va_end(ap);

		/* append possible strerror at the end of the message */
		if (type != PMEMPOOL_CHECK_MSG_TYPE_QUESTION && errno &&
				p > 0) {
			char buff[UTIL_MAX_ERR_MSG];
			util_strerror(errno, buff, UTIL_MAX_ERR_MSG);
			snprintf(st->msg + p, MAX_MSG_STR_SIZE - (size_t)p,
				": %s", buff);
		}

		st->status.type = type;
	}

	return status_push(ppc, st, question);
}
Ejemplo n.º 3
0
/*
 * pool_hdr_preliminary_check -- (internal) check pool header checksum and pool
 *	parameters
 */
static int
pool_hdr_preliminary_check(PMEMpoolcheck *ppc, location *loc)
{
	LOG(3, NULL);

	CHECK_INFO(ppc, "%schecking pool header", loc->prefix);

	if (util_is_zeroed((void *)&loc->hdr, sizeof(loc->hdr))) {
		if (CHECK_IS_NOT(ppc, REPAIR)) {
			check_end(ppc->data);
			ppc->result = CHECK_RESULT_NOT_CONSISTENT;
			return CHECK_ERR(ppc, "%sempty pool hdr", loc->prefix);
		}
	} else if (loc->hdr_valid) {
		enum pool_type type = pool_hdr_get_type(&loc->hdr);
		if (type == POOL_TYPE_UNKNOWN) {
			if (CHECK_IS_NOT(ppc, REPAIR)) {
				check_end(ppc->data);
				ppc->result = CHECK_RESULT_NOT_CONSISTENT;
				return CHECK_ERR(ppc, "%sinvalid signature",
					loc->prefix);
			}

			CHECK_INFO(ppc, "%sinvalid signature", loc->prefix);
		} else {
			/* valid check sum */
			CHECK_INFO(ppc, "%spool header correct",
				loc->prefix);
			loc->step = CHECK_STEP_COMPLETE;
			return 0;
		}
	} else if (CHECK_IS_NOT(ppc, REPAIR)) {
		check_end(ppc->data);
		ppc->result = CHECK_RESULT_NOT_CONSISTENT;
		return CHECK_ERR(ppc, "%sincorrect pool header", loc->prefix);
	} else {
		CHECK_INFO(ppc, "%sincorrect pool header", loc->prefix);
	}

	ASSERT(CHECK_IS(ppc, REPAIR));

	if (ppc->pool->params.type == POOL_TYPE_UNKNOWN) {
		ppc->pool->params.type = pool_hdr_possible_type(ppc);
		if (ppc->pool->params.type == POOL_TYPE_UNKNOWN) {
			ppc->result = CHECK_RESULT_CANNOT_REPAIR;
			return CHECK_ERR(ppc, "cannot determine pool type");
		}
	}

	if (!pool_supported(ppc->pool->params.type)) {
		ppc->result = CHECK_RESULT_CANNOT_REPAIR;
		return CHECK_ERR(ppc, "the repair of %s pools is not supported",
			pool_get_pool_type_str(ppc->pool->params.type));
	}

	return 0;
}
Ejemplo n.º 4
0
Archivo: pool.c Proyecto: mslusarz/nvml
/*
 * pool_data_alloc -- allocate pool data and open set_file
 */
struct pool_data *
pool_data_alloc(PMEMpoolcheck *ppc)
{
	LOG(3, NULL);

	struct pool_data *pool = malloc(sizeof(*pool));
	if (!pool) {
		ERR("!malloc");
		return NULL;
	}

	TAILQ_INIT(&pool->arenas);
	pool->narenas = 0;
	pool->blk_no_layout = 0;
	pool->uuid_op = UUID_NOP;
	pool->set_file = NULL;
	pool->bttc.valid = false;

	if (pool_params_parse(ppc, &pool->params, 0))
		goto error;

	int rdonly = CHECK_IS_NOT(ppc, REPAIR);
	int prv = CHECK_IS(ppc, DRY_RUN);

	if (prv && pool->params.is_device_dax) {
		errno = ENOTSUP;
		ERR("!cannot perform a dry run on dax device");
		goto error;
	}

	pool->set_file = pool_set_file_open(ppc->path, &pool->params, prv);
	if (pool->set_file == NULL)
		goto error;

	/*
	 * XXX mprotect for device dax with length not aligned to its
	 * page granularity causes SIGBUS on the next page fault.
	 * The length argument of this call should be changed to
	 * pool->set_file->poolsize once the kernel issue is solved.
	 */
	if (rdonly && mprotect(pool->set_file->addr,
		pool->set_file->poolset->replica[0]->repsize,
		PROT_READ) < 0)
		goto error;

	if (pool->params.type != POOL_TYPE_BTT) {
		if (pool_set_file_map_headers(pool->set_file, rdonly, prv))
			goto error;
	}

	return pool;

error:
	pool_data_free(pool);
	return NULL;
}
Ejemplo n.º 5
0
/*
 * pool_hdr_default_check -- (internal) check some default values in pool header
 */
static int
pool_hdr_default_check(PMEMpoolcheck *ppc, location *loc)
{
	LOG(3, NULL);

	ASSERT(CHECK_IS(ppc, REPAIR));

	struct pool_hdr def_hdr;
	pool_hdr_default(ppc->pool->params.type, &def_hdr);

	if (memcmp(loc->hdr.signature, def_hdr.signature, POOL_HDR_SIG_LEN)) {
		CHECK_ASK(ppc, Q_DEFAULT_SIGNATURE,
			"%spool_hdr.signature is not valid.|Do you want to set "
			"it to %.8s?", loc->prefix, def_hdr.signature);
	}

	if (loc->hdr.major != def_hdr.major) {
		CHECK_ASK(ppc, Q_DEFAULT_MAJOR,
			"%spool_hdr.major is not valid.|Do you want to set it "
			"to default value 0x%x?", loc->prefix, def_hdr.major);
	}

	if (loc->hdr.compat_features != def_hdr.compat_features) {
		CHECK_ASK(ppc, Q_DEFAULT_COMPAT_FEATURES,
			"%spool_hdr.compat_features is not valid.|Do you want "
			"to set it to default value 0x%x?", loc->prefix,
			def_hdr.compat_features);
	}

	if (loc->hdr.incompat_features != def_hdr.incompat_features) {
		CHECK_ASK(ppc, Q_DEFAULT_INCOMPAT_FEATURES,
			"%spool_hdr.incompat_features is not valid.|Do you "
			"want to set it to default value 0x%x?", loc->prefix,
			def_hdr.incompat_features);
	}

	if (loc->hdr.ro_compat_features != def_hdr.ro_compat_features) {
		CHECK_ASK(ppc, Q_DEFAULT_RO_COMPAT_FEATURES,
			"%spool_hdr.ro_compat_features is not valid.|Do you "
			"want to set it to default value 0x%x?", loc->prefix,
			def_hdr.ro_compat_features);
	}

	if (!util_is_zeroed(loc->hdr.unused, sizeof(loc->hdr.unused))) {
		CHECK_ASK(ppc, Q_ZERO_UNUSED_AREA,
			"%sunused area is not filled by zeros.|Do you want to "
			"fill it up?", loc->prefix);
	}

	return check_questions_sequence_validate(ppc);
}
Ejemplo n.º 6
0
/*
 * pool_hdr_uuid_links -- (internal) check UUID links values
 */
static int
pool_hdr_uuid_links(PMEMpoolcheck *ppc, location *loc)
{
	LOG(3, NULL);

	/*
	 * If the pool header is valid and there is not other parts or replicas
	 * in the poolset its uuid links are also valid.
	 */
	if (loc->hdr_valid && loc->single_repl && loc->single_part)
		return 0;

	uuid_t *links[] = {
		&loc->hdr.next_part_uuid, &loc->hdr.prev_part_uuid,
		&loc->hdr.next_repl_uuid, &loc->hdr.prev_repl_uuid};
	uuid_t *uuids[] = {
		&loc->next_part_hdrp->uuid, &loc->prev_part_hdrp->uuid,
		&loc->next_repl_hdrp->uuid, &loc->prev_repl_hdrp->uuid
	};
	uint32_t questions[] = {
		Q_NEXT_PART_UUID_SET, Q_PREV_PART_UUID_SET,
		Q_NEXT_REPL_UUID_SET, Q_PREV_REPL_UUID_SET
	};
	const char *fields[] = {
		"pool_hdr.next_part_uuid", "pool_hdr.prev_part_uuid",
		"pool_hdr.next_repl_uuid", "pool_hdr.prev_repl_uuid"
	};

	COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(uuids));
	COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(questions));
	COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(fields));
	for (uint64_t i = 0; i < ARRAY_SIZE(links); ++i) {
		if (uuidcmp(*links[i], *uuids[i]) == 0)
			continue;

		if (CHECK_IS(ppc, REPAIR)) {
			CHECK_ASK(ppc, questions[i],
				"%sinvalid %s.|Do you want to set it to a "
				"valid value?", loc->prefix, fields[i]);
		} else {
			ppc->result = CHECK_RESULT_NOT_CONSISTENT;
			return CHECK_ERR(ppc, "%sinvalid %s", loc->prefix,
				fields[i]);
		}
	}

	return check_questions_sequence_validate(ppc);
}
Ejemplo n.º 7
0
/*
 * pool_hdr_uuid_find -- (internal) check UUID value
 */
static int
pool_hdr_uuid_find(PMEMpoolcheck *ppc, location *loc)
{
	LOG(3, NULL);

	/*
	 * If the pool header is valid and there is not other parts or replicas
	 * in the poolset its uuid is also valid.
	 */
	if (loc->hdr_valid && loc->single_repl && loc->single_part)
		return 0;

	int hdrs_valid[] = {
		loc->next_part_hdr_valid, loc->prev_part_hdr_valid,
		loc->next_repl_hdr_valid, loc->prev_repl_hdr_valid};
	uuid_t *uuids[] = {
		&loc->next_part_hdrp->prev_part_uuid,
		&loc->prev_part_hdrp->next_part_uuid,
		&loc->next_repl_hdrp->prev_repl_uuid,
		&loc->prev_repl_hdrp->next_repl_uuid
	};

	/*
	 * if all valid poolset part files have the same uuid links to this part
	 * file it is valid uuid
	 * if all links have the same uuid and it is single file pool it is also
	 * the valid uuid
	 */
	loc->valid_uuid = NULL;
	if (loc->hdr_valid)
		loc->valid_uuid = &loc->hdr.uuid;
	uuid_t *common_uuid = uuids[0];

	COMPILE_ERROR_ON(ARRAY_SIZE(uuids) != ARRAY_SIZE(hdrs_valid));
	COMPILE_ERROR_ON(COMPARE_TO_FIRST_PART_ONLY >= ARRAY_SIZE(uuids));
	for (unsigned i = 0; i < ARRAY_SIZE(uuids); ++i) {
		if (i > 0 && common_uuid != NULL) {
			if (uuidcmp(*common_uuid, *uuids[i]) != 0) {
				common_uuid = NULL;
			}
		}

		if (i >= COMPARE_TO_FIRST_PART_ONLY && loc->part != 0)
			continue;

		if (!hdrs_valid[i])
			continue;

		if (!loc->valid_uuid) {
			loc->valid_uuid = uuids[i];
		} else if (uuidcmp(*loc->valid_uuid, *uuids[i]) != 0) {
			ppc->result = CHECK_RESULT_NOT_CONSISTENT;
			return CHECK_ERR(ppc, "%sambiguous pool_hdr.uuid",
				loc->prefix);
		}
	}

	if (!loc->valid_uuid && common_uuid)
		loc->valid_uuid = common_uuid;

	if (loc->valid_uuid != NULL) {
		if (uuidcmp(*loc->valid_uuid, loc->hdr.uuid) != 0) {
			CHECK_ASK(ppc, Q_UUID_SET, INVALID_UUID ".|Do you want "
				"to set it to %s from a valid part file?",
				loc->prefix,
				check_get_uuid_str(*loc->valid_uuid));
		}
	} else if (CHECK_IS(ppc, ADVANCED)) {
		CHECK_ASK(ppc, Q_UUID_REGENERATE, INVALID_UUID ".|Do you want "
				"to regenerate it?", loc->prefix);
	} else if (CHECK_IS(ppc, REPAIR)) {
		ppc->result = CHECK_RESULT_CANNOT_REPAIR;
		CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix);
		return CHECK_ERR(ppc, INVALID_UUID, loc->prefix);
	} else {
		ppc->result = CHECK_RESULT_NOT_CONSISTENT;
		return CHECK_ERR(ppc, INVALID_UUID, loc->prefix);
	}

	return check_questions_sequence_validate(ppc);
}