[DRBD-cvs] svn commit by phil - r2975 - in trunk: . drbd drbd/linux user - svnp run...

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Thu Jul 19 13:09:31 CEST 2007


Author: phil
Date: 2007-07-19 13:09:26 +0200 (Thu, 19 Jul 2007)
New Revision: 2975

Modified:
   trunk/
   trunk/ROADMAP
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_nl.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/linux/drbd_nl.h
   trunk/drbd/linux/drbd_tag_magic.h
   trunk/user/Makefile
   trunk/user/drbdadm_main.c
   trunk/user/drbdmeta.c
   trunk/user/drbdmeta_parser.h
   trunk/user/drbdmeta_scanner.fl
   trunk/user/drbdmeta_unfinished_rewrite.c
   trunk/user/drbdsetup.c
Log:
svnp run...



Property changes on: trunk
___________________________________________________________________
Name: propagate:at:1
   - 2950
   + 2974

Modified: trunk/ROADMAP
===================================================================
--- trunk/ROADMAP	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/ROADMAP	2007-07-19 11:09:26 UTC (rev 2975)
@@ -17,7 +17,10 @@
    with broken TSO engines during a clusters test phase. For production
    this should be turned off of course.
 
+5  startup / become primary.
 
+6  allow device,disk and meta-disk to be on resource level...
+
 Open Items from 8.0 (I am not shure if it makes sense to address this at all):
 ===================
 

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/drbd_int.h	2007-07-19 11:09:26 UTC (rev 2975)
@@ -50,6 +50,8 @@
 extern int fault_devs;
 #endif
 
+extern char usermode_helper[];
+
 #include <linux/major.h>
 #ifdef DRBD_MAJOR
 # warning "FIXME. DRBD_MAJOR is now officially defined in major.h"

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/drbd_main.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -117,6 +117,14 @@
 module_param(trace_devs,int,0644);
 #endif
 
+
+// Module parameter for setting the user mode helper program
+// to run. Default is /sbin/drbdadm
+
+char usermode_helper[80] = "/sbin/drbdadm";
+
+module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0644);
+
 // global panic flag
 volatile int drbd_did_panic = 0;
 

Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/drbd_nl.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -80,7 +80,7 @@
 #define STRING(pn,pr,member,len) \
 	case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \
 		 arg->member ## _len = dlen; \
-		 memcpy(arg->member,tags,dlen); \
+		 memcpy(arg->member,tags,min_t(size_t,dlen,len)); \
 		 break;
 #include "linux/drbd_nl.h"
 
@@ -164,7 +164,7 @@
 int drbd_khelper(drbd_dev *mdev, char* cmd)
 {
 	char mb[12];
-	char *argv[] = {"/sbin/drbdadm", cmd, mb, NULL };
+	char *argv[] = {usermode_helper, cmd, mb, NULL };
 	static char *envp[] = { "HOME=/",
 				"TERM=linux",
 				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
@@ -172,8 +172,10 @@
 
 	snprintf(mb,12,"minor-%d",mdev_to_minor(mdev));
 
+	INFO("helper command: %s %s\n",usermode_helper,cmd);
+
 	drbd_bcast_ev_helper(mdev,cmd);
-	return call_usermodehelper("/sbin/drbdadm",argv,envp,1);
+	return call_usermodehelper(usermode_helper,argv,envp,1);
 }
 
 drbd_disks_t drbd_try_outdate_peer(drbd_dev *mdev)
@@ -318,6 +320,10 @@
 
 	if (new_role == Secondary) {
 		set_disk_ro(mdev->vdisk, TRUE );
+		if ( inc_local(mdev) ) {
+			mdev->bc->md.uuid[Current] &= ~(u64)1;
+			dec_local(mdev);
+		}
 	} else {
 		if(inc_net(mdev)) {
 			mdev->net_conf->want_lose = 0;
@@ -328,10 +334,14 @@
 		mdev->this_bdev->bd_disk = mdev->vdisk;
 		 */
 
-		if ( ( ( mdev->state.conn < Connected ||
-			 mdev->state.pdsk <= Failed ) &&
-		       mdev->bc->md.uuid[Bitmap] == 0) || forced ) {
-			drbd_uuid_new_current(mdev);
+		if ( inc_local(mdev) ) {
+			if ( ( ( mdev->state.conn < Connected ||
+				 mdev->state.pdsk <= Failed ) &&
+			       mdev->bc->md.uuid[Bitmap] == 0) || forced ) {
+				drbd_uuid_new_current(mdev);
+			}
+			mdev->bc->md.uuid[Current] |=  (u64)1;
+			dec_local(mdev);
 		}
 	}
 
@@ -1001,6 +1011,13 @@
 	}
 
 	drbd_bm_unlock(mdev);
+
+	if(inc_local_if_state(mdev,Attaching)) {
+		if(mdev->state.role == Primary) mdev->bc->md.uuid[Current] |=  (u64)1;
+		else                            mdev->bc->md.uuid[Current] &= ~(u64)1;
+		dec_local(mdev);
+	}
+
 	drbd_md_sync(mdev);
 
 	reply->ret_code = retcode;

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/drbd_receiver.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -357,6 +357,7 @@
 	spin_lock_irq(&mdev->req_lock);
 	while(!list_empty(list)) {
 		le = list->next;
+		list_del(le);
 		e = list_entry(le, struct Tl_epoch_entry, w.list);
 		drbd_free_ee(mdev,e);
 		count++;
@@ -2496,8 +2497,8 @@
 	if (nconn == WFReportParams ) nconn = Connected;
 
 	if (mdev->p_uuid && oconn <= Connected &&
-	    inc_local_if_state(mdev,Negotiating) &&
-	    peer_state.disk >= Negotiating) {
+	    peer_state.disk >= Negotiating &&
+	    inc_local_if_state(mdev,Negotiating) ) {
 		nconn=drbd_sync_handshake(mdev,peer_state.role,peer_state.disk);
 		dec_local(mdev);
 
@@ -2561,7 +2562,9 @@
 	if (drbd_recv(mdev, h->payload, h->length) != h->length)
 		return FALSE;
 
-	drbd_uuid_set(mdev,Current,be64_to_cpu(p->uuid));
+	/* Here the _drbd_uuid_ functions are right, current should
+	   _not_ be rotated into the history */
+	_drbd_uuid_set(mdev,Current,be64_to_cpu(p->uuid));
 	_drbd_uuid_set(mdev,Bitmap,0UL);
 
 	drbd_start_resync(mdev,SyncTarget);

Modified: trunk/drbd/linux/drbd_nl.h
===================================================================
--- trunk/drbd/linux/drbd_nl.h	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/linux/drbd_nl.h	2007-07-19 11:09:26 UTC (rev 2975)
@@ -19,8 +19,8 @@
 
 PACKET(disk_conf, 3,
 	INT64(		2,	T_MAY_IGNORE,	disk_size)
-	STRING(		3,	T_MANDATORY,	backing_dev,	32)
-	STRING(		4,	T_MANDATORY,	meta_dev,	32)
+	STRING(		3,	T_MANDATORY,	backing_dev,	128)
+	STRING(		4,	T_MANDATORY,	meta_dev,	128)
 	INTEGER(	5,	T_MANDATORY,	meta_dev_idx)
 	INTEGER(	6,	T_MAY_IGNORE,	on_io_error)
 	INTEGER(	7,	T_MAY_IGNORE,	fencing)

Modified: trunk/drbd/linux/drbd_tag_magic.h
===================================================================
--- trunk/drbd/linux/drbd_tag_magic.h	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/drbd/linux/drbd_tag_magic.h	2007-07-19 11:09:26 UTC (rev 2975)
@@ -62,15 +62,16 @@
 struct tag {
 	const char* name;
 	int type_n_flags;
+	int max_len;
 };
 
 // declare tag names
 #define PACKET(name, number, fields) fields
 const struct tag tag_descriptions[] = {
-#define INTEGER(pn,pr,member)    [ pn ] = { #member, TT_INTEGER | pr },
-#define INT64(pn,pr,member)      [ pn ] = { #member, TT_INT64   | pr },
-#define BIT(pn,pr,member)        [ pn ] = { #member, TT_BIT     | pr },
-#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING  | pr },
+#define INTEGER(pn,pr,member)    [ pn ] = { #member, TT_INTEGER | pr, sizeof(int)   },
+#define INT64(pn,pr,member)      [ pn ] = { #member, TT_INT64   | pr, sizeof(__u64) },
+#define BIT(pn,pr,member)        [ pn ] = { #member, TT_BIT     | pr, sizeof(int)   },
+#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING  | pr, len           },
 #include "drbd_nl.h"
 };
 

Modified: trunk/user/Makefile
===================================================================
--- trunk/user/Makefile	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/Makefile	2007-07-19 11:09:26 UTC (rev 2975)
@@ -45,23 +45,28 @@
 drbdadm: $(drbdadm-obj)
 	$(CC) -o $@ $^
 
+# for debugging:
+# 	LANG=C LC_ALL=C flex -d -b -s -odrbdadm_scanner.c drbdadm_scanner.fl
+
 drbdadm_scanner.c: drbdadm_scanner.fl drbdadm_parser.h
 	flex -s -odrbdadm_scanner.c drbdadm_scanner.fl
 
 drbdmeta_scanner.c: drbdmeta_scanner.fl drbdmeta_parser.h
-	flex -odrbdmeta_scanner.c drbdmeta_scanner.fl
+	flex -s -odrbdmeta_scanner.c drbdmeta_scanner.fl
 
-# for debug:	flex -d -s -odrbdadm_scanner.c drbdadm_scanner.fl
-
 drbdsetup: $(drbdsetup-obj)
 	$(CC) -o $@ $^
 
 drbdmeta: $(drbdmeta-obj)
 	$(CC) -o $@ $^
 
+drbdmeta_unfinished_rewrite: CFLAGS += -fno-strict-aliasing
+drbdmeta_unfinished_rewrite: drbdmeta_unfinished_rewrite.o drbdmeta_scanner.o drbdtool_common.o drbd_buildtag.o
+	$(CC) -o $@ $^
+
 clean:
 	rm -f drbdadm_scanner.c drbdmeta_scanner.c
-	rm -f drbdsetup drbdadm drbdmeta *.o
+	rm -f drbdsetup drbdadm drbdmeta drbdmeta_unfinished_rewrite *.o
 	rm -f drbd_buildtag.c drbd_strings.c
 	rm -f *~
 
@@ -94,4 +99,5 @@
 drbdadm_scanner.o:                   drbdadm.h               drbdadm_parser.h
 drbdsetup.o:       drbdtool_common.h           ../drbd/linux/drbd_limits.h
 drbdmeta.o:        drbdtool_common.h drbd_endian.h
+drbdmeta_unfinished_rewrite.o:        drbdtool_common.h drbd_endian.h
 drbdadm_usage_cnt.o: drbdadm.h drbd_endian.h

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdadm_main.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -1664,6 +1664,8 @@
   struct adm_cmd *cmd;
   struct d_resource *res,*tmp;
   char *env_drbd_nodename = NULL;
+  int is_dump_xml;
+  int is_dump;
 
   drbdsetup=NULL;
   drbdmeta=NULL;
@@ -1874,14 +1876,15 @@
 
   uc_node(global_options.usage_count);
 
+  is_dump_xml = (cmd->function == adm_dump_xml);
+  is_dump = (is_dump_xml || cmd->function == adm_dump);
+  if (!is_dump || dry_run) expand_common();
+
   if(cmd->res_name_required)
     {
-      int is_dump_xml = (cmd->function == adm_dump_xml);
-      int is_dump = (is_dump_xml || cmd->function == adm_dump);
       if (optind + 1 > argc && !is_dump)
         print_usage_and_exit("missing arguments"); // arguments missing.
 
-      if (!is_dump || dry_run) expand_common();
       global_validate();
       if (!is_dump) {
 	if(!config_valid) exit(E_config_invalid);

Modified: trunk/user/drbdmeta.c
===================================================================
--- trunk/user/drbdmeta.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdmeta.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -777,6 +777,7 @@
 int meta_show_gi(struct format *cfg, char **argv, int argc);
 int meta_dump_md(struct format *cfg, char **argv, int argc);
 int meta_restore_md(struct format *cfg, char **argv, int argc);
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc);
 int meta_create_md(struct format *cfg, char **argv, int argc);
 int meta_wipe_md(struct format *cfg, char **argv, int argc);
 int meta_outdate(struct format *cfg, char **argv, int argc);
@@ -791,6 +792,7 @@
 	{"show-gi", 0, meta_show_gi, 1},
 	{"dump-md", 0, meta_dump_md, 1},
 	{"restore-md", "file", meta_restore_md, 1},
+	{"verify-dump", "file", meta_verify_dump_file, 1},
 	{"create-md", 0, meta_create_md, 1},
 	{"wipe-md", 0, meta_wipe_md, 1},
 	{"outdate", 0, meta_outdate, 1},
@@ -1772,15 +1774,90 @@
 	return cfg->ops->close(cfg);
 }
 
-void md_parse_error(const char *etext)
+void md_parse_error(int expected_token, int seen_token,const char *etext)
 {
-	fprintf(stderr,"Parse error '%s' expected.",etext);
+	if (!etext) {
+		switch(expected_token) {
+		/* leading space indicates to strip off "expected" below */
+		default : etext = " invalid/unexpected token!"; break;
+		case 0  : etext = "end of file"; break;
+		case ';': etext = "semicolon (;)"; break;
+		case '{': etext = "opening brace ({)"; break;
+		case '}': etext = "closing brace (})"; break;
+		case TK_BM:
+			etext = "keyword 'bm'"; break;
+		case TK_BM_BYTE_PER_BIT:
+			etext = "keyword 'bm-byte-per-bit'"; break;
+		case TK_DEVICE_UUID:
+			etext = "keyword 'device-uuid'"; break;
+		case TK_FLAGS:
+			etext = "keyword 'flags'"; break;
+		case TK_GC:
+			etext = "keyword 'gc'"; break;
+		case TK_LA_SIZE:
+			etext = "keyword 'la-size-sect'"; break;
+		case TK_TIMES:
+			etext = "keyword 'times'"; break;
+		case TK_UUID:
+			etext = "keyword 'uuid'"; break;
+		case TK_VERSION:
+			etext = "keyword 'version'"; break;
+		case TK_NUM:
+			etext = "number ([0-9], up to 20 digits)"; break;
+		case TK_STRING:
+			etext = "short quoted string "
+			        "(\"..up to 20 characters, no newline..\")";
+				break;
+		case TK_U32:
+			etext = "an 8-digit hex number"; break;
+		case TK_U64:
+			etext = "a 16-digit hex number"; break;
+		}
+	}
+	fflush(stdout);
+	fprintf(stderr,"Parse error in line %u: %s%s",
+		yylineno, etext,
+		(etext[0] == ' ' ? ":" : " expected")
+		);
+
+	switch(seen_token) {
+	case 0:
+		fprintf(stderr, ", but end of file encountered\n"); break;
+
+	case   1 ...  58: /* ord(';') == 58 */
+	case  60 ... 122: /* ord('{') == 123 */
+	case 124:         /* ord('}') == 125 */
+	case 126 ... 257:
+		/* oopsie. these should never be returned! */
+		fprintf(stderr, "; got token value %u (this should never happen!)\n", seen_token); break;
+		break;
+
+	case TK_INVALID_CHAR:
+		fprintf(stderr,"; got invalid input character '\\x%02x' [%c]\n",
+			(unsigned char)yylval.txt[0], yylval.txt[0]);
+		break;
+	case ';': case '{': case '}':
+		fprintf(stderr, ", not '%c'\n", seen_token); break;
+	case TK_NUM:
+	case TK_U32:
+	case TK_U64:
+		fprintf(stderr, ", not some number\n"); break;
+	case TK_INVALID:
+		/* already reported by scanner */
+		fprintf(stderr,"\n"); break;
+	default:
+		fprintf(stderr, ", not '%s'\n", yylval.txt);
+	}
 	exit(10);
 }
 
-#define EXP(TOKEN) if(yylex() != TOKEN) md_parse_error( #TOKEN );
+static void EXP(int expected_token) {
+	int tok = yylex();
+	if (tok != expected_token)
+		md_parse_error(expected_token, tok, NULL);
+}
 
-int meta_restore_md(struct format *cfg, char **argv, int argc)
+int verify_dumpfile_or_restore(struct format *cfg, char **argv, int argc, int parse_only)
 {
 	int i,times;
 	int err;
@@ -1794,7 +1871,7 @@
 		}
 	}
 
-	if (!cfg->ops->open(cfg)) {
+	if (!parse_only && !cfg->ops->open(cfg)) {
 		if (!confirmed("Valid meta-data in place, overwrite?"))
 			return -1;
 	}
@@ -1837,29 +1914,49 @@
 	bm = (le_u64 *)cfg->on_disk.bm;
 	i = 0;
 	while(1) {
-		switch(yylex()) {
+		int tok = yylex();
+		switch(tok) {
 		case TK_U64:
+			EXP(';');
+			/* NOTE:
+			 * even though this EXP(';'); already advanced
+			 * to the next token, yylval will *not* be updated
+			 * for * ';', so it is still valid.
+			 *
+			 * This seemed to be the least ugly way to implement a
+			 * "parse_only" functionality without ugly if-branches
+			 * or the maintenance nightmare of code duplication */
+			if (parse_only) break;
 			bm[i].le = cpu_to_le64(yylval.u64);
 			i++;
-			EXP(';');
 			break;
 		case TK_NUM:
+			times = yylval.u64;
 			EXP(TK_TIMES);
-			times = yylval.u64;
 			EXP(TK_U64);
+			EXP(';');
+			if (parse_only) break;
 			value.le = cpu_to_le64(yylval.u64);
-			EXP(';');
 			while(times--) bm[i++] = value;
 			break;
 		case '}':
 			goto break_loop;
 		default:
-			md_parse_error("TK_U64, TK_NUM or }");
+			md_parse_error(0 /* ignored, since etext is set */,
+				tok, "repeat count, 16-digit hex number, or closing brace (})");
 			goto break_loop;
 		}
 	}
 	break_loop:
 
+	/* there should be no trailing garbage in the input file */
+	EXP(0);
+
+	if (parse_only) {
+		printf("input file parsed ok\n");
+		return 0;
+	}
+
 	err = cfg->ops->md_cpu_to_disk(cfg);
 	err = cfg->ops->close(cfg) || err;
 	if (err) {
@@ -1872,8 +1969,16 @@
 	return 0;
 }
 
-#undef EXP
+int meta_restore_md(struct format *cfg, char **argv, int argc)
+{
+	return verify_dumpfile_or_restore(cfg,argv,argc,0);
+}
 
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc)
+{
+	return verify_dumpfile_or_restore(cfg,argv,argc,1);
+}
+
 int md_convert_07_to_08(struct format *cfg)
 {
 	int i,j=1;
@@ -2446,15 +2551,16 @@
 struct sigaction sa;
 static void signal_handler(int signo)
 {
-  fprintf(stderr,"%s\nThis feels like a bug.\n",
-		  (signo == SIGBUS)
-		  ? "SIGBUS: out of band access to the mmaped area!"
-		  : "SIGSEGV!");
-  fprintf(stderr,"debug hint: last memset: %s:%u: @%p %llu\n"
-		 "Sorry.\n",
-		 last_memset_func, last_memset_line,
-		 last_memset_target, (unsigned long long)last_memset_n);
-  exit(128 | signo);
+	fflush(stdout);
+	fprintf(stderr,"%s\nThis feels like a bug.\n",
+		(signo == SIGBUS)
+		? "SIGBUS: out of band access to the mmaped area!"
+		: "SIGSEGV!");
+	fprintf(stderr,"debug hint: last memset: %s:%u: @%p %llu\n"
+		"Sorry.\n",
+		last_memset_func, last_memset_line,
+		last_memset_target, (unsigned long long)last_memset_n);
+	exit(128 | signo);
 }
 
 int main(int argc, char **argv)

Modified: trunk/user/drbdmeta_parser.h
===================================================================
--- trunk/user/drbdmeta_parser.h	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdmeta_parser.h	2007-07-19 11:09:26 UTC (rev 2975)
@@ -8,6 +8,7 @@
 #define YY_NO_UNPUT 1
 
 extern YYSTYPE yylval;
+extern int yylineno;
 
 enum yytokentype {
 	TK_STRING = 258,
@@ -23,6 +24,8 @@
 	TK_DEVICE_UUID,
 	TK_TIMES,
 	TK_FLAGS,
+	TK_INVALID,
+	TK_INVALID_CHAR,
 };
 
 /* avoid compiler warnings about implicit declaration */

Modified: trunk/user/drbdmeta_scanner.fl
===================================================================
--- trunk/user/drbdmeta_scanner.fl	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdmeta_scanner.fl	2007-07-19 11:09:26 UTC (rev 2975)
@@ -4,45 +4,76 @@
 #include "drbdmeta_parser.h"
 
 static void unescape(void);
+static void bad_token(char*);
 
 //#define DP printf("%s ",yytext);
 #define DP
+#define CP yylval.txt=yytext
 #define YY_NO_UNPUT 1
 static void yyunput (int c, register char * yy_bp ) __attribute((unused));
 
 %}
 
 %option noyywrap
+%option yylineno
 
-WS		[ \t\n]
+/* remember to avoid backing up.
+ * tell user about bad/unexpected tokens. */
+
+OP		[{};]
+WS		[ \r\t\n]
 COMMENT		\#[^\n]*
-NUM		[0-9]{1,10}
+
+/* 1<<63 is 19 digits. has to be enough.
+ * 20 digits would risk overflow of 64bit unsigned int */
+NUM		[0-9]{1,19}
+NUM_TOO_LONG	{NUM}[0-9]
+
 U64		0x[0-9A-Fa-f]{16}
 U32		0x[0-9A-Fa-f]{8}
-OP		[{};]
-STRING		\"[^\"]*\"
+INVALID_HEX	0x[0-9A-Fa-f]{0,17}
 
+STRING		\"[^\"\r\n]{1,20}\"
+EMPTY_STRING    \"\"?
+INVALID_STRING  \"[^\"\r\n]{1,20}
+
+INVALID_TOKEN	 [-_a-zA-Z0-9]{1,100}
+INVALID_CHAR    [^-_a-zA-Z0-9 \t\r\n\";{}]
+
 %%
 
-{WS}
-{COMMENT}
+{WS}		/* skip silently */
+{COMMENT}	/* skip silently */
 {OP}		DP; return yytext[0];
-{STRING}	unescape(); yylval.txt=yytext; DP; return TK_STRING;
+{STRING}	unescape(); DP; CP; return TK_STRING;
 {U64}		yylval.u64 = strto_u64(yytext, NULL, 16); DP; return TK_U64;
 {U32}		yylval.u64 = strto_u64(yytext, NULL, 16); DP; return TK_U32;
 {NUM}		yylval.u64 = strto_u64(yytext, NULL, 10); DP; return TK_NUM;
-gc		DP; return TK_GC;
-bm		DP; return TK_BM;
-uuid		DP; return TK_UUID;
-version		DP; return TK_VERSION;
-la-size-sect	DP; return TK_LA_SIZE;
-bm-byte-per-bit DP; return TK_BM_BYTE_PER_BIT;
-device-uuid	DP; return TK_DEVICE_UUID;
-times		DP; return TK_TIMES;
-flags		DP; return TK_FLAGS;
+gc		DP; CP; return TK_GC;
+bm		DP; CP; return TK_BM;
+uuid		DP; CP; return TK_UUID;
+version		DP; CP; return TK_VERSION;
+la-size-sect	DP; CP; return TK_LA_SIZE;
+bm-byte-per-bit DP; CP; return TK_BM_BYTE_PER_BIT;
+device-uuid	DP; CP; return TK_DEVICE_UUID;
+times		DP; CP; return TK_TIMES;
+flags		DP; CP; return TK_FLAGS;
 
+{INVALID_STRING} CP; bad_token("invalid string"); return TK_INVALID;
+{EMPTY_STRING}	 CP; bad_token("invalid string"); return TK_INVALID;
+{INVALID_HEX}	 CP; bad_token("invalid hex number (only 8 or 16 hex digits accepted)"); return TK_INVALID;
+{NUM_TOO_LONG}	 CP; bad_token("number too big"); return TK_INVALID;
+{INVALID_TOKEN}	 CP; bad_token("unknown token"); return TK_INVALID;
+{INVALID_CHAR}	 CP; return TK_INVALID_CHAR;
+
 %%
 
+static void bad_token(char *msg)
+{
+	fflush(stdout);
+	fprintf(stderr,"line %u: %s: %s ...\n", yylineno, msg, yytext);
+}
+
 static void unescape(void)
 {
   /* backslash escapes from string */

Modified: trunk/user/drbdmeta_unfinished_rewrite.c
===================================================================
--- trunk/user/drbdmeta_unfinished_rewrite.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdmeta_unfinished_rewrite.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -593,6 +593,7 @@
 int meta_show_gi(struct format *cfg, char **argv, int argc);
 int meta_dump_md(struct format *cfg, char **argv, int argc);
 int meta_restore_md(struct format *cfg, char **argv, int argc);
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc);
 int meta_create_md(struct format *cfg, char **argv, int argc);
 int meta_wipe_md(struct format *cfg, char **argv, int argc);
 int meta_outdate(struct format *cfg, char **argv, int argc);
@@ -606,6 +607,7 @@
 	{"show-gi", 0, meta_show_gi, 1},
 	{"dump-md", 0, meta_dump_md, 1},
 	{"restore-md", "file", meta_restore_md, 1},
+	{"verify-dump", "file", meta_verify_dump_file, 1},
 	{"create-md", 0, meta_create_md, 1},
 	{"wipe-md", 0, meta_wipe_md, 1},
 	{"outdate", 0, meta_outdate, 1},
@@ -1505,15 +1507,90 @@
 	return cfg->ops->close(cfg);
 }
 
-void md_parse_error(const char *etext)
+void md_parse_error(int expected_token, int seen_token,const char *etext)
 {
-	fprintf(stderr,"Parse error '%s' expected.",etext);
+	if (!etext) {
+		switch(expected_token) {
+		/* leading space indicates to strip off "expected" below */
+		default : etext = " invalid/unexpected token!"; break;
+		case 0  : etext = "end of file"; break;
+		case ';': etext = "semicolon (;)"; break;
+		case '{': etext = "opening brace ({)"; break;
+		case '}': etext = "closing brace (})"; break;
+		case TK_BM:
+			etext = "keyword 'bm'"; break;
+		case TK_BM_BYTE_PER_BIT:
+			etext = "keyword 'bm-byte-per-bit'"; break;
+		case TK_DEVICE_UUID:
+			etext = "keyword 'device-uuid'"; break;
+		case TK_FLAGS:
+			etext = "keyword 'flags'"; break;
+		case TK_GC:
+			etext = "keyword 'gc'"; break;
+		case TK_LA_SIZE:
+			etext = "keyword 'la-size-sect'"; break;
+		case TK_TIMES:
+			etext = "keyword 'times'"; break;
+		case TK_UUID:
+			etext = "keyword 'uuid'"; break;
+		case TK_VERSION:
+			etext = "keyword 'version'"; break;
+		case TK_NUM:
+			etext = "number ([0-9], up to 20 digits)"; break;
+		case TK_STRING:
+			etext = "short quoted string "
+			        "(\"..up to 20 characters, no newline..\")";
+				break;
+		case TK_U32:
+			etext = "an 8-digit hex number"; break;
+		case TK_U64:
+			etext = "a 16-digit hex number"; break;
+		}
+	}
+	fflush(stdout);
+	fprintf(stderr,"Parse error in line %u: %s%s",
+		yylineno, etext,
+		(etext[0] == ' ' ? ":" : " expected")
+		);
+
+	switch(seen_token) {
+	case 0:
+		fprintf(stderr, ", but end of file encountered\n"); break;
+
+	case   1 ...  58: /* ord(';') == 58 */
+	case  60 ... 122: /* ord('{') == 123 */
+	case 124:         /* ord('}') == 125 */
+	case 126 ... 257:
+		/* oopsie. these should never be returned! */
+		fprintf(stderr, "; got token value %u (this should never happen!)\n", seen_token); break;
+		break;
+
+	case TK_INVALID_CHAR:
+		fprintf(stderr,"; got invalid input character '\\x%02x' [%c]\n",
+			(unsigned char)yylval.txt[0], yylval.txt[0]);
+		break;
+	case ';': case '{': case '}':
+		fprintf(stderr, ", not '%c'\n", seen_token); break;
+	case TK_NUM:
+	case TK_U32:
+	case TK_U64:
+		fprintf(stderr, ", not some number\n"); break;
+	case TK_INVALID:
+		/* already reported by scanner */
+		fprintf(stderr,"\n"); break;
+	default:
+		fprintf(stderr, ", not '%s'\n", yylval.txt);
+	}
 	exit(10);
 }
 
-#define EXP(TOKEN) if(yylex() != TOKEN) md_parse_error( #TOKEN );
+static void EXP(int expected_token) {
+	int tok = yylex();
+	if (tok != expected_token)
+		md_parse_error(expected_token, tok, NULL);
+}
 
-int meta_restore_md(struct format *cfg, char **argv, int argc)
+int verify_dumpfile_or_restore(struct format *cfg, char **argv, int argc, int parse_only)
 {
 	int i,times;
 	int err;
@@ -1528,7 +1605,7 @@
 		}
 	}
 
-	if (!cfg->ops->open(cfg)) {
+	if (!parse_only && !cfg->ops->open(cfg)) {
 		if (!confirmed("Valid meta-data in place, overwrite?"))
 			return -1;
 	}
@@ -1572,8 +1649,19 @@
 	i = 0;
 	bm_on_disk_off = cfg->bm_offset;
 	while(1) {
-		switch(yylex()) {
+		int tok = yylex();
+		switch(tok) {
 		case TK_U64:
+			EXP(';');
+			/* NOTE:
+			 * even though this EXP(';'); already advanced
+			 * to the next token, yylval will *not* be updated
+			 * for * ';', so it is still valid.
+			 *
+			 * This seemed to be the least ugly way to implement a
+			 * "parse_only" functionality without ugly if-branches
+			 * or the maintenance nightmare of code duplication */
+			if (parse_only) break;
 			bm[i].le = cpu_to_le64(yylval.u64);
 			if (++i == buffer_size/sizeof(*bm)) {
 				pwrite_or_die(cfg->md_fd, on_disk_buffer,
@@ -1582,14 +1670,14 @@
 				bm_on_disk_off += buffer_size;
 				i = 0;
 			}
-			EXP(';');
 			break;
 		case TK_NUM:
+			times = yylval.u64;
 			EXP(TK_TIMES);
-			times = yylval.u64;
 			EXP(TK_U64);
+			EXP(';');
+			if (parse_only) break;
 			value.le = cpu_to_le64(yylval.u64);
-			EXP(';');
 			while(times--) {
 				bm[i] = value;
 				if (++i == buffer_size/sizeof(*bm)) {
@@ -1604,11 +1692,22 @@
 		case '}':
 			goto break_loop;
 		default:
-			md_parse_error("TK_U64, TK_NUM or }");
+			md_parse_error(0 /* ignored, since etext is set */,
+				tok, "repeat count, 16-digit hex number, or closing brace (})");
 			goto break_loop;
 		}
 	}
 	break_loop:
+
+	/* there should be no trailing garbage in the input file */
+	EXP(0);
+
+	if (parse_only) {
+		printf("input file parsed ok\n");
+		return 0;
+	}
+
+	/* not reached if parse_only */
 	if (i) {
 		size_t s = i * sizeof(*bm);
 		memset(bm+i, 0x00, buffer_size - s);
@@ -1631,8 +1730,16 @@
 	return 0;
 }
 
-#undef EXP
+int meta_restore_md(struct format *cfg, char **argv, int argc)
+{
+	return verify_dumpfile_or_restore(cfg,argv,argc,0);
+}
 
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc)
+{
+	return verify_dumpfile_or_restore(cfg,argv,argc,1);
+}
+
 void md_convert_07_to_08(struct format *cfg)
 {
 	int i,j=1;

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2007-07-18 16:22:09 UTC (rev 2974)
+++ trunk/user/drbdsetup.c	2007-07-19 11:09:26 UTC (rev 2975)
@@ -482,6 +482,15 @@
 
 void add_tag(struct drbd_tag_list *tl, int tag, void *data, int data_len)
 {
+	if(data_len > tag_descriptions[tag_number(tag)].max_len) {
+		fprintf(stderr, "The value for %s may only be %d byte long."
+			" You requested %d.\n",
+			tag_descriptions[tag_number(tag)].name,
+			tag_descriptions[tag_number(tag)].max_len,
+			data_len);
+		exit(20);
+	}
+
 	if( (tl->tag_list_cpos - tl->tag_list_start) + data_len
 	    > tl->tag_size ) {
 		fprintf(stderr, "Tag list size exceeded!\n");



More information about the drbd-cvs mailing list