summaryrefslogtreecommitdiffstats
path: root/fs/ufs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /fs/ufs
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'fs/ufs')
-rw-r--r--fs/ufs/.cvsignore1
-rw-r--r--fs/ufs/ufs_dir.c32
-rw-r--r--fs/ufs/ufs_inode.c116
-rw-r--r--fs/ufs/ufs_namei.c86
-rw-r--r--fs/ufs/ufs_super.c221
-rw-r--r--fs/ufs/ufs_swab.c56
-rw-r--r--fs/ufs/ufs_swab.h84
-rw-r--r--fs/ufs/ufs_symlink.c32
8 files changed, 410 insertions, 218 deletions
diff --git a/fs/ufs/.cvsignore b/fs/ufs/.cvsignore
index 4671378ae..857dd22e9 100644
--- a/fs/ufs/.cvsignore
+++ b/fs/ufs/.cvsignore
@@ -1 +1,2 @@
.depend
+.*.flags
diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c
index c64f38684..e6d27c217 100644
--- a/fs/ufs/ufs_dir.c
+++ b/fs/ufs/ufs_dir.c
@@ -8,6 +8,9 @@
*
* swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
*
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
*/
#include <linux/fs.h>
@@ -28,17 +31,18 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
struct ufs_direct * de;
struct super_block * sb;
int de_reclen;
- __u32 s_flags, bytesex;
+ __u32 flags;
- /* Isn't that already done but the upper layer??? */
+ /* Isn't that already done in the upper layer???
+ * the VFS layer really needs some explicit documentation!
+ */
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
sb = inode->i_sb;
- s_flags = sb->u.ufs_sb.s_flags;
- bytesex = s_flags & UFS_BYTESEX;
+ flags = sb->u.ufs_sb.s_flags;
- if (s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("ufs_readdir: ino %lu f_pos %lu\n",
inode->i_ino, (unsigned long) filp->f_pos);
ufs_print_inode(inode);
@@ -92,20 +96,23 @@ revalidate:
&& offset < sb->s_blocksize) {
de = (struct ufs_direct *) (bh->b_data + offset);
/* XXX - put in a real ufs_check_dir_entry() */
- if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
+ if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) {
/* SWAB16() was unneeded -- compare to 0 */
- filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
+ filp->f_pos = (filp->f_pos &
+ (sb->s_blocksize - 1)) +
+ sb->s_blocksize;
brelse(bh);
return stored;
}
-#if 0
+#if 0 /* XXX */
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
/* XXX - beware about de having to be swabped somehow */
bh, offset)) {
/* On error, skip the f_pos to the
next block. */
- filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
- + sb->s_blocksize;
+ filp->f_pos = (filp->f_pos &
+ (sb->s_blocksize - 1)) +
+ sb->s_blocksize;
brelse (bh);
return stored;
}
@@ -121,11 +128,12 @@ revalidate:
* during the copy operation. */
unsigned long version = inode->i_version;
- if (s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("ufs_readdir: filldir(%s,%u)\n",
de->d_name, SWAB32(de->d_ino));
}
- error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino));
+ error = filldir(dirent, de->d_name, NAMLEN(de),
+ filp->f_pos, SWAB32(de->d_ino));
if (error)
break;
if (version != inode->i_version)
diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c
index 75329c584..2011a0be8 100644
--- a/fs/ufs/ufs_inode.c
+++ b/fs/ufs/ufs_inode.c
@@ -9,8 +9,18 @@
* Clean swab support on 19970406
* by Francois-Rene Rideau <rideau@ens.fr>
*
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
*/
+#undef DEBUG_UFS_INODE
+/*#define DEBUG_UFS_INODE 1*/
+/* Uncomment the line above when hacking ufs inode code */
+
#include <linux/fs.h>
#include <linux/ufs_fs.h>
#include <linux/sched.h>
@@ -25,29 +35,30 @@ void ufs_print_inode(struct inode * inode)
inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
" 0x%x 0x%x 0x%x 0x%x>\n",
- inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1],
- inode->u.ufs_i.i_data[2], inode->u.ufs_i.i_data[3],
- inode->u.ufs_i.i_data[4], inode->u.ufs_i.i_data[5],
- inode->u.ufs_i.i_data[6], inode->u.ufs_i.i_data[7],
- inode->u.ufs_i.i_data[8], inode->u.ufs_i.i_data[9],
- inode->u.ufs_i.i_data[10], inode->u.ufs_i.i_data[11]);
+ inode->u.ufs_i.i_u1.i_data[0], inode->u.ufs_i.i_u1.i_data[1],
+ inode->u.ufs_i.i_u1.i_data[2], inode->u.ufs_i.i_u1.i_data[3],
+ inode->u.ufs_i.i_u1.i_data[4], inode->u.ufs_i.i_u1.i_data[5],
+ inode->u.ufs_i.i_u1.i_data[6], inode->u.ufs_i.i_u1.i_data[7],
+ inode->u.ufs_i.i_u1.i_data[8], inode->u.ufs_i.i_u1.i_data[9],
+ inode->u.ufs_i.i_u1.i_data[10], inode->u.ufs_i.i_u1.i_data[11]);
printk(" gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n",
inode->u.ufs_i.i_gen,
- inode->u.ufs_i.i_data[UFS_IND_BLOCK],
- inode->u.ufs_i.i_data[UFS_DIND_BLOCK],
- inode->u.ufs_i.i_data[UFS_TIND_BLOCK]);
+ inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK],
+ inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK],
+ inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]);
}
-#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_data[(nr)])
+#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_u1.i_data[(nr)])
static inline int block_bmap (struct inode *inode, int block, int nr)
{
struct buffer_head *bh;
int tmp;
- __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+ __u32 flags = inode->i_sb->u.ufs_sb.s_flags;
/* XXX Split in fsize big blocks (Can't bread 8Kb). */
tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2);
- bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize);
+ bh = bread (inode->i_dev, inode->i_sb->u.ufs_sb.s_blockbase + block +
+ tmp, inode->i_sb->s_blocksize);
if (!bh)
return 0;
nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2;
@@ -75,13 +86,16 @@ int ufs_bmap (struct inode * inode, int block)
return 0;
}
if (lbn < UFS_NDADDR)
- return ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff);
+ return (inode->i_sb->u.ufs_sb.s_blockbase +
+ ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff));
lbn -= UFS_NDADDR;
if (lbn < addr_per_block) {
i = inode_bmap (inode, UFS_IND_BLOCK);
if (!i)
return 0;
- return ufs_dbn (inode->i_sb, block_bmap (inode, i, lbn), boff);
+ return (inode->i_sb->u.ufs_sb.s_blockbase +
+ ufs_dbn (inode->i_sb,
+ block_bmap (inode, i, lbn), boff));
}
lbn -= addr_per_block;
if (lbn < (1 << (addr_per_block_bits * 2))) {
@@ -91,9 +105,10 @@ int ufs_bmap (struct inode * inode, int block)
i = block_bmap (inode, i, lbn >> addr_per_block_bits);
if (!i)
return 0;
- return ufs_dbn (inode->i_sb,
+ return (inode->i_sb->u.ufs_sb.s_blockbase +
+ ufs_dbn (inode->i_sb,
block_bmap (inode, i, lbn & (addr_per_block-1)),
- boff);
+ boff));
}
lbn -= (1 << (addr_per_block_bits * 2));
i = inode_bmap (inode, UFS_TIND_BLOCK);
@@ -106,8 +121,9 @@ int ufs_bmap (struct inode * inode, int block)
(lbn >> addr_per_block_bits) & (addr_per_block - 1));
if (!i)
return 0;
- return ufs_dbn (inode->i_sb,
- block_bmap (inode, i, lbn & (addr_per_block-1)), boff);
+ return (inode->i_sb->u.ufs_sb.s_blockbase +
+ ufs_dbn (inode->i_sb,
+ block_bmap (inode, i, lbn & (addr_per_block-1)), boff));
}
/* XXX - ufs_read_inode is a mess */
@@ -116,28 +132,30 @@ void ufs_read_inode(struct inode * inode)
struct super_block * sb;
struct ufs_inode * ufsip;
struct buffer_head * bh;
- __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+ __u32 flags = inode->i_sb->u.ufs_sb.s_flags;
sb = inode->i_sb;
if (ufs_ino_ok(inode)) {
- printk("ufs_read_inode: bad inum %lu", inode->i_ino);
+ printk("ufs_read_inode: bad inum %lu\n", inode->i_ino);
return;
}
-#if 0
+#ifdef DEBUG_UFS_INODE
printk("ufs_read_inode: ino %lu cg %u cgino %u ipg %u inopb %u\n",
inode->i_ino, ufs_ino2cg(inode),
(inode->i_ino%sb->u.ufs_sb.s_inopb),
sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb);
#endif
bh = bread(inode->i_dev,
+ inode->i_sb->u.ufs_sb.s_blockbase +
ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
- (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
- BLOCK_SIZE);
+ (inode->i_ino%sb->u.ufs_sb.s_ipg)/
+ (sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
+ sb->s_blocksize);
if (!bh) {
- printk("ufs_read_inode: can't read inode %lu from dev %d/%d",
+ printk("ufs_read_inode: can't read inode %lu from dev %d/%d\n",
inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
return;
}
@@ -176,23 +194,21 @@ void ufs_read_inode(struct inode * inode)
* random users can't get at these files, since they get dynamically
* "chown()ed" to root.
*/
- if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) {
- /* EFT */
+ if (UFS_UID(ufsip) >= UFS_USEEFT) {
inode->i_uid = 0;
printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
- SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
- inode->i_uid);
+ UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
+ MINOR(inode->i_dev), inode->i_uid);
} else {
- inode->i_uid = SWAB16(ufsip->ui_suid);
+ inode->i_uid = UFS_UID(ufsip);
}
- if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) {
- /* EFT */
+ if (UFS_GID(ufsip) >= UFS_USEEFT) {
inode->i_gid = 0;
printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
- SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
- inode->i_gid);
+ UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
+ MINOR(inode->i_dev), inode->i_gid);
} else {
- inode->i_gid = SWAB16(ufsip->ui_sgid);
+ inode->i_gid = UFS_GID(ufsip);
}
/*
@@ -249,13 +265,19 @@ void ufs_read_inode(struct inode * inode)
S_ISLNK(inode->i_mode)) {
int i;
- for (i = 0; i < UFS_NDADDR; i++) {
- inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]);
- }
- for (i = 0; i < UFS_NINDIR; i++) {
- inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] =
- SWAB32(ufsip->ui_ib[i]);
- }
+ if (inode->i_blocks) {
+ for (i = 0; i < UFS_NDADDR; i++) {
+ inode->u.ufs_i.i_u1.i_data[i] =
+ SWAB32(ufsip->ui_u2.ui_addr.ui_db[i]);
+ }
+ for (i = 0; i < UFS_NINDIR; i++) {
+ inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK + i] =
+ SWAB32(ufsip->ui_u2.ui_addr.ui_ib[i]);
+ }
+ } else /* fast symlink */ {
+ memcpy(inode->u.ufs_i.i_u1.i_symlink,
+ ufsip->ui_u2.ui_symlink, 60);
+ }
}
/* KRR - I need to check the SunOS header files, but for the time
@@ -265,17 +287,15 @@ void ufs_read_inode(struct inode * inode)
* the code.
*/
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db);
+ inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db);
}
- /* XXX - implement fast and slow symlinks */
-
inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags);
inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */
- inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */
- inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid);
- inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid);
- inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag);
+ inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_u3.ui_sun.ui_shadow); /* XXX */
+ inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_u3.ui_sun.ui_uid);
+ inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_u3.ui_sun.ui_gid);
+ inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_u3.ui_sun.ui_oeftflag);
brelse(bh);
diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c
index 6cf8c6c39..021b85442 100644
--- a/fs/ufs/ufs_namei.c
+++ b/fs/ufs/ufs_namei.c
@@ -9,6 +9,9 @@
* Clean swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
* Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
*
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
*/
#include <linux/fs.h>
@@ -17,20 +20,21 @@
#include "ufs_swab.h"
/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- * stolen from ext2fs
+ * NOTE1: unlike strncmp, ufs_match returns 1 for success, 0 for failure
+ * (stolen from ext2fs.)
+ * NOTE2: flags *is* used, though this is hidden by macros like NAMLEN.
*/
-static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex)
+static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 flags)
{
if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
return 0;
/*
* "" means "." ---> so paths like "/usr/lib//libc.a" work
*/
- if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') &&
+ if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') &&
(d->d_name[1] == '\0'))
return 1;
- if (len != SWAB16(d->d_namlen))
+ if (len != NAMLEN(d))
return 0;
return !memcmp(name, d->d_name, len);
}
@@ -38,89 +42,88 @@ static int ufs_match (int len, const char * const name, struct ufs_direct * d, _
int ufs_lookup (struct inode *dir, struct dentry *dentry)
{
/* XXX - this is all fucked up! */
- /* XXX - and it's been broken since linux has this new dentry interface:
- * allows reading of files, but screws the whole dcache, even outside
- * of the ufs partition, so that umount'ing won't suffice to fix it --
- * reboot needed
- */
unsigned long int lfragno, fragno;
struct buffer_head * bh;
struct ufs_direct * d;
+ struct super_block * sb = dir->i_sb;
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
- __u32 bytesex;
+ __u32 flags;
struct inode *inode;
/* XXX - isn't that already done by the upper layer? */
if (!dir || !S_ISDIR(dir->i_mode))
return -EBADF;
- bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+ flags = sb->u.ufs_sb.s_flags;
- if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
+ if (flags & UFS_DEBUG)
printk("Passed name: %s\nPassed length: %d\n", name, len);
-
/* debugging hacks:
* Touching /xyzzy in a filesystem toggles debugging messages.
*/
if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
(dir->i_ino == UFS_ROOTINO)) {
- dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
+ sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
printk("UFS debugging %s\n",
- (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
+ (sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
"on": "off");
goto not_found;
/*return(-ENOENT);*/
}
/*
- * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c.
+ * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c
*/
if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
(dir->i_ino == UFS_ROOTINO)) {
- dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
+ sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
printk("UFS inode debugging %s\n",
- (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
+ (sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
"on": "off");
goto not_found;
/*return(-ENOENT);*/
}
+ /*
+ * Touching /xyzzy.n in a filesystem toggles debugging for ufs_namei.c
+ */
if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
(dir->i_ino == UFS_ROOTINO)) {
- dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
+ sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
printk("UFS namei debugging %s\n",
- (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
+ (sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
"on": "off");
goto not_found;
/*return(-ENOENT);*/
}
+ /*
+ * Touching /xyzzy.l in a filesystem toggles debugging for ufs_symlink.c
+ */
if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
(dir->i_ino == UFS_ROOTINO)) {
- dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
+ sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
printk("UFS symlink debugging %s\n",
- (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
+ (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
"on": "off");
goto not_found;
/*return(-ENOENT);*/
}
-
/* Now for the real thing */
- if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
+ if (flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
printk("ufs_lookup: called for ino %lu name %s\n",
dir->i_ino, name);
}
- /* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */
- for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) {
+ for (lfragno = 0; lfragno < dir->i_blocks; lfragno++) {
fragno = ufs_bmap(dir, lfragno);
+ /* ufs_bmap() reads the block (frag) size in s_blocksize */
/* XXX - ufs_bmap() call needs error checking */
- /* XXX - s_blocksize is actually the UFS frag size */
- if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("ufs_lookup: ino %lu lfragno %lu fragno %lu\n",
dir->i_ino, lfragno, fragno);
}
@@ -129,7 +132,7 @@ int ufs_lookup (struct inode *dir, struct dentry *dentry)
goto not_found;
/*return(-ENOENT);*/
}
- bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
+ bh = bread(dir->i_dev, fragno, sb->s_blocksize);
if (bh == NULL) {
printk("ufs_lookup: bread failed: "
"ino %lu, lfragno %lu",
@@ -138,17 +141,17 @@ int ufs_lookup (struct inode *dir, struct dentry *dentry)
}
d = (struct ufs_direct *)(bh->b_data);
while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <=
- dir->i_sb->s_blocksize) {
+ sb->s_blocksize) {
/* XXX - skip block if d_reclen or d_namlen is 0 */
- if ((d->d_reclen == 0) || (d->d_namlen == 0)) {
+ if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) {
/* no need to SWAB16(): test against 0 */
- if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("ufs_lookup: skipped space in directory, ino %lu\n",
dir->i_ino);
}
break;
}
- if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("lfragno 0x%lx "
"direct d 0x%x "
"d_ino %u "
@@ -158,30 +161,31 @@ int ufs_lookup (struct inode *dir, struct dentry *dentry)
(unsigned int)((unsigned long)d),
SWAB32(d->d_ino),
SWAB16(d->d_reclen),
- SWAB16(d->d_namlen),d->d_name);
+ NAMLEN(d),d->d_name);
}
- if ((SWAB16(d->d_namlen) == len) &&
+ if ((NAMLEN(d) == len) &&
/* XXX - don't use strncmp() - see ext2fs */
- (ufs_match(len, name, d, bytesex))) {
+ (ufs_match(len, name, d, flags))) {
/* We have a match */
/* XXX - I only superficially understand how things work,
* so use at your own risk... -- Fare'
*/
- inode = iget(dir->i_sb, SWAB32(d->d_ino));
+ inode = iget(sb, SWAB32(d->d_ino));
brelse(bh);
if(!inode) { return -EACCES; }
d_add(dentry,inode);
return(0);
} else {
/* XXX - bounds checking */
- if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (flags & UFS_DEBUG) {
printk("ufs_lookup: "
"wanted (%s,%d) got (%s,%d)\n",
name, len,
- d->d_name, SWAB16(d->d_namlen));
+ d->d_name, NAMLEN(d));
}
}
- d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen));
+ d = (struct ufs_direct *)((char *)d +
+ SWAB16(d->d_reclen));
}
brelse(bh);
}
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
index a3c32ccce..6a378fb13 100644
--- a/fs/ufs/ufs_super.c
+++ b/fs/ufs/ufs_super.c
@@ -19,9 +19,19 @@
*
* Clean swab support on 19970406 by
* Francois-Rene Rideau <rideau@ens.fr>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
*/
-#include <linux/config.h>
+#undef DEBUG_UFS_SUPER
+/*#define DEBUG_UFS_SUPER 1*/
+/* Uncomment the line above when hacking ufs superblock code */
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -42,7 +52,7 @@ static struct super_operations ufs_super_ops = {
NULL, /* XXX - ufs_write_inode() */
ufs_put_inode,
NULL, /* XXX - ufs_delete_inode() */
- NULL, /* notify_change() */
+ NULL, /* XXX - notify_change() */
ufs_put_super,
NULL, /* XXX - ufs_write_super() */
ufs_statfs,
@@ -89,23 +99,26 @@ void ufs_warning (struct super_block * sb, const char * function,
kdevname(sb->s_dev), function, error_buf);
}
-#if 0 /* unused */
+#ifdef DEBUG_UFS_SUPER
static void
ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
{
+ __u32 flags = sb->u.ufs_sb.s_flags;
printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno);
- printk("fs_size: 0x%8.8x\n", usb->fs_size);
- printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg);
- printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize);
- printk("fs_frag: 0x%8.8x\n", usb->fs_frag);
+ printk("fs_size: 0x%8.8x\n", usb->fs_size);
+ printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg);
+ printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize);
+ printk("fs_fsize: 0x%8.8x\n", usb->fs_fsize);
+ printk("fs_frag: 0x%8.8x\n", usb->fs_frag);
printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir);
- printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb);
- printk("fs_optim: 0x%8.8x\n", usb->fs_optim);
- printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl);
- printk("fs_state: 0x%8.8x\n", usb->fs_state);
- printk("fs_magic: 0x%8.8x\n", usb->fs_magic);
- printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt);
+ printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb);
+ printk("fs_optim: 0x%8.8x\n", usb->fs_optim);
+ printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl);
+ printk("fs_clean: 0x%8.8x\n", usb->fs_clean);
+ printk("fs_state: 0x%8.8x\n", UFS_STATE(usb));
+ printk("fs_magic: 0x%8.8x\n", usb->fs_magic);
+ printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt);
return;
}
@@ -116,7 +129,9 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
{
struct ufs_superblock * usb; /* normalized to local byteorder */
struct buffer_head * bh1, *bh2;
- __u32 bytesex = 0;
+ __u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */
+ static int offsets[] = { 0, 96, 160 }; /* different superblock locations */
+ int i;
/* sb->s_dev and sb->s_flags are set by our caller
* data is the mystery argument to sys_mount()
@@ -127,102 +142,137 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
MOD_INC_USE_COUNT;
lock_super (sb);
+ set_blocksize (sb->s_dev, BLOCK_SIZE);
/* XXX - make everything read only for testing */
sb->s_flags |= MS_RDONLY;
- if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) ||
- !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE,
- BLOCK_SIZE))) {
- brelse(bh1);
- printk ("ufs_read_super: unable to read superblock\n");
+ for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
+ if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE,
+ BLOCK_SIZE)) ||
+ !(bh2 = bread(sb->s_dev, offsets[i] +
+ UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) {
+ brelse(bh1);
+ printk ("ufs_read_super: unable to read superblock\n");
+ goto ufs_read_super_lose;
+ }
+ /* XXX - redo this so we can free it later... */
+ usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
+ if (usb == NULL) {
+ brelse(bh1);
+ brelse(bh2);
+ printk ("ufs_read_super: get_free_page() failed\n");
+ goto ufs_read_super_lose;
+ }
+
+ memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
+ memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
+ sizeof(struct ufs_superblock) - BLOCK_SIZE);
- goto ufs_read_super_lose;
- }
- /* XXX - redo this so we can free it later... */
- usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
- if (usb == NULL) {
brelse(bh1);
brelse(bh2);
- printk ("ufs_read_super: get_free_page() failed\n");
-
- goto ufs_read_super_lose;
- }
- memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
- memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
- sizeof(struct ufs_superblock) - BLOCK_SIZE);
-
- brelse(bh1);
- brelse(bh2);
-
- switch (le32_to_cpup(&usb->fs_magic)) {
- case UFS_MAGIC:
- bytesex = UFS_LITTLE_ENDIAN;
- ufs_superblock_le_to_cpus(usb);
- break;
- case UFS_CIGAM:
- bytesex = UFS_BIG_ENDIAN;
- ufs_superblock_be_to_cpus(usb);
- break;
- /* usb is now normalized to local byteorder */
- default:
- printk ("ufs_read_super: bad magic number 0x%8.8x "
- "on dev %d/%d\n", usb->fs_magic,
- MAJOR(sb->s_dev), MINOR(sb->s_dev));
- goto ufs_read_super_lose;
+ switch (le32_to_cpup(&usb->fs_magic)) {
+ case UFS_MAGIC:
+ flags |= UFS_LITTLE_ENDIAN;
+ ufs_superblock_le_to_cpus(usb);
+ goto found;
+ case UFS_CIGAM:
+ flags |= UFS_BIG_ENDIAN;
+ ufs_superblock_be_to_cpus(usb);
+ goto found;
+ /* usb is now normalized to local byteorder */
+ default:
+ }
}
-
+ printk ("ufs_read_super: bad magic number 0x%8.8x "
+ "on dev %d/%d\n", usb->fs_magic,
+ MAJOR(sb->s_dev), MINOR(sb->s_dev));
+ goto ufs_read_super_lose;
+found:
+#ifdef DEBUG_UFS_SUPER
+ printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]);
+#endif
/* We found a UFS filesystem on this device. */
/* XXX - parse args */
- if (usb->fs_bsize != UFS_BSIZE) {
- printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize,
- UFS_BSIZE);
+ if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) {
+ printk("ufs_read_super: invalid fs_bsize = %d\n",
+ usb->fs_bsize);
goto ufs_read_super_lose;
}
- if (usb->fs_fsize != UFS_FSIZE) {
- printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize,
- UFS_FSIZE);
+ if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) {
+ printk("ufs_read_super: invalid fs_fsize = %d\n",
+ usb->fs_fsize);
goto ufs_read_super_lose;
}
+ if (usb->fs_fsize != BLOCK_SIZE) {
+ set_blocksize (sb->s_dev, usb->fs_fsize);
+ }
+ flags |= UFS_VANILLA;
+ /* XXX more consistency check */
#ifdef DEBUG_UFS_SUPER
- printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt);
+ printk("ufs_read_super: maxsymlinklen 0x%8.8x\n",
+ usb->fs_u.fs_44.fs_maxsymlinklen);
#endif
+ if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) {
+ if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
+ flags |= UFS_44BSD;
+ } else {
+ flags |= UFS_OLD; /* 4.2BSD */
+ }
+ } else if (offsets[i] > 0) {
+ flags |= UFS_NEXT;
+ } else {
+ flags |= UFS_SUN;
+ }
- if (usb->fs_state == UFS_FSOK - usb->fs_time) {
- switch(usb->fs_clean) {
- case UFS_FSCLEAN:
#ifdef DEBUG_UFS_SUPER
- printk("ufs_read_super: fs is clean\n");
+ ufs_print_super_stuff(sb, usb);
+#endif
+ if ( ((flags&UFS_ST_MASK)==UFS_ST_44BSD)
+ || ((flags&UFS_ST_MASK)==UFS_ST_OLD)
+ || ((flags&UFS_ST_MASK)==UFS_ST_NEXT)
+ || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN)
+ && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) {
+ switch(usb->fs_clean) {
+ case UFS_FSACTIVE: /* 0x00 */
+ printk("ufs_read_super: fs is active\n");
+ sb->s_flags |= MS_RDONLY;
+ break;
+ case UFS_FSCLEAN: /* 0x01 */
+#ifdef DEBUG_UFS_SUPER
+ printk("ufs_read_super: fs is clean\n");
+#endif
+ break;
+ case UFS_FSSTABLE: /* 0x02 */
+#ifdef DEBUG_UFS_SUPER
+ printk("ufs_read_super: fs is stable\n");
#endif
- break;
- case UFS_FSSTABLE:
+ break;
+ case UFS_FSOSF1: /* 0x03 */
+ /* XXX is this correct for DEC OSF/1? */
#ifdef DEBUG_UFS_SUPER
- printk("ufs_read_super: fs is stable\n");
+ printk("ufs_read_super: fs is clean and stable (OSF/1)\n");
#endif
- break;
- case UFS_FSACTIVE:
- printk("ufs_read_super: fs is active\n");
- sb->s_flags |= MS_RDONLY;
- break;
- case UFS_FSBAD:
- printk("ufs_read_super: fs is bad\n");
- sb->s_flags |= MS_RDONLY;
- break;
- default:
- printk("ufs_read_super: can't grok fs_clean 0x%x\n",
- usb->fs_clean);
- sb->s_flags |= MS_RDONLY;
- break;
- }
+ break;
+ case UFS_FSBAD: /* 0xFF */
+ printk("ufs_read_super: fs is bad\n");
+ sb->s_flags |= MS_RDONLY;
+ break;
+ default:
+ printk("ufs_read_super: can't grok fs_clean 0x%x\n",
+ usb->fs_clean);
+ sb->s_flags |= MS_RDONLY;
+ break;
+ }
} else {
- printk("ufs_read_super: fs needs fsck\n");
- sb->s_flags |= MS_RDONLY;
- /* XXX - make it read only or barf if it's not (/, /usr) */
+ printk("ufs_read_super: fs needs fsck\n");
+ sb->s_flags |= MS_RDONLY;
+ /* XXX - make it read only or barf if it's not (/, /usr) */
}
/* XXX - sanity check sb fields */
@@ -238,7 +288,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
/* sb->s_wait */
/* XXX - sb->u.ufs_sb */
sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */
- sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ;
+ sb->u.ufs_sb.s_flags = flags ;
sb->u.ufs_sb.s_ncg = usb->fs_ncg;
sb->u.ufs_sb.s_ipg = usb->fs_ipg;
sb->u.ufs_sb.s_fpg = usb->fs_fpg;
@@ -257,6 +307,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask)
>> usb->fs_fshift);
sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
+ sb->u.ufs_sb.s_blockbase = offsets[i];
sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
#ifdef DEBUG_UFS_SUPER
@@ -271,6 +322,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
ufs_read_super_lose:
/* XXX - clean up */
+ set_blocksize (sb->s_dev, BLOCK_SIZE);
sb->s_dev = 0;
unlock_super (sb);
MOD_DEC_USE_COUNT;
@@ -285,6 +337,7 @@ void ufs_put_super (struct super_block * sb)
lock_super (sb);
/* XXX - sync fs data, set state to ok, and flush buffers */
+ set_blocksize (sb->s_dev, BLOCK_SIZE);
sb->s_dev = 0;
/* XXX - free allocated kernel memory */
diff --git a/fs/ufs/ufs_swab.c b/fs/ufs/ufs_swab.c
index 2dc4061a0..261d16de9 100644
--- a/fs/ufs/ufs_swab.c
+++ b/fs/ufs/ufs_swab.c
@@ -36,6 +36,10 @@
* 2) instead of byteswapping, use [bl]e_to_cpu:
* it might be that we run on a VAX!
*
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
* HOWTO continue adding swab support:
* basically, anywhere metadata is bread() (i.e. mapped to block device),
* data should either be SWAB()ed on the fly,
@@ -106,33 +110,69 @@ static __inline__ void n_le32_to_cpus(__u32*p,unsigned n) {
/*
* Here are the whole-structure swabping routines...
+ * They were fun to design, but I don't understand why we
+ * need a copy of the superblock, anyway. -- Fare'
*/
extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) {
#ifndef __BIG_ENDIAN
+ __u16 sb_type = 1; /* SUN type superblock */
+
+ if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
+ sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */
+
be32_to_cpus__between(*usb,fs_link,fs_fmod);
/* XXX - I dunno what to do w/ fs_csp,
* but it is unused by the current code, so that's ok for now.
*/
be32_to_cpus(&usb->fs_cpc);
- be16_to_cpus__between(*usb,fs_opostbl,fs_sparecon);
- be32_to_cpus__between(*usb,fs_sparecon,fs_qbmask);
- be64_to_cpus(&usb->fs_qbmask);
- be64_to_cpus(&usb->fs_qfmask);
+ if (sb_type) {
+ be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
+ be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
+ /* Might fail on strictly aligning 64-bit big-endian
+ * architectures. Ouch!
+ */
+ be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
+ be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
+ } else {
+ be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
+ be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
+ be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
+ be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
+ be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
+ be32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
+ }
be32_to_cpus__between(*usb,fs_postblformat,fs_magic);
#endif
}
extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) {
#ifndef __LITTLE_ENDIAN
+ __u16 sb_type = 1; /* SUN type superblock */
+
+ if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
+ sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */
+
le32_to_cpus__between(*usb,fs_link,fs_fmod);
/* XXX - I dunno what to do w/ fs_csp,
* but it is unused by the current code, so that's ok for now.
*/
le32_to_cpus(&usb->fs_cpc);
- le16_to_cpus__between(*usb,fs_opostbl,fs_sparecon);
- le32_to_cpus__between(*usb,fs_sparecon,fs_qbmask);
- le64_to_cpus(&usb->fs_qbmask);
- le64_to_cpus(&usb->fs_qfmask);
+ if (sb_type) {
+ le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
+ le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
+ /* Might fail on strictly aligning 64-bit big-endian
+ * architectures. Ouch!
+ */
+ le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
+ le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
+ } else {
+ le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
+ le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
+ le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
+ le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
+ le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
+ le32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
+ }
le32_to_cpus__between(*usb,fs_postblformat,fs_magic);
#endif
}
diff --git a/fs/ufs/ufs_swab.h b/fs/ufs/ufs_swab.h
index 921fb3d79..f8e9fd898 100644
--- a/fs/ufs/ufs_swab.h
+++ b/fs/ufs/ufs_swab.h
@@ -18,42 +18,104 @@
* to support them.
* (2) for a read/write ufs driver, we should distinguish
* between byteswapping for read or write accesses!
+ * naming should then be UFS16_TO_CPU and suches.
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
*/
#include <linux/ufs_fs.h>
#include <asm/byteorder.h>
/*
- * These are only valid inside ufs routines,
- * after bytesex has been initialized to sb->u.ufs_sb.s_flags&UFS_BYTESEX
+ * These are only valid inside ufs routines, after a variable named flags
+ * has been made visible in current scope and properly initialized:
+ __u32 flags = sb->u.ufs_sb.s_flags ;
*/
-#define SWAB16(x) ufs_swab16(bytesex,x)
-#define SWAB32(x) ufs_swab32(bytesex,x)
-#define SWAB64(x) ufs_swab64(bytesex,x)
+#define SWAB16(x) ufs_swab16(flags,x)
+#define SWAB32(x) ufs_swab32(flags,x)
+#define SWAB64(x) ufs_swab64(flags,x)
-extern __inline__ __const__ __u16 ufs_swab16(__u32 bytesex, __u16 x) {
- if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u16 ufs_swab16(__u32 flags, __u16 x) {
+ if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
return le16_to_cpu(x);
} else {
return be16_to_cpu(x);
}
}
-extern __inline__ __const__ __u32 ufs_swab32(__u32 bytesex, __u32 x) {
- if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u32 ufs_swab32(__u32 flags, __u32 x) {
+ if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
return le32_to_cpu(x);
} else {
return be32_to_cpu(x);
}
}
-extern __inline__ __const__ __u64 ufs_swab64(__u32 bytesex, __u64 x) {
- if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u64 ufs_swab64(__u32 flags, __u64 x) {
+ if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
return le64_to_cpu(x);
} else {
return be64_to_cpu(x);
}
}
+
+/*
+ * These are for in-core superblock normalization.
+ * It might or not be a bad idea once we go to a read/write driver,
+ * as all critical info should be copied to the sb info structure anyway.
+ * So better replace them with a static inline function
+ * ufs_superblock_to_sb_info() in ufs_super.c
+ */
extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb);
extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb);
+
+/*
+ * These also implicitly depend on variable flags...
+ * NAMLEN(foo) is already normalized to local format, so don't SWAB16() it!
+ */
+
+#define NAMLEN(direct) ufs_namlen(flags,direct)
+extern __inline__ __u16 ufs_namlen(__u32 flags, struct ufs_direct * direct) {
+ if ( (flags&UFS_DE_MASK) == UFS_DE_OLD) {
+ return SWAB16(direct->d_u.d_namlen);
+ } else /* UFS_DE_44BSD */ {
+ return direct->d_u.d_44.d_namlen;
+ }
+}
+
+/* Here is how the uid is computed:
+ if the file system is 4.2BSD, get it from oldids.
+ if it has sun extension and oldids is USEEFT, get it from ui_sun.
+ if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd).
+ depends on implicit variable flags being initialized from
+ __u32 flags = sb->u.ufs_sb.s_flags;
+*/
+#define UFS_UID(ino) ufs_uid(flags,ino)
+#define UFS_GID(ino) ufs_gid(flags,ino)
+
+extern __inline__ __u32 ufs_uid(__u32 flags,struct ufs_inode * ino) {
+ switch(flags&UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ return SWAB32(ino->ui_u3.ui_sun.ui_uid) ;
+ case UFS_UID_44BSD:
+ return SWAB32(ino->ui_u3.ui_44.ui_uid) ;
+ case UFS_UID_OLD:
+ default:
+ return SWAB16(ino->ui_u1.oldids.suid) ;
+ }
+}
+extern __inline__ __u32 ufs_gid(__u32 flags,struct ufs_inode * ino) {
+ switch(flags&UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ return SWAB32(ino->ui_u3.ui_sun.ui_gid) ;
+ case UFS_UID_44BSD:
+ return SWAB32(ino->ui_u3.ui_44.ui_gid) ;
+ case UFS_UID_OLD:
+ default:
+ return SWAB16(ino->ui_u1.oldids.sgid) ;
+ }
+}
+
#endif /* _UFS_SWAB_H */
diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c
index 76d5fbf11..e19abe44d 100644
--- a/fs/ufs/ufs_symlink.c
+++ b/fs/ufs/ufs_symlink.c
@@ -8,6 +8,9 @@
*
* Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
*
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
*/
#include <linux/fs.h>
@@ -19,15 +22,17 @@
extern int ufs_bmap (struct inode *, int);
static int
-ufs_readlink(struct inode * inode, char * buffer, int buflen)
+ufs_readlink(struct dentry * dentry, char * buffer, int buflen)
{
+ struct inode * inode = dentry->d_inode;
+ struct super_block * sb = inode->i_sb;
unsigned long int block;
struct buffer_head * bh = NULL;
char * link;
int i;
char c;
- if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
+ if (sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
printk("ufs_readlink: called on ino %lu dev %u/%u\n",
inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
}
@@ -36,16 +41,16 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
return -EINVAL;
}
- if (buflen > inode->i_sb->s_blocksize - 1)
- buflen = inode->i_sb->s_blocksize - 1;
+ if (buflen > sb->s_blocksize - 1)
+ buflen = sb->s_blocksize - 1;
if (inode->i_blocks) {
/* XXX - error checking */
block = ufs_bmap(inode, 0);
- if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
+ if (sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
printk("ufs_readlink: bmap got %lu for ino %lu\n",
block, inode->i_ino);
}
- bh = bread(inode->i_dev, block, BLOCK_SIZE);
+ bh = bread(inode->i_dev, block, sb->s_blocksize);
if (!bh) {
printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
inode->i_ino, MAJOR(inode->i_dev),
@@ -54,9 +59,8 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
}
link = bh->b_data;
/* no need to bswap */
- }
- else {
- link = (char *)&(inode->u.ufs_i.i_data[0]);
+ } else /* fast symlink */ {
+ link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
}
i = 0;
while (i < buflen && (c = link[i])) {
@@ -71,8 +75,9 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
* XXX - blatantly stolen from minix fs
*/
static struct dentry *
-ufs_follow_link(struct inode * inode, struct dentry * base)
+ufs_follow_link(struct dentry * dentry, struct dentry * base)
{
+ struct inode * inode = dentry->d_inode;
unsigned long int block;
struct buffer_head * bh = NULL;
char * link;
@@ -86,7 +91,7 @@ ufs_follow_link(struct inode * inode, struct dentry * base)
/* read the link from disk */
/* XXX - error checking */
block = ufs_bmap(inode, 0);
- bh = bread(inode->i_dev, block, BLOCK_SIZE);
+ bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize);
if (bh == NULL) {
printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
inode->i_ino, MAJOR(inode->i_dev),
@@ -95,9 +100,8 @@ ufs_follow_link(struct inode * inode, struct dentry * base)
return ERR_PTR(-EIO);
}
link = bh->b_data;
- } else {
- /* fast symlink */
- link = (char *)&(inode->u.ufs_i.i_data[0]);
+ } else /* fast symlink */ {
+ link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
}
base = lookup_dentry(link, base, 1);
brelse (bh);