summaryrefslogtreecommitdiffstats
path: root/fs/ufs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /fs/ufs
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'fs/ufs')
-rw-r--r--fs/ufs/Makefile10
-rw-r--r--fs/ufs/acl.c66
-rw-r--r--fs/ufs/balloc.c792
-rw-r--r--fs/ufs/cylinder.c212
-rw-r--r--fs/ufs/dir.c (renamed from fs/ufs/ufs_dir.c)105
-rw-r--r--fs/ufs/file.c281
-rw-r--r--fs/ufs/ialloc.c341
-rw-r--r--fs/ufs/inode.c665
-rw-r--r--fs/ufs/namei.c1147
-rw-r--r--fs/ufs/super.c690
-rw-r--r--fs/ufs/swab.h114
-rw-r--r--fs/ufs/symlink.c138
-rw-r--r--fs/ufs/truncate.c473
-rw-r--r--fs/ufs/ufs_file.c52
-rw-r--r--fs/ufs/ufs_inode.c332
-rw-r--r--fs/ufs/ufs_namei.c195
-rw-r--r--fs/ufs/ufs_super.c384
-rw-r--r--fs/ufs/ufs_swab.c178
-rw-r--r--fs/ufs/ufs_swab.h121
-rw-r--r--fs/ufs/ufs_symlink.c146
-rw-r--r--fs/ufs/util.c197
-rw-r--r--fs/ufs/util.h322
22 files changed, 5514 insertions, 1447 deletions
diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile
index 0a74c36c7..f8326866d 100644
--- a/fs/ufs/Makefile
+++ b/fs/ufs/Makefile
@@ -1,15 +1,15 @@
#
-# Makefile for the linux ufs-filesystem routines.
+# Makefile for the Linux ufs filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
+# unless it's something special (not a .c file).
#
-# Note 2! The CFLAGS definitions are now in the main makefile...
+# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := ufs.o
-O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \
- ufs_super.o ufs_symlink.o ufs_swab.o
+O_OBJS := acl.o balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
+ namei.o super.o symlink.o truncate.o util.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/ufs/acl.c b/fs/ufs/acl.c
new file mode 100644
index 000000000..934e474a1
--- /dev/null
+++ b/fs/ufs/acl.c
@@ -0,0 +1,66 @@
+/*
+ * linux/fs/ufs/acl.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/acl.c
+ *
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+/*
+ * This file will contain the Access Control Lists management for the
+ * second extended file system.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+/*
+ * ufs_permission ()
+ *
+ * Check for access rights
+ */
+int ufs_permission (struct inode * inode, int mask)
+{
+ unsigned short mode = inode->i_mode;
+
+ /*
+ * Nobody gets write access to a file on a readonly-fs
+ */
+ if ((mask & S_IWOTH) &&
+ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
+ IS_RDONLY(inode))
+ return -EROFS;
+ /*
+ * Nobody gets write access to an immutable file
+ */
+ if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+ return -EACCES;
+
+ /*
+ * If no ACL, checks using the file mode
+ */
+ else if (current->fsuid == inode->i_uid)
+ mode >>= 6;
+ else if (in_group_p (inode->i_gid))
+ mode >>= 3;
+ /*
+ * Access is always granted for root. We now check last,
+ * though, for BSD process accounting correctness
+ */
+ if (((mode & mask & S_IRWXO) == mask) || fsuser())
+ return 0;
+ else
+ return -EACCES;
+}
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
new file mode 100644
index 000000000..1022ad383
--- /dev/null
+++ b/fs/ufs/balloc.c
@@ -0,0 +1,792 @@
+/*
+ * linux/fs/ufs/balloc.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_BALLOC_DEBUG
+#undef UFS_BALLOC_DEBUG_MORE
+
+#ifdef UFS_BALLOC_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_BALLOC_DEBUG_MORE
+#define UFSDM \
+ufs_print_cylinder_stuff (ucg, swab); \
+printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), \
+swab32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
+printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
+printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
+printk("ndir: total %u, fs %u, cg %u\n\n", SWAB32(usb1->fs_cstotal.cs_ndir), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
+#else
+#define UFSDM
+#endif
+
+
+unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
+unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
+unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
+unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned);
+static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
+
+/*
+ * Free 'count' fragments from fragment number 'fragment'
+ */
+void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) {
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+
+ if (ufs_fragnum(fragment) + count > uspi->s_fpg)
+ ufs_error (sb, "ufs_free_fragments", "internal error");
+
+ lock_super(sb);
+
+ cgno = ufs_dtog(fragment);
+ bit = ufs_dtogd(fragment);
+ if (cgno >= uspi->s_ncg) {
+ ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
+ goto failed;
+ }
+
+ ucpi = ufs_load_cylinder (sb, cgno);
+ if (!ucpi)
+ goto failed;
+ ucg = ubh_get_ucg (UCPI_UBH);
+ if (!ufs_cg_chkmagic (ucg)) {
+ ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
+ goto failed;
+ }
+
+ UFSDM
+
+ end_bit = bit + count;
+ bbase = ufs_blknum (bit);
+ blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+ ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
+ for (i = bit; i < end_bit; i++) {
+ if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
+ ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
+ else ufs_error (sb, "ufs_free_fragments",
+ "bit already cleared for fragment %u", i);
+ }
+
+ DQUOT_FREE_BLOCK (sb, inode, count);
+ ADD_SWAB32(ucg->cg_cs.cs_nffree, count);
+ ADD_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+ ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+ blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+ ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
+
+ /*
+ * Trying to reasembly free fragments into block
+ */
+ blkno = ufs_fragstoblks (bbase);
+ if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+ SUB_SWAB32(ucg->cg_cs.cs_nffree, uspi->s_fpb);
+ SUB_SWAB32(usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
+ SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, uspi->s_fpb);
+ INC_SWAB32(ucg->cg_cs.cs_nbfree);
+ INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+ INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
+ cylno = ufs_cbtocylno (bbase);
+ INC_SWAB16(ubh_cg_blks (ucpi, cylno, ufs_cbtorpos(bbase)));
+ INC_SWAB32(ubh_cg_blktot (ucpi, cylno));
+ }
+
+ UFSDM
+
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+ sb->s_dirt = 1;
+
+ unlock_super (sb);
+ UFSD(("EXIT\n"))
+ return;
+
+failed:
+ unlock_super (sb);
+ UFSD(("EXIT (FAILED)\n"))
+ return;
+}
+
+/*
+ * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
+ */
+void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned overflow, cgno, bit, end_bit, blkno, i, cylno;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+
+ if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
+ ufs_error (sb, "ufs_free_blocks", "internal error");
+ goto failed;
+ }
+
+ lock_super(sb);
+
+do_more:
+ overflow = 0;
+ cgno = ufs_dtog (fragment);
+ bit = ufs_dtogd (fragment);
+ if (cgno >= uspi->s_ncg) {
+ ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
+ goto failed;
+ }
+ end_bit = bit + count;
+ if (end_bit > uspi->s_fpg) {
+ overflow = bit + count - uspi->s_fpg;
+ count -= overflow;
+ end_bit -= overflow;
+ }
+
+ ucpi = ufs_load_cylinder (sb, cgno);
+ if (!ucpi)
+ goto failed;
+ ucg = ubh_get_ucg (UCPI_UBH);
+ if (!ufs_cg_chkmagic (ucg)) {
+ ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
+ goto failed;
+ }
+
+ UFSDM
+
+ for (i = bit; i < end_bit; i += uspi->s_fpb) {
+ blkno = ufs_fragstoblks(i);
+ if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+ ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
+ }
+ ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+ DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb);
+ INC_SWAB32(ucg->cg_cs.cs_nbfree);
+ INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+ INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
+ cylno = ufs_cbtocylno(i);
+ INC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)));
+ INC_SWAB32(ubh_cg_blktot(ucpi, cylno));
+ }
+
+ UFSDM
+
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+
+ if (overflow) {
+ fragment += count;
+ count = overflow;
+ goto do_more;
+ }
+
+ sb->s_dirt = 1;
+ unlock_super (sb);
+ UFSD(("EXIT\n"))
+ return;
+
+failed:
+ unlock_super (sb);
+ UFSD(("EXIT (FAILED)\n"))
+ return;
+}
+
+
+
+#define NULLIFY_FRAGMENTS \
+ for (i = oldcount; i < newcount; i++) { \
+ bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \
+ memset (bh->b_data, 0, sb->s_blocksize); \
+ mark_buffer_uptodate(bh, 1); \
+ mark_buffer_dirty (bh, 1); \
+ if (IS_SYNC(inode)) { \
+ ll_rw_block (WRITE, 1, &bh); \
+ wait_on_buffer (bh); \
+ } \
+ brelse (bh); \
+ }
+
+unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
+ unsigned goal, unsigned count, int * err )
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct buffer_head * bh;
+ unsigned cgno, oldcount, newcount, tmp, request, i, result;
+ unsigned swab;
+
+ UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+ *err = -ENOSPC;
+
+ lock_super (sb);
+
+ tmp = SWAB32(*p);
+ if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
+ ufs_warning (sb, "ufs_new_fragments", "internal warning"
+ " fragment %u, count %u", fragment, count);
+ count = uspi->s_fpb - ufs_fragnum(fragment);
+ }
+ oldcount = ufs_fragnum (fragment);
+ newcount = oldcount + count;
+
+ /*
+ * Somebody else has just allocated our fragments
+ */
+ if (oldcount) {
+ if (!tmp) {
+ ufs_error (sb, "ufs_new_fragments", "internal error, "
+ "fragment %u, tmp %u\n", fragment, tmp);
+ return (unsigned)-1;
+ }
+ if (fragment < inode->u.ufs_i.i_lastfrag) {
+ UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+ printk("hlaska 2\n");
+ unlock_super (sb);
+ return 0;
+ }
+ }
+ else {
+ if (tmp) {
+ UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+ printk("hlaska 3, fragment %u, tmp %u, oldcount %u\n", fragment, tmp, oldcount);
+ unlock_super(sb);
+ return 0;
+ }
+ }
+
+ /*
+ * There is not enough space for user on the device
+ */
+ if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+ unlock_super (sb);
+ UFSD(("EXIT (FAILED)\n"))
+ return 0;
+ }
+
+ if (goal >= uspi->s_size)
+ goal = 0;
+ if (goal == 0)
+ cgno = ufs_inotocg (inode->i_ino);
+ else
+ cgno = ufs_dtog (goal);
+
+ /*
+ * allocate new fragment
+ */
+ if (oldcount == 0) {
+ result = ufs_alloc_fragments (inode, cgno, goal, count, err);
+ if (result) {
+ *p = SWAB32(result);
+ *err = 0;
+ inode->i_blocks += count << uspi->s_nspfshift;
+ inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+ NULLIFY_FRAGMENTS
+ }
+ unlock_super(sb);
+ UFSD(("EXIT, result %u\n", result))
+ return result;
+ }
+
+ /*
+ * resize block
+ */
+ result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
+ if (result) {
+ *err = 0;
+ inode->i_blocks += count << uspi->s_nspfshift;
+ inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+ NULLIFY_FRAGMENTS
+ unlock_super(sb);
+ UFSD(("EXIT, result %u\n", result))
+ return result;
+ }
+
+ /*
+ * allocate new block and move data
+ */
+ switch (SWAB32(usb1->fs_optim)) {
+ case UFS_OPTSPACE:
+ request = newcount;
+ if (uspi->s_minfree < 5 || SWAB32(usb1->fs_cstotal.cs_nffree)
+ > uspi->s_dsize * uspi->s_minfree / (2 * 100) )
+ break;
+ usb1->fs_optim = SWAB32(UFS_OPTTIME);
+ break;
+ default:
+ usb1->fs_optim = SWAB32(UFS_OPTTIME);
+
+ case UFS_OPTTIME:
+ request = uspi->s_fpb;
+ if (SWAB32(usb1->fs_cstotal.cs_nffree) < uspi->s_dsize *
+ (uspi->s_minfree - 2) / 100)
+ break;
+ usb1->fs_optim = SWAB32(UFS_OPTSPACE);
+ break;
+ }
+ result = ufs_alloc_fragments (inode, cgno, goal, request, err);
+ if (result) {
+ for (i = 0; i < oldcount; i++) {
+ bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
+ mark_buffer_clean (bh);
+ bh->b_blocknr = result + i;
+ mark_buffer_dirty (bh, 0);
+ if (IS_SYNC(inode)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+ }
+ *p = SWAB32(result);
+ *err = 0;
+ inode->i_blocks += count << uspi->s_nspfshift;
+ inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+ NULLIFY_FRAGMENTS
+ unlock_super(sb);
+ if (newcount < request)
+ ufs_free_fragments (inode, result + newcount, request - newcount);
+ ufs_free_fragments (inode, tmp, oldcount);
+ UFSD(("EXIT, result %u\n", result))
+ return result;
+ }
+
+ unlock_super(sb);
+ UFSD(("EXIT (FAILED)\n"))
+ return 0;
+}
+
+unsigned ufs_add_fragments (struct inode * inode, unsigned fragment,
+ unsigned oldcount, unsigned newcount, int * err)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned cgno, fragno, fragoff, count, fragsize, i;
+ unsigned swab;
+
+ UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first (USPI_UBH);
+ count = newcount - oldcount;
+
+ cgno = ufs_dtog(fragment);
+ if (sb->fs_cs(cgno).cs_nffree < count)
+ return 0;
+ if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
+ return 0;
+ ucpi = ufs_load_cylinder (sb, cgno);
+ if (!ucpi)
+ return 0;
+ ucg = ubh_get_ucg (UCPI_UBH);
+ if (!ufs_cg_chkmagic(ucg)) {
+ ufs_panic (sb, "ufs_add_fragments",
+ "internal error, bad magic number on cg %u", cgno);
+ return 0;
+ }
+
+ UFSDM
+
+ fragno = ufs_dtogd (fragment);
+ fragoff = ufs_fragnum (fragno);
+ for (i = oldcount; i < newcount; i++)
+ if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+ return 0;
+ /*
+ * Block can be extended
+ */
+ ucg->cg_time = SWAB32(CURRENT_TIME);
+ for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
+ if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+ break;
+ fragsize = i - oldcount;
+ if (!SWAB32(ucg->cg_frsum[fragsize]))
+ ufs_panic (sb, "ufs_add_fragments",
+ "internal error or corruted bitmap on cg %u", cgno);
+ DEC_SWAB32(ucg->cg_frsum[fragsize]);
+ if (fragsize != count)
+ INC_SWAB32(ucg->cg_frsum[fragsize - count]);
+ for (i = oldcount; i < newcount; i++)
+ ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
+ if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+ *err = -EDQUOT;
+ return 0;
+ }
+ SUB_SWAB32(ucg->cg_cs.cs_nffree, count);
+ SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+ SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+ usb1->fs_fmod = SWAB32(1);
+
+ UFSDM
+
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+ sb->s_dirt = 1;
+
+ UFSD(("EXIT, fragment %u\n", fragment))
+
+ return fragment;
+}
+
+#define UFS_TEST_FREE_SPACE_CG \
+ ucg = (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[cgno]->b_data; \
+ if (SWAB32(ucg->cg_cs.cs_nbfree)) \
+ goto cg_found; \
+ for (k = count; k < uspi->s_fpb; k++) \
+ if (SWAB32(ucg->cg_frsum[k])) \
+ goto cg_found;
+
+unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
+ unsigned goal, unsigned count, int * err)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned oldcg, i, j, k, result, allocsize;
+ unsigned swab;
+
+ UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+ oldcg = cgno;
+
+ /*
+ * 1. searching on preferred cylinder group
+ */
+ UFS_TEST_FREE_SPACE_CG
+
+ /*
+ * 2. quadratic rehash
+ */
+ for (j = 1; j < uspi->s_ncg; j *= 2) {
+ cgno += j;
+ if (cgno >= uspi->s_ncg)
+ cgno -= uspi->s_ncg;
+ UFS_TEST_FREE_SPACE_CG
+ }
+
+ /*
+ * 3. brute force search
+ * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
+ */
+ cgno = (oldcg + 1) % uspi->s_ncg;
+ for (j = 2; j < uspi->s_ncg; j++) {
+ cgno++;
+ if (cgno >= uspi->s_ncg)
+ cgno = 0;
+ UFS_TEST_FREE_SPACE_CG
+ }
+
+ UFSD(("EXIT (FAILED)\n"))
+ return 0;
+
+cg_found:
+ ucpi = ufs_load_cylinder (sb, cgno);
+ if (!ucpi)
+ return 0;
+ ucg = ubh_get_ucg (UCPI_UBH);
+ if (!ufs_cg_chkmagic(ucg))
+ ufs_panic (sb, "ufs_alloc_fragments",
+ "internal error, bad magic number on cg %u", cgno);
+ ucg->cg_time = SWAB32(CURRENT_TIME);
+
+ UFSDM
+
+ if (count == uspi->s_fpb) {
+ result = ufs_alloccg_block (inode, ucpi, goal, err);
+ if (result == (unsigned)-1)
+ return 0;
+ goto succed;
+ }
+
+ for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
+ if (SWAB32(ucg->cg_frsum[allocsize]) != 0)
+ break;
+
+ if (allocsize == uspi->s_fpb) {
+ result = ufs_alloccg_block (inode, ucpi, goal, err);
+ if (result == (unsigned)-1)
+ return 0;
+ goal = ufs_dtogd (result);
+ for (i = count; i < uspi->s_fpb; i++)
+ ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
+ i = uspi->s_fpb - count;
+ DQUOT_FREE_BLOCK(sb, inode, i);
+ ADD_SWAB32(ucg->cg_cs.cs_nffree, i);
+ ADD_SWAB32(usb1->fs_cstotal.cs_nffree, i);
+ ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, i);
+ INC_SWAB32(ucg->cg_frsum[i]);
+ goto succed;
+ }
+
+ result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
+ if (result == (unsigned)-1)
+ return 0;
+ if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+ *err = -EDQUOT;
+ return 0;
+ }
+ for (i = 0; i < count; i++)
+ ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i);
+ SUB_SWAB32(ucg->cg_cs.cs_nffree, count);
+ SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+ SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+ DEC_SWAB32(ucg->cg_frsum[allocsize]);
+ if (count != allocsize)
+ INC_SWAB32(ucg->cg_frsum[allocsize - count]);
+
+succed:
+ usb1->fs_fmod = SWAB32(1);
+
+ UFSDM
+
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+ sb->s_dirt = 1;
+
+ result += cgno * uspi->s_fpg;
+ UFSD(("EXIT3, result %u\n", result))
+ return result;
+}
+
+unsigned ufs_alloccg_block (struct inode * inode,
+ struct ufs_cg_private_info * ucpi, unsigned goal, int * err)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cylinder_group * ucg;
+ unsigned result, cylno, blkno;
+ unsigned swab;
+
+ UFSD(("ENTER, goal %u\n", goal))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH);
+
+ if (goal == 0) {
+ goal = ucpi->c_rotor;
+ goto norot;
+ }
+ goal = ufs_blknum (goal);
+ goal = ufs_dtogd (goal);
+
+ /*
+ * If the requested block is available, use it.
+ */
+ if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+ result = goal;
+ goto gotit;
+ }
+
+ /*** This function should be optimalized later ***/
+
+norot:
+ result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
+ if (result == (unsigned)-1)
+ return (unsigned)-1;
+ ucpi->c_rotor = result;
+gotit:
+ blkno = ufs_fragstoblks(result);
+ ubh_clrblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+ if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) {
+ *err = -EDQUOT;
+ return (unsigned)-1;
+ }
+ DEC_SWAB32(ucg->cg_cs.cs_nbfree);
+ DEC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+ DEC_SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree);
+ cylno = ufs_cbtocylno(result);
+ DEC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)));
+ DEC_SWAB32(ubh_cg_blktot(ucpi, cylno));
+ usb1->fs_fmod = 1;
+
+ UFSD(("EXIT, result %u\n", result))
+
+ return result;
+}
+
+unsigned ufs_bitmap_search (struct super_block * sb,
+ struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cylinder_group * ucg;
+ unsigned start, length, length2, location, result;
+ unsigned possition, fragsize, blockmap, mask;
+ unsigned swab;
+
+ UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
+
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first (USPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH);
+
+ if (goal)
+ start = ufs_dtogd(goal) >> 3;
+ else
+ start = ucpi->c_frotor >> 3;
+
+ length = howmany(uspi->s_fpg, 8) - start;
+ location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
+ (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
+ 1 << (count - 1 + (uspi->s_fpb & 7)));
+ if (location == 0) {
+ length2 = start + 1;
+ location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length2,
+ (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
+ 1 << (count - 1 + (uspi->s_fpb & 7)));
+ if (location == 0) {
+ ufs_error (sb, "ufs_bitmap_search",
+ "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n",
+ ucpi->c_cgx, start, length, count, ucpi->c_freeoff);
+ return (unsigned)-1;
+ }
+ start = 0;
+ length = length2;
+ }
+ result = (start + length - location) << 3;
+ ucpi->c_frotor = result;
+
+ /*
+ * found the byte in the map
+ */
+ blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result);
+ fragsize = 0;
+ for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) {
+ if (blockmap & mask) {
+ if (!(possition & uspi->s_fpbmask))
+ fragsize = 1;
+ else
+ fragsize++;
+ }
+ else {
+ if (fragsize == count) {
+ result += possition - count;
+ UFSD(("EXIT, result %u\n", result))
+ return result;
+ }
+ fragsize = 0;
+ }
+ }
+ if (fragsize == count) {
+ result += possition - count;
+ UFSD(("EXIT, result %u\n", result))
+ return result;
+ }
+ ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
+ UFSD(("EXIT (FAILED)\n"))
+ return (unsigned)-1;
+}
+
+static unsigned char ufs_fragtable_8fpb[] = {
+ 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+ 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+ 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+ 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
+ 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
+ 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
+};
+
+static unsigned char ufs_fragtable_other[] = {
+ 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
+ 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+ 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
+ 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
+ 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
+ 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
+ 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
+};
diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
new file mode 100644
index 000000000..a822438b6
--- /dev/null
+++ b/fs/ufs/cylinder.c
@@ -0,0 +1,212 @@
+/*
+ * linux/fs/ufs/cylinder.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * ext2 - inode (block) bitmap caching inspired
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_CYLINDER_DEBUG
+#undef UFS_CYLINDER_DEBUG_MORE
+
+#ifdef UFS_CYLINDER_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+/*
+ * Read cylinder group into cache. The memory space for ufs_cg_private_info
+ * structure is already allocated during ufs_read_super.
+ */
+static void ufs_read_cylinder (struct super_block * sb,
+ unsigned cgno, unsigned bitmap_nr)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned i, j;
+ unsigned swab;
+
+ UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
+ ucg = (struct ufs_cylinder_group *)sb->u.ufs_sb.s_ucg[cgno]->b_data;
+
+#ifdef UFS_CYLINDER_DEBUG_MORE
+ ufs_print_cylinder_stuff (ucg, swab);
+#endif
+
+ UCPI_UBH->fragment = ufs_cgcmin(cgno);
+ UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
+ /*
+ * We have already the first fragment of cylinder group block in buffer
+ */
+ UCPI_UBH->bh[0] = sb->u.ufs_sb.s_ucg[cgno];
+ for (i = 1; i < UCPI_UBH->count; i++)
+ if (!(UCPI_UBH->bh[i] = bread (sb->s_dev, UCPI_UBH->fragment + i, sb->s_blocksize)))
+ goto failed;
+ sb->u.ufs_sb.s_cgno[bitmap_nr] = cgno;
+
+ ucpi->c_cgx = SWAB32(ucg->cg_cgx);
+ ucpi->c_ncyl = SWAB16(ucg->cg_ncyl);
+ ucpi->c_niblk = SWAB16(ucg->cg_niblk);
+ ucpi->c_ndblk = SWAB32(ucg->cg_ndblk);
+ ucpi->c_rotor = SWAB32(ucg->cg_rotor);
+ ucpi->c_frotor = SWAB32(ucg->cg_frotor);
+ ucpi->c_irotor = SWAB32(ucg->cg_irotor);
+ ucpi->c_btotoff = SWAB32(ucg->cg_btotoff);
+ ucpi->c_boff = SWAB32(ucg->cg_boff);
+ ucpi->c_iusedoff = SWAB32(ucg->cg_iusedoff);
+ ucpi->c_freeoff = SWAB32(ucg->cg_freeoff);
+ ucpi->c_nextfreeoff = SWAB32(ucg->cg_nextfreeoff);
+
+ UFSD(("EXIT\n"))
+ return;
+
+failed:
+ for (j = 1; j < i; j++)
+ brelse (sb->u.ufs_sb.s_ucg[j]);
+ sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+ ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno);
+}
+
+/*
+ * Remove cylinder group from cache, does'n release memory
+ * allocated for cylinder group (this is done at ufs_put_super only).
+ */
+void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ unsigned i;
+ unsigned swab;
+
+ UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
+
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ if (sb->u.ufs_sb.s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
+ UFSD(("EXIT\n"))
+ return;
+ }
+ ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
+ ucg = ubh_get_ucg(UCPI_UBH);
+
+ if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sb->u.ufs_sb.s_cg_loaded) {
+ ufs_panic (sb, "ufs_put_cylinder", "internal error");
+ return;
+ }
+ /*
+ * rotor is not so important data, so we put it to disk
+ * at the end of working with cylinder
+ */
+ ucg->cg_rotor = SWAB32(ucpi->c_rotor);
+ ucg->cg_frotor = SWAB32(ucpi->c_frotor);
+ ucg->cg_irotor = SWAB32(ucpi->c_irotor);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ for (i = 1; i < UCPI_UBH->count; i++) {
+ brelse (UCPI_UBH->bh[i]);
+ }
+
+ sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+ UFSD(("EXIT\n"))
+}
+
+/*
+ * Find cylinder group in cache and return it as pointer.
+ * If cylinder group is not in cache, we will load it from disk.
+ *
+ * The cache is managed by LRU alghoritm.
+ */
+struct ufs_cg_private_info * ufs_load_cylinder (
+ struct super_block * sb, unsigned cgno)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_cg_private_info * ucpi;
+ unsigned cg, i, j;
+
+ UFSD(("ENTER, cgno %u\n", cgno))
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ if (cgno >= uspi->s_ncg) {
+ ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg");
+ return NULL;
+ }
+ /*
+ * Cylinder group number cg it in cache and it was last used
+ */
+ if (sb->u.ufs_sb.s_cgno[0] == cgno) {
+ UFSD(("EXIT\n"))
+ return sb->u.ufs_sb.s_ucpi[0];
+ }
+ /*
+ * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED
+ */
+ if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) {
+ if (sb->u.ufs_sb.s_cgno[cgno] != UFS_CGNO_EMPTY) {
+ if (sb->u.ufs_sb.s_cgno[cgno] != cgno) {
+ ufs_panic (sb, "ufs_load_cylinder", "internal error, wrog number of cg in cache");
+ UFSD(("EXIT (FAILED)\n"))
+ return NULL;
+ }
+ else {
+ UFSD(("EXIT\n"))
+ return sb->u.ufs_sb.s_ucpi[cgno];
+ }
+ } else {
+ ufs_read_cylinder (sb, cgno, cgno);
+ UFSD(("EXIT\n"))
+ return sb->u.ufs_sb.s_ucpi[cgno];
+ }
+ }
+ /*
+ * Cylinder group number cg is in cache but it was not last used,
+ * we will move to the first position
+ */
+ for (i = 0; i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] != cgno; i++);
+ if (i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] == cgno) {
+ cg = sb->u.ufs_sb.s_cgno[i];
+ ucpi = sb->u.ufs_sb.s_ucpi[i];
+ for (j = i; j > 0; j--) {
+ sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
+ sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+ }
+ sb->u.ufs_sb.s_cgno[0] = cg;
+ sb->u.ufs_sb.s_ucpi[0] = ucpi;
+ /*
+ * Cylinder group number cg is not in cache, we will read it from disk
+ * and put it to the first possition
+ */
+ } else {
+ if (sb->u.ufs_sb.s_cg_loaded < UFS_MAX_GROUP_LOADED)
+ sb->u.ufs_sb.s_cg_loaded++;
+ else
+ ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1);
+ for (j = sb->u.ufs_sb.s_cg_loaded - 1; j > 0; j--) {
+ sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
+ sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+ }
+ ufs_read_cylinder (sb, cgno, 0);
+ }
+ UFSD(("EXIT\n"))
+ return sb->u.ufs_sb.s_ucpi[0];
+}
diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/dir.c
index e6d27c217..ee0e85674 100644
--- a/fs/ufs/ufs_dir.c
+++ b/fs/ufs/dir.c
@@ -11,11 +11,22 @@
* 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>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
*/
#include <linux/fs.h>
-#include "ufs_swab.h"
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_DIR_DEBUG
+
+#ifdef UFS_DIR_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
/*
* This is blatantly stolen from ext2fs
@@ -28,10 +39,11 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
unsigned long offset, lblk, blk;
int i, stored;
struct buffer_head * bh;
- struct ufs_direct * de;
+ struct ufs_dir_entry * de;
struct super_block * sb;
int de_reclen;
- __u32 flags;
+ unsigned flags, swab;
+
/* Isn't that already done in the upper layer???
* the VFS layer really needs some explicit documentation!
@@ -40,13 +52,10 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
return -EBADF;
sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
flags = sb->u.ufs_sb.s_flags;
- 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);
- }
+ UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
stored = 0;
bh = NULL;
@@ -73,8 +82,7 @@ revalidate:
* to make sure. */
if (filp->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ufs_direct *)
- (bh->b_data + i);
+ de = (struct ufs_dir_entry *)(bh->b_data + i);
/* It's too expensive to do a full
* dirent test each time round this
* loop, but we do have to test at
@@ -94,9 +102,9 @@ revalidate:
while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
- de = (struct ufs_direct *) (bh->b_data + offset);
+ de = (struct ufs_dir_entry *) (bh->b_data + offset);
/* XXX - put in a real ufs_check_dir_entry() */
- if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) {
+ if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
/* SWAB16() was unneeded -- compare to 0 */
filp->f_pos = (filp->f_pos &
(sb->s_blocksize - 1)) +
@@ -128,11 +136,9 @@ revalidate:
* during the copy operation. */
unsigned long version = inode->i_version;
- if (flags & UFS_DEBUG) {
- printk("ufs_readdir: filldir(%s,%u)\n",
- de->d_name, SWAB32(de->d_ino));
- }
- error = filldir(dirent, de->d_name, NAMLEN(de),
+ UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
+ UFSD(("namlen %u\n", ufs_namlen(de)))
+ error = filldir(dirent, de->d_name, ufs_namlen(de),
filp->f_pos, SWAB32(de->d_ino));
if (error)
break;
@@ -145,15 +151,45 @@ revalidate:
offset = 0;
brelse (bh);
}
-#if 0 /* XXX */
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
-#endif /* XXX */
+ UPDATE_ATIME(inode);
return 0;
}
+int ufs_check_dir_entry (const char * function, struct inode * dir,
+ struct ufs_dir_entry * de, struct buffer_head * bh,
+ unsigned long offset)
+{
+ struct super_block * sb;
+ const char * error_msg;
+ unsigned flags, swab;
+
+ sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+ error_msg = NULL;
+
+ if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
+ error_msg = "reclen is smaller than minimal";
+ else if (SWAB16(de->d_reclen) % 4 != 0)
+ error_msg = "reclen % 4 != 0";
+ else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de)))
+ error_msg = "reclen is too small for namlen";
+ else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
+ dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+ else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
+ error_msg = "inode out of bounds";
+
+ if (error_msg != NULL)
+ ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
+ "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
+ dir->i_ino, dir->i_size, error_msg, offset,
+ (unsigned long) SWAB32(de->d_ino),
+ SWAB16(de->d_reclen), ufs_namlen(de));
+
+ return (error_msg == NULL ? 1 : 0);
+}
+
static struct file_operations ufs_dir_operations = {
NULL, /* lseek */
NULL, /* read */
@@ -172,20 +208,21 @@ static struct file_operations ufs_dir_operations = {
struct inode_operations ufs_dir_inode_operations = {
&ufs_dir_operations, /* default directory file operations */
- NULL, /* create */
+ ufs_create, /* create */
ufs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
+ ufs_link, /* link */
+ ufs_unlink, /* unlink */
+ ufs_symlink, /* symlink */
+ ufs_mkdir, /* mkdir */
+ ufs_rmdir, /* rmdir */
+ ufs_mknod, /* mknod */
+ ufs_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
+ ufs_bmap, /* bmap */
+ ufs_truncate, /* truncate */
+ ufs_permission, /* permission */
NULL, /* smap */
};
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
new file mode 100644
index 000000000..a6fa50377
--- /dev/null
+++ b/fs/ufs/file.c
@@ -0,0 +1,281 @@
+/*
+ * linux/fs/ufs/file.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/file.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/file.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext2 fs regular file handling primitives
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#define NBUF 32
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+
+static long long ufs_file_lseek(struct file *, long long, int);
+static ssize_t ufs_file_write (struct file *, const char *, size_t, loff_t *);
+static int ufs_release_file (struct inode *, struct file *);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the ufs filesystem.
+ */
+static struct file_operations ufs_file_operations = {
+ ufs_file_lseek, /* lseek */
+ generic_file_read, /* read */
+ ufs_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* poll - default */
+ NULL, /* ioctl */
+ generic_file_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ ufs_release_file, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
+};
+
+struct inode_operations ufs_file_inode_operations = {
+ &ufs_file_operations,/* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ generic_readpage, /* readpage */
+ NULL, /* writepage */
+ ufs_bmap, /* bmap */
+ ufs_truncate, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+/*
+ * Make sure the offset never goes beyond the 32-bit mark..
+ */
+static long long ufs_file_lseek(
+ struct file *file,
+ long long offset,
+ int origin )
+{
+ long long retval;
+ struct inode *inode = file->f_dentry->d_inode;
+
+ switch (origin) {
+ case 2:
+ offset += inode->i_size;
+ break;
+ case 1:
+ offset += file->f_pos;
+ }
+ retval = -EINVAL;
+ /* make sure the offset fits in 32 bits */
+ if (((unsigned long long) offset >> 32) == 0) {
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_reada = 0;
+ file->f_version = ++event;
+ }
+ retval = offset;
+ }
+ return retval;
+}
+
+static inline void remove_suid(struct inode *inode)
+{
+ unsigned int mode;
+
+ /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
+ mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
+
+ /* was any of the uid bits set? */
+ mode &= inode->i_mode;
+ if (mode && !suser()) {
+ inode->i_mode &= ~mode;
+ mark_inode_dirty(inode);
+ }
+}
+
+static ssize_t ufs_file_write (
+ struct file * filp,
+ const char * buf,
+ size_t count,
+ loff_t *ppos )
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ __u32 pos;
+ long block;
+ int offset;
+ int written, c;
+ struct buffer_head * bh, *bufferlist[NBUF];
+ struct super_block * sb;
+ int err;
+ int i,buffercount,write_error;
+
+ /* POSIX: mtime/ctime may not change for 0 count */
+ if (!count)
+ return 0;
+ write_error = buffercount = 0;
+ if (!inode)
+ return -EINVAL;
+ sb = inode->i_sb;
+ if (sb->s_flags & MS_RDONLY)
+ /*
+ * This fs has been automatically remounted ro because of errors
+ */
+ return -ENOSPC;
+
+ if (!S_ISREG(inode->i_mode)) {
+ ufs_warning (sb, "ufs_file_write", "mode = %07o",
+ inode->i_mode);
+ return -EINVAL;
+ }
+ remove_suid(inode);
+
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else {
+ pos = *ppos;
+ if (pos != *ppos)
+ return -EINVAL;
+ }
+
+ /* Check for overflow.. */
+ if (pos > (__u32) (pos + count)) {
+ count = ~pos; /* == 0xFFFFFFFF - pos */
+ if (!count)
+ return -EFBIG;
+ }
+
+ /*
+ * If a file has been opened in synchronous mode, we have to ensure
+ * that meta-data will also be written synchronously. Thus, we
+ * set the i_osync field. This field is tested by the allocation
+ * routines.
+ */
+ if (filp->f_flags & O_SYNC)
+ inode->u.ufs_i.i_osync++;
+ block = pos >> sb->s_blocksize_bits;
+ offset = pos & (sb->s_blocksize - 1);
+ c = sb->s_blocksize - offset;
+ written = 0;
+ do {
+ bh = ufs_getfrag (inode, block, 1, &err);
+ if (!bh) {
+ if (!written)
+ written = err;
+ break;
+ }
+ if (c > count)
+ c = count;
+ if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer (bh);
+ if (!buffer_uptodate(bh)) {
+ brelse (bh);
+ if (!written)
+ written = -EIO;
+ break;
+ }
+ }
+ c -= copy_from_user (bh->b_data + offset, buf, c);
+ if (!c) {
+ brelse(bh);
+ if (!written)
+ written = -EFAULT;
+ break;
+ }
+ update_vm_cache(inode, pos, bh->b_data + offset, c);
+ pos += c;
+ written += c;
+ buf += c;
+ count -= c;
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 0);
+ if (filp->f_flags & O_SYNC)
+ bufferlist[buffercount++] = bh;
+ else
+ brelse(bh);
+ if (buffercount == NBUF){
+ ll_rw_block(WRITE, buffercount, bufferlist);
+ for(i=0; i<buffercount; i++){
+ wait_on_buffer(bufferlist[i]);
+ if (!buffer_uptodate(bufferlist[i]))
+ write_error=1;
+ brelse(bufferlist[i]);
+ }
+ buffercount=0;
+ }
+ if (write_error)
+ break;
+ block++;
+ offset = 0;
+ c = sb->s_blocksize;
+ } while (count);
+ if (buffercount){
+ ll_rw_block(WRITE, buffercount, bufferlist);
+ for (i=0; i<buffercount; i++){
+ wait_on_buffer(bufferlist[i]);
+ if (!buffer_uptodate(bufferlist[i]))
+ write_error=1;
+ brelse(bufferlist[i]);
+ }
+ }
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ if (filp->f_flags & O_SYNC)
+ inode->u.ufs_i.i_osync--;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ *ppos = pos;
+ mark_inode_dirty(inode);
+ return written;
+}
+
+/*
+ * Called when an inode is released. Note that this is different
+ * from ufs_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+static int ufs_release_file (struct inode * inode, struct file * filp)
+{
+ return 0;
+}
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
new file mode 100644
index 000000000..6da43f20a
--- /dev/null
+++ b/fs/ufs/ialloc.c
@@ -0,0 +1,341 @@
+/*
+ * linux/fs/ufs/ialloc.c
+ *
+ * Copyright (c) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/ialloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * BSD ufs-inspired inode and directory allocation by
+ * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_IALLOC_DEBUG
+#undef UFS_IALLOC_DEBUG_MORE
+
+#ifdef UFS_IALLOC_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_IALLOC_DEBUG_MORE
+#define UFSDM \
+ufs_print_cylinder_stuff (ucg, swab); \
+printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
+printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
+printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
+printk("ndir: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_ndir), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
+#else
+#define UFSDM
+#endif
+
+
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
+void ufs_free_inode (struct inode * inode)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ int is_directory;
+ unsigned ino, cg, bit;
+ unsigned swab;
+
+ UFSD(("ENTER, ino %lu\n", inode->i_ino))
+
+ if (!inode)
+ return;
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ if (inode->i_count > 1) {
+ ufs_warning(sb, "ufs_free_inode", "inode has count=%d\n", inode->i_count);
+ return;
+ }
+ if (inode->i_nlink) {
+ ufs_warning(sb, "ufs_free_inode", "inode has nlink=%d\n", inode->i_nlink);
+ return;
+ }
+
+ ino = inode->i_ino;
+
+ lock_super (sb);
+
+ if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) {
+ ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino);
+ unlock_super (sb);
+ return;
+ }
+
+ cg = ufs_inotocg (ino);
+ bit = ufs_inotocgoff (ino);
+ ucpi = ufs_load_cylinder (sb, cg);
+ if (!ucpi) {
+ unlock_super (sb);
+ return;
+ }
+ ucg = ubh_get_ucg(UCPI_UBH);
+ if (!ufs_cg_chkmagic(ucg))
+ ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
+
+ UFSDM
+
+ ucg->cg_time = SWAB32(CURRENT_TIME);
+
+ is_directory = S_ISDIR(inode->i_mode);
+
+ DQUOT_FREE_INODE(sb, inode);
+
+ clear_inode (inode);
+
+ if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+ ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino);
+ else {
+ ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+ if (ino < ucpi->c_irotor)
+ ucpi->c_irotor = ino;
+ INC_SWAB32(ucg->cg_cs.cs_nifree);
+ INC_SWAB32(usb1->fs_cstotal.cs_nifree);
+ INC_SWAB32(sb->fs_cs(cg).cs_nifree);
+
+ if (is_directory) {
+ DEC_SWAB32(ucg->cg_cs.cs_ndir);
+ DEC_SWAB32(usb1->fs_cstotal.cs_ndir);
+ DEC_SWAB32(sb->fs_cs(cg).cs_ndir);
+ }
+ }
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+
+ UFSDM
+
+ sb->s_dirt = 1;
+ unlock_super (sb);
+ UFSD(("EXIT\n"))
+}
+
+/*
+ * There are two policies for allocating an inode. If the new inode is
+ * a directory, then a forward search is made for a block group with both
+ * free space and a low directory-to-inode ratio; if that fails, then of
+ * the groups with above-average free space, that group with the fewest
+ * directories already is chosen.
+ *
+ * For other inodes, search forward from the parent directory\'s block
+ * group to find a free inode.
+ */
+struct inode * ufs_new_inode (const struct inode * dir, int mode, int * err )
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_cg_private_info * ucpi;
+ struct ufs_cylinder_group * ucg;
+ struct inode * inode;
+ unsigned cg, bit, i, j, start;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ /* Cannot create files in a deleted directory */
+ if (!dir || !dir->i_nlink) {
+ *err = -EPERM;
+ return NULL;
+ }
+ inode = get_empty_inode ();
+ if (!inode) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ inode->i_sb = sb;
+ inode->i_flags = sb->s_flags;
+
+ lock_super (sb);
+
+ *err = -ENOSPC;
+
+ /*
+ * Try to place the inode in its parent directory
+ */
+ i = ufs_inotocg(dir->i_ino);
+ if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+ cg = i;
+ goto cg_found;
+ }
+
+ /*
+ * Use a quadratic hash to find a group with a free inode
+ */
+ for ( j = 1; j < uspi->s_ncg; j <<= 1 ) {
+ i += j;
+ if (i >= uspi->s_ncg)
+ i -= uspi->s_ncg;
+ if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+ cg = i;
+ goto cg_found;
+ }
+ }
+
+ /*
+ * That failed: try linear search for a free inode
+ */
+ i = ufs_inotocg(dir->i_ino) + 1;
+ for (j = 2; j < uspi->s_ncg; j++) {
+ i++;
+ if (i >= uspi->s_ncg)
+ i = 0;
+ if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+ cg = i;
+ goto cg_found;
+ }
+ }
+
+ goto failed;
+
+cg_found:
+ ucpi = ufs_load_cylinder (sb, cg);
+ if (!ucpi)
+ goto failed;
+ ucg = ubh_get_ucg(UCPI_UBH);
+ if (!ufs_cg_chkmagic(ucg))
+ ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
+
+ UFSDM
+
+ start = ucpi->c_irotor;
+ bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
+ if (!(bit < uspi->s_ipg)) {
+ bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start);
+ if (!(bit < start)) {
+ ufs_error (sb, "ufs_new_inode",
+ "cylinder group %u corrupted - error in inode bitmap\n", cg);
+ goto failed;
+ }
+ }
+ UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg))
+ if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+ ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+ else {
+ ufs_panic (sb, "ufs_new_inode", "internal error");
+ goto failed;
+ }
+
+ DEC_SWAB32(ucg->cg_cs.cs_nifree);
+ DEC_SWAB32(usb1->fs_cstotal.cs_nifree);
+ DEC_SWAB32(sb->fs_cs(cg).cs_nifree);
+
+ if (S_ISDIR(mode)) {
+ INC_SWAB32(ucg->cg_cs.cs_ndir);
+ INC_SWAB32(usb1->fs_cstotal.cs_ndir);
+ INC_SWAB32(sb->fs_cs(cg).cs_ndir);
+ }
+
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+ ubh_wait_on_buffer (UCPI_UBH);
+ }
+ sb->s_dirt = 1;
+
+ inode->i_mode = mode;
+ inode->i_sb = sb;
+ inode->i_nlink = 1;
+ inode->i_dev = sb->s_dev;
+ inode->i_uid = current->fsuid;
+ if (test_opt (sb, GRPID))
+ inode->i_gid = dir->i_gid;
+ else if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ } else
+ inode->i_gid = current->fsgid;
+
+ inode->i_ino = cg * uspi->s_ipg + bit;
+ inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
+ inode->u.ufs_i.i_uid = inode->i_uid;
+ inode->u.ufs_i.i_gid = inode->i_gid;
+ inode->u.ufs_i.i_lastfrag = 0;
+ inode->i_op = NULL;
+
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+
+ UFSDM
+
+ unlock_super (sb);
+
+ if(DQUOT_ALLOC_INODE(sb, inode)) {
+ sb->dq_op->drop(inode);
+ inode->i_nlink = 0;
+ iput(inode);
+ *err = -EDQUOT;
+ return NULL;
+ }
+
+ UFSD(("allocating inode %lu\n", inode->i_ino))
+ *err = 0;
+ UFSD(("EXIT\n"))
+ return inode;
+
+failed:
+ unlock_super (sb);
+ iput (inode);
+ UFSD(("EXIT (FAILED)\n"))
+ return NULL;
+}
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
new file mode 100644
index 000000000..123a76a75
--- /dev/null
+++ b/fs/ufs/inode.c
@@ -0,0 +1,665 @@
+/*
+ * linux/ufs/ufs/inode.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/inode.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_INODE_DEBUG
+#undef UFS_INODE_DEBUG_MORE
+
+#ifdef UFS_INODE_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_INODE_DEBUG_MORE
+static void ufs_print_inode(struct inode * inode)
+{
+ unsigned swab = inode->i_sb->u.ufs_sb.s_swab;
+ printk("ino %lu mode 0%6.6o nlink %d uid %d gid %d"
+ " size %lu blocks %lu\n",
+ inode->i_ino, inode->i_mode, inode->i_nlink,
+ inode->i_uid,inode->i_gid, inode->i_size, inode->i_blocks);
+ printk(" db <%u %u %u %u %u %u %u %u %u %u %u %u>\n",
+ SWAB32(inode->u.ufs_i.i_u1.i_data[0]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[1]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[2]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[3]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[4]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[5]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[6]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[7]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[8]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[9]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[10]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[11]));
+ printk(" gen %u ib <%u %u %u>\n",
+ inode->u.ufs_i.i_gen,
+ SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]),
+ SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]));
+}
+#endif
+
+#define ufs_inode_bmap(inode, nr) \
+ (SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
+
+static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr,
+ struct ufs_sb_private_info * uspi, unsigned swab)
+{
+ unsigned tmp;
+
+ UFSD(("ENTER, nr %u\n", nr))
+ if (!bh)
+ return 0;
+ tmp = SWAB32(((u32 *) bh->b_data)[nr >> uspi->s_fpbshift]) + (nr & uspi->s_fpbmask);
+ brelse (bh);
+ UFSD(("EXIT, resutl %u\n", tmp))
+ return tmp;
+}
+
+int ufs_bmap (struct inode * inode, int fragment)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ unsigned tmp;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+
+ UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+
+ if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
+ ufs_warning (sb, "ufs_bmap", "block > big");
+ return 0;
+ }
+
+ /*
+ * direct fragment
+ */
+ if (fragment < UFS_NDIR_FRAGMENT)
+ return ufs_inode_bmap (inode, fragment);
+
+ /*
+ * indirect fragment
+ */
+ fragment -= UFS_NDIR_FRAGMENT;
+ if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ tmp = ufs_inode_bmap (inode,
+ UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
+ if (!tmp)
+ return 0;
+ return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab);
+ }
+
+ /*
+ * dindirect fragment
+ */
+ fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ tmp = ufs_inode_bmap (inode,
+ UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
+ if (!tmp)
+ return 0;
+ tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
+ if (!tmp)
+ return 0;
+ return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab);
+ }
+
+ /*
+ * tindirect fragment
+ */
+ fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ tmp = ufs_inode_bmap (inode,
+ UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
+ if (!tmp)
+ return 0;
+ tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ (fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
+ if (!tmp)
+ return 0;
+ tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
+ if (!tmp)
+ return 0;
+ return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab);
+}
+
+static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
+ unsigned fragment, unsigned new_fragment, int create,
+ unsigned required, int * err )
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * result;
+ unsigned long limit;
+ unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
+ unsigned tmp, goal;
+ u32 * p, * p2;
+ unsigned swab;
+
+ UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
+ inode->i_ino, fragment, new_fragment, required))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ block = ufs_fragstoblks (fragment);
+ blockoff = ufs_fragnum (fragment);
+ p = inode->u.ufs_i.i_u1.i_data + block;
+ goal = 0;
+
+repeat:
+ tmp = SWAB32(*p);
+ lastfrag = inode->u.ufs_i.i_lastfrag;
+ if (tmp && fragment < lastfrag) {
+ result = getblk (sb->s_dev, tmp + blockoff, sb->s_blocksize);
+ if (tmp == SWAB32(*p)) {
+ UFSD(("EXIT, result %u\n", tmp + blockoff))
+ return result;
+ }
+ brelse (result);
+ goto repeat;
+ }
+ *err = -EFBIG;
+ if (!create)
+ return NULL;
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= sb->s_blocksize_bits;
+ if (new_fragment >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ return NULL;
+ }
+ }
+ lastblock = ufs_fragstoblks (lastfrag);
+ lastblockoff = ufs_fragnum (lastfrag);
+ /*
+ * We will extend file into new block beyond last allocated block
+ */
+ if (lastblock < block) {
+ /*
+ * We must reallocate last allocated block
+ */
+ if (lastblockoff) {
+ p2 = inode->u.ufs_i.i_u1.i_data + lastblock;
+ tmp = ufs_new_fragments (inode, p2, lastfrag,
+ SWAB32(*p2), uspi->s_fpb - lastblockoff, err);
+ if (!tmp) {
+ if (lastfrag != inode->u.ufs_i.i_lastfrag)
+ goto repeat;
+ else
+ return NULL;
+ }
+ lastfrag = inode->u.ufs_i.i_lastfrag;
+
+ }
+ goal = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock]) + uspi->s_fpb;
+ tmp = ufs_new_fragments (inode, p, fragment - blockoff,
+ goal, required + blockoff, err);
+ }
+ /*
+ * We will extend last allocated block
+ */
+ else if (lastblock == block) {
+ tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
+ SWAB32(*p), required + (blockoff - lastblockoff), err);
+ }
+ /*
+ * We will allocated new block before last allocat block
+ */
+ else /* (lastblock > block) */ {
+ if (lastblock && (tmp = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock-1])))
+ goal = tmp + uspi->s_fpb;
+ tmp = ufs_new_fragments (inode, p, fragment - blockoff,
+ goal, uspi->s_fpb, err);
+ }
+ if (!tmp) {
+ if ((!blockoff && SWAB32(*p)) ||
+ (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+ goto repeat;
+ else
+ return NULL;
+ }
+ result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
+ inode->i_ctime = CURRENT_TIME;
+ if (IS_SYNC(inode))
+ ufs_sync_inode (inode);
+ mark_inode_dirty(inode);
+ UFSD(("EXIT, result %u\n", tmp + blockoff))
+ return result;
+}
+
+static struct buffer_head * ufs_block_getfrag (struct inode * inode,
+ struct buffer_head * bh, unsigned fragment, unsigned new_fragment,
+ int create, unsigned blocksize, int * err)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * result;
+ unsigned tmp, goal, block, blockoff;
+ u32 * p;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ block = ufs_fragstoblks (fragment);
+ blockoff = ufs_fragnum (fragment);
+
+ UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))
+
+ if (!bh)
+ return NULL;
+ if (!buffer_uptodate(bh)) {
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer (bh);
+ if (!buffer_uptodate(bh)) {
+ brelse (bh);
+ return NULL;
+ }
+ }
+
+ p = (u32 *) bh->b_data + block;
+repeat:
+ tmp = SWAB32(*p);
+ if (tmp) {
+ result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+ if (tmp == SWAB32(*p)) {
+ brelse (bh);
+ UFSD(("EXIT, result %u\n", tmp + blockoff))
+ return result;
+ }
+ brelse (result);
+ goto repeat;
+ }
+ if (!create || new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize)) {
+ brelse (bh);
+ *err = -EFBIG;
+ return NULL;
+ }
+ if (block && (tmp = SWAB32(((u32*)bh->b_data)[block-1]) + uspi->s_fpb))
+ goal = tmp + uspi->s_fpb;
+ else
+ goal = bh->b_blocknr + uspi->s_fpb;
+ tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+ if (!tmp) {
+ if (SWAB32(*p)) {
+ printk("REPEAT\n");
+ goto repeat;
+ }
+ else {
+ return NULL;
+ }
+ }
+ result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(inode)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ brelse (bh);
+ UFSD(("EXIT, resutl %u\n", tmp + blockoff))
+ return result;
+}
+
+struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
+ int create, int * err)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * bh;
+ unsigned f;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+ *err = -EIO;
+
+ UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+ if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
+ ufs_warning (sb, "ufs_getblk", "block > big");
+ return NULL;
+ }
+
+ *err = -ENOSPC;
+ f = fragment;
+
+ /*
+ * Direct fragment
+ */
+ if (fragment < UFS_NDIR_FRAGMENT)
+ return ufs_inode_getfrag (inode, fragment, fragment, create, 1, err);
+ /*
+ * Indirect fragment
+ */
+ fragment -= UFS_NDIR_FRAGMENT;
+ if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ bh = ufs_inode_getfrag (inode,
+ UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
+ f, create, uspi->s_fpb, err);
+ return ufs_block_getfrag (inode, bh,
+ fragment & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+ }
+ /*
+ * Dindirect fragment
+ */
+ fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ bh = ufs_inode_getfrag (inode,
+ UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
+ f, create, uspi->s_fpb, err);
+ bh = ufs_block_getfrag (inode, bh,
+ (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+ return ufs_block_getfrag (inode, bh,
+ fragment & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+ }
+ /*
+ * Tindirect fragment
+ */
+ fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ bh = ufs_inode_getfrag (inode,
+ UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift),
+ f, create, uspi->s_fpb, err);
+ bh = ufs_block_getfrag (inode, bh,
+ (fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+ bh = ufs_block_getfrag (inode, bh,
+ (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+ return ufs_block_getfrag (inode, bh,
+ fragment & uspi->s_apbmask,
+ f, create, sb->s_blocksize, err);
+}
+
+
+
+struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
+ int create, int * err)
+{
+ struct buffer_head * bh;
+
+ UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+ bh = ufs_getfrag (inode, fragment, create, err);
+ if (!bh || buffer_uptodate(bh))
+ return bh;
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer (bh);
+ if (buffer_uptodate(bh))
+ return bh;
+ brelse (bh);
+ *err = -EIO;
+ return NULL;
+}
+
+void ufs_read_inode (struct inode * inode)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_inode * ufs_inode;
+ struct buffer_head * bh;
+ unsigned i;
+ unsigned flags, swab;
+
+ UFSD(("ENTER, ino %lu\n", inode->i_ino))
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (inode->i_ino < UFS_ROOTINO ||
+ inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+ ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
+ return;
+ }
+
+ bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+ if (!bh) {
+ ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
+ return;
+ }
+ ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
+
+ /*
+ * Copy data to the in-core inode.
+ */
+ inode->i_mode = SWAB16(ufs_inode->ui_mode);
+ inode->i_nlink = SWAB16(ufs_inode->ui_nlink);
+ if (inode->i_nlink == 0)
+ ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
+
+ /*
+ * Linux has only 16-bit uid and gid, so we can't support EFT.
+ * Files are dynamically chown()ed to root.
+ */
+ inode->i_uid = ufs_uid(ufs_inode);
+ if (inode->i_uid == UFS_USEEFT) {
+ inode->i_uid = 0;
+ }
+ if (inode->i_gid == UFS_USEEFT) {
+ inode->i_gid = 0;
+ }
+
+ /*
+ * Linux i_size can be 32 on some architektures. We will mark
+ * big files as read only and let user access first 32 bits.
+ */
+ inode->u.ufs_i.i_size = SWAB64(ufs_inode->ui_size);
+ inode->i_size = (off_t) inode->u.ufs_i.i_size;
+ if (sizeof(off_t) == 4 && (inode->u.ufs_i.i_size >> 32))
+ inode->i_size = (__u32)-1;
+
+ inode->i_atime = SWAB32(ufs_inode->ui_atime.tv_sec);
+ inode->i_ctime = SWAB32(ufs_inode->ui_ctime.tv_sec);
+ inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec);
+ inode->i_blocks = SWAB32(ufs_inode->ui_blocks);
+ inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat) */
+ inode->i_version = ++event;
+
+ inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags);
+ inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
+ inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow);
+ inode->u.ufs_i.i_uid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_uid);
+ inode->u.ufs_i.i_gid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_gid);
+ inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+ inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = to_kdev_t(SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0]));
+ else if (inode->i_blocks) {
+ for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+ inode->u.ufs_i.i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
+ }
+ else {
+ for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+ inode->u.ufs_i.i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
+ }
+
+ brelse (bh);
+
+ inode->i_op = NULL;
+
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &ufs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &ufs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &ufs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &blkdev_inode_operations;
+ else if (S_ISSOCK(inode->i_mode))
+ ; /* nothing */
+ else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+
+#ifdef UFS_INODE_DEBUG_MORE
+ ufs_print_inode (inode);
+#endif
+ UFSD(("EXIT\n"))
+}
+
+static int ufs_update_inode(struct inode * inode, int do_sync)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * bh;
+ struct ufs_inode * ufs_inode;
+ unsigned i;
+ unsigned swab;
+
+ UFSD(("ENTER, ino %lu\n", inode->i_ino))
+
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (inode->i_ino < UFS_ROOTINO ||
+ inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+ ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
+ return -1;
+ }
+
+ bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+ if (!bh) {
+ ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
+ return -1;
+ }
+ ufs_inode = (struct ufs_inode *) (bh->b_data + ufs_inotofsbo(inode->i_ino) * sizeof(struct ufs_inode));
+
+ ufs_inode->ui_mode = SWAB16(inode->i_mode);
+ ufs_inode->ui_nlink = SWAB16(inode->i_nlink);
+
+ if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT) {
+ ufs_inode->ui_u3.ui_sun.ui_uid = SWAB32(inode->u.ufs_i.i_uid);
+ ufs_inode->ui_u1.oldids.ui_suid = (__u16)ufs_inode->ui_u3.ui_sun.ui_uid;
+ }
+ else {
+ ufs_inode->ui_u1.oldids.ui_suid = SWAB16(inode->i_uid);
+ ufs_inode->ui_u3.ui_sun.ui_uid = (__u32) ufs_inode->ui_u1.oldids.ui_suid;
+ }
+ if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT) {
+ ufs_inode->ui_u3.ui_sun.ui_gid = SWAB32(inode->u.ufs_i.i_gid);
+ ufs_inode->ui_u1.oldids.ui_sgid = (__u16)ufs_inode->ui_u3.ui_sun.ui_gid;
+ }
+ else {
+ ufs_inode->ui_u1.oldids.ui_sgid = SWAB16(inode->i_gid);
+ ufs_inode->ui_u3.ui_sun.ui_gid = (__u32) ufs_inode->ui_u1.oldids.ui_sgid;
+ }
+
+ ufs_inode->ui_size = SWAB64((u64)inode->i_size);
+ ufs_inode->ui_atime.tv_sec = SWAB32(inode->i_atime);
+ ufs_inode->ui_atime.tv_usec = SWAB32(0);
+ ufs_inode->ui_ctime.tv_sec = SWAB32(inode->i_ctime);
+ ufs_inode->ui_ctime.tv_usec = SWAB32(0);
+ ufs_inode->ui_mtime.tv_sec = SWAB32(inode->i_mtime);
+ ufs_inode->ui_mtime.tv_usec = SWAB32(0);
+ ufs_inode->ui_blocks = SWAB32(inode->i_blocks);
+
+ ufs_inode->ui_flags = SWAB32(inode->u.ufs_i.i_flags);
+ ufs_inode->ui_gen = SWAB32(inode->u.ufs_i.i_gen);
+ ufs_inode->ui_u3.ui_sun.ui_shadow = SWAB32(inode->u.ufs_i.i_shadow);
+ ufs_inode->ui_u3.ui_sun.ui_oeftflag = SWAB32(inode->u.ufs_i.i_oeftflag);
+
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ ufs_inode->ui_u2.ui_addr.ui_db[0] = SWAB32(kdev_t_to_nr(inode->i_rdev));
+ else if (inode->i_blocks) {
+ for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+ ufs_inode->ui_u2.ui_addr.ui_db[i] = inode->u.ufs_i.i_u1.i_data[i];
+ }
+ else {
+ for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+ ufs_inode->ui_u2.ui_symlink[i] = inode->u.ufs_i.i_u1.i_symlink[i];
+ }
+
+ if (!inode->i_nlink)
+ memset (ufs_inode, 0, sizeof(struct ufs_inode));
+
+ mark_buffer_dirty(bh, 1);
+ if (do_sync) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+
+ UFSD(("EXIT\n"))
+ return 0;
+}
+
+void ufs_write_inode (struct inode * inode)
+{
+ ufs_update_inode (inode, 0);
+}
+
+int ufs_sync_inode (struct inode *inode)
+{
+ return ufs_update_inode (inode, 1);
+}
+
+void ufs_put_inode (struct inode * inode)
+{
+ UFSD(("ENTER & EXIT\n"))
+}
+
+void ufs_delete_inode (struct inode * inode)
+{
+ /*inode->u.ufs_i.i_dtime = CURRENT_TIME;*/
+ mark_inode_dirty(inode);
+ ufs_update_inode(inode, IS_SYNC(inode));
+ inode->i_size = 0;
+ if (inode->i_blocks)
+ ufs_truncate (inode);
+ ufs_free_inode (inode);
+}
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
new file mode 100644
index 000000000..309b31665
--- /dev/null
+++ b/fs/ufs/namei.c
@@ -0,0 +1,1147 @@
+/*
+ * linux/fs/ufs/namei.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/namei.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/namei.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_NAMEI_DEBUG
+
+#ifdef UFS_NAMEI_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS 2
+#define NAMEI_RA_BLOCKS 4
+#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
+/*
+ * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
+ */
+static int ufs_match (int len, const char * const name,
+ struct ufs_dir_entry * de, unsigned flags, unsigned swab)
+{
+ if (!de || !SWAB32(de->d_ino) || len > UFS_MAXNAMLEN)
+ return 0;
+ /*
+ * "" means "." ---> so paths like "/usr/lib//libc.a" work
+ */
+ if (!len && ufs_namlen(de) == 1 && (de->d_name[0] == '.') &&
+ (de->d_name[1] == '\0'))
+ return 1;
+ if (len != ufs_namlen(de))
+ return 0;
+ return !memcmp(name, de->d_name, len);
+}
+
+/*
+ * ufs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head * ufs_find_entry (struct inode * dir,
+ const char * const name, int namelen, struct ufs_dir_entry ** res_dir)
+{
+ struct super_block * sb;
+ struct buffer_head * bh_use[NAMEI_RA_SIZE];
+ struct buffer_head * bh_read[NAMEI_RA_SIZE];
+ unsigned long offset;
+ int block, toread, i, err;
+ unsigned flags, swab;
+
+ UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
+
+ *res_dir = NULL;
+ if (!dir)
+ return NULL;
+
+ sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (namelen > UFS_MAXNAMLEN)
+ return NULL;
+
+ memset (bh_use, 0, sizeof (bh_use));
+ toread = 0;
+ for (block = 0; block < NAMEI_RA_SIZE; ++block) {
+ struct buffer_head * bh;
+
+ if ((block << sb->s_blocksize_bits) >= dir->i_size)
+ break;
+ bh = ufs_getfrag (dir, block, 0, &err);
+ bh_use[block] = bh;
+ if (bh && !buffer_uptodate(bh))
+ bh_read[toread++] = bh;
+ }
+
+ for (block = 0, offset = 0; offset < dir->i_size; block++) {
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ char * dlimit;
+
+ if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
+ ll_rw_block (READ, toread, bh_read);
+ toread = 0;
+ }
+ bh = bh_use[block % NAMEI_RA_SIZE];
+ if (!bh) {
+ ufs_error (sb, "ufs_find_entry",
+ "directory #%lu contains a hole at offset %lu", dir->i_ino, offset);
+ offset += sb->s_blocksize;
+ continue;
+ }
+ wait_on_buffer (bh);
+ if (!buffer_uptodate(bh)) {
+ /*
+ * read error: all bets are off
+ */
+ break;
+ }
+
+ de = (struct ufs_dir_entry *) bh->b_data;
+ dlimit = bh->b_data + sb->s_blocksize;
+ while ((char *) de < dlimit && offset < dir->i_size) {
+ if (!ufs_check_dir_entry ("ufs_find_entry", dir, de, bh, offset))
+ goto failed;
+ if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+ for (i = 0; i < NAMEI_RA_SIZE; ++i) {
+ if (bh_use[i] != bh)
+ brelse (bh_use[i]);
+ }
+ *res_dir = de;
+ UFSD(("EXIT\n"))
+ return bh;
+ }
+ offset += SWAB16(de->d_reclen);
+ de = (struct ufs_dir_entry *)
+ ((char *) de + SWAB16(de->d_reclen));
+ }
+
+ brelse (bh);
+ if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
+ dir->i_size)
+ bh = NULL;
+ else
+ bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
+ bh_use[block % NAMEI_RA_SIZE] = bh;
+ if (bh && !buffer_uptodate(bh))
+ bh_read[toread++] = bh;
+ }
+
+failed:
+ for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
+ UFSD(("EXIT (FAILED)\n"))
+ return NULL;
+}
+
+int ufs_lookup(struct inode * dir, struct dentry *dentry)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ struct ufs_dir_entry * de;
+ struct buffer_head * bh;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (dentry->d_name.len > UFS_MAXNAMLEN)
+ return -ENAMETOOLONG;
+
+ bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ inode = NULL;
+ if (bh) {
+ unsigned long ino = SWAB32(de->d_ino);
+ brelse (bh);
+ inode = iget(sb, ino);
+ if (!inode)
+ return -EACCES;
+ }
+ d_add(dentry, inode);
+ UFSD(("EXIT\n"))
+ return 0;
+}
+
+/*
+ * ufs_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ufs_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * ufs_add_entry (struct inode * dir,
+ const char * name, int namelen, struct ufs_dir_entry ** res_dir,
+ int *err )
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ unsigned long offset;
+ unsigned fragoff;
+ unsigned short rec_len;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de, * de1;
+ unsigned flags, swab;
+
+ UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
+
+ *err = -EINVAL;
+ *res_dir = NULL;
+ if (!dir || !dir->i_nlink)
+ return NULL;
+
+ sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ if (namelen > UFS_MAXNAMLEN)
+ {
+ *err = -ENAMETOOLONG;
+ return NULL;
+ }
+
+ if (!namelen)
+ return NULL;
+ /*
+ * Is this a busy deleted directory? Can't create new files if so
+ */
+ if (dir->i_size == 0)
+ {
+ *err = -ENOENT;
+ return NULL;
+ }
+ bh = ufs_bread (dir, 0, 0, err);
+ if (!bh)
+ return NULL;
+ rec_len = UFS_DIR_REC_LEN(namelen);
+ offset = 0;
+ de = (struct ufs_dir_entry *) bh->b_data;
+ *err = -ENOSPC;
+ while (1) {
+ if ((char *)de >= SECTOR_SIZE + bh->b_data) {
+ fragoff = offset & ~uspi->s_fmask;
+ if (fragoff != 0 && fragoff != SECTOR_SIZE)
+ ufs_error (sb, "ufs_add_entry", "internal error"
+ " fragoff %u", fragoff);
+ if (!fragoff) {
+ brelse (bh);
+ bh = NULL;
+ bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, err);
+ }
+ if (!bh)
+ return NULL;
+ if (dir->i_size <= offset) {
+ if (dir->i_size == 0) {
+ *err = -ENOENT;
+ return NULL;
+ }
+ de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
+ de->d_ino = SWAB32(0);
+ de->d_reclen = SWAB16(SECTOR_SIZE);
+ de->d_u.d_namlen = SWAB16(0);
+ dir->i_size = offset + SECTOR_SIZE;
+ mark_inode_dirty(dir);
+ } else {
+ de = (struct ufs_dir_entry *) bh->b_data;
+ }
+ }
+ if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
+ *err = -ENOENT;
+ brelse (bh);
+ return NULL;
+ }
+ if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+ *err = -EEXIST;
+ brelse (bh);
+ return NULL;
+ }
+ if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) ||
+ (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)) + rec_len)) {
+ offset += SWAB16(de->d_reclen);
+ if (SWAB32(de->d_ino)) {
+ de1 = (struct ufs_dir_entry *) ((char *) de +
+ UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+ de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -
+ UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+ de->d_reclen = SWAB16(UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+ de = de1;
+ }
+ de->d_ino = SWAB32(0);
+ de->d_u.d_namlen = SWAB16(namelen);
+ memcpy (de->d_name, name, namelen + 1);
+ /*
+ * XXX shouldn't update any times until successful
+ * completion of syscall, but too many callers depend
+ * on this.
+ *
+ * XXX similarly, too many callers depend on
+ * ufs_new_inode() setting the times, but error
+ * recovery deletes the inode, so the worst that can
+ * happen is that the times are slightly out of date
+ * and/or different from the directory change time.
+ */
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ *res_dir = de;
+ *err = 0;
+
+ UFSD(("EXIT\n"))
+ return bh;
+ }
+ offset += SWAB16(de->d_reclen);
+ de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+ }
+ brelse (bh);
+ UFSD(("EXIT (FAILED)\n"))
+ return NULL;
+}
+
+/*
+ * ufs_delete_entry deletes a directory entry by merging it with the
+ * previous entry.
+ */
+static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
+ struct buffer_head * bh )
+
+{
+ struct super_block * sb;
+ struct ufs_dir_entry * de, * pde;
+ unsigned i;
+ unsigned flags, swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = inode->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+ i = 0;
+ pde = NULL;
+ de = (struct ufs_dir_entry *) bh->b_data;
+
+ UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),
+ SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+
+ while (i < bh->b_size) {
+ if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i))
+ return -EIO;
+ if (de == dir) {
+ if (pde)
+ pde->d_reclen =
+ SWAB16(SWAB16(pde->d_reclen) +
+ SWAB16(dir->d_reclen));
+ dir->d_ino = SWAB32(0);
+ UFSD(("EXIT\n"))
+ return 0;
+ }
+ i += SWAB16(de->d_reclen);
+ if (i == SECTOR_SIZE) pde = NULL;
+ else pde = de;
+ de = (struct ufs_dir_entry *)
+ ((char *) de + SWAB16(de->d_reclen));
+ if (i == SECTOR_SIZE && SWAB16(de->d_reclen) == 0)
+ break;
+ }
+ UFSD(("EXIT\n"))
+ return -ENOENT;
+}
+
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate().
+ */
+int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ int err = -EIO;
+ unsigned swab;
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ /*
+ * N.B. Several error exits in ufs_new_inode don't set err.
+ */
+ UFSD(("ENTER\n"))
+
+ inode = ufs_new_inode (dir, mode, &err);
+ if (!inode)
+ return err;
+ inode->i_op = &ufs_file_inode_operations;
+ inode->i_mode = mode;
+ mark_inode_dirty(inode);
+ bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ return err;
+ }
+ de->d_ino = SWAB32(inode->i_ino);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+ d_instantiate(dentry, inode);
+
+ UFSD(("EXIT\n"))
+
+ return 0;
+}
+
+int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ int err = -EIO;
+ unsigned swab;
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ err = -ENAMETOOLONG;
+ if (dentry->d_name.len > UFS_MAXNAMLEN)
+ goto out;
+
+ inode = ufs_new_inode (dir, mode, &err);
+ if (!inode)
+ goto out;
+
+ inode->i_uid = current->fsuid;
+ inode->i_mode = mode;
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &ufs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &ufs_dir_inode_operations;
+ if (dir->i_mode & S_ISGID)
+ inode->i_mode |= S_ISGID;
+ }
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &ufs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_rdev = to_kdev_t(rdev);
+ mark_inode_dirty(inode);
+ bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
+ goto out_no_entry;
+ de->d_ino = SWAB32(inode->i_ino);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ d_instantiate(dentry, inode);
+ brelse(bh);
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
+}
+
+int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ struct buffer_head * bh, * dir_block;
+ struct ufs_dir_entry * de;
+ int err;
+ unsigned swab;
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ err = -ENAMETOOLONG;
+ if (dentry->d_name.len > UFS_MAXNAMLEN)
+ goto out;
+
+ err = -EMLINK;
+ if (dir->i_nlink >= UFS_LINK_MAX)
+ goto out;
+ err = -EIO;
+ inode = ufs_new_inode (dir, S_IFDIR, &err);
+ if (!inode)
+ goto out;
+
+ inode->i_op = &ufs_dir_inode_operations;
+ inode->i_size = SECTOR_SIZE;
+ dir_block = ufs_bread (inode, 0, 1, &err);
+ if (!dir_block) {
+ inode->i_nlink--; /* is this nlink == 0? */
+ mark_inode_dirty(inode);
+ iput (inode);
+ return err;
+ }
+ inode->i_blocks = sb->s_blocksize / SECTOR_SIZE;
+ de = (struct ufs_dir_entry *) dir_block->b_data;
+ de->d_ino = SWAB32(inode->i_ino);
+ de->d_u.d_namlen = SWAB16(1);
+ de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1));
+ strcpy (de->d_name, ".");
+ de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+ de->d_ino = SWAB32(dir->i_ino);
+ de->d_reclen = SWAB16(SECTOR_SIZE - UFS_DIR_REC_LEN(1));
+ de->d_u.d_namlen = SWAB16(2);
+ strcpy (de->d_name, "..");
+ inode->i_nlink = 2;
+ mark_buffer_dirty(dir_block, 1);
+ brelse (dir_block);
+ inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+ if (dir->i_mode & S_ISGID)
+ inode->i_mode |= S_ISGID;
+ mark_inode_dirty(inode);
+ bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
+ goto out_no_entry;
+ de->d_ino = SWAB32(inode->i_ino);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ dir->i_nlink++;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry, inode);
+ brelse (bh);
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int ufs_empty_dir (struct inode * inode)
+{
+ struct super_block * sb;
+ unsigned long offset;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de, * de1;
+ int err;
+ unsigned swab;
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
+ !(bh = ufs_bread (inode, 0, 0, &err))) {
+ ufs_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no data block",
+ inode->i_ino);
+ return 1;
+ }
+ de = (struct ufs_dir_entry *) bh->b_data;
+ de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+ if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) ||
+ strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
+ ufs_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no `.' or `..'",
+ inode->i_ino);
+ return 1;
+ }
+ offset = SWAB16(de->d_reclen) + SWAB16(de1->d_reclen);
+ de = (struct ufs_dir_entry *) ((char *) de1 + SWAB16(de1->d_reclen));
+ while (offset < inode->i_size ) {
+ if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+ brelse (bh);
+ bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
+ if (!bh) {
+ ufs_error (sb, "empty_dir",
+ "directory #%lu contains a hole at offset %lu",
+ inode->i_ino, offset);
+ offset += sb->s_blocksize;
+ continue;
+ }
+ de = (struct ufs_dir_entry *) bh->b_data;
+ }
+ if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
+ brelse (bh);
+ return 1;
+ }
+ if (SWAB32(de->d_ino)) {
+ brelse (bh);
+ return 0;
+ }
+ offset += SWAB16(de->d_reclen);
+ de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+ }
+ brelse (bh);
+ return 1;
+}
+
+int ufs_rmdir (struct inode * dir, struct dentry *dentry)
+{
+ struct super_block *sb;
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ unsigned swab;
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ UFSD(("ENTER\n"))
+
+ retval = -ENAMETOOLONG;
+ if (dentry->d_name.len > UFS_MAXNAMLEN)
+ goto out;
+
+ retval = -ENOENT;
+ bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!bh)
+ goto end_rmdir;
+
+ inode = dentry->d_inode;
+ if (inode->i_sb->dq_op)
+ inode->i_sb->dq_op->initialize (inode, -1);
+
+ retval = -EPERM;
+ if ((dir->i_mode & S_ISVTX) &&
+ current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
+ goto end_rmdir;
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
+ goto end_rmdir;
+
+ retval = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
+ goto end_rmdir;
+
+ retval = -EIO;
+ if (inode->i_dev != dir->i_dev)
+ goto end_rmdir;
+ if (SWAB32(de->d_ino) != inode->i_ino)
+ goto end_rmdir;
+
+ down(&inode->i_sem);
+ /*
+ * Prune any child dentries so that this dentry becomes negative.
+ */
+ if (dentry->d_count > 1) {
+ ufs_warning (sb, "ufs_rmdir", "d_count=%d, pruning\n", dentry->d_count);
+ shrink_dcache_parent(dentry);
+ }
+ if (!ufs_empty_dir (inode))
+ retval = -ENOTEMPTY;
+ else if (SWAB32(de->d_ino) != inode->i_ino)
+ retval = -ENOENT;
+ else {
+ if (dentry->d_count > 1) {
+ /*
+ * Are we deleting the last instance of a busy directory?
+ * Better clean up if so.
+ *
+ * Make directory empty (it will be truncated when finally
+ * dereferenced). This also inhibits ufs_add_entry.
+ */
+ inode->i_size = 0;
+ }
+ retval = ufs_delete_entry (dir, de, bh);
+ dir->i_version = ++event;
+ }
+ up(&inode->i_sem);
+ if (retval)
+ goto end_rmdir;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ if (inode->i_nlink != 2)
+ ufs_warning (inode->i_sb, "ufs_rmdir",
+ "empty directory has nlink!=2 (%d)",
+ inode->i_nlink);
+ inode->i_version = ++event;
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ dir->i_nlink--;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ d_delete(dentry);
+
+end_rmdir:
+ brelse (bh);
+out:
+ UFSD(("EXIT\n"))
+
+ return retval;
+}
+
+int ufs_unlink(struct inode * dir, struct dentry *dentry)
+{
+ struct super_block * sb;
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ufs_dir_entry * de;
+ unsigned flags, swab;
+
+ sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+
+ retval = -ENAMETOOLONG;
+ if (dentry->d_name.len > UFS_MAXNAMLEN)
+ goto out;
+
+ retval = -ENOENT;
+ bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ UFSD(("de: ino %u, reclen %u, namelen %u, name %s\n", SWAB32(de->d_ino),
+ SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+ if (!bh)
+ goto end_unlink;
+
+ inode = dentry->d_inode;
+ if (inode->i_sb->dq_op)
+ inode->i_sb->dq_op->initialize (inode, -1);
+
+ retval = -EPERM;
+ if (S_ISDIR(inode->i_mode))
+ goto end_unlink;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto end_unlink;
+ if ((dir->i_mode & S_ISVTX) &&
+ current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
+ goto end_unlink;
+
+ retval = -EIO;
+ if (SWAB32(de->d_ino) != inode->i_ino)
+ goto end_unlink;
+
+ if (!inode->i_nlink) {
+ ufs_warning (inode->i_sb, "ufs_unlink",
+ "Deleting nonexistent file (%lu), %d",
+ inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ retval = ufs_delete_entry (dir, de, bh);
+ if (retval)
+ goto end_unlink;
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ inode->i_ctime = dir->i_ctime;
+ retval = 0;
+ d_delete(dentry); /* This also frees the inode */
+
+end_unlink:
+ brelse (bh);
+out:
+ return retval;
+}
+
+
+int ufs_link (struct dentry * old_dentry, struct inode * dir,
+ struct dentry *dentry)
+{
+ struct super_block * sb;
+ struct inode *inode = old_dentry->d_inode;
+ struct ufs_dir_entry * de;
+ struct buffer_head * bh;
+ int err;
+ unsigned swab;
+
+ inode = old_dentry->d_inode;
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return -EPERM;
+
+ if (inode->i_nlink >= UFS_LINK_MAX)
+ return -EMLINK;
+
+ bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
+ return err;
+
+ de->d_ino = SWAB32(inode->i_ino);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ inode->i_count++;
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+/*
+ * Create symbolic link. We use only slow symlinks at this time.
+ */
+int ufs_symlink (struct inode * dir, struct dentry * dentry,
+ const char * symname)
+{
+ struct super_block * sb;
+ struct ufs_dir_entry * de;
+ struct inode * inode;
+ struct buffer_head * bh, * name_block;
+ char * link;
+ unsigned i, l;
+ int err;
+ char c;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = dir->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ bh = name_block = NULL;
+ err = -EIO;
+
+ if (!(inode = ufs_new_inode (dir, S_IFLNK, &err))) {
+ return err;
+ }
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ inode->i_op = &ufs_symlink_inode_operations;
+ for (l = 0; l < sb->s_blocksize - 1 && symname [l]; l++);
+
+ /***if (l >= sizeof (inode->u.ufs_i.i_data)) {***/
+ if (1) {
+ /* slow symlink */
+ name_block = ufs_bread (inode, 0, 1, &err);
+ if (!name_block) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ return err;
+ }
+ link = name_block->b_data;
+
+ } else {
+ /* fast symlink */
+ link = (char *) inode->u.ufs_i.i_u1.i_data;
+ }
+ i = 0;
+ while (i < sb->s_blocksize - 1 && (c = *(symname++)))
+ link[i++] = c;
+ link[i] = 0;
+ if (name_block) {
+ mark_buffer_dirty(name_block, 1);
+ brelse (name_block);
+ }
+ inode->i_size = i;
+ mark_inode_dirty(inode);
+
+ bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
+ goto out_no_entry;
+ de->d_ino = SWAB32(inode->i_ino);
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+ d_instantiate(dentry, inode);
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
+}
+
+
+#define PARENT_INO(buffer) \
+ ((struct ufs_dir_entry *) ((char *) buffer + \
+ SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino
+/*
+ * rename uses retrying to avoid race-conditions: at least they should be
+ * minimal.
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
+ * checks fail, it tries to restart itself again. Very practical - no changes
+ * are done until we know everything works ok.. and then all the changes can be
+ * done in one fell swoop when we have claimed all the buffers needed.
+ *
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry )
+{
+ struct super_block * sb;
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct ufs_dir_entry * old_de, * new_de;
+ int retval;
+ unsigned flags, swab;
+
+ sb = old_dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
+
+ UFSD(("ENTER\n"))
+
+ old_inode = new_inode = NULL;
+ old_bh = new_bh = dir_bh = NULL;
+ new_de = NULL;
+ retval = -ENAMETOOLONG;
+ if (old_dentry->d_name.len > UFS_MAXNAMLEN)
+ goto end_rename;
+
+ UFSD(("name %s, len %u\n", old_dentry->d_name.name, old_dentry->d_name.len))
+ old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+ UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino),
+ SWAB16(old_de->d_reclen), ufs_namlen(old_de), old_de->d_name))
+
+ retval = -ENOENT;
+ if (!old_bh)
+ goto end_rename;
+ old_inode = old_dentry->d_inode;
+
+ retval = -EPERM;
+ if ((old_dir->i_mode & S_ISVTX) &&
+ current->fsuid != old_inode->i_uid &&
+ current->fsuid != old_dir->i_uid && !fsuser())
+ goto end_rename;
+ if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
+ goto end_rename;
+
+ new_inode = new_dentry->d_inode;
+ UFSD(("name %s, len %u\n", new_dentry->d_name.name, new_dentry->d_name.len))
+ new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
+ if (new_bh) {
+ if (!new_inode) {
+ brelse (new_bh);
+ new_bh = NULL;
+ } else {
+ if (new_inode->i_sb->dq_op)
+ new_inode->i_sb->dq_op->initialize (new_inode, -1);
+ }
+ }
+ retval = 0;
+ if (new_inode == old_inode)
+ goto end_rename;
+ if (new_inode && S_ISDIR(new_inode->i_mode)) {
+ retval = -EISDIR;
+ if (!S_ISDIR(old_inode->i_mode))
+ goto end_rename;
+ retval = -EINVAL;
+ if (is_subdir(new_dentry, old_dentry))
+ goto end_rename;
+ retval = -ENOTEMPTY;
+ if (!ufs_empty_dir (new_inode))
+ goto end_rename;
+ retval = -EBUSY;
+ if (new_dentry->d_count > 1)
+ goto end_rename;
+ }
+ retval = -EPERM;
+ if (new_inode) {
+ if ((new_dir->i_mode & S_ISVTX) &&
+ current->fsuid != new_inode->i_uid &&
+ current->fsuid != new_dir->i_uid && !fsuser())
+ goto end_rename;
+ if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
+ goto end_rename;
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ retval = -ENOTDIR;
+ if (new_inode && !S_ISDIR(new_inode->i_mode))
+ goto end_rename;
+ retval = -EINVAL;
+ if (is_subdir(new_dentry, old_dentry))
+ goto end_rename;
+ dir_bh = ufs_bread (old_inode, 0, 0, &retval);
+ if (!dir_bh)
+ goto end_rename;
+ if (SWAB32(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+ goto end_rename;
+ retval = -EMLINK;
+ if (!new_inode && new_dir->i_nlink >= UFS_LINK_MAX)
+ goto end_rename;
+ }
+
+ if (!new_bh)
+ new_bh = ufs_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de,
+ &retval);
+ if (!new_bh)
+ goto end_rename;
+ new_dir->i_version = ++event;
+
+ /*
+ * ok, that's it
+ */
+ new_de->d_ino = SWAB32(old_inode->i_ino);
+ ufs_delete_entry (old_dir, old_de, old_bh);
+
+ old_dir->i_version = ++event;
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(old_dir);
+ if (dir_bh) {
+ PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino);
+ mark_buffer_dirty(dir_bh, 1);
+ old_dir->i_nlink--;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ mark_inode_dirty(new_inode);
+ } else {
+ new_dir->i_nlink++;
+ mark_inode_dirty(new_dir);
+ }
+ }
+ mark_buffer_dirty(old_bh, 1);
+ if (IS_SYNC(old_dir)) {
+ ll_rw_block (WRITE, 1, &old_bh);
+ wait_on_buffer (old_bh);
+ }
+
+ mark_buffer_dirty(new_bh, 1);
+ if (IS_SYNC(new_dir)) {
+ ll_rw_block (WRITE, 1, &new_bh);
+ wait_on_buffer (new_bh);
+ }
+
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry);
+ retval = 0;
+end_rename:
+ brelse (dir_bh);
+ brelse (old_bh);
+ brelse (new_bh);
+
+ UFSD(("EXIT\n"))
+
+ return retval;
+}
+
+/*
+ * Ok, rename also locks out other renames, as they can change the parent of
+ * a directory, and we don't want any races. Other races are checked for by
+ * "do_rename()", which restarts if there are inconsistencies.
+ *
+ * Note that there is no race between different filesystems: it's only within
+ * the same device that races occur: many renames can happen at once, as long
+ * as they are on different partitions.
+ *
+ * In the second extended file system, we use a lock flag stored in the memory
+ * super-block. This way, we really lock other renames only if they occur
+ * on the same file system
+ */
+int ufs_rename (struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry )
+{
+ int result;
+
+ UFSD(("ENTER\n"))
+
+ while (old_dir->i_sb->u.ufs_sb.s_rename_lock)
+ sleep_on (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
+ old_dir->i_sb->u.ufs_sb.s_rename_lock = 1;
+ result = do_ufs_rename (old_dir, old_dentry, new_dir, new_dentry);
+ old_dir->i_sb->u.ufs_sb.s_rename_lock = 0;
+ wake_up (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
+
+ UFSD(("EXIT\n"))
+
+ return result;
+}
+
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
new file mode 100644
index 000000000..b68af5771
--- /dev/null
+++ b/fs/ufs/super.c
@@ -0,0 +1,690 @@
+/*
+ * linux/fs/ufs/super.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Kernel module support added on 96/04/26 by
+ * Stefan Reinauer <stepan@home.culture.mipt.ru>
+ *
+ * Module usage counts added on 96/04/29 by
+ * Gertjan van Wingerde <gertjan@cs.vu.nl>
+ *
+ * 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>.
+ *
+ * write support Daniel Pirkl <daniel.pirkl@email.cz> 1998
+ *
+
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/locks.h>
+#include <asm/uaccess.h>
+#include <linux/malloc.h>
+
+#include "swab.h"
+#include "util.h"
+
+
+#undef UFS_SUPER_DEBUG
+#undef UFS_SUPER_DEBUG_MORE
+
+#ifdef UFS_SUPER_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_SUPER_DEBUG_MORE
+/*
+ * Print contents of ufs_super_block, useful for debuging
+ */
+void ufs_print_super_stuff(struct ufs_super_block_first * usb1,
+ struct ufs_super_block_second * usb2,
+ struct ufs_super_block_third * usb3, unsigned swab)
+{
+ printk("\nufs_print_super_stuff\n");
+ printk("size of usb: %lu\n", sizeof(struct ufs_super_block));
+ printk(" magic: 0x%x\n", SWAB32(usb3->fs_magic));
+ printk(" sblkno: %u\n", SWAB32(usb1->fs_sblkno));
+ printk(" cblkno: %u\n", SWAB32(usb1->fs_cblkno));
+ printk(" iblkno: %u\n", SWAB32(usb1->fs_iblkno));
+ printk(" dblkno: %u\n", SWAB32(usb1->fs_dblkno));
+ printk(" cgoffset: %u\n", SWAB32(usb1->fs_cgoffset));
+ printk(" ~cgmask: 0x%x\n", ~SWAB32(usb1->fs_cgmask));
+ printk(" size: %u\n", SWAB32(usb1->fs_size));
+ printk(" dsize: %u\n", SWAB32(usb1->fs_dsize));
+ printk(" ncg: %u\n", SWAB32(usb1->fs_ncg));
+ printk(" bsize: %u\n", SWAB32(usb1->fs_bsize));
+ printk(" fsize: %u\n", SWAB32(usb1->fs_fsize));
+ printk(" frag: %u\n", SWAB32(usb1->fs_frag));
+ printk(" fragshift: %u\n", SWAB32(usb1->fs_fragshift));
+ printk(" ~fmask: %u\n", ~SWAB32(usb1->fs_fmask));
+ printk(" fshift: %u\n", SWAB32(usb1->fs_fshift));
+ printk(" sbsize: %u\n", SWAB32(usb1->fs_sbsize));
+ printk(" spc: %u\n", SWAB32(usb1->fs_spc));
+ printk(" cpg: %u\n", SWAB32(usb1->fs_cpg));
+ printk(" ipg: %u\n", SWAB32(usb1->fs_ipg));
+ printk(" fpg: %u\n", SWAB32(usb1->fs_fpg));
+ printk(" csaddr: %u\n", SWAB32(usb1->fs_csaddr));
+ printk(" cssize: %u\n", SWAB32(usb1->fs_cssize));
+ printk(" cgsize: %u\n", SWAB32(usb1->fs_cgsize));
+ printk(" fstodb: %u\n", SWAB32(usb1->fs_fsbtodb));
+ printk(" postblformat: %u\n", SWAB32(usb3->fs_postblformat));
+ printk(" nrpos: %u\n", SWAB32(usb3->fs_nrpos));
+ printk(" ndir %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
+ printk(" nifree %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
+ printk(" nbfree %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
+ printk(" nffree %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+}
+
+
+/*
+ * Print contents of ufs_cylinder_group, useful for debuging
+ */
+void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab)
+{
+ printk("\nufs_print_cylinder_stuff\n");
+ printk("size of ucg: %lu\n", sizeof(struct ufs_cylinder_group));
+ printk(" magic: %x\n", SWAB32(cg->cg_magic));
+ printk(" time: %u\n", SWAB32(cg->cg_time));
+ printk(" cgx: %u\n", SWAB32(cg->cg_cgx));
+ printk(" ncyl: %u\n", SWAB16(cg->cg_ncyl));
+ printk(" niblk: %u\n", SWAB16(cg->cg_niblk));
+ printk(" ndblk: %u\n", SWAB32(cg->cg_ndblk));
+ printk(" cs_ndir: %u\n", SWAB32(cg->cg_cs.cs_ndir));
+ printk(" cs_nbfree: %u\n", SWAB32(cg->cg_cs.cs_nbfree));
+ printk(" cs_nifree: %u\n", SWAB32(cg->cg_cs.cs_nifree));
+ printk(" cs_nffree: %u\n", SWAB32(cg->cg_cs.cs_nffree));
+ printk(" rotor: %u\n", SWAB32(cg->cg_rotor));
+ printk(" frotor: %u\n", SWAB32(cg->cg_frotor));
+ printk(" irotor: %u\n", SWAB32(cg->cg_irotor));
+ printk(" frsum: %u, %u, %u, %u, %u, %u, %u, %u\n",
+ SWAB32(cg->cg_frsum[0]), SWAB32(cg->cg_frsum[1]),
+ SWAB32(cg->cg_frsum[2]), SWAB32(cg->cg_frsum[3]),
+ SWAB32(cg->cg_frsum[4]), SWAB32(cg->cg_frsum[5]),
+ SWAB32(cg->cg_frsum[6]), SWAB32(cg->cg_frsum[7]));
+ printk(" btotoff: %u\n", SWAB32(cg->cg_btotoff));
+ printk(" boff: %u\n", SWAB32(cg->cg_boff));
+ printk(" iuseoff: %u\n", SWAB32(cg->cg_iusedoff));
+ printk(" freeoff: %u\n", SWAB32(cg->cg_freeoff));
+ printk(" nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff));
+}
+#endif /* UFS_SUPER_DEBUG_MORE */
+
+/*
+ * Called while file system is mounted, read super block
+ * and create important imtermal structures.
+ */
+struct super_block * ufs_read_super (
+ struct super_block * sb,
+ void * data,
+ int silent)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_super_block_second * usb2;
+ struct ufs_super_block_third * usb3;
+ struct ufs_buffer_head * ubh;
+ unsigned char * base, * space;
+ unsigned size, blks, i;
+ unsigned block_size, super_block_size;
+ unsigned flags, swab;
+ s64 tmp;
+ static unsigned offsets[] = {0, 96, 160}; /* different superblock locations */
+
+ UFSD(("ENTER\n"))
+
+ uspi = NULL;
+ ubh = NULL;
+ base = space = NULL;
+ sb->u.ufs_sb.s_ucg = NULL;
+ flags = 0;
+ swab = 0;
+
+ /* sb->s_dev and sb->s_flags are set by our caller
+ * data is the mystery argument to sys_mount()
+ *
+ * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
+ * and s_type when we return.
+ */
+
+ MOD_INC_USE_COUNT;
+ lock_super (sb);
+
+ sb->u.ufs_sb.s_uspi = uspi =
+ kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
+ if (!uspi)
+ goto failed;
+
+ block_size = BLOCK_SIZE;
+ super_block_size = BLOCK_SIZE * 2;
+
+ uspi->s_fsize = block_size;
+ uspi->s_fmask = ~(BLOCK_SIZE - 1);
+ uspi->s_fshift = BLOCK_SIZE_BITS;
+ uspi->s_sbsize = super_block_size;
+ i = 0;
+ uspi->s_sbbase = offsets[i];
+
+again:
+ set_blocksize (sb->s_dev, block_size);
+
+ /*
+ * read ufs super block from device
+ */
+ ubh = ubh_bread2 (sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+ if (!ubh)
+ goto failed;
+
+ usb1 = ubh_get_usb_first(USPI_UBH);
+ usb2 = ubh_get_usb_second(USPI_UBH);
+ usb3 = ubh_get_usb_third(USPI_UBH);
+
+ /*
+ * Check ufs magic number
+ */
+ if (usb3->fs_magic != UFS_MAGIC) {
+ switch (le32_to_cpup(&usb3->fs_magic)) {
+ case UFS_MAGIC:
+ swab = UFS_LITTLE_ENDIAN; break;
+ case UFS_CIGAM:
+ swab = UFS_BIG_ENDIAN; break;
+ default:
+ /*
+ * Try another super block location
+ */
+ if (++i < sizeof(offsets)/sizeof(unsigned)) {
+ ubh_brelse2(ubh);
+ ubh = NULL;
+ uspi->s_sbbase = offsets[i];
+ goto again;
+ }
+ else {
+ printk("ufs_read_super: super block loacation not in { 0, 96, 160} or bad magic number\n");
+ goto failed;
+ }
+ }
+ }
+
+ /*
+ * Check block and fragment sizes
+ */
+ uspi->s_bsize = SWAB32(usb1->fs_bsize);
+ uspi->s_fsize = SWAB32(usb1->fs_fsize);
+ uspi->s_sbsize = SWAB32(usb1->fs_sbsize);
+
+ if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192) {
+ printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
+ goto failed;
+ }
+ if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
+ printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
+ goto failed;
+ }
+
+ /*
+ * Block size is not 1024, set block_size to 512,
+ * free buffers and read it again
+ */
+ if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
+ ubh_brelse2(ubh);
+ ubh = NULL;
+ uspi->s_fmask = SWAB32(usb1->fs_fmask);
+ uspi->s_fshift = SWAB32(usb1->fs_fshift);
+ goto again;
+ }
+
+#ifdef UFS_SUPER_DEBUG_MORE
+ ufs_print_super_stuff (usb1, usb2, usb3, swab);
+#endif
+ /*
+ * Check file system type
+ */
+ flags |= UFS_VANILLA;
+ /* XXX more consistency check */
+ UFSD(("ufs_read_super: maxsymlinklen 0x%8.8x\n", usb3->fs_u.fs_44.fs_maxsymlinklen))
+ if (usb3->fs_u.fs_44.fs_maxsymlinklen >= 0) {
+ if (usb3->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
+ UFSD(("44BSD\n"))
+ flags |= UFS_44BSD;
+ sb->s_flags |= MS_RDONLY;
+ } else {
+ UFSD(("OLD\n"))
+ sb->s_flags |= UFS_OLD; /* 4.2BSD */
+ }
+ } else if (uspi->s_sbbase > 0) {
+ UFSD(("NEXT\n"))
+ flags |= UFS_NEXT;
+ sb->s_flags |= MS_RDONLY;
+ } else {
+ UFSD(("SUN\n"))
+ flags |= UFS_SUN;
+ }
+
+ /*
+ * Check, if file system was correctly unmounted.
+ * If not, make it read only.
+ */
+ 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(usb3) == UFS_FSOK - usb1->fs_time)) {
+ switch(usb1->fs_clean) {
+ case UFS_FSCLEAN:
+ UFSD(("fs is clean\n"))
+ break;
+ case UFS_FSSTABLE:
+ UFSD(("fs is stable\n"))
+ 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",
+ usb1->fs_clean);
+ sb->s_flags |= MS_RDONLY;
+ break;
+ }
+ } else {
+ printk("ufs_read_super: fs needs fsck\n");
+ sb->s_flags |= MS_RDONLY;
+ }
+
+ sb->s_flags &= ~MS_RDONLY;
+ /*
+ * Read ufs_super_block into internal data structures
+ */
+ sb->s_blocksize = SWAB32(usb1->fs_fsize);
+ sb->s_blocksize_bits = SWAB32(usb1->fs_fshift);
+ sb->s_op = &ufs_super_ops;
+ sb->dq_op = 0; /* XXX */
+ sb->s_magic = SWAB32(usb3->fs_magic);
+
+ uspi->s_sblkno = SWAB32(usb1->fs_sblkno);
+ uspi->s_cblkno = SWAB32(usb1->fs_cblkno);
+ uspi->s_iblkno = SWAB32(usb1->fs_iblkno);
+ uspi->s_dblkno = SWAB32(usb1->fs_dblkno);
+ uspi->s_cgoffset = SWAB32(usb1->fs_cgoffset);
+ uspi->s_cgmask = SWAB32(usb1->fs_cgmask);
+ uspi->s_size = SWAB32(usb1->fs_size);
+ uspi->s_dsize = SWAB32(usb1->fs_dsize);
+ uspi->s_ncg = SWAB32(usb1->fs_ncg);
+ /* s_bsize already set */
+ /* s_fsize already set */
+ uspi->s_fpb = SWAB32(usb1->fs_frag);
+ uspi->s_minfree = SWAB32(usb1->fs_minfree);
+ uspi->s_bmask = SWAB32(usb1->fs_bmask);
+ uspi->s_fmask = SWAB32(usb1->fs_fmask);
+ uspi->s_bshift = SWAB32(usb1->fs_bshift);
+ uspi->s_fshift = SWAB32(usb1->fs_fshift);
+ uspi->s_fpbshift = SWAB32(usb1->fs_fragshift);
+ uspi->s_fsbtodb = SWAB32(usb1->fs_fsbtodb);
+ /* s_sbsize already set */
+ uspi->s_csmask = SWAB32(usb1->fs_csmask);
+ uspi->s_csshift = SWAB32(usb1->fs_csshift);
+ uspi->s_nindir = SWAB32(usb1->fs_nindir);
+ uspi->s_inopb = SWAB32(usb1->fs_inopb);
+ uspi->s_nspf = SWAB32(usb1->fs_nspf);
+ uspi->s_npsect = SWAB32(usb1->fs_npsect);
+ uspi->s_interleave = SWAB32(usb1->fs_interleave);
+ uspi->s_trackskew = SWAB32(usb1->fs_trackskew);
+ uspi->s_csaddr = SWAB32(usb1->fs_csaddr);
+ uspi->s_cssize = SWAB32(usb1->fs_cssize);
+ uspi->s_cgsize = SWAB32(usb1->fs_cgsize);
+ uspi->s_ntrak = SWAB32(usb1->fs_ntrak);
+ uspi->s_nsect = SWAB32(usb1->fs_nsect);
+ uspi->s_spc = SWAB32(usb1->fs_spc);
+ uspi->s_ipg = SWAB32(usb1->fs_ipg);
+ uspi->s_fpg = SWAB32(usb1->fs_fpg);
+ uspi->s_cpc = SWAB32(usb2->fs_cpc);
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
+ uspi->s_qbmask = SWAB64(tmp);
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
+ uspi->s_qfmask = SWAB64(tmp);
+ uspi->s_postblformat = SWAB32(usb3->fs_postblformat);
+ uspi->s_nrpos = SWAB32(usb3->fs_nrpos);
+ uspi->s_postbloff = SWAB32(usb3->fs_postbloff);
+ uspi->s_rotbloff = SWAB32(usb3->fs_rotbloff);
+
+ /*
+ * Compute another fraquently used values
+ */
+ uspi->s_fpbmask = uspi->s_fpb - 1;
+ uspi->s_apbshift = uspi->s_bshift - 2;
+ uspi->s_2apbshift = uspi->s_apbshift * 2;
+ uspi->s_3apbshift = uspi->s_apbshift * 3;
+ uspi->s_apb = 1 << uspi->s_apbshift;
+ uspi->s_2apb = 1 << uspi->s_2apbshift;
+ uspi->s_3apb = 1 << uspi->s_3apbshift;
+ uspi->s_apbmask = uspi->s_apb - 1;
+ uspi->s_nspfshift = uspi->s_fshift - SECTOR_BITS;
+ uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift;
+ uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift;
+
+ sb->u.ufs_sb.s_flags = flags;
+ sb->u.ufs_sb.s_swab = swab;
+ sb->u.ufs_sb.s_rename_lock = 0;
+ sb->u.ufs_sb.s_rename_wait = NULL;
+
+ sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
+
+ /*
+ * Read cs structures from (usually) first data block
+ * on the device.
+ */
+ size = uspi->s_cssize;
+ blks = howmany(size, uspi->s_fsize);
+ base = space = kmalloc(size, GFP_KERNEL);
+ if (!base)
+ goto failed;
+ for (i = 0; i < blks; i += uspi->s_fpb) {
+ size = uspi->s_bsize;
+ if (i + uspi->s_fpb > blks)
+ size = (blks - i) * uspi->s_fsize;
+ ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
+ if (!ubh)
+ goto failed;
+ ubh_ubhcpymem (space, ubh, size);
+ sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+ space += size;
+ ubh_brelse (ubh);
+ ubh = NULL;
+ }
+
+ /*
+ * Read cylinder group (we read only first fragment from block
+ * at this time) and prepare internal data structures for cg caching.
+ */
+ if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
+ goto failed;
+ for (i = 0; i < uspi->s_ncg; i++)
+ sb->u.ufs_sb.s_ucg[i] = NULL;
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+ sb->u.ufs_sb.s_ucpi[i] = NULL;
+ sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+ }
+ for (i = 0; i < uspi->s_ncg; i++) {
+ UFSD(("read cg %u\n", i))
+ if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
+ goto failed;
+ if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
+ goto failed;
+#ifdef UFS_SUPER_DEBUG_MORE
+ ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
+#endif
+ }
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+ if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+ goto failed;
+ sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+ }
+ sb->u.ufs_sb.s_cg_loaded = 0;
+
+ unlock_super(sb);
+ UFSD(("EXIT\n"))
+ return(sb);
+
+failed:
+ if (ubh) ubh_brelse2 (ubh);
+ if (uspi) kfree (uspi);
+ if (base) kfree (base);
+
+ if (sb->u.ufs_sb.s_ucg) {
+ for (i = 0; i < uspi->s_ncg; i++)
+ if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
+ kfree (sb->u.ufs_sb.s_ucg);
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
+ if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
+ }
+ sb->s_dev = 0;
+ unlock_super (sb);
+ MOD_DEC_USE_COUNT;
+ UFSD(("EXIT (FAILED)\n"))
+ return(NULL);
+}
+
+/*
+ * Put super block, release internal structures
+ */
+void ufs_put_super (struct super_block * sb)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * ubh;
+ unsigned char * base, * space;
+ unsigned size, blks, i;
+
+ UFSD(("ENTER\n"))
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ size = uspi->s_cssize;
+ blks = howmany(size, uspi->s_fsize);
+ base = space = (char*) sb->u.ufs_sb.s_csp[0];
+ for (i = 0; i < blks; i += uspi->s_fpb) {
+ size = uspi->s_bsize;
+ if (i + uspi->s_fpb > blks)
+ size = (blks - i) * uspi->s_fsize;
+ ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
+ if (!ubh)
+ goto go_on;
+ ubh_memcpyubh (ubh, space, size);
+ space += size;
+ ubh_mark_buffer_uptodate (ubh, 1);
+ ubh_mark_buffer_dirty (ubh, 0);
+ ubh_brelse (ubh);
+ }
+
+go_on:
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+ ufs_put_cylinder (sb, i);
+ kfree (sb->u.ufs_sb.s_ucpi[i]);
+ }
+ for (i = 0; i < uspi->s_ncg; i++)
+ brelse (sb->u.ufs_sb.s_ucg[i]);
+ kfree (sb->u.ufs_sb.s_ucg);
+ kfree (base);
+ ubh_brelse2 (USPI_UBH);
+ kfree (sb->u.ufs_sb.s_uspi);
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return;
+}
+
+/*
+ * Write super block to device
+ */
+void ufs_write_super (struct super_block * sb) {
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct ufs_super_block_third * usb3;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+ usb3 = ubh_get_usb_third(USPI_UBH);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ if (SWAB16(usb3->fs_u.fs_sun.fs_state) & UFS_FSOK)
+ usb3->fs_u.fs_sun.fs_state = SWAB16(SWAB16(usb3->fs_u.fs_sun.fs_state) & ~UFS_FSOK);
+ usb1->fs_time = SWAB32(CURRENT_TIME);
+ usb3->fs_u.fs_sun.fs_state = SWAB32(UFS_FSOK - SWAB32(usb1->fs_time));
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ }
+ sb->s_dirt = 0;
+ UFSD(("EXIT\n"))
+}
+
+/*
+ * Copy some info about file system to user
+ */
+int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ struct statfs tmp;
+ struct statfs *sp = &tmp;
+ unsigned long used, avail;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first (USPI_UBH);
+
+ sp->f_type = UFS_MAGIC;
+ sp->f_bsize = sb->s_blocksize;
+ sp->f_blocks = uspi->s_dsize;
+ sp->f_bfree = (SWAB32(usb1->fs_cstotal.cs_nbfree) << uspi->s_fpbshift )+
+ SWAB32(usb1->fs_cstotal.cs_nffree);
+
+ avail = sp->f_blocks - (sp->f_blocks / 100) * uspi->s_minfree;
+ used = sp->f_blocks - sp->f_bfree;
+ if (avail > used)
+ sp->f_bavail = avail - used;
+ else
+ sp->f_bavail = 0;
+ sp->f_files = uspi->s_ncg * uspi->s_ipg;
+ sp->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+ sp->f_fsid.val[0] = SWAB32(usb1->fs_id[0]);
+ sp->f_fsid.val[1] = SWAB32(usb1->fs_id[1]);
+ sp->f_namelen = UFS_MAXNAMLEN;
+
+ UFSD(("EXIT\n"))
+
+ return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
+}
+
+
+static char error_buf[1024];
+
+void ufs_warning (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vsprintf (error_buf, fmt, args);
+ va_end (args);
+ printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+}
+
+void ufs_error (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ va_list args;
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ usb1->fs_clean = UFS_FSBAD;
+ ubh_mark_buffer_dirty(USPI_UBH, 1);
+ sb->s_dirt = 1;
+ sb->s_flags |= MS_RDONLY;
+ }
+ va_start (args, fmt);
+ vsprintf (error_buf, fmt, args);
+ va_end (args);
+ printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+}
+
+void ufs_panic (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ va_list args;
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ usb1->fs_clean = UFS_FSBAD;
+ ubh_mark_buffer_dirty(USPI_UBH, 1);
+ sb->s_dirt = 1;
+ }
+ va_start (args, fmt);
+ vsprintf (error_buf, fmt, args);
+ va_end (args);
+ /* this is to prevent panic from syncing this filesystem */
+ if (sb->s_lock)
+ sb->s_lock = 0;
+ sb->s_flags |= MS_RDONLY;
+ printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+/* panic ("UFS-fs panic (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+*/
+}
+
+
+static struct super_operations ufs_super_ops = {
+ ufs_read_inode,
+ ufs_write_inode,
+ ufs_put_inode,
+ ufs_delete_inode,
+ NULL, /* notify_change() */
+ ufs_put_super,
+ ufs_write_super,
+ ufs_statfs,
+ NULL, /* XXX - ufs_remount() */
+};
+
+static struct file_system_type ufs_fs_type = {
+ "ufs",
+ FS_REQUIRES_DEV,
+ ufs_read_super,
+ NULL
+};
+
+
+int init_ufs_fs(void)
+{
+ return(register_filesystem(&ufs_fs_type));
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ return init_ufs_fs();
+}
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&ufs_fs_type);
+}
+#endif
+
diff --git a/fs/ufs/swab.h b/fs/ufs/swab.h
new file mode 100644
index 000000000..534c26981
--- /dev/null
+++ b/fs/ufs/swab.h
@@ -0,0 +1,114 @@
+/*
+ * linux/fs/ufs/ufs_swab.h
+ *
+ * Copyright (C) 1997 Francois-Rene Rideau <rideau@ens.fr>
+ * Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
+ */
+
+#ifndef _UFS_SWAB_H
+#define _UFS_SWAB_H
+
+/*
+ * Notes:
+ * HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes
+ * in case there are ufs implementations that have strange bytesexes,
+ * you'll need to modify code here as well as in ufs_super.c and ufs_fs.h
+ * to support them.
+ */
+
+#include <linux/ufs_fs.h>
+#include <asm/byteorder.h>
+
+/*
+ * These are only valid inside ufs routines,
+ * after swab has been initialized to sb->u.ufs_sb.s_swab
+ */
+#define SWAB16(x) ufs_swab16(swab,x)
+#define SWAB32(x) ufs_swab32(swab,x)
+#define SWAB64(x) ufs_swab64(swab,x)
+
+/*
+ * We often use swabing, when we want to increment/decrement some value, so these
+ * macros might become handy and increase readability. (Daniel)
+ */
+#define INC_SWAB16(x) x=ufs_swab16_add(swab,x,1)
+#define INC_SWAB32(x) x=ufs_swab32_add(swab,x,1)
+#define INC_SWAB64(x) x=ufs_swab64_add(swab,x,1)
+#define DEC_SWAB16(x) x=ufs_swab16_add(swab,x,-1)
+#define DEC_SWAB32(x) x=ufs_swab32_add(swab,x,-1)
+#define DEC_SWAB64(x) x=ufs_swab64_add(swab,x,-1)
+#define ADD_SWAB16(x,y) x=ufs_swab16_add(swab,x,y)
+#define ADD_SWAB32(x,y) x=ufs_swab32_add(swab,x,y)
+#define ADD_SWAB64(x,y) x=ufs_swab64_add(swab,x,y)
+#define SUB_SWAB16(x,y) x=ufs_swab16_add(swab,x,-(y))
+#define SUB_SWAB32(x,y) x=ufs_swab32_add(swab,x,-(y))
+#define SUB_SWAB64(x,y) x=ufs_swab64_add(swab,x,-(y))
+
+#ifndef __PDP_ENDIAN
+extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) {
+ if (swab)
+ return swab16(x);
+ else
+ return x;
+}
+extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) {
+ if (swab)
+ return swab32(x);
+ else
+ return x;
+}
+extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) {
+ if (swab)
+ return swab64(x);
+ else
+ return x;
+}
+extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) {
+ if (swab)
+ return swab16(swab16(x)+y);
+ else
+ return x + y;
+}
+extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) {
+ if (swab)
+ return swab32(swab32(x)+y);
+ else
+ return x + y;
+}
+extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) {
+ if (swab)
+ return swab64(swab64(x)+y);
+ else
+ return x + y;
+}
+#else /* __PDP_ENDIAN */
+extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) {
+ if (swab & UFS_LITTLE_ENDIAN)
+ return le16_to_cpu(x);
+ else
+ return be16_to_cpu(x);
+}
+extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) {
+ if (swab & UFS_LITTLE_ENDIAN)
+ return le32_to_cpu(x);
+ else
+ return be32_to_cpu(x);
+}
+extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) {
+ if (swab & UFS_LITTLE_ENDIAN)
+ return le64_to_cpu(x);
+ else
+ return be64_to_cpu(x);
+}
+extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) {
+ return ufs_swab16(swab, ufs_swab16(swab, x) + y);
+}
+extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) {
+ return ufs_swab32(swab, ufs_swab32(swab, x) + y);
+}
+extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) {
+ return ufs_swab64(swab, ufs_swab64(swab, x) + y);
+}
+#endif /* __PDP_ENDIAN */
+
+#endif /* _UFS_SWAB_H */
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
new file mode 100644
index 000000000..9d18c5f53
--- /dev/null
+++ b/fs/ufs/symlink.c
@@ -0,0 +1,138 @@
+/*
+ * linux/ufs/ufs/symlink.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@emai.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/symlink.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/symlink.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext2 symlink handling code
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+
+
+#undef UFS_SYMLINK_DEBUG
+
+#ifdef UFS_SYMLINK_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+static struct dentry * ufs_follow_link(struct dentry * dentry,
+ struct dentry * base)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ int error;
+ char * link;
+
+ UFSD(("ENTER\n"))
+
+ inode = dentry->d_inode;
+ bh = NULL;
+ /* slow symlink */
+ if (inode->i_blocks) {
+ if (!(bh = ufs_bread (inode, 0, 0, &error))) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ link = bh->b_data;
+ }
+ /* fast symlink */
+ else {
+ link = (char *) inode->u.ufs_i.i_u1.i_symlink;
+ }
+ UPDATE_ATIME(inode);
+ base = lookup_dentry(link, base, 1);
+ if (bh)
+ brelse(bh);
+ UFSD(("EXIT\n"))
+ return base;
+}
+
+static int ufs_readlink (struct dentry * dentry, char * buffer, int buflen)
+{
+ struct super_block * sb;
+ struct inode * inode;
+ struct buffer_head * bh;
+ char * link;
+ int i;
+
+ UFSD(("ENTER\n"))
+
+ inode = dentry->d_inode;
+ sb = inode->i_sb;
+ bh = NULL;
+ if (buflen > sb->s_blocksize - 1)
+ buflen = sb->s_blocksize - 1;
+ /* slow symlink */
+ if (inode->i_blocks) {
+ int err;
+ bh = ufs_bread (inode, 0, 0, &err);
+ if (!bh) {
+ if(err < 0) /* indicate type of error */
+ return err;
+ return 0;
+ }
+ link = bh->b_data;
+ }
+ /* fast symlink */
+ else {
+ link = (char *) inode->u.ufs_i.i_u1.i_symlink;
+ }
+ i = 0;
+ while (i < buflen && link[i])
+ i++;
+ if (copy_to_user(buffer, link, i))
+ i = -EFAULT;
+ UPDATE_ATIME(inode);
+ if (bh)
+ brelse (bh);
+ UFSD(("ENTER\n"))
+ return i;
+}
+
+struct inode_operations ufs_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ ufs_readlink, /* readlink */
+ ufs_follow_link, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
new file mode 100644
index 000000000..c6dca7358
--- /dev/null
+++ b/fs/ufs/truncate.c
@@ -0,0 +1,473 @@
+/*
+ * linux/fs/ufs/truncate.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ *
+ * from
+ *
+ * linux/fs/ext2/truncate.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/truncate.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/string.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_TRUNCATE_DEBUG
+
+#ifdef UFS_TRUNCATE_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+/*
+ * Secure deletion currently doesn't work. It interacts very badly
+ * with buffers shared with memory mappings, and for that reason
+ * can't be done in the truncate() routines. It should instead be
+ * done separately in "release()" before calling the truncate routines
+ * that will release the actual file blocks.
+ *
+ * Linus
+ */
+
+#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize)
+#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
+
+static int ufs_trunc_direct (struct inode * inode)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * bh;
+ u32 * p;
+ unsigned frag1, frag2, frag3, frag4, block1, block2;
+ unsigned frag_to_free, free_count;
+ unsigned i, j, tmp;
+ int retry;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ frag_to_free = 0;
+ free_count = 0;
+ retry = 0;
+
+ frag1 = DIRECT_FRAGMENT;
+ frag4 = min (UFS_NDIR_FRAGMENT, inode->u.ufs_i.i_lastfrag);
+ frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
+ frag3 = frag4 & ~uspi->s_fpbmask;
+ block1 = block2 = 0;
+ if (frag2 > frag3) {
+ frag2 = frag4;
+ frag3 = frag4 = 0;
+ }
+ else if (frag2 < frag3) {
+ block1 = ufs_fragstoblks (frag2);
+ block2 = ufs_fragstoblks (frag3);
+ }
+
+ UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4))
+
+ if (frag1 >= frag2)
+ goto next1;
+
+ /*
+ * Free first free fragments
+ */
+ p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag1);
+ tmp = SWAB32(*p);
+ if (!tmp )
+ ufs_panic (sb, "ufs_trunc_direct", "internal error");
+ frag1 = ufs_fragnum (frag1);
+ frag2 = ufs_fragnum (frag2);
+ for (j = frag1; j < frag2; j++) {
+ bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+ if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+ retry = 1;
+ brelse (bh);
+ goto next1;
+ }
+ bforget (bh);
+ }
+ inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
+ mark_inode_dirty(inode);
+ ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+ frag_to_free = tmp + frag1;
+
+next1:
+ /*
+ * Free whole blocks
+ */
+ for (i = block1 ; i < block2; i++) {
+ p = inode->u.ufs_i.i_u1.i_data + i;
+ tmp = SWAB32(*p);
+ if (!tmp)
+ continue;
+ for (j = 0; j < uspi->s_fpb; j++) {
+ bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+ if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+ retry = 1;
+ brelse (bh);
+ goto next2;
+ }
+ bforget (bh);
+ }
+ *p = SWAB32(0);
+ inode->i_blocks -= uspi->s_nspb;
+ mark_inode_dirty(inode);
+ if (free_count == 0) {
+ frag_to_free = tmp;
+ free_count = uspi->s_fpb;
+ } else if (free_count > 0 && frag_to_free == tmp - free_count)
+ free_count += uspi->s_fpb;
+ else {
+ ufs_free_blocks (inode, frag_to_free, free_count);
+ frag_to_free = tmp;
+ free_count = uspi->s_fpb;
+ }
+next2:
+ }
+
+ if (free_count > 0)
+ ufs_free_blocks (inode, frag_to_free, free_count);
+
+ if (frag3 >= frag4)
+ goto next3;
+
+ /*
+ * Free last free fragments
+ */
+ p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag3);
+ tmp = SWAB32(*p);
+ if (!tmp )
+ ufs_panic(sb, "ufs_truncate_direct", "internal error");
+ frag4 = ufs_fragnum (frag4);
+ for (j = 0; j < frag4; j++) {
+ bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+ if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+ retry = 1;
+ brelse (bh);
+ goto next1;
+ }
+ bforget (bh);
+ }
+ *p = SWAB32(0);
+ inode->i_blocks -= frag4 << uspi->s_nspfshift;
+ mark_inode_dirty(inode);
+ ufs_free_fragments (inode, tmp, frag4);
+ next3:
+
+ UFSD(("EXIT\n"))
+ return retry;
+}
+
+
+static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * ind_ubh;
+ struct buffer_head * bh;
+ u32 * ind;
+ unsigned indirect_block, i, j, tmp;
+ unsigned frag_to_free, free_count;
+ int retry;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ frag_to_free = 0;
+ free_count = 0;
+ retry = 0;
+
+ tmp = SWAB32(*p);
+ if (!tmp)
+ return 0;
+ ind_ubh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+ if (tmp != SWAB32(*p)) {
+ ubh_brelse (ind_ubh);
+ return 1;
+ }
+ if (!ind_ubh) {
+ *p = SWAB32(0);
+ return 0;
+ }
+
+ indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0;
+ for (i = indirect_block; i < uspi->s_apb; i++) {
+ ind = ubh_get_addr32 (ind_ubh, i);
+ tmp = SWAB32(*ind);
+ if (!tmp)
+ continue;
+ for (j = 0; j < uspi->s_fpb; j++) {
+ bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+ if ((bh && bh->b_count != 1) || tmp != SWAB32(*ind)) {
+ retry = 1;
+ brelse (bh);
+ goto next;
+ }
+ bforget (bh);
+ }
+ *ind = SWAB32(0);
+ ubh_mark_buffer_dirty(ind_ubh, 1);
+ if (free_count == 0) {
+ frag_to_free = tmp;
+ free_count = uspi->s_fpb;
+ } else if (free_count > 0 && frag_to_free == tmp - free_count)
+ free_count += uspi->s_fpb;
+ else {
+ ufs_free_blocks (inode, frag_to_free, free_count);
+ frag_to_free = tmp;
+ free_count = uspi->s_fpb;
+ }
+ inode->i_blocks -= uspi->s_nspb;
+ mark_inode_dirty(inode);
+next:
+ }
+
+ if (free_count > 0) {
+ ufs_free_blocks (inode, frag_to_free, free_count);
+ }
+ for (i = 0; i < uspi->s_apb; i++)
+ if (SWAB32(*ubh_get_addr32(ind_ubh,i)))
+ break;
+ if (i >= uspi->s_apb) {
+ if (ubh_max_bcount(ind_ubh) != 1) {
+ retry = 1;
+ }
+ else {
+ tmp = SWAB32(*p);
+ *p = SWAB32(0);
+ inode->i_blocks -= uspi->s_nspb;
+ mark_inode_dirty(inode);
+ ufs_free_blocks (inode, tmp, uspi->s_fpb);
+ ubh_bforget(ind_ubh);
+ ind_ubh = NULL;
+ }
+ }
+ if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
+ ubh_ll_rw_block (WRITE, 1, &ind_ubh);
+ ubh_wait_on_buffer (ind_ubh);
+ }
+ ubh_brelse (ind_ubh);
+
+ UFSD(("EXIT\n"))
+
+ return retry;
+}
+
+static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * dind_bh;
+ unsigned i, tmp, dindirect_block;
+ u32 * dind;
+ int retry = 0;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ dindirect_block = (DIRECT_BLOCK > offset)
+ ? ((DIRECT_BLOCK - offset) / uspi->s_apb) : 0;
+ retry = 0;
+
+ tmp = SWAB32(*p);
+ if (!tmp)
+ return 0;
+ dind_bh = ubh_bread (inode->i_dev, tmp, uspi->s_bsize);
+ if (tmp != SWAB32(*p)) {
+ ubh_brelse (dind_bh);
+ return 1;
+ }
+ if (!dind_bh) {
+ *p = SWAB32(0);
+ return 0;
+ }
+
+ for (i = dindirect_block ; i < uspi->s_apb ; i++) {
+ dind = ubh_get_addr32 (dind_bh, i);
+ tmp = SWAB32(*dind);
+ if (!tmp)
+ continue;
+ retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind);
+ ubh_mark_buffer_dirty(dind_bh, 1);
+ }
+
+ for (i = 0; i < uspi->s_apb; i++)
+ if (SWAB32(*ubh_get_addr32 (dind_bh, i)))
+ break;
+ if (i >= uspi->s_apb) {
+ if (ubh_max_bcount(dind_bh) != 1)
+ retry = 1;
+ else {
+ tmp = SWAB32(*p);
+ *p = SWAB32(0);
+ inode->i_blocks -= uspi->s_nspb;
+ mark_inode_dirty(inode);
+ ufs_free_blocks (inode, tmp, uspi->s_fpb);
+ ubh_bforget(dind_bh);
+ dind_bh = NULL;
+ }
+ }
+ if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
+ ubh_ll_rw_block (WRITE, 1, &dind_bh);
+ ubh_wait_on_buffer (dind_bh);
+ }
+ ubh_brelse (dind_bh);
+
+ UFSD(("EXIT\n"))
+
+ return retry;
+}
+
+static int ufs_trunc_tindirect (struct inode * inode)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * tind_bh;
+ unsigned tindirect_block, tmp, i;
+ u32 * tind, * p;
+ int retry;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ sb = inode->i_sb;
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+ retry = 0;
+
+ tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
+ ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) / uspi->s_2apb) : 0;
+ p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
+ if (!(tmp = SWAB32(*p)))
+ return 0;
+ tind_bh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+ if (tmp != SWAB32(*p)) {
+ ubh_brelse (tind_bh);
+ return 1;
+ }
+ if (!tind_bh) {
+ *p = SWAB32(0);
+ return 0;
+ }
+
+ for (i = tindirect_block ; i < uspi->s_apb ; i++) {
+ tind = ubh_get_addr32 (tind_bh, i);
+ retry |= ufs_trunc_dindirect(inode, UFS_NDADDR +
+ uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind);
+ ubh_mark_buffer_dirty(tind_bh, 1);
+ }
+ for (i = 0; i < uspi->s_apb; i++)
+ if (SWAB32(*ubh_get_addr32 (tind_bh, i)))
+ break;
+ if (i >= uspi->s_apb) {
+ if (ubh_max_bcount(tind_bh) != 1)
+ retry = 1;
+ else {
+ tmp = SWAB32(*p);
+ *p = SWAB32(0);
+ inode->i_blocks -= uspi->s_nspb;
+ mark_inode_dirty(inode);
+ ufs_free_blocks (inode, tmp, uspi->s_fpb);
+ ubh_bforget(tind_bh);
+ tind_bh = NULL;
+ }
+ }
+ if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
+ ubh_ll_rw_block (WRITE, 1, &tind_bh);
+ ubh_wait_on_buffer (tind_bh);
+ }
+ ubh_brelse (tind_bh);
+
+ UFSD(("EXIT\n"))
+ return retry;
+}
+
+void ufs_truncate (struct inode * inode)
+{
+ struct super_block * sb;
+ struct ufs_sb_private_info * uspi;
+ struct buffer_head * bh;
+ unsigned offset;
+ int err, retry;
+
+ UFSD(("ENTER\n"))
+ sb = inode->i_sb;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+ while (1) {
+ retry = ufs_trunc_direct(inode);
+ retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK,
+ (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]);
+ retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb,
+ (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]);
+ retry |= ufs_trunc_tindirect (inode);
+ if (!retry)
+ break;
+ if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
+ ufs_sync_inode (inode);
+ current->counter = 0;
+ schedule ();
+
+
+ }
+ offset = inode->i_size & uspi->s_fshift;
+ if (offset) {
+ bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
+ if (bh) {
+ memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
+ mark_buffer_dirty (bh, 0);
+ brelse (bh);
+ }
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+ mark_inode_dirty(inode);
+ UFSD(("EXIT\n"))
+}
diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c
deleted file mode 100644
index 7471156a0..000000000
--- a/fs/ufs/ufs_file.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * linux/fs/ufs/ufs_file.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * $Id: ufs_file.c,v 1.9 1997/07/17 02:24:13 davem Exp $
- *
- */
-
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-
-static struct file_operations ufs_file_operations = {
- NULL, /* lseek */
- generic_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* release */
- file_fsync, /* fsync */
- NULL, /* fasync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
-};
-
-struct inode_operations ufs_file_inode_operations = {
- &ufs_file_operations, /* default directory file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- generic_readpage, /* readpage */
- NULL, /* writepage */
- ufs_bmap, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
-};
-
diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c
deleted file mode 100644
index 2011a0be8..000000000
--- a/fs/ufs/ufs_inode.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * linux/fs/ufs/ufs_inode.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * 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>
-
-#include "ufs_swab.h"
-
-void ufs_print_inode(struct inode * inode)
-{
- printk("ino %lu mode 0%6.6o lk %d uid %d gid %d"
- " sz %lu blks %lu cnt %u\n",
- inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
- 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_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_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_u1.i_data[(nr)])
-
-static inline int block_bmap (struct inode *inode, int block, int nr)
-{
- struct buffer_head *bh;
- int tmp;
- __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, 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;
- tmp = SWAB32(((__u32 *)bh->b_data)[nr]);
- brelse (bh);
- return tmp;
-}
-
-int ufs_bmap (struct inode * inode, int block)
-{
- int i;
- int addr_per_block = UFS_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = UFS_ADDR_PER_BLOCK_BITS(inode->i_sb);
- int lbn = ufs_lbn (inode->i_sb, block);
- int boff = ufs_boff (inode->i_sb, block);
-
- if (lbn < 0) {
- ufs_warning (inode->i_sb, "ufs_bmap", "block < 0");
- return 0;
- }
- if (lbn >= UFS_NDADDR + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ufs_warning (inode->i_sb, "ufs_bmap", "block > big");
- return 0;
- }
- if (lbn < UFS_NDADDR)
- 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 (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))) {
- i = inode_bmap (inode, UFS_DIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (inode, i, lbn >> addr_per_block_bits);
- if (!i)
- return 0;
- return (inode->i_sb->u.ufs_sb.s_blockbase +
- ufs_dbn (inode->i_sb,
- block_bmap (inode, i, lbn & (addr_per_block-1)),
- boff));
- }
- lbn -= (1 << (addr_per_block_bits * 2));
- i = inode_bmap (inode, UFS_TIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (inode, i, lbn >> (addr_per_block_bits * 2));
- if (!i)
- return 0;
- i = block_bmap (inode, i,
- (lbn >> addr_per_block_bits) & (addr_per_block - 1));
- if (!i)
- return 0;
- 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 */
-void ufs_read_inode(struct inode * inode)
-{
- struct super_block * sb;
- struct ufs_inode * ufsip;
- struct buffer_head * bh;
- __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\n", inode->i_ino);
-
- return;
- }
-
-#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),
- sb->s_blocksize);
- if (!bh) {
- 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;
- }
-
- ufsip = (struct ufs_inode *)bh->b_data;
- ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag));
-
- /*
- * Copy data to the in-core inode.
- */
- inode->i_mode = SWAB16(ufsip->ui_mode);
- inode->i_nlink = SWAB16(ufsip->ui_nlink);
- if (inode->i_nlink == 0) {
- /* XXX */
- printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n",
- inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
- inode->i_nlink = 1;
- printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n",
- inode->i_ino,
- ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
- (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
- MAJOR(inode->i_dev), MINOR(inode->i_dev));
- }
- /* XXX - debugging */
- if (SWAB32(ufsip->ui_gen) == 0) {
- printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n",
- inode->i_ino,
- ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
- (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
- MAJOR(inode->i_dev), MINOR(inode->i_dev));
- }
- /*
- * Since Linux currently only has 16-bit uid_t and gid_t, we can't
- * really support EFTs. For the moment, we use 0 as the uid and gid
- * if an inode has a uid or gid that won't fit in 16 bits. This way
- * random users can't get at these files, since they get dynamically
- * "chown()ed" to root.
- */
- 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",
- UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
- MINOR(inode->i_dev), inode->i_uid);
- } else {
- inode->i_uid = UFS_UID(ufsip);
- }
- 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",
- UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
- MINOR(inode->i_dev), inode->i_gid);
- } else {
- inode->i_gid = UFS_GID(ufsip);
- }
-
- /*
- * Linux i_size is 32 bits on most architectures,
- * so some files on a UFS filesystem may not
- * be readable. I let people access the first 32 bits worth of them.
- * for the rw code, we may want to mark these inodes as read-only.
- * XXX - bug Linus to make i_size a __u64 instead of a __u32.
- */
- inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size);
- /* KRR - Just type cast inode->u.ufs_i.i_size into off_t and
- * worry about overflow later
- */
- inode->i_size = (off_t)inode->u.ufs_i.i_size;
-
- /*
- * Linux doesn't keep tv_usec around in the kernel, so we discard it.
- * XXX - I'm not sure what I should do about writing things. I may
- * want to keep this data, but for the moment I think I'll just write
- * zeros for these fields when writing out inodes.
- */
- inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec);
- inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec);
- inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec);
- inode->i_blksize = sb->u.ufs_sb.s_fsize;
- inode->i_blocks = SWAB32(ufsip->ui_blocks);
- inode->i_version = ++event; /* see linux/kernel/sched.c */
-
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &ufs_file_inode_operations;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ufs_dir_inode_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &ufs_symlink_inode_operations;
- } else if (S_ISCHR(inode->i_mode)) {
- inode->i_op = &chrdev_inode_operations;
- } else if (S_ISBLK(inode->i_mode)) {
- inode->i_op = &blkdev_inode_operations;
- } else if (S_ISFIFO(inode->i_mode)) {
- init_fifo(inode);
- } else {
- printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n",
- inode->i_mode, inode->i_ino, MAJOR(inode->i_dev),
- MINOR(inode->i_dev));
- /* XXX - debugging */
- ufs_print_inode(inode);
- inode->i_op = &ufs_file_inode_operations;
- }
-
- /*
- * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane.
- */
- if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)) {
- int 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
- * being, I'm going to tread ui_db[0] and [1] as a __u64 and swab
- * them appropriately. This should clean up any real endian problems,
- * but we'll still need to add size checks in the write portion of
- * the code.
- */
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db);
- }
-
- 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_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);
-
- if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
- ufs_print_inode(inode);
- }
-
- return;
-}
-
-void ufs_put_inode (struct inode * inode)
-{
- if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
- printk("ufs_put_inode:\n");
- ufs_print_inode(inode);
- }
-
- if (inode->i_nlink)
- return;
-
- printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n",
- inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
- ufs_print_inode(inode);
- panic("ufs_put_inode: fs is read only, and nlink == 0");
-
- /* XXX - this code goes here eventually
- inode->i_size = 0;
- if (inode->i_blocks)
- ufs_truncate(inode);
- ufs_free_inode(inode);
- */
-
- return;
-}
diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c
deleted file mode 100644
index 021b85442..000000000
--- a/fs/ufs/ufs_namei.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * linux/fs/ufs/ufs_namei.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * 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>
-#include <linux/ufs_fs.h>
-#include <linux/string.h>
-#include "ufs_swab.h"
-
-/*
- * 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 flags)
-{
- if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
- return 0;
- /*
- * "" means "." ---> so paths like "/usr/lib//libc.a" work
- */
- if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') &&
- (d->d_name[1] == '\0'))
- return 1;
- if (len != NAMLEN(d))
- return 0;
- return !memcmp(name, d->d_name, len);
-}
-
-int ufs_lookup (struct inode *dir, struct dentry *dentry)
-{
- /* XXX - this is all fucked up! */
- 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 flags;
- struct inode *inode;
-
- /* XXX - isn't that already done by the upper layer? */
- if (!dir || !S_ISDIR(dir->i_mode))
- return -EBADF;
-
- flags = sb->u.ufs_sb.s_flags;
-
- 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)) {
- sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
- printk("UFS debugging %s\n",
- (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
- */
- if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
- (dir->i_ino == UFS_ROOTINO)) {
- sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
- printk("UFS inode debugging %s\n",
- (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)) {
- sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
- printk("UFS namei debugging %s\n",
- (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)) {
- sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
- printk("UFS symlink debugging %s\n",
- (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
- "on": "off");
- goto not_found;
- /*return(-ENOENT);*/
- }
-
- /* Now for the real thing */
-
- if (flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
- printk("ufs_lookup: called for ino %lu name %s\n",
- dir->i_ino, name);
- }
-
- 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 */
- if (flags & UFS_DEBUG) {
- printk("ufs_lookup: ino %lu lfragno %lu fragno %lu\n",
- dir->i_ino, lfragno, fragno);
- }
- if (fragno == 0) {
- /* XXX - bug bug bug */
- goto not_found;
- /*return(-ENOENT);*/
- }
- bh = bread(dir->i_dev, fragno, sb->s_blocksize);
- if (bh == NULL) {
- printk("ufs_lookup: bread failed: "
- "ino %lu, lfragno %lu",
- dir->i_ino, lfragno);
- return(-EIO);
- }
- d = (struct ufs_direct *)(bh->b_data);
- while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <=
- sb->s_blocksize) {
- /* XXX - skip block if d_reclen or d_namlen is 0 */
- if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) {
- /* no need to SWAB16(): test against 0 */
- if (flags & UFS_DEBUG) {
- printk("ufs_lookup: skipped space in directory, ino %lu\n",
- dir->i_ino);
- }
- break;
- }
- if (flags & UFS_DEBUG) {
- printk("lfragno 0x%lx "
- "direct d 0x%x "
- "d_ino %u "
- "d_reclen %u "
- "d_namlen %u d_name `%s'\n",
- lfragno,
- (unsigned int)((unsigned long)d),
- SWAB32(d->d_ino),
- SWAB16(d->d_reclen),
- NAMLEN(d),d->d_name);
- }
- if ((NAMLEN(d) == len) &&
- /* XXX - don't use strncmp() - see ext2fs */
- (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(sb, SWAB32(d->d_ino));
- brelse(bh);
- if(!inode) { return -EACCES; }
- d_add(dentry,inode);
- return(0);
- } else {
- /* XXX - bounds checking */
- if (flags & UFS_DEBUG) {
- printk("ufs_lookup: "
- "wanted (%s,%d) got (%s,%d)\n",
- name, len,
- d->d_name, NAMLEN(d));
- }
- }
- d = (struct ufs_direct *)((char *)d +
- SWAB16(d->d_reclen));
- }
- brelse(bh);
- }
- not_found:
- d_add(dentry,NULL);
- return(0);
-}
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
deleted file mode 100644
index 7fdac8dd6..000000000
--- a/fs/ufs/ufs_super.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * linux/fs/ufs/ufs_super.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- *
- */
-
-/*
- * Kernel module support added on 96/04/26 by
- * Stefan Reinauer <stepan@home.culture.mipt.ru>
- *
- * Module usage counts added on 96/04/29 by
- * Gertjan van Wingerde <gertjan@cs.vu.nl>
- *
- * 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_SUPER
-/*#define DEBUG_UFS_SUPER 1*/
-/* Uncomment the line above when hacking ufs superblock code */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/locks.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-#include "ufs_swab.h"
-
-struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent);
-void ufs_put_super (struct super_block * sb);
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize);
-
-static struct super_operations ufs_super_ops = {
- ufs_read_inode,
- NULL, /* XXX - ufs_write_inode() */
- ufs_put_inode,
- NULL, /* XXX - ufs_delete_inode() */
- NULL, /* XXX - notify_change() */
- ufs_put_super,
- NULL, /* XXX - ufs_write_super() */
- ufs_statfs,
- NULL, /* XXX - ufs_remount() */
-};
-
-static struct file_system_type ufs_fs_type = {
- "ufs",
- FS_REQUIRES_DEV,
- ufs_read_super,
- NULL
-};
-
-__initfunc(int init_ufs_fs(void))
-{
- return(register_filesystem(&ufs_fs_type));
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
- return init_ufs_fs();
-}
-
-void cleanup_module(void)
-{
- unregister_filesystem(&ufs_fs_type);
-}
-#endif
-
-static char error_buf[1024];
-
-void ufs_warning (struct super_block * sb, const char * function,
- const char * fmt, ...)
-{
- va_list args;
-
- va_start (args, fmt);
- vsprintf (error_buf, fmt, args);
- va_end (args);
- printk (KERN_WARNING "UFS warning (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
-}
-
-#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_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_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;
-}
-#endif
-
-struct super_block *
-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 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()
- *
- * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
- * and s_type when we return.
- */
-
- 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;
-
- 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);
-
- brelse(bh1);
- brelse(bh2);
-
- 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 != 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 != 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: 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;
- }
-
-#ifdef DEBUG_UFS_SUPER
- 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_FSOSF1: /* 0x03 */
- /* XXX is this correct for DEC OSF/1? */
-#ifdef DEBUG_UFS_SUPER
- printk("ufs_read_super: fs is clean and stable (OSF/1)\n");
-#endif
- 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) */
- }
-
- /* XXX - sanity check sb fields */
-
- /* KRR - Why are we not using fs_bsize for blocksize? */
- sb->s_blocksize = usb->fs_fsize;
- sb->s_blocksize_bits = usb->fs_fshift;
- /* XXX - sb->s_lock */
- sb->s_op = &ufs_super_ops;
- sb->dq_op = 0; /* XXX */
- sb->s_magic = usb->fs_magic;
- /* sb->s_time */
- /* 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 = 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;
- sb->u.ufs_sb.s_fsize = usb->fs_fsize;
- sb->u.ufs_sb.s_fmask = usb->fs_fmask;
- sb->u.ufs_sb.s_fshift = usb->fs_fshift;
- sb->u.ufs_sb.s_bsize = usb->fs_bsize;
- sb->u.ufs_sb.s_bmask = usb->fs_bmask;
- sb->u.ufs_sb.s_bshift = usb->fs_bshift;
- sb->u.ufs_sb.s_iblkno = usb->fs_iblkno;
- sb->u.ufs_sb.s_dblkno = usb->fs_dblkno;
- sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset;
- sb->u.ufs_sb.s_cgmask = usb->fs_cgmask;
- sb->u.ufs_sb.s_inopb = usb->fs_inopb;
- sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift;
- 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
- printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
-#endif
- /*
- * XXX - read cg structs?
- */
-
- unlock_super(sb);
- return(sb);
-
-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;
- return(NULL);
-}
-
-void ufs_put_super (struct super_block * sb)
-{
- if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("ufs_put_super\n"); /* XXX */
- }
-
-
- /* XXX - sync fs data, set state to ok, and flush buffers */
- set_blocksize (sb->s_dev, BLOCK_SIZE);
-
- /* XXX - free allocated kernel memory */
- /* includes freeing usb page */
-
- MOD_DEC_USE_COUNT;
-
- return;
-}
-
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
-{
- struct statfs tmp;
- struct statfs *sp = &tmp;
- struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb;
- /* fsb was already normalized during mounting */
- unsigned long used, avail;
-
- if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("ufs_statfs\n"); /* XXX */
- }
-
- sp->f_type = sb->s_magic;
- sp->f_bsize = sb->s_blocksize;
- sp->f_blocks = fsb->fs_dsize;
- sp->f_bfree = fsb->fs_cstotal.cs_nbfree *
- fsb->fs_frag +
- fsb->fs_cstotal.cs_nffree;
-
- avail = sp->f_blocks - (sp->f_blocks / 100) *
- fsb->fs_minfree;
- used = sp->f_blocks - sp->f_bfree;
- if (avail > used)
- sp->f_bavail = avail - used;
- else
- sp->f_bavail = 0;
-
- sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
- sp->f_ffree = fsb->fs_cstotal.cs_nifree;
- sp->f_fsid.val[0] = fsb->fs_id[0];
- sp->f_fsid.val[1] = fsb->fs_id[1];
- sp->f_namelen = UFS_MAXNAMLEN;
-
- return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
-}
diff --git a/fs/ufs/ufs_swab.c b/fs/ufs/ufs_swab.c
deleted file mode 100644
index 261d16de9..000000000
--- a/fs/ufs/ufs_swab.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * linux/fs/ufs/ufs_swab.c
- *
- * Copyright (C) 1997
- * Francois-Rene Rideau <rideau@ens.fr>
- *
- */
-
-/*
- * For inspiration, you might wanna check sys/ufs/ffs/fs.h from whateverBSD
- *
- * NOTES
- * 19970406 - Fare <rideau@ens.fr>
- * 1) I began from old very preliminary 2.0.x sources,
- * but it was underfeatured;
- * I later saw that 2.1.1 sources had a *global* UFS byteswap flag.
- * EVIL: imagine that a swabbed partition be mounted
- * while a non-swabbed partition are active (that sucks!)
- * I merged that source tree with mine.
- * 2) I hope no one is using obNNUUXXIIous byteorder.
- * That's the only thing I might have broken,
- * though I rather think it's a fix:
- * instead of __u64 like BSD,
- * the former driver used an explicitly bigendian array of __u32!
- * 3) I provide a few macros that use GCC C Extensions.
- * Port to other compilers would require avoiding them.
- * in any case, 64 bit (long long) support is required,
- * unless you're ready to workaround
- * 4) the swab routines below depend on the precise name and order
- * of the structure elements. Watch out any modification in ufs_fs.h!!!
- * 5) putting byteswapping stuff in ufs_swab* seems cleaner to me.
- * 6) These sources should work with both 2.0 and 2.1 kernels...
- *
- * 19971013 - Fare <rideaufr@issy.cnet.fr>
- * 1) Ported to 2.1.57
- * 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,
- * or copied to a buffer and globally bswap_ufs_*() there.
- *
- */
-
-#include <linux/fs.h>
-#include "ufs_swab.h"
-
-static __inline__ void n_be16_to_cpus(__u16*p,unsigned n) {
-#ifndef __BIG_ENDIAN
- unsigned i;
- for(i=0;i<n;i++) {
- be16_to_cpus(&p[i]);
- }
-#endif
-}
-static __inline__ void n_be32_to_cpus(__u32*p,unsigned n) {
-#ifndef __BIG_ENDIAN
- unsigned i;
- for(i=0;i<n;i++) {
- be32_to_cpus(&p[i]);
- }
-#endif
-}
-static __inline__ void n_le16_to_cpus(__u16*p,unsigned n) {
-#ifndef __LITTLE_ENDIAN
- unsigned i;
- for(i=0;i<n;i++) {
- le16_to_cpus(&p[i]);
- }
-#endif
-}
-static __inline__ void n_le32_to_cpus(__u32*p,unsigned n) {
-#ifndef __LITTLE_ENDIAN
- unsigned i;
- for(i=0;i<n;i++) {
- le32_to_cpus(&p[i]);
- }
-#endif
-}
-
-#define __length_before(p,member) \
- ((unsigned)(((char*)&((p)->member))-(char*)(p)))
-#define __length_since(p,member) \
- ((unsigned)(sizeof(*p)-__length_before(p,member)))
-#define __length_between(p,begin,after_end) \
- ((unsigned)(__length_before(p,after_end)-__length_before(p,begin)))
-#define be32_to_cpus__between(s,begin,after_end) \
- n_be32_to_cpus((__u32*)&((s).begin), \
- __length_between(&s,begin,after_end)/4)
-#define le32_to_cpus__between(s,begin,after_end) \
- n_le32_to_cpus((__u32*)&((s).begin), \
- __length_between(&s,begin,after_end)/4)
-#define be32_to_cpus__since(s,begin) \
- n_be32_to_cpus((__u32*)&((s).begin), \
- __length_since(&s,begin)/4)
-#define le32_to_cpus__since(s,begin) \
- n_le32_to_cpus((__u32*)&((s).begin), \
- __length_since(&s,begin)/4)
-#define be16_to_cpus__between(s,begin,after_end) \
- n_be16_to_cpus((__u16*)&((s).begin), \
- __length_between(&s,begin,after_end)/2)
-#define le16_to_cpus__between(s,begin,after_end) \
- n_le16_to_cpus((__u16*)&((s).begin), \
- __length_between(&s,begin,after_end)/2)
-
-/*
- * 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);
- 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);
- 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
deleted file mode 100644
index f8e9fd898..000000000
--- a/fs/ufs/ufs_swab.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * linux/fs/ufs/ufs_swab.h
- *
- * Copyright (C) 1997
- * Francois-Rene Rideau <rideau@ens.fr>
- *
- */
-
-#ifndef _UFS_SWAB_H
-#define _UFS_SWAB_H
-
-
-/*
- * Notes:
- * (1) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes
- * in case there are ufs implementations that have strange bytesexes,
- * you'll need to modify code here as well as in ufs_super.c and ufs_fs.h
- * 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 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(flags,x)
-#define SWAB32(x) ufs_swab32(flags,x)
-#define SWAB64(x) ufs_swab64(flags,x)
-
-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 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 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
deleted file mode 100644
index e19abe44d..000000000
--- a/fs/ufs/ufs_symlink.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * linux/fs/ufs/ufs_symlink.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * 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>
-#include <linux/ufs_fs.h>
-#include <linux/sched.h>
-
-#include <asm/uaccess.h>
-
-extern int ufs_bmap (struct inode *, int);
-
-static int
-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 (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));
- }
-
- if (!S_ISLNK(inode->i_mode)) {
- return -EINVAL;
- }
-
- if (buflen > sb->s_blocksize - 1)
- buflen = sb->s_blocksize - 1;
- if (inode->i_blocks) {
- /* XXX - error checking */
- block = ufs_bmap(inode, 0);
- 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, 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),
- MINOR(inode->i_dev));
- return 0;
- }
- link = bh->b_data;
- /* no need to bswap */
- } else /* fast symlink */ {
- link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
- }
- i = 0;
- while (i < buflen && (c = link[i])) {
- i++;
- put_user (c, buffer++);
- }
- brelse (bh);
- return i;
-}
-
-/*
- * XXX - blatantly stolen from minix fs
- */
-static struct dentry *
-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;
-
- if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
- printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
- inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
- }
-
- if (inode->i_blocks) {
- /* read the link from disk */
- /* XXX - error checking */
- block = ufs_bmap(inode, 0);
- 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),
- MINOR(inode->i_dev));
- dput(base);
- return ERR_PTR(-EIO);
- }
- link = bh->b_data;
- } else /* fast symlink */ {
- link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
- }
- base = lookup_dentry(link, base, 1);
- brelse (bh);
- return base;
-}
-
-
-static struct file_operations ufs_symlink_operations = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* release */
- NULL, /* fsync */ /* XXX - is this ok? */
- NULL, /* fasync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
-};
-
-struct inode_operations ufs_symlink_inode_operations = {
- &ufs_symlink_operations, /* default directory file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- &ufs_readlink, /* readlink */
- &ufs_follow_link, /* follow_link */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
-};
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
new file mode 100644
index 000000000..a0348c6f4
--- /dev/null
+++ b/fs/ufs/util.c
@@ -0,0 +1,197 @@
+/*
+ * linux/fs/ufs/util.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ */
+
+#include <linux/malloc.h>
+#include <linux/locks.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_UTILS_DEBUG
+
+#ifdef UFS_UTILS_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
+ kdev_t dev, unsigned fragment, unsigned size)
+{
+ struct ufs_buffer_head * ubh;
+ unsigned i, j, count;
+ if (size & ~uspi->s_fmask)
+ return NULL;
+ count = size >> uspi->s_fshift;
+ if (count > UFS_MAXFRAG)
+ return NULL;
+ ubh = (struct ufs_buffer_head *)
+ kmalloc (sizeof (struct ufs_buffer_head), GFP_KERNEL);
+ if (!ubh)
+ return NULL;
+ ubh->fragment = fragment;
+ ubh->count = count;
+ for (i = 0; i < count; i++)
+ if (!(ubh->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+ goto failed;
+ for (; i < UFS_MAXFRAG; i++)
+ ubh->bh[i] = NULL;
+ return ubh;
+failed:
+ for (j = 0; j < i; j++)
+ brelse (ubh->bh[j]);
+ return NULL;
+}
+
+struct ufs_buffer_head * _ubh_bread2_ (struct ufs_sb_private_info * uspi,
+ kdev_t dev, unsigned fragment, unsigned size)
+{
+ unsigned i, j, count;
+ if (size & ~uspi->s_fmask)
+ return NULL;
+ count = size >> uspi->s_fshift;
+ if (count <= 0 || count > UFS_MAXFRAG)
+ return NULL;
+ USPI_UBH->fragment = fragment;
+ USPI_UBH->count = count;
+ for (i = 0; i < count; i++)
+ if (!(USPI_UBH->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+ goto failed;
+ for (; i < UFS_MAXFRAG; i++)
+ USPI_UBH->bh[i] = NULL;
+ return USPI_UBH;
+failed:
+ for (j = 0; j < i; j++)
+ brelse (USPI_UBH->bh[j]);
+ return NULL;
+}
+
+void ubh_brelse (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for (i = 0; i < ubh->count; i++)
+ brelse (ubh->bh[i]);
+ kfree (ubh);
+}
+
+void ubh_brelse2 (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < ubh->count; i++ ) {
+ brelse (ubh->bh[i]);
+ ubh->bh[i] = NULL;
+ }
+}
+
+void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh, int flag)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < ubh->count; i++ )
+ mark_buffer_dirty (ubh->bh[i], flag);
+}
+
+void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < ubh->count; i++ )
+ mark_buffer_uptodate (ubh->bh[i], flag);
+}
+
+void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < nr; i++ )
+ ll_rw_block (rw, ubh[i]->count, ubh[i]->bh);
+}
+
+void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < ubh->count; i++ )
+ wait_on_buffer (ubh->bh[i]);
+}
+
+unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ unsigned max = 0;
+ if (!ubh)
+ return 0;
+ for ( i = 0; i < ubh->count; i++ )
+ if ( ubh->bh[i]->b_count > max )
+ max = ubh->bh[i]->b_count;
+ if (max == 0)
+ printk("Je cosi shnileho v kralovstvi Danskem!\n");
+ return max;
+}
+
+void ubh_bforget (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ if (!ubh)
+ return;
+ for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] )
+ bforget (ubh->bh[i]);
+}
+
+int ubh_buffer_dirty (struct ufs_buffer_head * ubh)
+{
+ unsigned i;
+ unsigned result = 0;
+ if (!ubh)
+ return 0;
+ for ( i = 0; i < ubh->count; i++ )
+ result |= buffer_dirty(ubh->bh[i]);
+ return result;
+}
+
+void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi,
+ unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size)
+{
+ unsigned len, bhno;
+ if ( size > (ubh->count << uspi->s_fshift) )
+ size = ubh->count << uspi->s_fshift;
+ bhno = 0;
+ while ( size ) {
+ len = min (size, uspi->s_fsize);
+ memcpy (mem, ubh->bh[bhno]->b_data, len);
+ mem += uspi->s_fsize;
+ size -= len;
+ bhno++;
+ }
+}
+
+void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi,
+ struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size)
+{
+ unsigned len, bhno;
+ if ( size > (ubh->count << uspi->s_fshift) )
+ size = ubh->count << uspi->s_fshift;
+ bhno = 0;
+ while ( size ) {
+ len = min (size, uspi->s_fsize);
+ memcpy (ubh->bh[bhno]->b_data, mem, len);
+ mem += uspi->s_fsize;
+ size -= len;
+ bhno++;
+ }
+}
+
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
new file mode 100644
index 000000000..8f5e66727
--- /dev/null
+++ b/fs/ufs/util.h
@@ -0,0 +1,322 @@
+/*
+ * linux/fs/ufs/util.h
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+#include <linux/fs.h>
+#include "swab.h"
+
+
+/*
+ * some usefull marcos
+ */
+#define in_range(b,first,len) ((b)>=(first)&&(b)<(first)+(len))
+#define howmany(x,y) (((x)+(y)-1)/(y))
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+
+/*
+ * current filesystem state; method depends on flags
+ */
+#define ufs_state(usb3) \
+ (((flags & UFS_ST_MASK) == UFS_ST_OLD) \
+ ? (usb3)->fs_u.fs_sun.fs_state /* old normal way */ \
+ : (usb3)->fs_u.fs_44.fs_state /* 4.4BSD way */)
+
+/*
+ * namlen, it's format depends of flags
+ */
+#define ufs_namlen(de) _ufs_namlen_(de,flags,swab)
+static inline __u16 _ufs_namlen_(struct ufs_dir_entry * de, unsigned flags, unsigned swab) {
+ if ((flags & UFS_DE_MASK) == UFS_DE_OLD) {
+ return SWAB16(de->d_u.d_namlen);
+ } else /* UFS_DE_44BSD */ {
+ return de->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).
+ */
+#define ufs_uid(inode) _ufs_uid_(inode,flags,swab)
+static inline __u32 _ufs_uid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+ switch (flags & UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ return SWAB32(inode->ui_u3.ui_sun.ui_uid);
+ case UFS_UID_44BSD:
+ return SWAB32(inode->ui_u3.ui_44.ui_uid);
+ case UFS_UID_OLD:
+ default:
+ return SWAB16(inode->ui_u1.oldids.ui_suid);
+ }
+}
+
+#define ufs_gid(inode) _ufs_gid_(inode,flags,swab)
+static inline __u32 _ufs_gid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+ switch (flags & UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ return SWAB32(inode->ui_u3.ui_sun.ui_gid);
+ case UFS_UID_44BSD:
+ return SWAB32(inode->ui_u3.ui_44.ui_gid);
+ case UFS_UID_OLD:
+ default:
+ return SWAB16(inode->ui_u1.oldids.ui_sgid);
+ }
+}
+
+/*
+ * marcros used for retyping
+ */
+#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
+#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+
+/*
+ * This functions manipulate with ufs_buffers
+ */
+#define ubh_bread(dev,fragment,size) _ubh_bread_(uspi,dev,fragment,size)
+extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+#define ubh_bread2(dev,fragment,size) _ubh_bread2_(uspi,dev,fragment,size)
+extern struct ufs_buffer_head * _ubh_bread2_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+extern void ubh_brelse (struct ufs_buffer_head *);
+extern void ubh_brelse2 (struct ufs_buffer_head *);
+extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int);
+extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
+extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
+extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
+extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
+extern void ubh_bforget (struct ufs_buffer_head *);
+extern int ubh_buffer_dirty (struct ufs_buffer_head *);
+#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
+extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struct ufs_buffer_head *, unsigned);
+#define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size)
+extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned);
+
+/*
+ * macros to get important structures from ufs_buffer_head
+ */
+#define ubh_get_usb_first(ubh) \
+ ((struct ufs_super_block_first *)((ubh)->bh[0]->b_data))
+
+#define ubh_get_usb_second(ubh) \
+ ((struct ufs_super_block_second *)(ubh)-> \
+ bh[SECTOR_SIZE >> uspi->s_fshift]->b_data + (SECTOR_SIZE & ~uspi->s_fmask))
+
+#define ubh_get_usb_third(ubh) \
+ ((struct ufs_super_block_third *)((ubh)-> \
+ bh[SECTOR_SIZE*2 >> uspi->s_fshift]->b_data + (SECTOR_SIZE*2 & ~uspi->s_fmask)))
+
+#define ubh_get_ucg(ubh) \
+ ((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data))
+
+/*
+ * Extract byte from ufs_buffer_head
+ * Extract the bits for a block from a map inside ufs_buffer_head
+ */
+#define ubh_get_addr8(ubh,begin) \
+ ((u8*)(ubh)->bh[(begin) >> uspi->s_fshift]->b_data + ((begin) & ~uspi->s_fmask))
+
+#define ubh_get_addr16(ubh,begin) \
+ (((u16*)((ubh)->bh[(begin) >> (uspi->s_fshift-1)]->b_data)) + ((begin) & (uspi->fsize>>1) - 1)))
+
+#define ubh_get_addr32(ubh,begin) \
+ (((u32*)((ubh)->bh[(begin) >> (BLOCK_SIZE_BITS-2)]->b_data)) + \
+ ((begin) & ((BLOCK_SIZE>>2) - 1)))
+
+#define ubh_get_addr ubh_get_addr8
+
+#define ubh_blkmap(ubh,begin,bit) \
+ ((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
+
+/*
+ * Macros for access to superblock array structures
+ */
+#define ubh_postbl(ubh,cylno,i) \
+ ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
+ ? (*(__s16*)(ubh_get_addr(ubh, \
+ (unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \
+ + (((cylno) * 16 + (i)) << 1) ) )) \
+ : (*(__s16*)(ubh_get_addr(ubh, \
+ uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) ))))
+
+#define ubh_rotbl(ubh,i) \
+ ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
+ ? (*(__u8*)(ubh_get_addr(ubh, \
+ (unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \
+ : (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i)))))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define ufs_freespace(usb, percentreserved) \
+ (ufs_blkstofrags(SWAB32((usb)->fs_cstotal.cs_nbfree)) + \
+ SWAB32((usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100))
+
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define ubh_cg_blktot(ucpi,cylno) \
+ (*((__u32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2))))
+
+#define ubh_cg_blks(ucpi,cylno,rpos) \
+ (*((__u16*)ubh_get_addr(UCPI_UBH, \
+ (ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 ))))
+
+/*
+ * Bitmap operation
+ * This functions work like classical bitmap operations. The diference
+ * is that we havn't the whole bitmap in one continuous part of memory,
+ * but in a few buffers.
+ * The parameter of each function is super_block, ufs_buffer_head and
+ * position of the begining of the bitmap.
+ */
+#define ubh_setbit(ubh,begin,bit) \
+ (*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) |= (1 << ((bit) & 7)))
+
+#define ubh_clrbit(ubh,begin,bit) \
+ (*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) &= ~(1 << ((bit) & 7)))
+
+#define ubh_isset(ubh,begin,bit) \
+ (*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) & (1 << ((bit) & 7)))
+
+#define ubh_isclr(ubh,begin,bit) (!ubh_isset(ubh,begin,bit))
+
+#define ubh_find_first_zero_bit(ubh,begin,size) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,0)
+#define ubh_find_next_zero_bit(ubh,begin,size,offset) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,offset)
+static inline unsigned _ubh_find_next_zero_bit_(
+ struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
+ unsigned begin, unsigned size, unsigned offset)
+{
+ unsigned base, rest;
+
+ begin <<= 3;
+ size += begin;
+ offset += begin;
+ base = offset >> (uspi->s_fshift + 3);
+ offset &= ((uspi->s_fsize << 3) - 1);
+ for (;;) {
+ rest = min (size, uspi->s_fsize << 3);
+ size -= rest;
+ offset = ext2_find_next_zero_bit (ubh->bh[base]->b_data, rest, offset);
+ if (offset < rest || !size)
+ break;
+ base++;
+ offset = 0;
+ }
+ return (base << (uspi->s_fshift + 3)) + offset - begin;
+}
+
+#define ubh_isblockclear(ubh,begin,block) (!_ubh_isblockset_(uspi,ubh,begin,block))
+#define ubh_isblockset(ubh,begin,block) _ubh_isblockset_(uspi,ubh,begin,block)
+static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
+ struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+ switch (uspi->s_fpb) {
+ case 8:
+ return (*ubh_get_addr (ubh, begin + block) == 0xff);
+ case 4:
+ return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
+ case 2:
+ return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1)));
+ case 1:
+ return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07)));
+ }
+ return 0;
+}
+
+#define ubh_clrblock(ubh,begin,block) _ubh_clrblock_(uspi,ubh,begin,block)
+static inline void _ubh_clrblock_(struct ufs_sb_private_info * uspi,
+ struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+ switch (uspi->s_fpb) {
+ case 8:
+ *ubh_get_addr (ubh, begin + block) = 0x00;
+ return;
+ case 4:
+ *ubh_get_addr (ubh, begin + (block >> 1)) &= ~(0x0f << ((block & 0x01) << 2));
+ return;
+ case 2:
+ *ubh_get_addr (ubh, begin + (block >> 2)) &= ~(0x03 << ((block & 0x03) << 1));
+ return;
+ case 1:
+ *ubh_get_addr (ubh, begin + (block >> 3)) &= ~(0x01 << ((block & 0x07)));
+ return;
+ }
+}
+
+#define ubh_setblock(ubh,begin,block) _ubh_setblock_(uspi,ubh,begin,block)
+static inline void _ubh_setblock_(struct ufs_sb_private_info * uspi,
+ struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+ switch (uspi->s_fpb) {
+ case 8:
+ *ubh_get_addr(ubh, begin + block) = 0xff;
+ return;
+ case 4:
+ *ubh_get_addr(ubh, begin + (block >> 1)) |= (0x0f << ((block & 0x01) << 2));
+ return;
+ case 2:
+ *ubh_get_addr(ubh, begin + (block >> 2)) |= (0x03 << ((block & 0x03) << 1));
+ return;
+ case 1:
+ *ubh_get_addr(ubh, begin + (block >> 3)) |= (0x01 << ((block & 0x07)));
+ return;
+ }
+}
+
+static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap,
+ unsigned * fraglist, int cnt)
+{
+ struct ufs_sb_private_info * uspi;
+ unsigned fragsize, pos;
+ unsigned swab;
+
+ swab = sb->u.ufs_sb.s_swab;
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ fragsize = 0;
+ for (pos = 0; pos < uspi->s_fpb; pos++) {
+ if (blockmap & (1 << pos)) {
+ fragsize++;
+ }
+ else if (fragsize > 0) {
+ ADD_SWAB32(fraglist[fragsize], cnt);
+ fragsize = 0;
+ }
+ }
+ if (fragsize > 0 && fragsize < uspi->s_fpb)
+ ADD_SWAB32(fraglist[fragsize], cnt);
+}
+
+#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
+static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
+ unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
+{
+ unsigned rest, offset;
+ unsigned char * cp;
+
+
+ offset = begin & ~uspi->s_fmask;
+ begin >>= uspi->s_fshift;
+ for (;;) {
+ if ((offset + size) < uspi->s_fsize)
+ rest = size;
+ else
+ rest = uspi->s_fsize - offset;
+ size -= rest;
+ cp = ubh->bh[begin]->b_data + offset;
+ while ((table[*cp++] & mask) == 0 && --rest);
+ if (rest || !size)
+ break;
+ begin++;
+ offset = 0;
+ }
+ return (size + rest);
+}