summaryrefslogtreecommitdiffstats
path: root/lib/libstand/ufs.c
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2002-06-21 06:18:05 +0000
committermckusick <mckusick@FreeBSD.org>2002-06-21 06:18:05 +0000
commit88d85c15ef183c06524d6ca695f62c0c0672b00c (patch)
treef1364dbfb9835934a3879b5904f7ff9a1495744c /lib/libstand/ufs.c
parenteacb69b0197a8553d5004aa99532cabad8778e36 (diff)
downloadFreeBSD-src-88d85c15ef183c06524d6ca695f62c0c0672b00c.zip
FreeBSD-src-88d85c15ef183c06524d6ca695f62c0c0672b00c.tar.gz
This commit adds basic support for the UFS2 filesystem. The UFS2
filesystem expands the inode to 256 bytes to make space for 64-bit block pointers. It also adds a file-creation time field, an ability to use jumbo blocks per inode to allow extent like pointer density, and space for extended attributes (up to twice the filesystem block size worth of attributes, e.g., on a 16K filesystem, there is space for 32K of attributes). UFS2 fully supports and runs existing UFS1 filesystems. New filesystems built using newfs can be built in either UFS1 or UFS2 format using the -O option. In this commit UFS1 is the default format, so if you want to build UFS2 format filesystems, you must specify -O 2. This default will be changed to UFS2 when UFS2 proves itself to be stable. In this commit the boot code for reading UFS2 filesystems is not compiled (see /sys/boot/common/ufsread.c) as there is insufficient space in the boot block. Once the size of the boot block is increased, this code can be defined. Things to note: the definition of SBSIZE has changed to SBLOCKSIZE. The header file <ufs/ufs/dinode.h> must be included before <ufs/ffs/fs.h> so as to get the definitions of ufs2_daddr_t and ufs_lbn_t. Still TODO: Verify that the first level bootstraps work for all the architectures. Convert the utility ffsinfo to understand UFS2 and test growfs. Add support for the extended attribute storage. Update soft updates to ensure integrity of extended attribute storage. Switch the current extended attribute interfaces to use the extended attribute storage. Add the extent like functionality (framework is there, but is currently never used). Sponsored by: DARPA & NAI Labs. Reviewed by: Poul-Henning Kamp <phk@freebsd.org>
Diffstat (limited to 'lib/libstand/ufs.c')
-rw-r--r--lib/libstand/ufs.c185
1 files changed, 90 insertions, 95 deletions
diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c
index 2bd9d17..8993d6c 100644
--- a/lib/libstand/ufs.c
+++ b/lib/libstand/ufs.c
@@ -1,7 +1,16 @@
/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */
/*-
- * Copyright (c) 1993
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -107,7 +116,10 @@ struct fs_ops ufs_fsops = {
struct file {
off_t f_seekp; /* seek pointer */
struct fs *f_fs; /* pointer to super-block */
- struct dinode f_di; /* copy of on-disk inode */
+ union dinode {
+ struct ufs1_dinode di1;
+ struct ufs2_dinode di2;
+ } f_di; /* copy of on-disk inode */
int f_nindir[NIADDR];
/* number of blocks mapped by
indirect block at level i */
@@ -115,20 +127,20 @@ struct file {
level i */
size_t f_blksize[NIADDR];
/* size of buffer */
- daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
+ ufs2_daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
+ ufs2_daddr_t f_buf_blkno; /* block number of data block */
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 */
};
+#define DIP(fp, field) \
+ ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
+ (fp)->f_di.di1.field : (fp)->f_di.di2.field)
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 *, ufs2_daddr_t, ufs2_daddr_t *);
static int buf_read_file(struct open_file *, char **, size_t *);
static int buf_write_file(struct open_file *, char *, size_t *);
static int search_directory(char *, struct open_file *, ino_t *);
-#ifdef COMPAT_UFS
-static void ffs_oldfscompat(struct fs *);
-#endif
/*
* Read a new inode into a file structure.
@@ -162,12 +174,12 @@ read_inode(inumber, f)
goto out;
}
- {
- struct dinode *dp;
-
- dp = (struct dinode *)buf;
- fp->f_di = dp[ino_to_fsbo(fs, inumber)];
- }
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ fp->f_di.di1 = ((struct ufs1_dinode *)buf)
+ [ino_to_fsbo(fs, inumber)];
+ else
+ fp->f_di.di2 = ((struct ufs2_dinode *)buf)
+ [ino_to_fsbo(fs, inumber)];
/*
* Clear out the old buffers
@@ -191,15 +203,14 @@ out:
static int
block_map(f, file_block, disk_block_p)
struct open_file *f;
- daddr_t file_block;
- daddr_t *disk_block_p; /* out */
+ ufs2_daddr_t file_block;
+ ufs2_daddr_t *disk_block_p; /* out */
{
struct file *fp = (struct file *)f->f_fsdata;
struct fs *fs = fp->f_fs;
int level;
int idx;
- daddr_t ind_block_num;
- u_int32_t *ind_p;
+ ufs2_daddr_t ind_block_num;
int rc;
/*
@@ -227,7 +238,7 @@ block_map(f, file_block, disk_block_p)
if (file_block < NDADDR) {
/* Direct block. */
- *disk_block_p = fp->f_di.di_db[file_block];
+ *disk_block_p = DIP(fp, di_db[file_block]);
return (0);
}
@@ -249,7 +260,7 @@ block_map(f, file_block, disk_block_p)
return (EFBIG);
}
- ind_block_num = fp->f_di.di_ib[level];
+ ind_block_num = DIP(fp, di_ib[level]);
for (; level >= 0; level--) {
if (ind_block_num == 0) {
@@ -274,15 +285,16 @@ block_map(f, file_block, disk_block_p)
fp->f_blkno[level] = ind_block_num;
}
- ind_p = (u_int32_t *)fp->f_blk[level];
-
if (level > 0) {
idx = file_block / fp->f_nindir[level - 1];
file_block %= fp->f_nindir[level - 1];
} else
idx = file_block;
- ind_block_num = ind_p[idx];
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
+ else
+ ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
}
*disk_block_p = ind_block_num;
@@ -302,8 +314,8 @@ buf_write_file(f, buf_p, 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;
+ ufs_lbn_t file_block;
+ ufs2_daddr_t disk_block;
size_t block_size;
int rc;
@@ -312,21 +324,22 @@ buf_write_file(f, buf_p, size_p)
*/
off = blkoff(fs, fp->f_seekp);
file_block = lblkno(fs, fp->f_seekp);
- block_size = dblksize(fs, &fp->f_di, file_block);
+ block_size = sblksize(fs, DIP(fp, di_size), file_block);
rc = block_map(f, file_block, &disk_block);
if (rc)
return (rc);
if (disk_block == 0)
- return (EFBIG); /* Because we can't allocate space on the drive */
+ /* Because we can't allocate space on the drive */
+ return (EFBIG);
/*
* Truncate buffer at end of file, and at the end of
* this block.
*/
- if (*size_p > fp->f_di.di_size - fp->f_seekp)
- *size_p = fp->f_di.di_size - fp->f_seekp;
+ if (*size_p > DIP(fp, di_size) - fp->f_seekp)
+ *size_p = DIP(fp, di_size) - fp->f_seekp;
if (*size_p > block_size - off)
*size_p = block_size - off;
@@ -353,7 +366,7 @@ buf_write_file(f, buf_p, size_p)
/*
* Copy the user data into the cached block.
*/
- bcopy(buf_p,fp->f_buf + off,*size_p);
+ bcopy(buf_p, fp->f_buf + off, *size_p);
/*
* Write the block out to storage.
@@ -379,14 +392,14 @@ buf_read_file(f, buf_p, 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;
+ ufs_lbn_t file_block;
+ ufs2_daddr_t disk_block;
size_t block_size;
int rc;
off = blkoff(fs, fp->f_seekp);
file_block = lblkno(fs, fp->f_seekp);
- block_size = dblksize(fs, &fp->f_di, file_block);
+ block_size = sblksize(fs, DIP(fp, di_size), file_block);
if (file_block != fp->f_buf_blkno) {
if (fp->f_buf == (char *)0)
@@ -422,8 +435,8 @@ buf_read_file(f, buf_p, size_p)
/*
* But truncate buffer at end of file.
*/
- if (*size_p > fp->f_di.di_size - fp->f_seekp)
- *size_p = fp->f_di.di_size - fp->f_seekp;
+ if (*size_p > DIP(fp, di_size) - fp->f_seekp)
+ *size_p = DIP(fp, di_size) - fp->f_seekp;
return (0);
}
@@ -449,7 +462,7 @@ search_directory(name, f, inumber_p)
length = strlen(name);
fp->f_seekp = 0;
- while (fp->f_seekp < fp->f_di.di_size) {
+ while (fp->f_seekp < DIP(fp, di_size)) {
rc = buf_read_file(f, &buf, &buf_size);
if (rc)
return (rc);
@@ -479,6 +492,8 @@ search_directory(name, f, inumber_p)
return (ENOENT);
}
+static int sblock_try[] = SBLOCKSEARCH;
+
/*
* Open a file.
*/
@@ -492,7 +507,7 @@ ufs_open(upath, f)
ino_t inumber, parent_inumber;
struct file *fp;
struct fs *fs;
- int rc;
+ int i, rc;
size_t buf_size;
int nlinks = 0;
char namebuf[MAXPATHLEN+1];
@@ -505,28 +520,35 @@ ufs_open(upath, f)
f->f_fsdata = (void *)fp;
/* allocate space and read super block */
- fs = malloc(SBSIZE);
+ fs = malloc(SBLOCKSIZE);
fp->f_fs = fs;
twiddle();
- rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- SBLOCK, SBSIZE, (char *)fs, &buf_size);
- if (rc)
- goto out;
-
- if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
- fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
+ /*
+ * Try reading the superblock in each of its possible locations.
+ */
+ for (i = 0; sblock_try[i] != -1; i++) {
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
+ (char *)fs, &buf_size);
+ if (rc)
+ goto out;
+ if ((fs->fs_magic == FS_UFS1_MAGIC ||
+ (fs->fs_magic == FS_UFS2_MAGIC &&
+ fs->fs_sblockloc == numfrags(fs, sblock_try[i]))) &&
+ buf_size == SBLOCKSIZE &&
+ fs->fs_bsize <= MAXBSIZE &&
+ fs->fs_bsize >= sizeof(struct fs))
+ break;
+ }
+ if (sblock_try[i] == -1) {
rc = EINVAL;
goto out;
}
-#ifdef COMPAT_UFS
- ffs_oldfscompat(fs);
-#endif
-
/*
* Calculate indirect block levels.
*/
{
- int mult;
+ ufs2_daddr_t mult;
int level;
mult = 1;
@@ -558,7 +580,7 @@ ufs_open(upath, f)
/*
* Check that current node is a directory.
*/
- if ((fp->f_di.di_mode & IFMT) != IFDIR) {
+ if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
rc = ENOTDIR;
goto out;
}
@@ -600,8 +622,8 @@ ufs_open(upath, f)
/*
* Check for symbolic link.
*/
- if ((fp->f_di.di_mode & IFMT) == IFLNK) {
- int link_len = fp->f_di.di_size;
+ if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
+ int link_len = DIP(fp, di_size);
int len;
len = strlen(cp);
@@ -615,19 +637,22 @@ ufs_open(upath, f)
bcopy(cp, &namebuf[link_len], len + 1);
if (link_len < fs->fs_maxsymlinklen) {
- bcopy(fp->f_di.di_shortlink, namebuf,
- (unsigned) link_len);
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ cp = (caddr_t)(fp->f_di.di1.di_db);
+ else
+ cp = (caddr_t)(fp->f_di.di2.di_db);
+ bcopy(cp, namebuf, (unsigned) link_len);
} else {
/*
* Read file for symbolic link
*/
size_t buf_size;
- daddr_t disk_block;
+ ufs2_daddr_t disk_block;
struct fs *fs = fp->f_fs;
if (!buf)
buf = malloc(fs->fs_bsize);
- rc = block_map(f, (daddr_t)0, &disk_block);
+ rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
if (rc)
goto out;
@@ -715,7 +740,7 @@ ufs_read(f, start, size, resid)
char *addr = start;
while (size != 0) {
- if (fp->f_seekp >= fp->f_di.di_size)
+ if (fp->f_seekp >= DIP(fp, di_size))
break;
rc = buf_read_file(f, &buf, &buf_size);
@@ -756,7 +781,7 @@ ufs_write(f, start, size, resid)
csize = size;
while ((size != 0) && (csize != 0)) {
- if (fp->f_seekp >= fp->f_di.di_size)
+ if (fp->f_seekp >= DIP(fp, di_size))
break;
if (csize >= 512) csize = 512; /* XXX */
@@ -790,7 +815,7 @@ ufs_seek(f, offset, where)
fp->f_seekp += offset;
break;
case SEEK_END:
- fp->f_seekp = fp->f_di.di_size - offset;
+ fp->f_seekp = DIP(fp, di_size) - offset;
break;
default:
return (-1);
@@ -806,10 +831,10 @@ ufs_stat(f, sb)
struct file *fp = (struct file *)f->f_fsdata;
/* only important stuff */
- sb->st_mode = fp->f_di.di_mode;
- sb->st_uid = fp->f_di.di_uid;
- sb->st_gid = fp->f_di.di_gid;
- sb->st_size = fp->f_di.di_size;
+ sb->st_mode = DIP(fp, di_mode);
+ sb->st_uid = DIP(fp, di_uid);
+ sb->st_gid = DIP(fp, di_gid);
+ sb->st_size = DIP(fp, di_size);
return (0);
}
@@ -826,7 +851,7 @@ ufs_readdir(struct open_file *f, struct dirent *d)
* assume that a directory entry will not be split across blocks
*/
again:
- if (fp->f_seekp >= fp->f_di.di_size)
+ if (fp->f_seekp >= DIP(fp, di_size))
return (ENOENT);
error = buf_read_file(f, &buf, &buf_size);
if (error)
@@ -839,33 +864,3 @@ again:
strcpy(d->d_name, dp->d_name);
return (0);
}
-
-#ifdef COMPAT_UFS
-/*
- * Sanity checks for old file systems.
- *
- * XXX - goes away some day.
- */
-static void
-ffs_oldfscompat(fs)
- struct fs *fs;
-{
- int i;
-
- fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
- fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
- if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
- fs->fs_nrpos = 8; /* XXX */
- if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
- quad_t sizepb = fs->fs_bsize; /* XXX */
- /* XXX */
- fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
- for (i = 0; i < NIADDR; i++) { /* XXX */
- sizepb *= NINDIR(fs); /* XXX */
- fs->fs_maxfilesize += sizepb; /* XXX */
- } /* XXX */
- fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
- fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
- } /* XXX */
-}
-#endif
OpenPOWER on IntegriCloud