diff options
| author | dsl <dsl@NetBSD.org> | 2003-08-22 21:33:52 +0000 |
|---|---|---|
| committer | dsl <dsl@NetBSD.org> | 2003-08-22 21:33:52 +0000 |
| commit | db4706faf9d0203ca9b36cdfe80ae8248a2f85dc (patch) | |
| tree | 5593031a08f3fd85d16f47f7f5af1fde9077a78e /sys | |
| parent | f3404c9f638b5367538fdc4583b33fc300f69fcb (diff) | |
Reduce memory footprint:
- use file buffer for all block reads
- only save a small amount of the indirect block list
Allows i386 bootxx_ufs code to load /boot from a filesystem with 32k blocks
while still fitting inside 64k of memory.
Code size reduced as well (by ~1k on i386).
It ought to be possible to use a buffer that is smaller than a filesystem
block. This might be needed in order to boot from filesystems with larger
block sizes.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/lib/libsa/ufs.c | 237 |
1 files changed, 100 insertions, 137 deletions
diff --git a/sys/lib/libsa/ufs.c b/sys/lib/libsa/ufs.c index 0f25482b2ed..8a2b3091766 100644 --- a/sys/lib/libsa/ufs.c +++ b/sys/lib/libsa/ufs.c @@ -1,4 +1,4 @@ -/* $NetBSD: ufs.c,v 1.39 2003/08/21 00:01:28 elric Exp $ */ +/* $NetBSD: ufs.c,v 1.40 2003/08/22 21:33:52 dsl Exp $ */ /*- * Copyright (c) 1993 @@ -121,6 +121,13 @@ struct fs { #define twiddle() #endif +#undef cgstart +#if defined(LIBSA_FFSv2) +#define cgstart(fc, c) cgstart_ufs2((fs), (c)) +#else +#define cgstart(fc, c) cgstart_ufs1((fs), (c)) +#endif + #ifndef ufs_dinode #define ufs_dinode ufs1_dinode #endif @@ -128,32 +135,39 @@ struct fs { #define indp_t uint32_t #endif #ifndef FSBTODB -#define FSBTODB(fs, daddr) fsbtodb(fs, daddr) +#define FSBTODB(fs, indp) fsbtodb(fs, indp) #endif /* + * To avoid having a lot of filesystem-block sized buffers lurking (which + * could be 32k) we only keep a few entries of the indirect block map. + * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block + * ~13 times pulling in a 6M kernel. + * The cache size must be smaller than the smallest filesystem block, + * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). + */ +#define LN2_IND_CACHE_SZ 6 +#define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) +#define IND_CACHE_MASK (IND_CACHE_SZ - 1) + +/* * In-core open file. */ struct file { off_t f_seekp; /* seek pointer */ struct fs *f_fs; /* pointer to super-block */ struct ufs_dinode f_di; /* copy of on-disk inode */ - daddr_t f_nindir[NIADDR]; - /* number of blocks mapped by - indirect block at level i */ - int f_l2indir[NIADDR]; /* log2(f_nindir) */ - char *f_blk[NIADDR]; /* buffer for indirect block at - level i */ - size_t f_blksize[NIADDR]; - /* size of buffer */ - daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ + uint f_nishift; /* for blocks in indirect block */ + indp_t f_ind_cache_block; + indp_t f_ind_cache[IND_CACHE_SZ]; + char *f_buf; /* buffer for data block */ size_t f_buf_size; /* size of data block */ daddr_t f_buf_blkno; /* block number of data block */ }; static int read_inode(ino_t, struct open_file *); -static int block_map(struct open_file *, daddr_t, daddr_t *); +static int block_map(struct open_file *, indp_t, indp_t *); static int buf_read_file(struct open_file *, char **, size_t *); static int search_directory(const char *, int, struct open_file *, ino_t *); #ifdef LIBSA_FFSv1 @@ -228,30 +242,23 @@ read_inode(ino_t inumber, struct open_file *f) /* * Read inode and save it. */ - buf = alloc(fs->fs_bsize); + buf = fp->f_buf; twiddle(); rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, - inode_sector, fs->fs_bsize, - buf, &rsize); + inode_sector, fs->fs_bsize, buf, &rsize); if (rc) - goto out; - if (rsize != fs->fs_bsize) { - rc = EIO; - goto out; - } + return rc; + if (rsize != fs->fs_bsize) + return EIO; #ifdef LIBSA_LFS - rc = EINVAL; cnt = INOPBx(fs); - for (dip = (struct ufs_dinode *)buf + (cnt - 1); cnt--; --dip) { - if (dip->di_inumber == inumber) { - rc = 0; - break; - } + dip = (struct ufs_dinode *)buf + (cnt - 1); + for (; dip->di_inumber != inumber; --dip) { + /* kernel code panics, but boot blocks which panic are Bad. */ + if (--cnt == 0) + return EINVAL; } - /* kernel code panics, but boot blocks which panic are Bad. */ - if (rc) - goto out; fp->f_di = *dip; #else fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)]; @@ -260,15 +267,8 @@ read_inode(ino_t inumber, struct open_file *f) /* * Clear out the old buffers */ - { - int level; - - for (level = 0; level < NIADDR; level++) - fp->f_blkno[level] = -1; - fp->f_buf_blkno = -1; - } -out: - free(buf, fs->fs_bsize); + fp->f_ind_cache_block = ~0; + fp->f_buf_blkno = -1; return (rc); } @@ -277,15 +277,16 @@ out: * contains that block. */ static int -block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) +block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p) { struct file *fp = (struct file *)f->f_fsdata; struct fs *fs = fp->f_fs; int level; - int idx; - daddr_t ind_block_num; - indp_t *ind_p; + indp_t ind_cache; + indp_t ind_block_num; + size_t rsize; int rc; + indp_t *buf = (void *)fp->f_buf; /* * Index structure of an inode: @@ -318,63 +319,64 @@ block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) file_block -= NDADDR; - /* - * nindir[0] = NINDIR - * nindir[1] = NINDIR**2 - * nindir[2] = NINDIR**3 - * etc - */ - for (level = 0; ; level++) { - if (level == NIADDR) + ind_cache = file_block >> LN2_IND_CACHE_SZ; + if (ind_cache == fp->f_ind_cache_block) { + *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK]; + return 0; + } + + for (level = 0;;) { + level += fp->f_nishift; + if (file_block < (indp_t)1 << level) + break; + if (level > NIADDR * fp->f_nishift) /* Block number too high */ return (EFBIG); - if (file_block < fp->f_nindir[level]) - break; - file_block -= fp->f_nindir[level]; + file_block -= (indp_t)1 << level; } - ind_block_num = fp->f_di.di_ib[level]; + ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1]; - for (; level >= 0; level--) { + for (;;) { + level -= fp->f_nishift; if (ind_block_num == 0) { *disk_block_p = 0; /* missing */ return (0); } - if (fp->f_blkno[level] != ind_block_num) { - if (fp->f_blk[level] == NULL) - fp->f_blk[level] = alloc(fs->fs_bsize); - twiddle(); - rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, - FSBTODB(fp->f_fs, ind_block_num), - fs->fs_bsize, - fp->f_blk[level], - &fp->f_blksize[level]); - if (rc) - return (rc); - if (fp->f_blksize[level] != fs->fs_bsize) - return (EIO); - fp->f_blkno[level] = ind_block_num; - } - - if (level > 0) { - idx = file_block >> fp->f_l2indir[level - 1]; - file_block &= fp->f_nindir[level - 1] - 1; - } else - idx = file_block; - - ind_p = (void *)fp->f_blk[level]; - ind_block_num = ind_p[idx]; + twiddle(); + /* + * If we were feeling brave, we could work out the number + * of the disk sector and read a single disk sector instead + * of a filesystem block. + * However we don't do this very often anyway... + */ + rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, + FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize, + buf, &rsize); + if (rc) + return (rc); + if (rsize != fs->fs_bsize) + return EIO; + ind_block_num = buf[file_block >> level]; + if (level == 0) + break; + file_block &= (1 << level) - 1; } + /* Save the part of the block that contains this sector */ + memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], + IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); + fp->f_ind_cache_block = ind_cache; + *disk_block_p = ind_block_num; return (0); } /* - * Read a portion of a file into an internal buffer. Return - * the location in the buffer and the amount in the buffer. + * Read a portion of a file into an internal buffer. + * Return the location in the buffer and the amount in the buffer. */ static int buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) @@ -382,8 +384,8 @@ buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) struct file *fp = (struct file *)f->f_fsdata; struct fs *fs = fp->f_fs; long off; - daddr_t file_block; - daddr_t disk_block; + indp_t file_block; + indp_t disk_block; size_t block_size; int rc; @@ -400,9 +402,6 @@ buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) if (rc) return (rc); - if (fp->f_buf == NULL) - fp->f_buf = alloc(fs->fs_bsize); - if (disk_block == 0) { bzero(fp->f_buf, block_size); fp->f_buf_size = block_size; @@ -460,6 +459,8 @@ search_directory(const char *name, int length, struct open_file *f, dp = (struct direct *)buf; edp = (struct direct *)(buf + buf_size); for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { + if (dp->d_reclen <= 0) + break; if (dp->d_ino == (ino_t)0) continue; #if BYTE_ORDER == LITTLE_ENDIAN @@ -492,8 +493,7 @@ ffs_find_superblock(struct open_file *f, struct fs *fs) for (i = 0; sblock_try[i] != -1; i++) { rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, - sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, (char *)fs, - &buf_size); + sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); if (rc != 0 || buf_size != SBLOCKSIZE) return rc; if (fs->fs_magic == FS_UFS2_MAGIC) { @@ -523,7 +523,7 @@ ufs_open(const char *path, struct open_file *f) ino_t parent_inumber; int nlinks = 0; char namebuf[MAXPATHLEN+1]; - char *buf = NULL; + char *buf; #endif /* allocate file system specific data structure */ @@ -544,8 +544,7 @@ ufs_open(const char *path, struct open_file *f) { size_t buf_size; rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, - SBLOCKOFFSET / DEV_BSIZE, - SBLOCKSIZE, (char *)fs, &buf_size); + SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); if (rc) goto out; if (buf_size != SBLOCKSIZE || @@ -580,8 +579,7 @@ ufs_open(const char *path, struct open_file *f) * Calculate indirect block levels. */ { - daddr_t mult; - int level; + indp_t mult; int ln2; /* @@ -601,13 +599,11 @@ ufs_open(const char *path, struct open_file *f) for (ln2 = 0; mult != 1; ln2++) mult >>= 1; - for (level = 0; level < NIADDR; level++) { - mult *= NINDIR(fs); - fp->f_nindir[level] = mult; - fp->f_l2indir[level] = ln2 * (level + 1); - } + fp->f_nishift = ln2; } + /* alloc a block sized buffer used for all fs transfers */ + fp->f_buf = alloc(fs->fs_bsize); inumber = ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; @@ -682,11 +678,10 @@ ufs_open(const char *path, struct open_file *f) * Read file for symbolic link */ size_t buf_size; - daddr_t disk_block; + indp_t disk_block; - if (!buf) - buf = alloc(fs->fs_bsize); - rc = block_map(f, (daddr_t)0, &disk_block); + buf = fp->f_buf; + rc = block_map(f, (indp_t)0, &disk_block); if (rc) goto out; @@ -736,40 +731,26 @@ ufs_open(const char *path, struct open_file *f) fp->f_seekp = 0; /* reset seek pointer */ out: -#ifndef LIBSA_NO_FS_SYMLINK - if (buf) - free(buf, fs->fs_bsize); -#endif -#ifndef LIBSA_NO_FS_CLOSE - if (rc) { + if (rc) ufs_close(f); - } -#endif return (rc); } -#ifndef LIBSA_NO_FS_CLOSE int ufs_close(struct open_file *f) { struct file *fp = (struct file *)f->f_fsdata; - int level; f->f_fsdata = NULL; if (fp == NULL) return (0); - for (level = 0; level < NIADDR; level++) { - if (fp->f_blk[level]) - free(fp->f_blk[level], fp->f_fs->fs_bsize); - } if (fp->f_buf) free(fp->f_buf, fp->f_fs->fs_bsize); free(fp->f_fs, SBLOCKSIZE); free(fp, sizeof(struct file)); return (0); } -#endif /* !LIBSA_NO_FS_CLOSE */ /* * Copy a portion of a file into kernel memory. @@ -849,6 +830,7 @@ ufs_stat(struct open_file *f, struct stat *sb) struct file *fp = (struct file *)f->f_fsdata; /* only important stuff */ + memset(sb, 0, sizeof *sb); sb->st_mode = fp->f_di.di_mode; sb->st_uid = fp->f_di.di_uid; sb->st_gid = fp->f_di.di_gid; @@ -861,34 +843,15 @@ ufs_stat(struct open_file *f, struct stat *sb) * Sanity checks for old file systems. * * XXX - goes away some day. + * Stripped of stuff libsa doesn't need..... */ static void ffs_oldfscompat(struct fs *fs) { -#ifdef COMPAT_UFS - int i; -#endif - if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_size != fs->fs_old_size) { - fs->fs_maxbsize = fs->fs_bsize; - fs->fs_time = fs->fs_old_time; - fs->fs_size = fs->fs_old_size; - fs->fs_dsize = fs->fs_old_dsize; - fs->fs_csaddr = fs->fs_old_csaddr; - fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir; - fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree; - fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree; - fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree; - } #ifdef COMPAT_UFS if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_old_inodefmt < FS_44INODEFMT) { - quad_t sizepb = fs->fs_bsize; - fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; - for (i = 0; i < NIADDR; i++) { - sizepb *= NINDIR(fs); - fs->fs_maxfilesize += sizepb; - } fs->fs_qbmask = ~fs->fs_bmask; fs->fs_qfmask = ~fs->fs_fmask; } |
