예제 #1
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
init_device(struct sbd_context *st)
{
	struct sector_header_s	*s_header;
	struct sector_node_s	*s_node;
	struct sector_mbox_s	*s_mbox;
	struct stat 		s;
	char			uuid[37];
	int			i;
	int			rc = 0;

	s_header = sector_alloc();
	s_node = sector_alloc();
	s_mbox = sector_alloc();
	memcpy(s_header->magic, sbd_magic, sizeof(s_header->magic));
	s_header->version = sbd_version;
	s_header->slots = 255;
	s_header->sector_size = sector_size;
	s_header->timeout_watchdog = timeout_watchdog;
	s_header->timeout_allocate = timeout_allocate;
	s_header->timeout_loop = timeout_loop;
	s_header->timeout_msgwait = timeout_msgwait;

	s_header->minor_version = 1;
	uuid_generate(s_header->uuid);
	uuid_unparse_lower(s_header->uuid, uuid);

	fstat(st->devfd, &s);
	/* printf("st_size = %ld, st_blksize = %ld, st_blocks = %ld\n",
			s.st_size, s.st_blksize, s.st_blocks); */

	cl_log(LOG_INFO, "Creating version %d.%d header on device %d (uuid: %s)",
			s_header->version, s_header->minor_version,
			st->devfd, uuid);
	fprintf(stdout, "Creating version %d.%d header on device %d (uuid: %s)\n",
			s_header->version, s_header->minor_version,
			st->devfd, uuid);
	if (header_write(st, s_header) < 0) {
		rc = -1; goto out;
	}
	cl_log(LOG_INFO, "Initializing %d slots on device %d",
			s_header->slots,
			st->devfd);
	fprintf(stdout, "Initializing %d slots on device %d\n",
			s_header->slots,
			st->devfd);
	for (i=0;i < s_header->slots;i++) {
		if (slot_write(st, i, s_node) < 0) {
			rc = -1; goto out;
		}
		if (mbox_write(st, i, s_mbox) < 0) {
			rc = -1; goto out;
		}
	}

out:	free(s_node);
	free(s_header);
	free(s_mbox);
	return(rc);
}
예제 #2
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
slot_allocate(struct sbd_context *st, const char *name)
{
	struct sector_header_s	*s_header = NULL;
	struct sector_node_s	*s_node = NULL;
	struct sector_mbox_s	*s_mbox = NULL;
	int			i;
	int			rc = 0;

	if (!name) {
		cl_log(LOG_ERR, "slot_allocate(): No name specified.\n");
		fprintf(stderr, "slot_allocate(): No name specified.\n");
		rc = -1; goto out;
	}

	s_header = header_get(st);
	if (!s_header) {
		rc = -1; goto out;
	}

	s_node = sector_alloc();
	s_mbox = sector_alloc();

	while (1) {
		i = slot_lookup(st, s_header, name);
		if ((i >= 0) || (i == -2)) {
			/* -1 is "no slot found", in which case we
			 * proceed to allocate a new one.
			 * -2 is "read error during lookup", in which
			 * case we error out too
			 * >= 0 is "slot already allocated" */
			rc = i; goto out;
		}

		i = slot_unused(st, s_header);
		if (i >= 0) {
			cl_log(LOG_INFO, "slot %d is unused - trying to own", i);
			fprintf(stdout, "slot %d is unused - trying to own\n", i);
			memset(s_node, 0, sizeof(*s_node));
			s_node->in_use = 1;
			strncpy(s_node->name, name, sizeof(s_node->name));
			if (slot_write(st, i, s_node) < 0) {
				rc = -1; goto out;
			}
			sleep(timeout_allocate);
		} else {
			cl_log(LOG_ERR, "No more free slots.");
			fprintf(stderr, "No more free slots.\n");
			rc = -1; goto out;
		}
	}

out:	free(s_node);
	free(s_header);
	free(s_mbox);
	return(rc);
}
예제 #3
0
/**
 * Create a logpack.
 *
 * @logh_sectdp pointer to sector data pointer
 *   for logpack header (will be set).
 * @logd_sect_aryp pointer to sector data array pointer
 *   for logpack data (will be set).
 * @pbs physical block size [byte].
 * @bufsize buffer size for log data [byte].
 *
 * RETURN:
 *    allocated logpack in success, or NULL.
 */
struct logpack *alloc_logpack(
	unsigned int pbs, unsigned int n_sectors)
{
	struct logpack *pack;

	ASSERT(is_valid_pbs(pbs));
	ASSERT(0 < n_sectors);

	pack = (struct logpack *)malloc(sizeof(*pack));
	if (!pack) { goto error1; }
	memset(pack, 0, sizeof(*pack));

	/* Buffer for logpack header. */
	pack->sectd = sector_alloc(pbs);
	if (!pack->sectd) { goto error1; }
	pack->header = get_logpack_header(pack->sectd);

	/* Buffer for logpack data. */
	pack->sectd_ary = sector_array_alloc(pbs, n_sectors);
	if (!pack->sectd_ary) { goto error1; }
	return pack;

error1:
	LOGe("Memory allocation failure.\n");
	free_logpack(pack);
	return NULL;
}
예제 #4
0
파일: sbd-md.c 프로젝트: credativ/sbd
/* Check if there already is a slot allocated to said name; returns the
 * slot number. If not found, returns -1.
 * This is necessary because slots might not be continuous. */
static int
slot_lookup(struct sbd_context *st, const struct sector_header_s *s_header, const char *name)
{
	struct sector_node_s	*s_node = NULL;
	int 			i;
	int			rc = -1;

	if (!name) {
		cl_log(LOG_ERR, "slot_lookup(): No name specified.\n");
		goto out;
	}

	s_node = sector_alloc();

	for (i=0; i < s_header->slots; i++) {
		if (slot_read(st, i, s_node) < 0) {
			rc = -2; goto out;
		}
		if (s_node->in_use != 0) {
			if (strncasecmp(s_node->name, name,
						sizeof(s_node->name)) == 0) {
				DBGLOG(LOG_INFO, "%s owns slot %d", name, i);
				rc = i; goto out;
			}
		}
	}

out:	free(s_node);
	return rc;
}
예제 #5
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
mbox_write_verify(struct sbd_context *st, int mbox, struct sector_mbox_s *s_mbox)
{
	void *data;
	int rc = 0;

	if (sector_write(st, MBOX_TO_SECTOR(mbox), s_mbox) < 0)
		return -1;

	data = sector_alloc();
	if (sector_read(st, MBOX_TO_SECTOR(mbox), data) < 0) {
		rc = -1;
		goto out;
	}


	if (memcmp(s_mbox, data, sector_size) != 0) {
		cl_log(LOG_ERR, "Write verification failed!");
		rc = -1;
		goto out;
	}
	rc = 0;
out:
	free(data);
	return rc;
}
예제 #6
0
/**
 * Invalidate lsid inside ring buffer.
 */
bool invalidate_lsid(struct walb_dev *wdev, u64 lsid)
{
	struct sector_data *zero_sector;
	struct walb_super_sector *super;
	u64 off;
	bool ret;

	ASSERT(lsid != INVALID_LSID);

	zero_sector = sector_alloc(
		wdev->physical_bs, GFP_KERNEL | __GFP_ZERO);
	if (!zero_sector) {
		LOGe("sector allocation failed.\n");
		return false;
	}

	spin_lock(&wdev->lsuper0_lock);
	super = get_super_sector(wdev->lsuper0);
	off = get_offset_of_lsid_2(super, lsid);
	spin_unlock(&wdev->lsuper0_lock);

	ret = sector_io(WRITE, wdev->ldev, off, zero_sector);
	if (!ret) {
		LOGe("sector write failed.\n");
		iocore_set_readonly(wdev);
	}
	sector_free(zero_sector);
	return ret;
}
예제 #7
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
slot_list(struct sbd_context *st)
{
	struct sector_header_s	*s_header = NULL;
	struct sector_node_s	*s_node = NULL;
	struct sector_mbox_s	*s_mbox = NULL;
	int 			i;
	int			rc = 0;

	s_header = header_get(st);
	if (!s_header) {
		rc = -1; goto out;
	}

	s_node = sector_alloc();
	s_mbox = sector_alloc();

	for (i=0; i < s_header->slots; i++) {
		if (slot_read(st, i, s_node) < 0) {
			rc = -1; goto out;
		}
		if (s_node->in_use > 0) {
			if (mbox_read(st, i, s_mbox) < 0) {
				rc = -1; goto out;
			}
			printf("%d\t%s\t%s\t%s\n",
				i, s_node->name, char2cmd(s_mbox->cmd),
				s_mbox->from);
		}
	}

out:	free(s_node);
	free(s_header);
	free(s_mbox);
	return rc;
}
예제 #8
0
/**
 * Check logpack of the given lsid exists.
 *
 * @lsid lsid to check.
 *
 * @return Non-zero if valid, or 0.
 */
int walb_check_lsid_valid(struct walb_dev *wdev, u64 lsid)
{
	struct sector_data *sect;
	struct walb_logpack_header *logh;
	u64 off;

	ASSERT(wdev);

	sect = sector_alloc(wdev->physical_bs, GFP_NOIO);
	if (!sect) {
		LOGe("walb_check_lsid_valid: alloc sector failed.\n");
		goto error0;
	}
	ASSERT(is_same_size_sector(sect, wdev->lsuper0));
	logh = get_logpack_header(sect);

	spin_lock(&wdev->lsuper0_lock);
	off = get_offset_of_lsid_2(get_super_sector(wdev->lsuper0), lsid);
	spin_unlock(&wdev->lsuper0_lock);
	if (!sector_io(READ, wdev->ldev, off, sect)) {
		LOGe("walb_check_lsid_valid: read sector failed.\n");
		goto error1;
	}

	/* Check valid logpack header. */
	if (!is_valid_logpack_header_with_checksum(
			logh, wdev->physical_bs, wdev->log_checksum_salt)) {
		goto error1;
	}

	/* Check lsid. */
	if (logh->logpack_lsid != lsid) {
		goto error1;
	}

	sector_free(sect);
	return 1;

error1:
	sector_free(sect);
error0:
	return 0;
}
예제 #9
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
slot_unused(struct sbd_context *st, const struct sector_header_s *s_header)
{
	struct sector_node_s	*s_node;
	int 			i;
	int			rc = -1;

	s_node = sector_alloc();

	for (i=0; i < s_header->slots; i++) {
		if (slot_read(st, i, s_node) < 0) {
			rc = -1; goto out;
		}
		if (s_node->in_use == 0) {
			rc = i; goto out;
		}
	}

out:	free(s_node);
	return rc;
}
예제 #10
0
파일: sbd-md.c 프로젝트: credativ/sbd
static struct sector_header_s *
header_get(struct sbd_context *st)
{
	struct sector_header_s *s_header;
	s_header = sector_alloc();

	if (header_read(st, s_header) < 0) {
		cl_log(LOG_ERR, "Unable to read header from device %d", st->devfd);
		return NULL;
	}

	if (valid_header(s_header) < 0) {
		cl_log(LOG_ERR, "header on device %d is not valid.", st->devfd);
		return NULL;
	}

	/* cl_log(LOG_INFO, "Found version %d header with %d slots",
			s_header->version, s_header->slots); */

	return s_header;
}
예제 #11
0
/**
 * Write an end logpack header block.
 */
bool write_end_logpack_header(int fd, unsigned int pbs, u32 salt)
{
	bool ret = false;
	struct walb_logpack_header *h;
	struct sector_data *sect = sector_alloc(pbs);
	if (!sect) {
		LOGe("sector_alloc failed.\n");
		return false;
	}
	h = get_logpack_header(sect);

	memset(h, 0, pbs);
	h->sector_type = SECTOR_TYPE_LOGPACK;
	h->n_records = 0;
	h->logpack_lsid = (u64)(-1);
	h->checksum = 0;
	h->checksum = checksum((const u8 *)h, pbs, salt);

	ret = write_data(fd, (const u8 *)h, pbs);
	if (!ret) LOGe("write_data failed.\n");
	sector_free(sect);
	return ret;
}
예제 #12
0
/****************************************************************
*																*
*					cree la fenˆtre du tampon					*
*																*
****************************************************************/
void creer_tampon(void)
{
	register int k;
	register windowptr thewin;

	/* Allocate space for window record. */
	if ((Tampon = (windowptr)malloc(sizeof(windowrec))) == NULL)
		return;

	thewin = Tampon;

	/* Initialize window data structure. */
	thewin -> next = NULL;
	thewin -> kind_c = SIZER | MOVER | FULLER | CLOSER | NAME | UPARROW | DNARROW | VSLIDE | LFARROW | RTARROW | HSLIDE;
	thewin -> type = TAMPON;
	thewin -> menu_entry = FAIL;
	thewin -> place = 0;
	strcpy(thewin -> title, Messages(TAMPON_14));

	if ((thewin -> fonction.tampon.secteurBin = sector_alloc(512)) == NULL)
	{
		free(thewin);
		Tampon = NULL;
		return;
	}

	if ((thewin -> fonction.tampon.Text = malloc((size_t)SECTEURSIZE)) == NULL)
	{
		error_msg(Z_NOT_ENOUGH_MEMORY);
		free(thewin -> fonction.tampon.secteurBin);
		free(thewin);
		Tampon = NULL;
		return;
	}

	if ((thewin -> fonction.tampon.Ligne = (char **)malloc((size_t)SECTEURLINE * sizeof(char *))) == NULL)
	{
		error_msg(Z_NOT_ENOUGH_MEMORY);
		free(thewin -> fonction.tampon.secteurBin);
		free(thewin -> fonction.tampon.Text);
		free(thewin);
		Tampon = NULL;
		return;
	}

	/* le bloc contient d‚ja toutes les lignes remplies */
	thewin -> fonction.tampon.TextSize = SECTEURSIZE;
	thewin -> fonction.tampon.LineNumberMax = SECTEURLINE;
	thewin -> fonction.tampon.LineNumber = SECTEURLINE-2;
	thewin -> fonction.tampon.CurrentLine = SECTEURLINE-2;
	thewin -> fonction.tampon.taille_pt = gr_ch == 8 ? 9 : 10;
	thewin -> fonction.tampon.taille_w = gr_cw;
	thewin -> fonction.tampon.taille_h = gr_ch;
	thewin -> fonction.tampon.PrintLine = SECTEURLINE-3;
	thewin -> fonction.tampon.ligne = SECTEURLINE-3;
	thewin -> fonction.tampon.colonne = 0;

	/* chaque ligne … 0 */
	*thewin -> fonction.tampon.Text = '\0';

	for (k=1; k<SECTEURLINE; k++)	/* la premiŠre ligne est deux fois plus grande */
		thewin -> fonction.tampon.Text[(k+1) * SECTEURLINESIZE] = '\0';

	/* un pointeur sur chaque ligne */
	thewin -> fonction.tampon.Ligne[0] = thewin -> fonction.tampon.Text;

	for (k=1; k<SECTEURLINE; k++)
		thewin -> fonction.tampon.Ligne[k] = &thewin -> fonction.tampon.Text[(k+1) * SECTEURLINESIZE];

	thewin -> fonction.tampon.ascii = TRUE;
	thewin -> fonction.tampon.curseur_x = thewin -> fonction.tampon.curseur_y = FAIL;
	thewin -> fonction.tampon.page = 0;

	/* les champs suivant ne sont pas utilis‚ mais sont initialis‚s quand mˆme au cas ou... */
	thewin -> fonction.tampon.dirty = FALSE;
	thewin -> fonction.tampon.slide = NULL;
	thewin -> fonction.tampon.goto_liste = NULL;
	thewin -> fonction.tampon.max = 1;
	thewin -> fonction.tampon.secteur = 0;
	thewin -> fonction.tampon.sector_size = 1;

	/* secteur … 0 */
	memset(thewin -> fonction.tampon.secteurBin, 0, 512L);

	strncpy(thewin -> fonction.tampon.Ligne[0], "  Tampon", SECTEURLINESIZE*2);
	strncpy(thewin -> fonction.tampon.Ligne[1], "      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[2], "      0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[3], "                                                                    ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[4], "0000  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[5], "0020  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[6], "0040  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[7], "0060  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[8], "0080  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[9], "00A0  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[10], "00C0  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[11], "00E0  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[12], "0100  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[13], "0120  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[14], "0140  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[15], "0160  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[16], "0180  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[17], "01A0  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[18], "01C0  ", SECTEURLINESIZE);
	strncpy(thewin -> fonction.tampon.Ligne[19], "01E0  ", SECTEURLINESIZE);
} /* creer_tampon */
예제 #13
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
slot_ping(struct sbd_context *st, const char *name)
{
	struct sector_header_s	*s_header = NULL;
	struct sector_mbox_s	*s_mbox = NULL;
	int			mbox;
	int			waited = 0;
	int			rc = 0;

	if (!name) {
		cl_log(LOG_ERR, "slot_ping(): No recipient specified.\n");
		rc = -1; goto out;
	}

	s_header = header_get(st);
	if (!s_header) {
		rc = -1; goto out;
	}

	if (strcmp(name, "LOCAL") == 0) {
		name = local_uname;
	}

	mbox = slot_lookup(st, s_header, name);
	if (mbox < 0) {
		cl_log(LOG_ERR, "slot_msg(): No slot found for %s.", name);
		rc = -1; goto out;
	}

	s_mbox = sector_alloc();
	s_mbox->cmd = SBD_MSG_TEST;

	strncpy(s_mbox->from, local_uname, sizeof(s_mbox->from)-1);

	DBGLOG(LOG_DEBUG, "Pinging node %s", name);
	if (mbox_write(st, mbox, s_mbox) < -1) {
		rc = -1; goto out;
	}

	rc = -1;
	while (waited <= timeout_msgwait) {
		if (mbox_read(st, mbox, s_mbox) < 0)
			break;
		if (s_mbox->cmd != SBD_MSG_TEST) {
			rc = 0;
			break;
		}
		sleep(1);
		waited++;
	}

	if (rc == 0) {
		cl_log(LOG_DEBUG, "%s successfully pinged.", name);
	} else {
		cl_log(LOG_ERR, "%s failed to ping.", name);
	}

out:	free(s_mbox);
	free(s_header);
	return rc;
}
예제 #14
0
파일: sbd-md.c 프로젝트: credativ/sbd
static int
slot_msg(struct sbd_context *st, const char *name, const char *cmd)
{
	struct sector_header_s	*s_header = NULL;
	struct sector_mbox_s	*s_mbox = NULL;
	int			mbox;
	int			rc = 0;
	char			uuid[37];

	if (!name || !cmd) {
		cl_log(LOG_ERR, "slot_msg(): No recipient / cmd specified.\n");
		rc = -1; goto out;
	}

	s_header = header_get(st);
	if (!s_header) {
		rc = -1; goto out;
	}

	if (strcmp(name, "LOCAL") == 0) {
		name = local_uname;
	}
	
	if (s_header->minor_version > 0) {
		uuid_unparse_lower(s_header->uuid, uuid);
		cl_log(LOG_INFO, "Device UUID: %s", uuid);
	}

	mbox = slot_lookup(st, s_header, name);
	if (mbox < 0) {
		cl_log(LOG_ERR, "slot_msg(): No slot found for %s.", name);
		rc = -1; goto out;
	}

	s_mbox = sector_alloc();

	s_mbox->cmd = cmd2char(cmd);
	if (s_mbox->cmd < 0) {
		cl_log(LOG_ERR, "slot_msg(): Invalid command %s.", cmd);
		rc = -1; goto out;
	}

	strncpy(s_mbox->from, local_uname, sizeof(s_mbox->from)-1);

	cl_log(LOG_INFO, "Writing %s to node slot %s",
			cmd, name);
	if (mbox_write_verify(st, mbox, s_mbox) < -1) {
		rc = -1; goto out;
	}
	if (strcasecmp(cmd, "exit") != 0) {
		cl_log(LOG_INFO, "Messaging delay: %d",
				(int)timeout_msgwait);
		sleep(timeout_msgwait);
	}
	cl_log(LOG_INFO, "%s successfully delivered to %s",
			cmd, name);

out:	free(s_mbox);
	free(s_header);
	return rc;
}
예제 #15
0
파일: sbd-md.c 프로젝트: credativ/sbd
int servant(const char *diskname, int mode, const void* argp)
{
	struct sector_mbox_s *s_mbox = NULL;
	struct sector_node_s *s_node = NULL;
	struct sector_header_s	*s_header = NULL;
	int mbox;
	int rc = 0;
	time_t t0, t1, latency;
	union sigval signal_value;
	sigset_t servant_masks;
	struct sbd_context *st;
	pid_t ppid;
	char uuid[37];
	const struct servants_list_item *s = argp;

	if (!diskname) {
		cl_log(LOG_ERR, "Empty disk name %s.", diskname);
		return -1;
	}

	cl_log(LOG_INFO, "Servant starting for device %s", diskname);

	/* Block most of the signals */
	sigfillset(&servant_masks);
	sigdelset(&servant_masks, SIGKILL);
	sigdelset(&servant_masks, SIGFPE);
	sigdelset(&servant_masks, SIGILL);
	sigdelset(&servant_masks, SIGSEGV);
	sigdelset(&servant_masks, SIGBUS);
	sigdelset(&servant_masks, SIGALRM);
	/* FIXME: check error */
	sigprocmask(SIG_SETMASK, &servant_masks, NULL);

	atexit(servant_exit);
	servant_inform_parent = 1;

	st = open_device(diskname, LOG_WARNING);
	if (!st) {
		return -1;
	}

	s_header = header_get(st);
	if (!s_header) {
		cl_log(LOG_ERR, "Not a valid header on %s", diskname);
		return -1;
	}

	if (servant_check_timeout_inconsistent(s_header) < 0) {
		cl_log(LOG_ERR, "Timeouts on %s do not match first device",
				diskname);
		return -1;
	}

	if (s_header->minor_version > 0) {
		uuid_unparse_lower(s_header->uuid, uuid);
		cl_log(LOG_INFO, "Device %s uuid: %s", diskname, uuid);
	}

	mbox = slot_allocate(st, local_uname);
	if (mbox < 0) {
		cl_log(LOG_ERR,
		       "No slot allocated, and automatic allocation failed for disk %s.",
		       diskname);
		rc = -1;
		goto out;
	}
	s_node = sector_alloc();
	if (slot_read(st, mbox, s_node) < 0) {
		cl_log(LOG_ERR, "Unable to read node entry on %s",
				diskname);
		exit(1);
	}

	DBGLOG(LOG_INFO, "Monitoring slot %d on disk %s", mbox, diskname);
	if (s_header->minor_version == 0) {
		set_proc_title("sbd: watcher: %s - slot: %d", diskname, mbox);
	} else {
		set_proc_title("sbd: watcher: %s - slot: %d - uuid: %s",
				diskname, mbox, uuid);
	}

	s_mbox = sector_alloc();
	if (s->first_start) {
		if (mode > 0) {
			if (mbox_read(st, mbox, s_mbox) < 0) {
				cl_log(LOG_ERR, "mbox read failed during start-up in servant.");
				rc = -1;
				goto out;
			}
			if (s_mbox->cmd != SBD_MSG_EXIT &&
					s_mbox->cmd != SBD_MSG_EMPTY) {
				/* Not a clean stop. Abort start-up */
				cl_log(LOG_WARNING, "Found fencing message - aborting start-up. Manual intervention required!");
				ppid = getppid();
				sigqueue(ppid, SIG_EXITREQ, signal_value);
				rc = 0;
				goto out;
			}
		}
		DBGLOG(LOG_INFO, "First servant start - zeroing inbox");
		memset(s_mbox, 0, sizeof(*s_mbox));
		if (mbox_write(st, mbox, s_mbox) < 0) {
			rc = -1;
			goto out;
		}
	}

	memset(&signal_value, 0, sizeof(signal_value));

	while (1) {
		struct sector_header_s	*s_header_retry = NULL;
		struct sector_node_s	*s_node_retry = NULL;

		t0 = time(NULL);
		sleep(timeout_loop);

		ppid = getppid();

		if (ppid == 1) {
			/* Our parent died unexpectedly. Triggering
			 * self-fence. */
			do_reset();
		}

		/* These attempts are, by definition, somewhat racy. If
		 * the device is wiped out or corrupted between here and
		 * us reading our mbox, there is nothing we can do about
		 * that. But at least we tried. */
		s_header_retry = header_get(st);
		if (!s_header_retry) {
			cl_log(LOG_ERR, "No longer found a valid header on %s", diskname);
			exit(1);
		}
		if (memcmp(s_header, s_header_retry, sizeof(*s_header)) != 0) {
			cl_log(LOG_ERR, "Header on %s changed since start-up!", diskname);
			exit(1);
		}
		free(s_header_retry);

		s_node_retry = sector_alloc();
		if (slot_read(st, mbox, s_node_retry) < 0) {
			cl_log(LOG_ERR, "slot read failed in servant.");
			exit(1);
		}
		if (memcmp(s_node, s_node_retry, sizeof(*s_node)) != 0) {
			cl_log(LOG_ERR, "Node entry on %s changed since start-up!", diskname);
			exit(1);
		}
		free(s_node_retry);

		if (mbox_read(st, mbox, s_mbox) < 0) {
			cl_log(LOG_ERR, "mbox read failed in servant.");
			exit(1);
		}

		if (s_mbox->cmd > 0) {
			cl_log(LOG_INFO,
			       "Received command %s from %s on disk %s",
			       char2cmd(s_mbox->cmd), s_mbox->from, diskname);

			switch (s_mbox->cmd) {
			case SBD_MSG_TEST:
				memset(s_mbox, 0, sizeof(*s_mbox));
				mbox_write(st, mbox, s_mbox);
				sigqueue(ppid, SIG_TEST, signal_value);
				break;
			case SBD_MSG_RESET:
				do_reset();
				break;
			case SBD_MSG_OFF:
				do_off();
				break;
			case SBD_MSG_EXIT:
				sigqueue(ppid, SIG_EXITREQ, signal_value);
				break;
			case SBD_MSG_CRASHDUMP:
				do_crashdump();
				break;
			default:
				/* FIXME:
				   An "unknown" message might result
				   from a partial write.
				   log it and clear the slot.
				 */
				cl_log(LOG_ERR, "Unknown message on disk %s",
				       diskname);
				memset(s_mbox, 0, sizeof(*s_mbox));
				mbox_write(st, mbox, s_mbox);
				break;
			}
		}
		sigqueue(ppid, SIG_LIVENESS, signal_value);

		t1 = time(NULL);
		latency = t1 - t0;
		if (timeout_watchdog_warn && (latency > timeout_watchdog_warn)) {
			cl_log(LOG_WARNING,
			       "Latency: %d exceeded threshold %d on disk %s",
			       (int)latency, (int)timeout_watchdog_warn,
			       diskname);
		} else if (debug) {
			DBGLOG(LOG_INFO, "Latency: %d on disk %s", (int)latency,
			       diskname);
		}
	}
 out:
	free(s_mbox);
	close_device(st);
	if (rc == 0) {
		servant_inform_parent = 0;
	}
	return rc;
}