🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.unix.wizards
5 messages
5 total messages Started by Matthew R. Singer Wed, 30 Dec 1992 16:31
file system layout
#6321
Author: Matthew R. Singer
Date: Wed, 30 Dec 1992 16:31
31 lines
1761 bytes
--
I'm looking at building a data recording system that consists of 10 channels
each spooling data to 3 SCSI disks via 3 seperate SCSI chips...  I would
like to be able to read this disks directly on a Sun. Each disk will only 
have one file on it which is all the free space on the  disk after the 
file system is laid out.

Now, the options appear to be:

1) Format the disks in MS-DOS format with VxWorks and use SOS under VxWorks to
   make the disks NFS mountable on a Sun.

2) Again format the disk in MS-DOS format, but use a third party driver that
   can directly mount MS-DOS format disks.

3) Format and mkfs under SunOS.  

 
If I were to pre-write a file a Sun disk, is there a simple way to find out
what blocks on the disk the file system has allocated for it.  Since I 
am writing just one big file on a newly formatted disk, it should be 
contiguous (right?).



-----------------------------------------------------------------------------
Matthew R. Singer                                    MIT Lincoln Laboratory
(617) 981-3771                                       244 Wood Street
singer@ll.mit.edu                                    Lexington, MA 02173
-----------------------------------------------------------------------------
Re: file system layout
#6324
Author: John Hascall
Date: Thu, 31 Dec 1992 16:57
19 lines
1248 bytes
singer@ll.mit.edu (Matthew R. Singer) writes:
}3) Format and mkfs under SunOS.  

}If I were to pre-write a file a Sun disk, is there a simple way to find out
}what blocks on the disk the file system has allocated for it.  Since I 
}am writing just one big file on a newly formatted disk, it should be 
}contiguous (right?).

Not necessarily (probably not).  First, disks are divided into
"cylinder groups".  Second, there is a parameter fs_maxcontig
which limits the number of contiguous blocks.  A more detailed
discussion can be found in `A Fast File System for Unix'.

John
-- 
John Hascall                   ``An ill-chosen word is the fool's messenger.''
Systmes Software Engineer
Project Vincent
Iowa State University Computation Center  +  Ames, IA  50011  +  515/294-9551
Re: file system layout
#6325
Author: Larry McVoy
Date: Thu, 31 Dec 1992 22:47
265 lines
6522 bytes
singer@ll.mit.edu (Matthew R. Singer) writes:
: If I were to pre-write a file a Sun disk, is there a simple way to find out
: what blocks on the disk the file system has allocated for it.  

Yup.  Source included below.  This is essentialy the read path of UFS. 
Pretty simple, eh?  I saw a perl script that did this once - now that's 
cool.

: Since I 
: am writing just one big file on a newly formatted disk, it should be 
: contiguous (right?).

Nope.  Even though I wacked it to do contig allocation when it can, it
still switches cylinder groups every meg or so.  I suppose you could
dick around with the tuning parameters to make one mondo cyl group.


If you want more info on the SunOS UFS, send mail like so

	Mail archives@slovax.eng.sun.com
	Subject: fs_cluster
	^D

That will send you the clustering paper.  (Yeah, I gotta get netlib.)

--lm

Here's the code.  


#include <stdio.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/vnode.h>
#ifdef	svr4
#include <sys/fs/ufs_fs.h>
#include <sys/fs/ufs_inode.h>
#define	DEV
#else
#include <ufs/fs.h>
#include <ufs/inode.h>
#include <sys/dir.h>
#endif
#include <sys/stat.h>

#define SECTORSIZE	512
#define SUPERADDR	(16*SECTORSIZE)

union {
	char	sb_buffer[SBSIZE];
	struct	fs fs;
} sb;
union {
	char	i_buffer[MAXBSIZE];
	struct dinode dinode[MAXBSIZE/sizeof(struct dinode)];
} di;
char	*cmdname;
void	*malloc();
int	block;	/* global because I'm too lazy to pass a pointer */

main(argc, argv)
	int	argc;
	char	*argv[];
{
	struct	stat	statb;
	struct	fs	*fsp;
	struct	dinode	*ip;
	char	*file;
	int	*blk;
	int	size;
	int	devfd;
	int	inode;
	int	offset;
	int	seekaddr;
	int	i, j;
	int	extent;

	cmdname = argv[0];
	if (argc != 2 && argc != 3) {
		fprintf(stderr, "Usage: %s file [diskdev]\n", cmdname);
		exit(1);
	}
	file = argv[1];
	if (stat(file, &statb) == -1) {
		fprintf(stderr, "File %s not found\n", file);
		exit(1);
	}
	sync();
	inode = statb.st_ino;
	if (argc == 3) {
		devfd = open(argv[2], 0);
#ifndef	DEV
	} else {
		devfd = getdev(statb.st_dev);
#endif
	}
	if (lseek(devfd, SUPERADDR, 0) == -1) {
		fprintf(stderr, "Seek to superblock failed\n");
		exit(1);
	}
	fsp = &sb.fs;
	if (read(devfd, sb.sb_buffer, SBSIZE) == -1) {
		fprintf(stderr, "Read of superblock failed\n");
		exit(1);
	}
	if (fsp->fs_magic != FS_MAGIC) {
		fprintf(stderr, "Not a superblock\n");
		exit(1);
	}
	block = itod(fsp, inode);
	offset = itoo(fsp, inode);
	seekaddr = fsbtodb(fsp, block) * SECTORSIZE;
	if (lseek(devfd, seekaddr, 0) == -1) {
		fprintf(stderr, "Seek to block %d offset %d failed\n", 
			block, offset);
		exit(1);
	}
	if (read(devfd, di.i_buffer, fsp->fs_bsize) == -1) {
		fprintf(stderr, "Read of inode %d failed\n", inode);
		exit(1);
	}
	ip = &di.dinode[offset];
	/* fprintf(stderr, "ncg %d rotor %d\n", fsp->fs_ncg, fsp->fs_cgrotor);*/
	/* printf("%d\n", fsp->fs_fpg); */
	size = ip->di_size;
	for (i = 0; i < NDADDR && size > 0; ) {
		extent = findextent(fsp, &ip->di_db[i], NDADDR - i);
		printf("off=%dK block=%d extent=%dK\n", 
		    i * fsp->fs_bsize / 1024, ip->di_db[i],
		    extent * fsp->fs_bsize / 1024);
		i += extent ? extent : 1;
		if (i * fsp->fs_bsize >= size)
		    exit(0);
	}
	block = NDADDR;
	blk = (int *) malloc(fsp->fs_bsize);
	/*
	 * block of pointers
	 */
	doblk(devfd, fsbtodb(fsp, ip->di_ib[0]) * SECTORSIZE, fsp, size);
	/*
	 * Block of pointers to pointers
	 */
	if (lseek(devfd, fsbtodb(fsp, ip->di_ib[1]) * SECTORSIZE, 0) == -1) {
		fprintf(stderr, "Seek to indirect block %d failed\n",
			fsbtodb(fsp, ip->di_ib[1]));
		exit(1);
	}
	if (read(devfd, (char *) blk, fsp->fs_bsize) != fsp->fs_bsize) {
		fprintf(stderr, "Read of indirect block %d failed\n",
			fsbtodb(fsp, ip->di_ib[1]));
		exit(1);
	}
	for (j = 0; j < NINDIR(fsp); j++) {
		doblk(devfd, fsbtodb(fsp, blk[j]) * SECTORSIZE, fsp, size);
	}
	/*
	 * Too lazy to do this
	 */
	printf("Quitting early\n");
	exit(0);
	/*NOTREACHED*/
}

doblk(fd, loc, fsp, size)
	struct	fs	*fsp;
{
	int	*blk;
	int	j;
	int	extent;

	if (lseek(fd, loc, 0) != loc) {
		perror("lseek");
		exit(0);
	}
	blk = (int*)malloc(fsp->fs_bsize);
	if (read(fd, (char*)blk, fsp->fs_bsize) != fsp->fs_bsize) {
		perror("read");
		exit(0);
	}
	for (j = 0; j < NINDIR(fsp); ) {
		if (extent = findextent(fsp, &blk[j], NINDIR(fsp) - j)) {
			printf("off=%dK block=%d extent=%dK\n",
			    block * fsp->fs_bsize / 1024, 
			    blk[j], extent * fsp->fs_bsize / 1024);
			block += extent;
			j += extent;
		} else {
			printf("off=%dK HOLE\n", block * fsp->fs_bsize / 1024);
			block += 1;
			j += 1;
		}
		if (block * fsp->fs_bsize >= size)
		    exit(0);
	}
}

#ifndef	DEV
getdev(dev)
	dev_t dev;
{
	DIR *dirp;
	struct direct *dp;
	struct stat statb;
	char buf[100];
	int fd;

	dirp = opendir("/dev");
	if (dirp == NULL) {
		fprintf(stderr, "cannot open /dev\n");
		exit(1);
	}
	while (dp = readdir(dirp)) {
		if (dp->d_fileno == 0) {
			continue;
		}
		sprintf(buf, "/dev/%s", dp->d_name);
		if (stat(buf, &statb) == -1) {
			continue;
		}
		if (statb.st_rdev == dev && (statb.st_mode & IFMT) == IFBLK) {
			sprintf(buf, "/dev/r%s", dp->d_name);
			fd = open(buf, 0);
			if (fd < 0) {
				fprintf(stderr, "cannot open %s\n", buf);
				exit(1);
			}
			closedir(dirp);
			return (fd);
		}
	}
	fprintf(stderr, "Device %x not found (NFS file?).\n", dev & 0xffff);
	exit(1);
	/*NOTREACHED*/
}
#endif

static int
findextent(fs, sbp, n)
	struct fs *fs;
	daddr_t *sbp;
	register int n;
{
	register daddr_t bn, nextbn;
	register daddr_t *bp;
	register int diff;

	if (n <= 0)
		return (0);
	bn = *sbp;
	if (bn == 0)
		return (0);
	diff = fs->fs_frag;
	bp = sbp;
	while (--n > 0) {
		nextbn = *(bp + 1);
		if (nextbn == 0 || bn + diff != nextbn)
			break;
		bn = nextbn;
		bp++;
	}
	return ((int)(bp - sbp) + 1);
}
---
Larry McVoy			(415) 336-7627			 lm@sun.com
Re: file system layout
#6329
Author: Chris Torek
Date: Fri, 01 Jan 1993 00:08
55 lines
2834 bytes
In article <1992Dec30.163131.17280@ll.mit.edu> singer@ll.mit.edu
(Matthew R. Singer) writes:
>>Since I am writing just one big file on a newly formatted disk, it
>>should be contiguous (right?) [under SunOS].

In article <lk6u47INN47f@appserv.Eng.Sun.COM> lm@slovax.Eng.Sun.COM
(Larry McVoy) writes:
>Nope.  Even though I wacked it to do contig allocation when it can, it
>still switches cylinder groups every meg or so.  I suppose you could
>dick around with the tuning parameters to make one mondo cyl group.

The `change groups' strategy exists to prevent the local clustering
tactics from turning the file system into a series of unmanageable
clumps.  By forcing a seek every 1 MB or so, the file system tries to
guarantee a high probability of a `well positioned' block being
available whenever needed.  Without this, large files would fill their
primary cylinder group, and new files created in that group would get
scattered hither and yon.

Of course, if you are just going to write one single file on a disk,
the file system policies work against you.  Then again, if you are
going to use the entire disk as a single file, you hardly need a file
system at all....

Incidentally, Margo Seltzer found the following bug in the original BSD
block allocator:

[ffs_alloc.c: your line numbers will differ; in fact your code might
even differ a bit, and/or be found in ufs_alloc.c.  Presumably this is
fixed in SunOS.]
***************
*** 458,464 ****
	 */
	nextblk = bap[indx - 1] + fs->fs_frag;
! 	if (indx > fs->fs_maxcontig &&
! 	    bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig)
! 	    != nextblk)
		return (nextblk);
	if (fs->fs_rotdelay != 0)
--- 464,469 ----
	 */
	nextblk = bap[indx - 1] + fs->fs_frag;
! 	if (indx < fs->fs_maxcontig || bap[indx - fs->fs_maxcontig] +
! 	    blkstofrags(fs, fs->fs_maxcontig) != nextblk)
		return (nextblk);
	if (fs->fs_rotdelay != 0)

Kirk got the test backwards originally, so the tunefs -a parameter
never mattered....  I no longer have VAXen, but I am curious as to
whether this fix might improve performance on the old RA81 disks.  I
was never able to tune those at all; the performance was always
miserable, never more than a few hundred K per second.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov
Disk tuning (was Re: file system layout)
#6331
Author: Bruce Evans
Date: Fri, 01 Jan 1993 10:25
76 lines
4402 bytes
In article <28188@dog.ee.lbl.gov> torek@horse.ee.lbl.gov (Chris Torek) writes:
>Incidentally, Margo Seltzer found the following bug in the original BSD
>block allocator:
>
>[ffs_alloc.c: your line numbers will differ; in fact your code might
>even differ a bit, and/or be found in ufs_alloc.c.  Presumably this is
>fixed in SunOS.]
>***************
>*** 458,464 ****
>	 */
>	nextblk = bap[indx - 1] + fs->fs_frag;
>! 	if (indx > fs->fs_maxcontig &&
>! 	    bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig)
>! 	    != nextblk)
>		return (nextblk);
>	if (fs->fs_rotdelay != 0)
>--- 464,469 ----
>	 */
>	nextblk = bap[indx - 1] + fs->fs_frag;
>! 	if (indx < fs->fs_maxcontig || bap[indx - fs->fs_maxcontig] +
>! 	    blkstofrags(fs, fs->fs_maxcontig) != nextblk)
>		return (nextblk);
>	if (fs->fs_rotdelay != 0)
>

>Kirk got the test backwards originally, so the tunefs -a parameter
>never mattered....  I no longer have VAXen, but I am curious as to
>whether this fix might improve performance on the old RA81 disks.  I
>was never able to tune those at all; the performance was always
>miserable, never more than a few hundred K per second.

386BSD-0.1 still has the old version (assuming that the above patch is
not backwards :-).

I tried tuning a Seagate 330MB ESDI disk under 386BSD yesterday.  The
tunefs -a parameter worked like I expected: increasing it increased read
performance and reduced write performance.  This is because my disk
controller (a WD1007V-SE1) takes too long in between separate write
commands and the 386BSD driver does not coalesce contiguous blocks
into a single write command (nor does ufs give it enough opportunities
to do so).  Separate read commands are not so much of a problem because
the slow controller is disguised by caching in the controller.

I get best results with tunefs -a 1 -d 1 and a block size of 4K.  The
default rotational delay is 4 msec, which corresponds to 14 sector times
or 2 blocks or at best 33% efficiency :-(.  A rotational delay of 0
works poorly for writing.  Rotational delays of 1 msec and 2 msec both
correspond to 1 block and work OK (for at best 50% efficiency).  A larger
block size wouldn't help because _some_delay between blocks is required,
and the minimum delay of 1 block time always reduces the maximum
efficiency to 50%.  (Actually, for large files I get very close to 25%
efficiency on 15Mb/sec drive and not so close to 50% efficiency on a
10Mb/sec drive, because the faster drive has to be formatted at 2:1
interleave for the controller's caching to keep up.  At 2:1 interleave
the timing is not very critical so it is easier to get close to the
maximum possible efficiency.)

Minix and linux (both using the minix-1.5 file system) get much better
performance from this controller.  E.g., under my version of Minix
(which is more or less standard except for the disk driver), reading and
writing a 2MB file on recently built 64MB Minix file system with only
4MB free was about 50% faster than reading and writing a 2MB file on an
empty 166MB 386BSD file system.  The minix-1.5 fs uses a block size of
only 1K and attempts to lay out the blocks contiguously.  It uses my
modifications of reading ahead up to 17K and always writing all dirty
blocks whenever any dirty block has to be written, so that the driver
usually has a large number of contiguous blocks to work with.  The
driver collects disk-contiguous blocks and makes the largest possible
i/o requests to the controller.  Directory blocks are _not_ written
immediately. This goes well with writing all dirty blocks whenever one
dirty block has to be written and makes operations like `ar xo libc.a'
and `rm -rf junk' 10 to 20 times faster than with the 386BSD ufs.  It
increases the chance of a crash messing up the file system, but I prefer
the reduced chance of a crash because of less i/o.
-- 
Bruce Evans  (bde@runx.oz.au)
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads