Commit 17c19e02 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.112pre1

parent 5662673d
...@@ -1488,6 +1488,76 @@ CONFIG_FB ...@@ -1488,6 +1488,76 @@ CONFIG_FB
If you want to play with it, say Y here and to the driver for your If you want to play with it, say Y here and to the driver for your
graphics board, below. If unsure, say N. 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 Open Firmware frame buffer device support
CONFIG_FB_OF CONFIG_FB_OF
Say Y if you want support with Open Firmware for your graphics board. Say Y if you want support with Open Firmware for your graphics board.
...@@ -1500,6 +1570,31 @@ ATI Mach64 display support ...@@ -1500,6 +1570,31 @@ ATI Mach64 display support
CONFIG_FB_ATY CONFIG_FB_ATY
This driver supports graphics boards with the ATI Mach64 chips. 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) VGA chipset support (text only)
CONFIG_FB_VGA CONFIG_FB_VGA
This is the frame buffer device driver for generic VGA chips. This This is the frame buffer device driver for generic VGA chips. This
...@@ -1530,38 +1625,143 @@ CONFIG_FB_MDA ...@@ -1530,38 +1625,143 @@ CONFIG_FB_MDA
If unsure, say N. If unsure, say N.
### SBUS and UPA framebuffers
### Somebody please explain the following options CONFIG_FB_SBUS
### Say Y if you want support for SBUS or UPA based frame buffer device.
# Virtual Frame Buffer support (ONLY FOR TESTING!)
# CONFIG_FB_VIRTUAL Creator/Creator3D support
# CONFIG_FB_CREATOR
# Advanced low level driver options This is the frame buffer device driver for the Creator and Creator3D
# CONFIG_FBCON_ADVANCED graphics boards.
#
# Monochrome support CGsix (GX,TurboGX) support
# CONFIG_FBCON_MFB CONFIG_FB_CGSIX
# This is the frame buffer device driver for the CGsix (GX, TurboGX)
# 2 bpp packed pixels support frame buffer.
# CONFIG_FBCON_CFB2
# BWtwo support
# 4 bpp packed pixels support CONFIG_FB_BWTWO
# CONFIG_FBCON_CFB4 This is the frame buffer device driver for the BWtwo frame buffer.
#
# 8 bpp packed pixels support CGthree support
# CONFIG_FBCON_CFB8 CONFIG_FB_CGTHREE
# This is the frame buffer device driver for the CGthree frame buffer.
# 16 bpp packed pixels support
# CONFIG_FBCON_CFB16 TCX (SS4/SS5 only) support
# CONFIG_FB_TCX
# 24 bpp packed pixels support This is the frame buffer device driver for the TCX 24/8bit frame buffer.
# CONFIG_FBCON_CFB24
# Virtual Frame Buffer support (ONLY FOR TESTING!)
# 32 bpp packed pixels support CONFIG_FB_VIRTUAL
# CONFIG_FBCON_CFB32 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.
# VGA characters/attributes support This means you cannot see any output sent to this frame buffer device,
# CONFIG_FBCON_VGA 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 Parallel-port support
CONFIG_PARPORT CONFIG_PARPORT
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 1 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/) 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: ...@@ -298,7 +298,7 @@ modules_install:
cd modules; \ cd modules; \
MODULES=""; \ MODULES=""; \
inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ 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; \ echo Installing modules under $$MODLIB/$$2; \
}; \ }; \
\ \
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/malloc.h> #include <linux/malloc.h>
#include <linux/cdrom.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -1141,6 +1142,17 @@ static int idefloppy_get_capacity (ide_drive_t *drive) ...@@ -1141,6 +1142,17 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
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; return -EIO;
} }
......
...@@ -1525,6 +1525,7 @@ int ide_revalidate_disk(kdev_t i_rdev) ...@@ -1525,6 +1525,7 @@ int ide_revalidate_disk(kdev_t i_rdev)
if (sb) if (sb)
invalidate_inodes(sb); invalidate_inodes(sb);
invalidate_buffers (devp); invalidate_buffers (devp);
set_blocksize(devp, 1024);
} }
drive->part[p].start_sect = 0; drive->part[p].start_sect = 0;
drive->part[p].nr_sects = 0; drive->part[p].nr_sects = 0;
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
* int espserial_init(void); * int espserial_init(void);
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/signal.h> #include <linux/signal.h>
......
...@@ -772,7 +772,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ...@@ -772,7 +772,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
rq->cmd = IDESCSI_PC_RQ; rq->cmd = IDESCSI_PC_RQ;
spin_unlock(&io_request_lock); spin_unlock(&io_request_lock);
(void) ide_do_drive_cmd (drive, rq, ide_end); (void) ide_do_drive_cmd (drive, rq, ide_end);
spin_lock(&io_request_lock); spin_lock_irq(&io_request_lock);
return 0; return 0;
abort: abort:
if (pc) kfree (pc); if (pc) kfree (pc);
......
...@@ -750,6 +750,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, ...@@ -750,6 +750,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
case TYPE_MOD: case TYPE_MOD:
case TYPE_PROCESSOR: case TYPE_PROCESSOR:
case TYPE_SCANNER: case TYPE_SCANNER:
case TYPE_MEDIUM_CHANGER:
SDpnt->writeable = 1; SDpnt->writeable = 1;
break; break;
case TYPE_WORM: case TYPE_WORM:
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
* *
********************************************************************/ ********************************************************************/
#include <linux/config.h>
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < 0x020101 #if LINUX_VERSION_CODE < 0x020101
# define LINUX20 # define LINUX20
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#ifndef __MSND_CLASSIC_H #ifndef __MSND_CLASSIC_H
#define __MSND_CLASSIC_H #define __MSND_CLASSIC_H
#include <linux/config.h>
#define DSP_NUMIO 0x10 #define DSP_NUMIO 0x10
#define HP_MEMM 0x08 #define HP_MEMM 0x08
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#ifndef __MSND_PINNACLE_H #ifndef __MSND_PINNACLE_H
#define __MSND_PINNACLE_H #define __MSND_PINNACLE_H
#include <linux/config.h>
#define DSP_NUMIO 0x08 #define DSP_NUMIO 0x08
#define HP_DSPR 0x04 #define HP_DSPR 0x04
......
...@@ -66,7 +66,7 @@ tristate 'Kernel automounter support' CONFIG_AUTOFS_FS ...@@ -66,7 +66,7 @@ tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
if [ "$CONFIG_AFFS_FS" != "n" ]; then if [ "$CONFIG_AFFS_FS" != "n" ]; then
define_bool CONFIG_AMIGA_PARTITION y define_bool CONFIG_AMIGA_PARTITION y
fi fi
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS tristate 'UFS filesystem support' CONFIG_UFS_FS
if [ "$CONFIG_UFS_FS" != "n" ]; then if [ "$CONFIG_UFS_FS" != "n" ]; then
bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile. # Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := ufs.o O_TARGET := ufs.o
O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \ O_OBJS := acl.o balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
ufs_super.o ufs_symlink.o ufs_swab.o namei.o super.o symlink.o truncate.o util.o
M_OBJS := $(O_TARGET) M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
/*
* 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;
}
/*
* 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,
};
/*
* 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];
}
...@@ -11,11 +11,22 @@ ...@@ -11,11 +11,22 @@
* 4.4BSD (FreeBSD) support added on February 1st 1998 by * 4.4BSD (FreeBSD) support added on February 1st 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk> partially based * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
* on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. * 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 <linux/fs.h>
#include "ufs_swab.h" #include "swab.h"
#include "util.h"
#undef UFS_DIR_DEBUG
#ifdef UFS_DIR_DEBUG
#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
#else
#define UFSD(x)
#endif
/* /*
* This is blatantly stolen from ext2fs * This is blatantly stolen from ext2fs
...@@ -28,10 +39,11 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -28,10 +39,11 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
unsigned long offset, lblk, blk; unsigned long offset, lblk, blk;
int i, stored; int i, stored;
struct buffer_head * bh; struct buffer_head * bh;
struct ufs_direct * de; struct ufs_dir_entry * de;
struct super_block * sb; struct super_block * sb;
int de_reclen; int de_reclen;
__u32 flags; unsigned flags, swab;
/* Isn't that already done in the upper layer??? /* Isn't that already done in the upper layer???
* the VFS layer really needs some explicit documentation! * the VFS layer really needs some explicit documentation!
...@@ -40,13 +52,10 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -40,13 +52,10 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
return -EBADF; return -EBADF;
sb = inode->i_sb; sb = inode->i_sb;
swab = sb->u.ufs_sb.s_swab;
flags = sb->u.ufs_sb.s_flags; flags = sb->u.ufs_sb.s_flags;
if (flags & UFS_DEBUG) { UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
printk("ufs_readdir: ino %lu f_pos %lu\n",
inode->i_ino, (unsigned long) filp->f_pos);
ufs_print_inode(inode);
}
stored = 0; stored = 0;
bh = NULL; bh = NULL;
...@@ -73,8 +82,7 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -73,8 +82,7 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
* to make sure. */ * to make sure. */
if (filp->f_version != inode->i_version) { if (filp->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) { for (i = 0; i < sb->s_blocksize && i < offset; ) {
de = (struct ufs_direct *) de = (struct ufs_dir_entry *)(bh->b_data + i);
(bh->b_data + i);
/* It's too expensive to do a full /* It's too expensive to do a full
* dirent test each time round this * dirent test each time round this
* loop, but we do have to test at * loop, but we do have to test at
...@@ -94,9 +102,9 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -94,9 +102,9 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
while (!error && filp->f_pos < inode->i_size while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) { && offset < sb->s_blocksize) {
de = (struct ufs_direct *) (bh->b_data + offset); de = (struct ufs_dir_entry *) (bh->b_data + offset);
/* XXX - put in a real ufs_check_dir_entry() */ /* XXX - put in a real ufs_check_dir_entry() */
if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) { if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
/* SWAB16() was unneeded -- compare to 0 */ /* SWAB16() was unneeded -- compare to 0 */
filp->f_pos = (filp->f_pos & filp->f_pos = (filp->f_pos &
(sb->s_blocksize - 1)) + (sb->s_blocksize - 1)) +
...@@ -128,11 +136,9 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -128,11 +136,9 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
* during the copy operation. */ * during the copy operation. */
unsigned long version = inode->i_version; unsigned long version = inode->i_version;
if (flags & UFS_DEBUG) { UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
printk("ufs_readdir: filldir(%s,%u)\n", UFSD(("namlen %u\n", ufs_namlen(de)))
de->d_name, SWAB32(de->d_ino)); error = filldir(dirent, de->d_name, ufs_namlen(de),
}
error = filldir(dirent, de->d_name, NAMLEN(de),
filp->f_pos, SWAB32(de->d_ino)); filp->f_pos, SWAB32(de->d_ino));
if (error) if (error)
break; break;
...@@ -145,15 +151,45 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) ...@@ -145,15 +151,45 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
offset = 0; offset = 0;
brelse (bh); brelse (bh);
} }
#if 0 /* XXX */ UPDATE_ATIME(inode);
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
#endif /* XXX */
return 0; 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 = { static struct file_operations ufs_dir_operations = {
NULL, /* lseek */ NULL, /* lseek */
NULL, /* read */ NULL, /* read */
...@@ -172,20 +208,21 @@ static struct file_operations ufs_dir_operations = { ...@@ -172,20 +208,21 @@ static struct file_operations ufs_dir_operations = {
struct inode_operations ufs_dir_inode_operations = { struct inode_operations ufs_dir_inode_operations = {
&ufs_dir_operations, /* default directory file operations */ &ufs_dir_operations, /* default directory file operations */
NULL, /* create */ ufs_create, /* create */
ufs_lookup, /* lookup */ ufs_lookup, /* lookup */
NULL, /* link */ ufs_link, /* link */
NULL, /* unlink */ ufs_unlink, /* unlink */
NULL, /* symlink */ ufs_symlink, /* symlink */
NULL, /* mkdir */ ufs_mkdir, /* mkdir */
NULL, /* rmdir */ ufs_rmdir, /* rmdir */
NULL, /* mknod */ ufs_mknod, /* mknod */
NULL, /* rename */ ufs_rename, /* rename */
NULL, /* readlink */ NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */ NULL, /* readpage */
NULL, /* writepage */ NULL, /* writepage */
NULL, /* bmap */ ufs_bmap, /* bmap */
NULL, /* truncate */ ufs_truncate, /* truncate */
NULL, /* permission */ ufs_permission, /* permission */
NULL, /* smap */ NULL, /* smap */
}; };
/*
* 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;
}
/*
* 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;
}
/*
* 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);
}
/*
* 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;
}
/*
* 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
/*
* 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 */
/*
* 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 */
};
/*
* 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"))
}
/*
* 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 */
};
/*
* 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;
}
/*
* 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);
}
/*
* 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;
}
/*
* 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
}
/*
* 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 */
/*
* 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 */
};
/*
* 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
/*
* 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);
}
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/processor.h> #include <asm/processor.h>
#ifdef CONFIG_MTRR
# include <asm/mtrr.h>
#endif
#define CONFIG_BUGi386 #define CONFIG_BUGi386
__initfunc(static void no_halt(char *s, int *ints)) __initfunc(static void no_halt(char *s, int *ints))
...@@ -333,7 +329,4 @@ __initfunc(static void check_bugs(void)) ...@@ -333,7 +329,4 @@ __initfunc(static void check_bugs(void))
check_amd_k6(); check_amd_k6();
check_pentium_f00f(); check_pentium_f00f();
system_utsname.machine[1] = '0' + boot_cpu_data.x86; system_utsname.machine[1] = '0' + boot_cpu_data.x86;
#if defined(CONFIG_MTRR)
mtrr_init ();
#endif
} }
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/posix_types.h>
#include <linux/nfsd/const.h> #include <linux/nfsd/const.h>
#include <linux/nfsd/export.h> #include <linux/nfsd/export.h>
#include <linux/nfsd/nfsfh.h> #include <linux/nfsd/nfsfh.h>
...@@ -54,29 +55,29 @@ struct nfsctl_client { ...@@ -54,29 +55,29 @@ struct nfsctl_client {
struct nfsctl_export { struct nfsctl_export {
char ex_client[NFSCLNT_IDMAX+1]; char ex_client[NFSCLNT_IDMAX+1];
char ex_path[NFS_MAXPATHLEN+1]; char ex_path[NFS_MAXPATHLEN+1];
dev_t ex_dev; __kernel_dev_t ex_dev;
ino_t ex_ino; __kernel_ino_t ex_ino;
int ex_flags; int ex_flags;
uid_t ex_anon_uid; __kernel_uid_t ex_anon_uid;
gid_t ex_anon_gid; __kernel_gid_t ex_anon_gid;
}; };
/* UGIDUPDATE */ /* UGIDUPDATE */
struct nfsctl_uidmap { struct nfsctl_uidmap {
char * ug_ident; char * ug_ident;
uid_t ug_uidbase; __kernel_uid_t ug_uidbase;
int ug_uidlen; int ug_uidlen;
uid_t * ug_udimap; __kernel_uid_t * ug_udimap;
uid_t ug_gidbase; __kernel_gid_t ug_gidbase;
int ug_gidlen; int ug_gidlen;
gid_t * ug_gdimap; __kernel_gid_t * ug_gdimap;
}; };
/* GETFH */ /* GETFH */
struct nfsctl_fhparm { struct nfsctl_fhparm {
struct sockaddr gf_addr; struct sockaddr gf_addr;
dev_t gf_dev; __kernel_dev_t gf_dev;
ino_t gf_ino; __kernel_ino_t gf_ino;
int gf_version; int gf_version;
}; };
......
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
#ifndef __LINUX_UFS_FS_H #ifndef __LINUX_UFS_FS_H
#define __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/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/time.h> #include <linux/time.h>
...@@ -35,11 +31,15 @@ ...@@ -35,11 +31,15 @@
#define UFS_SBLOCK 8192 #define UFS_SBLOCK 8192
#define UFS_SBSIZE 8192 #define UFS_SBSIZE 8192
#define SECTOR_SIZE 512
#define SECTOR_BITS 9
#define UFS_MAGIC 0x00011954 #define UFS_MAGIC 0x00011954
#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ #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_NDADDR 12
#define UFS_NINDIR 3 #define UFS_NINDIR 3
...@@ -48,7 +48,13 @@ ...@@ -48,7 +48,13 @@
#define UFS_DIND_BLOCK (UFS_NDADDR + 1) #define UFS_DIND_BLOCK (UFS_NDADDR + 1)
#define UFS_TIND_BLOCK (UFS_NDADDR + 2) #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_ROOTINO 2
#define UFS_FIRST_INO (UFS_ROOTINO + 1)
#define UFS_USEEFT ((__u16)65535) #define UFS_USEEFT ((__u16)65535)
...@@ -87,62 +93,109 @@ ...@@ -87,62 +93,109 @@
#define UFS_HURD 0x00000130 #define UFS_HURD 0x00000130
#define UFS_SUN 0x00000200 #define UFS_SUN 0x00000200
#define UFS_NEXT 0x00000400 #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 */ /* fs_inodefmt options */
#define UFS_42INODEFMT -1 #define UFS_42INODEFMT -1
#define UFS_44INODEFMT 2 #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
/* Test if the inode number is valid. */ /*
#define ufs_ino_ok(inode) ((inode->i_ino < 2) && \ * Turn file system block numbers into disk block addresses.
(inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1))) * 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)
/* Convert (sb,cg) to the first physical block number for that cg. */ /*
#define ufs_cgstart(sb, cg) \ * Cylinder group macros to locate things in cylinder groups.
(((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask))) * 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 phys. block number for inodes in that cg. */ /*
#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno) * Macros for handling inode numbers:
#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno) * 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)
/*
* 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. */ * Compute the cylinder and rotational position of a cyl block addr.
#define ufs_ino2cg(inode) ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg) */
#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) \ * The following macros optimize certain frequently calculated
( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \ * quantities by using shifts and masks in place of divisions
? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \ * modulos and multiplications.
: (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ ) */
#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_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)) * UFS_DIR_PAD defines the directory entries boundaries
#define ufs_dbn(sb, block, boff) ((block) + ufs_boff((sb), (boff))) * (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 { struct ufs_timeval {
__s32 tv_sec; __s32 tv_sec;
__s32 tv_usec; __s32 tv_usec;
}; };
struct ufs_direct { struct ufs_dir_entry {
__u32 d_ino; /* inode number of this entry */ __u32 d_ino; /* inode number of this entry */
__u16 d_reclen; /* length of this entry */ __u16 d_reclen; /* length of this entry */
union { union {
...@@ -155,9 +208,6 @@ struct ufs_direct { ...@@ -155,9 +208,6 @@ struct ufs_direct {
__u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */ __u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */
}; };
#define MAXMNTLEN 512
#define MAXCSBUFS 32
struct ufs_csum { struct ufs_csum {
__u32 cs_ndir; /* number of directories */ __u32 cs_ndir; /* number of directories */
__u32 cs_nbfree; /* number of free blocks */ __u32 cs_nbfree; /* number of free blocks */
...@@ -168,7 +218,7 @@ struct ufs_csum { ...@@ -168,7 +218,7 @@ struct ufs_csum {
/* /*
* This is the actual superblock, as it is laid out on the disk. * 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_link; /* UNUSED */
__u32 fs_rlink; /* UNUSED */ __u32 fs_rlink; /* UNUSED */
__u32 fs_sblkno; /* addr of super-block in filesys */ __u32 fs_sblkno; /* addr of super-block in filesys */
...@@ -237,15 +287,18 @@ struct ufs_superblock { ...@@ -237,15 +287,18 @@ struct ufs_superblock {
__u8 fs_clean; /* file system is clean flag */ __u8 fs_clean; /* file system is clean flag */
__u8 fs_ronly; /* mounted read-only flag */ __u8 fs_ronly; /* mounted read-only flag */
__u8 fs_flags; /* currently unused 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 */ /* these fields retain the current block allocation info */
__u32 fs_cgrotor; /* last cg searched */ __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 */ __u32 fs_cpc; /* cyl per cycle in postbl */
__u16 fs_opostbl[16][8]; /* old rotation block list head */ __u16 fs_opostbl[16][8]; /* old rotation block list head */
union { union {
struct { 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 */ __s32 fs_state; /* file system state time stamp */
__u32 fs_qbmask[2]; /* ~usb_bmask */ __u32 fs_qbmask[2]; /* ~usb_bmask */
__u32 fs_qfmask[2]; /* ~usb_fmask */ __u32 fs_qfmask[2]; /* ~usb_fmask */
...@@ -255,7 +308,7 @@ struct ufs_superblock { ...@@ -255,7 +308,7 @@ struct ufs_superblock {
__s32 fs_contigsumsize;/* size of cluster summary array */ __s32 fs_contigsumsize;/* size of cluster summary array */
__s32 fs_maxsymlinklen;/* max length of an internal symlink */ __s32 fs_maxsymlinklen;/* max length of an internal symlink */
__s32 fs_inodefmt; /* format of on-disk inodes */ __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_qbmask[2]; /* ~usb_bmask */
__u32 fs_qfmask[2]; /* ~usb_fmask */ __u32 fs_qfmask[2]; /* ~usb_fmask */
__s32 fs_state; /* file system state time stamp */ __s32 fs_state; /* file system state time stamp */
...@@ -269,6 +322,59 @@ struct ufs_superblock { ...@@ -269,6 +322,59 @@ struct ufs_superblock {
__u8 fs_space[1]; /* list of blocks for each rotation */ __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 * structure of an on-disk inode
*/ */
...@@ -277,11 +383,11 @@ struct ufs_inode { ...@@ -277,11 +383,11 @@ struct ufs_inode {
__u16 ui_nlink; /* 0x2 */ __u16 ui_nlink; /* 0x2 */
union { union {
struct { struct {
__u16 suid; /* 0x4 */ __u16 ui_suid; /* 0x4 */
__u16 sgid; /* 0x6 */ __u16 ui_sgid; /* 0x6 */
} oldids; } oldids;
__u32 inumber; /* 0x4 lsf: inode number */ __u32 ui_inumber; /* 0x4 lsf: inode number */
__u32 author; /* 0x4 GNU HURD: author */ __u32 ui_author; /* 0x4 GNU HURD: author */
} ui_u1; } ui_u1;
__u64 ui_size; /* 0x8 */ __u64 ui_size; /* 0x8 */
struct ufs_timeval ui_atime; /* 0x10 access */ struct ufs_timeval ui_atime; /* 0x10 access */
...@@ -334,42 +440,72 @@ struct ufs_inode { ...@@ -334,42 +440,72 @@ struct ufs_inode {
#define UFS_SF_APPEND 0x00040000 /* append-only */ #define UFS_SF_APPEND 0x00040000 /* append-only */
#define UFS_SF_NOUNLINK 0x00100000 /* can't be removed or renamed */ #define UFS_SF_NOUNLINK 0x00100000 /* can't be removed or renamed */
#ifdef __KERNEL__ #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 *); /* acl.c */
extern int ufs_permission (struct inode *, int);
/* ufs_namei.c */
extern int ufs_lookup (struct inode *, struct dentry *);
/* ufs_super.c */ /* balloc.c */
extern void ufs_warning (struct super_block *, const char *, const char *, ...) extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
__attribute__ ((format (printf, 3, 4))); extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
extern int init_ufs_fs(void); extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *);
/* /* cylinder.c */
* Inodes and files operations 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 inode_operations ufs_dir_inode_operations;
extern struct file_operations ufs_dir_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 inode_operations ufs_file_inode_operations;
extern struct file_operations ufs_file_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 inode_operations ufs_symlink_inode_operations;
extern struct file_operations ufs_symlink_operations;
/* truncate.c */
extern void ufs_truncate (struct inode *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* *
* NeXTstep support added on February 5th 1998 by * NeXTstep support added on February 5th 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk>. * Niels Kristian Bech Jensen <nkbj@image.dk>.
*
* write support by Daniel Pirkl <daniel.pirkl@email.cz>
*/ */
#ifndef _LINUX_UFS_FS_I_H #ifndef _LINUX_UFS_FS_I_H
...@@ -16,7 +18,7 @@ ...@@ -16,7 +18,7 @@
struct ufs_inode_info { struct ufs_inode_info {
union { union {
__u32 i_data[15]; __u32 i_data[15];
__u8 i_symlink[4*15]; /* fast symlink */ __u8 i_symlink[4*15];
} i_u1; } i_u1;
__u64 i_size; __u64 i_size;
__u32 i_flags; __u32 i_flags;
...@@ -25,6 +27,8 @@ struct ufs_inode_info { ...@@ -25,6 +27,8 @@ struct ufs_inode_info {
__u32 i_uid; __u32 i_uid;
__u32 i_gid; __u32 i_gid;
__u32 i_oeftflag; __u32 i_oeftflag;
__u16 i_osync;
__u32 i_lastfrag;
}; };
#endif /* _LINUX_UFS_FS_I_H */ #endif /* _LINUX_UFS_FS_I_H */
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
* Laboratory for Computer Science Research Computing Facility * Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey * Rutgers, The State University of New Jersey
* *
* NeXTstep support added on February 5th 1998 by * $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $
* Niels Kristian Bech Jensen <nkbj@image.dk>. *
* Write support by Daniel Pirkl (daniel.pirkl@email.cz)
* Charles University (Prague), Faculty of Mathematics and Physics
*/ */
#ifndef __LINUX_UFS_FS_SB_H #ifndef __LINUX_UFS_FS_SB_H
...@@ -15,27 +17,210 @@ ...@@ -15,27 +17,210 @@
#include <linux/ufs_fs.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_sb_info {
struct ufs_superblock * s_raw_sb; struct ufs_sb_private_info * s_uspi;
__u32 s_flags; /* internal flags for UFS code */ struct ufs_csum * s_csp[UFS_MAXCSBUFS];
__u32 s_ncg; /* used in ufs_read_inode */ int s_rename_lock;
__u32 s_ipg; /* used in ufs_read_inode */ struct wait_queue * s_rename_wait;
__u32 s_fpg; unsigned s_swab;
__u32 s_fsize; unsigned s_flags;
__u32 s_fshift; struct buffer_head ** s_ucg;
__u32 s_fmask; struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED];
__u32 s_bsize; unsigned s_cgno[UFS_MAX_GROUP_LOADED];
__u32 s_bmask; unsigned short s_cg_loaded;
__u32 s_bshift; };
__u32 s_iblkno;
__u32 s_dblkno; /*
__u32 s_cgoffset; * Sizes of this structures are:
__u32 s_cgmask; * ufs_super_block_first 512
__u32 s_inopb; * ufs_super_block_second 512
__u32 s_lshift; * ufs_super_block_third 356
__u32 s_lmask; */
__u32 s_fsfrag; struct ufs_super_block_first {
__u32 s_blockbase; /* offset of NeXTstep superblock */ __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 */ #endif /* __LINUX_UFS_FS_SB_H */
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
#include <linux/dio.h> #include <linux/dio.h>
#endif #endif
#ifdef CONFIG_MTRR
# include <asm/mtrr.h>
#endif
/* /*
* Versions of gcc older than that listed below may actually compile * Versions of gcc older than that listed below may actually compile
* and link okay, but the end product can have subtle run time bugs. * and link okay, but the end product can have subtle run time bugs.
...@@ -1106,11 +1110,21 @@ __initfunc(asmlinkage void start_kernel(void)) ...@@ -1106,11 +1110,21 @@ __initfunc(asmlinkage void start_kernel(void))
#if defined(CONFIG_QUOTA) #if defined(CONFIG_QUOTA)
dquot_init_hash(); dquot_init_hash();
#endif #endif
printk("POSIX conformance testing by UNIFIX\n");
check_bugs();
#ifdef __SMP__ #ifdef __SMP__
smp_init(); smp_init();
#endif #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(); sock_init();
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
......
...@@ -105,10 +105,19 @@ void scheduling_functions_start_here(void) { } ...@@ -105,10 +105,19 @@ void scheduling_functions_start_here(void) { }
static inline void reschedule_idle(struct task_struct * p) static inline void reschedule_idle(struct task_struct * p)
{ {
/* /*
* For SMP, we try to see if the CPU the task used * For SMP, we try to see if the CPU the task used
* to run on is idle.. * 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__ #ifdef __SMP__
int want_cpu = p->processor; int want_cpu = p->processor;
...@@ -131,6 +140,7 @@ static inline void reschedule_idle(struct task_struct * p) ...@@ -131,6 +140,7 @@ static inline void reschedule_idle(struct task_struct * p)
} }
} while (--i > 0); } while (--i > 0);
} }
#endif
#endif #endif
if (p->policy != SCHED_OTHER || p->counter > current->counter + 3) if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
current->need_resched = 1; current->need_resched = 1;
......
...@@ -532,6 +532,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) ...@@ -532,6 +532,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
error = blkdev_open(swap_dentry->d_inode, &filp); error = blkdev_open(swap_dentry->d_inode, &filp);
if (error) if (error)
goto bad_swap_2; goto bad_swap_2;
set_blocksize(p->swap_device, PAGE_SIZE);
error = -ENODEV; error = -ENODEV;
if (!p->swap_device || if (!p->swap_device ||
(blk_size[MAJOR(p->swap_device)] && (blk_size[MAJOR(p->swap_device)] &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment