diskscrubber [was Major problems]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If you have a backup from which you can restore or if the data is so
trashed that you have to reinstall, then how about running the following
against the file system before you put the data back?  This will "scrub"
the file system with a sequence of patterns and check them.  Let it run 
until the output wraps around, you should see a sequence like

	0000111122223333

where the number of each digits varies based on how much data you are 
scrubbing.  You want to scrub the entire file system, and the usage is

	cd /mnt			# or where you have the file system mounted
	diskscrubber 4900	# about right for a 5GB partition

You need to scrub a bit less than the size because the blocks of pointers
eat up space as well.  If you leave 5-10% that seems to be enough, you 
can do one run, check disk space, and recorrect it.

I use this for a 48 hour burn in on any system where I care about the data.

--lm

/*
 * diskscrubber.c - write patterns in datafile[s] and verify them.
 * Handles 32 bit problems by never writing a single file bigger that 1G,
 * handles buffering problems by writing all files and then reading them.
 *
 * (c) May 2001 Larry McVoy, do whatever you want with this.
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define	u32	unsigned int
#define	BSIZ	(4<<20)
#define	FSIZ	(mb<<20)
#define	CHUNK	1024

void writen(int fd, u32 *buf, int size);
void readn(int fd, u32 *buf, int size);
void bad(unsigned int off, unsigned int bad, unsigned int want);
void doit(char *file, u32 mb, int pass);

u32	buf[BSIZ];	/* I do not want to realloc this on each call */

int
main(int ac, char **av)
{
	u32	mb, left;
	int	i, pass;
	char	file[200];
	char	c;

	if (sizeof(u32) != 4) {
		fprintf(stderr, "Expected 4 byte ints\n");
		exit(1);
	}
	if (ac != 2) {
		printf("Usage: %s amount_in_MB\n", av[0]);
		exit(0);
	}
	mb = atoi(av[1]);
	if (mb % (BSIZ>>20)) {
		printf("Usage: %s amount must be a multiple of %d\n",
		    av[0], BSIZ>>20);
		exit(0);
	}
	pass = 0;
	for ( ;; ) {
		for (i = 0, left = mb; left > 0; i++) {
			sprintf(file, "_data%d", i);
			if (left >= CHUNK) {
				left -= CHUNK;
				doit(file, CHUNK, pass);
			} else {
				doit(file, left, pass);
				left = 0;
			}
			c = '0' + pass;
			write(1, &c, 1);
		}
		pass = (pass + 1) % 4;
		/*
		 * Only the first tine through the loop do we need pass 0,
		 * in all other cases pass 4 has done what pass 0 would do.
		 */
		if (!pass) pass = 1;
	}
	return (0);	/* lint */
}

void
writen(int fd, u32 *buf, int size)
{
	if (write(fd, (char*)buf, size) != size) {
		perror("write");
		exit(1);
	}
}

void
readn(int fd, u32 *buf, int size)
{
	if (read(fd, (char*)buf, size) != size) {
		perror("read");
		exit(1);
	}
	lseek(fd, -size, SEEK_CUR);
}

void
bad(u32 off, u32 bad, u32 want)
{
	printf("\nBAD @ %8u %08x:%08x\n", off, bad, want);
	exit(1);
}

/*
 * Write different bits into the file forcing bit changes.
 * pass 0 - just write the offset into the file
 * pass 1 - read data and check for offset, then write 0x55555555
 * pass 2 - read data and check for 0x55555555, then write 0xaaaaaaaa
 * pass 3 - read data and check for 0xaaaaaaaa, then write offset
 */
void
doit(char *file, u32 mb, int pass)
{
	u32	off = 0;
	int	i;
	int	fd = open(file, O_CREAT|O_RDWR, 0666);

	
	switch (pass) {
	    case 0:
	    /* pass 0 - just write the offset into the file */
		for (off = 0; off < FSIZ; ) {
			for (i = 0; i < BSIZ/4; buf[i++] = off, off += 4);
			writen(fd, buf, BSIZ);
		}
		break;
	    case 1:
	    /* pass 1 - read and check for offset, then write 0x55555555 */
		for (off = 0; off < FSIZ; ) {
			readn(fd, buf, BSIZ);
			for (i = 0; i < BSIZ/4; off += 4) {
				if (buf[i] != off) bad(off, buf[i], off);
				buf[i++] = 0x55555555;
			}
			writen(fd, buf, BSIZ);
		}
		break;
	    case 2:
	    /* pass 2 - read and check for 0x55555555, then write 0xaaaaaaaa */
		for (off = 0; off < FSIZ; off += BSIZ) {
			readn(fd, buf, BSIZ);
			for (i = 0; i < BSIZ/4; ) {
				if (buf[i] != 0x55555555) {
					bad(off, buf[i], 0x55555555);
				}
				buf[i++] = 0xaaaaaaaa;
			}
			writen(fd, buf, BSIZ);
		}
		break;
	    case 3:
	    /* pass 4 - read and check for 0xaaaaaaaa, then write offset */
		for (off = 0; off < FSIZ; ) {
			readn(fd, buf, BSIZ);
			for (i = 0; i < BSIZ/4; off += 4) {
				if (buf[i] != 0xaaaaaaaa) {
					bad(off, buf[i], 0xaaaaaaaa);
				}
				buf[i++] = off;
			}
			writen(fd, buf, BSIZ);
		}
		break;
	}
	close(fd);
}





[Index of Archives]         [Linux RAID]     [Kernel Development]     [Red Hat Install]     [Video 4 Linux]     [Postgresql]     [Fedora]     [Gimp]     [Yosemite News]

  Powered by Linux