Filter driver by Wu Bingzheng et al
This commit is contained in:
		
							parent
							
								
									f197bcb435
								
							
						
					
					
						commit
						be2087ecf9
					
				| @ -23,7 +23,7 @@ case $#:$1 in | |||||||
| 	ttypa ttypb ttypc ttypd ttype ttypf \ | 	ttypa ttypb ttypc ttypd ttype ttypf \ | ||||||
| 	ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9 \ | 	ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9 \ | ||||||
| 	ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf \ | 	ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf \ | ||||||
| 	eth klog random rescue | 	eth klog random rescue filter | ||||||
|     ;; |     ;; | ||||||
| 0:|1:-\?) | 0:|1:-\?) | ||||||
|     cat >&2 <<EOF |     cat >&2 <<EOF | ||||||
| @ -48,6 +48,7 @@ Where key is one of the following: | |||||||
|   kbd                     # Make /dev/kbd |   kbd                     # Make /dev/kbd | ||||||
|   kbdaux                  # Make /dev/kbdaux |   kbdaux                  # Make /dev/kbdaux | ||||||
|   rescue                  # Make /dev/rescue |   rescue                  # Make /dev/rescue | ||||||
|  |   filter                  # Make /dev/filter | ||||||
|   video                   # Make /dev/video |   video                   # Make /dev/video | ||||||
|   std			  # All standard devices |   std			  # All standard devices | ||||||
| EOF | EOF | ||||||
| @ -259,6 +260,11 @@ do | |||||||
|     	$e mknod klog c 15 0 |     	$e mknod klog c 15 0 | ||||||
| 	$e chmod 600 klog | 	$e chmod 600 klog | ||||||
| 	;; | 	;; | ||||||
|  |     filter) | ||||||
|  | 	# filter driver | ||||||
|  | 	$e mknod filter b 11 0 | ||||||
|  | 	$e chmod 644 filter | ||||||
|  | 	;; | ||||||
|     *) |     *) | ||||||
| 	echo "$0: don't know about $dev" >&2 | 	echo "$0: don't know about $dev" >&2 | ||||||
| 	ex=1 | 	ex=1 | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ all install depend clean: | |||||||
| 	cd ./dpeth && $(MAKE) $@ | 	cd ./dpeth && $(MAKE) $@ | ||||||
| 	cd ./log && $(MAKE) $@ | 	cd ./log && $(MAKE) $@ | ||||||
| 	cd ./bios_wini && $(MAKE) $@ | 	cd ./bios_wini && $(MAKE) $@ | ||||||
|  | 	cd ./filter && $(MAKE) $@ | ||||||
| 	cd ./random && $(MAKE) $@ | 	cd ./random && $(MAKE) $@ | ||||||
| 	cd ./readclock && $(MAKE) $@ | 	cd ./readclock && $(MAKE) $@ | ||||||
| 	cd ./dp8390 && $(MAKE) $@ | 	cd ./dp8390 && $(MAKE) $@ | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								drivers/filter/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								drivers/filter/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | # Makefile for filter driver
 | ||||||
|  | DRIVER = filter | ||||||
|  | 
 | ||||||
|  | # programs, flags, etc.
 | ||||||
|  | CC = cc | ||||||
|  | CFLAGS = -DDEBUG=1 -DDEBUG2=0 | ||||||
|  | LDFLAGS =  | ||||||
|  | LIBS = -lsys | ||||||
|  | 
 | ||||||
|  | OBJ = main.o sum.o driver.o util.o optset.o crc.o md5.o | ||||||
|  | 
 | ||||||
|  | # build local binary
 | ||||||
|  | all build:	$(DRIVER) | ||||||
|  | $(DRIVER):	$(OBJ)  | ||||||
|  | 	$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) | ||||||
|  | 
 | ||||||
|  | # install with other drivers
 | ||||||
|  | install:	/usr/sbin/$(DRIVER) | ||||||
|  | /usr/sbin/$(DRIVER):	$(DRIVER) | ||||||
|  | 	install -o root -c $? $@ | ||||||
|  | 
 | ||||||
|  | # clean up local files
 | ||||||
|  | clean: | ||||||
|  | 	rm -f *.o *.bak $(DRIVER) | ||||||
|  | 
 | ||||||
|  | depend:  | ||||||
|  | 	mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend | ||||||
|  | 
 | ||||||
|  | # Include generated dependencies.
 | ||||||
|  | include .depend | ||||||
|  | 
 | ||||||
							
								
								
									
										88
									
								
								drivers/filter/crc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								drivers/filter/crc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | /* CRC32 implementation taken from cksum.c */ | ||||||
|  | 
 | ||||||
|  | /* Copyright 1991 by Vincent Archer
 | ||||||
|  |  *	You may freely redistribute this software, in source or binary | ||||||
|  |  *	form, provided that you do not alter this copyright mention in any | ||||||
|  |  *	way. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <sys/types.h> | ||||||
|  | 
 | ||||||
|  | unsigned long crctab[] = { | ||||||
|  |   0x7fffffff, | ||||||
|  |   0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | ||||||
|  |   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, | ||||||
|  |   0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, | ||||||
|  |   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, | ||||||
|  |   0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, | ||||||
|  |   0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, | ||||||
|  |   0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | ||||||
|  |   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, | ||||||
|  |   0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, | ||||||
|  |   0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, | ||||||
|  |   0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, | ||||||
|  |   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, | ||||||
|  |   0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | ||||||
|  |   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, | ||||||
|  |   0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, | ||||||
|  |   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, | ||||||
|  |   0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, | ||||||
|  |   0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, | ||||||
|  |   0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | ||||||
|  |   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, | ||||||
|  |   0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, | ||||||
|  |   0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, | ||||||
|  |   0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, | ||||||
|  |   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, | ||||||
|  |   0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | ||||||
|  |   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, | ||||||
|  |   0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, | ||||||
|  |   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, | ||||||
|  |   0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, | ||||||
|  |   0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, | ||||||
|  |   0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | ||||||
|  |   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, | ||||||
|  |   0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, | ||||||
|  |   0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, | ||||||
|  |   0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, | ||||||
|  |   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, | ||||||
|  |   0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | ||||||
|  |   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, | ||||||
|  |   0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, | ||||||
|  |   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, | ||||||
|  |   0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, | ||||||
|  |   0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, | ||||||
|  |   0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | ||||||
|  |   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, | ||||||
|  |   0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, | ||||||
|  |   0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, | ||||||
|  |   0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, | ||||||
|  |   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, | ||||||
|  |   0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | ||||||
|  |   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, | ||||||
|  |   0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | unsigned long compute_crc( unsigned char *b, size_t n) | ||||||
|  | { | ||||||
|  |   int i; | ||||||
|  |   unsigned long s = 0;        | ||||||
|  |   int aux = 0; | ||||||
|  | 
 | ||||||
|  |   while (n-- > 0) { | ||||||
|  |     /* Compute the index to the crc table */ | ||||||
|  |     i = (s >> 24) ^ ((unsigned int) (*b++)); | ||||||
|  | 
 | ||||||
|  |     if (i == 0) { | ||||||
|  |       /* Replace an intermediate zero with the next value
 | ||||||
|  |        * from the sequence */ | ||||||
|  |       i = aux++; | ||||||
|  |       if (aux >= sizeof(crctab) / sizeof(crctab[0])) aux = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* New checksum value */ | ||||||
|  |     s = (s << 8) ^ crctab[i]; | ||||||
|  |   } | ||||||
|  |   return(s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										6
									
								
								drivers/filter/crc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								drivers/filter/crc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #ifndef _CRC_H | ||||||
|  | #define _CRC_H | ||||||
|  | 
 | ||||||
|  | extern unsigned long compute_crc(unsigned char *b, size_t n); | ||||||
|  | 
 | ||||||
|  | #endif /* _CRC_H */ | ||||||
							
								
								
									
										930
									
								
								drivers/filter/driver.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										930
									
								
								drivers/filter/driver.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,930 @@ | |||||||
|  | /* Filter driver - lowest layer - disk driver management */ | ||||||
|  | 
 | ||||||
|  | #include "inc.h" | ||||||
|  | 
 | ||||||
|  | /* Drivers. */ | ||||||
|  | static struct { | ||||||
|  |   char *label; | ||||||
|  |   int minor; | ||||||
|  |   endpoint_t endpt; | ||||||
|  | 
 | ||||||
|  |   int problem;		/* one of BD_* */ | ||||||
|  |   int error;		/* one of E*, only relevant if problem>0 */ | ||||||
|  |   int retries; | ||||||
|  |   int kills; | ||||||
|  | } driver[2]; | ||||||
|  | 
 | ||||||
|  | /* State variables. */ | ||||||
|  | static endpoint_t self_ep; | ||||||
|  | static asynmsg_t amsgtable[2]; | ||||||
|  | 
 | ||||||
|  | static int size_known = 0; | ||||||
|  | static u64_t disk_size; | ||||||
|  | 
 | ||||||
|  | static int problem_stats[BD_LAST] = { 0 }; | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				driver_open				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int driver_open(int which) | ||||||
|  | { | ||||||
|  | 	/* Perform an open or close operation on the driver. This is
 | ||||||
|  | 	 * unfinished code: we should never be doing a blocking sendrec() to | ||||||
|  | 	 * the driver. | ||||||
|  | 	 */ | ||||||
|  | 	message msg; | ||||||
|  | 	cp_grant_id_t gid; | ||||||
|  | 	struct partition part; | ||||||
|  | 	sector_t sectors; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	msg.m_type = DEV_OPEN; | ||||||
|  | 	msg.DEVICE = driver[which].minor; | ||||||
|  | 	msg.IO_ENDPT = self_ep; | ||||||
|  | 	r = sendrec(driver[which].endpt, &msg); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		/* Should we restart the driver now? */ | ||||||
|  | 		printf("Filter: driver_open: sendrec returned %d\n", r); | ||||||
|  | 
 | ||||||
|  | 		return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) { | ||||||
|  | 		printf("Filter: driver_open: sendrec returned %d, %d\n", | ||||||
|  | 			msg.m_type, msg.REP_STATUS); | ||||||
|  | 
 | ||||||
|  | 		return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Take the opportunity to retrieve the hard disk size. */ | ||||||
|  | 	gid = cpf_grant_direct(driver[which].endpt, | ||||||
|  | 		(vir_bytes) &part, sizeof(part), CPF_WRITE); | ||||||
|  | 	if(!GRANT_VALID(gid)) | ||||||
|  | 		panic(__FILE__, "invalid grant", gid); | ||||||
|  | 
 | ||||||
|  | 	msg.m_type = DEV_IOCTL_S; | ||||||
|  | 	msg.REQUEST = DIOCGETP; | ||||||
|  | 	msg.DEVICE = driver[which].minor; | ||||||
|  | 	msg.IO_ENDPT = self_ep; | ||||||
|  | 	msg.IO_GRANT = (char *) gid; | ||||||
|  | 
 | ||||||
|  | 	r = sendrec(driver[which].endpt, &msg); | ||||||
|  | 
 | ||||||
|  | 	cpf_revoke(gid); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK || msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) { | ||||||
|  | 		/* Not sure what to do here, either. */ | ||||||
|  | 		printf("Filter: ioctl(DIOCGETP) returned (%d, %d)\n",  | ||||||
|  | 			r, msg.m_type); | ||||||
|  | 
 | ||||||
|  | 		return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(!size_known) { | ||||||
|  | 		disk_size = part.size; | ||||||
|  | 		size_known = 1; | ||||||
|  | 		sectors = div64u(disk_size, SECTOR_SIZE); | ||||||
|  | 		if(cmp64(mul64u(sectors, SECTOR_SIZE), disk_size)) { | ||||||
|  | 			printf("Filter: partition too large\n"); | ||||||
|  | 
 | ||||||
|  | 			return RET_REDO; | ||||||
|  | 		} | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: partition size: 0x%s / %lu sectors\n", | ||||||
|  | 			print64(disk_size), sectors); | ||||||
|  | #endif | ||||||
|  | 	} else { | ||||||
|  | 		if(cmp64(disk_size, part.size)) { | ||||||
|  | 			printf("Filter: partition size mismatch (%s != %s)\n", | ||||||
|  | 				print64(part.size), print64(disk_size)); | ||||||
|  | 
 | ||||||
|  | 			return RET_REDO; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				driver_close				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int driver_close(int which) | ||||||
|  | { | ||||||
|  | 	message msg; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	msg.m_type = DEV_CLOSE; | ||||||
|  | 	msg.DEVICE = driver[which].minor; | ||||||
|  | 	msg.IO_ENDPT = self_ep; | ||||||
|  | 	r = sendrec(driver[which].endpt, &msg); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		/* Should we restart the driver now? */ | ||||||
|  | 		printf("Filter: driver_close: sendrec returned %d\n", r); | ||||||
|  | 
 | ||||||
|  | 		return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) { | ||||||
|  | 		printf("Filter: driver_close: sendrec returned %d, %d\n", | ||||||
|  | 			msg.m_type, msg.REP_STATUS); | ||||||
|  | 
 | ||||||
|  | 		return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				driver_init				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void driver_init(void) | ||||||
|  | { | ||||||
|  | 	/* Initialize the driver layer. */ | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	self_ep = getprocnr(); | ||||||
|  | 
 | ||||||
|  | 	memset(driver, 0, sizeof(driver)); | ||||||
|  | 
 | ||||||
|  | 	/* Endpoints unknown. */ | ||||||
|  | 	driver[DRIVER_MAIN].endpt = NONE; | ||||||
|  | 	driver[DRIVER_BACKUP].endpt = NONE; | ||||||
|  | 
 | ||||||
|  | 	/* Get disk driver's and this proc's endpoint. */ | ||||||
|  | 	driver[DRIVER_MAIN].label = MAIN_LABEL; | ||||||
|  | 	driver[DRIVER_MAIN].minor = MAIN_MINOR; | ||||||
|  | 
 | ||||||
|  | 	r = ds_retrieve_u32(driver[DRIVER_MAIN].label, | ||||||
|  | 		(u32_t *) &driver[DRIVER_MAIN].endpt); | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		printf("Filter: failed to get main disk driver's endpoint: " | ||||||
|  | 			"%d\n", r); | ||||||
|  | 		bad_driver(DRIVER_MAIN, BD_DEAD, EFAULT); | ||||||
|  | 		check_driver(DRIVER_MAIN); | ||||||
|  | 	} | ||||||
|  | 	else if (driver_open(DRIVER_MAIN) != OK) { | ||||||
|  | 		panic(__FILE__, "unhandled driver_open failure", NO_NUM); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(USE_MIRROR) { | ||||||
|  | 		driver[DRIVER_BACKUP].label = BACKUP_LABEL; | ||||||
|  | 		driver[DRIVER_BACKUP].minor = BACKUP_MINOR; | ||||||
|  | 
 | ||||||
|  | 		if(!strcmp(driver[DRIVER_MAIN].label, | ||||||
|  | 				driver[DRIVER_BACKUP].label)) { | ||||||
|  | 			panic(__FILE__, "same driver: not tested", NO_NUM); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		r = ds_retrieve_u32(driver[DRIVER_BACKUP].label, | ||||||
|  | 			(u32_t *) &driver[DRIVER_BACKUP].endpt); | ||||||
|  | 		if (r != OK) { | ||||||
|  | 			printf("Filter: failed to get backup disk driver's " | ||||||
|  | 				"endpoint: %d\n", r); | ||||||
|  | 			bad_driver(DRIVER_BACKUP, BD_DEAD, EFAULT); | ||||||
|  | 			check_driver(DRIVER_BACKUP); | ||||||
|  | 		} | ||||||
|  | 		else if (driver_open(DRIVER_BACKUP) != OK) { | ||||||
|  | 			panic(__FILE__, "unhandled driver_open failure", | ||||||
|  | 				NO_NUM); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				driver_shutdown				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void driver_shutdown(void) | ||||||
|  | { | ||||||
|  | 	/* Clean up. */ | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: %u driver deaths, %u protocol errors, " | ||||||
|  | 		"%u data errors\n", problem_stats[BD_DEAD], | ||||||
|  | 		problem_stats[BD_PROTO], problem_stats[BD_DATA]); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	if(driver_close(DRIVER_MAIN) != OK) | ||||||
|  | 		printf("Filter: DEV_CLOSE failed on shutdown (1)\n"); | ||||||
|  | 
 | ||||||
|  | 	if(USE_MIRROR) | ||||||
|  | 		if(driver_close(DRIVER_BACKUP) != OK) | ||||||
|  | 			printf("Filter: DEV_CLOSE failed on shutdown (2)\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				get_raw_size				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | u64_t get_raw_size(void) | ||||||
|  | { | ||||||
|  | 	/* Return the size of the raw disks as used by the filter driver.
 | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	return disk_size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				reset_kills				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void reset_kills(void) | ||||||
|  | { | ||||||
|  | 	/* Reset kill and retry statistics. */ | ||||||
|  | 	driver[DRIVER_MAIN].kills = 0; | ||||||
|  | 	driver[DRIVER_MAIN].retries = 0; | ||||||
|  | 	driver[DRIVER_BACKUP].kills = 0; | ||||||
|  | 	driver[DRIVER_BACKUP].retries = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				bad_driver				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | int bad_driver(int which, int type, int error) | ||||||
|  | { | ||||||
|  | 	/* A disk driver has died or produced an error. Mark it so that we can
 | ||||||
|  | 	 * deal with it later, and return RET_REDO to indicate that the | ||||||
|  | 	 * current operation is to be retried. Also store an error code to | ||||||
|  | 	 * return to the user if the situation is unrecoverable. | ||||||
|  | 	 */ | ||||||
|  | 	driver[which].problem = type; | ||||||
|  | 	driver[which].error = error; | ||||||
|  | 
 | ||||||
|  | 	return RET_REDO; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				new_driver_ep				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int new_driver_ep(int which) | ||||||
|  | { | ||||||
|  | 	/* See if a new driver instance has already been started for the given
 | ||||||
|  | 	 * driver, by retrieving its entry from DS. | ||||||
|  | 	 */ | ||||||
|  | 	int r; | ||||||
|  | 	endpoint_t endpt; | ||||||
|  | 
 | ||||||
|  | 	r = ds_retrieve_u32(driver[which].label, (u32_t *) &endpt); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		printf("Filter: DS query for %s failed\n", | ||||||
|  | 			driver[which].label); | ||||||
|  | 
 | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (endpt == driver[which].endpt) { | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: same endpoint for %s\n", driver[which].label); | ||||||
|  | #endif | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: new enpdoint for %s: %d -> %d\n", driver[which].label, | ||||||
|  | 		driver[which].endpt, endpt); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	driver[which].endpt = endpt; | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_problem				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int check_problem(int which, int problem, int retries, int *tell_rs) | ||||||
|  | { | ||||||
|  | 	/* A problem has occurred with a driver. Update statistics, and decide
 | ||||||
|  | 	 * what to do. If EAGAIN is returned, the driver should be restarted; | ||||||
|  | 	 * any other result will be passed up. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: check_driver processing driver %d, problem %d\n", | ||||||
|  | 		which, problem); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	problem_stats[problem]++; | ||||||
|  | 
 | ||||||
|  | 	if(new_driver_ep(which)) { | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: check_problem: noticed a new driver\n"); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		if(driver_open(which) == OK) { | ||||||
|  | #if DEBUG2 | ||||||
|  | 			printf("Filter: open OK -> no recovery\n"); | ||||||
|  | #endif | ||||||
|  | 			return OK; | ||||||
|  | 		} else { | ||||||
|  | #if DEBUG2 | ||||||
|  | 			printf("Filter: open not OK -> recovery\n"); | ||||||
|  | #endif | ||||||
|  | 			problem = BD_PROTO; | ||||||
|  | 			problem_stats[problem]++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* If the driver has died, we always need to restart it. If it has
 | ||||||
|  | 	 * been giving problems, we first retry the request, up to N times, | ||||||
|  | 	 * after which we kill and restart the driver. We restart the driver | ||||||
|  | 	 * up to M times, after which we remove the driver from the mirror | ||||||
|  | 	 * configuration. If we are not set up to do mirroring, we can only | ||||||
|  | 	 * do one thing, and that is continue to limp along with the bad | ||||||
|  | 	 * driver.. | ||||||
|  | 	 */ | ||||||
|  | 	switch(problem) { | ||||||
|  | 	case BD_PROTO: | ||||||
|  | 	case BD_DATA: | ||||||
|  | 		driver[which].retries++; | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: disk driver %d has had " | ||||||
|  | 			"%d/%d retry attempts, %d/%d kills\n", which,  | ||||||
|  | 			driver[which].retries, NR_RETRIES, | ||||||
|  | 			driver[which].kills, NR_RESTARTS); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		if (driver[which].retries < NR_RETRIES) { | ||||||
|  | 			if(retries == 1) { | ||||||
|  | #if DEBUG | ||||||
|  | 				printf("Filter: not restarting; retrying " | ||||||
|  | 					"(retries %d/%d, kills %d/%d)\n", | ||||||
|  | 					driver[which].retries, NR_RETRIES, | ||||||
|  | 					driver[which].kills, NR_RESTARTS); | ||||||
|  | #endif | ||||||
|  | 				return OK; | ||||||
|  | 			} | ||||||
|  | #if DEBUG | ||||||
|  | 			printf("Filter: restarting (retries %d/%d, " | ||||||
|  | 				"kills %d/%d, internal retry %d)\n", | ||||||
|  | 				driver[which].retries, NR_RETRIES, | ||||||
|  | 				driver[which].kills, NR_RESTARTS, retries); | ||||||
|  | #endif | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: disk driver %d has reached error " | ||||||
|  | 			"threshold, restarting driver\n", which); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		*tell_rs = 1; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case BD_DEAD: | ||||||
|  | 		/* Can't kill that which is already dead.. */ | ||||||
|  | 		*tell_rs = 0; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		panic(__FILE__, "invalid problem", problem); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* At this point, the driver will be restarted. */ | ||||||
|  | 	driver[which].retries = 0; | ||||||
|  | 	driver[which].kills++; | ||||||
|  | 
 | ||||||
|  | 	if (driver[which].kills < NR_RESTARTS) | ||||||
|  | 		return EAGAIN; | ||||||
|  | 
 | ||||||
|  | 	/* We've reached the maximum number of restarts for this driver. */ | ||||||
|  | 	if (USE_MIRROR) { | ||||||
|  | 		printf("Filter: kill threshold reached, disabling mirroring\n"); | ||||||
|  | 
 | ||||||
|  | 		USE_MIRROR = 0; | ||||||
|  | 
 | ||||||
|  | 		if (which == DRIVER_MAIN) { | ||||||
|  | 			driver[DRIVER_MAIN] = driver[DRIVER_BACKUP]; | ||||||
|  | 
 | ||||||
|  | 			/* This is not necessary. */ | ||||||
|  | 			strcpy(MAIN_LABEL, BACKUP_LABEL); | ||||||
|  | 			MAIN_MINOR = BACKUP_MINOR; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		driver[DRIVER_BACKUP].endpt = NONE; | ||||||
|  | 
 | ||||||
|  | 		return OK; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		/* We tried, we really did. But now we give up. Tell the user.
 | ||||||
|  | 		 */ | ||||||
|  | 		printf("Filter: kill threshold reached, returning error\n"); | ||||||
|  | 
 | ||||||
|  | 		if (driver[which].error == EAGAIN) return EIO; | ||||||
|  | 
 | ||||||
|  | 		return driver[which].error; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				restart_driver				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void restart_driver(int which, int tell_rs) | ||||||
|  | { | ||||||
|  | 	/* Restart the given driver. Block until the new instance is up.
 | ||||||
|  | 	 */ | ||||||
|  | 	message msg; | ||||||
|  | 	endpoint_t endpt; | ||||||
|  | 	int r, w = 0; | ||||||
|  | 
 | ||||||
|  | 	if (tell_rs) { | ||||||
|  | 		/* Tell RS to refresh or restart the driver */ | ||||||
|  | 		msg.m_type = RS_REFRESH; | ||||||
|  | 		msg.RS_CMD_ADDR = driver[which].label; | ||||||
|  | 		msg.RS_CMD_LEN = strlen(driver[which].label); | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: asking RS to refresh %s..\n", | ||||||
|  | 			driver[which].label); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		r = sendrec(RS_PROC_NR, &msg); | ||||||
|  | 
 | ||||||
|  | 		if (r != OK || msg.m_type != OK) | ||||||
|  | 			panic(__FILE__, "RS request failed", r); | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: RS call succeeded\n"); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Wait until the new driver instance is up, and get its endpoint. */ | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: endpoint update driver %d; old endpoint %d\n", | ||||||
|  | 		which, driver[which].endpt); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		if(w) flt_sleep(1); | ||||||
|  | 		w = 1; | ||||||
|  | 
 | ||||||
|  | 		r = ds_retrieve_u32(driver[which].label, (u32_t *) &endpt); | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 		if (r != OK) | ||||||
|  | 			printf("Filter: DS request failed (%d)\n", r); | ||||||
|  | 		else if (endpt == driver[which].endpt) | ||||||
|  | 			printf("Filter: DS returned same endpoint\n"); | ||||||
|  | 		else | ||||||
|  | 			printf("Filter: DS request OK, new endpoint\n"); | ||||||
|  | #endif | ||||||
|  | 	} while (r != OK || endpt == driver[which].endpt); | ||||||
|  | 
 | ||||||
|  | 	driver[which].endpt = endpt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_driver				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | int check_driver(int which) | ||||||
|  | { | ||||||
|  | 	/* See if the given driver has been troublesome, and if so, deal with
 | ||||||
|  | 	 * it. | ||||||
|  | 	 */ | ||||||
|  | 	int problem, tell_rs; | ||||||
|  | 	int r, retries = 0; | ||||||
|  | 
 | ||||||
|  | 	problem = driver[which].problem; | ||||||
|  | 
 | ||||||
|  | 	if (problem == BD_NONE) | ||||||
|  | 		return OK; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		if(retries) { | ||||||
|  | #if DEBUG | ||||||
|  | 			printf("Filter: check_driver: retry number %d\n", | ||||||
|  | 				retries); | ||||||
|  | #endif | ||||||
|  | 			problem = BD_PROTO; | ||||||
|  | 		} | ||||||
|  | 		retries++; | ||||||
|  | 		driver[which].problem = BD_NONE; | ||||||
|  | 
 | ||||||
|  | 		/* Decide what to do: continue operation, restart the driver,
 | ||||||
|  | 		 * or return an error. | ||||||
|  | 		 */ | ||||||
|  | 		r = check_problem(which, problem, retries, &tell_rs); | ||||||
|  | 		if (r != EAGAIN) | ||||||
|  | 			return r; | ||||||
|  | 
 | ||||||
|  | 		/* Restarting the driver it is. First tell RS (if necessary),
 | ||||||
|  | 		 * then wait for the new driver instance to come up. | ||||||
|  | 		 */ | ||||||
|  | 		restart_driver(which, tell_rs); | ||||||
|  | 
 | ||||||
|  | 		/* Finally, open the device on the new driver */ | ||||||
|  | 	} while (driver_open(which) != OK); | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: check_driver restarted driver %d, endpoint %d\n", | ||||||
|  | 		which, driver[which].endpt); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_senda				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int flt_senda(message *mess, int which) | ||||||
|  | { | ||||||
|  | 	/* Send a message to one driver. Can only return OK at the moment. */ | ||||||
|  | 	int r; | ||||||
|  | 	asynmsg_t *amp; | ||||||
|  | 
 | ||||||
|  | 	/* Fill in the last bits of the message. */ | ||||||
|  | 	mess->DEVICE = driver[which].minor; | ||||||
|  | 	mess->IO_ENDPT = self_ep; | ||||||
|  | 
 | ||||||
|  | 	/* Send the message asynchronously. */ | ||||||
|  | 	amp = &amsgtable[which]; | ||||||
|  | 	amp->dst = driver[which].endpt; | ||||||
|  | 	amp->msg = *mess; | ||||||
|  | 	amp->flags = AMF_VALID; | ||||||
|  | 	r = senda(amsgtable, 2); | ||||||
|  | 
 | ||||||
|  | 	if(r != OK) | ||||||
|  | 		panic(__FILE__, "senda returned error", r); | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_senda				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int check_senda(int which) | ||||||
|  | { | ||||||
|  | 	/* Check whether an earlier senda resulted in an error indicating the
 | ||||||
|  | 	 * message never got delivered. Only in that case can we reliably say | ||||||
|  | 	 * that the driver died. Return BD_DEAD in this case, and BD_PROTO | ||||||
|  | 	 * otherwise. | ||||||
|  | 	 */ | ||||||
|  | 	asynmsg_t *amp; | ||||||
|  | 
 | ||||||
|  | 	amp = &amsgtable[which]; | ||||||
|  | 
 | ||||||
|  | 	if ((amp->flags & AMF_DONE) && | ||||||
|  | 		(amp->result == EDEADSRCDST || amp->result == EDSTDIED)) { | ||||||
|  | 
 | ||||||
|  | 		return BD_DEAD; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return BD_PROTO; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_receive				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int flt_receive(message *mess, int which) | ||||||
|  | { | ||||||
|  | 	/* Receive a message from one or either driver, unless a timeout
 | ||||||
|  | 	 * occurs. Can only return OK or RET_REDO. | ||||||
|  | 	 */ | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	for (;;) { | ||||||
|  | 		r = receive(ANY, mess); | ||||||
|  | 		if(r != OK) | ||||||
|  | 			panic(__FILE__, "receive returned error", r); | ||||||
|  | 
 | ||||||
|  | 		if(mess->m_source == CLOCK && is_notify(mess->m_type)) { | ||||||
|  | 			if (mess->NOTIFY_TIMESTAMP < flt_alarm(-1)) { | ||||||
|  | #if DEBUG | ||||||
|  | 				printf("Filter: SKIPPING old alarm " | ||||||
|  | 					"notification\n"); | ||||||
|  | #endif | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 			printf("Filter: timeout waiting for disk driver %d " | ||||||
|  | 				"reply!\n", which); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 			/* If we're waiting for either driver,
 | ||||||
|  | 		 	 * both are at fault. | ||||||
|  | 		 	 */ | ||||||
|  | 			if (which < 0) { | ||||||
|  | 				bad_driver(DRIVER_MAIN, | ||||||
|  | 					check_senda(DRIVER_MAIN), EFAULT); | ||||||
|  | 
 | ||||||
|  | 				return bad_driver(DRIVER_BACKUP, | ||||||
|  | 					check_senda(DRIVER_BACKUP), EFAULT); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			/* Otherwise, just report the one not replying as dead.
 | ||||||
|  | 			 */ | ||||||
|  | 			return bad_driver(which, check_senda(which), EFAULT); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (mess->m_source != driver[DRIVER_MAIN].endpt && | ||||||
|  | 				mess->m_source != driver[DRIVER_BACKUP].endpt) { | ||||||
|  | #if DEBUG | ||||||
|  | 			printf("Filter: got STRAY message %d from %d\n", | ||||||
|  | 				mess->m_type, mess->m_source); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* We are waiting for a reply from one specific driver. */ | ||||||
|  | 		if (which >= 0) { | ||||||
|  | 			/* If the message source is that driver, good. */ | ||||||
|  | 			if (mess->m_source == driver[which].endpt) | ||||||
|  | 				break; | ||||||
|  | 
 | ||||||
|  | 			/* This should probably be treated as a real protocol
 | ||||||
|  | 			 * error. We do not abort any receives (not even paired | ||||||
|  | 			 * receives) except because of timeouts. Getting here | ||||||
|  | 			 * means a driver replied at least the timeout period | ||||||
|  | 			 * later than expected, which should be enough reason | ||||||
|  | 			 * to kill it really. The other explanation is that it | ||||||
|  | 			 * is actually violating the protocol and sending bogus | ||||||
|  | 			 * messages... | ||||||
|  | 			 */ | ||||||
|  | #if DEBUG | ||||||
|  | 			printf("Filter: got UNEXPECTED reply from %d\n", | ||||||
|  | 				mess->m_source); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* We got a message from one of the drivers, and we didn't
 | ||||||
|  | 		 * care which one we wanted to receive from. A-OK. | ||||||
|  | 		 */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_sendrec				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int flt_sendrec(message *mess, int which) | ||||||
|  | { | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	r = flt_senda(mess, which); | ||||||
|  | 	if(r != OK) | ||||||
|  | 		return r; | ||||||
|  | 
 | ||||||
|  | 	if(check_senda(which) == BD_DEAD) { | ||||||
|  | 		return bad_driver(which, BD_DEAD, EFAULT); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Set alarm. */ | ||||||
|  | 	flt_alarm(DRIVER_TIMEOUT); | ||||||
|  | 
 | ||||||
|  | 	r = flt_receive(mess, which); | ||||||
|  | 
 | ||||||
|  | 	/* Clear the alarm. */ | ||||||
|  | 	flt_alarm(0); | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				do_sendrec_both				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int do_sendrec_both(message *m1, message *m2) | ||||||
|  | { | ||||||
|  | 	/* If USEE_MIRROR is set, call flt_sendrec() to both drivers.
 | ||||||
|  | 	 * Otherwise, only call flt_sendrec() to the main driver. | ||||||
|  | 	 * This function will only return either OK or RET_REDO. | ||||||
|  | 	 */ | ||||||
|  | 	int r, which = -1; | ||||||
|  | 	message ma, mb; | ||||||
|  | 
 | ||||||
|  | 	/* If the two disks use the same driver, call flt_sendrec() twice
 | ||||||
|  | 	 * sequentially. Such a setup is not very useful though. | ||||||
|  | 	 */ | ||||||
|  | 	if (!strcmp(driver[DRIVER_MAIN].label, driver[DRIVER_BACKUP].label)) { | ||||||
|  | 		if ((r = flt_sendrec(m1, DRIVER_MAIN)) != OK) return r; | ||||||
|  | 		return flt_sendrec(m2, DRIVER_BACKUP); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* If the two disks use different drivers, call flt_senda()
 | ||||||
|  | 	 * twice, and then flt_receive(), and distinguish the return | ||||||
|  | 	 * messages by means of m_source. | ||||||
|  | 	 */ | ||||||
|  | 	if ((r = flt_senda(m1, DRIVER_MAIN)) != OK) return r; | ||||||
|  | 	if ((r = flt_senda(m2, DRIVER_BACKUP)) != OK) return r; | ||||||
|  | 
 | ||||||
|  | 	/* Set alarm. */ | ||||||
|  | 	flt_alarm(DRIVER_TIMEOUT); | ||||||
|  | 
 | ||||||
|  | 	/* The message received by the 1st flt_receive() may not be
 | ||||||
|  | 	 * from DRIVER_MAIN. | ||||||
|  | 	 */ | ||||||
|  | 	if ((r = flt_receive(&ma, -1)) != OK) { | ||||||
|  | 		flt_alarm(0); | ||||||
|  | 		return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ma.m_source == driver[DRIVER_MAIN].endpt) { | ||||||
|  | 		which = DRIVER_BACKUP; | ||||||
|  | 	} else if (ma.m_source == driver[DRIVER_BACKUP].endpt) { | ||||||
|  | 		which = DRIVER_MAIN; | ||||||
|  | 	} else { | ||||||
|  | 		panic(__FILE__, "message from unexpected source", | ||||||
|  | 			ma.m_source); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r = flt_receive(&mb, which); | ||||||
|  | 
 | ||||||
|  | 	/* Clear the alarm. */ | ||||||
|  | 	flt_alarm(0); | ||||||
|  | 
 | ||||||
|  | 	if(r != OK) | ||||||
|  | 		return r; | ||||||
|  | 
 | ||||||
|  | 	if (ma.m_source == driver[DRIVER_MAIN].endpt) { | ||||||
|  | 		*m1 = ma; | ||||||
|  | 		*m2 = mb; | ||||||
|  | 	} else { | ||||||
|  | 		*m1 = mb; | ||||||
|  | 		*m2 = ma; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				do_sendrec_one				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int do_sendrec_one(message *m1, message *m2) | ||||||
|  | { | ||||||
|  | 	/* Only talk to the main driver. If something goes wrong, it will
 | ||||||
|  | 	 * be fixed elsewhere. | ||||||
|  | 	 * This function will only return either OK or RET_REDO. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  |     	return flt_sendrec(m1, DRIVER_MAIN); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				paired_sendrec				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int paired_sendrec(message *m1, message *m2, int both) | ||||||
|  | { | ||||||
|  | 	/* Sendrec with the disk driver. If the disk driver is down, and was
 | ||||||
|  | 	 * restarted, redo the request, until the driver works fine, or can't | ||||||
|  | 	 * be restarted again. | ||||||
|  | 	 */ | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 	printf("paired_sendrec(%d) - <%d,%x:%x,%d> - %x,%x\n", | ||||||
|  | 		both, m1->m_type, m1->HIGHPOS, m1->POSITION, m1->COUNT, | ||||||
|  | 		m1->IO_GRANT, m2->IO_GRANT); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	if (both) | ||||||
|  | 		r = do_sendrec_both(m1, m2); | ||||||
|  | 	else | ||||||
|  | 		r = do_sendrec_one(m1, m2); | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 	if (r != OK) | ||||||
|  | 		printf("paired_sendrec about to return %d\n", r); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				paired_grant				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void paired_grant(char *buf1, char *buf2, size_t size, int request, | ||||||
|  | 	cp_grant_id_t *gids, int both) | ||||||
|  | { | ||||||
|  | 	/* Create memory grants. If USE_MIRROR, grant to both drivers,
 | ||||||
|  | 	 * otherwise only to the main one. | ||||||
|  | 	 */ | ||||||
|  | 	cp_grant_id_t gid; | ||||||
|  | 	int access; | ||||||
|  | 
 | ||||||
|  | 	access = (request == FLT_WRITE) ? CPF_READ : CPF_WRITE; | ||||||
|  | 
 | ||||||
|  | 	if(driver[DRIVER_MAIN].endpt > 0) { | ||||||
|  | 		gid = cpf_grant_direct(driver[DRIVER_MAIN].endpt, | ||||||
|  | 			(vir_bytes) buf1, size, access); | ||||||
|  | 		if(!GRANT_VALID(gid)) | ||||||
|  | 			panic(__FILE__, "invalid grant", gid); | ||||||
|  | 		gids[0] = gid; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (both) { | ||||||
|  | 		if(driver[DRIVER_BACKUP].endpt > 0) { | ||||||
|  | 			gid = cpf_grant_direct(driver[DRIVER_BACKUP].endpt, | ||||||
|  | 				(vir_bytes) buf2, size, access); | ||||||
|  | 			if(!GRANT_VALID(gid)) | ||||||
|  | 				panic(__FILE__, "invalid grant", gid); | ||||||
|  | 			gids[1] = gid; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				paired_revoke				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void paired_revoke(cp_grant_id_t gid1, cp_grant_id_t gid2, int both) | ||||||
|  | { | ||||||
|  | 	cpf_revoke(gid1); | ||||||
|  | 
 | ||||||
|  | 	if (both) | ||||||
|  | 		cpf_revoke(gid2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				read_write				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | int read_write(u64_t pos, char *bufa, char *bufb, size_t *sizep, int request) | ||||||
|  | { | ||||||
|  | 	message m1, m2; | ||||||
|  | 	cp_grant_id_t gids[2]; | ||||||
|  | 	int r, both; | ||||||
|  | 
 | ||||||
|  | 	gids[0] = gids[1] = GRANT_INVALID; | ||||||
|  | 
 | ||||||
|  | 	/* Send two requests only if mirroring is enabled and the given request
 | ||||||
|  | 	 * is either FLT_READ2 or FLT_WRITE. | ||||||
|  | 	 */ | ||||||
|  | 	both = (USE_MIRROR && request != FLT_READ); | ||||||
|  | 
 | ||||||
|  | 	m1.m_type = (request == FLT_WRITE) ? DEV_WRITE_S : DEV_READ_S; | ||||||
|  | 	m1.COUNT = *sizep; | ||||||
|  | 	m1.POSITION = ex64lo(pos); | ||||||
|  | 	m1.HIGHPOS = ex64hi(pos); | ||||||
|  | 	m2 = m1; | ||||||
|  | 
 | ||||||
|  | 	paired_grant(bufa, bufb, *sizep, request, gids, both); | ||||||
|  | 	m1.IO_GRANT = (char *) gids[0]; | ||||||
|  | 	m2.IO_GRANT = (char *) gids[1]; | ||||||
|  | 
 | ||||||
|  | 	r = paired_sendrec(&m1, &m2, both); | ||||||
|  | 
 | ||||||
|  | 	paired_revoke(gids[0], gids[1], both); | ||||||
|  | 
 | ||||||
|  | 	if(r != OK) { | ||||||
|  | #if DEBUG | ||||||
|  | 		if (r != RET_REDO) | ||||||
|  | 			printf("Filter: paired_sendrec returned %d\n", r); | ||||||
|  | #endif | ||||||
|  | 		return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (m1.m_type != TASK_REPLY || m1.REP_STATUS < 0) { | ||||||
|  | 		printf("Filter: unexpected/invalid reply from main driver: " | ||||||
|  | 			"(%x, %d)\n", m1.m_type, m1.REP_STATUS); | ||||||
|  | 
 | ||||||
|  | 		return bad_driver(DRIVER_MAIN, BD_PROTO, | ||||||
|  | 			(m1.m_type == TASK_REPLY) ? m1.REP_STATUS : EFAULT); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (m1.REP_STATUS != *sizep) { | ||||||
|  | 		printf("Filter: truncated reply %u to I/O request of size " | ||||||
|  | 			"0x%x at 0x%s; size 0x%s\n", | ||||||
|  | 			m1.REP_STATUS, *sizep, | ||||||
|  | 			print64(pos), print64(disk_size)); | ||||||
|  | 
 | ||||||
|  | 		/* If the driver returned a value *larger* than we requested,
 | ||||||
|  | 		 * OR if we did NOT exceed the disk size, then we should | ||||||
|  | 		 * report the driver for acting strangely! | ||||||
|  | 		 */ | ||||||
|  | 		if (m1.REP_STATUS > *sizep || | ||||||
|  | 		  cmp64(add64u(pos, *sizep), disk_size) < 0) | ||||||
|  | 			return bad_driver(DRIVER_MAIN, BD_PROTO, EFAULT); | ||||||
|  | 
 | ||||||
|  | 		/* Return the actual size. */ | ||||||
|  | 		*sizep = m1.REP_STATUS; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (both) { | ||||||
|  | 		if (m2.m_type != TASK_REPLY || m2.REP_STATUS < 0) { | ||||||
|  | 			printf("Filter: unexpected/invalid reply from " | ||||||
|  | 				"backup driver (%x, %d)\n", | ||||||
|  | 				m2.m_type, m2.REP_STATUS); | ||||||
|  | 
 | ||||||
|  | 			return bad_driver(DRIVER_BACKUP, BD_PROTO, | ||||||
|  | 				m2.m_type == TASK_REPLY ? m2.REP_STATUS : | ||||||
|  | 				EFAULT); | ||||||
|  | 		} | ||||||
|  | 		if (m2.REP_STATUS != *sizep) { | ||||||
|  | 			printf("Filter: truncated reply from backup driver\n"); | ||||||
|  | 
 | ||||||
|  | 			/* As above */ | ||||||
|  | 			if (m2.REP_STATUS > *sizep || | ||||||
|  | 				cmp64(add64u(pos, *sizep), disk_size) < 0) | ||||||
|  | 				return bad_driver(DRIVER_BACKUP, BD_PROTO, | ||||||
|  | 					EFAULT); | ||||||
|  | 
 | ||||||
|  | 			/* Return the actual size. */ | ||||||
|  | 			if (*sizep >= m2.REP_STATUS) | ||||||
|  | 				*sizep = m2.REP_STATUS; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								drivers/filter/inc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								drivers/filter/inc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | |||||||
|  | /* Filter driver - general include file */ | ||||||
|  | #define _MINIX 1 | ||||||
|  | #define _SYSTEM 1 | ||||||
|  | #include <minix/config.h> | ||||||
|  | #include <minix/const.h> | ||||||
|  | #include <minix/type.h> | ||||||
|  | #include <minix/com.h> | ||||||
|  | #include <minix/ipc.h> | ||||||
|  | #include <sys/ioc_disk.h> | ||||||
|  | #include <minix/sysutil.h> | ||||||
|  | #include <minix/syslib.h> | ||||||
|  | #include <minix/partition.h> | ||||||
|  | #include <minix/ds.h> | ||||||
|  | #include <minix/callnr.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | #define SECTOR_SIZE	512 | ||||||
|  | 
 | ||||||
|  | enum { | ||||||
|  |   ST_XOR,		/* XOR-based checksums */ | ||||||
|  |   ST_CRC,		/* CRC32-based checksums */ | ||||||
|  |   ST_MD5		/* MD5-based checksums */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum { | ||||||
|  |   FLT_WRITE,		/* write to up to two disks */ | ||||||
|  |   FLT_READ,		/* read from one disk */ | ||||||
|  |   FLT_READ2		/* read from both disks */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Something was wrong and the disk driver has been restarted/refreshed,
 | ||||||
|  |  * so the request needs to be redone. | ||||||
|  |  */ | ||||||
|  | #define RET_REDO	1 | ||||||
|  | 
 | ||||||
|  | /* The cases where the disk driver need to be restarted/refreshed by RS. 
 | ||||||
|  |  * BD_DEAD: the disk driver has died. Restart it. | ||||||
|  |  * BD_PROTO: a protocol error has occurred. Refresh it. | ||||||
|  |  * BD_DATA: a data error has occurred. Refresh it. | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |   BD_NONE, | ||||||
|  |   BD_DEAD, | ||||||
|  |   BD_PROTO, | ||||||
|  |   BD_DATA, | ||||||
|  |   BD_LAST | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define DRIVER_MAIN	0 | ||||||
|  | #define DRIVER_BACKUP	1 | ||||||
|  | 
 | ||||||
|  | /* Requests for more than this many bytes need to go through malloc(). */ | ||||||
|  | #define BUF_SIZE	(128 * 1024) | ||||||
|  | #define SBUF_SIZE	(BUF_SIZE * 2) | ||||||
|  | 
 | ||||||
|  | #define LABEL_SIZE	32 | ||||||
|  | 
 | ||||||
|  | typedef unsigned long	sector_t; | ||||||
|  | 
 | ||||||
|  | /* main.c */ | ||||||
|  | extern int USE_CHECKSUM; | ||||||
|  | extern int USE_MIRROR; | ||||||
|  | extern int BAD_SUM_ERROR; | ||||||
|  | extern int USE_SUM_LAYOUT; | ||||||
|  | extern int SUM_TYPE; | ||||||
|  | extern int SUM_SIZE; | ||||||
|  | extern int NR_SUM_SEC; | ||||||
|  | extern int NR_RETRIES; | ||||||
|  | extern int NR_RESTARTS; | ||||||
|  | extern int DRIVER_TIMEOUT; | ||||||
|  | 
 | ||||||
|  | extern char MAIN_LABEL[LABEL_SIZE]; | ||||||
|  | extern char BACKUP_LABEL[LABEL_SIZE]; | ||||||
|  | extern int MAIN_MINOR; | ||||||
|  | extern int BACKUP_MINOR; | ||||||
|  | 
 | ||||||
|  | /* sum.c */ | ||||||
|  | extern void sum_init(void); | ||||||
|  | extern int transfer(u64_t pos, char *buffer, size_t *sizep, int flag_rw); | ||||||
|  | extern u64_t convert(u64_t size); | ||||||
|  | 
 | ||||||
|  | /* driver.c */ | ||||||
|  | extern void driver_init(void); | ||||||
|  | extern void driver_shutdown(void); | ||||||
|  | extern u64_t get_raw_size(void); | ||||||
|  | extern void reset_kills(void); | ||||||
|  | extern int check_driver(int which); | ||||||
|  | extern int bad_driver(int which, int type, int error); | ||||||
|  | extern int read_write(u64_t pos, char *bufa, char *bufb, size_t *sizep, | ||||||
|  | 	int flag_rw); | ||||||
|  | 
 | ||||||
|  | /* util.c */ | ||||||
|  | extern char *flt_malloc(size_t size, char *sbuf, size_t ssize); | ||||||
|  | extern void flt_free(char *buf, size_t size, char *sbuf); | ||||||
|  | extern char *print64(u64_t p); | ||||||
|  | extern clock_t flt_alarm(clock_t dt); | ||||||
|  | extern void flt_sleep(int secs); | ||||||
							
								
								
									
										446
									
								
								drivers/filter/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										446
									
								
								drivers/filter/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,446 @@ | |||||||
|  | /* Filter driver - top layer - block interface */ | ||||||
|  | 
 | ||||||
|  | /* This is a filter driver, which lays above disk driver, and forwards
 | ||||||
|  |  * messages between disk driver and its callers. The filter can detect | ||||||
|  |  * corrupted data (toggled by USE_CHECKSUM) and recover it (toggled | ||||||
|  |  * by USE_MIRROR). These two functions are independent from each other.  | ||||||
|  |  * The mirroring function requires two disks, on separate disk drivers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "inc.h" | ||||||
|  | #include "optset.h" | ||||||
|  | 
 | ||||||
|  | #define _POSIX_SOURCE 1 | ||||||
|  | #include <signal.h> | ||||||
|  | 
 | ||||||
|  | /* Global settings. */ | ||||||
|  | int USE_CHECKSUM = 0;	/* enable checksumming */ | ||||||
|  | int USE_MIRROR = 0;	/* enable mirroring */ | ||||||
|  | 
 | ||||||
|  | int BAD_SUM_ERROR = 1;	/* bad checksums are considered a driver error */ | ||||||
|  | 
 | ||||||
|  | int USE_SUM_LAYOUT = 0;	/* use checksumming layout on disk */ | ||||||
|  | int NR_SUM_SEC = 8;	/* number of checksums per checksum sector */ | ||||||
|  | 
 | ||||||
|  | int SUM_TYPE = 0;	/* use XOR, CRC or MD5 */ | ||||||
|  | int SUM_SIZE = 0;	/* size of the stored checksum */ | ||||||
|  | 
 | ||||||
|  | int NR_RETRIES = 3;	/* number of times the request will be retried (N) */ | ||||||
|  | int NR_RESTARTS = 3;	/* number of times a driver will be restarted (M) */ | ||||||
|  | int DRIVER_TIMEOUT = 5;	/* timeout in seconds to declare a driver dead (T) */ | ||||||
|  | 
 | ||||||
|  | char MAIN_LABEL[LABEL_SIZE] = "";		/* main disk driver label */ | ||||||
|  | char BACKUP_LABEL[LABEL_SIZE] = "";		/* backup disk driver label */ | ||||||
|  | int MAIN_MINOR = -1;				/* main partition minor nr */ | ||||||
|  | int BACKUP_MINOR = -1;				/* backup partition minor nr */ | ||||||
|  | 
 | ||||||
|  | struct optset optset_table[] = { | ||||||
|  |   { "label0",	OPT_STRING,	MAIN_LABEL,		LABEL_SIZE	}, | ||||||
|  |   { "label1",	OPT_STRING,	BACKUP_LABEL,		LABEL_SIZE	}, | ||||||
|  |   { "minor0",	OPT_INT,	&MAIN_MINOR,		10		}, | ||||||
|  |   { "minor1",	OPT_INT,	&BACKUP_MINOR,		10		}, | ||||||
|  |   { "sum_sec",	OPT_INT,	&NR_SUM_SEC,		10		}, | ||||||
|  |   { "layout",	OPT_BOOL,	&USE_SUM_LAYOUT,	1		}, | ||||||
|  |   { "nolayout",	OPT_BOOL,	&USE_SUM_LAYOUT,	0		}, | ||||||
|  |   { "sum",	OPT_BOOL,	&USE_CHECKSUM,		1		}, | ||||||
|  |   { "nosum",	OPT_BOOL,	&USE_CHECKSUM,		0		}, | ||||||
|  |   { "mirror",	OPT_BOOL,	&USE_MIRROR,		1		}, | ||||||
|  |   { "nomirror",	OPT_BOOL,	&USE_MIRROR,		0		}, | ||||||
|  |   { "xor",	OPT_BOOL,	&SUM_TYPE,		ST_XOR		}, | ||||||
|  |   { "crc",	OPT_BOOL,	&SUM_TYPE,		ST_CRC		}, | ||||||
|  |   { "md5",	OPT_BOOL,	&SUM_TYPE,		ST_MD5		}, | ||||||
|  |   { "sumerr",	OPT_BOOL,	&BAD_SUM_ERROR,		1		}, | ||||||
|  |   { "nosumerr",	OPT_BOOL,	&BAD_SUM_ERROR,		0		}, | ||||||
|  |   { "retries",	OPT_INT,	&NR_RETRIES,		10		}, | ||||||
|  |   { "N",	OPT_INT,	&NR_RETRIES,		10		}, | ||||||
|  |   { "restarts",	OPT_INT,	&NR_RESTARTS,		10		}, | ||||||
|  |   { "M",	OPT_INT,	&NR_RESTARTS,		10		}, | ||||||
|  |   { "timeout",	OPT_INT,	&DRIVER_TIMEOUT,	10		}, | ||||||
|  |   { "T",	OPT_INT,	&DRIVER_TIMEOUT,	10		}, | ||||||
|  |   { NULL								} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Request message. */ | ||||||
|  | static message m_in; | ||||||
|  | static endpoint_t who_e;			/* m_source */ | ||||||
|  | static endpoint_t proc_e;			/* IO_ENDPT */ | ||||||
|  | static cp_grant_id_t grant_id;			/* IO_GRANT */ | ||||||
|  | 
 | ||||||
|  | /* Data buffers. */ | ||||||
|  | static char *buf_array, *buffer;		/* contiguous buffer */ | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				carry					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int carry(size_t size, int flag_rw) | ||||||
|  | { | ||||||
|  | 	/* Carry data between caller proc and filter.
 | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	if (flag_rw == FLT_WRITE) | ||||||
|  | 		return sys_safecopyfrom(proc_e, grant_id, 0, | ||||||
|  | 			(vir_bytes) buffer, size, D); | ||||||
|  | 	else | ||||||
|  | 		return sys_safecopyto(proc_e, grant_id, 0, | ||||||
|  | 			(vir_bytes) buffer, size, D); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				vcarry					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int vcarry(int grants, iovec_t *iov, int flag_rw, size_t size) | ||||||
|  | { | ||||||
|  | 	/* Carry data between caller proc and filter, through grant-vector.
 | ||||||
|  | 	 */ | ||||||
|  | 	char *bufp; | ||||||
|  | 	int i, r; | ||||||
|  | 	size_t bytes; | ||||||
|  | 
 | ||||||
|  | 	bufp = buffer; | ||||||
|  | 	for(i = 0; i < grants && size > 0; i++) { | ||||||
|  | 		bytes = MIN(size, iov[i].iov_size); | ||||||
|  | 
 | ||||||
|  | 		if (flag_rw == FLT_WRITE) | ||||||
|  | 			r = sys_safecopyfrom(proc_e, | ||||||
|  | 				(vir_bytes) iov[i].iov_addr, 0, | ||||||
|  | 				(vir_bytes) bufp, bytes, D); | ||||||
|  | 		else | ||||||
|  | 			r = sys_safecopyto(proc_e, | ||||||
|  | 				(vir_bytes) iov[i].iov_addr, 0, | ||||||
|  | 				(vir_bytes) bufp, bytes, D); | ||||||
|  | 
 | ||||||
|  | 		if(r != OK) | ||||||
|  | 			return r; | ||||||
|  | 
 | ||||||
|  | 		bufp += bytes; | ||||||
|  | 		size -= bytes; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				do_rdwt					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int do_rdwt(int flag_rw) | ||||||
|  | { | ||||||
|  | 	size_t size, size_ret; | ||||||
|  | 	u64_t pos; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	pos = make64(m_in.POSITION, m_in.HIGHPOS); | ||||||
|  | 	size = m_in.COUNT; | ||||||
|  | 
 | ||||||
|  | 	if (rem64u(pos, SECTOR_SIZE) != 0 || size % SECTOR_SIZE != 0) { | ||||||
|  | 		printf("Filter: unaligned request from caller!\n"); | ||||||
|  | 
 | ||||||
|  | 		return EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buffer = flt_malloc(size, buf_array, BUF_SIZE); | ||||||
|  | 
 | ||||||
|  | 	if(flag_rw == FLT_WRITE) | ||||||
|  | 		carry(size, flag_rw); | ||||||
|  | 
 | ||||||
|  | 	reset_kills(); | ||||||
|  | 
 | ||||||
|  | 	for (;;) { | ||||||
|  | 		size_ret = size; | ||||||
|  | 		r = transfer(pos, buffer, &size_ret, flag_rw); | ||||||
|  | 		if(r != RET_REDO) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: transfer yielded RET_REDO, checking drivers\n"); | ||||||
|  | #endif | ||||||
|  | 		if((r = check_driver(DRIVER_MAIN)) != OK) break; | ||||||
|  | 		if((r = check_driver(DRIVER_BACKUP)) != OK) break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(r == OK && flag_rw == FLT_READ) | ||||||
|  | 		carry(size_ret, flag_rw); | ||||||
|  | 
 | ||||||
|  | 	flt_free(buffer, size, buf_array); | ||||||
|  | 	return r != OK ? r : size_ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				do_vrdwt				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int do_vrdwt(int flag_rw) | ||||||
|  | { | ||||||
|  | 	size_t size, size_ret, bytes; | ||||||
|  | 	int grants; | ||||||
|  | 	int r, i; | ||||||
|  | 	u64_t pos; | ||||||
|  | 	iovec_t iov_proc[NR_IOREQS]; | ||||||
|  | 
 | ||||||
|  | 	/* Extract informations. */ | ||||||
|  | 	grants = m_in.COUNT; | ||||||
|  | 	if((r = sys_safecopyfrom(who_e, grant_id, 0, (vir_bytes) iov_proc, | ||||||
|  | 		grants * sizeof(iovec_t), D)) != OK) { | ||||||
|  | 		panic(__FILE__, "copying in grant vector failed", r); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pos = make64(m_in.POSITION, m_in.HIGHPOS); | ||||||
|  | 	for(size = 0, i = 0; i < grants; i++) | ||||||
|  | 		size += iov_proc[i].iov_size; | ||||||
|  | 
 | ||||||
|  | 	if (rem64u(pos, SECTOR_SIZE) != 0 || size % SECTOR_SIZE != 0) { | ||||||
|  | 		printf("Filter: unaligned request from caller!\n"); | ||||||
|  | 		return EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buffer = flt_malloc(size, buf_array, BUF_SIZE); | ||||||
|  | 
 | ||||||
|  | 	if(flag_rw == FLT_WRITE) | ||||||
|  | 		vcarry(grants, iov_proc, flag_rw, size); | ||||||
|  | 
 | ||||||
|  | 	reset_kills(); | ||||||
|  | 
 | ||||||
|  | 	for (;;) { | ||||||
|  | 		size_ret = size; | ||||||
|  | 		r = transfer(pos, buffer, &size_ret, flag_rw); | ||||||
|  | 		if(r != RET_REDO) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: transfer yielded RET_REDO, checking drivers\n"); | ||||||
|  | #endif | ||||||
|  | 		if((r = check_driver(DRIVER_MAIN)) != OK) break; | ||||||
|  | 		if((r = check_driver(DRIVER_BACKUP)) != OK) break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(r != OK) { | ||||||
|  | 		flt_free(buffer, size, buf_array); | ||||||
|  | 		return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if(flag_rw == FLT_READ) | ||||||
|  | 		vcarry(grants, iov_proc, flag_rw, size_ret); | ||||||
|  | 
 | ||||||
|  | 	/* Set the result-iovec. */ | ||||||
|  | 	for(i = 0; i < grants && size_ret > 0; i++) { | ||||||
|  | 		bytes = MIN(size_ret, iov_proc[i].iov_size); | ||||||
|  | 
 | ||||||
|  | 		iov_proc[i].iov_size -= bytes; | ||||||
|  | 		size_ret -= bytes; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Copy the caller's grant-table back. */ | ||||||
|  | 	if((r = sys_safecopyto(who_e, grant_id, 0, (vir_bytes) iov_proc, | ||||||
|  | 		grants * sizeof(iovec_t), D)) != OK) { | ||||||
|  | 		panic(__FILE__, "copying out grant vector failed", r); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flt_free(buffer, size, buf_array); | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				do_ioctl				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int do_ioctl(message *m) | ||||||
|  | { | ||||||
|  | 	struct partition sizepart; | ||||||
|  | 
 | ||||||
|  | 	switch(m->REQUEST) { | ||||||
|  | 	case DIOCSETP: | ||||||
|  | 	case DIOCTIMEOUT: | ||||||
|  | 	case DIOCOPENCT: | ||||||
|  | 		/* These do not make sense for us. */ | ||||||
|  | 		return EINVAL; | ||||||
|  | 
 | ||||||
|  | 	case DIOCGETP: | ||||||
|  | 		memset(&sizepart, 0, sizeof(sizepart)); | ||||||
|  | 
 | ||||||
|  | 		/* The presented disk size is the raw partition size,
 | ||||||
|  | 		 * corrected for space needed for checksums. | ||||||
|  | 		 */ | ||||||
|  | 		sizepart.size = convert(get_raw_size()); | ||||||
|  | 
 | ||||||
|  | 		if(sys_safecopyto(proc_e, (vir_bytes) grant_id, 0, | ||||||
|  | 				(vir_bytes) &sizepart, | ||||||
|  | 				sizeof(struct partition), D) != OK) { | ||||||
|  | 			printf("Filter: DIOCGETP safecopyto failed\n"); | ||||||
|  | 			return EIO; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		printf("Filter: unknown ioctl request: %d!\n", m->REQUEST); | ||||||
|  | 		return EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				parse_arguments				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int parse_arguments(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	if(argc != 2) | ||||||
|  | 		return EINVAL; | ||||||
|  | 
 | ||||||
|  | 	optset_parse(optset_table, argv[1]); | ||||||
|  | 
 | ||||||
|  | 	if (MAIN_LABEL[0] == 0 || MAIN_MINOR < 0 || MAIN_MINOR > 255) | ||||||
|  | 		return EINVAL; | ||||||
|  | 	if (USE_MIRROR && (BACKUP_LABEL[0] == 0 || | ||||||
|  | 			BACKUP_MINOR < 0 || BACKUP_MINOR > 255)) | ||||||
|  | 		return EINVAL; | ||||||
|  | 
 | ||||||
|  | 	/* Checksumming implies a checksum layout. */ | ||||||
|  | 	if (USE_CHECKSUM) | ||||||
|  | 		USE_SUM_LAYOUT = 1; | ||||||
|  | 
 | ||||||
|  | 	/* Determine the checksum size for the chosen checksum type. */ | ||||||
|  | 	switch (SUM_TYPE) { | ||||||
|  | 	case ST_XOR: | ||||||
|  | 		SUM_SIZE = 16;	/* compatibility */ | ||||||
|  | 		break; | ||||||
|  | 	case ST_CRC: | ||||||
|  | 		SUM_SIZE = 4; | ||||||
|  | 		break; | ||||||
|  | 	case ST_MD5: | ||||||
|  | 		SUM_SIZE = 16; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (NR_SUM_SEC <= 0 || SUM_SIZE * NR_SUM_SEC > SECTOR_SIZE) | ||||||
|  | 		return EINVAL; | ||||||
|  | 
 | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter starting. Configuration:\n"); | ||||||
|  | 	printf("  USE_CHECKSUM :   %3s ", USE_CHECKSUM ? "yes" : "no"); | ||||||
|  | 	printf("  USE_MIRROR : %3s\n", USE_MIRROR ? "yes" : "no"); | ||||||
|  | 
 | ||||||
|  | 	if (USE_CHECKSUM) { | ||||||
|  | 		printf("  BAD_SUM_ERROR :  %3s ", | ||||||
|  | 			BAD_SUM_ERROR ? "yes" : "no"); | ||||||
|  | 		printf("  NR_SUM_SEC : %3d\n", NR_SUM_SEC); | ||||||
|  | 
 | ||||||
|  | 		printf("  SUM_TYPE :       "); | ||||||
|  | 
 | ||||||
|  | 		switch (SUM_TYPE) { | ||||||
|  | 		case ST_XOR: printf("xor"); break; | ||||||
|  | 		case ST_CRC: printf("crc"); break; | ||||||
|  | 		case ST_MD5: printf("md5"); break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		printf("   SUM_SIZE :   %3d\n", SUM_SIZE); | ||||||
|  | 	} | ||||||
|  | 	else printf("  USE_SUM_LAYOUT : %3s\n", USE_SUM_LAYOUT ? "yes" : "no"); | ||||||
|  | 
 | ||||||
|  | 	printf("  N : %3dx       M : %3dx        T : %3ds\n", | ||||||
|  | 		NR_RETRIES, NR_RESTARTS, DRIVER_TIMEOUT); | ||||||
|  | 
 | ||||||
|  | 	printf("  MAIN_LABEL / MAIN_MINOR : %19s / %d\n", | ||||||
|  | 		MAIN_LABEL, MAIN_MINOR); | ||||||
|  | 	if (USE_MIRROR) { | ||||||
|  | 		printf("  BACKUP_LABEL / BACKUP_MINOR : %15s / %d\n",	 | ||||||
|  | 			BACKUP_LABEL, BACKUP_MINOR); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	/* Convert timeout seconds to ticks. */ | ||||||
|  | 	DRIVER_TIMEOUT *= sys_hz(); | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				got_signal				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void got_signal(void) | ||||||
|  | { | ||||||
|  | 	sigset_t set; | ||||||
|  | 
 | ||||||
|  | 	/* See if PM sent us a SIGTERM. */ | ||||||
|  | 	if (getsigset(&set) != 0) return; | ||||||
|  | 
 | ||||||
|  | 	if (!sigismember(&set, SIGTERM)) return; | ||||||
|  | 
 | ||||||
|  | 	/* If so, shut down this driver. */ | ||||||
|  | #if DEBUG | ||||||
|  | 	printf("Filter: shutdown...\n"); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	driver_shutdown(); | ||||||
|  | 
 | ||||||
|  | 	exit(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				main					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | int main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	message m_out; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	r = parse_arguments(argc, argv); | ||||||
|  | 	if(r != OK) { | ||||||
|  | 		printf("Filter: wrong argument!\n"); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((buf_array = alloc_contig(BUF_SIZE, 0, NULL)) == NULL) | ||||||
|  | 		panic(__FILE__, "no memory available", NO_NUM); | ||||||
|  | 
 | ||||||
|  | 	sum_init(); | ||||||
|  | 
 | ||||||
|  | 	driver_init(); | ||||||
|  | 
 | ||||||
|  | 	for (;;) { | ||||||
|  | 		/* Wait for request. */ | ||||||
|  | 		if(receive(ANY, &m_in) != OK) { | ||||||
|  | 			panic(__FILE__, "receive failed", NO_NUM); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 		printf("Filter: got request %d from %d\n", | ||||||
|  | 			m_in.m_type, m_in.m_source); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		if (is_notify(m_in.m_type) && m_in.m_source == PM_PROC_NR) | ||||||
|  | 			got_signal(); | ||||||
|  | 
 | ||||||
|  | 		who_e = m_in.m_source; | ||||||
|  | 		proc_e = m_in.IO_ENDPT; | ||||||
|  | 		grant_id = (cp_grant_id_t) m_in.IO_GRANT; | ||||||
|  | 
 | ||||||
|  | 		/* Forword the request message to the drivers. */ | ||||||
|  | 		switch(m_in.m_type) { | ||||||
|  | 		case DEV_OPEN:		/* open/close is a noop for filter. */ | ||||||
|  | 		case DEV_CLOSE:		r = OK;				break; | ||||||
|  | 		case DEV_READ_S:	r = do_rdwt(FLT_READ);		break; | ||||||
|  | 		case DEV_WRITE_S:	r = do_rdwt(FLT_WRITE);		break; | ||||||
|  | 		case DEV_GATHER_S:	r = do_vrdwt(FLT_READ);		break; | ||||||
|  | 		case DEV_SCATTER_S:	r = do_vrdwt(FLT_WRITE);	break; | ||||||
|  | 		case DEV_IOCTL_S:	r = do_ioctl(&m_in);		break; | ||||||
|  | 
 | ||||||
|  | 		default: | ||||||
|  | 			printf("Filter: ignoring unknown request %d from %d\n",  | ||||||
|  | 				m_in.m_type, m_in.m_source); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 		printf("Filter: replying with code %d\n", r); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		/* Send back reply message. */ | ||||||
|  | 		m_out.m_type = TASK_REPLY; | ||||||
|  | 		m_out.REP_ENDPT = proc_e; | ||||||
|  | 		m_out.REP_STATUS = r; | ||||||
|  | 		send(who_e, &m_out); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
							
								
								
									
										315
									
								
								drivers/filter/md5.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								drivers/filter/md5.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,315 @@ | |||||||
|  | /*
 | ||||||
|  |  * This code implements the MD5 message-digest algorithm. | ||||||
|  |  * The algorithm is due to Ron Rivest.  This code was | ||||||
|  |  * written by Colin Plumb in 1993, no copyright is claimed. | ||||||
|  |  * This code is in the public domain; do with it what you wish. | ||||||
|  |  * | ||||||
|  |  * Equivalent code is available from RSA Data Security, Inc. | ||||||
|  |  * This code has been tested against that, and is equivalent, | ||||||
|  |  * except that you don't need to include two pages of legalese | ||||||
|  |  * with every copy. | ||||||
|  |  * | ||||||
|  |  * To compute the message digest of a chunk of bytes, declare an | ||||||
|  |  * MD5Context structure, pass it to MD5Init, call MD5Update as | ||||||
|  |  * needed on buffers full of bytes, and then call MD5Final, which | ||||||
|  |  * will fill a supplied 16-byte array with the digest. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
 | ||||||
|  |    not require an integer type which is exactly 32 bits.  This work | ||||||
|  |    draws on the changes for the same purpose by Tatu Ylonen | ||||||
|  |    <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use | ||||||
|  |    that code, there is no copyright issue.  I hereby disclaim | ||||||
|  |    copyright in any changes I have made; this code remains in the | ||||||
|  |    public domain.  */ | ||||||
|  | 
 | ||||||
|  | #ifdef TEST | ||||||
|  | #include <stdlib.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <string.h>	/* for memcpy() and memset() */ | ||||||
|  | 
 | ||||||
|  | #include "md5.h" | ||||||
|  | 
 | ||||||
|  | /* Little-endian byte-swapping routines.  Note that these do not
 | ||||||
|  |    depend on the size of datatypes such as uint32, nor do they require | ||||||
|  |    us to detect the endianness of the machine we are running on.  It | ||||||
|  |    is possible they should be macros for speed, but I would be | ||||||
|  |    surprised if they were a performance bottleneck for MD5.  */ | ||||||
|  | 
 | ||||||
|  | static uint32 | ||||||
|  | getu32 (const unsigned char *addr) | ||||||
|  | { | ||||||
|  | 	return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | ||||||
|  | 		| addr[1]) << 8 | addr[0]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | putu32 (uint32 data, unsigned char *addr) | ||||||
|  | { | ||||||
|  | 	addr[0] = (unsigned char)data; | ||||||
|  | 	addr[1] = (unsigned char)(data >> 8); | ||||||
|  | 	addr[2] = (unsigned char)(data >> 16); | ||||||
|  | 	addr[3] = (unsigned char)(data >> 24); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious | ||||||
|  |  * initialization constants. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | MD5Init (ctx) | ||||||
|  |      struct MD5Context *ctx; | ||||||
|  | { | ||||||
|  | 	ctx->buf[0] = 0x67452301; | ||||||
|  | 	ctx->buf[1] = 0xefcdab89; | ||||||
|  | 	ctx->buf[2] = 0x98badcfe; | ||||||
|  | 	ctx->buf[3] = 0x10325476; | ||||||
|  | 
 | ||||||
|  | 	ctx->bits[0] = 0; | ||||||
|  | 	ctx->bits[1] = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Update context to reflect the concatenation of another buffer full | ||||||
|  |  * of bytes. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | MD5Update (ctx, buf, len) | ||||||
|  |      struct MD5Context *ctx; | ||||||
|  |      unsigned char const *buf; | ||||||
|  |      unsigned len; | ||||||
|  | { | ||||||
|  | 	uint32 t; | ||||||
|  | 
 | ||||||
|  | 	/* Update bitcount */ | ||||||
|  | 
 | ||||||
|  | 	t = ctx->bits[0]; | ||||||
|  | 	if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t) | ||||||
|  | 		ctx->bits[1]++;	/* Carry from low to high */ | ||||||
|  | 	ctx->bits[1] += len >> 29; | ||||||
|  | 
 | ||||||
|  | 	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */ | ||||||
|  | 
 | ||||||
|  | 	/* Handle any leading odd-sized chunks */ | ||||||
|  | 
 | ||||||
|  | 	if ( t ) { | ||||||
|  | 		unsigned char *p = ctx->in + t; | ||||||
|  | 
 | ||||||
|  | 		t = 64-t; | ||||||
|  | 		if (len < t) { | ||||||
|  | 			memcpy(p, buf, len); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		memcpy(p, buf, t); | ||||||
|  | 		MD5Transform (ctx->buf, ctx->in); | ||||||
|  | 		buf += t; | ||||||
|  | 		len -= t; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Process data in 64-byte chunks */ | ||||||
|  | 
 | ||||||
|  | 	while (len >= 64) { | ||||||
|  | 		memcpy(ctx->in, buf, 64); | ||||||
|  | 		MD5Transform (ctx->buf, ctx->in); | ||||||
|  | 		buf += 64; | ||||||
|  | 		len -= 64; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Handle any remaining bytes of data. */ | ||||||
|  | 
 | ||||||
|  | 	memcpy(ctx->in, buf, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Final wrapup - pad to 64-byte boundary with the bit pattern  | ||||||
|  |  * 1 0* (64-bit count of bits processed, MSB-first) | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | MD5Final (digest, ctx) | ||||||
|  |      unsigned char digest[16]; | ||||||
|  |      struct MD5Context *ctx; | ||||||
|  | { | ||||||
|  | 	unsigned count; | ||||||
|  | 	unsigned char *p; | ||||||
|  | 
 | ||||||
|  | 	/* Compute number of bytes mod 64 */ | ||||||
|  | 	count = (ctx->bits[0] >> 3) & 0x3F; | ||||||
|  | 
 | ||||||
|  | 	/* Set the first char of padding to 0x80.  This is safe since there is
 | ||||||
|  | 	   always at least one byte free */ | ||||||
|  | 	p = ctx->in + count; | ||||||
|  | 	*p++ = 0x80; | ||||||
|  | 
 | ||||||
|  | 	/* Bytes of padding needed to make 64 bytes */ | ||||||
|  | 	count = 64 - 1 - count; | ||||||
|  | 
 | ||||||
|  | 	/* Pad out to 56 mod 64 */ | ||||||
|  | 	if (count < 8) { | ||||||
|  | 		/* Two lots of padding:  Pad the first block to 64 bytes */ | ||||||
|  | 		memset(p, 0, count); | ||||||
|  | 		MD5Transform (ctx->buf, ctx->in); | ||||||
|  | 
 | ||||||
|  | 		/* Now fill the next block with 56 bytes */ | ||||||
|  | 		memset(ctx->in, 0, 56); | ||||||
|  | 	} else { | ||||||
|  | 		/* Pad block to 56 bytes */ | ||||||
|  | 		memset(p, 0, count-8); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Append length in bits and transform */ | ||||||
|  | 	putu32(ctx->bits[0], ctx->in + 56); | ||||||
|  | 	putu32(ctx->bits[1], ctx->in + 60); | ||||||
|  | 
 | ||||||
|  | 	MD5Transform (ctx->buf, ctx->in); | ||||||
|  | 	putu32(ctx->buf[0], digest); | ||||||
|  | 	putu32(ctx->buf[1], digest + 4); | ||||||
|  | 	putu32(ctx->buf[2], digest + 8); | ||||||
|  | 	putu32(ctx->buf[3], digest + 12); | ||||||
|  | 	memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifndef ASM_MD5 | ||||||
|  | 
 | ||||||
|  | /* The four core functions - F1 is optimized somewhat */ | ||||||
|  | 
 | ||||||
|  | /* #define F1(x, y, z) (x & y | ~x & z) */ | ||||||
|  | #define F1(x, y, z) (z ^ (x & (y ^ z))) | ||||||
|  | #define F2(x, y, z) F1(z, x, y) | ||||||
|  | #define F3(x, y, z) (x ^ y ^ z) | ||||||
|  | #define F4(x, y, z) (y ^ (x | ~z)) | ||||||
|  | 
 | ||||||
|  | /* This is the central step in the MD5 algorithm. */ | ||||||
|  | #define MD5STEP(f, w, x, y, z, data, s) \ | ||||||
|  | 	( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x ) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * The core of the MD5 algorithm, this alters an existing MD5 hash to | ||||||
|  |  * reflect the addition of 16 longwords of new data.  MD5Update blocks | ||||||
|  |  * the data and converts bytes into longwords for this routine. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | MD5Transform (buf, inraw) | ||||||
|  |      uint32 buf[4]; | ||||||
|  |      const unsigned char inraw[64]; | ||||||
|  | { | ||||||
|  | 	register uint32 a, b, c, d; | ||||||
|  | 	uint32 in[16]; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < 16; ++i) | ||||||
|  | 		in[i] = getu32 (inraw + 4 * i); | ||||||
|  | 
 | ||||||
|  | 	a = buf[0]; | ||||||
|  | 	b = buf[1]; | ||||||
|  | 	c = buf[2]; | ||||||
|  | 	d = buf[3]; | ||||||
|  | 
 | ||||||
|  | 	MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7); | ||||||
|  | 	MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); | ||||||
|  | 	MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); | ||||||
|  | 	MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); | ||||||
|  | 	MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7); | ||||||
|  | 	MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); | ||||||
|  | 	MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); | ||||||
|  | 	MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); | ||||||
|  | 	MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7); | ||||||
|  | 	MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); | ||||||
|  | 	MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); | ||||||
|  | 	MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); | ||||||
|  | 	MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7); | ||||||
|  | 	MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); | ||||||
|  | 	MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); | ||||||
|  | 	MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); | ||||||
|  | 
 | ||||||
|  | 	MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5); | ||||||
|  | 	MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9); | ||||||
|  | 	MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); | ||||||
|  | 	MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); | ||||||
|  | 	MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5); | ||||||
|  | 	MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9); | ||||||
|  | 	MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); | ||||||
|  | 	MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); | ||||||
|  | 	MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5); | ||||||
|  | 	MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9); | ||||||
|  | 	MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); | ||||||
|  | 	MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); | ||||||
|  | 	MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5); | ||||||
|  | 	MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9); | ||||||
|  | 	MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); | ||||||
|  | 	MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); | ||||||
|  | 
 | ||||||
|  | 	MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4); | ||||||
|  | 	MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); | ||||||
|  | 	MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); | ||||||
|  | 	MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); | ||||||
|  | 	MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4); | ||||||
|  | 	MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); | ||||||
|  | 	MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); | ||||||
|  | 	MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); | ||||||
|  | 	MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4); | ||||||
|  | 	MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); | ||||||
|  | 	MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); | ||||||
|  | 	MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); | ||||||
|  | 	MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4); | ||||||
|  | 	MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); | ||||||
|  | 	MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); | ||||||
|  | 	MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); | ||||||
|  | 
 | ||||||
|  | 	MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6); | ||||||
|  | 	MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); | ||||||
|  | 	MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); | ||||||
|  | 	MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); | ||||||
|  | 	MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6); | ||||||
|  | 	MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); | ||||||
|  | 	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); | ||||||
|  | 	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); | ||||||
|  | 	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6); | ||||||
|  | 	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); | ||||||
|  | 	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); | ||||||
|  | 	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); | ||||||
|  | 	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6); | ||||||
|  | 	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); | ||||||
|  | 	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); | ||||||
|  | 	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); | ||||||
|  | 
 | ||||||
|  | 	buf[0] += a; | ||||||
|  | 	buf[1] += b; | ||||||
|  | 	buf[2] += c; | ||||||
|  | 	buf[3] += d; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef TEST | ||||||
|  | /* Simple test program.  Can use it to manually run the tests from
 | ||||||
|  |    RFC1321 for example.  */ | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | main (int argc, char **argv) | ||||||
|  | { | ||||||
|  | 	struct MD5Context context; | ||||||
|  | 	unsigned char checksum[16]; | ||||||
|  | 	int i; | ||||||
|  | 	int j; | ||||||
|  | 
 | ||||||
|  | 	if (argc < 2) | ||||||
|  | 	{ | ||||||
|  | 		fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); | ||||||
|  | 		exit (1); | ||||||
|  | 	} | ||||||
|  | 	for (j = 1; j < argc; ++j) | ||||||
|  | 	{ | ||||||
|  | 		printf ("MD5 (\"%s\") = ", argv[j]); | ||||||
|  | 		MD5Init (&context); | ||||||
|  | 		MD5Update (&context, (unsigned char *)argv[j], strlen (argv[j])); | ||||||
|  | 		MD5Final (checksum, &context); | ||||||
|  | 		for (i = 0; i < 16; i++) | ||||||
|  | 		{ | ||||||
|  | 			printf ("%02x", (unsigned int) checksum[i]); | ||||||
|  | 		} | ||||||
|  | 		printf ("\n"); | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif /* TEST */ | ||||||
							
								
								
									
										26
									
								
								drivers/filter/md5.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								drivers/filter/md5.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | /* See md5.c for explanation and copyright information.  */ | ||||||
|  | 
 | ||||||
|  | #ifndef MD5_H | ||||||
|  | #define MD5_H | ||||||
|  | 
 | ||||||
|  | /* Unlike previous versions of this code, uint32 need not be exactly
 | ||||||
|  |    32 bits, merely 32 bits or more.  Choosing a data type which is 32 | ||||||
|  |    bits instead of 64 is not important; speed is considerably more | ||||||
|  |    important.  ANSI guarantees that "unsigned long" will be big enough, | ||||||
|  |    and always using it seems to have few disadvantages.  */ | ||||||
|  | typedef unsigned long uint32; | ||||||
|  | 
 | ||||||
|  | struct MD5Context { | ||||||
|  | 	uint32 buf[4]; | ||||||
|  | 	uint32 bits[2]; | ||||||
|  | 	unsigned char in[64]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void MD5Init(struct MD5Context *context); | ||||||
|  | void MD5Update(struct MD5Context *context, | ||||||
|  | 			   unsigned char const *buf, unsigned len); | ||||||
|  | void MD5Final(unsigned char digest[16], | ||||||
|  | 			  struct MD5Context *context); | ||||||
|  | void MD5Transform(uint32 buf[4], const unsigned char in[64]); | ||||||
|  | 
 | ||||||
|  | #endif /* !MD5_H */ | ||||||
							
								
								
									
										128
									
								
								drivers/filter/optset.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								drivers/filter/optset.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | /* This file provides functionality to parse strings of comma-separated
 | ||||||
|  |  * options, each being either a single key name or a key=value pair, where the | ||||||
|  |  * value may be enclosed in quotes. A table of optset entries is provided to | ||||||
|  |  * determine which options are recognized, how to parse their values, and where | ||||||
|  |  * to store those. Unrecognized options are silently ignored; improperly | ||||||
|  |  * formatted options are silently set to reasonably acceptable values. | ||||||
|  |  * | ||||||
|  |  * The entry points into this file are: | ||||||
|  |  *   optset_parse	parse the given options string using the given table | ||||||
|  |  * | ||||||
|  |  * Created: | ||||||
|  |  *   May 2009 (D.C. van Moolenbroek) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define _MINIX 1 | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <minix/config.h> | ||||||
|  | #include <minix/const.h> | ||||||
|  | 
 | ||||||
|  | #include "optset.h" | ||||||
|  | 
 | ||||||
|  | FORWARD _PROTOTYPE( void optset_parse_entry, (struct optset *entry, | ||||||
|  | 						char *ptr, int len)	); | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				optset_parse_entry			     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | PRIVATE void optset_parse_entry(entry, ptr, len) | ||||||
|  | struct optset *entry; | ||||||
|  | char *ptr; | ||||||
|  | int len; | ||||||
|  | { | ||||||
|  | /* Parse and store the value of a single option.
 | ||||||
|  |  */ | ||||||
|  |   char *dst; | ||||||
|  |   int val; | ||||||
|  | 
 | ||||||
|  |   switch (entry->os_type) { | ||||||
|  |   case OPT_BOOL: | ||||||
|  | 	*((int *) entry->os_ptr) = entry->os_val; | ||||||
|  | 
 | ||||||
|  | 	break; | ||||||
|  | 
 | ||||||
|  |   case OPT_STRING: | ||||||
|  | 	if (len >= entry->os_val) | ||||||
|  | 		len = entry->os_val - 1; | ||||||
|  | 
 | ||||||
|  | 	dst = (char *) entry->os_ptr; | ||||||
|  | 
 | ||||||
|  | 	if (len > 0) | ||||||
|  | 		memcpy(dst, ptr, len); | ||||||
|  | 	dst[len] = 0; | ||||||
|  | 
 | ||||||
|  | 	break; | ||||||
|  | 
 | ||||||
|  |   case OPT_INT: | ||||||
|  | 	if (len > 0) | ||||||
|  | 		val = strtol(ptr, NULL, entry->os_val); | ||||||
|  | 	else | ||||||
|  | 		val = 0; | ||||||
|  | 
 | ||||||
|  | 	*((int *) entry->os_ptr) = val; | ||||||
|  | 
 | ||||||
|  | 	break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				optset_parse				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | PUBLIC void optset_parse(table, string) | ||||||
|  | struct optset *table; | ||||||
|  | char *string; | ||||||
|  | { | ||||||
|  | /* Parse a string of options, using the provided table of optset entries.
 | ||||||
|  |  */ | ||||||
|  |   char *p, *kptr, *vptr; | ||||||
|  |   int i, klen, vlen; | ||||||
|  | 
 | ||||||
|  |   for (p = string; *p; ) { | ||||||
|  | 	/* Get the key name for the field. */ | ||||||
|  | 	for (kptr = p, klen = 0; *p && *p != '=' && *p != ','; p++, klen++); | ||||||
|  | 
 | ||||||
|  | 	if (*p == '=') { | ||||||
|  | 		/* The field has an associated value. */ | ||||||
|  | 		vptr = ++p; | ||||||
|  | 
 | ||||||
|  | 		/* If the first character after the '=' is a quote character,
 | ||||||
|  | 		 * find a matching quote character followed by either a comma | ||||||
|  | 		 * or the terminating null character, and use the string in | ||||||
|  | 		 * between. Otherwise, use the string up to the next comma or | ||||||
|  | 		 * the terminating null character. | ||||||
|  | 		 */ | ||||||
|  | 		if (*p == '\'' || *p == '"') { | ||||||
|  | 			p++; | ||||||
|  | 
 | ||||||
|  | 			for (vlen = 0; *p && (*p != *vptr || | ||||||
|  | 				(p[1] && p[1] != ',')); p++, vlen++); | ||||||
|  | 
 | ||||||
|  | 			if (*p) p++; | ||||||
|  | 			vptr++; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 			for (vlen = 0; *p && *p != ','; p++, vlen++); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		vptr = NULL; | ||||||
|  | 		vlen = 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (*p == ',') p++; | ||||||
|  | 
 | ||||||
|  | 	/* Find a matching entry for this key in the given table. If found,
 | ||||||
|  | 	 * call optset_parse_entry() on it. Silently ignore the option | ||||||
|  | 	 * otherwise. | ||||||
|  | 	 */ | ||||||
|  | 	for (i = 0; table[i].os_name != NULL; i++) { | ||||||
|  | 		if (strlen(table[i].os_name) == klen && | ||||||
|  | 			!strncasecmp(table[i].os_name, kptr, klen)) { | ||||||
|  | 
 | ||||||
|  | 			optset_parse_entry(&table[i], vptr, vlen); | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								drivers/filter/optset.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								drivers/filter/optset.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #ifndef _OPTSET_H | ||||||
|  | #define _OPTSET_H | ||||||
|  | 
 | ||||||
|  | enum { | ||||||
|  |   OPT_BOOL, | ||||||
|  |   OPT_STRING, | ||||||
|  |   OPT_INT | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* An entry for the parser of an options set. The 'os_name' field must point
 | ||||||
|  |  * to a string, which is treated case-insensitively; the last entry of a table | ||||||
|  |  * must have NULL name. The 'os_type' field must be set to one of the OPT_ | ||||||
|  |  * values defined above. The 'os_ptr' field must point to the field that is to | ||||||
|  |  * receive the value of a recognized option. For OPT_STRING, it must point to a | ||||||
|  |  * string of a size set in 'os_val'; the resulting string may be truncated, but | ||||||
|  |  * will always be null-terminated. For OPT_BOOL, it must point to an int which | ||||||
|  |  * will be set to the value in 'os_val' if the option is present. For OPT_INT, | ||||||
|  |  * it must point to an int which will be set to the provided option value; | ||||||
|  |  * 'os_val' is then a base passed to strtol(). | ||||||
|  |  */ | ||||||
|  | struct optset { | ||||||
|  |   char *os_name; | ||||||
|  |   int os_type; | ||||||
|  |   void *os_ptr; | ||||||
|  |   int os_val; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | _PROTOTYPE( void optset_parse, (struct optset *table, char *string)	); | ||||||
|  | 
 | ||||||
|  | #endif /* _OPTSET_H */ | ||||||
							
								
								
									
										613
									
								
								drivers/filter/sum.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										613
									
								
								drivers/filter/sum.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,613 @@ | |||||||
|  | /* Filter driver - middle layer - checksumming */ | ||||||
|  | 
 | ||||||
|  | #include "inc.h" | ||||||
|  | #include "crc.h" | ||||||
|  | #include "md5.h" | ||||||
|  | 
 | ||||||
|  | #define GROUP_SIZE	(SECTOR_SIZE * NR_SUM_SEC) | ||||||
|  | #define SEC2SUM_NR(nr)	((nr)/NR_SUM_SEC*(NR_SUM_SEC+1) + NR_SUM_SEC) | ||||||
|  | #define LOG2PHYS(nr)	((nr)/NR_SUM_SEC*(NR_SUM_SEC+1) + (nr)%NR_SUM_SEC) | ||||||
|  | 
 | ||||||
|  | #define POS2SEC(nr)	div64u((nr), SECTOR_SIZE) | ||||||
|  | #define SEC2POS(nr)	mul64u((nr), SECTOR_SIZE) | ||||||
|  | 
 | ||||||
|  | /* Data buffers. */ | ||||||
|  | static char *ext_array, *ext_buffer;	/* interspersed buffer */ | ||||||
|  | static char *rb0_array;			/* write readback buffer for disk 0 */ | ||||||
|  | static char *rb1_array;			/* write readback buffer for disk 1 */ | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				sum_init				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void sum_init(void) | ||||||
|  | { | ||||||
|  |   /* Initialize buffers. */ | ||||||
|  | 
 | ||||||
|  |   ext_array = alloc_contig(SBUF_SIZE, 0, NULL); | ||||||
|  |   rb0_array = alloc_contig(SBUF_SIZE, 0, NULL); | ||||||
|  |   rb1_array = alloc_contig(SBUF_SIZE, 0, NULL); | ||||||
|  | 
 | ||||||
|  |   if (ext_array == NULL || rb0_array == NULL || rb1_array == NULL) | ||||||
|  | 	panic(__FILE__, "no memory available", NO_NUM); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				calc_sum				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void calc_sum(unsigned sector, char *data, char *sum) | ||||||
|  | { | ||||||
|  | 	/* Compute the checksum for a sector. The sector number must be part
 | ||||||
|  | 	 * of the checksum in some way. | ||||||
|  | 	 */ | ||||||
|  | 	unsigned long crc, *p, *q; | ||||||
|  | 	int i, j; | ||||||
|  | 	struct MD5Context ctx; | ||||||
|  | 
 | ||||||
|  | 	switch(SUM_TYPE) { | ||||||
|  | 	case ST_XOR: | ||||||
|  | 		/* Basic XOR checksum */ | ||||||
|  | 		p = (unsigned long *) data; | ||||||
|  | 
 | ||||||
|  | 		memset(sum, 0, SUM_SIZE); | ||||||
|  | 		for(i = 0; i < SECTOR_SIZE / SUM_SIZE; i++) { | ||||||
|  | 			q = (unsigned long *) sum; | ||||||
|  | 			for(j = 0; j < SUM_SIZE / sizeof(*p); j++) { | ||||||
|  | 				*q ^= *p; | ||||||
|  | 				q++; | ||||||
|  | 				p++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		q = (unsigned long *) sum; | ||||||
|  | 		*q ^= sector; | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case ST_CRC: | ||||||
|  | 		/* CRC32 checksum */ | ||||||
|  | 
 | ||||||
|  | 		crc = compute_crc((unsigned char *) data, SECTOR_SIZE); | ||||||
|  | 
 | ||||||
|  | 		q = (unsigned long *) sum; | ||||||
|  | 
 | ||||||
|  | 		*q = crc ^ sector; | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case ST_MD5: | ||||||
|  | 		/* MD5 checksum */ | ||||||
|  | 
 | ||||||
|  | 		MD5Init(&ctx); | ||||||
|  | 		MD5Update(&ctx, (unsigned char *) data, SECTOR_SIZE); | ||||||
|  | 		MD5Update(&ctx, (unsigned char *) §or, sizeof(sector)); | ||||||
|  | 		MD5Final((unsigned char *) sum, &ctx); | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		panic(__FILE__, "invalid checksum type", SUM_TYPE); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				read_sectors				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int read_sectors(char *buf, sector_t phys_sector, int count) | ||||||
|  | { | ||||||
|  | 	/* Read 'count' sectors starting at 'phys_sector' into 'buf'. If an
 | ||||||
|  | 	 * EOF occurs, zero-fill the remaining part of the buffer. | ||||||
|  | 	 */ | ||||||
|  | 	size_t size, wsize; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	size = wsize = count * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 	r = read_write(SEC2POS(phys_sector), buf, buf, &size, FLT_READ); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) | ||||||
|  | 		return r; | ||||||
|  | 
 | ||||||
|  | 	if (size != wsize) { | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: EOF reading sector %lu\n", phys_sector); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		memset(buf + size, 0, wsize - size); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				make_group_sum				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void make_group_sum(char *bufp, char *sump, sector_t sector, int index, | ||||||
|  |  int count) | ||||||
|  | { | ||||||
|  | 	/* Compute checksums for 'count' sectors within a group, starting at
 | ||||||
|  | 	 * sector 'index' into the group, which has logical sector number | ||||||
|  | 	 * 'sector'. The 'bufp' pointer points to the same first sector to | ||||||
|  | 	 * start checksumming; 'sump' is a pointer to the checksum sector. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	sump += index * SUM_SIZE; | ||||||
|  | 
 | ||||||
|  | 	while (count--) { | ||||||
|  | 		calc_sum(sector, bufp, sump); | ||||||
|  | 
 | ||||||
|  | 		bufp += SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		sump += SUM_SIZE; | ||||||
|  | 		sector++; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_group_sum				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int check_group_sum(char *bufp, char *sump, sector_t sector, int index, | ||||||
|  |  int count) | ||||||
|  | { | ||||||
|  | 	/* Check checksums in a group. Parameters are the same as in
 | ||||||
|  | 	 * make_group_sum(). Return OK if all checksums check out, or RET_REDO | ||||||
|  | 	 * upon failure. | ||||||
|  | 	 */ | ||||||
|  | 	char sum_buffer[SECTOR_SIZE]; | ||||||
|  | 
 | ||||||
|  | 	sump += index * SUM_SIZE; | ||||||
|  | 
 | ||||||
|  | 	while (count--) { | ||||||
|  | 		calc_sum(sector, bufp, sum_buffer); | ||||||
|  | 
 | ||||||
|  | 		if (memcmp(sum_buffer, sump, SUM_SIZE)) { | ||||||
|  | 			printf("Filter: BAD CHECKSUM at sector %lu\n", sector); | ||||||
|  | 
 | ||||||
|  | 			if (BAD_SUM_ERROR) | ||||||
|  | 				return bad_driver(DRIVER_MAIN, BD_DATA, EIO); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bufp += SECTOR_SIZE; | ||||||
|  | 		sump += SUM_SIZE; | ||||||
|  | 		sector++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				make_sum				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int make_sum(sector_t current_sector, sector_t sectors_left) | ||||||
|  | { | ||||||
|  | 	/* Compute checksums over all data in the buffer with expanded data.
 | ||||||
|  | 	 * As side effect, possibly read in first and last checksum sectors | ||||||
|  | 	 * and data to fill the gap between the last data sector and the last | ||||||
|  | 	 * checksum sector. | ||||||
|  | 	 */ | ||||||
|  | 	sector_t sector_in_group, group_left; | ||||||
|  | 	size_t size, gap; | ||||||
|  | 	char *extp; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	/* See the description of the extended buffer in transfer(). A number
 | ||||||
|  | 	 * of points are relevant for this function in particular: | ||||||
|  | 	 * | ||||||
|  | 	 * 1) If the "xx" head of the buffer does not cover an entire group, | ||||||
|  | 	 *    we need to copy in the first checksum sector so that we can | ||||||
|  | 	 *    modify it. | ||||||
|  | 	 * 2) We can generate checksums for the full "yyyyy" groups without | ||||||
|  | 	 *    copying in the corresponding checksum sectors first, because | ||||||
|  | 	 *    those sectors will be overwritten entirely anyway. | ||||||
|  | 	 * 3) We copy in not only the checksum sector for the group containing | ||||||
|  | 	 *    the "zzz" tail data, but also all the data between "zzz" and the | ||||||
|  | 	 *    last checksum sector. This allows us to write all the data in | ||||||
|  | 	 *    the buffer in one operation. In theory, we could verify the | ||||||
|  | 	 *    checksum of the data in this gap for extra early failure | ||||||
|  | 	 *    detection, but we currently do not do this. | ||||||
|  | 	 * | ||||||
|  | 	 * If points 1 and 3 cover the same group (implying a small, unaligned | ||||||
|  | 	 * write operation), the read operation is done only once. Whether | ||||||
|  | 	 * point 1 or 3 is skipped depends on whether there is a gap before | ||||||
|  | 	 * the checksum sector. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	sector_in_group = current_sector % NR_SUM_SEC; | ||||||
|  | 	group_left = NR_SUM_SEC - sector_in_group; | ||||||
|  | 
 | ||||||
|  | 	extp = ext_buffer; | ||||||
|  | 
 | ||||||
|  | 	/* This loop covers points 1 and 2. */ | ||||||
|  | 	while (sectors_left >= group_left) { | ||||||
|  | 		size = group_left * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		if (sector_in_group > 0) { | ||||||
|  | 			if ((r = read_sectors(extp + size, | ||||||
|  | 					LOG2PHYS(current_sector) + group_left, | ||||||
|  | 					1)) != OK) | ||||||
|  | 				return r; | ||||||
|  | 		} | ||||||
|  | 		else memset(extp + size, 0, SECTOR_SIZE); | ||||||
|  | 
 | ||||||
|  | 		make_group_sum(extp, extp + size, current_sector, | ||||||
|  | 			sector_in_group, group_left); | ||||||
|  | 
 | ||||||
|  | 		extp += size + SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		sectors_left -= group_left; | ||||||
|  | 		current_sector += group_left; | ||||||
|  | 
 | ||||||
|  | 		sector_in_group = 0; | ||||||
|  | 		group_left = NR_SUM_SEC; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* The remaining code covers point 3. */ | ||||||
|  | 	if (sectors_left > 0) { | ||||||
|  | 		size = sectors_left * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		if (group_left != NR_SUM_SEC - sector_in_group) | ||||||
|  | 			panic(__FILE__, "group_left assertion", 0); | ||||||
|  | 
 | ||||||
|  | 		gap = group_left - sectors_left; | ||||||
|  | 
 | ||||||
|  | 		if (gap <= 0) | ||||||
|  | 			panic(__FILE__, "gap assertion", 0); | ||||||
|  | 
 | ||||||
|  | 		if ((r = read_sectors(extp + size, | ||||||
|  | 				LOG2PHYS(current_sector) + sectors_left, | ||||||
|  | 				gap + 1)) != OK) | ||||||
|  | 			return r; | ||||||
|  | 
 | ||||||
|  | 		make_group_sum(extp, extp + size + gap * SECTOR_SIZE, | ||||||
|  | 			current_sector, sector_in_group, sectors_left); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_sum				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int check_sum(sector_t current_sector, size_t bytes_left) | ||||||
|  | { | ||||||
|  | 	/* Check checksums of all data in the buffer with expanded data.
 | ||||||
|  | 	 * Return OK if all checksums are okay, or RET_REDO upon failure. | ||||||
|  | 	 */ | ||||||
|  | 	sector_t sector_in_group; | ||||||
|  | 	size_t size, groupbytes_left; | ||||||
|  | 	int count; | ||||||
|  | 	char *extp; | ||||||
|  | 
 | ||||||
|  | 	extp = ext_buffer; | ||||||
|  | 
 | ||||||
|  | 	sector_in_group = current_sector % NR_SUM_SEC; | ||||||
|  | 	groupbytes_left = (NR_SUM_SEC - sector_in_group) * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 	while (bytes_left > 0) { | ||||||
|  | 		size = MIN(bytes_left, groupbytes_left); | ||||||
|  | 		count = size / SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		if (check_group_sum(extp, extp + groupbytes_left, | ||||||
|  | 				current_sector, sector_in_group, count)) | ||||||
|  | 			return RET_REDO; | ||||||
|  | 
 | ||||||
|  | 		extp += size + SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		bytes_left -= MIN(size + SECTOR_SIZE, bytes_left); | ||||||
|  | 		current_sector += count; | ||||||
|  | 
 | ||||||
|  | 		sector_in_group = 0; | ||||||
|  | 		groupbytes_left = GROUP_SIZE; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				check_write				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static int check_write(u64_t pos, size_t size) | ||||||
|  | { | ||||||
|  | 	/* Read back the data just written, from both disks if mirroring is
 | ||||||
|  | 	 * enabled, and check the result against the original. Return OK on | ||||||
|  | 	 * success; report the malfunctioning driver and return RET_REDO | ||||||
|  | 	 * otherwise. | ||||||
|  | 	 */ | ||||||
|  | 	char *rb0_buffer, *rb1_buffer; | ||||||
|  | 	size_t orig_size; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	if (size == 0) | ||||||
|  | 		return OK; | ||||||
|  | 
 | ||||||
|  | 	rb0_buffer = rb1_buffer = | ||||||
|  | 		flt_malloc(size, rb0_array, SBUF_SIZE); | ||||||
|  | 	if (USE_MIRROR) | ||||||
|  | 		rb1_buffer = flt_malloc(size, rb1_array, SBUF_SIZE); | ||||||
|  | 
 | ||||||
|  | 	orig_size = size; | ||||||
|  | 
 | ||||||
|  | 	r = read_write(pos, rb0_buffer, rb1_buffer, &size, FLT_READ2); | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		if (USE_MIRROR) flt_free(rb1_buffer, orig_size, rb1_array); | ||||||
|  | 		flt_free(rb0_buffer, orig_size, rb0_array); | ||||||
|  | 
 | ||||||
|  | 		return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* If we get a size smaller than what we requested, then we somehow
 | ||||||
|  | 	 * succeeded in writing past the disk end, and now fail to read it all | ||||||
|  | 	 * back. This is not an error, and we just compare the part that we | ||||||
|  | 	 * did manage to read back in. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	if (memcmp(ext_buffer, rb0_buffer, size)) { | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: readback from disk 0 failed (size %d)\n", | ||||||
|  | 			size); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		return bad_driver(DRIVER_MAIN, BD_DATA, EFAULT); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (USE_MIRROR && memcmp(ext_buffer, rb1_buffer, size)) { | ||||||
|  | #if DEBUG | ||||||
|  | 		printf("Filter: readback from disk 1 failed (size %d)\n", | ||||||
|  | 			size); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		return bad_driver(DRIVER_BACKUP, BD_DATA, EFAULT); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (USE_MIRROR) flt_free(rb1_buffer, orig_size, rb1_array); | ||||||
|  | 	flt_free(rb0_buffer, orig_size, rb0_array); | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				expand					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void expand(sector_t first_sector, char *buffer, sector_t sectors_left) | ||||||
|  | { | ||||||
|  | 	/* Expand the contiguous data in 'buffer' to interspersed format in
 | ||||||
|  | 	 * 'ext_buffer'. The checksum areas are not touched. | ||||||
|  | 	 */ | ||||||
|  | 	char *srcp, *dstp; | ||||||
|  | 	sector_t group_left; | ||||||
|  | 	size_t size; | ||||||
|  | 	int count; | ||||||
|  | 
 | ||||||
|  | 	srcp = buffer; | ||||||
|  | 	dstp = ext_buffer; | ||||||
|  | 
 | ||||||
|  | 	group_left = NR_SUM_SEC - first_sector % NR_SUM_SEC; | ||||||
|  | 
 | ||||||
|  | 	while (sectors_left > 0) { | ||||||
|  | 		count = MIN(sectors_left, group_left); | ||||||
|  | 		size = count * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		memcpy(dstp, srcp, size); | ||||||
|  | 
 | ||||||
|  | 		srcp += size; | ||||||
|  | 		dstp += size + SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 		sectors_left -= count; | ||||||
|  | 		group_left = NR_SUM_SEC; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				collapse				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void collapse(sector_t first_sector, char *buffer, size_t *sizep) | ||||||
|  | { | ||||||
|  | 	/* Collapse the interspersed data in 'ext_buffer' to contiguous format
 | ||||||
|  | 	 * in 'buffer'. As side effect, adjust the given size to reflect the | ||||||
|  | 	 * resulting contiguous data size. | ||||||
|  | 	 */ | ||||||
|  | 	char *srcp, *dstp; | ||||||
|  | 	size_t size, bytes_left, groupbytes_left; | ||||||
|  | 
 | ||||||
|  | 	srcp = ext_buffer; | ||||||
|  | 	dstp = buffer; | ||||||
|  | 
 | ||||||
|  | 	bytes_left = *sizep; | ||||||
|  | 	groupbytes_left = | ||||||
|  | 		(NR_SUM_SEC - first_sector % NR_SUM_SEC) * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 	while (bytes_left > 0) { | ||||||
|  | 		size = MIN(bytes_left, groupbytes_left); | ||||||
|  | 
 | ||||||
|  | 		memcpy(dstp, srcp, size); | ||||||
|  | 
 | ||||||
|  | 		srcp += size + SECTOR_SIZE; | ||||||
|  | 		dstp += size; | ||||||
|  | 
 | ||||||
|  | 		bytes_left -= MIN(size + SECTOR_SIZE, bytes_left); | ||||||
|  | 		groupbytes_left = GROUP_SIZE; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	*sizep = dstp - buffer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				expand_sizes				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static size_t expand_sizes(sector_t first_sector, sector_t nr_sectors, | ||||||
|  | 	size_t *req_size) | ||||||
|  | { | ||||||
|  | 	/* Compute the size of the data area including interspersed checksum
 | ||||||
|  | 	 * sectors (req_size) and the size of the data area including | ||||||
|  | 	 * interspersed and trailing checksum sectors (the return value). | ||||||
|  | 	 */ | ||||||
|  | 	sector_t last_sector, sum_sector, phys_sector; | ||||||
|  | 
 | ||||||
|  | 	last_sector = LOG2PHYS(first_sector + nr_sectors - 1); | ||||||
|  | 
 | ||||||
|  | 	sum_sector = SEC2SUM_NR(first_sector + nr_sectors - 1); | ||||||
|  | 
 | ||||||
|  | 	phys_sector = LOG2PHYS(first_sector); | ||||||
|  | 
 | ||||||
|  | 	*req_size = (last_sector - phys_sector + 1) * SECTOR_SIZE; | ||||||
|  | 
 | ||||||
|  | 	return (sum_sector - phys_sector + 1) * SECTOR_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				collapse_size				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void collapse_size(sector_t first_sector, size_t *sizep) | ||||||
|  | { | ||||||
|  | 	/* Compute the size of the contiguous user data written to disk, given
 | ||||||
|  | 	 * the result size of the write operation with interspersed checksums. | ||||||
|  | 	 */ | ||||||
|  | 	sector_t sector_in_group; | ||||||
|  | 	size_t sectors_from_group_base, nr_sum_secs, nr_data_secs; | ||||||
|  | 
 | ||||||
|  | 	sector_in_group = first_sector % NR_SUM_SEC; | ||||||
|  | 
 | ||||||
|  | 	sectors_from_group_base = *sizep / SECTOR_SIZE + sector_in_group; | ||||||
|  | 
 | ||||||
|  | 	nr_sum_secs = sectors_from_group_base / (NR_SUM_SEC+1); | ||||||
|  | 
 | ||||||
|  | 	nr_data_secs = sectors_from_group_base - sector_in_group - nr_sum_secs; | ||||||
|  | 
 | ||||||
|  | 	*sizep = nr_data_secs * SECTOR_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				transfer				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | int transfer(u64_t pos, char *buffer, size_t *sizep, int flag_rw) | ||||||
|  | { | ||||||
|  | 	/* Transfer data in interspersed-checksum format. When writing, first
 | ||||||
|  | 	 * compute checksums, and read back the written data afterwards. When | ||||||
|  | 	 * reading, check the stored checksums afterwards. | ||||||
|  | 	 */ | ||||||
|  | 	sector_t first_sector, nr_sectors; | ||||||
|  | 	size_t ext_size, req_size, res_size; | ||||||
|  | 	u64_t phys_pos; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	/* If we don't use checksums or even checksum layout, simply pass on
 | ||||||
|  | 	 * the request to the drivers as is. | ||||||
|  | 	 */ | ||||||
|  | 	if (!USE_SUM_LAYOUT) | ||||||
|  | 		return read_write(pos, buffer, buffer, sizep, flag_rw); | ||||||
|  | 
 | ||||||
|  | 	/* The extended buffer (for checksumming) essentially looks like this:
 | ||||||
|  | 	 * | ||||||
|  | 	 *  ------------------------------ | ||||||
|  | 	 *  |xx|C|yyyyy|C|yyyyy|C|zzz  |C| | ||||||
|  | 	 *  ------------------------------ | ||||||
|  | 	 * | ||||||
|  | 	 * In this example, "xxyyyyyyyyyyzzz" is our actual data. The data is | ||||||
|  | 	 * split up into groups, so that each group is followed by a checksum | ||||||
|  | 	 * sector C containing the checksums for all data sectors in that | ||||||
|  | 	 * group. The head and tail of the actual data may cover parts of | ||||||
|  | 	 * groups; the remaining data (nor their checksums) are not to be | ||||||
|  | 	 * modified. | ||||||
|  | 	 * | ||||||
|  | 	 * The entire buffer is written or read in one operation: the | ||||||
|  | 	 * read_write() call below. In order to write, we may first have to | ||||||
|  | 	 * read some data; see the description in make_sum(). | ||||||
|  | 	 * | ||||||
|  | 	 * Some points of interest here: | ||||||
|  | 	 * - We need a buffer large enough to hold the all user and non-user | ||||||
|  | 	 *   data, from the first "xx" to the last checksum sector. This size | ||||||
|  | 	 *   is ext_size. | ||||||
|  | 	 * - For writing, we need to expand the user-provided data from | ||||||
|  | 	 *   contiguous layout to interspersed format. The size of the user | ||||||
|  | 	 *   data after expansion is req_size. | ||||||
|  | 	 * - For reading, we need to collapse the user-requested data from | ||||||
|  | 	 *   interspersed to contiguous format. For writing, we still need to | ||||||
|  | 	 *   compute the contiguous result size to return to the user. | ||||||
|  | 	 * - In both cases, the result size may be different from the | ||||||
|  | 	 *   requested write size, because an EOF (as in, disk end) may occur | ||||||
|  | 	 *   and the resulting size is less than the requested size. | ||||||
|  | 	 * - If we only follow the checksum layout, and do not do any | ||||||
|  | 	 *   checksumming, ext_size is reduced to req_size. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	first_sector = POS2SEC(pos); | ||||||
|  | 	nr_sectors = *sizep / SECTOR_SIZE; | ||||||
|  | 	phys_pos = SEC2POS(LOG2PHYS(first_sector)); | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 	printf("Filter: transfer: pos 0x%lx:0x%lx -> phys_pos 0x%lx:0x%lx\n", | ||||||
|  | 		ex64hi(pos), ex64lo(pos), ex64hi(phys_pos), ex64lo(phys_pos)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	/* Compute the size for the buffer and for the user data after
 | ||||||
|  | 	 * expansion. | ||||||
|  | 	 */ | ||||||
|  | 	ext_size = expand_sizes(first_sector, nr_sectors, &req_size); | ||||||
|  | 
 | ||||||
|  | 	if (!USE_CHECKSUM) | ||||||
|  | 		ext_size = req_size; | ||||||
|  | 
 | ||||||
|  | 	ext_buffer = flt_malloc(ext_size, ext_array, SBUF_SIZE); | ||||||
|  | 
 | ||||||
|  | 	if (flag_rw == FLT_WRITE) { | ||||||
|  | 		expand(first_sector, buffer, nr_sectors); | ||||||
|  | 
 | ||||||
|  | 		if (USE_CHECKSUM && make_sum(first_sector, nr_sectors)) | ||||||
|  | 			return RET_REDO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Perform the actual I/O. */ | ||||||
|  | 	res_size = ext_size; | ||||||
|  | 	r = read_write(phys_pos, ext_buffer, ext_buffer, &res_size, flag_rw); | ||||||
|  | 
 | ||||||
|  | #if DEBUG2 | ||||||
|  | 	printf("Filter: transfer: read_write(%x:%x, %u, %d) = %d, %u\n", | ||||||
|  | 		ex64hi(phys_pos), ex64lo(phys_pos), ext_size, flag_rw, r, | ||||||
|  | 		res_size); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	if (r != OK) { | ||||||
|  | 		flt_free(ext_buffer, ext_size, ext_array); | ||||||
|  | 
 | ||||||
|  | 		return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Limit the resulting size to the user data part of the buffer.
 | ||||||
|  | 	 * The resulting size may already be less, due to an EOF. | ||||||
|  | 	 */ | ||||||
|  | 	*sizep = MIN(req_size, res_size); | ||||||
|  | 
 | ||||||
|  | 	if (flag_rw == FLT_WRITE) { | ||||||
|  | 		if (USE_CHECKSUM && check_write(phys_pos, res_size)) | ||||||
|  | 			return RET_REDO; | ||||||
|  | 
 | ||||||
|  | 		collapse_size(first_sector, sizep); | ||||||
|  | 	} | ||||||
|  | 	else { /* FLT_READ */ | ||||||
|  | 		if (USE_CHECKSUM && check_sum(first_sector, *sizep)) | ||||||
|  | 			return RET_REDO; | ||||||
|  | 
 | ||||||
|  | 		collapse(first_sector, buffer, sizep); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flt_free(ext_buffer, ext_size, ext_array); | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				convert					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | u64_t convert(u64_t size) | ||||||
|  | { | ||||||
|  | 	/* Given a raw disk size, subtract the amount of disk space used for
 | ||||||
|  | 	 * checksums, resulting in the user-visible disk size. | ||||||
|  | 	 */ | ||||||
|  | 	sector_t sectors; | ||||||
|  | 
 | ||||||
|  | 	if (!USE_SUM_LAYOUT) | ||||||
|  | 		return size; | ||||||
|  | 
 | ||||||
|  | 	sectors = POS2SEC(size); | ||||||
|  | 
 | ||||||
|  | 	return SEC2POS(sectors / (NR_SUM_SEC + 1) * NR_SUM_SEC); | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								drivers/filter/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								drivers/filter/util.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | |||||||
|  | /* Filter driver - utility functions */ | ||||||
|  | 
 | ||||||
|  | #include "inc.h" | ||||||
|  | #include <sys/mman.h> | ||||||
|  | #include <signal.h> | ||||||
|  | 
 | ||||||
|  | static clock_t next_alarm; | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_malloc				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | char *flt_malloc(size_t size, char *sbuf, size_t ssize) | ||||||
|  | { | ||||||
|  | 	/* Allocate a buffer for 'size' bytes. If 'size' is equal to or less
 | ||||||
|  | 	 * than 'ssize', return the static buffer 'sbuf', otherwise, use | ||||||
|  | 	 * malloc() to allocate memory dynamically. | ||||||
|  | 	 */ | ||||||
|  | 	char *p; | ||||||
|  | 
 | ||||||
|  | 	if (size <= ssize) | ||||||
|  | 		return sbuf; | ||||||
|  | 
 | ||||||
|  | 	p = alloc_contig(size, 0, NULL); | ||||||
|  | 	if (p == NULL) | ||||||
|  | 		panic(__FILE__, "out of memory", size); | ||||||
|  | 
 | ||||||
|  | 	return p; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_free				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void flt_free(char *buf, size_t size, char *sbuf) | ||||||
|  | {	 | ||||||
|  | 	/* Free a buffer previously allocated with flt_malloc().
 | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	if(buf != sbuf) | ||||||
|  | 		munmap(buf, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				print64					     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | char *print64(u64_t p) | ||||||
|  | { | ||||||
|  | #define NB 10 | ||||||
|  | 	static int n = 0; | ||||||
|  | 	static char buf[NB][100]; | ||||||
|  | 	u32_t lo = ex64lo(p), hi = ex64hi(p); | ||||||
|  | 	n = (n+1) % NB; | ||||||
|  | 	if(!hi) sprintf(buf[n], "%lx", lo); | ||||||
|  | 	else sprintf(buf[n], "%lx%08lx", hi, lo); | ||||||
|  | 	return buf[n]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_alarm				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | clock_t flt_alarm(clock_t dt) | ||||||
|  | { | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	if(dt < 0) | ||||||
|  | 		return next_alarm; | ||||||
|  | 
 | ||||||
|  | 	r = sys_setalarm(dt, 0); | ||||||
|  | 
 | ||||||
|  | 	if(r != OK) | ||||||
|  | 		panic(__FILE__, "sys_setalarm failed", r); | ||||||
|  | 
 | ||||||
|  | 	if(dt == 0) { | ||||||
|  | 		if(!next_alarm) | ||||||
|  | 			panic(__FILE__, "clearing unset alarm", r); | ||||||
|  | 		next_alarm = 0; | ||||||
|  | 	} else { | ||||||
|  | 		if(next_alarm) | ||||||
|  | 			panic(__FILE__, "overwriting alarm", r); | ||||||
|  | 		if ((r = getuptime(&next_alarm)) != OK) | ||||||
|  | 			panic(__FILE__, "getuptime failed", r); | ||||||
|  | 		next_alarm += dt; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return next_alarm; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				got_alarm				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | static void got_alarm(int sig) | ||||||
|  | { | ||||||
|  | 	/* Do nothing. */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*===========================================================================*
 | ||||||
|  |  *				flt_sleep				     * | ||||||
|  |  *===========================================================================*/ | ||||||
|  | void flt_sleep(int secs) | ||||||
|  | { | ||||||
|  | 	/* Sleep for the given number of seconds. Don't use sleep(), as that
 | ||||||
|  | 	 * will end up calling select() to VFS. This implementation could be | ||||||
|  | 	 * improved. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	signal(SIGALRM, got_alarm); | ||||||
|  | 	alarm(secs); | ||||||
|  | 
 | ||||||
|  | 	pause(); | ||||||
|  | } | ||||||
| @ -464,3 +464,25 @@ driver osscore | |||||||
| 		; | 		; | ||||||
| 	uid     0; | 	uid     0; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | driver filter | ||||||
|  | { | ||||||
|  | 	system | ||||||
|  | 		SETALARM	# 24 | ||||||
|  | 		TIMES		# 25 | ||||||
|  | 		GETINFO		# 26 | ||||||
|  | 		SAFECOPYFROM	# 31 | ||||||
|  | 		SAFECOPYTO	# 32 | ||||||
|  | 		SETGRANT	# 34 | ||||||
|  | 		SYSCTL		# 44 | ||||||
|  | 	; | ||||||
|  | 	ipc | ||||||
|  | 		SYSTEM PM VFS RS DS VM | ||||||
|  | 		at_wini | ||||||
|  | 		bios_wini | ||||||
|  | 	; | ||||||
|  | 	control | ||||||
|  | 		at_wini | ||||||
|  | 		bios_wini | ||||||
|  | 	; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -38,6 +38,8 @@ enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE }; | |||||||
| 
 | 
 | ||||||
| #define RESCUE_MAJOR		   9    /* major device for rescue */ | #define RESCUE_MAJOR		   9    /* major device for rescue */ | ||||||
| 
 | 
 | ||||||
|  | #define FILTER_MAJOR		  11	/* major device for filter driver */ | ||||||
|  | 
 | ||||||
| #define LOG_MAJOR		  15	/* major device for log driver */ | #define LOG_MAJOR		  15	/* major device for log driver */ | ||||||
| #  define IS_KLOG_DEV		   0	/* minor device for /dev/klog */ | #  define IS_KLOG_DEV		   0	/* minor device for /dev/klog */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ PRIVATE struct dmap init_dmap[] = { | |||||||
|   DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE, "")   /* 8 = /dev/c1    */ |   DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE, "")   /* 8 = /dev/c1    */ | ||||||
|   DT(0, 0,        0,       0,   	DMAP_MUTABLE, "")   /* 9 = not used   */ |   DT(0, 0,        0,       0,   	DMAP_MUTABLE, "")   /* 9 = not used   */ | ||||||
|   DT(0, no_dev,   0,       0,           DMAP_MUTABLE, "")   /*10 = /dev/c2    */ |   DT(0, no_dev,   0,       0,           DMAP_MUTABLE, "")   /*10 = /dev/c2    */ | ||||||
|   DT(0, 0,        0,       0,   	DMAP_MUTABLE, "")   /*11 = not used   */ |   DT(0, no_dev,   0,       0,   	DMAP_MUTABLE, "")   /*11 = /dev/filter*/ | ||||||
|   DT(0, no_dev,   0,       NONE,     	DMAP_MUTABLE, "")   /*12 = /dev/c3    */ |   DT(0, no_dev,   0,       NONE,     	DMAP_MUTABLE, "")   /*12 = /dev/c3    */ | ||||||
|   DT(0, no_dev,   0,       NONE,	DMAP_MUTABLE, "")   /*13 = /dev/audio */ |   DT(0, no_dev,   0,       NONE,	DMAP_MUTABLE, "")   /*13 = /dev/audio */ | ||||||
|   DT(0, 0,   	  0,       0,		DMAP_MUTABLE, "")   /*14 = not used   */ |   DT(0, 0,   	  0,       0,		DMAP_MUTABLE, "")   /*14 = not used   */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 David van Moolenbroek
						David van Moolenbroek