Side-project feature request for 'hammer mirror-*' functions

Michael Neumann mneumann at ntecs.de
Fri Oct 10 08:38:26 PDT 2008


Matthew Dillon wrote:
    If someone has the time, this is a really simple feature request.
    Ok, yah, I could do it myself, but I'm going to offer it to others
    first and that might save me a little time :-)
    It's simple.  If you do a hammer mirror-copy or hammer mirror-stream
    to a target HAMMER filesystem the code checks that the target is a PFS
    slave with the same shared UUID as the master's UUID.
    I want a feature that asks the user whether he wants to create a
    conforming PFS on the target at that point, if the target directory
    does not exist, instead of exiting with an error.
    i.e. this would take away all the effort of having to create a pfs-slave
    and assign the correct UUID to it.  It takes about 60 seconds and some
    cutting and pasting to do that manually now... not long, but we can
    make it ultra convenient.
    You would simply run the command and it would ask if you wanted to create
    a new PFS on the target instead of exiting.  You would say 'yes', and
    poof, new mirror slave target :-).
Appended is a first patch. I'm unsure if this is the correct way to do
it, as the protocol is modified, and I think it's not easily possible to
read "yes" or "no" from the keyboard in mirror-write (when run via ssh).
Funny, when I run mirror-copy several times I get a panic (screenshot 
appended). I don't think this can be related to my changes...

Regards,

  Michael
Index: cmd_mirror.c
===================================================================
RCS file: /home/dcvs/src/sbin/hammer/cmd_mirror.c,v
retrieving revision 1.15
diff -u -r1.15 cmd_mirror.c
--- cmd_mirror.c	9 Sep 2008 23:34:21 -0000	1.15
+++ cmd_mirror.c	10 Oct 2008 15:23:55 -0000
@@ -46,8 +46,8 @@
 			 hammer_ioc_mrecord_any_t mrec, int bytes);
 static void generate_mrec_header(int fd, int fdout, int pfs_id,
 			 hammer_tid_t *tid_begp, hammer_tid_t *tid_endp);
-static int validate_mrec_header(int fd, int fdin, int is_target, int pfs_id,
-			 struct hammer_ioc_mrecord_head *pickup,
+static int validate_mrec_header(int fd, hammer_ioc_mrecord_any_t mrec, 
+			 int is_target, int pfs_id,
 			 hammer_tid_t *tid_begp, hammer_tid_t *tid_endp);
 static void update_pfs_snapshot(int fd, hammer_tid_t snapshot_tid, int pfs_id);
 static ssize_t writebw(int fd, const void *buf, size_t nbytes,
@@ -106,14 +106,26 @@
 	bwcount = 0;
 
 	/*
+	 * Send initial header for the purpose to determine shared-uuid.
+	 */
+	generate_mrec_header(fd, 1, pfs.pfs_id, NULL, NULL);
+
+	/*
 	 * In 2-way mode the target will send us a PFS info packet
 	 * first.  Use the target's current snapshot TID as our default
 	 * begin TID.
 	 */
 	mirror.tid_beg = 0;
 	if (TwoWayPipeOpt) {
-		n = validate_mrec_header(fd, 0, 0, pfs.pfs_id, &pickup,
+		mrec = read_mrecord(0, &error, &pickup);
+		if (mrec == NULL) {
+			if (error == 0)
+				fprintf(stderr, "validate_mrec_header: short read\n");
+			exit(1);
+		}
+		n = validate_mrec_header(fd, mrec, 0, pfs.pfs_id, 
 					 NULL, &mirror.tid_beg);
+		free(mrec); mrec = NULL;
 		if (n < 0) {	/* got TERM record */
 			relpfs(fd, &pfs);
 			return;
@@ -298,6 +310,33 @@
 	fprintf(stderr, "Mirror-read %s succeeded\n", filesystem);
 }
 
+static void
+create_pfs(const char *filesystem, uuid_t *s_uuid)
+{
+	fprintf(stderr, "PFS slave %s does not exist. Do you want" 
+			" to create id? (yes|no) ", filesystem);
+	fflush(stderr);
+	/* XXX: How to read from keyboard? */
+
+	u_int32_t status;
+	char *shared_uuid = NULL;
+	uuid_to_string(s_uuid, &shared_uuid, &status);
+
+	char *cmd = NULL;
+	asprintf(&cmd, "/sbin/hammer pfs-slave '%s' shared-uuid=%s 1>&2",
+		 filesystem, shared_uuid); 
+	free(shared_uuid);
+
+	if (cmd == NULL) {
+		fprintf(stderr, "Failed to alloc memory\n");
+		exit(1);
+	}
+	if (system(cmd) != 0) {
+		fprintf(stderr, "Failed to create PFS\n");
+	}
+	free(cmd);
+}
+
 /*
  * Pipe the mirroring data stream on stdin to the HAMMER VFS, adding
  * some additional packet types to negotiate TID ranges and to verify
@@ -337,6 +376,7 @@
 	int error;
 	int fd;
 	int n;
+	struct stat st;
 
 	if (ac != 1)
 		mirror_usage(1);
@@ -351,6 +391,42 @@
 	hammer_key_end_init(&mirror.key_end);
 	mirror.key_end = mirror.key_beg;
 
+	/*
+	 * Read initial packet
+	 */
+	mrec = read_mrecord(0, &error, &pickup);
+	pickup.signature = 0;
+	pickup.type = 0;
+	if (mrec == NULL) {
+		if (error == 0)
+			fprintf(stderr, "validate_mrec_header: short read\n");
+		exit(1);
+	}
+	/*
+	 * Validate packet
+	 */
+	if (mrec->head.type == HAMMER_MREC_TYPE_TERM) {
+		return;
+	}
+	if (mrec->head.type != HAMMER_MREC_TYPE_PFSD) {
+		fprintf(stderr, "validate_mrec_header: did not get expected "
+				"PFSD record type\n");
+		exit(1);
+	}
+	if (mrec->head.rec_size != sizeof(mrec->pfs)) {
+		fprintf(stderr, "validate_mrec_header: unexpected payload "
+				"size\n");
+		exit(1);
+	}
+
+	/*
+	 * Create slave PFS if it doesn't yet exist
+	 */
+	if (lstat(filesystem, &st) != 0) {
+		create_pfs(filesystem, &mrec->pfs.pfsd.shared_uuid);
+	}
+	free(mrec); mrec = NULL;
+
 	fd = getpfs(&pfs, filesystem);
 
 	/*
@@ -368,8 +444,15 @@
 	 * Read and process the PFS header.  The source informs us of
 	 * the TID range the stream represents.
 	 */
-	n = validate_mrec_header(fd, 0, 1, pfs.pfs_id, &pickup,
+	mrec = read_mrecord(0, &error, &pickup);
+	if (mrec == NULL) {
+		if (error == 0)
+			fprintf(stderr, "validate_mrec_header: short read\n");
+		exit(1);
+	}
+	n = validate_mrec_header(fd, mrec, 1, pfs.pfs_id, 
 				 &mirror.tid_beg, &mirror.tid_end);
+	free(mrec); mrec = NULL; 
 	if (n < 0) {	/* got TERM record */
 		relpfs(fd, &pfs);
 		return;
@@ -948,14 +1031,12 @@
  * return -1 if we got a TERM record
  */
 static int
-validate_mrec_header(int fd, int fdin, int is_target, int pfs_id,
-		     struct hammer_ioc_mrecord_head *pickup,
+validate_mrec_header(int fd, hammer_ioc_mrecord_any_t mrec, 
+		     int is_target, int pfs_id,
 		     hammer_tid_t *tid_begp, hammer_tid_t *tid_endp)
 {
 	struct hammer_ioc_pseudofs_rw pfs;
 	struct hammer_pseudofs_data pfsd;
-	hammer_ioc_mrecord_any_t mrec;
-	int error;
 
 	/*
 	 * Get the PFSD info from the target filesystem.
@@ -973,18 +1054,9 @@
 		fprintf(stderr, "mirror-write: HAMMER pfs version mismatch!\n");
 		exit(1);
 	}
-
-	mrec = read_mrecord(fdin, &error, pickup);
-	if (mrec == NULL) {
-		if (error == 0)
-			fprintf(stderr, "validate_mrec_header: short read\n");
-		exit(1);
-	}
 	if (mrec->head.type == HAMMER_MREC_TYPE_TERM) {
-		free(mrec);
 		return(-1);
 	}
-
 	if (mrec->head.type != HAMMER_MREC_TYPE_PFSD) {
 		fprintf(stderr, "validate_mrec_header: did not get expected "
 				"PFSD record type\n");
@@ -1019,7 +1091,6 @@
 		*tid_begp = mrec->pfs.pfsd.sync_beg_tid;
 	if (tid_endp)
 		*tid_endp = mrec->pfs.pfsd.sync_end_tid;
-	free(mrec);
 	return(0);
 }
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: jpg00000.jpg
Type: application/octet-stream
Size: 122208 bytes
Desc: ""
URL: <http://lists.dragonflybsd.org/pipermail/kernel/attachments/20081010/e3b48634/attachment-0020.obj>


More information about the Kernel mailing list