]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.112pre1 2.1.112pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:04 +0000 (15:16 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:04 +0000 (15:16 -0500)
42 files changed:
Documentation/Configure.help
Makefile
drivers/block/ide-floppy.c
drivers/block/ide.c
drivers/char/esp.c
drivers/scsi/ide-scsi.c
drivers/scsi/scsi.c
drivers/sound/msnd.c
drivers/sound/msnd_classic.h
drivers/sound/msnd_pinnacle.h
fs/Config.in
fs/ufs/Makefile
fs/ufs/acl.c [new file with mode: 0644]
fs/ufs/balloc.c [new file with mode: 0644]
fs/ufs/cylinder.c [new file with mode: 0644]
fs/ufs/dir.c [new file with mode: 0644]
fs/ufs/file.c [new file with mode: 0644]
fs/ufs/ialloc.c [new file with mode: 0644]
fs/ufs/inode.c [new file with mode: 0644]
fs/ufs/namei.c [new file with mode: 0644]
fs/ufs/super.c [new file with mode: 0644]
fs/ufs/swab.h [new file with mode: 0644]
fs/ufs/symlink.c [new file with mode: 0644]
fs/ufs/truncate.c [new file with mode: 0644]
fs/ufs/ufs_dir.c [deleted file]
fs/ufs/ufs_file.c [deleted file]
fs/ufs/ufs_inode.c [deleted file]
fs/ufs/ufs_namei.c [deleted file]
fs/ufs/ufs_super.c [deleted file]
fs/ufs/ufs_swab.c [deleted file]
fs/ufs/ufs_swab.h [deleted file]
fs/ufs/ufs_symlink.c [deleted file]
fs/ufs/util.c [new file with mode: 0644]
fs/ufs/util.h [new file with mode: 0644]
include/asm-i386/bugs.h
include/linux/nfsd/syscall.h
include/linux/ufs_fs.h
include/linux/ufs_fs_i.h
include/linux/ufs_fs_sb.h
init/main.c
kernel/sched.c
mm/swapfile.c

index 566474a03c50347ddf6177e8c87820dd0c458333..615a866e6a45b49f26e201fa80cbd360f46da41a 100644 (file)
@@ -1488,6 +1488,76 @@ CONFIG_FB
   If you want to play with it, say Y here and to the driver for your
   graphics board, below. If unsure, say N.
 
+Acorn VIDC support
+CONFIG_FB_ACORN
+  This is the frame buffer device driver for the Acorn VIDC graphics
+  chipset.
+
+Apollo frame buffer device
+CONFIG_FB_APOLLO
+  This is the frame buffer device driver for the monochrome graphics
+  hardware found in some Apollo workstations.
+
+Amiga native chipset support
+CONFIG_FB_AMIGA
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Amigas.
+
+Amiga OCS chipset support
+CONFIG_FB_AMIGA_OCS
+  This enables support for the original Agnus and Denise video chips,
+  found in the Amiga 1000 and most A500's and A2000's.  If you intend
+  to run Linux on any of these systems, say Y; otherwise say N.
+
+Amiga ECS chipset support
+CONFIG_FB_AMIGA_ECS
+  This enables support for the Enhanced Chip Set, found in later
+  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV.  If
+  you intend to run Linux on any of these systems, say Y; otherwise
+  say N.
+
+Amiga AGA chipset support
+CONFIG_FB_AMIGA_AGA
+  This enables support for the Advanced Graphics Architecture (also
+  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
+  and CD32.  If you intend to run Linux on any of these systems, say Y;
+  otherwise say N.
+
+Amiga CyberVision support
+CONFIG_FB_CYBER
+  This enables support for the Cybervision 64 graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64 or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the Cybervision 64 3D
+  card, as they use incompatible video chips.           
+
+Amiga CyberVision3D support (EXPERIMENTAL)
+CONFIG_FB_VIRGE
+  This enables support for the Cybervision 64/3D graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64/3D or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the older Cybervision 64
+  card, as they use incompatible video chips.           
+
+Amiga RetinaZ3 support (EXPERIMENTAL)
+CONFIG_FB_RETINAZ3
+  This enables support for the Retina Z3 graphics card. Say N unless you
+  have a Retina Z3 or plan to get one before you next recompile the kernel.
+
+Amiga CLgen driver (EXPERIMENTAL)
+CONFIG_FB_CLGEN
+  This enables support for Cirrus Logic GD542x/543x based boards on Amiga:
+  SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.  Say N
+  unless you have such a graphics board or plan to get one before you next
+  recompile the kernel.
+
+Atari native chipset support
+CONFIG_FB_ATARI
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Ataris.
+
 Open Firmware frame buffer device support 
 CONFIG_FB_OF
   Say Y if you want support with Open Firmware for your graphics board.
@@ -1500,6 +1570,31 @@ ATI Mach64 display support
 CONFIG_FB_ATY
   This driver supports graphics boards with the ATI Mach64 chips.
 
+PowerMac "control" frame buffer device support
+CONFIG_FB_CONTROL
+  This driver supports a frame buffer for the graphics adapter in the
+  Power Macintosh 7300 and others.
+
+PowerMac "platinum" frame buffer device support
+CONFIG_FB_PLATINUM
+  This driver supports a frame buffer for the "platinum" graphics adapter
+  in some Power Macintoshes.
+
+Chips 65550 display support
+CONFIG_FB_CT65550
+  This is the frame buffer device driver for the Chips & Technologies
+  65550 graphics chip in PowerBooks.
+
+Mac frame buffer device
+CONFIG_FB_MAC
+  This is the frame buffer device driver for the graphics hardware in
+  m68k Macintoshes.
+
+HP300 frame buffer device
+CONFIG_FB_HP300
+  This is the frame buffer device driver for the Topcat graphics
+  hardware found in HP300 workstations.
+
 VGA chipset support (text only)
 CONFIG_FB_VGA
   This is the frame buffer device driver for generic VGA chips. This
@@ -1530,38 +1625,143 @@ CONFIG_FB_MDA
   
   If unsure, say N.
 
-###
-### Somebody please explain the following options
-###
-# Virtual Frame Buffer support (ONLY FOR TESTING!)
-# CONFIG_FB_VIRTUAL
-#
-# Advanced low level driver options
-# CONFIG_FBCON_ADVANCED
-#
-# Monochrome support
-# CONFIG_FBCON_MFB
-#
-# 2 bpp packed pixels support
-# CONFIG_FBCON_CFB2
-#
-# 4 bpp packed pixels support
-# CONFIG_FBCON_CFB4
-#
-# 8 bpp packed pixels support
-# CONFIG_FBCON_CFB8
-#
-# 16 bpp packed pixels support
-# CONFIG_FBCON_CFB16
-#
-# 24 bpp packed pixels support
-# CONFIG_FBCON_CFB24
-#
-# 32 bpp packed pixels support
-# CONFIG_FBCON_CFB32
-#
-# VGA characters/attributes support
-# CONFIG_FBCON_VGA
+SBUS and UPA framebuffers
+CONFIG_FB_SBUS
+  Say Y if you want support for SBUS or UPA based frame buffer device.
+
+Creator/Creator3D support
+CONFIG_FB_CREATOR
+  This is the frame buffer device driver for the Creator and Creator3D
+  graphics boards.
+
+CGsix (GX,TurboGX) support
+CONFIG_FB_CGSIX
+  This is the frame buffer device driver for the CGsix (GX, TurboGX)
+  frame buffer.
+
+BWtwo support
+CONFIG_FB_BWTWO
+  This is the frame buffer device driver for the BWtwo frame buffer.
+
+CGthree support
+CONFIG_FB_CGTHREE
+  This is the frame buffer device driver for the CGthree frame buffer.
+
+TCX (SS4/SS5 only) support
+CONFIG_FB_TCX
+  This is the frame buffer device driver for the TCX 24/8bit frame buffer.
+
+Virtual Frame Buffer support (ONLY FOR TESTING!)
+CONFIG_FB_VIRTUAL
+  This is a `virtual' frame buffer device.  It operates on a chunk of
+  unswapable kernel memory instead of on the memory of a graphics board.
+  This means you cannot see any output sent to this frame buffer device,
+  while it does consume precious memory.  The main use of this frame
+  buffer device is testing and debugging the frame buffer subsystem. Do
+  NOT enable it for normal systems! To protect the innocent, it has to
+  be enabled explicitly on boot time using the kernel option `video=vfb:'.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called vfb.o.  If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+  If unsure, say N.
+
+Advanced low level driver options
+CONFIG_FBCON_ADVANCED
+  The frame buffer console uses character drawing routines that are
+  tailored to the specific organization of pixels in the memory of your
+  graphics hardware.  These are called the low level frame buffer console
+  drivers. Note that they are used for text console output only; they are
+  NOT needed for graphical applications.
+
+  If you do not enable this option, the needed low level drivers are
+  automatically enabled, depending on what frame buffer devices you
+  selected. This is recommended for most users.
+
+  If you enable this option, you have more fine-grained control over which
+  low level drivers are enabled. You can e.g. leave out low level drivers
+  for color depths you do not intend to use for text consoles.
+
+  Low level frame buffer console drivers can be modules ( = code which
+  can be inserted and removed from the running kernel whenever you want).
+  The modules will be called fbcon-*.o.  If you want to compile (some of)
+  them as modules, read Documentation/modules.txt.
+  
+  If unsure, say N.
+
+Monochrome support
+CONFIG_FBCON_MFB
+  This is the low level frame buffer console driver for monochrome
+  (2 colors) packed pixels.
+
+2 bpp packed pixels support
+CONFIG_FBCON_CFB2
+  This is the low level frame buffer console driver for 2 bits per pixel
+  (4 colors) packed pixels.
+
+4 bpp packed pixels support
+CONFIG_FBCON_CFB4
+  This is the low level frame buffer console driver for 4 bits per pixel
+  (16 colors) packed pixels.
+
+8 bpp packed pixels support
+CONFIG_FBCON_CFB8
+  This is the low level frame buffer console driver for 8 bits per pixel
+  (256 colors) packed pixels.
+
+16 bpp packed pixels support
+CONFIG_FBCON_CFB16
+  This is the low level frame buffer console driver for 15 or 16 bits
+  per pixel (32K or 64K colors, also known as `hicolor') packed pixels.
+
+24 bpp packed pixels support
+CONFIG_FBCON_CFB24
+  This is the low level frame buffer console driver for 24 bits per
+  pixel (16M colors, also known as `truecolor') packed pixels. It is
+  NOT for `sparse' 32 bits per pixel mode.
+
+32 bpp packed pixels support
+CONFIG_FBCON_CFB32
+  This is the low level frame buffer console driver for 32 bits per pixel
+  (16M colors, also known as `truecolor') sparse packed pixels.
+
+Amiga bitplanes support
+CONFIG_FBCON_AFB
+  This is the low level frame buffer console driver for 1 to 8 bitplanes
+  (2 to 256 colors) on Amiga.
+
+Amiga interleaved bitplanes support
+CONFIG_FBCON_ILBM
+  This is the low level frame buffer console driver for 1 to 8
+  interleaved bitplanes (2 to 256 colors) on Amiga.
+
+Atari interleaved bitplanes (2 planes) support
+CONFIG_FBCON_IPLAN2P2
+  This is the low level frame buffer console driver for 2 interleaved
+  bitplanes (4 colors) on Atari.
+
+Atari interleaved bitplanes (4 planes) support
+CONFIG_FBCON_IPLAN2P4
+  This is the low level frame buffer console driver for 4 interleaved
+  bitplanes (16 colors) on Atari.
+
+Atari interleaved bitplanes (8 planes) support
+CONFIG_FBCON_IPLAN2P8
+  This is the low level frame buffer console driver for 8 interleaved
+  bitplanes (256 colors) on Atari.
+
+Mac variable bpp packed pixels support
+CONFIG_FBCON_MAC
+  This is the low level frame buffer console driver for 1/2/4/8/16/32
+  bits per pixel packed pixels on Mac. It supports variable fontwidths
+  for low resolution screens.
+  
+VGA characters/attributes support
+CONFIG_FBCON_VGA
+  This is the low level frame buffer console driver for VGA text mode, as
+  used by vgafb.
 
 Parallel-port support
 CONFIG_PARPORT
index 7d6677851415840550f54777abf3f045d162060b..31b3c0e6773a5047fc0874d9cbfffa73487cbd01 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 111
+SUBLEVEL = 112
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -298,7 +298,7 @@ modules_install:
        cd modules; \
        MODULES=""; \
        inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
-               mkdir -p $$MODLIB/$$2; cp -p $$These $$MODLIB/$$2; \
+               mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \
                echo Installing modules under $$MODLIB/$$2; \
        }; \
        \
index e59565e21f80fabaecc233e764720588385b5271..3c6d0c0066e45848f634e927985ddec38d5cebe1 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/cdrom.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -1141,7 +1142,18 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
 static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
                                 unsigned int cmd, unsigned long arg)
 {
-       return -EIO;
+       idefloppy_pc_t pc;
+
+       if (cmd == CDROMEJECT) {
+               if (drive->usage > 1)
+                       return -EBUSY;
+               idefloppy_create_prevent_cmd (&pc, 0);
+               (void) idefloppy_queue_pc_tail (drive, &pc);
+               idefloppy_create_start_stop_cmd (&pc, 2);
+               (void) idefloppy_queue_pc_tail (drive, &pc);
+               return 0;
+       }
+       return -EIO;
 }
 
 /*
index 741a9a5505d3d779be58dc9059f4f4accf98d762..5e0ddfaaac0b8beb48ea1958f22548ccf61df107 100644 (file)
@@ -1525,6 +1525,7 @@ int ide_revalidate_disk(kdev_t i_rdev)
                        if (sb)
                                invalidate_inodes(sb);
                        invalidate_buffers (devp);
+                       set_blocksize(devp, 1024);
                }
                drive->part[p].start_sect = 0;
                drive->part[p].nr_sects   = 0;
index 585d1ebfe488bf9f9fff740efc031e706777a1b5..522569077c44cdfc07279ae1a57f55b39aff2c8b 100644 (file)
@@ -37,7 +37,6 @@
  *     int espserial_init(void);
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
index d7cdff1d7ca4c44402fa30f3737dbdc898996299..dd49bcfb7e52d920d9bf209fba346690f833124f 100644 (file)
@@ -772,7 +772,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
        rq->cmd = IDESCSI_PC_RQ;
        spin_unlock(&io_request_lock);
        (void) ide_do_drive_cmd (drive, rq, ide_end);
-       spin_lock(&io_request_lock);
+       spin_lock_irq(&io_request_lock);
        return 0;
 abort:
        if (pc) kfree (pc);
index a70a80acecdc67df0e7a1d02f91f3d67f3224f93..d3ab250db2ac1496c63d46cc1ad93562415f4a2b 100644 (file)
@@ -750,6 +750,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   case TYPE_MOD:
   case TYPE_PROCESSOR:
   case TYPE_SCANNER:
+  case TYPE_MEDIUM_CHANGER:
     SDpnt->writeable = 1;
     break;
   case TYPE_WORM:
index c8c6058960739458190afdfa98daf113b354ac00..8c0f99ed84465e22eeef2ddc2b20d240b3ec9d61 100644 (file)
@@ -24,7 +24,6 @@
  *
  ********************************************************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < 0x020101
 #  define LINUX20
index c6a5e666278492058698816213ce8341a791f032..3ae0e0b3b9bdf2f49af1d48433a1d015349048b3 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef __MSND_CLASSIC_H
 #define __MSND_CLASSIC_H
 
+#include <linux/config.h>
+
 #define DSP_NUMIO              0x10
 
 #define        HP_MEMM                 0x08
index 19cd251dd459e5fe2a6cebc7610eae0c1900ecf7..f6971c9498464817ca51433b3d4f7fea785d43e9 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef __MSND_PINNACLE_H
 #define __MSND_PINNACLE_H
 
+#include <linux/config.h>
+
 #define DSP_NUMIO              0x08
 
 #define        HP_DSPR                 0x04
index 49db98c50b358dc5b9a1b116852047bdb90b9465..81096aa9d1f4206ab65e910f79c8f238edeab988 100644 (file)
@@ -66,7 +66,7 @@ tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 if [ "$CONFIG_AFFS_FS" != "n" ]; then
   define_bool CONFIG_AMIGA_PARTITION y
 fi
-tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
+tristate 'UFS filesystem support' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
   bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
index 4895c1eebbd30a3c5cee3be69f707d54f2e402db..f8326866d7c8c601ce25da3343b7580c6932c657 100644 (file)
@@ -8,8 +8,8 @@
 # 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 (file)
index 0000000..934e474
--- /dev/null
@@ -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 (file)
index 0000000..1022ad3
--- /dev/null
@@ -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 (file)
index 0000000..a822438
--- /dev/null
@@ -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/dir.c b/fs/ufs/dir.c
new file mode 100644 (file)
index 0000000..ee0e856
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  linux/fs/ufs/ufs_dir.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
+ *
+ * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
+ */
+
+#include <linux/fs.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
+ */
+static int
+ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       int error = 0;
+       unsigned long offset, lblk, blk;
+       int i, stored;
+       struct buffer_head * bh;
+       struct ufs_dir_entry * de;
+       struct super_block * sb;
+       int de_reclen;
+       unsigned flags, swab;
+
+
+       /* Isn't that already done in the upper layer???
+         * the VFS layer really needs some explicit documentation!
+         */
+       if (!inode || !S_ISDIR(inode->i_mode))
+               return -EBADF;
+
+       sb = inode->i_sb;
+       swab = sb->u.ufs_sb.s_swab;
+        flags = sb->u.ufs_sb.s_flags;
+
+       UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
+
+       stored = 0;
+       bh = NULL;
+       offset = filp->f_pos & (sb->s_blocksize - 1);
+
+       while (!error && !stored && filp->f_pos < inode->i_size) {
+               lblk = (filp->f_pos) >> sb->s_blocksize_bits;
+               /* XXX - ufs_bmap() call needs error checking */
+               blk = ufs_bmap(inode, lblk);
+               bh = bread (sb->s_dev, blk, sb->s_blocksize);
+               if (!bh) {
+                       /* XXX - error - skip to the next block */
+                       printk("ufs_readdir: "
+                              "dir inode %lu has a hole at offset %lu\n",
+                              inode->i_ino, (unsigned long int)filp->f_pos);
+                       filp->f_pos += sb->s_blocksize - offset;
+                       continue;
+               }
+
+revalidate:
+               /* If the dir block has changed since the last call to
+                * readdir(2), then we might be pointing to an invalid
+                * dirent right now.  Scan from the start of the block
+                * to make sure. */
+               if (filp->f_version != inode->i_version) {
+                       for (i = 0; i < sb->s_blocksize && i < offset; ) {
+                               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
+                                * least that it is non-zero.  A
+                                * failure will be detected in the
+                                * dirent test below. */
+                               de_reclen = SWAB16(de->d_reclen);
+                               if (de_reclen < 1)
+                                       break;
+                               i += de_reclen;
+                       }
+                       offset = i;
+                       filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+                               | offset;
+                       filp->f_version = inode->i_version;
+               }
+
+               while (!error && filp->f_pos < inode->i_size
+                      && offset < sb->s_blocksize) {
+                       de = (struct ufs_dir_entry *) (bh->b_data + offset);
+                       /* XXX - put in a real ufs_check_dir_entry() */
+                       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)) +
+                                              sb->s_blocksize;
+                               brelse(bh);
+                               return stored;
+                       }
+#if 0 /* XXX */
+                       if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+                       /* XXX - beware about de having to be swabped somehow */
+                                                  bh, offset)) {
+                               /* On error, skip the f_pos to the
+                                  next block. */
+                               filp->f_pos = (filp->f_pos &
+                                             (sb->s_blocksize - 1)) +
+                                              sb->s_blocksize;
+                               brelse (bh);
+                               return stored;
+                       }
+#endif /* XXX */
+                       offset += SWAB16(de->d_reclen);
+                       if (de->d_ino) {
+                       /* SWAB16() was unneeded -- compare to 0 */
+                               /* We might block in the next section
+                                * if the data destination is
+                                * currently swapped out.  So, use a
+                                * version stamp to detect whether or
+                                * not the directory has been modified
+                                * during the copy operation. */
+                               unsigned long version = inode->i_version;
+
+                               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;
+                               if (version != inode->i_version)
+                                       goto revalidate;
+                               stored ++;
+                       }
+                       filp->f_pos += SWAB16(de->d_reclen);
+               }
+               offset = 0;
+               brelse (bh);
+       }
+       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 */
+       NULL,                   /* write */
+       ufs_readdir,            /* readdir */
+       NULL,                   /* select */
+       NULL,                   /* ioctl */
+       NULL,                   /* mmap */
+       NULL,                   /* open */
+       NULL,                   /* release */
+       file_fsync,             /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+};
+
+struct inode_operations ufs_dir_inode_operations = {
+       &ufs_dir_operations,    /* default directory file operations */
+       ufs_create,             /* create */
+       ufs_lookup,             /* lookup */
+       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 */
+       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 (file)
index 0000000..a6fa503
--- /dev/null
@@ -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 (file)
index 0000000..6da43f2
--- /dev/null
@@ -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 (file)
index 0000000..123a76a
--- /dev/null
@@ -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 (file)
index 0000000..309b316
--- /dev/null
@@ -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 (file)
index 0000000..b68af57
--- /dev/null
@@ -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 (file)
index 0000000..534c269
--- /dev/null
@@ -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 (file)
index 0000000..9d18c5f
--- /dev/null
@@ -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 (file)
index 0000000..7b16768
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ *  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_dir.c b/fs/ufs/ufs_dir.c
deleted file mode 100644 (file)
index e6d27c2..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_dir.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
- *
- * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- */
-
-#include <linux/fs.h>
-
-#include "ufs_swab.h"
-
-/*
- * This is blatantly stolen from ext2fs
- */
-static int
-ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
-{
-       struct inode *inode = filp->f_dentry->d_inode;
-       int error = 0;
-       unsigned long offset, lblk, blk;
-       int i, stored;
-       struct buffer_head * bh;
-       struct ufs_direct * de;
-       struct super_block * sb;
-       int de_reclen;
-       __u32 flags;
-
-       /* Isn't that already done in the upper layer???
-         * the VFS layer really needs some explicit documentation!
-         */
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
-       sb = inode->i_sb;
-        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);
-       }
-
-       stored = 0;
-       bh = NULL;
-       offset = filp->f_pos & (sb->s_blocksize - 1);
-
-       while (!error && !stored && filp->f_pos < inode->i_size) {
-               lblk = (filp->f_pos) >> sb->s_blocksize_bits;
-               /* XXX - ufs_bmap() call needs error checking */
-               blk = ufs_bmap(inode, lblk);
-               bh = bread (sb->s_dev, blk, sb->s_blocksize);
-               if (!bh) {
-                       /* XXX - error - skip to the next block */
-                       printk("ufs_readdir: "
-                              "dir inode %lu has a hole at offset %lu\n",
-                              inode->i_ino, (unsigned long int)filp->f_pos);
-                       filp->f_pos += sb->s_blocksize - offset;
-                       continue;
-               }
-
-revalidate:
-               /* If the dir block has changed since the last call to
-                * readdir(2), then we might be pointing to an invalid
-                * dirent right now.  Scan from the start of the block
-                * 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);
-                               /* It's too expensive to do a full
-                                * dirent test each time round this
-                                * loop, but we do have to test at
-                                * least that it is non-zero.  A
-                                * failure will be detected in the
-                                * dirent test below. */
-                               de_reclen = SWAB16(de->d_reclen);
-                               if (de_reclen < 1)
-                                       break;
-                               i += de_reclen;
-                       }
-                       offset = i;
-                       filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
-                               | offset;
-                       filp->f_version = inode->i_version;
-               }
-
-               while (!error && filp->f_pos < inode->i_size
-                      && offset < sb->s_blocksize) {
-                       de = (struct ufs_direct *) (bh->b_data + offset);
-                       /* XXX - put in a real ufs_check_dir_entry() */
-                       if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) {
-                       /* SWAB16() was unneeded -- compare to 0 */
-                               filp->f_pos = (filp->f_pos &
-                                             (sb->s_blocksize - 1)) +
-                                              sb->s_blocksize;
-                               brelse(bh);
-                               return stored;
-                       }
-#if 0 /* XXX */
-                       if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
-                       /* XXX - beware about de having to be swabped somehow */
-                                                  bh, offset)) {
-                               /* On error, skip the f_pos to the
-                                  next block. */
-                               filp->f_pos = (filp->f_pos &
-                                             (sb->s_blocksize - 1)) +
-                                              sb->s_blocksize;
-                               brelse (bh);
-                               return stored;
-                       }
-#endif /* XXX */
-                       offset += SWAB16(de->d_reclen);
-                       if (de->d_ino) {
-                       /* SWAB16() was unneeded -- compare to 0 */
-                               /* We might block in the next section
-                                * if the data destination is
-                                * currently swapped out.  So, use a
-                                * version stamp to detect whether or
-                                * not the directory has been modified
-                                * 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),
-                                               filp->f_pos, SWAB32(de->d_ino));
-                               if (error)
-                                       break;
-                               if (version != inode->i_version)
-                                       goto revalidate;
-                               stored ++;
-                       }
-                       filp->f_pos += SWAB16(de->d_reclen);
-               }
-               offset = 0;
-               brelse (bh);
-       }
-#if 0 /* XXX */
-       if (!IS_RDONLY(inode)) {
-               inode->i_atime = CURRENT_TIME;
-               inode->i_dirt = 1;
-       }
-#endif /* XXX */
-       return 0;
-}
-
-static struct file_operations ufs_dir_operations = {
-       NULL,                   /* lseek */
-       NULL,                   /* read */
-       NULL,                   /* write */
-       ufs_readdir,            /* readdir */
-       NULL,                   /* select */
-       NULL,                   /* ioctl */
-       NULL,                   /* mmap */
-       NULL,                   /* open */
-       NULL,                   /* release */
-       file_fsync,             /* fsync */
-       NULL,                   /* fasync */
-       NULL,                   /* check_media_change */
-       NULL,                   /* revalidate */
-};
-
-struct inode_operations ufs_dir_inode_operations = {
-       &ufs_dir_operations,    /* default directory file operations */
-       NULL,                   /* create */
-       ufs_lookup,             /* lookup */
-       NULL,                   /* link */
-       NULL,                   /* unlink */
-       NULL,                   /* symlink */
-       NULL,                   /* mkdir */
-       NULL,                   /* rmdir */
-       NULL,                   /* mknod */
-       NULL,                   /* rename */
-       NULL,                   /* readlink */
-       NULL,                   /* readpage */
-       NULL,                   /* writepage */
-       NULL,                   /* bmap */
-       NULL,                   /* truncate */
-       NULL,                   /* permission */
-       NULL,                   /* smap */
-};
diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c
deleted file mode 100644 (file)
index 7471156..0000000
+++ /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 (file)
index 88e260e..0000000
+++ /dev/null
@@ -1,334 +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 if (S_ISSOCK(inode->i_mode)) {
-               /* nothing */
-       } 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 (file)
index 021b854..0000000
+++ /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 (file)
index 7fdac8d..0000000
+++ /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 (file)
index 261d16d..0000000
+++ /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 (file)
index f8e9fd8..0000000
+++ /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 (file)
index e19abe4..0000000
+++ /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 (file)
index 0000000..4d7fd2d
--- /dev/null
@@ -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++;
+       }
+}
+               
\ No newline at end of file
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
new file mode 100644 (file)
index 0000000..8f5e667
--- /dev/null
@@ -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);
+}
index fa23800c39ef00de6551483379b2792564a90028..f9b6694bdcb8c3c9b55a02fb03d921376b587578 100644 (file)
 #include <linux/config.h>
 #include <asm/processor.h>
 
-#ifdef CONFIG_MTRR
-#  include <asm/mtrr.h>
-#endif
-
 #define CONFIG_BUGi386
 
 __initfunc(static void no_halt(char *s, int *ints))
@@ -333,7 +329,4 @@ __initfunc(static void check_bugs(void))
        check_amd_k6();
        check_pentium_f00f();
        system_utsname.machine[1] = '0' + boot_cpu_data.x86;
-#if defined(CONFIG_MTRR)
-       mtrr_init ();
-#endif
 }
index 0bf4a5a58299ef462bac1e50b60628e371dc26d1..896ead46b5bce1f27416498b4ac76ef52f39ee02 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/posix_types.h>
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/export.h>
 #include <linux/nfsd/nfsfh.h>
@@ -54,29 +55,29 @@ struct nfsctl_client {
 struct nfsctl_export {
        char                    ex_client[NFSCLNT_IDMAX+1];
        char                    ex_path[NFS_MAXPATHLEN+1];
-       dev_t                   ex_dev;
-       ino_t                   ex_ino;
+       __kernel_dev_t          ex_dev;
+       __kernel_ino_t          ex_ino;
        int                     ex_flags;
-       uid_t                   ex_anon_uid;
-       gid_t                   ex_anon_gid;
+       __kernel_uid_t          ex_anon_uid;
+       __kernel_gid_t          ex_anon_gid;
 };
 
 /* UGIDUPDATE */
 struct nfsctl_uidmap {
        char *                  ug_ident;
-       uid_t                   ug_uidbase;
+       __kernel_uid_t          ug_uidbase;
        int                     ug_uidlen;
-       uid_t *                 ug_udimap;
-       uid_t                   ug_gidbase;
+       __kernel_uid_t *        ug_udimap;
+       __kernel_gid_t          ug_gidbase;
        int                     ug_gidlen;
-       gid_t *                 ug_gdimap;
+       __kernel_gid_t *        ug_gdimap;
 };
 
 /* GETFH */
 struct nfsctl_fhparm {
        struct sockaddr         gf_addr;
-       dev_t                   gf_dev;
-       ino_t                   gf_ino;
+       __kernel_dev_t          gf_dev;
+       __kernel_ino_t          gf_ino;
        int                     gf_version;
 };
 
index b59cd5f901efa49dcacec15e1fa85ec325a3a77f..70740489c33dbccd8fa7abcd437add0f3129157d 100644 (file)
 #ifndef __LINUX_UFS_FS_H
 #define __LINUX_UFS_FS_H
 
-#undef UFS_HEAVY_DEBUG
-/*#define UFS_HEAVY_DEBUG 1*/
-/* Uncomment the line above when hacking ufs code */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/time.h>
 #define UFS_SBLOCK 8192
 #define UFS_SBSIZE 8192
 
+#define SECTOR_SIZE 512
+#define SECTOR_BITS 9
 #define UFS_MAGIC 0x00011954
 #define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */
 
-#define UFS_FSIZE 1024
-#define UFS_BSIZE 8192
+#define UFS_BSIZE      8192
+#define UFS_MINBSIZE   4096
+#define UFS_FSIZE      1024
+#define UFS_MAXFRAG    (UFS_BSIZE / UFS_FSIZE)
 
 #define UFS_NDADDR 12
 #define UFS_NINDIR 3
 #define UFS_DIND_BLOCK (UFS_NDADDR + 1)
 #define UFS_TIND_BLOCK (UFS_NDADDR + 2)
 
+#define UFS_NDIR_FRAGMENT (UFS_NDADDR << uspi->s_fpbshift)
+#define UFS_IND_FRAGMENT (UFS_IND_BLOCK << uspi->s_fpbshift)
+#define UFS_DIND_FRAGMENT (UFS_DIND_BLOCK << uspi->s_fpbshift)
+#define UFS_TIND_FRAGMENT (UFS_TIND_BLOCK << uspi->s_fpbshift)
+
 #define UFS_ROOTINO 2
+#define UFS_FIRST_INO (UFS_ROOTINO + 1)
 
 #define UFS_USEEFT  ((__u16)65535)
 
 #define UFS_HURD               0x00000130
 #define UFS_SUN                        0x00000200
 #define UFS_NEXT               0x00000400
-/* we preserve distinction in flavor identification even without difference,
- * because yet-to-be-supported features may introduce difference in the future
- */
-/* last but not least, debug flags */
-#define UFS_DEBUG              0x01000000
-#define UFS_DEBUG_INODE        0x02000000
-#define UFS_DEBUG_NAMEI        0x04000000
-#define UFS_DEBUG_LINKS        0x08000000
-
-#ifdef UFS_HEAVY_DEBUG
-#  define UFS_DEBUG_INITIAL UFS_DEBUG
-#else
-#  define UFS_DEBUG_INITIAL 0
-#endif
 
 /* fs_inodefmt options */
 #define UFS_42INODEFMT -1
 #define UFS_44INODEFMT 2
 
-#define UFS_ADDR_PER_BLOCK(sb)         ((sb)->u.ufs_sb.s_bsize >> 2)
-#define UFS_ADDR_PER_BLOCK_BITS(sb)    ((sb)->u.ufs_sb.s_bshift - 2)
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define UFS_MINFREE         5
+#define UFS_DEFAULTOPT      UFS_OPTTIME
+            
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define ufs_fsbtodb(uspi, b)   ((b) << (uspi)->s_fsbtodb)
+#define        ufs_dbtofsb(uspi, b)    ((b) >> (uspi)->s_fsbtodb)
 
-/* Test if the inode number is valid. */
-#define ufs_ino_ok(inode)  ((inode->i_ino < 2) &&  \
-                           (inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1)))
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define        ufs_cgbase(c)   (uspi->s_fpg * (c))
+#define ufs_cgstart(c) (ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))
+#define        ufs_cgsblock(c) (ufs_cgstart(c) + uspi->s_sblkno)       /* super blk */
+#define        ufs_cgcmin(c)   (ufs_cgstart(c) + uspi->s_cblkno)       /* cg block */
+#define        ufs_cgimin(c)   (ufs_cgstart(c) + uspi->s_iblkno)       /* inode blk */
+#define        ufs_cgdmin(c)   (ufs_cgstart(c) + uspi->s_dblkno)       /* 1st data */
 
-/* Convert (sb,cg) to the first physical block number for that cg. */
-#define ufs_cgstart(sb, cg)   \
-  (((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask)))
+/*
+ * Macros for handling inode numbers:
+ *     inode number to file system block offset.
+ *     inode number to cylinder group number.
+ *     inode number to file system block address.
+ */
+#define        ufs_inotocg(x)          ((x) / uspi->s_ipg)
+#define        ufs_inotocgoff(x)       ((x) % uspi->s_ipg)
+#define        ufs_inotofsba(x)        (ufs_cgimin(ufs_inotocg(x)) + ufs_inotocgoff(x) / uspi->s_inopf)
+#define        ufs_inotofsbo(x)        ((x) % uspi->s_inopf)
 
-/* Convert (sb,cg) to the first phys. block number for inodes in that cg. */
-#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno)
-#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno)
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define        ufs_dtog(d)     ((d) / uspi->s_fpg)
+#define        ufs_dtogd(d)    ((d) % uspi->s_fpg)
 
-/* Convert an inode number to a cg number. */
-/* XXX - this can be optimized if s_ipg is a power of 2. */
-#define ufs_ino2cg(inode)  ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg)
+/*
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define ufs_cbtocylno(bno) \
+       ((bno) * uspi->s_nspf / uspi->s_spc)
+#define ufs_cbtorpos(bno) \
+       ((((bno) * uspi->s_nspf % uspi->s_spc / uspi->s_nsect \
+       * uspi->s_trackskew + (bno) * uspi->s_nspf % uspi->s_spc \
+       % uspi->s_nsect * uspi->s_interleave) % uspi->s_nsect \
+       * uspi->s_nrpos) / uspi->s_npsect)
 
-/* current filesystem state; method depends on flags */
-#define UFS_STATE(usb) \
-               ( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \
-                  ? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \
-                  : (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ )
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define ufs_blkoff(loc)                ((loc) & uspi->s_qbmask)
+#define ufs_fragoff(loc)       ((loc) & uspi->s_qfmask)
+#define ufs_lblktosize(blk)    ((blk) << uspi->s_bshift)
+#define ufs_lblkno(loc)                ((loc) >> uspi->s_bshift)
+#define ufs_numfrags(loc)      ((loc) >> uspi->s_fshift)
+#define ufs_blkroundup(size)   (((size) + uspi->s_qbmask) & uspi->s_bmask)
+#define ufs_fragroundup(size)  (((size) + uspi->s_qfmask) & uspi->s_fmask)
+#define ufs_fragstoblks(frags) ((frags) >> uspi->s_fpbshift)
+#define ufs_blkstofrags(blks)  ((blks) << uspi->s_fpbshift)
+#define ufs_fragnum(fsb)       ((fsb) & uspi->s_fpbmask)
+#define ufs_blknum(fsb)                ((fsb) & ~uspi->s_fpbmask)
 
 #define        UFS_MAXNAMLEN 255
+#define UFS_MAXMNTLEN 512
+#define UFS_MAXCSBUFS 31
+#define UFS_LINK_MAX EXT2_LINK_MAX
 
-#define ufs_lbn(sb, block)             ((block) >> (sb)->u.ufs_sb.s_lshift)
-#define ufs_boff(sb, block)            ((block) & ~((sb)->u.ufs_sb.s_lmask))
-#define ufs_dbn(sb, block, boff)       ((block) + ufs_boff((sb), (boff)))
+/*
+ * UFS_DIR_PAD defines the directory entries boundaries
+ * (must be a multiple of 4)
+ */
+#define UFS_DIR_PAD                    4
+#define UFS_DIR_ROUND                  (UFS_DIR_PAD - 1)
+#define UFS_DIR_REC_LEN(name_len)      (((name_len) + 1 + 8 + UFS_DIR_ROUND) & ~UFS_DIR_ROUND)
 
 struct ufs_timeval {
        __s32   tv_sec;
        __s32   tv_usec;
 };
 
-struct ufs_direct {
+struct ufs_dir_entry {
        __u32  d_ino;                   /* inode number of this entry */
        __u16  d_reclen;                /* length of this entry */
        union {
@@ -155,9 +208,6 @@ struct ufs_direct {
        __u8    d_name[UFS_MAXNAMLEN + 1];      /* file name */
 };
 
-#define MAXMNTLEN 512
-#define MAXCSBUFS 32
-
 struct ufs_csum {
        __u32   cs_ndir;        /* number of directories */
        __u32   cs_nbfree;      /* number of free blocks */
@@ -168,7 +218,7 @@ struct ufs_csum {
 /*
  * This is the actual superblock, as it is laid out on the disk.
  */
-struct ufs_superblock {
+struct ufs_super_block {
        __u32   fs_link;        /* UNUSED */
        __u32   fs_rlink;       /* UNUSED */
        __u32   fs_sblkno;      /* addr of super-block in filesys */
@@ -237,15 +287,18 @@ struct ufs_superblock {
        __u8    fs_clean;       /* file system is clean flag */
        __u8    fs_ronly;       /* mounted read-only flag */
        __u8    fs_flags;       /* currently unused flag */
-       __u8    fs_fsmnt[MAXMNTLEN];    /* name mounted on */
+       __u8    fs_fsmnt[UFS_MAXMNTLEN];        /* name mounted on */
 /* these fields retain the current block allocation info */
        __u32   fs_cgrotor;     /* last cg searched */
-       __u32   fs_csp[MAXCSBUFS];      /* list of fs_cs info buffers */
+       __u32   fs_csp[UFS_MAXCSBUFS];  /* list of fs_cs info buffers */
+       __u32   fs_maxcluster;
        __u32   fs_cpc;         /* cyl per cycle in postbl */
        __u16   fs_opostbl[16][8];      /* old rotation block list head */      
        union {
                struct {
-                       __s32   fs_sparecon[55];/* reserved for future constants */
+                       __s32   fs_sparecon[53];/* reserved for future constants */
+                       __s32   fs_reclaim;
+                       __s32   fs_sparecon2[1];
                        __s32   fs_state;       /* file system state time stamp */
                        __u32   fs_qbmask[2];   /* ~usb_bmask */
                        __u32   fs_qfmask[2];   /* ~usb_fmask */
@@ -255,7 +308,7 @@ struct ufs_superblock {
                        __s32   fs_contigsumsize;/* size of cluster summary array */
                        __s32   fs_maxsymlinklen;/* max length of an internal symlink */
                        __s32   fs_inodefmt;    /* format of on-disk inodes */
-                       __u32   fs_maxfilesize[2];/* max representable file size */
+                       __u32   fs_maxfilesize[2];      /* max representable file size */
                        __u32   fs_qbmask[2];   /* ~usb_bmask */
                        __u32   fs_qfmask[2];   /* ~usb_fmask */
                        __s32   fs_state;       /* file system state time stamp */
@@ -269,6 +322,59 @@ struct ufs_superblock {
        __u8    fs_space[1];            /* list of blocks for each rotation */
 };
 
+/*
+ * Preference for optimization.
+ */
+#define UFS_OPTTIME    0       /* minimize allocation time */
+#define UFS_OPTSPACE   1       /* minimize disk fragmentation */
+
+/*
+ * Rotational layout table format types
+ */
+#define UFS_42POSTBLFMT                -1      /* 4.2BSD rotational table format */
+#define UFS_DYNAMICPOSTBLFMT   1       /* dynamic rotational table format */
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define fs_cs(indx) \
+       u.ufs_sb.s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ *
+ * Writable fields in the cylinder group are protected by the associated
+ * super block lock fs->fs_lock.
+ */
+#define        CG_MAGIC        0x090255
+#define ufs_cg_chkmagic(ucg)   (SWAB32((ucg)->cg_magic) == CG_MAGIC)
+
+/*
+ * size of this structure is 172 B
+ */
+struct ufs_cylinder_group {
+       __u32   cg_link;                /* linked list of cyl groups */
+       __u32   cg_magic;               /* magic number */
+       __u32   cg_time;                /* time last written */
+       __u32   cg_cgx;                 /* we are the cgx'th cylinder group */
+       __u16   cg_ncyl;                /* number of cyl's this cg */
+       __u16   cg_niblk;               /* number of inode blocks this cg */
+       __u32   cg_ndblk;               /* number of data blocks this cg */
+       struct  ufs_csum cg_cs;         /* cylinder summary information */
+       __u32   cg_rotor;               /* position of last used block */
+       __u32   cg_frotor;              /* position of last used frag */
+       __u32   cg_irotor;              /* position of last used inode */
+       __u32   cg_frsum[UFS_MAXFRAG];  /* counts of available frags */
+       __u32   cg_btotoff;             /* (__u32) block totals per cylinder */
+       __u32   cg_boff;                /* (short) free block positions */
+       __u32   cg_iusedoff;            /* (char) used inode map */
+       __u32   cg_freeoff;             /* (u_char) free block map */
+       __u32   cg_nextfreeoff;         /* (u_char) next available space */
+       __u32   cg_sparecon[16];        /* reserved for future use */
+       __u8    cg_space[1];            /* space for cylinder group maps */
+/* actually longer */
+};
+
 /*
  * structure of an on-disk inode
  */
@@ -277,11 +383,11 @@ struct ufs_inode {
        __u16   ui_nlink;               /*  0x2 */
        union {
                struct {
-                       __u16   suid;   /*  0x4 */
-                       __u16   sgid;   /*  0x6 */
+                       __u16   ui_suid;        /*  0x4 */
+                       __u16   ui_sgid;        /*  0x6 */
                } oldids;
-               __u32   inumber;        /*  0x4 lsf: inode number */
-               __u32   author;         /*  0x4 GNU HURD: author */
+               __u32   ui_inumber;     /*  0x4 lsf: inode number */
+               __u32   ui_author;              /*  0x4 GNU HURD: author */
        } ui_u1;
        __u64   ui_size;                /*  0x8 */
        struct ufs_timeval ui_atime;    /* 0x10 access */
@@ -333,43 +439,73 @@ struct ufs_inode {
 #define UFS_SF_IMMUTABLE  0x00020000  /* immutable (can't "change") */
 #define UFS_SF_APPEND     0x00040000  /* append-only */
 #define UFS_SF_NOUNLINK   0x00100000  /* can't be removed or renamed */
-    
-#ifdef __KERNEL__
-/*
- * Function prototypes
- */
-
-/* ufs_inode.c */
-extern int ufs_bmap (struct inode *, int);
-extern void ufs_read_inode(struct inode * inode);
-extern void ufs_put_inode(struct inode * inode);
 
-extern void ufs_print_inode (struct inode *);
+#ifdef __KERNEL__
 
-/* ufs_namei.c */
-extern int ufs_lookup (struct inode *, struct dentry *);
+/* acl.c */
+extern int ufs_permission (struct inode *, int);
 
-/* ufs_super.c */
-extern void ufs_warning (struct super_block *, const char *, const char *, ...)
-        __attribute__ ((format (printf, 3, 4)));
-extern int init_ufs_fs(void);
+/* balloc.c */
+extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
+extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
+extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *);
 
-/*
- * Inodes and files operations
- */
+/* cylinder.c */
+extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
+extern void ufs_put_cylinder (struct super_block *, unsigned);
 
-/* ufs_dir.c */
+/* dir.c */
 extern struct inode_operations ufs_dir_inode_operations;
 extern struct file_operations ufs_dir_operations;
+extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
 
-/* ufs_file.c */
+/* file.c */
 extern struct inode_operations ufs_file_inode_operations;
 extern struct file_operations ufs_file_operations;
 
-/* ufs_symlink.c */
+/* ialloc.c */
+extern void ufs_free_inode (struct inode *inode);
+extern struct inode * ufs_new_inode (const struct inode *, int, int *);
+
+/* inode.c */
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_read_inode (struct inode *);
+extern void ufs_put_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern int ufs_sync_inode (struct inode *);
+extern void ufs_print_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern void ufs_delete_inode (struct inode *);
+extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
+extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+
+/* namei.c */
+extern int ufs_lookup (struct inode *, struct dentry *);
+extern int ufs_mkdir(struct inode *, struct dentry *, int);
+extern int ufs_rmdir (struct inode *, struct dentry *);
+extern int ufs_unlink (struct inode *, struct dentry *);
+extern int ufs_create (struct inode *, struct dentry *, int);
+extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int ufs_mknod (struct inode *, struct dentry *, int, int);
+extern int ufs_symlink (struct inode *, struct dentry *, const char *);
+extern int ufs_link (struct dentry *, struct inode *, struct dentry *);
+        
+/* super.c */
+extern struct super_operations ufs_super_ops;
+extern struct file_system_type ufs_fs_type;
+extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+        
+extern int init_ufs_fs(void);
+extern void ufs_write_super (struct super_block *);
+extern void ufs_print_cylinder_stuff(struct ufs_cylinder_group *, __u32);
+
+/* symlink.c */
 extern struct inode_operations ufs_symlink_inode_operations;
-extern struct file_operations ufs_symlink_operations;
+
+/* truncate.c */
+extern void ufs_truncate (struct inode *);
 
 #endif /* __KERNEL__ */
 
index 31611830bebbbe320ff5056ec03db53022091544..e270b71aa8c1b43615fc4171f580bfd43ae7aaa0 100644 (file)
@@ -8,6 +8,8 @@
  *
  * NeXTstep support added on February 5th 1998 by
  * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz>
  */
 
 #ifndef _LINUX_UFS_FS_I_H
@@ -16,7 +18,7 @@
 struct ufs_inode_info {
        union {
                __u32   i_data[15];
-               __u8    i_symlink[4*15];        /* fast symlink */
+               __u8    i_symlink[4*15];
        } i_u1;
        __u64   i_size;
        __u32   i_flags;
@@ -25,6 +27,8 @@ struct ufs_inode_info {
        __u32   i_uid;
        __u32   i_gid;
        __u32   i_oeftflag;
+       __u16   i_osync;
+       __u32   i_lastfrag;
 };
 
 #endif /* _LINUX_UFS_FS_I_H */
index 1469f659fc767aa4edb20bdf6bbf65e620662b90..3f89d407921b0ae8b91f8042076974e83bf41b17 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/* 
  *  linux/include/linux/ufs_fs_sb.h
  *
  * Copyright (C) 1996
@@ -6,8 +6,10 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * NeXTstep support added on February 5th 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ * $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $
+ *
+ * Write support by Daniel Pirkl (daniel.pirkl@email.cz)
+ * Charles University (Prague), Faculty of Mathematics and Physics
  */
 
 #ifndef __LINUX_UFS_FS_SB_H
 
 #include <linux/ufs_fs.h>
 
+/*
+ * This structure is used for reading disk structures larger
+ * than the size of fragment.
+ */
+struct ufs_buffer_head {
+       unsigned fragment;                      /* first fragment */
+       unsigned count;                         /* number of fragments */
+       struct buffer_head * bh[UFS_MAXFRAG];   /* buffers */
+};
+
+struct ufs_cg_private_info {
+       struct ufs_cylinder_group ucg;
+       __u32   c_cgx;          /* number of cylidner group */
+       __u16   c_ncyl;         /* number of cyl's this cg */
+       __u16   c_niblk;        /* number of inode blocks this cg */
+       __u32   c_ndblk;        /* number of data blocks this cg */
+       __u32   c_rotor;        /* position of last used block */
+       __u32   c_frotor;       /* position of last used frag */
+       __u32   c_irotor;       /* position of last used inode */
+       __u32   c_btotoff;      /* (__u32) block totals per cylinder */
+       __u32   c_boff;         /* (short) free block positions */
+       __u32   c_iusedoff;     /* (char) used inode map */
+       __u32   c_freeoff;      /* (u_char) free block map */
+       __u32   c_nextfreeoff;  /* (u_char) next available space */
+};     
+       
+
+struct ufs_sb_private_info {
+       struct ufs_buffer_head s_ubh; /* buffer containing super block */
+       __u32   s_sblkno;       /* offset of super-blocks in filesys */
+       __u32   s_cblkno;       /* offset of cg-block in filesys */
+       __u32   s_iblkno;       /* offset of inode-blocks in filesys */
+       __u32   s_dblkno;       /* offset of first data after cg */
+       __u32   s_cgoffset;     /* cylinder group offset in cylinder */
+       __u32   s_cgmask;       /* used to calc mod fs_ntrak */
+       __u32   s_size;         /* number of blocks (fragments) in fs */
+       __u32   s_dsize;        /* number of data blocks in fs */
+       __u32   s_ncg;          /* number of cylinder groups */
+       __u32   s_bsize;        /* size of basic blocks */
+       __u32   s_fsize;        /* size of fragments */
+       __u32   s_fpb;          /* fragments per block */
+       __u32   s_minfree;      /* minimum percentage of free blocks */
+       __u32   s_bmask;        /* `blkoff'' calc of blk offsets */
+       __u32   s_fmask;        /* s_fsize mask */
+       __u32   s_bshift;       /* `lblkno'' calc of logical blkno */
+       __u32   s_fshift;       /* s_fsize shift */
+       __u32   s_fpbshift;     /* fragments per block shift */
+       __u32   s_fsbtodb;      /* fsbtodb and dbtofsb shift constant */
+       __u32   s_sbsize;       /* actual size of super block */
+       __u32   s_csmask;       /* csum block offset */
+       __u32   s_csshift;      /* csum block number */
+       __u32   s_nindir;       /* value of NINDIR */
+       __u32   s_inopb;        /* value of INOPB */
+       __u32   s_nspf;         /* value of NSPF */
+       __u32   s_npsect;       /* # sectors/track including spares */
+       __u32   s_interleave;   /* hardware sector interleave */
+       __u32   s_trackskew;    /* sector 0 skew, per track */
+       __u32   s_csaddr;       /* blk addr of cyl grp summary area */
+       __u32   s_cssize;       /* size of cyl grp summary area */
+       __u32   s_cgsize;       /* cylinder group size */
+       __u32   s_ntrak;        /* tracks per cylinder */
+       __u32   s_nsect;        /* sectors per track */
+       __u32   s_spc;          /* sectors per cylinder */
+       __u32   s_ipg;          /* inodes per group */
+       __u32   s_fpg;          /* fragments per group */
+       __u32   s_cpc;          /* cyl per cycle in postbl */
+       __s64   s_qbmask;       /* ~usb_bmask */
+       __s64   s_qfmask;       /* ~usb_fmask */
+       __s32   s_postblformat; /* format of positional layout tables */
+       __s32   s_nrpos;        /* number of rotational positions */
+        __s32  s_postbloff;    /* (__s16) rotation block list head */
+       __s32   s_rotbloff;     /* (__u8) blocks for each rotation */
+
+       __u32   s_fpbmask;      /* fragments per block mask */
+       __u32   s_apb;          /* address per block */
+       __u32   s_2apb;         /* address per block^2 */
+       __u32   s_3apb;         /* address per block^3 */
+       __u32   s_apbmask;      /* address per block mask */
+       __u32   s_apbshift;     /* address per block shift */
+       __u32   s_2apbshift;    /* address per block shift * 2 */
+       __u32   s_3apbshift;    /* address per block shift * 3 */
+       __u32   s_nspfshift;    /* number of sector per fragment shift */
+       __u32   s_nspb;         /* number of sector per block */
+       __u32   s_inopf;        /* inodes per fragment */
+       __u32   s_sbbase;       /* offset of NeXTstep superblock */
+};
+
+
+#define UFS_MAX_GROUP_LOADED 1
+#define UFS_CGNO_EMPTY uspi->s_ncg
+
 struct ufs_sb_info {
-       struct ufs_superblock * s_raw_sb;
-       __u32   s_flags; /* internal flags for UFS code */
-       __u32   s_ncg;   /* used in ufs_read_inode */
-       __u32   s_ipg;   /* used in ufs_read_inode */
-       __u32   s_fpg;
-       __u32   s_fsize;
-       __u32   s_fshift;
-       __u32   s_fmask;
-       __u32   s_bsize;
-       __u32   s_bmask;
-       __u32   s_bshift;
-       __u32   s_iblkno;
-       __u32   s_dblkno;
-       __u32   s_cgoffset;
-       __u32   s_cgmask;
-       __u32   s_inopb;
-       __u32   s_lshift;
-       __u32   s_lmask;
-       __u32   s_fsfrag;
-       __u32   s_blockbase;    /* offset of NeXTstep superblock */
+       struct ufs_sb_private_info * s_uspi;    
+       struct ufs_csum * s_csp[UFS_MAXCSBUFS];
+       int s_rename_lock;
+       struct wait_queue * s_rename_wait;
+       unsigned s_swab;
+       unsigned s_flags;
+       struct buffer_head ** s_ucg;
+       struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED]; 
+       unsigned s_cgno[UFS_MAX_GROUP_LOADED];
+       unsigned short s_cg_loaded;
+};
+
+/*
+ * Sizes of this structures are:
+ *     ufs_super_block_first   512
+ *     ufs_super_block_second  512
+ *     ufs_super_block_third   356
+ */
+struct ufs_super_block_first {
+       __u32   fs_link;
+       __u32   fs_rlink;
+       __u32   fs_sblkno;
+       __u32   fs_cblkno;
+       __u32   fs_iblkno;
+       __u32   fs_dblkno;
+       __u32   fs_cgoffset;
+       __u32   fs_cgmask;
+       __u32   fs_time;
+       __u32   fs_size;
+       __u32   fs_dsize;
+       __u32   fs_ncg;
+       __u32   fs_bsize;
+       __u32   fs_fsize;
+       __u32   fs_frag;
+       __u32   fs_minfree;
+       __u32   fs_rotdelay;
+       __u32   fs_rps;
+       __u32   fs_bmask;
+       __u32   fs_fmask;
+       __u32   fs_bshift;
+       __u32   fs_fshift;
+       __u32   fs_maxcontig;
+       __u32   fs_maxbpg;
+       __u32   fs_fragshift;
+       __u32   fs_fsbtodb;
+       __u32   fs_sbsize;
+       __u32   fs_csmask;
+       __u32   fs_csshift;
+       __u32   fs_nindir;
+       __u32   fs_inopb;
+       __u32   fs_nspf;
+       __u32   fs_optim;
+       __u32   fs_npsect;
+       __u32   fs_interleave;
+       __u32   fs_trackskew;
+       __u32   fs_id[2];
+       __u32   fs_csaddr;
+       __u32   fs_cssize;
+       __u32   fs_cgsize;
+       __u32   fs_ntrak;
+       __u32   fs_nsect;
+       __u32   fs_spc;
+       __u32   fs_ncyl;
+       __u32   fs_cpg;
+       __u32   fs_ipg;
+       __u32   fs_fpg;
+       struct ufs_csum fs_cstotal;
+       __u8    fs_fmod;
+       __u8    fs_clean;
+       __u8    fs_ronly;
+       __u8    fs_flags;
+       __u8    fs_fsmnt[UFS_MAXMNTLEN - 212];
+
+};
+
+struct ufs_super_block_second {
+       __u8    fs_fsmnt[212];
+       __u32   fs_cgrotor;
+       __u32   fs_csp[UFS_MAXCSBUFS];
+       __u32   fs_maxcluster;
+       __u32   fs_cpc;
+       __u16   fs_opostbl[82];
+};     
+
+struct ufs_super_block_third {
+       __u16   fs_opostbl[46];
+       union {
+               struct {
+                       __s32   fs_sparecon[53];/* reserved for future constants */
+                       __s32   fs_reclaim;
+                       __s32   fs_sparecon2[1];
+                       __s32   fs_state;       /* file system state time stamp */
+                       __u32   fs_qbmask[2];   /* ~usb_bmask */
+                       __u32   fs_qfmask[2];   /* ~usb_fmask */
+               } fs_sun;
+               struct {
+                       __s32   fs_sparecon[50];/* reserved for future constants */
+                       __s32   fs_contigsumsize;/* size of cluster summary array */
+                       __s32   fs_maxsymlinklen;/* max length of an internal symlink */
+                       __s32   fs_inodefmt;    /* format of on-disk inodes */
+                       __u32   fs_maxfilesize[2];      /* max representable file size */
+                       __u32   fs_qbmask[2];   /* ~usb_bmask */
+                       __u32   fs_qfmask[2];   /* ~usb_fmask */
+                       __s32   fs_state;       /* file system state time stamp */
+               } fs_44;
+       } fs_u;
+       __s32   fs_postblformat;
+       __s32   fs_nrpos;
+       __s32   fs_postbloff;
+       __s32   fs_rotbloff;
+       __s32   fs_magic;
+       __u8    fs_space[1];
 };
 
 #endif /* __LINUX_UFS_FS_SB_H */
index df6b54072c22ce03ff9d43fd86fe3d2dd739be67..2ab0deba7e632b5243dd99fbc1ac652c3a764d10 100644 (file)
 #include <linux/dio.h>
 #endif
 
+#ifdef CONFIG_MTRR
+#  include <asm/mtrr.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -1106,11 +1110,21 @@ __initfunc(asmlinkage void start_kernel(void))
 #if defined(CONFIG_QUOTA)
        dquot_init_hash();
 #endif
+       printk("POSIX conformance testing by UNIFIX\n");
+       check_bugs();
+
 #ifdef __SMP__
        smp_init();
 #endif
-       printk("POSIX conformance testing by UNIFIX\n");
-       check_bugs();
+
+#if defined(CONFIG_MTRR)       /* Do this after SMP initialization */
+/*
+ * We should probably create some architecture-dependent "fixup after
+ * everything is up" style function where this would belong better
+ * than in init/main.c..
+ */
+       mtrr_init ();
+#endif
 
        sock_init();
 #ifdef CONFIG_SYSCTL
index 5fb7be6fbeef38a4114991fcdaab6406bec16052..caa29b74047b49497a62682f877995430c4f5b6e 100644 (file)
@@ -105,10 +105,19 @@ void scheduling_functions_start_here(void) { }
 
 static inline void reschedule_idle(struct task_struct * p)
 {
+
        /*
         * For SMP, we try to see if the CPU the task used
         * to run on is idle..
         */
+#if 0
+       /*
+        * Disable this for now. Ingo has some interesting
+        * code that looks too complex, and I have some ideas,
+        * but in the meantime.. One problem is that "wakeup()"
+        * can be (and is) called before we've even initialized
+        * SMP completely, so..
+        */
 #ifdef __SMP__
        int want_cpu = p->processor;
 
@@ -131,6 +140,7 @@ static inline void reschedule_idle(struct task_struct * p)
                        }
                } while (--i > 0);
        }
+#endif
 #endif
        if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
                current->need_resched = 1;      
index d2d591bb0f185e80291e057781e5fcf799523086..d33a334cb61aace186f2eddd894747bd936578e7 100644 (file)
@@ -532,6 +532,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
                error = blkdev_open(swap_dentry->d_inode, &filp);
                if (error)
                        goto bad_swap_2;
+               set_blocksize(p->swap_device, PAGE_SIZE);
                error = -ENODEV;
                if (!p->swap_device ||
                    (blk_size[MAJOR(p->swap_device)] &&