E: cananian@alumni.princeton.edu
W: http://www.pdos.lcs.mit.edu/~cananian
P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0
-D: pty improvements.
+D: Unix98 pty support.
+D: APM update to 1.2 spec.
N: Erik Andersen
E: andersee@debian.org
N: Bas Laarhoven
E: bas@vimec.nl
D: Loadable modules and ftape driver
-S: Mr. v. Boemellaan 39
-S: NL-5237 KA 's-Hertogenbosch
+S: J. Obrechtstr 23
+S: NL-5216 GP 's-Hertogenbosch
S: The Netherlands
N: Savio Lam
N: Dirk Melchers
E: dirk@merlin.nbg.sub.org
D: 8 bit XT hard disk driver for OMTI5520
-S: Heidackerstrass 19
-S: D-91056 Erlangen
+S: Schloessleinsgasse 31
+S: D-90453 Nuernberg
S: Germany
N: Michael Meskes
therefore owes credit to the same people as that file (Jared Mauch,
Axel Boldt, Alessandro Sigala, and countless other users all over the
'net). Please feel free to submit changes, corrections, gripes,
-flames, money, etc. to me (gt1355b@prism.gatech.edu). If you do so,
-you don't need to bother doing so in the form of a diff, as this is
-generated by texinfo so a diff is useless anyway (though I can
-incorporate one by hand if you insist upon sending it that way ;-).
+flames, money, etc. to me (kaboom@gatech.edu). If you do so, you don't
+need to bother doing so in the form of a diff, as this is generated by
+texinfo so a diff is useless anyway (though I can incorporate one by
+hand if you insist upon sending it that way ;-).
Check out http://www.cviog.uga.edu/Misc/info/LinuxBleed.html for an
HTML-ized shopping list.
http://www.datanet.hu/generations/linux/Changes2.html is an
English-language HTML version.
-Last updated: September 13. 1997
-Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
+ The most current version should always be available from
+http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
+
+ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
+needs.
+
+Last updated: February 16. 1998
+Current Author: Chris Ricker (kaboom@gatech.edu).
Current Minimal Requirements
****************************
encountered a bug! If you're unsure what version you're currently
running, the suggested command should tell you.
-- Kernel modules modutils-2.1.55 ; insmod -V
+- Kernel modules modutils-2.1.85 ; insmod -V
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.1 ; ld -v
- Linux C Library 5.4.38 ; ls -l /lib/libc.so.*
- Dynamic Linker (ld.so) 1.9.5 ; ldd -v
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
-- Procps 1.2 ; ps --version
+- Procps 1.2.5 ; ps --version
- Procinfo 0.11 ; procinfo -v
-- Mount 2.6h ; mount --version
+- Mount 2.7l ; mount --version
- Net-tools 1.41 ; hostname -V
- Loadlin 1.6a
- Sh-utils 1.16 ; expr --v
-- Autofs 0.3.11 ; automount --version
+- Autofs 0.3.11 ; automount --version
- NFS 0.4.21 ; showmount --version
- Bash 1.14.7 ; bash -version
+- Ncpfs 2.1.1 ; ncpmount -v
+- Pcmcia-cs 2.9.12
+- PPP 2.3.3 ; pppd -v
Upgrade notes
*************
For modules to work, you need to be running libc-5.4.x or greater.
Since updates to libc fix other problems as well (security flaws, for
example) and since 5.4.7 is missing a few needed symbols, try to get
-the latest 5.4.x you can. Currently, libc-5.4.38 is the latest public
+the latest 5.4.x you can. Currently, libc-5.4.44 is the latest public
release.
If you upgrade to libc-5.4.x, you also have to upgrade your dynamic
If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
you're using NIS.
+ If you upgrade to libc-5.4.44, please read and pay attention to its
+accompanying release notes. The section about it breaking make is not
+a joke.
+
Modules
=======
- You need to upgrade to modutils-2.1.55 for kernels 2.1.55 and later.
+ You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later.
This version will also work with 2.0.x kernels.
Binutils
You need at least GCC 2.7.2 to compile the kernel. If you're
upgrading from an earlier release, you might as well get GCC 2.7.2.3,
-the latest public release. If you already have GCC 2.7.2 on your
-system, you don't have to upgrade just so the kernel will work (though
-feel free to upgrade if you want the gcc bug fixes).
+the latest stable public release. If you already have GCC 2.7.2 on
+your system, you don't have to upgrade just so the kernel will work
+(though feel free to upgrade if you want the gcc bug fixes).
+
+ Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad
+Things while compiling your kernel, particularly if absurd
+optimizations (like -O9) are used. Caveat emptor.
Networking Changes
==================
/dev/lp0 with the new Plug-and-Play driver. If printing breaks with
the new driver, try checking your lpd configuration.
-pppd
-====
-This kernel version needs a minor bugfix to pppd. See
-Documentation/networking/ppp.txt for more information.
-
Syncookies
==========
-When you build your kernel with Syncookie support (CONFIG_SYN_COOKIES)
-the syncookie code still defaults to off (unlike the 2.0.30+ behaviour).
-You have to explicitely enable it by add a line like
-echo 1 >/proc/sys/net/ipv4/tcp_syncookies
-to one of your startup scripts (e.g. /etc/rc.d/rc.local on a redhat system)
+
+ When you build your kernel with Syncookie support
+(CONFIG_SYN_COOKIES) the syncookie code still defaults to off (unlike
+the 2.0.30+ behavior). You have to explicitly enable it by issuing the
+following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies
Bash
====
cause problems when compiling modules. Upgrade to at least 1.14 to fix
this problem.
+Ncpfs
+=====
+
+ To mount NetWare shares, you'll need to upgrade to a more recent
+version of the ncpfs utils.
+
+Pcmcia-cs
+=========
+
+ If you use pcmcia cards, you'll need to upgrade the daemon and
+support utils to the latest release of pcmcia-cs.
+
+PPP
+===
+
+ Due to changes in the routing code, those of you using PPP
+networking will need to upgrade your pppd.
+
Where to get the files
**********************
Modules utilities
=================
-The 2.1.55 release:
-ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.55.tar.gz
-ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.55.tar.gz
+The 2.1.85 release:
+ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.85.tar.gz
+ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz
Procps utilities
================
The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.5.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.5.tgz
Procinfo utilities
==================
Mount
=====
-The 2.6h release:
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6h.tar.gz
+The 2.7l release:
+ftp://ftp.win.tue.nl/pub/linux/util/mount/mount-2.7l.tar.gz
Autofs
======
Net-tools
=========
-The 1.41 release:
-ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
-ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
+The 1.432 release:
+ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.432.tar.gz
Ypbind
======
The 1.14.7 release:
ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz
+Ncpfs
+=====
+
+The 2.1.1 release:
+ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz
+ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz
+
+Pcmcia-cs
+=========
+
+The 1.9.12 release:
+ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-2.9.12.tar.gz
+
+PPP
+===
+
+The 2.3.3 release:
+ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.3.tar.gz
+
Other Info
==========
Please send info about any other packages that 2.1.x "broke" or about
any new features of 2.1.x that require extra or new packages for use to
-Chris Ricker (gt1355b@prism.gatech.edu).
+Chris Ricker (kaboom@gatech.edu).
powers off the computer). As with the other APM options, this
option may not work reliably with some APM BIOS implementations.
+Ignore multiple suspend/standby events
+CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ This option is necessary on the Thinkpad 560, but should work on all
+ other laptops. When the APM BIOS returns multiple suspend or standby
+ events while one is already being processed they will be ignored.
+ Without this the Thinkpad 560 has troubles with apmd, and pcmcia-cs.
+
Watchdog Timer Support
CONFIG_WATCHDOG
If you say Y here (and to one of the following options) and create a
verbose The volume name, file system type and block size will
be written to the syslog when the filesystem is mounted.
+mufs The filesystem is really a muFS, also it doesn't
+ identify itself as one. This option is neccessary if
+ the filesystem wasn't formatted as muFS, but is used
+ as one.
+
prefix=path Path will be prefixed to every absolute path name of
symbolic links on an AFFS partition. Default = /
The VFS relatively simple, but it is nice not to have to browse through
pages of code to determine what is expected when writing a filesystem.
Hopefully this helps anyone attempting such a feat, as well as clearing up
-a few important points/dependancies.
+a few important points/dependencies.
register_filesystem (struct file_system_type *fstype)
5. Application
a) For some card-types, firmware has to be loaded into the cards, before
- proceeding with device-independant setup. See README.<yourDriver>
+ proceeding with device-independent setup. See README.<yourDriver>
for how to do that.
b) If you only intend to use ttys, you are nearly ready now.
type.
The second parameter <trackbuffer> tells the kernel whether to use
- track buffering (1) or not (0). The default is machine dependant:
+ track buffering (1) or not (0). The default is machine-dependent:
no for the Medusa and yes for all others.
With the two following parameters, you can change the default
software but have not been seen, enable the exception in
hardware so that we can update our software status mask. */
fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+ fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
wrfpcr(fpcr);
return 0;
NULL, NULL, NULL, NULL }},
{ X86_VENDOR_INTEL, 6,
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II", NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+ "Pentium II (0.25 um)", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_CYRIX, 4,
{ NULL, NULL, NULL, NULL, "MediaGX", NULL, NULL, NULL, NULL, "5x86",
NULL, NULL, NULL, NULL, NULL, NULL }},
c->cpuid_level < 0)
return;
- if ((c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) ||
- (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c)))
+ if (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c))
return;
if (c->x86_model < 16)
p = cpu_models[i].model_names[c->x86_model];
break;
}
- if (p)
+ if (p) {
strcpy(c->x86_model_id, p);
- else
- sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
+ return;
+ }
+
+ if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
+ return;
+
+ sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
}
static char *cpu_vendor_names[] __initdata = {
# CONFIG_KERNELD is not set
#
-# Platform dependant setup
+# Platform-dependent setup
#
CONFIG_AMIGA=y
# CONFIG_ATARI is not set
endif
#
-# CPU dependand compiler/assembler options for optimization.
+# CPU-dependent compiler/assembler options for optimization.
#
ifdef CONFIG_CPU_R3000
CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1
endif
#
-# Board dependand options and extra files
+# Board-dependent options and extra files
#
ifdef CONFIG_ALGOR_P4032
CORE_FILES += arch/mips/algor/algor.o
/*
- * Setup pointers to hardware dependand routines.
+ * Setup pointers to hardware-dependent routines.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
/*
- * Setup pointers to hardware dependand routines.
+ * Setup pointers to hardware-dependent routines.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
#undef p
break;
case StartDepFunc:
- printk("Start dependant function:\n");
+ printk("Start dependent function:\n");
break;
case EndDepFunc:
- printk("End dependant function\n");
+ printk("End dependent function\n");
break;
case IOPort:
#define p pkt->S8_Pack
bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
+ bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
fi
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
* Version 1.0 and 1.1
* May 1996, Version 1.2
* Feb 1998, Version 1.3
+ * Feb 1998, Version 1.4
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
* The new replacment for it is, but Linux doesn't yet support this.
* Alan Cox Linux 2.1.55
* 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
+ * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
+ * Dean Gaudet <dgaudet@arctic.org>.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
*
- * Reference:
+ * APM 1.1 Reference:
*
* Intel Corporation, Microsoft Corporation. Advanced Power Management
* (APM) BIOS Interface Specification, Revision 1.1, September 1993.
* ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
* available from Microsoft by calling 206.882.8080.]
*
+ * APM 1.2 Reference:
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
+ *
+ * [This document is available from Intel at:
+ * http://www.intel.com/IAL/powermgm
+ * or Microsoft at
+ * http://www.microsoft.com/windows/thirdparty/hardware/pcfuture.htm
+ * ]
*/
#include <linux/config.h>
* problems have been reported when using this option with gpm (if you'd
* like to debug this, please do so).
*
+ * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
+ * on returning multiple suspend/standby events whenever one occurs. We
+ * really only need one at a time, so just ignore any beyond the first.
+ * This is probably safe on most laptops.
+ *
* If you are debugging the APM support for your laptop, note that code for
* all of these options is contained in this file, so you can #define or
* #undef these on the next line to avoid recompiling the whole kernel.
#endif
static int suspends_pending = 0;
static int standbys_pending = 0;
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+static int waiting_for_resume = 0;
+#endif
static long clock_cmos_diff;
static int got_clock_diff = 0;
static struct timer_list apm_timer;
-static char driver_version[] = "1.3"; /* no spaces */
+static char driver_version[] = "1.4"; /* no spaces */
#ifdef APM_DEBUG
static char * apm_event_name[] = {
if (as == sender)
continue;
as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
- if (as->event_head == as->event_tail)
+ if (as->event_head == as->event_tail) {
+ static int notified;
+
+ if (notified == 0) {
+ printk( "apm_bios: an event queue overflowed\n" );
+ notified = 1;
+ }
as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+ }
as->events[as->event_head] = event;
if (!as->suser)
continue;
apm_event_t event;
while ((event = get_event()) != 0) {
+#ifdef APM_DEBUG
+ if (event <= NR_APM_EVENT_NAME)
+ printk(KERN_DEBUG "APM BIOS received %s notify\n",
+ apm_event_name[event - 1]);
+ else
+ printk(KERN_DEBUG "APM BIOS received unknown "
+ "event 0x%02x\n", event);
+#endif
switch (event) {
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ if (waiting_for_resume) {
+ return;
+ }
+ waiting_for_resume = 1;
+#endif
send_event(event, APM_STANDBY_RESUME, NULL);
if (standbys_pending <= 0)
standby();
break;
#endif
case APM_SYS_SUSPEND:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ if (waiting_for_resume) {
+ return;
+ }
+ waiting_for_resume = 1;
+#endif
send_event(event, APM_NORMAL_RESUME, NULL);
if (suspends_pending <= 0)
suspend();
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
case APM_STANDBY_RESUME:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ waiting_for_resume = 0;
+#endif
set_time();
send_event(event, 0, NULL);
break;
suspend();
break;
}
-#ifdef APM_DEBUG
- if (event <= NR_APM_EVENT_NAME)
- printk(KERN_DEBUG "APM BIOS received %s notify\n",
- apm_event_name[event - 1]);
- else
- printk(KERN_DEBUG "APM BIOS received unknown event 0x%02x\n",
- event);
-#endif
}
}
/* ----------------------------------------------------------------------
Begin generic memory functions. These functions will be alias
- (point at) more specific functions dependant on the board being
+ (point at) more specific functions dependent on the board being
configured.
----------------------------------------------------------------------- */
cards (Such as PCI) needs no windowing routines at all. We provide
these do nothing routines so that the same code base can be used.
The driver will ALWAYS call a windowing routine if it thinks it needs
- to; regardless of the card. However, dependant on the card the routine
+ to; regardless of the card. However, dependent on the card the routine
may or may not do anything.
---------------------------------------------------------------------------*/
base_addr5);
/* ------------------------------------------------------------------------
- NOTE - The code below mask out either the 2 or 4 bits dependant on the
+ NOTE - The code below mask out either the 2 or 4 bits dependent on the
space being addressed. (base_addr value reflecting io space, have their
first 2 bits mask out, while base_addr value reflecting mem space, have
their first 4 bits mask out.) These bits are flag bits and should always
static __inline__ void lp_yield (int minor)
{
- if (parport_yield (lp_table[minor].dev, 1) == 1 && need_resched)
+ if (!parport_yield_blocking (lp_table[minor].dev) && need_resched)
schedule ();
}
__initfunc(void lp_setup(char *str, int *ints))
{
- if (!strncmp(str, "parport", 7)) {
+ if (!str) {
+ if (ints[0] == 0 || ints[1] == 0) {
+ /* disable driver on "lp=" or "lp=0" */
+ parport[0] = LP_PARPORT_OFF;
+ } else {
+ printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
+ }
+ } else if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str+7, NULL, 10);
if (parport_ptr < LP_NO)
parport[parport_ptr++] = n;
parport[parport_ptr++] = LP_PARPORT_NONE;
} else if (!strcmp(str, "reset")) {
reset = 1;
- } else {
- if (ints[0] == 0 || ints[1] == 0) {
- /* disable driver on "lp=" or "lp=0" */
- parport[0] = LP_PARPORT_OFF;
- } else {
- printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
- }
}
}
return kmem_start;
}
-static struct tty_driver dev_tty_driver, dev_console_driver,
- dev_syscons_driver, dev_ptmx_driver;
+static struct tty_driver dev_tty_driver, dev_syscons_driver, dev_ptmx_driver;
+#ifdef CONFIG_VT
+static struct tty_driver dev_console_driver;
+#endif
/*
* Ok, now we can initialize the rest of the tty devices and can count
typedef struct aty_regvals {
int offset[3]; /* first pixel address */
- int crtc_h_sync_strt_wid[3]; /* depth dependant */
+ int crtc_h_sync_strt_wid[3]; /* depth dependent */
int crtc_gen_cntl[3];
int mem_cntl[3];
- int crtc_h_tot_disp; /* mode dependant */
+ int crtc_h_tot_disp; /* mode dependent */
int crtc_v_tot_disp;
int crtc_v_sync_strt_wid;
int crtc_off_pitch;
#define DATA_LATCH 0x3350010
/* ARC can't read from the data latch, so we must use a soft copy. */
-static unsigned int data_copy;
+static unsigned char data_copy;
-static void arc_write_data(struct parport *p, unsigned int data)
+static void arc_write_data(struct parport *p, unsigned char data)
{
data_copy = data;
outb(data, DATA_LATCH);
}
-static unsigned int arc_read_data(struct parport *p)
+static unsigned char arc_read_data(struct parport *p)
{
return data_copy;
}
}
void
-parport_ax_write_epp(struct parport *p, unsigned int d)
+parport_ax_write_epp(struct parport *p, unsigned char d)
{
outb(d, p->base + EPPREG);
}
-unsigned int
+unsigned char
parport_ax_read_epp(struct parport *p)
{
- return (unsigned int)inb(p->base + EPPREG);
+ return inb(p->base + EPPREG);
}
-unsigned int
+unsigned char
parport_ax_read_configb(struct parport *p)
{
- return (unsigned int)inb(p->base + CONFIGB);
+ return inb(p->base + CONFIGB);
}
void
-parport_ax_write_data(struct parport *p, unsigned int d)
+parport_ax_write_data(struct parport *p, unsigned char d)
{
outb(d, p->base + DATA);
}
-unsigned int
+unsigned char
parport_ax_read_data(struct parport *p)
{
- return (unsigned int)inb(p->base + DATA);
+ return inb(p->base + DATA);
}
void
-parport_ax_write_control(struct parport *p, unsigned int d)
+parport_ax_write_control(struct parport *p, unsigned char d)
{
outb(d, p->base + CONTROL);
}
-unsigned int
+unsigned char
parport_ax_read_control(struct parport *p)
{
- return (unsigned int)inb(p->base + CONTROL);
+ return inb(p->base + CONTROL);
}
-unsigned int
-parport_ax_frob_control(struct parport *p, unsigned int mask, unsigned int val)
+unsigned char
+parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base + CONTROL);
+ unsigned char old = inb(p->base + CONTROL);
outb(((old & ~mask) ^ val), p->base + CONTROL);
return old;
}
void
-parport_ax_write_status(struct parport *p, unsigned int d)
+parport_ax_write_status(struct parport *p, unsigned char d)
{
outb(d, p->base + STATUS);
}
-unsigned int
+unsigned char
parport_ax_read_status(struct parport *p)
{
- return (unsigned int)inb(p->base + STATUS);
+ return inb(p->base + STATUS);
}
void
-parport_ax_write_econtrol(struct parport *p, unsigned int d)
+parport_ax_write_econtrol(struct parport *p, unsigned char d)
{
outb(d, p->base + ECONTROL);
}
-unsigned int
+unsigned char
parport_ax_read_econtrol(struct parport *p)
{
- return (unsigned int)inb(p->base + ECONTROL);
+ return inb(p->base + ECONTROL);
}
-unsigned int
-parport_ax_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
+unsigned char
+parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base + ECONTROL);
+ unsigned char old = inb(p->base + ECONTROL);
outb(((old & ~mask) ^ val), p->base + ECONTROL);
return old;
}
}
void
-parport_ax_write_fifo(struct parport *p, unsigned int v)
+parport_ax_write_fifo(struct parport *p, unsigned char v)
{
outb(v, p->base + DFIFO);
}
-unsigned int
+unsigned char
parport_ax_read_fifo(struct parport *p)
{
return inb(p->base + DFIFO);
parport_ax_write_econtrol(p, s->u.pc.ecr);
}
-unsigned int
-parport_ax_epp_read_block(struct parport *p, void *buf, unsigned int length)
+size_t
+parport_ax_epp_read_block(struct parport *p, void *buf, size_t length)
{
return 0; /* FIXME */
}
-unsigned int
-parport_ax_epp_write_block(struct parport *p, void *buf, unsigned int length)
+size_t
+parport_ax_epp_write_block(struct parport *p, void *buf, size_t length)
{
return 0; /* FIXME */
}
-unsigned int
-parport_ax_ecp_read_block(struct parport *p, void *buf, unsigned int length,
- void (*fn)(struct parport *, void *, unsigned int),
+int
+parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length,
+ void (*fn)(struct parport *, void *, size_t),
void *handle)
{
return 0; /* FIXME */
}
-unsigned int
-parport_ax_ecp_write_block(struct parport *p, void *buf, unsigned int length,
- void (*fn)(struct parport *, void *, unsigned int),
+int
+parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length,
+ void (*fn)(struct parport *, void *, size_t),
void *handle)
{
return 0; /* FIXME */
*/
static int parport_ECR_present(struct parport *pb)
{
- unsigned int r, octr = pb->ops->read_control(pb),
+ unsigned int r;
+ unsigned char octr = pb->ops->read_control(pb),
oecr = pb->ops->read_econtrol(pb);
r = pb->ops->read_control(pb);
static int parport_ECP_supported(struct parport *pb)
{
- int i, oecr = pb->ops->read_econtrol(pb);
+ int i;
+ unsigned char oecr = pb->ops->read_econtrol(pb);
/* If there is no ECONTROL, we have no hope of supporting ECP. */
if (!(pb->modes & PARPORT_MODE_PCECR))
static int parport_PS2_supported(struct parport *pb)
{
- int ok = 0, octr = pb->ops->read_control(pb);
+ int ok = 0;
+ unsigned char octr = pb->ops->read_control(pb);
pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */
static int parport_ECPPS2_supported(struct parport *pb)
{
- int mode, oecr = pb->ops->read_econtrol(pb);
+ int mode;
+ unsigned char oecr = pb->ops->read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
/* Null function - does nothing */
}
-void parport_pc_write_epp(struct parport *p, unsigned int d)
+void parport_pc_write_epp(struct parport *p, unsigned char d)
{
outb(d, p->base+EPPREG);
}
-unsigned int parport_pc_read_epp(struct parport *p)
+unsigned char parport_pc_read_epp(struct parport *p)
{
- return (unsigned int)inb(p->base+EPPREG);
+ return inb(p->base+EPPREG);
}
-unsigned int parport_pc_read_configb(struct parport *p)
+unsigned char parport_pc_read_configb(struct parport *p)
{
- return (unsigned int)inb(p->base+CONFIGB);
+ return inb(p->base+CONFIGB);
}
-void parport_pc_write_data(struct parport *p, unsigned int d)
+void parport_pc_write_data(struct parport *p, unsigned char d)
{
outb(d, p->base+DATA);
}
-unsigned int parport_pc_read_data(struct parport *p)
+unsigned char parport_pc_read_data(struct parport *p)
{
- return (unsigned int)inb(p->base+DATA);
+ return inb(p->base+DATA);
}
-void parport_pc_write_control(struct parport *p, unsigned int d)
+void parport_pc_write_control(struct parport *p, unsigned char d)
{
outb(d, p->base+CONTROL);
}
-unsigned int parport_pc_read_control(struct parport *p)
+unsigned char parport_pc_read_control(struct parport *p)
{
- return (unsigned int)inb(p->base+CONTROL);
+ return inb(p->base+CONTROL);
}
-unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val)
+unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base+CONTROL);
+ unsigned char old = inb(p->base+CONTROL);
outb(((old & ~mask) ^ val), p->base+CONTROL);
return old;
}
-void parport_pc_write_status(struct parport *p, unsigned int d)
+void parport_pc_write_status(struct parport *p, unsigned char d)
{
outb(d, p->base+STATUS);
}
-unsigned int parport_pc_read_status(struct parport *p)
+unsigned char parport_pc_read_status(struct parport *p)
{
- return (unsigned int)inb(p->base+STATUS);
+ return inb(p->base+STATUS);
}
-void parport_pc_write_econtrol(struct parport *p, unsigned int d)
+void parport_pc_write_econtrol(struct parport *p, unsigned char d)
{
outb(d, p->base+ECONTROL);
}
-unsigned int parport_pc_read_econtrol(struct parport *p)
+unsigned char parport_pc_read_econtrol(struct parport *p)
{
- return (unsigned int)inb(p->base+ECONTROL);
+ return inb(p->base+ECONTROL);
}
-unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
+unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base+ECONTROL);
+ unsigned char old = inb(p->base+ECONTROL);
outb(((old & ~mask) ^ val), p->base+ECONTROL);
return old;
}
/* FIXME */
}
-void parport_pc_write_fifo(struct parport *p, unsigned int v)
+void parport_pc_write_fifo(struct parport *p, unsigned char v)
{
/* FIXME */
}
-unsigned int parport_pc_read_fifo(struct parport *p)
+unsigned char parport_pc_read_fifo(struct parport *p)
{
return 0; /* FIXME */
}
parport_pc_write_econtrol(p, s->u.pc.ecr);
}
-unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length)
+size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
{
return 0; /* FIXME */
}
-unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length)
+size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
{
return 0; /* FIXME */
}
-unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
+int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
{
return 0; /* FIXME */
}
-unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle)
+int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
{
return 0; /* FIXME */
}
/* Only if supports ECP mode */
static int programmable_dma_support(struct parport *pb)
{
- int dma, oldstate = parport_pc_read_econtrol(pb);
+ unsigned char dma, oldstate = parport_pc_read_econtrol(pb);
parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
static int parport_dma_probe(struct parport *pb)
{
int dma,retv;
- int dsr,dsr_read;
+ unsigned char dsr,dsr_read;
char *buff;
retv = programmable_dma_support(pb);
*/
static int epp_clear_timeout(struct parport *pb)
{
- int r;
+ unsigned char r;
if (!(parport_pc_read_status(pb) & 0x01))
return 1;
*/
static int parport_ECR_present(struct parport *pb)
{
- unsigned int r, octr = parport_pc_read_control(pb),
+ unsigned char r, octr = parport_pc_read_control(pb),
oecr = parport_pc_read_econtrol(pb);
r = parport_pc_read_control(pb);
static int parport_ECP_supported(struct parport *pb)
{
- int i, oecr = parport_pc_read_econtrol(pb);
+ int i;
+ unsigned char oecr = parport_pc_read_econtrol(pb);
/* If there is no ECR, we have no hope of supporting ECP. */
if (!(pb->modes & PARPORT_MODE_PCECR))
static int parport_ECPEPP_supported(struct parport *pb)
{
- int mode, oecr = parport_pc_read_econtrol(pb);
+ int mode;
+ unsigned char oecr = parport_pc_read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
static int parport_PS2_supported(struct parport *pb)
{
- int ok = 0, octr = parport_pc_read_control(pb);
+ int ok = 0;
+ unsigned char octr = parport_pc_read_control(pb);
epp_clear_timeout(pb);
static int parport_ECPPS2_supported(struct parport *pb)
{
- int mode, oecr = parport_pc_read_econtrol(pb);
+ int mode;
+ unsigned char oecr = parport_pc_read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
/* Only if supports ECP mode */
static int programmable_irq_support(struct parport *pb)
{
- int irq, oecr = parport_pc_read_econtrol(pb);
+ int irq, intrLine;
+ unsigned char oecr = parport_pc_read_econtrol(pb);
+ static const int lookup[8] = {
+ PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
+ };
parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */
- irq = (parport_pc_read_configb(pb) >> 3) & 0x07;
-
- switch(irq){
- case 2:
- irq = 9;
- break;
- case 7:
- irq = 5;
- break;
- case 0:
- irq = PARPORT_IRQ_NONE;
- break;
- default:
- irq += 7;
- }
-
+ intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07;
+ irq = lookup[intrLine];
+
parport_pc_write_econtrol(pb, oecr);
return irq;
}
static int irq_probe_ECP(struct parport *pb)
{
- int irqs, i, oecr = parport_pc_read_econtrol(pb);
+ int irqs, i;
+ unsigned char oecr = parport_pc_read_econtrol(pb);
probe_irq_off(probe_irq_on()); /* Clear any interrupts */
irqs = open_intr_election();
*/
static int irq_probe_EPP(struct parport *pb)
{
- int irqs, octr = parport_pc_read_control(pb);
+ int irqs;
+ unsigned char octr = parport_pc_read_control(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
static int irq_probe_SPP(struct parport *pb)
{
- int irqs, octr = parport_pc_read_control(pb);
+ int irqs;
+ unsigned char octr = parport_pc_read_control(pb);
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
tmp->devices = tmp->cad = NULL;
tmp->flags = 0;
tmp->ops = ops;
+ tmp->number = portcount;
spin_lock_init (&tmp->lock);
tmp->name = kmalloc(15, GFP_KERNEL);
* When compiled as a loadable module, this driver can operate
* the board as either a 4/6 port switch with a 5th or 7th port
* that is a conventional NIC interface as far as the host is
- * concerned, OR as 4/6 independant NICs. To select multi-NIC
+ * concerned, OR as 4/6 independent NICs. To select multi-NIC
* mode, add "nicmode=1" on the insmod load line for the driver.
*
* This driver uses the "dev" common ethernet device structure
M_OBJS :=
ifeq ($(CONFIG_SPARCAUDIO),y)
-M=y
+SBUS_AUDIO=y
else
ifeq ($(CONFIG_SPARCAUDIO),m)
- MM=y
+ SBUS_AUDIO_MODULE=y
endif
endif
ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y)
-M=y
+SBUS_AUDIO=y
OX_OBJS += amd7930.o
else
ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m)
- MM=y
+ SBUS_AUDIO_MODULE=y
MX_OBJS += amd7930.o
endif
endif
ifeq ($(CONFIG_SPARCAUDIO_CS4231),y)
-M=y
+SBUS_AUDIO=y
O_OBJS += cs4231.o
else
ifeq ($(CONFIG_SPARCAUDIO_CS4231),m)
- MM=y
+ SBUS_AUDIO_MODULE=y
M_OBJS += cs4231.o
endif
endif
-ifdef M
+ifdef SBUS_AUDIO
OX_OBJS += audio.o
else
- ifdef MM
+ ifdef SBUS_AUDIO_MODULE
MX_OBJS += audio.o
endif
endif
flash_llseek,
flash_read,
NULL, /* no write to the Flash, use mmap
- * and play flash dependant tricks.
+ * and play flash dependent tricks.
*/
NULL, /* readdir */
NULL, /* poll */
Change to linux source directory
Configure with NCR53C7,8XX support = N
Configure with NCR53C8XX support = Y (or m)
- Make dependancies
+ Make dependencies
Make the kernel (use make zdisk first)
Make and install modules if you have configured with 'm'
Please direct bug reports to: hjw@zvw.de
+Version 3.8
+-----------
+Bill Hawes kindly reviewed the affs and sent me the
+patches he did. They're marked (BH). Thanks, Bill!
+
+- Cleanup of error handling in read_super().
+ Didn't release all ressources in case of an
+ error. (BH)
+
+- put_inode() releases the ext cache only if it's
+ no longer needed. (BH)
+
+- One set of dentry callbacks is enough. (BH)
+
+- Cleanup of error handling in namei.c. (BH)
+
+- Cleanup of error handling in file.c. (BH)
+
+- The original blocksize of the device is
+ restored when the fs is unmounted. (BH)
+
+- getblock() did not invalidate the key cache
+ when it allocated a new block.
+
+- Removed some unneccessary locks as Bill
+ suggested.
+
+- Simplified match_name(), changed all hashing
+ and case insensitive name comparisons to use
+ uppercase. This makes the tolower() routines
+ obsolete.
+
+- Added mount option 'mufs' to force muFS
+ uid/gid interpretation.
+
+- File mode changes were not updated on disk.
+ This was fixed before, but somehow got lost.
+
Version 3.7
-----------
* block allocation, deallocation, calculation of free space.
*/
+#define DEBUG 0
#include <linux/sched.h>
#include <linux/affs_fs.h>
#include <linux/stat.h>
for (;;) {
bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
- if (!bh)
+ if (!bh)
return 0;
index = seqnum_to_index(ext);
if (index > inode->u.affs_i.i_ec->max_ext &&
static struct buffer_head *
affs_getblock(struct inode *inode, s32 block)
{
- struct buffer_head *bh;
- struct buffer_head *ebh;
- struct buffer_head *pbh;
+ struct super_block *sb = inode->i_sb;
+ int ofs = sb->u.affs_sb.s_flags & SF_OFS;
+ int ext = block / AFFS_I2HSIZE(inode);
+ struct buffer_head *bh, *ebh, *pbh = NULL;
struct key_cache *kc;
s32 key, nkey;
- int ext;
int cf, j, pt;
int index;
- int ofs;
+ int err;
pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
if (block < 0)
- return NULL;
+ goto out_fail;
- /* Writers always use cache line 3. In almost all cases, files
- * will be written by only one process at the same time, and
- * they also will be written in strict sequential order. Thus
- * there is not much sense in looking whether the key of the
- * requested block is available - it won't be there.
- */
- kc = &inode->u.affs_i.i_ec->kc[3];
- ofs = inode->i_sb->u.affs_sb.s_flags & SF_OFS;
- ext = block / AFFS_I2HSIZE(inode);
key = calc_key(inode,&ext);
block -= ext * AFFS_I2HSIZE(inode);
pt = ext ? T_LIST : T_SHORT;
- pbh = NULL;
+ /* Key refers now to the last known extension block,
+ * ext is its sequence number (if 0, key refers to the
+ * header block), and block is the block number relative
+ * to the first block stored in that extension block.
+ */
for (;;) { /* Loop over header block and extension blocks */
+ struct file_front *fdp;
+
bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
if (!bh)
- return NULL;
- if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) ||
- cf != pt || j != ST_FILE) {
- affs_error(inode->i_sb,"getblock","Inode %d is not a valid %s",key,
- pt == T_SHORT ? "file header" : "extension block");
- affs_brelse(bh);
- return NULL;
+ goto out_fail;
+ fdp = (struct file_front *) bh->b_data;
+ err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);
+ if (err || cf != pt || j != ST_FILE) {
+ affs_error(sb, "getblock",
+ "Block %d is not a valid %s", key,
+ pt == T_SHORT ? "file header" : "ext block");
+ goto out_free_bh;
}
j = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
- cf = 0;
- while (j < AFFS_I2HSIZE(inode) && j <= block) {
+ for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
- if (j > 0)
- pbh = affs_bread(inode->i_dev,cpu_to_be32(AFFS_BLOCK(bh->b_data,inode,j - 1)),
- AFFS_I2BSIZE(inode));
- else
+ if (j > 0) {
+ s32 k = AFFS_BLOCK(bh->b_data, inode,
+ j - 1);
+ pbh = affs_bread(inode->i_dev,
+ be32_to_cpu(k),
+ AFFS_I2BSIZE(inode));
+ } else
pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
if (!pbh) {
- affs_error(inode->i_sb,"getblock",
+ affs_error(sb,"getblock",
"Cannot get last block in file");
break;
}
if (!nkey)
break;
inode->u.affs_i.i_lastblock++;
- lock_super(inode->i_sb);
if (AFFS_BLOCK(bh->b_data,inode,j)) {
- unlock_super(inode->i_sb);
- affs_warning(inode->i_sb,"getblock","Block already allocated");
- affs_free_block(inode->i_sb,nkey);
- j++;
+ affs_warning(sb,"getblock","Block already allocated");
+ affs_free_block(sb,nkey);
continue;
}
- unlock_super(inode->i_sb);
AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
if (ofs) {
ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
if (!ebh) {
- affs_error(inode->i_sb,"getblock",
+ affs_error(sb,"getblock",
"Cannot get block %d",nkey);
- affs_free_block(inode->i_sb,nkey);
+ affs_free_block(sb,nkey);
AFFS_BLOCK(bh->b_data,inode,j) = 0;
break;
}
DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA);
DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino);
DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),
+ ebh->b_data, 5);
+ mark_buffer_dirty(ebh, 0);
if (pbh) {
DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
mark_buffer_dirty(pbh,0);
- mark_buffer_dirty(ebh,0);
affs_brelse(pbh);
}
pbh = ebh;
}
- j++;
cf = 1;
}
+ /* N.B. May need to release pbh after here */
+
if (cf) {
if (pt == T_SHORT)
- ((struct file_front *)bh->b_data)->first_data =
- AFFS_BLOCK(bh->b_data,inode,0);
- ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(j);
+ fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
+ fdp->block_count = cpu_to_be32(j);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
mark_buffer_dirty(bh,1);
}
break;
}
if (j < AFFS_I2HSIZE(inode)) {
- affs_brelse(bh);
- return NULL;
+ /* N.B. What about pbh here? */
+ goto out_free_bh;
}
block -= AFFS_I2HSIZE(inode);
key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
if (!key) {
key = affs_new_header(inode);
- if (!key) {
- affs_brelse(bh);
- return NULL;
- }
+ if (!key)
+ goto out_free_bh;
ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
if (!ebh) {
- affs_free_block(inode->i_sb,key);
- return NULL;
+ /* N.B. must free bh here */
+ goto out_free_block;
}
((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
((struct file_front *)ebh->b_data)->own_key = cpu_to_be32(key);
FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE);
FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino);
affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+ mark_buffer_dirty(ebh, 1);
FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
mark_buffer_dirty(bh,1);
affs_brelse(bh);
bh = ebh;
}
- affs_brelse(bh);
pt = T_LIST;
ext++;
- if ((index = seqnum_to_index(ext)) > inode->u.affs_i.i_ec->max_ext &&
- AFFS_ISINDEX(ext) && inode->u.affs_i.i_ec) {
+ index = seqnum_to_index(ext);
+ if (index > inode->u.affs_i.i_ec->max_ext &&
+ AFFS_ISINDEX(ext)) {
inode->u.affs_i.i_ec->ec[index] = key;
inode->u.affs_i.i_ec->max_ext = index;
}
+ affs_brelse(bh);
+ }
+
+ /* Invalidate key cache */
+ for (j = 0; j < 4; j++) {
+ kc = &inode->u.affs_i.i_ec->kc[j];
+ kc->kc_last = -1;
}
- kc->kc_this_key = key;
- kc->kc_this_seq = ext;
- kc->kc_next_key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
affs_brelse(bh);
if (!key)
- return NULL;
-
- return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ goto out_fail;
+
+ bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
+ return bh;
+
+out_free_block:
+ affs_free_block(sb, key);
+out_free_bh:
+ affs_brelse(bh);
+out_fail:
+ return NULL;
}
static ssize_t
inode->i_mode);
return -EINVAL;
}
- if (!inode->u.affs_i.i_ec) {
- if (alloc_ext_cache(inode)) {
- return -ENOMEM;
- }
- }
- if (filp->f_flags & O_APPEND) {
+ if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
+ return -ENOMEM;
+ if (filp->f_flags & O_APPEND)
pos = inode->i_size;
- } else
+ else
pos = *ppos;
written = 0;
blocksize = AFFS_I2BSIZE(inode);
return written;
}
+/* Free any preallocated blocks */
+void
+affs_free_prealloc(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ int block;
+
+ pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
+
+ while (inode->u.affs_i.i_pa_cnt) {
+ block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
+ inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
+ inode->u.affs_i.i_pa_cnt--;
+ affs_free_block(sb, block);
+ }
+}
+
void
affs_truncate(struct inode *inode)
{
}
bh = affs_getblock(inode,first - 1);
- while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */
- affs_free_block(inode->i_sb,
- inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
- inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
- inode->u.affs_i.i_pa_cnt--;
- }
+ affs_free_prealloc(inode);
if (inode->u.affs_i.i_zone) {
lock_super(inode->i_sb);
zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
static int
affs_release_file(struct inode *inode, struct file *filp)
{
+ struct super_block *sb = inode->i_sb;
struct affs_zone *zone;
pr_debug("AFFS: release_file(ino=%lu)\n",inode->i_ino);
if (filp->f_mode & 2) { /* Free preallocated blocks */
- while (inode->u.affs_i.i_pa_cnt) {
- affs_free_block(inode->i_sb,
- inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
- inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
- inode->u.affs_i.i_pa_cnt--;
- }
+ affs_free_prealloc(inode);
if (inode->u.affs_i.i_zone) {
- lock_super(inode->i_sb);
- zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+ zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
if (zone->z_ino == inode->i_ino)
zone->z_ino = 0;
- unlock_super(inode->i_sb);
}
}
return 0;
}
+/*
+ * Called only when we need to allocate the extension cache.
+ */
static int
alloc_ext_cache(struct inode *inode)
{
s32 key;
int i;
+ unsigned long cache_page;
+ int error = 0;
pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino);
- lock_super(inode->i_sb);
- if (!inode->u.affs_i.i_ec) {
- inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
- if (inode->u.affs_i.i_ec) {
- /* We only have to initialize non-zero values.
- * get_free_page() zeroed the page already.
- */
- key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
- inode->u.affs_i.i_ec->ec[0] = key;
- for (i = 0; i < 4; i++) {
- inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
- inode->u.affs_i.i_ec->kc[i].kc_last = -1;
- }
- }
- }
- unlock_super(inode->i_sb);
-
- if (!inode->u.affs_i.i_ec) {
- affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
- return -ENOMEM;
+ cache_page = get_free_page(GFP_KERNEL);
+ /*
+ * Check whether somebody else allocated it for us ...
+ */
+ if (inode->u.affs_i.i_ec)
+ goto out_free;
+ if (!cache_page)
+ goto out_error;
+
+ inode->u.affs_i.i_ec = (struct ext_cache *) cache_page;
+ /* We only have to initialize non-zero values.
+ * get_free_page() zeroed the page already.
+ */
+ key = inode->u.affs_i.i_original;
+ if (!inode->u.affs_i.i_original)
+ key = inode->i_ino;
+ inode->u.affs_i.i_ec->ec[0] = key;
+ for (i = 0; i < 4; i++) {
+ inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
+ inode->u.affs_i.i_ec->kc[i].kc_last = -1;
}
- return 0;
+out:
+ return error;
+
+out_free:
+ if (cache_page)
+ free_page(cache_page);
+ goto out;
+
+out_error:
+ affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
+ error = -ENOMEM;
+ goto out;
}
error = inode_change_ok(inode,attr);
if (error)
- return error;
+ goto out;
if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) ||
((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) ||
((attr->ia_valid & ATTR_MODE) &&
- (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE))))
- error = -EPERM;
-
- if (error)
- return (inode->i_sb->u.affs_sb.s_flags & SF_QUIET) ? 0 : error;
+ (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE)))) {
+ if (!(inode->i_sb->u.affs_sb.s_flags & SF_QUIET))
+ error = -EPERM;
+ goto out;
+ }
if (attr->ia_valid & ATTR_MODE)
inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
- inode_setattr(inode,attr);
-
- return 0;
+ inode_setattr(inode, attr);
+ mark_inode_dirty(inode);
+ error = 0;
+out:
+ return error;
}
void
affs_put_inode(struct inode *inode)
{
- pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
- lock_super(inode->i_sb);
- if (inode->u.affs_i.i_ec) {
- pr_debug("AFFS: freeing ext cache\n");
- free_page((unsigned long)inode->u.affs_i.i_ec);
- inode->u.affs_i.i_ec = NULL;
+ pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
+ inode->i_ino,inode->i_nlink);
+ if (inode->i_count == 1) {
+ unsigned long cache_page = (unsigned long) inode->u.affs_i.i_ec;
+ if (cache_page) {
+ pr_debug("AFFS: freeing ext cache\n");
+ inode->u.affs_i.i_ec = NULL;
+ free_page(cache_page);
+ }
}
- unlock_super(inode->i_sb);
}
void
#include <linux/errno.h>
-/* Simple toupper()/tolower() for DOS\1 */
+/* Simple toupper() for DOS\1 */
-static inline unsigned int
+static unsigned int
affs_toupper(unsigned int ch)
{
return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
}
-static inline unsigned int
-affs_tolower(unsigned int ch)
-{
- return ch >= 'A' && ch <= 'Z' ? ch + ('a' - 'A') : ch;
-}
+/* International toupper() for DOS\3 ("international") */
-/* International toupper()/tolower() for DOS\3 ("international") */
-
-static inline unsigned int
+static unsigned int
affs_intl_toupper(unsigned int ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
ch - ('a' - 'A') : ch;
}
-static inline unsigned int
-affs_intl_tolower(unsigned int ch)
-{
- return (ch >= 'A' && ch <= 'Z') || (ch >= 0xC0
- && ch <= 0xDE && ch != 0xD7) ?
- ch + ('a' - 'A') : ch;
-}
-
-/* We need 2 sets of dentry operations, since we cannot
- * determine the fs flavour in the callback routines.
- */
-
static int affs_hash_dentry(struct dentry *, struct qstr *);
static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static int affs_hash_dentry_intl(struct dentry *, struct qstr *);
-static int affs_compare_dentry_intl(struct dentry *, struct qstr *, struct qstr *);
-
struct dentry_operations affs_dentry_operations = {
NULL, /* d_validate */
affs_hash_dentry, /* d_hash */
NULL /* d_delete */
};
-struct dentry_operations affs_dentry_operations_intl = {
- NULL, /* d_validate */
- affs_hash_dentry_intl, /* d_hash */
- affs_compare_dentry_intl, /* d_compare */
- NULL /* d_delete */
-};
-
+/*
+ * Note: the dentry argument is the parent dentry.
+ */
static int
affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
{
+ unsigned int (*toupper)(unsigned int) = affs_toupper;
unsigned long hash;
int i;
if ((i = affs_check_name(qstr->name,qstr->len)))
return i;
+
+ /* Check whether to use the international 'toupper' routine */
+ if (AFFS_I2FSTYPE(dentry->d_inode))
+ toupper = affs_intl_toupper;
hash = init_name_hash();
for (i = 0; i < qstr->len && i < 30; i++)
- hash = partial_name_hash(affs_tolower(qstr->name[i]),hash);
+ hash = partial_name_hash(toupper(qstr->name[i]), hash);
qstr->hash = end_name_hash(hash);
return 0;
static int
affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
+ unsigned int (*toupper)(unsigned int) = affs_toupper;
+ int alen = a->len;
+ int blen = b->len;
int i;
/* 'a' is the qstr of an already existing dentry, so the name
/* If the names are longer than the allowed 30 chars,
* the excess is ignored, so their length may differ.
*/
-
- if ((a->len < 30 || b->len < 30) && a->len != b->len)
+ if (alen > 30)
+ alen = 30;
+ if (blen > 30)
+ blen = 30;
+ if (alen != blen)
return 1;
- for (i = 0; i < a->len && i < 30; i++)
- if (affs_tolower(a->name[i]) != affs_tolower(b->name[i]))
- return 1;
-
- return 0;
-}
-
-static int
-affs_hash_dentry_intl(struct dentry *dentry, struct qstr *qstr)
-{
- unsigned long hash;
- int i;
+ /* Check whether to use the international 'toupper' routine */
+ if (AFFS_I2FSTYPE(dentry->d_inode))
+ toupper = affs_intl_toupper;
- if ((i = affs_check_name(qstr->name,qstr->len)))
- return i;
- hash = init_name_hash();
- for (i = 0; i < qstr->len && i < 30; i++)
- hash = partial_name_hash(affs_intl_tolower(qstr->name[i]),hash);
- qstr->hash = end_name_hash(hash);
-
- return 0;
-}
-
-static int
-affs_compare_dentry_intl(struct dentry *dentry, struct qstr *a, struct qstr *b)
-{
- int i;
-
- if (affs_check_name(b->name,b->len))
- return 1;
- if ((a->len < 30 || b->len < 30) && a->len != b->len)
- return 1;
-
- for (i = 0; i < a->len && i < 30; i++)
- if (affs_intl_tolower(a->name[i]) != affs_intl_tolower(b->name[i]))
+ for (i = 0; i < alen; i++)
+ if (toupper(a->name[i]) != toupper(b->name[i]))
return 1;
return 0;
static int
affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
{
+ unsigned int (*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper;
+ int i;
+
if (!compare)
return 0;
return 1;
if (dlen != len)
return 0;
- if (intl) {
- while (dlen--) {
- if (affs_intl_toupper(*name) != affs_intl_toupper(*compare))
- return 0;
- name++;
- compare++;
- }
- } else {
- while (dlen--) {
- if (affs_toupper(*name) != affs_toupper(*compare))
- return 0;
- name++;
- compare++;
- }
- }
+ for (i = 0; i < len; i++)
+ if (toupper(name[i]) != toupper(compare[i]))
+ return 0;
return 1;
}
affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
struct buffer_head *bh;
- int intl;
+ int intl = AFFS_I2FSTYPE(dir);
s32 key;
const char *name = dentry->d_name.name;
int namelen = dentry->d_name.len;
pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
- intl = AFFS_I2FSTYPE(dir);
- bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+ bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
if (!bh)
return NULL;
- if (affs_match(name,namelen,".",1,intl)) {
+ if (namelen == 1 && name[0] == '.') {
*ino = dir->i_ino;
return bh;
}
- if (affs_match(name,namelen,"..",2,intl)) {
+ if (namelen == 2 && name[0] == '.' && name[1] == '.') {
*ino = affs_parent_ino(dir);
return bh;
}
int cnamelen;
affs_brelse(bh);
- if (key == 0) {
- bh = NULL;
+ bh = NULL;
+ if (key == 0)
break;
- }
bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
if (!bh)
break;
if (!inode)
return -EACCES;
}
- dentry->d_op = AFFS_I2FSTYPE(dir) ? &affs_dentry_operations_intl
- : &affs_dentry_operations;
+ dentry->d_op = &affs_dentry_operations;
d_add(dentry,inode);
return 0;
}
pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
- bh = NULL;
retval = -ENOENT;
- if (!dir)
- goto unlink_done;
if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto unlink_done;
inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
- retval = 0;
d_delete(dentry);
+ mark_inode_dirty(dir);
+ retval = 0;
+
unlink_done:
affs_brelse(bh);
return retval;
pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
dentry->d_name.name,mode);
- if (!dir)
- return -ENOENT;
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
pr_debug(" -- ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
inode->i_op = &affs_file_inode_operations;
error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
- if (error) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return error;
- }
+ if (error)
+ goto out_iput;
inode->i_mode = mode;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ d_instantiate(dentry,inode);
+ mark_inode_dirty(inode);
dir->i_version = ++event;
mark_inode_dirty(dir);
- d_instantiate(dentry,inode);
+out:
+ return error;
- return 0;
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
int
pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,mode);
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
inode->i_op = &affs_dir_inode_operations;
error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
- if (error) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return error;
- }
+ if (error)
+ goto out_iput;
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ d_instantiate(dentry,inode);
+ mark_inode_dirty(inode);
dir->i_version = ++event;
mark_inode_dirty(dir);
- d_instantiate(dentry,inode);
+out:
+ return error;
- return 0;
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
static int
int
affs_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode = dentry->d_inode;
int retval;
unsigned long ino;
- struct inode *inode;
struct buffer_head *bh;
pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
- inode = NULL;
- bh = NULL;
retval = -ENOENT;
- if (!dir)
- goto rmdir_done;
if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto rmdir_done;
- inode = dentry->d_inode;
-
retval = -EPERM;
if (current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid && !fsuser())
goto rmdir_done;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto rmdir_done;
- if (!S_ISDIR(inode->i_mode)) {
- retval = -ENOTDIR;
+ retval = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
goto rmdir_done;
- }
- down(&inode->i_sem);
- if (dentry->d_count > 1) {
+ /*
+ * Make sure the directory is empty and the dentry isn't busy.
+ */
+ if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
- }
- up(&inode->i_sem);
- if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
- retval = -ENOTEMPTY;
+ retval = -ENOTEMPTY;
+ if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
goto rmdir_done;
- }
- if (inode->i_count > 1) {
- retval = -EBUSY;
+ retval = -EBUSY;
+ if (dentry->d_count > 1)
goto rmdir_done;
- }
+
if ((retval = affs_remove_header(bh,inode)) < 0)
goto rmdir_done;
inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
retval = 0;
+ mark_inode_dirty(dir);
mark_inode_dirty(inode);
d_delete(dentry);
+
rmdir_done:
affs_brelse(bh);
return retval;
struct inode *inode;
char *p;
unsigned long tmp;
- int i, maxlen;
+ int i, maxlen, error;
char c, lc;
pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,symname);
maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+ error = -ENOSPC;
inode = affs_new_inode(dir);
if (!inode)
- return -ENOSPC;
+ goto out;
inode->i_op = &affs_symlink_inode_operations;
inode->i_mode = S_IFLNK | 0777;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ error = -EIO;
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- if (!bh) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- return -EIO;
- }
+ if (!bh)
+ goto out_iput;
i = 0;
p = ((struct slink_front *)bh->b_data)->symname;
lc = '/';
mark_buffer_dirty(bh,1);
affs_brelse(bh);
mark_inode_dirty(inode);
+
+ /* N.B. This test shouldn't be necessary ... dentry must be negative */
+ error = -EEXIST;
bh = affs_find_entry(dir,dentry,&tmp);
- if (bh) {
- inode->i_nlink = 0;
- iput(inode);
- affs_brelse(bh);
- return -EEXIST;
- }
- i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
- if (i) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput(inode);
- affs_brelse(bh);
- return i;
- }
- dir->i_version = ++event;
+ if (bh)
+ goto out_release;
+ /* N.B. Shouldn't we add the entry before dirtying the buffer? */
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
+ if (error)
+ goto out_release;
d_instantiate(dentry,inode);
-
- return 0;
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+
+out:
+ return error;
+
+out_release:
+ affs_brelse(bh);
+out_iput:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
int
pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name);
+ /* N.B. Do we need this test? The dentry must be negative ... */
bh = affs_find_entry(dir,dentry,&i);
if (bh) {
affs_brelse(bh);
affs_warning(dir->i_sb,"link","Impossible link to link");
return -EINVAL;
}
+ error = -ENOSPC;
if (!(inode = affs_new_inode(dir)))
- return -ENOSPC;
+ goto out;
inode->i_op = oldinode->i_op;
inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode);
inode->i_nlink = 0;
else {
dir->i_version = ++event;
+ mark_inode_dirty(dir);
mark_inode_dirty(oldinode);
oldinode->i_count++;
d_instantiate(dentry,oldinode);
mark_inode_dirty(inode);
iput(inode);
+out:
return error;
}
new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
- return retval;
+ goto out;
new_bh = NULL;
retval = -ENOENT;
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (is_subdir(new_dentry,old_dentry))
+ if (is_subdir(new_dentry, old_dentry))
goto end_rename;
+ if (new_dentry->d_count > 1)
+ shrink_dcache_parent(new_dentry);
retval = -ENOTEMPTY;
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (is_subdir(new_dentry,old_dentry))
+ if (is_subdir(new_dentry, old_dentry))
goto end_rename;
if (affs_parent_ino(old_inode) != old_dir->i_ino)
goto end_rename;
end_rename:
affs_brelse(old_bh);
affs_brelse(new_bh);
-
+out:
return retval;
}
kfree(sb->u.affs_sb.s_bitmap);
affs_brelse(sb->u.affs_sb.s_root_bh);
- /* I'm not happy with this. It would be better to save the previous
- * value of this devices blksize_size[][] in the super block and
- * restore it here, but with the affs superblock being quite large
- * already ...
+ /*
+ * Restore the previous value of this device's blksize_size[][]
*/
- set_blocksize(sb->s_dev,BLOCK_SIZE);
+ set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize);
sb->s_dev = 0;
unlock_super(sb);
} else
sb->s_dirt = 0;
- pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean);
+ pr_debug("AFFS: write_super() at %lu, clean=%d\n", CURRENT_TIME, clean);
}
static struct super_operations affs_sops = {
parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
{
- char *this_char, *value;
+ char *this_char, *value, *optn;
int f;
/* Fill in defaults */
f = 0;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
- if (!strcmp(this_char,"protect")) {
- if (value) {
- printk("AFFS: Option protect does not take an argument\n");
- return 0;
- }
+ if ((optn = "protect") && !strcmp(this_char, optn)) {
+ if (value)
+ goto out_inv_arg;
*mount_opts |= SF_IMMUTABLE;
- } else if (!strcmp(this_char,"verbose")) {
- if (value) {
- printk("AFFS: Option verbose does not take an argument\n");
- return 0;
- }
+ } else if ((optn = "verbose") && !strcmp(this_char, optn)) {
+ if (value)
+ goto out_inv_arg;
*mount_opts |= SF_VERBOSE;
+ } else if ((optn = "mufs") && !strcmp(this_char, optn)) {
+ if (value)
+ goto out_inv_arg;
+ *mount_opts |= SF_MUFS;
} else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) {
if (value) {
if (!*value) {
}
}
} else if (!strcmp(this_char,"prefix")) {
- if (!value || !*value) {
- printk("AFFS: The prefix option requires an argument\n");
- return 0;
- }
- if (*prefix) /* Free any previous prefix */
+ optn = "prefix";
+ if (!value || !*value)
+ goto out_no_arg;
+ if (*prefix) { /* Free any previous prefix */
kfree(*prefix);
+ *prefix = NULL;
+ }
*prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
if (!*prefix)
return 0;
strcpy(*prefix,value);
*mount_opts |= SF_PREFIX;
} else if (!strcmp(this_char,"volume")) {
- if (!value || !*value) {
- printk("AFFS: The volume option requires an argument\n");
- return 0;
- }
+ optn = "volume";
+ if (!value || !*value)
+ goto out_no_arg;
if (strlen(value) > 30)
value[30] = 0;
strncpy(volume,value,30);
} else if (!strcmp(this_char,"mode")) {
- if (!value || !*value) {
- printk("AFFS: The mode option requires an argument\n");
- return 0;
- }
+ optn = "mode";
+ if (!value || !*value)
+ goto out_no_arg;
*mode = simple_strtoul(value,&value,8) & 0777;
if (*value)
return 0;
*mount_opts |= SF_SETMODE;
} else if (!strcmp(this_char,"reserved")) {
- if (!value || !*value) {
- printk("AFFS: The reserved option requires an argument\n");
- return 0;
- }
+ optn = "reserved";
+ if (!value || !*value)
+ goto out_no_arg;
*reserved = simple_strtoul(value,&value,0);
if (*value)
return 0;
} else if (!strcmp(this_char,"root")) {
- if (!value || !*value) {
- printk("AFFS: The root option requires an argument\n");
- return 0;
- }
+ optn = "root";
+ if (!value || !*value)
+ goto out_no_arg;
*root = simple_strtoul(value,&value,0);
if (*value)
return 0;
} else if (!strcmp(this_char,"bs")) {
- if (!value || !*value) {
- printk("AFFS: The bs option requires an argument\n");
- return 0;
- }
+ optn = "bs";
+ if (!value || !*value)
+ goto out_no_arg;
*blocksize = simple_strtoul(value,&value,0);
if (*value)
return 0;
}
}
return 1;
+
+out_no_arg:
+ printk("AFFS: The %s option requires an argument\n", optn);
+ return 0;
+out_inv_arg:
+ printk("AFFS: Option %s does not take an argument\n", optn);
+ return 0;
}
/* This function definitely needs to be split up. Some fine day I'll
*/
static struct super_block *
-affs_read_super(struct super_block *s,void *data, int silent)
+affs_read_super(struct super_block *s, void *data, int silent)
{
struct buffer_head *bh = NULL;
struct buffer_head *bb;
struct inode *root_inode;
kdev_t dev = s->s_dev;
s32 root_block;
- int size;
+ int blocks, size, blocksize;
u32 chksum;
u32 *bm;
s32 ptype, stype;
int num_bm;
int i, j;
s32 key;
- int blocksize;
uid_t uid;
gid_t gid;
int reserved;
pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options");
MOD_INC_USE_COUNT;
-
- s->u.affs_sb.s_prefix = NULL;
- if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
- &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
- s->s_dev = 0;
- printk(KERN_ERR "AFFS: Error parsing options\n");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
lock_super(s);
-
- /* Get the size of the device in 512-byte blocks.
- * If we later see that the partition uses bigger
- * blocks, we will have to change it.
- */
-
- size = blksize_size[MAJOR(dev)][MINOR(dev)];
- size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)];
-
+ s->s_magic = AFFS_SUPER_MAGIC;
+ s->s_op = &affs_sops;
s->u.affs_sb.s_bitmap = NULL;
s->u.affs_sb.s_root_bh = NULL;
+ s->u.affs_sb.s_prefix = NULL;
+ s->u.affs_sb.s_hashsize= 0;
+
+ if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
+ &blocksize,&s->u.affs_sb.s_prefix,
+ s->u.affs_sb.s_volume, &mount_flags))
+ goto out_bad_opts;
+ /* N.B. after this point s_prefix must be released */
+
s->u.affs_sb.s_flags = mount_flags;
s->u.affs_sb.s_mode = i;
s->u.affs_sb.s_uid = uid;
s->u.affs_sb.s_gid = gid;
+ s->u.affs_sb.s_reserved= reserved;
- if (size == 0) {
- s->s_dev = 0;
- unlock_super(s);
- printk(KERN_ERR "AFFS: Could not determine device size\n");
- goto out;
- }
- s->u.affs_sb.s_partition_size = size;
- s->u.affs_sb.s_reserved = reserved;
+ /* Get the size of the device in 512-byte blocks.
+ * If we later see that the partition uses bigger
+ * blocks, we will have to change it.
+ */
+
+ blocks = blk_size[MAJOR(dev)][MINOR(dev)];
+ if (blocks == 0)
+ goto out_bad_size;
+ s->u.affs_sb.s_blksize = blksize_size[MAJOR(dev)][MINOR(dev)];
+ if (!s->u.affs_sb.s_blksize)
+ s->u.affs_sb.s_blksize = BLOCK_SIZE;
+ size = (s->u.affs_sb.s_blksize / 512) * blocks;
+ pr_debug("AFFS: initial blksize=%d, blocks=%d\n",
+ s->u.affs_sb.s_blksize, blocks);
/* Try to find root block. Its location depends on the block size. */
- s->u.affs_sb.s_hashsize = 0;
+ i = 512;
+ j = 4096;
if (blocksize > 0) {
- i = blocksize;
- j = blocksize;
- } else {
- i = 512;
- j = 4096;
+ i = j = blocksize;
+ size = size / (blocksize / 512);
}
for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
+ s->u.affs_sb.s_root_block = root_block;
if (root_block < 0)
s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
- else
- s->u.affs_sb.s_root_block = root_block;
- set_blocksize(dev,blocksize);
+ pr_debug("AFFS: setting blocksize to %d\n", blocksize);
+ set_blocksize(dev, blocksize);
/* The root block location that was calculated above is not
* correct if the partition size is an odd number of 512-
* block behind the calculated one. So we check this one, too.
*/
for (num_bm = 0; num_bm < 2; num_bm++) {
- pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, "
- "size=%d blocks, %d reserved\n",kdevname(dev),blocksize,
- s->u.affs_sb.s_root_block + num_bm,size,reserved);
- bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize);
- if (!bh) {
- printk(KERN_ERR "AFFS: Cannot read root block\n");
- goto out;
- }
+ pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, "
+ "size=%d, reserved=%d\n",
+ kdevname(dev),
+ s->u.affs_sb.s_root_block + num_bm,
+ blocksize, size, reserved);
+ bh = affs_bread(dev, s->u.affs_sb.s_root_block + num_bm,
+ blocksize);
+ if (!bh)
+ continue;
if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
ptype == T_SHORT && stype == ST_ROOT) {
s->s_blocksize = blocksize;
s->u.affs_sb.s_hashsize = blocksize / 4 - 56;
s->u.affs_sb.s_root_block += num_bm;
key = 1;
- break;
+ goto got_root;
}
+ affs_brelse(bh);
+ bh = NULL;
}
- if (key)
- break;
- affs_brelse(bh);
- bh = NULL;
- }
- if (!key) {
- affs_brelse(bh);
- if (!silent)
- printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n",
- kdevname(dev));
- goto out;
}
+ goto out_no_valid_block;
+
+ /* N.B. after this point bh must be released */
+got_root:
root_block = s->u.affs_sb.s_root_block;
s->u.affs_sb.s_partition_size = size;
/* Find out which kind of FS we have */
bb = affs_bread(dev,0,s->s_blocksize);
- if (bb) {
- chksum = be32_to_cpu(*(u32 *)bb->b_data);
-
- /* Dircache filesystems are compatible with non-dircache ones
- * when reading. As long as they aren't supported, writing is
- * not recommended.
- */
- if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
- || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
- printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
- kdevname(dev));
- s->s_flags |= MS_RDONLY;
- s->u.affs_sb.s_flags |= SF_READONLY;
- }
- switch (chksum) {
- case MUFS_FS:
- case MUFS_INTLFFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- /* fall thru */
- case FS_INTLFFS:
- s->u.affs_sb.s_flags |= SF_INTL;
- break;
- case MUFS_DCFFS:
- case MUFS_FFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- break;
- case FS_DCFFS:
- case FS_FFS:
- break;
- case MUFS_OFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- /* fall thru */
- case FS_OFS:
- s->u.affs_sb.s_flags |= SF_OFS;
- break;
- case MUFS_DCOFS:
- case MUFS_INTLOFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- case FS_DCOFS:
- case FS_INTLOFS:
- s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
- break;
- default:
- printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
- kdevname(dev),chksum);
- affs_brelse(bb);
- goto out;
- }
- affs_brelse(bb);
- } else {
- printk(KERN_ERR "AFFS: Cannot read boot block\n");
- goto out;
+ if (!bb)
+ goto out_no_root_block;
+ chksum = be32_to_cpu(*(u32 *)bb->b_data);
+ affs_brelse(bb);
+
+ /* Dircache filesystems are compatible with non-dircache ones
+ * when reading. As long as they aren't supported, writing is
+ * not recommended.
+ */
+ if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
+ || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
+ printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
+ kdevname(dev));
+ s->s_flags |= MS_RDONLY;
+ s->u.affs_sb.s_flags |= SF_READONLY;
+ }
+ switch (chksum) {
+ case MUFS_FS:
+ case MUFS_INTLFFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ /* fall thru */
+ case FS_INTLFFS:
+ s->u.affs_sb.s_flags |= SF_INTL;
+ break;
+ case MUFS_DCFFS:
+ case MUFS_FFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ break;
+ case FS_DCFFS:
+ case FS_FFS:
+ break;
+ case MUFS_OFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ /* fall thru */
+ case FS_OFS:
+ s->u.affs_sb.s_flags |= SF_OFS;
+ break;
+ case MUFS_DCOFS:
+ case MUFS_INTLOFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ case FS_DCOFS:
+ case FS_INTLOFS:
+ s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
+ break;
+ default:
+ goto out_unknown_fs;
}
+
if (mount_flags & SF_VERBOSE) {
chksum = cpu_to_be32(chksum);
printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
(char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
}
- s->s_magic = AFFS_SUPER_MAGIC;
s->s_flags |= MS_NODEV | MS_NOSUID;
/* Keep super block in cache */
- if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
- printk(KERN_ERR "AFFS: Cannot read root block\n");
- goto out;
- }
+ bb = affs_bread(dev,root_block,s->s_blocksize);
+ if (!bb)
+ goto out_no_root_block;
+ s->u.affs_sb.s_root_bh = bb;
+ /* N.B. after this point s_root_bh must be released */
/* Allocate space for bitmaps, zones and others */
az_no * sizeof(struct affs_alloc_zone) +
MAX_ZONES * sizeof(struct affs_zone);
pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
- if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
- printk(KERN_ERR "AFFS: Not enough memory\n");
- goto out;
- }
+ if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype, GFP_KERNEL)))
+ goto out_no_bitmap;
memset(s->u.affs_sb.s_bitmap,0,ptype);
+ /* N.B. after the point s_bitmap must be released */
s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES];
s->u.affs_sb.s_flags |= SF_READONLY;
continue;
}
- bb = affs_bread(s->s_dev,be32_to_cpu(bm[i]),s->s_blocksize);
- if (bb) {
- if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
- !(s->s_flags & MS_RDONLY)) {
- printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - "
- "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]),
- kdevname(dev));
- s->s_flags |= MS_RDONLY;
- s->u.affs_sb.s_flags |= SF_READONLY;
- }
- /* Mark unused bits in the last word as allocated */
- if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */
- ptype = size / 32 + 1; /* word number */
- key = size & 0x1F; /* used bits */
- if (key && !(s->s_flags & MS_RDONLY)) {
- chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key));
- ((u32 *)bb->b_data)[ptype] &= chksum;
- affs_fix_checksum(s->s_blocksize,bb->b_data,0);
- mark_buffer_dirty(bb,1);
- bmalt = 1;
- }
- ptype = (size + 31) & ~0x1F;
- size = 0;
- s->u.affs_sb.s_flags |= SF_BM_VALID;
- } else {
- ptype = s->s_blocksize * 8 - 32;
- size -= ptype;
- }
- s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
- s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL;
- s->u.affs_sb.s_bitmap[mapidx].bm_key = be32_to_cpu(bm[i]);
- s->u.affs_sb.s_bitmap[mapidx].bm_count = 0;
- offset += ptype;
-
- for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
- key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */
- s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
- s->u.affs_sb.s_alloc[az_no].az_free =
- affs_count_free_bits(key / 8,bb->b_data +
- j * (AFFS_ZONE_SIZE / 8) + 4);
+ bb = affs_bread(dev,be32_to_cpu(bm[i]),s->s_blocksize);
+ if (!bb)
+ goto out_no_read_bm;
+ if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
+ !(s->s_flags & MS_RDONLY)) {
+ printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - "
+ "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]),
+ kdevname(dev));
+ s->s_flags |= MS_RDONLY;
+ s->u.affs_sb.s_flags |= SF_READONLY;
+ }
+ /* Mark unused bits in the last word as allocated */
+ if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */
+ ptype = size / 32 + 1; /* word number */
+ key = size & 0x1F; /* used bits */
+ if (key && !(s->s_flags & MS_RDONLY)) {
+ chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key));
+ ((u32 *)bb->b_data)[ptype] &= chksum;
+ affs_fix_checksum(s->s_blocksize,bb->b_data,0);
+ mark_buffer_dirty(bb,1);
+ bmalt = 1;
}
- affs_brelse(bb);
+ ptype = (size + 31) & ~0x1F;
+ size = 0;
+ s->u.affs_sb.s_flags |= SF_BM_VALID;
} else {
- printk(KERN_ERR "AFFS: Cannot read bitmap\n");
- goto out;
+ ptype = s->s_blocksize * 8 - 32;
+ size -= ptype;
+ }
+ s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
+ s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL;
+ s->u.affs_sb.s_bitmap[mapidx].bm_key = be32_to_cpu(bm[i]);
+ s->u.affs_sb.s_bitmap[mapidx].bm_count = 0;
+ offset += ptype;
+
+ for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
+ key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */
+ s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
+ s->u.affs_sb.s_alloc[az_no].az_free =
+ affs_count_free_bits(key / 8,bb->b_data +
+ j * (AFFS_ZONE_SIZE / 8) + 4);
}
+ affs_brelse(bb);
}
key = be32_to_cpu(bm[stype]); /* Next block of bitmap pointers */
ptype = 0;
stype = s->s_blocksize / 4 - 1;
affs_brelse(bh);
+ bh = NULL;
if (key) {
- if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
- printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
- goto out;
- }
- } else
- bh = NULL;
- }
- if (mapidx < num_bm) {
- printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
- goto out;
+ bh = affs_bread(dev,key,s->s_blocksize);
+ if (!bh)
+ goto out_no_bm_ext;
+ }
}
+ if (mapidx < num_bm)
+ goto out_bad_num;
+
nobitmap:
s->u.affs_sb.s_bm_count = num_bm;
/* set up enough so that it can read an inode */
- s->s_dev = dev;
- s->s_op = &affs_sops;
s->s_dirt = 1;
root_inode = iget(s,root_block);
- s->s_root = d_alloc_root(root_inode,NULL);
- unlock_super(s);
-
- if (!(s->s_root)) {
- s->s_dev = 0;
- affs_brelse(s->u.affs_sb.s_root_bh);
- printk(KERN_ERR "AFFS: get root inode failed\n");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
- s->s_root->d_op = (s->u.affs_sb.s_flags & SF_INTL) ? &affs_dentry_operations_intl
- : &affs_dentry_operations;
+ if (!root_inode)
+ goto out_no_root;
+ s->s_root = d_alloc_root(root_inode, NULL);
+ if (!s->s_root)
+ goto out_no_root;
+ s->s_root->d_op = &affs_dentry_operations;
+ unlock_super(s);
/* Record date of last change if the bitmap was truncated and
* create data zones if the volume is writable.
*/
pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
return s;
- out: /* Kick out for various error conditions */
- affs_brelse (bh);
+out_bad_opts:
+ printk(KERN_ERR "AFFS: Error parsing options\n");
+ goto out_fail;
+out_bad_size:
+ printk(KERN_ERR "AFFS: Could not determine device size\n");
+ goto out_free_prefix;
+out_no_valid_block:
+ if (!silent)
+ printk(KERN_ERR "AFFS: No valid root block on device %s\n",
+ kdevname(dev));
+ goto out_restore;
+out_unknown_fs:
+ printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
+ kdevname(dev), chksum);
+ goto out_free_bh;
+out_no_root_block:
+ printk(KERN_ERR "AFFS: Cannot read root block\n");
+ goto out_free_bh;
+out_no_bitmap:
+ printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
+ goto out_free_root_block;
+out_no_read_bm:
+ printk(KERN_ERR "AFFS: Cannot read bitmap\n");
+ goto out_free_bitmap;
+out_no_bm_ext:
+ printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
+ goto out_free_bitmap;
+out_bad_num:
+ printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",
+ mapidx, num_bm);
+ goto out_free_bitmap;
+out_no_root:
+ printk(KERN_ERR "AFFS: get root inode failed\n");
+
+ /*
+ * Begin the cascaded cleanup ...
+ */
+ iput(root_inode);
+out_free_bitmap:
+ kfree(s->u.affs_sb.s_bitmap);
+out_free_root_block:
affs_brelse(s->u.affs_sb.s_root_bh);
- if (s->u.affs_sb.s_bitmap)
- kfree(s->u.affs_sb.s_bitmap);
- set_blocksize(dev,BLOCK_SIZE);
+out_free_bh:
+ affs_brelse(bh);
+out_restore:
+ set_blocksize(dev, s->u.affs_sb.s_blksize);
+out_free_prefix:
+ if (s->u.affs_sb.s_prefix)
+ kfree(s->u.affs_sb.s_prefix);
+out_fail:
s->s_dev = 0;
unlock_super(s);
MOD_DEC_USE_COUNT;
static void ntfs_put_inode(struct inode *ino)
{
- ntfs_debug(DEBUG_OTHER, "ntfs_put_inode %lx\n",ino->i_ino);
+}
+
+static void _ntfs_clear_inode(struct inode *ino)
+{
+ ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino);
#ifdef NTFS_IN_LINUX_KERNEL
if(ino->i_ino!=FILE_MFT)
ntfs_clear_inode(&ino->u.ntfs_i);
ino->u.generic_ip=0;
}
#endif
- clear_inode(ino);
+ return;
}
/* Called when umounting a filesystem by do_umount() in fs/super.c */
NULL, /* write_super */
ntfs_statfs,
ntfs_remount_fs, /* remount */
+ _ntfs_clear_inode, /* clear_inode */
};
/* Called to mount a filesystem by read_super() in fs/super.c
void ntfs_clear_inode(ntfs_inode *ino)
{
int i;
+ if(!ino->attr){
+ ntfs_error("ntfs_clear_inode: double free\n");
+ return;
+ }
ntfs_free(ino->attr);
+ ino->attr=0;
ntfs_free(ino->records);
+ ino->records=0;
for(i=0;i<ino->attr_count;i++)
{
if(ino->attrs[i].name)
}
}
ntfs_free(ino->attrs);
+ ino->attrs=0;
}
/* Check and fixup a MFT record */
unsigned char green [256];
unsigned char blue [256];
};
-
-
-
-#define GFX_NAME_NEWPORT "NG1"
-
-/* ioctls */
-#define NG1_SET_CURSOR_HOTSPOT 21001
-struct ng1_set_cursor_hotspot {
- unsigned short xhot;
- unsigned short yhot;
-};
-
-#define NG1_SETDISPLAYMODE 21006
-struct ng1_setdisplaymode_args {
- int wid;
- unsigned int mode;
-};
-
-#define NG1_SETGAMMARAMP0 21007
-struct ng1_setgammaramp_args {
- unsigned char red [256];
- unsigned char green [256];
- unsigned char blue [256];
-};
-
-
-/*
- * IRIX prctl interface
- *
- * The IRIX kernel maps a page at PRDA_ADDRESS with the
- * contents of prda and fills it the bits on prda_sys.
- * $Id: prctl.h,v 1.1 1997/09/21 22:27:19 miguel Exp $
- */
-
-#ifndef __PRCTL_H__
-#define __PRCTL_H__
-
-#define PRDA_ADDRESS 0x200000L
-#define PRDA ((struct prda *) PRDA_ADDRESS)
-
-struct prda_sys {
- pid_t t_pid;
- u32 t_hint;
- u32 t_dlactseq;
- u32 t_fpflags;
- u32 t_prid; /* processor type, $prid CP0 register */
- u32 t_dlendseq;
- u64 t_unused1[5];
- pid_t t_rpid;
- s32 t_resched;
- u32 t_unused[8];
- u32 t_cpu; /* current/last cpu */
-
- /* FIXME: The signal information, not supported by Linux now */
- u32 t_flags; /* if true, then the sigprocmask is in userspace */
- u32 t_sigprocmask [1]; /* the sigprocmask */
-};
-
-struct prda {
- char fill [0xe00];
- struct prda_sys prda_sys;
-};
-
-#define t_sys prda_sys
-
-ptrdiff_t prctl (int op, int v1, int v2);
-
-#endif
/*
* IRIX prctl interface
*
caddr_t ptr;
} svr4_xrs_t;
-/* Machine dependant context */
+/* Machine dependent context */
typedef struct {
svr4_gregset_t greg; /* registers 0..19 (see top) */
svr4_gwindows_t *gwin; /* may point to register windows */
u32 ptr;
} svr4_xrs_t;
-/* Machine dependant context */
+/* Machine dependent context */
typedef struct {
svr4_gregset_t greg; /* registers 0..19 (see top) */
u32 gwin; /* may point to register windows */
struct affs_sb_info {
int s_partition_size; /* Partition size in blocks. */
+ int s_blksize; /* Initial device blksize */
s32 s_root_block; /* FFS root block number. */
int s_hashsize; /* Size of hash table. */
unsigned long s_flags; /* See below. */
#define AT_GID 13 /* real gid */
#define AT_EGID 14 /* effective gid */
#define AT_PLATFORM 15 /* string identifying cpu for optimizations */
-#define AT_HWCAP 16 /* arch dependant hints at cpu capabilities */
+#define AT_HWCAP 16 /* arch dependent hints at cpu capabilities */
typedef struct dynamic{
Elf32_Sword d_tag;
#define SHAPER_QLEN 10
/*
- * This is a bit speed dependant (read it shouldnt be a constant!)
+ * This is a bit speed dependent (read it shouldn't be a constant!)
*
* 5 is about right for 28.8 upwards. Below that double for every
* halving of speed or so. - ie about 20 for 9600 baud.
#ifndef _PARPORT_H_
#define _PARPORT_H_
+/* Start off with user-visible constants */
+
+/* Maximum of 8 ports per machine */
+#define PARPORT_MAX 8
+
+/* Magic numbers */
+#define PARPORT_IRQ_NONE -1
+#define PARPORT_DMA_NONE -1
+#define PARPORT_IRQ_AUTO -2
+#define PARPORT_DMA_AUTO -2
+#define PARPORT_DISABLE -2
+
+#define PARPORT_CONTROL_STROBE 0x1
+#define PARPORT_CONTROL_AUTOFD 0x2
+#define PARPORT_CONTROL_INIT 0x4
+#define PARPORT_CONTROL_SELECT 0x8
+#define PARPORT_CONTROL_INTEN 0x10
+#define PARPORT_CONTROL_DIRECTION 0x20
+
+#define PARPORT_STATUS_ERROR 0x8
+#define PARPORT_STATUS_SELECT 0x10
+#define PARPORT_STATUS_PAPEROUT 0x20
+#define PARPORT_STATUS_ACK 0x40
+#define PARPORT_STATUS_BUSY 0x80
+
+/* Type classes for Plug-and-Play probe. */
+typedef enum {
+ PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */
+ PARPORT_CLASS_PRINTER,
+ PARPORT_CLASS_MODEM,
+ PARPORT_CLASS_NET,
+ PARPORT_CLASS_HDC, /* Hard disk controller */
+ PARPORT_CLASS_PCMCIA,
+ PARPORT_CLASS_MEDIA, /* Multimedia device */
+ PARPORT_CLASS_FDC, /* Floppy disk controller */
+ PARPORT_CLASS_PORTS,
+ PARPORT_CLASS_SCANNER,
+ PARPORT_CLASS_DIGCAM,
+ PARPORT_CLASS_OTHER, /* Anything else */
+ PARPORT_CLASS_UNSPEC /* No CLS field in ID */
+} parport_device_class;
+
+/* The "modes" entry in parport is a bit field representing the following
+ * modes.
+ * Note that PARPORT_MODE_PCECPEPP is for the SMC EPP+ECP mode which is NOT
+ * 100% compatible with EPP.
+ */
+#define PARPORT_MODE_PCSPP 0x0001
+#define PARPORT_MODE_PCPS2 0x0002
+#define PARPORT_MODE_PCEPP 0x0004
+#define PARPORT_MODE_PCECP 0x0008
+#define PARPORT_MODE_PCECPEPP 0x0010
+#define PARPORT_MODE_PCECR 0x0020 /* ECR Register Exists */
+#define PARPORT_MODE_PCECPPS2 0x0040
+
+/* The rest is for the kernel only */
+#ifdef __KERNEL__
+
#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/spinlock.h>
#define PARPORT_NEED_GENERIC_OPS
-/* Maximum of 8 ports per machine */
-#define PARPORT_MAX 8
-
-/* Magic numbers */
-#define PARPORT_IRQ_NONE -2
-#define PARPORT_DMA_NONE -2
-#define PARPORT_IRQ_AUTO -1
-#define PARPORT_DMA_AUTO -1
-#define PARPORT_DISABLE -2
-
/* Define this later. */
struct parport;
};
struct parport_operations {
- void (*write_data)(struct parport *, unsigned int);
- unsigned int (*read_data)(struct parport *);
- void (*write_control)(struct parport *, unsigned int);
- unsigned int (*read_control)(struct parport *);
- unsigned int (*frob_control)(struct parport *, unsigned int mask, unsigned int val);
- void (*write_econtrol)(struct parport *, unsigned int);
- unsigned int (*read_econtrol)(struct parport *);
- unsigned int (*frob_econtrol)(struct parport *, unsigned int mask, unsigned int val);
- void (*write_status)(struct parport *, unsigned int);
- unsigned int (*read_status)(struct parport *);
- void (*write_fifo)(struct parport *, unsigned int);
- unsigned int (*read_fifo)(struct parport *);
+ void (*write_data)(struct parport *, unsigned char);
+ unsigned char (*read_data)(struct parport *);
+ void (*write_control)(struct parport *, unsigned char);
+ unsigned char (*read_control)(struct parport *);
+ unsigned char (*frob_control)(struct parport *, unsigned char mask, unsigned char val);
+ void (*write_econtrol)(struct parport *, unsigned char);
+ unsigned char (*read_econtrol)(struct parport *);
+ unsigned char (*frob_econtrol)(struct parport *, unsigned char mask, unsigned char val);
+ void (*write_status)(struct parport *, unsigned char);
+ unsigned char (*read_status)(struct parport *);
+ void (*write_fifo)(struct parport *, unsigned char);
+ unsigned char (*read_fifo)(struct parport *);
void (*change_mode)(struct parport *, int);
void (*release_resources)(struct parport *);
int (*claim_resources)(struct parport *);
- unsigned int (*epp_write_block)(struct parport *, void *, unsigned int);
- unsigned int (*epp_read_block)(struct parport *, void *, unsigned int);
+ size_t (*epp_write_block)(struct parport *, void *, size_t);
+ size_t (*epp_read_block)(struct parport *, void *, size_t);
- unsigned int (*ecp_write_block)(struct parport *, void *, unsigned int, void (*fn)(struct parport *, void *, unsigned int), void *);
- unsigned int (*ecp_read_block)(struct parport *, void *, unsigned int, void (*fn)(struct parport *, void *, unsigned int), void *);
+ int (*ecp_write_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
+ int (*ecp_read_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
void (*save_state)(struct parport *, struct parport_state *);
void (*restore_state)(struct parport *, struct parport_state *);
void (*dec_use_count)(void);
};
-#define PARPORT_CONTROL_STROBE 0x1
-#define PARPORT_CONTROL_AUTOFD 0x2
-#define PARPORT_CONTROL_INIT 0x4
-#define PARPORT_CONTROL_SELECT 0x8
-#define PARPORT_CONTROL_INTEN 0x10
-#define PARPORT_CONTROL_DIRECTION 0x20
-
-#define PARPORT_STATUS_ERROR 0x8
-#define PARPORT_STATUS_SELECT 0x10
-#define PARPORT_STATUS_PAPEROUT 0x20
-#define PARPORT_STATUS_ACK 0x40
-#define PARPORT_STATUS_BUSY 0x80
-
-/* Type classes for Plug-and-Play probe. */
-typedef enum {
- PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */
- PARPORT_CLASS_PRINTER,
- PARPORT_CLASS_MODEM,
- PARPORT_CLASS_NET,
- PARPORT_CLASS_HDC, /* Hard disk controller */
- PARPORT_CLASS_PCMCIA,
- PARPORT_CLASS_MEDIA, /* Multimedia device */
- PARPORT_CLASS_FDC, /* Floppy disk controller */
- PARPORT_CLASS_PORTS,
- PARPORT_CLASS_SCANNER,
- PARPORT_CLASS_DIGCAM,
- PARPORT_CLASS_OTHER, /* Anything else */
- PARPORT_CLASS_UNSPEC /* No CLS field in ID */
-} parport_device_class;
-
struct parport_device_info {
parport_device_class class;
char *mfr;
struct parport_operations *ops;
void *private_data; /* for lowlevel driver */
-
+ int number; /* port index - the `n' in `parportn' */
spinlock_t lock;
};
extern void parport_release(struct pardevice *dev);
-extern __inline__ unsigned int parport_yield(struct pardevice *dev,
- unsigned int block)
+/* parport_yield relinquishes the port if it would be helpful to other
+ * drivers. The return value is the same as for parport_claim.
+ */
+extern __inline__ unsigned int parport_yield(struct pardevice *dev)
{
unsigned long int timeslip = (jiffies - dev->time);
if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
- return 1;
+ return 0;
parport_release(dev);
- return (block)?parport_claim_or_block(dev):parport_claim(dev);
+ return parport_claim(dev);
}
-/* The "modes" entry in parport is a bit field representing the following
- * modes.
- * Note that LP_ECPEPP is for the SMC EPP+ECP mode which is NOT
- * 100% compatible with EPP.
+/* parport_yield_blocking is the same but uses parport_claim_or_block
+ * instead of parport_claim.
*/
-#define PARPORT_MODE_PCSPP 0x0001
-#define PARPORT_MODE_PCPS2 0x0002
-#define PARPORT_MODE_PCEPP 0x0004
-#define PARPORT_MODE_PCECP 0x0008
-#define PARPORT_MODE_PCECPEPP 0x0010
-#define PARPORT_MODE_PCECR 0x0020 /* ECR Register Exists */
-#define PARPORT_MODE_PCECPPS2 0x0040
+extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev)
+{
+ unsigned long int timeslip = (jiffies - dev->time);
+ if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
+ return 0;
+ parport_release(dev);
+ return parport_claim_or_block(dev);
+}
/* Flags used to identify what a device does. */
#define PARPORT_DEV_TRAN 0x0000 /* We're transient. */
#define parport_claim_resources(p) (p)->ops->claim_resources(p)
#endif
+#endif /* __KERNEL__ */
#endif /* _PARPORT_H_ */
#define STATUS 0x1
#define DATA 0
-extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned int d)
+extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
{
outb(d, p->base+EPPREG);
}
-extern __inline__ unsigned int parport_pc_read_epp(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
{
- return (unsigned int)inb(p->base+EPPREG);
+ return inb(p->base+EPPREG);
}
-extern __inline__ unsigned int parport_pc_read_configb(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
{
- return (unsigned int)inb(p->base+CONFIGB);
+ return inb(p->base+CONFIGB);
}
-extern __inline__ void parport_pc_write_data(struct parport *p, unsigned int d)
+extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
{
outb(d, p->base+DATA);
}
-extern __inline__ unsigned int parport_pc_read_data(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
{
- return (unsigned int)inb(p->base+DATA);
+ return inb(p->base+DATA);
}
-extern __inline__ void parport_pc_write_control(struct parport *p, unsigned int d)
+extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
{
outb(d, p->base+CONTROL);
}
-extern __inline__ unsigned int parport_pc_read_control(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
{
- return (unsigned int)inb(p->base+CONTROL);
+ return inb(p->base+CONTROL);
}
-extern __inline__ unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val)
+extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base+CONTROL);
+ unsigned char old = inb(p->base+CONTROL);
outb(((old & ~mask) ^ val), p->base+CONTROL);
return old;
}
-extern __inline__ void parport_pc_write_status(struct parport *p, unsigned int d)
+extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
{
outb(d, p->base+STATUS);
}
-extern __inline__ unsigned int parport_pc_read_status(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
{
- return (unsigned int)inb(p->base+STATUS);
+ return inb(p->base+STATUS);
}
-extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned int d)
+extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
{
outb(d, p->base+ECONTROL);
}
-extern __inline__ unsigned int parport_pc_read_econtrol(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
{
- return (unsigned int)inb(p->base+ECONTROL);
+ return inb(p->base+ECONTROL);
}
-extern __inline__ unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
+extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned int old = (unsigned int)inb(p->base+ECONTROL);
+ unsigned char old = inb(p->base+ECONTROL);
outb(((old & ~mask) ^ val), p->base+ECONTROL);
return old;
}
extern void parport_pc_change_mode(struct parport *p, int m);
-extern void parport_pc_write_fifo(struct parport *p, unsigned int v);
+extern void parport_pc_write_fifo(struct parport *p, unsigned char v);
-extern unsigned int parport_pc_read_fifo(struct parport *p);
+extern unsigned char parport_pc_read_fifo(struct parport *p);
extern void parport_pc_disable_irq(struct parport *p);
extern void parport_pc_restore_state(struct parport *p, struct parport_state *s);
-extern unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length);
+extern size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length);
-extern unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length);
+extern size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length);
-extern unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle);
+extern int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
-extern unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle);
+extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
extern int parport_pc_examine_irq(struct parport *p);
#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */
#define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */
#define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */
-/*----- Command-dependant results -----*/
+/*----- Command-dependent results -----*/
#define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */
#define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */
#define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/
struct iw_statistics
{
__u8 status; /* Status
- * - device dependant for now */
+ * - device dependent for now */
struct iw_quality qual; /* Quality of the link
* (instant/mean/max) */
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
-/* These are AF independant. */
+/* These are AF independent. */
static __inline__ int tcp_bhashfn(__u16 lport)
{
return (lport ^ (lport >> 7)) & (TCP_BHTABLE_SIZE - 1);
goto done;
}
if (!pte_none(pte)) {
- rw_swap_page(READ, pte_val(pte), (char *) page, 1); /* FIXME */
+ rw_swap_page_nocache(READ, pte_val(pte), (char *)page);
pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1)
goto check_table;
shp->shm_pages[idx] = swap_nr;
- rw_swap_page(WRITE, swap_nr, (char *) pte_page(page), 1); /* FIXME */
+ rw_swap_page_nocache (WRITE, swap_nr, (char *) pte_page(page));
free_page(pte_page(page));
swap_successes++;
shm_swp++;
EXPORT_SYMBOL(find_inode_number);
EXPORT_SYMBOL(is_subdir);
+#ifdef CONFIG_AUTOFS_FS_MODULE
+EXPORT_SYMBOL(locks_remove_flock);
+#endif
+
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL(do_nfsservctl);
#endif
for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
struct module *o, *d = dep->dep;
- /* Make sure the indicated dependancies are really modules. */
+ /* Make sure the indicated dependencies are really modules. */
if (d == mod) {
printk(KERN_ERR "init_module: self-referential "
- "dependancy in mod->deps.\n");
+ "dependency in mod->deps.\n");
goto err3;
}
for (o = module_list; o != &kernel_module; o = o->next)
if (o == d) goto found_dep;
- printk(KERN_ERR "init_module: found dependancy that is "
+ printk(KERN_ERR "init_module: found dependency that is "
"(no longer?) a module.\n");
goto err3;
mod->flags &= ~MOD_RUNNING;
}
- /* Remove the module from the dependancy lists. */
+ /* Remove the module from the dependency lists. */
for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
struct module_ref **pp;
}
page->inode = &swapper_inode;
page->offset = entry;
+ atomic_inc(&page->count); /* Protect from shrink_mmap() */
rw_swap_page(rw, entry, buffer, 1);
+ atomic_dec(&page->count);
page->inode = 0;
clear_bit(PG_swap_cache, &page->flags);
}
*
* -- Stephen Tweedie 1998 */
- if (pte_write(pte)) {
- /*
- * We _will_ allow dirty cached mappings later on, once
- * MAP_SHARED|MAP_ANONYMOUS is working, but for now
- * catch this as a bug.
- */
- if (is_page_shared(page_map)) {
- printk ("VM: Found a shared writable dirty page!\n");
- return 0;
- }
- if (PageSwapCache(page_map)) {
+ if (PageSwapCache(page_map)) {
+ if (pte_write(pte)) {
printk ("VM: Found a writable swap-cached page!\n");
return 0;
}
}
/*
- * FIXME: We could do with an architecture dependant
+ * FIXME: We could do with an architecture dependent
* 'alignment mask'.
*/
return isn;
}
-/* This value should be dependant on TCP_TIMEOUT_INIT and
+/* This value should be dependent on TCP_TIMEOUT_INIT and
* sysctl_tcp_retries1. It's a rather complicated formula
* (exponential backoff) to compute at runtime so it's currently hardcoded
* here.
return 0;
}
-/* Find a "good" local port, this is family independant.
+/* Find a "good" local port, this is family independent.
* There are several strategies working in unison here to
* get the best possible performance. The current socket
* load is kept track of, if it is zero there is a strong