summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authordsl <dsl@NetBSD.org>2003-08-22 21:33:52 +0000
committerdsl <dsl@NetBSD.org>2003-08-22 21:33:52 +0000
commitdb4706faf9d0203ca9b36cdfe80ae8248a2f85dc (patch)
tree5593031a08f3fd85d16f47f7f5af1fde9077a78e /sys
parentf3404c9f638b5367538fdc4583b33fc300f69fcb (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.c237
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;
}