## Automatically generated incremental diff
## From:   linux-2.5.66-bk2
## To:     linux-2.5.66-bk3
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.5.66-bk2/CREDITS linux-2.5.66-bk3/CREDITS
--- linux-2.5.66-bk2/CREDITS	Mon Mar 24 14:01:12 2003
+++ linux-2.5.66-bk3/CREDITS	Mon Mar 31 12:48:53 2003
@@ -1210,6 +1210,10 @@
 S: Atlanta, Georgia 30332
 S: USA
 
+N: Brad Hards
+E: bradh@frogmouth.net
+D: Various USB bits, other minor patches
+
 N: Angelo Haritsis
 E: ah@computer.org
 D: kernel patches (serial, watchdog)
diff -urN linux-2.5.66-bk2/MAINTAINERS linux-2.5.66-bk3/MAINTAINERS
--- linux-2.5.66-bk2/MAINTAINERS	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/MAINTAINERS	Mon Mar 31 12:48:53 2003
@@ -1869,11 +1869,12 @@
 W:	http://www.kroah.com/linux-usb/
 
 USB CDC ETHERNET DRIVER
-P:	Brad Hards
-M:	bradh@frogmouth.net
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
+W:	http://www.kroah.com/linux-usb/
 
 USB EHCI DRIVER
 P:	David Brownell
diff -urN linux-2.5.66-bk2/Makefile linux-2.5.66-bk3/Makefile
--- linux-2.5.66-bk2/Makefile	Mon Mar 31 12:48:51 2003
+++ linux-2.5.66-bk3/Makefile	Mon Mar 31 12:48:53 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 66
-EXTRAVERSION = -bk2
+EXTRAVERSION = -bk3
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.66-bk2/arch/arm/kernel/apm.c linux-2.5.66-bk3/arch/arm/kernel/apm.c
--- linux-2.5.66-bk2/arch/arm/kernel/apm.c	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/arch/arm/kernel/apm.c	Mon Mar 31 12:48:53 2003
@@ -552,8 +552,6 @@
 MODULE_DESCRIPTION("Advanced Power Management");
 MODULE_LICENSE("GPL");
 
-EXPORT_NO_SYMBOLS;
-
 #ifndef MODULE
 static int __init apm_setup(char *str)
 {
diff -urN linux-2.5.66-bk2/arch/arm/kernel/armksyms.c linux-2.5.66-bk3/arch/arm/kernel/armksyms.c
--- linux-2.5.66-bk2/arch/arm/kernel/armksyms.c	Mon Mar 24 14:00:16 2003
+++ linux-2.5.66-bk3/arch/arm/kernel/armksyms.c	Mon Mar 31 12:48:53 2003
@@ -69,6 +69,7 @@
 extern void __udivsi3(void);
 extern void __umodsi3(void);
 extern void abort(void);
+extern void do_div64(void);
 
 extern void ret_from_exception(void);
 extern void fpundefinstr(void);
@@ -234,6 +235,7 @@
 EXPORT_SYMBOL_NOVERS(__udivmoddi4);
 EXPORT_SYMBOL_NOVERS(__udivsi3);
 EXPORT_SYMBOL_NOVERS(__umodsi3);
+EXPORT_SYMBOL_NOVERS(do_div64);
 
 	/* bitops */
 EXPORT_SYMBOL(_set_bit_le);
diff -urN linux-2.5.66-bk2/arch/arm/kernel/entry-armv.S linux-2.5.66-bk3/arch/arm/kernel/entry-armv.S
--- linux-2.5.66-bk2/arch/arm/kernel/entry-armv.S	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk3/arch/arm/kernel/entry-armv.S	Mon Mar 31 12:48:53 2003
@@ -997,11 +997,11 @@
  * previous and next are guaranteed not to be the same.
  */
 ENTRY(__switch_to)
-		add	ip, r0, #TI_CPU_SAVE
-		ldr	r2, [r1, #TI_CPU_DOMAIN]!
+		add	ip, r1, #TI_CPU_SAVE
+		ldr	r3, [r2, #TI_CPU_DOMAIN]!
 		stmia	ip, {r4 - sl, fp, sp, lr}	@ Store most regs on stack
-		mcr	p15, 0, r2, c3, c0		@ Set domain register
-		ldmib	r1, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
+		mcr	p15, 0, r3, c3, c0, 0		@ Set domain register
+		ldmib	r2, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
 
 		__INIT
 /*
diff -urN linux-2.5.66-bk2/arch/arm/kernel/entry-common.S linux-2.5.66-bk3/arch/arm/kernel/entry-common.S
--- linux-2.5.66-bk2/arch/arm/kernel/entry-common.S	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/arch/arm/kernel/entry-common.S	Mon Mar 31 12:48:53 2003
@@ -75,7 +75,6 @@
  * This is how we return from a fork.
  */
 ENTRY(ret_from_fork)
-	ldr	r0, [r0, #TI_TASK]
 	bl	schedule_tail
 	get_thread_info tsk
 	ldr	r1, [tsk, #TI_FLAGS]		@ check for syscall tracing
diff -urN linux-2.5.66-bk2/arch/arm/lib/Makefile linux-2.5.66-bk3/arch/arm/lib/Makefile
--- linux-2.5.66-bk2/arch/arm/lib/Makefile	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk3/arch/arm/lib/Makefile	Mon Mar 31 12:48:53 2003
@@ -13,7 +13,7 @@
 		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
 		   testclearbit.o testsetbit.o uaccess.o getuser.o    \
 		   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
-		   ucmpdi2.o udivdi3.o lib1funcs.o
+		   ucmpdi2.o udivdi3.o lib1funcs.o div64.o
 obj-m		:=
 obj-n		:=
 
diff -urN linux-2.5.66-bk2/arch/arm/lib/div64.S linux-2.5.66-bk3/arch/arm/lib/div64.S
--- linux-2.5.66-bk2/arch/arm/lib/div64.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/arch/arm/lib/div64.S	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,42 @@
+#include <linux/linkage.h>
+
+ql	.req	r0			@ quotient low
+qh	.req	r1			@ quotient high
+dl	.req	r3			@ divisor low
+dh	.req	r2			@ divisor high
+nl	.req	r4			@ dividend low
+nh	.req	r5			@ dividend high
+
+ENTRY(do_div64)
+	stmfd	sp!, {r4, r5, lr}
+	mov	nl, r0
+	movs	nh, r1			@ if high bits are zero
+	movne	lr, #33
+	moveq	lr, #1			@ only divide low bits
+	moveq	nh, r0
+
+1:	cmp	nh, dh
+	bls	2f
+	add	lr, lr, #1
+	movs	dh, dh, lsl #1		@ left justify divisor
+	bpl	1b
+
+2:	movs	nh, r1
+	moveq	dl, dh
+	moveq	dh, #0
+	movne	dl, #0
+	mov	ql, #0
+	mov	qh, #0
+3:	subs	ip, nl, dl		@ trial subtraction
+	sbcs	ip, nh, dh
+	movcs	nh, ip			@ only update if successful
+	subcs	nl, nl, dl		@ (repeat the subtraction)
+	adcs	ql, ql, ql		@ C=1 if successful, shift into
+	adc	qh, qh, qh		@ quotient
+	movs	dh, dh, lsr #1		@ shift base high part right
+	mov	dl, dl, rrx		@ shift base low part right
+	subs	lr, lr, #1
+	bne	3b
+
+	mov	r2, nl
+	ldmfd	sp!, {r4, r5, pc}
diff -urN linux-2.5.66-bk2/arch/arm/mach-footbridge/dc21285.c linux-2.5.66-bk3/arch/arm/mach-footbridge/dc21285.c
--- linux-2.5.66-bk2/arch/arm/mach-footbridge/dc21285.c	Mon Mar 24 14:01:53 2003
+++ linux-2.5.66-bk3/arch/arm/mach-footbridge/dc21285.c	Mon Mar 31 12:48:53 2003
@@ -25,10 +25,13 @@
 
 #define MAX_SLOTS		21
 
-#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \
-			PCI_STATUS_REC_MASTER_ABORT | \
-			PCI_STATUS_REC_TARGET_ABORT | \
-			PCI_STATUS_PARITY) << 16)
+#define PCICMD_ABORT		((PCI_STATUS_REC_MASTER_ABORT| \
+				  PCI_STATUS_REC_TARGET_ABORT)<<16)
+
+#define PCICMD_ERROR_BITS	((PCI_STATUS_DETECTED_PARITY | \
+				  PCI_STATUS_REC_MASTER_ABORT | \
+				  PCI_STATUS_REC_TARGET_ABORT | \
+				  PCI_STATUS_PARITY) << 16)
 
 extern int setup_arm_irq(int, struct irqaction *);
 extern void pcibios_report_status(u_int status_mask, int warn);
@@ -84,6 +87,12 @@
 
 	*value = v;
 
+	v = *CSR_PCICMD;
+	if (v & PCICMD_ABORT) {
+		*CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
+		return -1;
+	}
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -92,6 +101,7 @@
 		     int size, u32 value)
 {
 	unsigned long addr = dc21285_base_address(bus, devfn);
+	u32 v;
 
 	if (addr)
 		switch (size) {
@@ -109,6 +119,12 @@
 			break;
 		}
 
+	v = *CSR_PCICMD;
+	if (v & PCICMD_ABORT) {
+		*CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
+		return -1;
+	}
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -148,16 +164,16 @@
 	cmd = cmd & 0xffff;
 
 	if (status & PCI_STATUS_REC_MASTER_ABORT) {
-		printk(KERN_DEBUG "PCI: master abort: ");
-		pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1);
-		printk("\n");
-
+		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n",
+			instruction_pointer(regs));
 		cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
 	}
 
 	if (status & PCI_STATUS_REC_TARGET_ABORT) {
 		printk(KERN_DEBUG "PCI: target abort: ");
-		pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1);
+		pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT |
+				      PCI_STATUS_SIG_TARGET_ABORT |
+				      PCI_STATUS_REC_TARGET_ABORT, 1);
 		printk("\n");
 
 		cmd |= PCI_STATUS_REC_TARGET_ABORT << 16;
@@ -289,6 +305,38 @@
 		"%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
 		"central function" : "addin");
 
+	if (footbridge_cfn_mode()) {
+		/*
+		 * Clear any existing errors - we aren't
+		 * interested in historical data...
+		 */
+		*CSR_SA110_CNTL	= (*CSR_SA110_CNTL & 0xffffde07) |
+				  SA110_CNTL_RXSERR;
+		*CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
+	}
+
+	init_timer(&serr_timer);
+	init_timer(&perr_timer);
+
+	serr_timer.data = IRQ_PCI_SERR;
+	serr_timer.function = dc21285_enable_error;
+	perr_timer.data = IRQ_PCI_PERR;
+	perr_timer.function = dc21285_enable_error;
+
+	/*
+	 * We don't care if these fail.
+	 */
+	request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT,
+		    "PCI system error", &serr_timer);
+	request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT,
+		    "PCI parity error", &perr_timer);
+	request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT,
+		    "PCI abort", NULL);
+	request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT,
+		    "Discard timer", NULL);
+	request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT,
+		    "PCI data parity", NULL);
+
 	if (cfn_mode) {
 		static struct resource csrio;
 
@@ -324,35 +372,5 @@
 
 void __init dc21285_postinit(void)
 {
-	if (footbridge_cfn_mode()) {
-		/*
-		 * Clear any existing errors - we aren't
-		 * interested in historical data...
-		 */
-		*CSR_SA110_CNTL	= (*CSR_SA110_CNTL & 0xffffde07) |
-				  SA110_CNTL_RXSERR;
-		*CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
-	}
-
-	/*
-	 * Initialise PCI error IRQ after we've finished probing
-	 */
-	request_irq(IRQ_PCI_ABORT,     dc21285_abort_irq,   SA_INTERRUPT, "PCI abort",       NULL);
-	request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer",   NULL);
-	request_irq(IRQ_PCI_DPERR,     dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL);
-
-	init_timer(&serr_timer);
-	init_timer(&perr_timer);
-
-	serr_timer.data = IRQ_PCI_SERR;
-	serr_timer.function = dc21285_enable_error;
-	perr_timer.data = IRQ_PCI_PERR;
-	perr_timer.function = dc21285_enable_error;
-
-	request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT,
-		    "PCI system error", &serr_timer);
-	request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT,
-		    "PCI parity error", &perr_timer);
-
 	register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
 }
diff -urN linux-2.5.66-bk2/arch/arm/mach-sa1100/assabet.c linux-2.5.66-bk3/arch/arm/mach-sa1100/assabet.c
--- linux-2.5.66-bk2/arch/arm/mach-sa1100/assabet.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/arch/arm/mach-sa1100/assabet.c	Mon Mar 31 12:48:53 2003
@@ -117,6 +117,8 @@
 	PGSR = 0;
 	PCFR = 0;
 	PSDR = 0;
+	PPDR |= PPC_TXD3 | PPC_TXD1;
+	PPSR |= PPC_TXD3 | PPC_TXD1;
 
 	sa1100fb_lcd_power = assabet_lcd_power;
 	sa1100fb_backlight_power = assabet_backlight_power;
diff -urN linux-2.5.66-bk2/arch/arm/mach-sa1100/cpu-sa1110.c linux-2.5.66-bk3/arch/arm/mach-sa1100/cpu-sa1110.c
--- linux-2.5.66-bk2/arch/arm/mach-sa1100/cpu-sa1110.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/arch/arm/mach-sa1100/cpu-sa1110.c	Mon Mar 31 12:48:53 2003
@@ -234,6 +234,8 @@
 		    (sa11x0_ppcr_to_freq(ppcr-1) >= policy->min))
 			ppcr--;
 		break;
+	default:
+		return -EINVAL;
 	}
 
 	freqs.old = sa11x0_getspeed();
diff -urN linux-2.5.66-bk2/arch/arm/tools/mach-types linux-2.5.66-bk3/arch/arm/tools/mach-types
--- linux-2.5.66-bk2/arch/arm/tools/mach-types	Mon Mar 24 14:00:35 2003
+++ linux-2.5.66-bk3/arch/arm/tools/mach-types	Mon Mar 31 12:48:53 2003
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Wed Mar 5 22:11:59 2003
+# Last update: Tue Mar 25 16:34:29 2003
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -305,3 +305,11 @@
 pxa_whitechapel		ARCH_PXA_WHITECHAPEL	PXA_WHITECHAPEL		294
 nwsc			ARCH_NWSC		NWSC			295
 nwlarm			ARCH_NWLARM		NWLARM			296
+ixp425_mguard		ARCH_IXP425_MGUARD	IXP425_MGUARD		297
+pxa_netdcu4		ARCH_PXA_NETDCU4	PXA_NETDCU4		298
+ixdp2401		ARCH_IXDP2401		IXDP2401		299
+ixdp2801		ARCH_IXDP2801		IXDP2801		300
+zodiac			ARCH_ZODIAC		ZODIAC			301
+armmodul		ARCH_ARMMODUL		ARMMODUL		302
+ketop			SA1100_KETOP		KETOP			303
+av7200			ARCH_AV7200		AV7200			304
diff -urN linux-2.5.66-bk2/arch/sparc/Makefile linux-2.5.66-bk3/arch/sparc/Makefile
--- linux-2.5.66-bk2/arch/sparc/Makefile	Mon Mar 24 14:00:03 2003
+++ linux-2.5.66-bk3/arch/sparc/Makefile	Mon Mar 31 12:48:53 2003
@@ -54,13 +54,16 @@
 LIBS_Y		:= $(patsubst %/, %/lib.a, $(libs-y))
 export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y
 
-makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1)
+# Default target
+all: image
+
+boot := arch/sparc/boot
 
 image tftpboot.img: vmlinux
-	$(call makeboot,arch/sparc/boot/$@)
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 archclean:
-	$(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/$(ARCH)/boot
+	$(Q)$(MAKE) $(clean)=$(boot)
 
 prepare: include/asm-$(ARCH)/asm_offsets.h
 
@@ -72,3 +75,9 @@
 
 CLEAN_FILES +=	include/asm-$(ARCH)/asm_offsets.h	\
 		arch/$(ARCH)/kernel/asm-offsets.s
+
+# Don't use tabs in echo arguments.
+define archhelp
+  echo  '* image        - kernel image ($(boot)/image)'
+  echo  '  tftpboot.img - image prepared for tftp'
+endef
diff -urN linux-2.5.66-bk2/arch/sparc/boot/Makefile linux-2.5.66-bk3/arch/sparc/boot/Makefile
--- linux-2.5.66-bk2/arch/sparc/boot/Makefile	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk3/arch/sparc/boot/Makefile	Mon Mar 31 12:48:53 2003
@@ -32,7 +32,3 @@
 
 $(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE
 	$(call if_changed,btfix)
-
-archhelp:
-	@echo '* image		- kernel image ($(obj)/image)'
-	@echo '  tftpboot.img	- image prepared for tftp'
diff -urN linux-2.5.66-bk2/arch/sparc64/Kconfig linux-2.5.66-bk3/arch/sparc64/Kconfig
--- linux-2.5.66-bk2/arch/sparc64/Kconfig	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk3/arch/sparc64/Kconfig	Mon Mar 31 12:48:53 2003
@@ -139,8 +139,8 @@
 	bool "CPU Frequency scaling"
 	help
 	  Clock scaling allows you to change the clock speed of CPUs on the
-	  fly.  Currently there is only a sparc64 driver for UltraSPARC-III
-	  processors.
+	  fly.  Currently there are only sparc64 drivers for UltraSPARC-III
+	  and UltraSPARC-IIe processors.
 
 	  For details, take a look at linux/Documentation/cpufreq. 
 
@@ -164,6 +164,16 @@
 
 	  For details, take a look at linux/Documentation/cpufreq. 
 
+	  If in doubt, say N.
+
+config US2E_FREQ
+	tristate "UltraSPARC-IIe CPU Frequency driver"
+	depends on CPU_FREQ_TABLE
+	help
+	  This adds the CPUFreq driver for UltraSPARC-IIe processors.
+
+	  For details, take a look at linux/Documentation/cpufreq. 
+
 	  If in doubt, say N.
 
 source "drivers/cpufreq/Kconfig"
diff -urN linux-2.5.66-bk2/arch/sparc64/Makefile linux-2.5.66-bk3/arch/sparc64/Makefile
--- linux-2.5.66-bk2/arch/sparc64/Makefile	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/arch/sparc64/Makefile	Mon Mar 31 12:48:53 2003
@@ -71,10 +71,13 @@
 # FIXME: is drivers- right?
 drivers-$(CONFIG_OPROFILE)	+= arch/sparc64/oprofile/
 
-makeboot = $(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1)
+boot := arch/sparc64/boot
 
 image tftpboot.img vmlinux.aout: vmlinux
-	$(call makeboot,arch/sparc64/boot/$@)
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+archclean:
+	$(Q)$(MAKE) $(clean)=$(boot)
 
 define archhelp
   echo  '* vmlinux       - Standard sparc64 kernel'
diff -urN linux-2.5.66-bk2/arch/sparc64/boot/Makefile linux-2.5.66-bk3/arch/sparc64/boot/Makefile
--- linux-2.5.66-bk2/arch/sparc64/boot/Makefile	Mon Mar 24 13:59:53 2003
+++ linux-2.5.66-bk3/arch/sparc64/boot/Makefile	Mon Mar 31 12:48:53 2003
@@ -8,7 +8,7 @@
 ELFTOAOUT	:= elftoaout
 
 host-progs	:= piggyback
-targets		:= tftpboot.img vmlinux.aout
+targets		:= image tftpboot.img vmlinux.aout
 
 quiet_cmd_elftoaout = ELT2AOUT $@
       cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/Makefile linux-2.5.66-bk3/arch/sparc64/kernel/Makefile
--- linux-2.5.66-bk2/arch/sparc64/kernel/Makefile	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/Makefile	Mon Mar 31 12:48:53 2003
@@ -21,6 +21,7 @@
 obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
+obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
 
 ifdef CONFIG_SUNOS_EMUL
   obj-y += sys_sunos32.o sunos_ioctl32.o
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/binfmt_elf32.c linux-2.5.66-bk3/arch/sparc64/kernel/binfmt_elf32.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/binfmt_elf32.c	Mon Mar 24 14:01:23 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/binfmt_elf32.c	Mon Mar 31 12:48:53 2003
@@ -152,7 +152,6 @@
 #ifdef CONFIG_BINFMT_ELF32_MODULE
 #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
 #endif
-#define ELF_FLAGS_INIT	set_thread_flag(TIF_32BIT)
 
 MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
 MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/devices.c linux-2.5.66-bk3/arch/sparc64/kernel/devices.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/devices.c	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/devices.c	Mon Mar 31 12:48:53 2003
@@ -17,6 +17,7 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 #include <asm/spitfire.h>
+#include <asm/timer.h>
 
 /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
  * operations in asm/ns87303.h
@@ -88,7 +89,6 @@
 
 #ifndef CONFIG_SMP
 	{
-		extern unsigned long up_clock_tick;
 		up_clock_tick = prom_getintdefault(prom_node_cpu,
 						   "clock-frequency",
 						   0);
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/setup.c linux-2.5.66-bk3/arch/sparc64/kernel/setup.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/setup.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/setup.c	Mon Mar 31 12:48:53 2003
@@ -44,6 +44,7 @@
 #include <asm/starfire.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
+#include <asm/timer.h>
 
 #ifdef CONFIG_IP_PNP
 #include <net/ipconfig.h>
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/sparc64_ksyms.c linux-2.5.66-bk3/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 24 14:01:18 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 31 12:48:53 2003
@@ -55,6 +55,7 @@
 #endif
 #include <asm/a.out.h>
 #include <asm/ns87303.h>
+#include <asm/timer.h>
 
 struct poll {
 	int fd;
@@ -159,11 +160,7 @@
 EXPORT_SYMBOL(smp_call_function);
 #endif /* CONFIG_SMP */
 
-/* Uniprocessor clock frequency */
-#ifndef CONFIG_SMP
-extern unsigned long up_clock_tick;
-EXPORT_SYMBOL(up_clock_tick);
-#endif
+EXPORT_SYMBOL(sparc64_get_clock_tick);
 
 /* semaphores */
 EXPORT_SYMBOL(down);
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/time.c linux-2.5.66-bk3/arch/sparc64/kernel/time.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/time.c	Mon Mar 24 14:00:38 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/time.c	Mon Mar 31 12:48:53 2003
@@ -26,6 +26,8 @@
 #include <linux/profile.h>
 #include <linux/bcd.h>
 #include <linux/jiffies.h>
+#include <linux/cpufreq.h>
+#include <linux/percpu.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -988,6 +990,73 @@
 	return clock;
 }
 
+struct freq_table {
+	unsigned long udelay_val_ref;
+	unsigned long clock_tick_ref;
+	unsigned int ref_freq;
+};
+static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 };
+
+unsigned long sparc64_get_clock_tick(unsigned int cpu)
+{
+	struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
+
+	if (ft->clock_tick_ref)
+		return ft->clock_tick_ref;
+#ifdef CONFIG_SMP
+	return cpu_data[cpu].clock_tick;
+#else
+	return up_clock_tick;
+#endif
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+				    void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	unsigned int cpu = freq->cpu;
+	struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
+
+#ifdef CONFIG_SMP
+	if (!ft->ref_freq) {
+		ft->ref_freq = freq->old;
+		ft->udelay_val_ref = cpu_data[cpu].udelay_val;
+		ft->clock_tick_ref = cpu_data[cpu].clock_tick;
+	}
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
+		cpu_data[cpu].udelay_val =
+			cpufreq_scale(ft->udelay_val_ref,
+				      ft->ref_freq,
+				      freq->new);
+		cpu_data[cpu].clock_tick =
+			cpufreq_scale(ft->clock_tick_ref,
+				      ft->ref_freq,
+				      freq->new);
+	}
+#else
+	/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
+	 * loops_per_jiffy.
+	 */
+	if (!ft->ref_freq) {
+		ft->ref_freq = freq->old;
+		ft->clock_tick_ref = up_clock_tick;
+	}
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
+		up_clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new);
+#endif
+
+	return 0;
+}
+
+static struct notifier_block sparc64_cpufreq_notifier_block = {
+	.notifier_call	= sparc64_cpufreq_notifier
+};
+#endif
+
 /* The quotient formula is taken from the IA64 port. */
 void __init time_init(void)
 {
@@ -996,6 +1065,11 @@
 	timer_ticks_per_usec_quotient =
 		(((1000000UL << 30) +
 		  (clock / 2)) / clock);
+
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_register_notifier(&sparc64_cpufreq_notifier_block,
+				  CPUFREQ_TRANSITION_NOTIFIER);
+#endif
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/us2e_cpufreq.c linux-2.5.66-bk3/arch/sparc64/kernel/us2e_cpufreq.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/us2e_cpufreq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/arch/sparc64/kernel/us2e_cpufreq.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,398 @@
+/* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * Many thanks to Dominik Brodowski for fixing up the cpufreq
+ * infrastructure in order to make this driver easier to implement.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <linux/threads.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/asi.h>
+#include <asm/timer.h>
+
+static struct cpufreq_driver *cpufreq_us2e_driver;
+
+struct us2e_freq_percpu_info {
+	struct cpufreq_frequency_table table[6];
+};
+
+/* Indexed by cpu number. */
+static struct us2e_freq_percpu_info *us2e_freq_table;
+
+#define HBIRD_MEM_CNTL0_ADDR	0x1fe0000f010UL
+#define HBIRD_ESTAR_MODE_ADDR	0x1fe0000f080UL
+
+/* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8.  These are controlled
+ * in the ESTAR mode control register.
+ */
+#define ESTAR_MODE_DIV_1	0x0000000000000000UL
+#define ESTAR_MODE_DIV_2	0x0000000000000001UL
+#define ESTAR_MODE_DIV_4	0x0000000000000003UL
+#define ESTAR_MODE_DIV_6	0x0000000000000002UL
+#define ESTAR_MODE_DIV_8	0x0000000000000004UL
+#define ESTAR_MODE_DIV_MASK	0x0000000000000007UL
+
+#define MCTRL0_SREFRESH_ENAB	0x0000000000010000UL
+#define MCTRL0_REFR_COUNT_MASK	0x0000000000007f00UL
+#define MCTRL0_REFR_COUNT_SHIFT	8
+#define MCTRL0_REFR_INTERVAL	7800
+#define MCTRL0_REFR_CLKS_P_CNT	64
+
+static unsigned long read_hbreg(unsigned long addr)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=&r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+	return ret;
+}
+
+static void write_hbreg(unsigned long addr, unsigned long val)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "membar	#Sync"
+			     : /* no outputs */
+			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)
+			     : "memory");
+	if (addr == HBIRD_ESTAR_MODE_ADDR) {
+		/* Need to wait 16 clock cycles for the PLL to lock.  */
+		udelay(1);
+	}
+}
+
+static void self_refresh_ctl(int enable)
+{
+	unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
+
+	if (enable)
+		mctrl |= MCTRL0_SREFRESH_ENAB;
+	else
+		mctrl &= ~MCTRL0_SREFRESH_ENAB;
+	write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
+	(void) read_hbreg(HBIRD_MEM_CNTL0_ADDR);
+}
+
+static void frob_mem_refresh(int cpu_slowing_down,
+			     unsigned long clock_tick,
+			     unsigned long old_divisor, unsigned long divisor)
+{
+	unsigned long old_refr_count, refr_count, mctrl;
+
+
+	refr_count  = (clock_tick * MCTRL0_REFR_INTERVAL);
+	refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL);
+
+	mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
+	old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK)
+		>> MCTRL0_REFR_COUNT_SHIFT;
+
+	mctrl &= ~MCTRL0_REFR_COUNT_MASK;
+	mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT;
+	write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
+	mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
+
+	if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) {
+		unsigned long usecs;
+
+		/* We have to wait for both refresh counts (old
+		 * and new) to go to zero.
+		 */
+		usecs = (MCTRL0_REFR_CLKS_P_CNT *
+			 (refr_count + old_refr_count) *
+			 1000000UL *
+			 old_divisor) / clock_tick;
+		udelay(usecs + 1UL);
+	}
+}
+
+static void us2e_transition(unsigned long estar, unsigned long new_bits,
+			    unsigned long clock_tick,
+			    unsigned long old_divisor, unsigned long divisor)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	estar &= ~ESTAR_MODE_DIV_MASK;
+
+	/* This is based upon the state transition diagram in the IIe manual.  */
+	if (old_divisor == 2 && divisor == 1) {
+		self_refresh_ctl(0);
+		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
+		frob_mem_refresh(0, clock_tick, old_divisor, divisor);
+	} else if (old_divisor == 1 && divisor == 2) {
+		frob_mem_refresh(1, clock_tick, old_divisor, divisor);
+		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
+		self_refresh_ctl(1);
+	} else if (old_divisor == 1 && divisor > 2) {
+		us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
+				1, 2);
+		us2e_transition(estar, new_bits, clock_tick,
+				2, divisor);
+	} else if (old_divisor > 2 && divisor == 1) {
+		us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
+				old_divisor, 2);
+		us2e_transition(estar, new_bits, clock_tick,
+				2, divisor);
+	} else if (old_divisor < divisor) {
+		frob_mem_refresh(0, clock_tick, old_divisor, divisor);
+		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
+	} else if (old_divisor > divisor) {
+		write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
+		frob_mem_refresh(1, clock_tick, old_divisor, divisor);
+	} else {
+		BUG();
+	}
+
+	local_irq_restore(flags);
+}
+
+static unsigned long index_to_estar_mode(unsigned int index)
+{
+	switch (index) {
+	case 0:
+		return ESTAR_MODE_DIV_1;
+
+	case 1:
+		return ESTAR_MODE_DIV_2;
+
+	case 2:
+		return ESTAR_MODE_DIV_4;
+
+	case 3:
+		return ESTAR_MODE_DIV_6;
+
+	case 4:
+		return ESTAR_MODE_DIV_8;
+
+	default:
+		BUG();
+	};
+}
+
+static unsigned long index_to_divisor(unsigned int index)
+{
+	switch (index) {
+	case 0:
+		return 1;
+
+	case 1:
+		return 2;
+
+	case 2:
+		return 4;
+
+	case 3:
+		return 6;
+
+	case 4:
+		return 8;
+
+	default:
+		BUG();
+	};
+}
+
+static unsigned long estar_to_divisor(unsigned long estar)
+{
+	unsigned long ret;
+
+	switch (estar & ESTAR_MODE_DIV_MASK) {
+	case ESTAR_MODE_DIV_1:
+		ret = 1;
+		break;
+	case ESTAR_MODE_DIV_2:
+		ret = 2;
+		break;
+	case ESTAR_MODE_DIV_4:
+		ret = 4;
+		break;
+	case ESTAR_MODE_DIV_6:
+		ret = 6;
+		break;
+	case ESTAR_MODE_DIV_8:
+		ret = 8;
+		break;
+	default:
+		BUG();
+	};
+
+	return ret;
+}
+
+static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+	unsigned long new_bits, new_freq, cpus_allowed;
+	unsigned long clock_tick, divisor, old_divisor, estar;
+	struct cpufreq_freqs freqs;
+
+	if (!cpu_online(cpu))
+		return;
+
+	cpus_allowed = current->cpus_allowed;
+	set_cpus_allowed(current, (1UL << cpu));
+
+	new_freq = clock_tick = sparc64_get_clock_tick(cpu);
+	new_bits = index_to_estar_mode(index);
+	divisor = index_to_divisor(index);
+	new_freq /= divisor;
+
+	estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
+
+	old_divisor = estar_to_divisor(estar);
+
+	freqs.old = clock_tick / old_divisor;
+	freqs.new = new_freq;
+	freqs.cpu = cpu;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	us2e_transition(estar, new_bits, clock_tick, old_divisor, divisor);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	set_cpus_allowed(current, cpus_allowed);
+}
+
+static int us2e_freq_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
+{
+	unsigned int new_index = 0;
+
+	if (cpufreq_frequency_table_target(policy,
+					      &us2e_freq_table[policy->cpu].table[0],
+					      target_freq,
+					      relation,
+					      &new_index))
+		return -EINVAL;
+
+	us2e_set_cpu_divider_index(policy->cpu, new_index);
+
+	return 0;
+}
+
+static int us2e_freq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy,
+					      &us2e_freq_table[policy->cpu].table[0]);
+}
+
+static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned int cpu = policy->cpu;
+	unsigned long clock_tick = sparc64_get_clock_tick(cpu);
+	struct cpufreq_frequency_table *table =
+		&us2e_freq_table[cpu].table[0];
+
+	table[0].index = 0;
+	table[0].frequency = clock_tick / 1;
+	table[1].index = 1;
+	table[1].frequency = clock_tick / 2;
+	table[2].index = 2;
+	table[2].frequency = clock_tick / 4;
+	table[2].index = 3;
+	table[2].frequency = clock_tick / 6;
+	table[2].index = 4;
+	table[2].frequency = clock_tick / 8;
+	table[2].index = 5;
+	table[3].frequency = CPUFREQ_TABLE_END;
+
+	policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	policy->cpuinfo.transition_latency = 0;
+	policy->cur = clock_tick;
+
+	return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static int __exit us2e_freq_cpu_exit(struct cpufreq_policy *policy)
+{
+	if (cpufreq_us2e_driver)
+		us2e_set_cpu_divider_index(policy->cpu, 0);
+
+	return 0;
+}
+
+static int __init us2e_freq_init(void)
+{
+	unsigned long manuf, impl, ver;
+	int ret;
+
+	__asm__("rdpr %%ver, %0" : "=r" (ver));
+	manuf = ((ver >> 48) & 0xffff);
+	impl  = ((ver >> 32) & 0xffff);
+
+	if (manuf == 0x17 && impl == 0x13) {
+		struct cpufreq_driver *driver;
+
+		ret = -ENOMEM;
+		driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
+		if (!driver)
+			goto err_out;
+		memset(driver, 0, sizeof(*driver));
+
+		us2e_freq_table = kmalloc(
+			(NR_CPUS * sizeof(struct us2e_freq_percpu_info)),
+			GFP_KERNEL);
+		if (!us2e_freq_table)
+			goto err_out;
+
+		memset(us2e_freq_table, 0,
+		       (NR_CPUS * sizeof(struct us2e_freq_percpu_info)));
+
+		driver->verify = us2e_freq_verify;
+		driver->target = us2e_freq_target;
+		driver->init = us2e_freq_cpu_init;
+		driver->exit = us2e_freq_cpu_exit;
+		driver->owner = THIS_MODULE,
+		strcpy(driver->name, "UltraSPARC-IIe");
+
+		cpufreq_us2e_driver = driver;
+		ret = cpufreq_register_driver(driver);
+		if (ret)
+			goto err_out;
+
+		return 0;
+
+err_out:
+		if (driver) {
+			kfree(driver);
+			cpufreq_us2e_driver = NULL;
+		}
+		if (us2e_freq_table) {
+			kfree(us2e_freq_table);
+			us2e_freq_table = NULL;
+		}
+		return ret;
+	}
+
+	return -ENODEV;
+}
+
+static void __exit us2e_freq_exit(void)
+{
+	if (cpufreq_us2e_driver) {
+		cpufreq_unregister_driver(cpufreq_us2e_driver);
+
+		kfree(cpufreq_us2e_driver);
+		cpufreq_us2e_driver = NULL;
+		kfree(us2e_freq_table);
+		us2e_freq_table = NULL;
+	}
+}
+
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
+MODULE_LICENSE("GPL");
+
+module_init(us2e_freq_init);
+module_exit(us2e_freq_exit);
diff -urN linux-2.5.66-bk2/arch/sparc64/kernel/us3_cpufreq.c linux-2.5.66-bk3/arch/sparc64/kernel/us3_cpufreq.c
--- linux-2.5.66-bk2/arch/sparc64/kernel/us3_cpufreq.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/arch/sparc64/kernel/us3_cpufreq.c	Mon Mar 31 12:48:53 2003
@@ -16,14 +16,12 @@
 #include <linux/init.h>
 
 #include <asm/head.h>
+#include <asm/timer.h>
 
 static struct cpufreq_driver *cpufreq_us3_driver;
 
 struct us3_freq_percpu_info {
 	struct cpufreq_frequency_table table[4];
-	unsigned long udelay_val_ref;
-	unsigned long clock_tick_ref;
-	unsigned int ref_freq;
 };
 
 /* Indexed by cpu number. */
@@ -56,71 +54,9 @@
 			     : "memory");
 }
 
-#ifndef CONFIG_SMP
-extern unsigned long up_clock_tick;
-unsigned long clock_tick_ref;
-unsigned int ref_freq;
-#endif
-
-static __inline__ unsigned long get_clock_tick(unsigned int cpu)
-{
-#ifdef CONFIG_SMP
-	if (us3_freq_table[cpu].clock_tick_ref)
-		return us3_freq_table[cpu].clock_tick_ref;
-	return cpu_data[cpu].clock_tick;
-#else
-	if (clock_tick_ref)
-		return clock_tick_ref;
-	return up_clock_tick;
-#endif
-}
-
-static int us3_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-				void *data)
-{
-	struct cpufreq_freqs *freq = data;
-#ifdef CONFIG_SMP
-	unsigned int cpu = freq->cpu;
-
-	if (!us3_freq_table[cpu].ref_freq) {
-		us3_freq_table[cpu].ref_freq = freq->old;
-		us3_freq_table[cpu].udelay_val_ref = cpu_data[cpu].udelay_val;
-		us3_freq_table[cpu].clock_tick_ref = cpu_data[cpu].clock_tick;
-	}
-	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
-		cpu_data[cpu].udelay_val =
-			cpufreq_scale(us3_freq_table[cpu].udelay_val_ref,
-				      us3_freq_table[cpu].ref_freq,
-				      freq->new);
-		cpu_data[cpu].clock_tick =
-			cpufreq_scale(us3_freq_table[cpu].clock_tick_ref,
-				      us3_freq_table[cpu].ref_freq,
-				      freq->new);
-	}
-#else
-	/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
-	 * loops_per_jiffy.
-	 */
-	if (!ref_freq) {
-		ref_freq = freq->old;
-		clock_tick_ref = up_clock_tick;
-	}
-	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
-		up_clock_tick = cpufreq_scale(clock_tick_ref, ref_freq, freq->new);
-#endif
-
-	return 0;
-}
-
-static struct notifier_block us3_cpufreq_notifier_block = {
-	.notifier_call	= us3_cpufreq_notifier
-};
-
 static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
 {
-	unsigned long clock_tick = get_clock_tick(cpu);
+	unsigned long clock_tick = sparc64_get_clock_tick(cpu);
 	unsigned long ret;
 
 	switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
@@ -151,7 +87,7 @@
 	cpus_allowed = current->cpus_allowed;
 	set_cpus_allowed(current, (1UL << cpu));
 
-	new_freq = get_clock_tick(cpu);
+	new_freq = sparc64_get_clock_tick(cpu);
 	switch (index) {
 	case 0:
 		new_bits = SAFARI_CFG_DIV_1;
@@ -186,17 +122,17 @@
 	set_cpus_allowed(current, cpus_allowed);
 }
 
-static int us3freq_target(struct cpufreq_policy *policy,
+static int us3_freq_target(struct cpufreq_policy *policy,
 			  unsigned int target_freq,
 			  unsigned int relation)
 {
 	unsigned int new_index = 0;
 
 	if (cpufreq_frequency_table_target(policy,
-					      &us3_freq_table[policy->cpu].table[0],
-					      target_freq,
-					      relation,
-					      &new_index))
+					   &us3_freq_table[policy->cpu].table[0],
+					   target_freq,
+					   relation,
+					   &new_index))
 		return -EINVAL;
 
 	us3_set_cpu_divider_index(policy->cpu, new_index);
@@ -204,16 +140,16 @@
 	return 0;
 }
 
-static int us3freq_verify(struct cpufreq_policy *policy)
+static int us3_freq_verify(struct cpufreq_policy *policy)
 {
 	return cpufreq_frequency_table_verify(policy,
 					      &us3_freq_table[policy->cpu].table[0]);
 }
 
-static int __init us3freq_cpu_init(struct cpufreq_policy *policy)
+static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
 {
 	unsigned int cpu = policy->cpu;
-	unsigned long clock_tick = get_clock_tick(cpu);
+	unsigned long clock_tick = sparc64_get_clock_tick(cpu);
 	struct cpufreq_frequency_table *table =
 		&us3_freq_table[cpu].table[0];
 
@@ -233,7 +169,7 @@
 	return cpufreq_frequency_table_cpuinfo(policy, table);
 }
 
-static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy)
+static int __exit us3_freq_cpu_exit(struct cpufreq_policy *policy)
 {
 	if (cpufreq_us3_driver)
 		us3_set_cpu_divider_index(policy->cpu, 0);
@@ -241,7 +177,7 @@
 	return 0;
 }
 
-static int __init us3freq_init(void)
+static int __init us3_freq_init(void)
 {
 	unsigned long manuf, impl, ver;
 	int ret;
@@ -254,9 +190,6 @@
 	    (impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) {
 		struct cpufreq_driver *driver;
 
-		cpufreq_register_notifier(&us3_cpufreq_notifier_block,
-					  CPUFREQ_TRANSITION_NOTIFIER);
-
 		ret = -ENOMEM;
 		driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
 		if (!driver)
@@ -272,10 +205,10 @@
 		memset(us3_freq_table, 0,
 		       (NR_CPUS * sizeof(struct us3_freq_percpu_info)));
 
-		driver->verify = us3freq_verify;
-		driver->target = us3freq_target;
-		driver->init = us3freq_cpu_init;
-		driver->exit = us3freq_cpu_exit;
+		driver->verify = us3_freq_verify;
+		driver->target = us3_freq_target;
+		driver->init = us3_freq_cpu_init;
+		driver->exit = us3_freq_cpu_exit;
 		driver->owner = THIS_MODULE,
 		strcpy(driver->name, "UltraSPARC-III");
 
@@ -295,20 +228,16 @@
 			kfree(us3_freq_table);
 			us3_freq_table = NULL;
 		}
-		cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
-					    CPUFREQ_TRANSITION_NOTIFIER);
 		return ret;
 	}
 
 	return -ENODEV;
 }
 
-static void __exit us3freq_exit(void)
+static void __exit us3_freq_exit(void)
 {
 	if (cpufreq_us3_driver) {
 		cpufreq_unregister_driver(cpufreq_us3_driver);
-		cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
-					    CPUFREQ_TRANSITION_NOTIFIER);
 
 		kfree(cpufreq_us3_driver);
 		cpufreq_us3_driver = NULL;
@@ -321,5 +250,5 @@
 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
 MODULE_LICENSE("GPL");
 
-module_init(us3freq_init);
-module_exit(us3freq_exit);
+module_init(us3_freq_init);
+module_exit(us3_freq_exit);
diff -urN linux-2.5.66-bk2/arch/sparc64/lib/Makefile linux-2.5.66-bk3/arch/sparc64/lib/Makefile
--- linux-2.5.66-bk2/arch/sparc64/lib/Makefile	Mon Mar 24 13:59:56 2003
+++ linux-2.5.66-bk3/arch/sparc64/lib/Makefile	Mon Mar 31 12:48:53 2003
@@ -11,4 +11,4 @@
 	 VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
 	 VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \
 	 dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \
-	 U3copy_in_user.o mcount.o ipcsum.o
+	 U3copy_in_user.o mcount.o ipcsum.o rwsem.o
diff -urN linux-2.5.66-bk2/arch/sparc64/lib/rwsem.c linux-2.5.66-bk3/arch/sparc64/lib/rwsem.c
--- linux-2.5.66-bk2/arch/sparc64/lib/rwsem.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/arch/sparc64/lib/rwsem.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,238 @@
+/* rwsem.c: Don't inline expand these suckers all over the place.
+ *
+ * Written by David S. Miller (davem@redhat.com), 2001.
+ * Derived from asm-i386/rwsem.h
+ */
+
+#include <linux/kernel.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+
+extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
+extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *));
+
+void __down_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __down_read\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"add		%%g5, 1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" add		%%g7, 1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g1, %%l1\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l1, %%g1\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __down_read"
+		: : "r" (sem), "i" (rwsem_down_read_failed)
+		: "g5", "g7", "memory", "cc");
+}
+EXPORT_SYMBOL(__down_read);
+
+int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"! beginning __down_read_trylock\n"
+		"1:\tlduw	[%1], %%g5\n\t"
+		"add		%%g5, 1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 2f\n\t"
+		" mov		0, %0\n\t"
+		"cas		[%1], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" mov		1, %0\n\t"
+		"membar		#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		"! ending __down_read_trylock"
+		: "=&r" (result)
+                : "r" (sem)
+		: "g5", "g7", "memory", "cc");
+
+	return result;
+}
+EXPORT_SYMBOL(__down_read_trylock);
+
+void __down_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __down_write\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"add		%%g5, %%g1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" cmp		%%g7, 0\n\t"
+		"bne,pn		%%icc, 3f\n\t"
+		" membar	#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __down_write"
+		: : "r" (sem), "i" (rwsem_down_write_failed),
+		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+EXPORT_SYMBOL(__down_write);
+
+int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"! beginning __down_write_trylock\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%1], %%g5\n\t"
+		"cmp		%%g5, 0\n\t"
+		"bne,pn		%%icc, 2f\n\t"
+		" mov		0, %0\n\t"
+		"add		%%g5, %%g1, %%g7\n\t"
+		"cas		[%1], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" mov		1, %0\n\t"
+		"membar		#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		"! ending __down_write_trylock"
+		: "=&r" (result)
+		: "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+
+	return result;
+}
+EXPORT_SYMBOL(__down_write_trylock);
+
+void __up_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __up_read\n\t"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"sub		%%g5, 1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tsethi	%%hi(%2), %%g1\n\t"
+		"sub		%%g7, 1, %%g7\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n\t"
+		"andcc		%%g7, %%g1, %%g0\n\t"
+		"bne,pn		%%icc, 2b\n\t"
+		" mov		%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __up_read"
+		: : "r" (sem), "i" (rwsem_wake),
+		    "i" (RWSEM_ACTIVE_MASK)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+EXPORT_SYMBOL(__up_read);
+
+void __up_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __up_write\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"sub		%%g5, %%g1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" sub		%%g7, %%g1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		".subsection 2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __up_write"
+		: : "r" (sem), "i" (rwsem_wake),
+		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+EXPORT_SYMBOL(__up_write);
+
+void __downgrade_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __downgrade_write\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"sub		%%g5, %%g1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" sub		%%g7, %%g1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		".subsection 2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __up_write"
+		: : "r" (sem), "i" (rwsem_downgrade_wake),
+		    "i" (RWSEM_WAITING_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+EXPORT_SYMBOL(__downgrade_write);
diff -urN linux-2.5.66-bk2/drivers/atm/iphase.c linux-2.5.66-bk3/drivers/atm/iphase.c
--- linux-2.5.66-bk2/drivers/atm/iphase.c	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/drivers/atm/iphase.c	Mon Mar 31 12:48:53 2003
@@ -2893,7 +2893,7 @@
         struct tx_buf_desc *buf_desc_ptr;
         int desc;
         int comp_code;
-        int total_len, pad, last;
+        int total_len;
         struct cpcs_trailer *trailer;
         struct ia_vcc *iavcc;
 
@@ -2975,9 +2975,7 @@
 	/* Figure out the exact length of the packet and padding required to 
            make it  aligned on a 48 byte boundary.  */
 	total_len = skb->len + sizeof(struct cpcs_trailer);  
-	last = total_len - (total_len/48)*48;  
-	pad = 48 - last;  
-	total_len = pad + total_len;  
+	total_len = ((total_len + 47) / 48) * 48;
 	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);)  
  
 	/* Put the packet in a tx buffer */   
diff -urN linux-2.5.66-bk2/drivers/char/pcmcia/synclink_cs.c linux-2.5.66-bk3/drivers/char/pcmcia/synclink_cs.c
--- linux-2.5.66-bk2/drivers/char/pcmcia/synclink_cs.c	Mon Mar 24 14:00:16 2003
+++ linux-2.5.66-bk3/drivers/char/pcmcia/synclink_cs.c	Mon Mar 31 12:48:53 2003
@@ -76,7 +76,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
 #define CONFIG_SYNCLINK_SYNCPPP 1
@@ -241,7 +240,6 @@
 	dev_link_t	      link;
 	dev_node_t	      node;
 	int		      stop;
-	struct bus_operations *bus;
 
 	/* SPPP/Cisco HDLC device parts */
 	int netcount;
@@ -826,7 +824,6 @@
 	    break;
     case CS_EVENT_CARD_INSERTION:
 	    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	    info->bus = args->bus;
 	    mgslpc_config(link);
 	    break;
     case CS_EVENT_PM_SUSPEND:
diff -urN linux-2.5.66-bk2/drivers/isdn/hisax/elsa_cs.c linux-2.5.66-bk3/drivers/isdn/hisax/elsa_cs.c
--- linux-2.5.66-bk2/drivers/isdn/hisax/elsa_cs.c	Mon Mar 24 14:00:35 2003
+++ linux-2.5.66-bk3/drivers/isdn/hisax/elsa_cs.c	Mon Mar 31 12:48:53 2003
@@ -53,7 +53,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
 
 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
 MODULE_AUTHOR("Klaus Lichtenwalder");
@@ -163,17 +162,12 @@
    "stopped" due to a power management event, or card ejection.  The
    device IO routines can use a flag like this to throttle IO to a
    card that is not ready to accept it.
-
-   The bus_operations pointer is used on platforms for which we need
-   to use special socket-specific versions of normal IO primitives
-   (inb, outb, readb, writeb, etc) for card IO.
 */
 
 typedef struct local_info_t {
     dev_link_t          link;
     dev_node_t          node;
     int                 busy;
-  struct bus_operations *bus;
 } local_info_t;
 
 /*====================================================================*/
@@ -522,7 +516,6 @@
         break;
     case CS_EVENT_CARD_INSERTION:
         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-        dev->bus = args->bus;
         elsa_cs_config(link);
         break;
     case CS_EVENT_PM_SUSPEND:
diff -urN linux-2.5.66-bk2/drivers/isdn/hisax/sedlbauer_cs.c linux-2.5.66-bk3/drivers/isdn/hisax/sedlbauer_cs.c
--- linux-2.5.66-bk2/drivers/isdn/hisax/sedlbauer_cs.c	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk3/drivers/isdn/hisax/sedlbauer_cs.c	Mon Mar 31 12:48:53 2003
@@ -53,7 +53,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
 
 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
 MODULE_AUTHOR("Marcus Niemann");
@@ -171,17 +170,12 @@
    "stopped" due to a power management event, or card ejection.  The
    device IO routines can use a flag like this to throttle IO to a
    card that is not ready to accept it.
-
-   The bus_operations pointer is used on platforms for which we need
-   to use special socket-specific versions of normal IO primitives
-   (inb, outb, readb, writeb, etc) for card IO.
 */
    
 typedef struct local_info_t {
     dev_link_t		link;
     dev_node_t		node;
     int			stop;
-    struct bus_operations *bus;
 } local_info_t;
 
 /*====================================================================*/
@@ -620,7 +614,6 @@
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	dev->bus = args->bus;
 	sedlbauer_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
diff -urN linux-2.5.66-bk2/drivers/mtd/maps/epxa10db-flash.c linux-2.5.66-bk3/drivers/mtd/maps/epxa10db-flash.c
--- linux-2.5.66-bk2/drivers/mtd/maps/epxa10db-flash.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/drivers/mtd/maps/epxa10db-flash.c	Mon Mar 31 12:48:53 2003
@@ -199,12 +199,12 @@
 
 	printk("Using default partitions for %s\n",BOARD_NAME);
 	npartitions=1;
-	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
-	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
+	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL);
 	if (!parts) {
 		ret = -ENOMEM;
 		goto out;
 	}
+	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
 	i=0;
 	names = (char *)&parts[npartitions];	
 	parts[i].name = names;
@@ -218,10 +218,11 @@
 	parts[i].size = FLASH_SIZE-0x00180000;
 	parts[i].offset = 0x00180000;
 #endif
+	ret = npartitions;
 
  out:
 	*pparts = parts;
-	return npartitions;
+	return ret;
 }
 
 
diff -urN linux-2.5.66-bk2/drivers/pci/Makefile linux-2.5.66-bk3/drivers/pci/Makefile
--- linux-2.5.66-bk2/drivers/pci/Makefile	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk3/drivers/pci/Makefile	Mon Mar 31 12:48:53 2003
@@ -29,6 +29,9 @@
 obj-y += setup-bus.o
 endif
 
+# Hotplug (eg, cardbus) now requires setup-bus
+obj-$(CONFIG_HOTPLUG) += setup-bus.o
+
 ifndef CONFIG_X86
 obj-y += syscall.o
 endif
diff -urN linux-2.5.66-bk2/drivers/pcmcia/Kconfig linux-2.5.66-bk3/drivers/pcmcia/Kconfig
--- linux-2.5.66-bk2/drivers/pcmcia/Kconfig	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/Kconfig	Mon Mar 31 12:48:53 2003
@@ -87,5 +87,9 @@
 	tristate "SA1111 support"
 	depends on PCMCIA_SA1100 && SA1111
 
+config PCMCIA_PROBE
+	bool
+	default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X
+
 endmenu
 
diff -urN linux-2.5.66-bk2/drivers/pcmcia/Makefile linux-2.5.66-bk3/drivers/pcmcia/Makefile
--- linux-2.5.66-bk2/drivers/pcmcia/Makefile	Mon Mar 24 14:01:15 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/Makefile	Mon Mar 31 12:48:53 2003
@@ -2,46 +2,43 @@
 # Makefile for the kernel pcmcia subsystem (c/o David Hinds)
 #
 
-obj-$(CONFIG_PCMCIA)			+= pcmcia_core.o ds.o
+obj-$(CONFIG_PCMCIA)				+= pcmcia_core.o ds.o
 ifeq ($(CONFIG_CARDBUS),y)
-  obj-$(CONFIG_PCMCIA) 			+= yenta_socket.o
+  obj-$(CONFIG_PCMCIA) 				+= yenta_socket.o
 endif
 
-obj-$(CONFIG_I82365)			+= i82365.o
-obj-$(CONFIG_I82092)			+= i82092.o
-obj-$(CONFIG_TCIC)			+= tcic.o
-obj-$(CONFIG_HD64465_PCMCIA)		+= hd64465_ss.o
-obj-$(CONFIG_PCMCIA_SA1100)		+= sa1100_cs.o
-obj-$(CONFIG_PCMCIA_SA1111)		+= sa1111_cs.o
-
-yenta_socket-objs				:= pci_socket.o yenta.o
-
-pcmcia_core-objs-y				:= cistpl.o rsrc_mgr.o bulkmem.o cs.o
-pcmcia_core-objs-$(CONFIG_CARDBUS)		+= cardbus.o
-pcmcia_core-objs				:= $(pcmcia_core-objs-y)
-
-sa1111_cs-objs-y				:= sa1111_generic.o
-sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o
-sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o
-sa1111_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o
-sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
-sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o
-sa1111_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
-sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)	+= sa1100_system3.o
-sa1111_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
-sa1111_cs-objs					:= $(sa1111_cs-objs-y)
-
-sa1100_cs-objs-y				:= sa1100_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
-sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
-sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
-sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
-sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)	+= sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
-sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
-sa1100_cs-objs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
-sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) 	+= sa1100_trizeps.o
-sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
-sa1100_cs-objs					:= $(sa1100_cs-objs-y)
+obj-$(CONFIG_I82365)				+= i82365.o
+obj-$(CONFIG_I82092)				+= i82092.o
+obj-$(CONFIG_TCIC)				+= tcic.o
+obj-$(CONFIG_HD64465_PCMCIA)			+= hd64465_ss.o
+obj-$(CONFIG_PCMCIA_SA1100)			+= sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)			+= sa1111_cs.o
+
+yenta_socket-y					+= pci_socket.o yenta.o
+
+pcmcia_core-y					+= cistpl.o rsrc_mgr.o bulkmem.o cs.o
+pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
+
+sa1111_cs-y					+= sa1111_generic.o
+sa1111_cs-$(CONFIG_SA1100_ADSBITSY)		+= sa1100_adsbitsy.o
+sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
+sa1111_cs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o
+sa1111_cs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
+sa1111_cs-$(CONFIG_SA1100_JORNADA720)		+= sa1100_jornada720.o
+sa1111_cs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
+sa1111_cs-$(CONFIG_SA1100_PT_SYSTEM3)		+= sa1100_system3.o
+sa1111_cs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
+
+sa1100_cs-y					+= sa1100_generic.o
+sa1100_cs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
+sa1100_cs-$(CONFIG_SA1100_CERF)			+= sa1100_cerf.o
+sa1100_cs-$(CONFIG_SA1100_FLEXANET)		+= sa1100_flexanet.o
+sa1100_cs-$(CONFIG_SA1100_FREEBIRD)		+= sa1100_freebird.o
+sa1100_cs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
+sa1100_cs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-$(CONFIG_SA1100_PANGOLIN)		+= sa1100_pangolin.o
+sa1100_cs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
+sa1100_cs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
+sa1100_cs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
+sa1100_cs-$(CONFIG_SA1100_TRIZEPS) 		+= sa1100_trizeps.o
+sa1100_cs-$(CONFIG_SA1100_YOPY)			+= sa1100_yopy.o
diff -urN linux-2.5.66-bk2/drivers/pcmcia/cardbus.c linux-2.5.66-bk3/drivers/pcmcia/cardbus.c
--- linux-2.5.66-bk2/drivers/pcmcia/cardbus.c	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/cardbus.c	Mon Mar 31 12:48:53 2003
@@ -87,10 +87,6 @@
 #define PCDATA_CODE_TYPE	0x0014
 #define PCDATA_INDICATOR	0x0015
 
-typedef struct cb_config_t {
-	struct pci_dev *dev[8];
-} cb_config_t;
-
 /*=====================================================================
 
     Expansion ROM's have a special layout, and pointers specify an
@@ -173,11 +169,10 @@
 
 	DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len);
 
-	if (!s->cb_config)
+	dev = pci_find_slot(s->cap.cb_dev->subordinate->number, 0);
+	if (!dev)
 		goto fail;
 
-	dev = s->cb_config->dev[0];
-
 	/* Config space? */
 	if (space == 0) {
 		if (addr + len > 0x100)
@@ -219,171 +214,61 @@
     
 =====================================================================*/
 
-int cb_alloc(socket_info_t * s)
+/*
+ * Since there is only one interrupt available to CardBus
+ * devices, all devices downstream of this device must
+ * be using this IRQ.
+ */
+static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
 {
-	struct pci_bus *bus;
-	u_short vend, v, dev;
-	u_char i, hdr, fn;
-	cb_config_t *c;
-	int irq;
-
-	bus = s->cap.cb_dev->subordinate;
-
-	pci_bus_read_config_word(bus, 0, PCI_VENDOR_ID, &vend);
-	pci_bus_read_config_word(bus, 0, PCI_DEVICE_ID, &dev);
-	printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, "
-	       "device 0x%04x\n", bus->number, vend, dev);
-
-	pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr);
-	fn = 1;
-	if (hdr & 0x80) {
-		do {
-			if (pci_bus_read_config_word(bus, fn, PCI_VENDOR_ID, &v) ||
-			    !v || v == 0xffff)
-				break;
-			fn++;
-		} while (fn < 8);
-	}
-	s->functions = fn;
-
-	c = kmalloc(sizeof(struct cb_config_t), GFP_ATOMIC);
-	if (!c)
-		return CS_OUT_OF_RESOURCE;
- 	memset(c, 0, sizeof(struct cb_config_t));
-
-	for (i = 0; i < fn; i++) {
-		c->dev[i] = kmalloc(sizeof(struct pci_dev), GFP_ATOMIC);
-		if (!c->dev[i]) {
-			for (; i--; )
-				kfree(c->dev[i]);
-			kfree(c);
-			return CS_OUT_OF_RESOURCE;
-		}
-		memset(c->dev[i], 0, sizeof(struct pci_dev));
-	}
+	struct pci_dev *dev;
 
-	irq = s->cap.pci_irq;
-	for (i = 0; i < fn; i++) {
-		struct pci_dev *dev = c->dev[i];
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		u8 irq_pin;
-		int r;
-
-		dev->bus = bus;
-		dev->sysdata = bus->sysdata;
-		dev->dev.parent = bus->dev;
-		dev->dev.bus = &pci_bus_type;
-		dev->devfn = i;
-
-		pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
-		pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
-		dev->hdr_type = hdr & 0x7f;
-		dev->dma_mask = 0xffffffff;
-		dev->dev.dma_mask = &dev->dma_mask;
-
-		pci_setup_device(dev);
-
-		strcpy(dev->dev.bus_id, dev->slot_name);
-
-		/* We need to assign resources for expansion ROM. */
-		for (r = 0; r < 7; r++) {
-			struct resource *res = dev->resource + r;
-			if (res->flags)
-				pci_assign_resource(dev, r);
-		}
 
-		/* Does this function have an interrupt at all? */
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
-		if (irq_pin)
+		if (irq_pin) {
 			dev->irq = irq;
-		
-		/* pci_enable_device needs to be called after pci_assign_resource */
-		/* because it returns an error if (!res->start && res->end).      */
-		if (pci_enable_device(dev))
-			continue;
-
-		if (irq_pin)
-			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-		
-		device_register(&dev->dev);
-		pci_insert_device(dev, bus);
-	}
-
-	s->cb_config = c;
-	s->irq.AssignedIRQ = irq;
-	return CS_SUCCESS;
-}
-
-void cb_free(socket_info_t * s)
-{
-	cb_config_t *c = s->cb_config;
-
-	if (c) {
-		s->cb_config = NULL;
-		pci_remove_behind_bridge(s->cap.cb_dev);
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		}
 
-		kfree(c);
-		printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
+		if (dev->subordinate)
+			cardbus_assign_irqs(dev->subordinate, irq);
 	}
 }
 
-/*=====================================================================
-
-    cb_enable() has the job of configuring a socket for a Cardbus
-    card, and initializing the card's PCI configuration registers.
-
-    It first sets up the Cardbus bridge windows, for IO and memory
-    accesses.  Then, it initializes each card function's base address
-    registers, interrupt line register, and command register.
-
-    It is called as part of the RequestConfiguration card service.
-    It should be called after a previous call to cb_config() (via the
-    RequestIO service).
-    
-======================================================================*/
-
-void cb_enable(socket_info_t * s)
+int cb_alloc(socket_info_t * s)
 {
+	struct pci_bus *bus = s->cap.cb_dev->subordinate;
 	struct pci_dev *dev;
-	u_char i;
+	unsigned int max, pass;
 
-	DEBUG(0, "cs: cb_enable(bus %d)\n", s->cap.cb_dev->subordinate->number);
+	s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
+//	pcibios_fixup_bus(bus);
 
-	/* Configure bridge */
-	cb_release_cis_mem(s);
-
-	/* Set up PCI interrupt and command registers */
-	for (i = 0; i < s->functions; i++) {
-		dev = s->cb_config->dev[i];
-		pci_write_config_byte(dev, PCI_COMMAND, PCI_COMMAND_MASTER |
-				      PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-				      L1_CACHE_BYTES / 4);
-	}
+	max = bus->secondary;
+	for (pass = 0; pass < 2; pass++)
+		list_for_each_entry(dev, &bus->devices, bus_list)
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+				max = pci_scan_bridge(bus, dev, max, pass);
+
+	/*
+	 * Size all resources below the CardBus controller.
+	 */
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	cardbus_assign_irqs(bus, s->cap.pci_irq);
+	pci_enable_bridges(bus);
+	pci_bus_add_devices(bus);
 
-	if (s->irq.AssignedIRQ) {
-		for (i = 0; i < s->functions; i++) {
-			dev = s->cb_config->dev[i];
-			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
-					      s->irq.AssignedIRQ);
-		}
-		s->socket.io_irq = s->irq.AssignedIRQ;
-		s->ss_entry->set_socket(s->sock, &s->socket);
-	}
+	s->irq.AssignedIRQ = s->cap.pci_irq;
+	return CS_SUCCESS;
 }
 
-/*======================================================================
-
-    cb_disable() unconfigures a Cardbus card previously set up by
-    cb_enable().
-
-    It is called from the ReleaseConfiguration service.
-    
-======================================================================*/
-
-void cb_disable(socket_info_t * s)
+void cb_free(socket_info_t * s)
 {
-	DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cb_dev->subordinate->number);
+	struct pci_dev *bridge = s->cap.cb_dev;
 
-	/* Turn off bridge windows */
-	cb_release_cis_mem(s);
+	pci_remove_behind_bridge(bridge);
 }
diff -urN linux-2.5.66-bk2/drivers/pcmcia/cistpl.c linux-2.5.66-bk3/drivers/pcmcia/cistpl.c
--- linux-2.5.66-bk2/drivers/pcmcia/cistpl.c	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/cistpl.c	Mon Mar 31 12:48:53 2003
@@ -47,7 +47,6 @@
 #include <asm/byteorder.h>
 
 #include <pcmcia/cs_types.h>
-#include <pcmcia/bus_ops.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
@@ -83,6 +82,52 @@
 
 INT_MODULE_PARM(cis_width,	0);		/* 16-bit CIS? */
 
+void release_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start != 0) {
+	s->cis_mem.flags &= ~MAP_ACTIVE;
+	s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
+	if (!(s->cap.features & SS_CAP_STATIC_MAP))
+	    release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
+	iounmap(s->cis_virt);
+	s->cis_mem.sys_start = 0;
+	s->cis_virt = NULL;
+    }
+}
+
+/*
+ * Map the card memory at "card_offset" into virtual space.
+ * If flags & MAP_ATTRIB, map the attribute space, otherwise
+ * map the memory space.
+ */
+static unsigned char *
+set_cis_map(socket_info_t *s, unsigned int card_offset, unsigned int flags)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    if (!(s->cap.features & SS_CAP_STATIC_MAP) &&
+	mem->sys_start == 0) {
+	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
+	validate_mem(s);
+	mem->sys_start = 0;
+	if (find_mem_region(&mem->sys_start, s->cap.map_size,
+			    s->cap.map_size, low, "card services", s)) {
+	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
+	    return NULL;
+	}
+	mem->sys_stop = mem->sys_start+s->cap.map_size-1;
+	s->cis_virt = ioremap(mem->sys_start, s->cap.map_size);
+    }
+    mem->card_start = card_offset;
+    mem->flags = flags;
+    s->ss_entry->set_mem_map(s->sock, mem);
+    if (s->cap.features & SS_CAP_STATIC_MAP) {
+	if (s->cis_virt)
+	    iounmap(s->cis_virt);
+	s->cis_virt = ioremap(mem->sys_start, s->cap.map_size);
+    }
+    return s->cis_virt;
+}
+
 /*======================================================================
 
     Low-level functions to read and write CIS memory.  I think the
@@ -94,60 +139,60 @@
 #define IS_ATTR		1
 #define IS_INDIRECT	8
 
-static int setup_cis_mem(socket_info_t *s);
-
-static void set_cis_map(socket_info_t *s, pccard_mem_map *mem)
-{
-    s->ss_entry->set_mem_map(s->sock, mem);
-    if (s->cap.features & SS_CAP_STATIC_MAP) {
-	if (s->cis_virt)
-	    bus_iounmap(s->cap.bus, s->cis_virt);
-	s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start,
-				  s->cap.map_size);
-    }
-}
-
 int read_cis_mem(socket_info_t *s, int attr, u_int addr,
 		 u_int len, void *ptr)
 {
-    pccard_mem_map *mem = &s->cis_mem;
-    u_char *sys, *buf = ptr;
+    u_char *sys, *end, *buf = ptr;
     
     DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
-    if (setup_cis_mem(s) != 0) {
-	memset(ptr, 0xff, len);
-	return -1;
-    }
-    mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
 	   locations in common memory */
 	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
-	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
-	mem->card_start = 0; mem->flags = MAP_ACTIVE;
-	set_cis_map(s, mem);
-	sys = s->cis_virt;
-	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
-	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
-	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
-	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
-	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	if (attr & IS_ATTR) {
+	    addr *= 2;
+	    flags = ICTRL0_AUTOINC;
+	}
+
+	sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
+	if (!sys) {
+	    memset(ptr, 0xff, len);
+	    return -1;
+	}
+
+	writeb(flags, sys+CISREG_ICTRL0);
+	writeb(addr & 0xff, sys+CISREG_IADDR0);
+	writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+	writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+	writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
 	for ( ; len > 0; len--, buf++)
-	    *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0);
+	    *buf = readb(sys+CISREG_IDATA0);
     } else {
-	u_int inc = 1;
-	if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
-	sys += (addr & (s->cap.map_size-1));
-	mem->card_start = addr & ~(s->cap.map_size-1);
+	u_int inc = 1, card_offset, flags;
+
+	flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+	if (attr) {
+	    flags |= MAP_ATTRIB;
+	    inc++;
+	    addr *= 2;
+	}
+
+	card_offset = addr & ~(s->cap.map_size-1);
 	while (len) {
-	    set_cis_map(s, mem);
-	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    sys = set_cis_map(s, card_offset, flags);
+	    if (!sys) {
+		memset(ptr, 0xff, len);
+		return -1;
+	    }
+	    end = sys + s->cap.map_size;
+	    sys = sys + (addr & (s->cap.map_size-1));
 	    for ( ; len > 0; len--, buf++, sys += inc) {
-		if (sys == s->cis_virt+s->cap.map_size) break;
-		*buf = bus_readb(s->cap.bus, sys);
+		if (sys == end)
+		    break;
+		*buf = readb(sys);
 	    }
-	    mem->card_start += s->cap.map_size;
+	    card_offset += s->cap.map_size;
 	    addr = 0;
 	}
     }
@@ -160,40 +205,54 @@
 void write_cis_mem(socket_info_t *s, int attr, u_int addr,
 		   u_int len, void *ptr)
 {
-    pccard_mem_map *mem = &s->cis_mem;
-    u_char *sys, *buf = ptr;
+    u_char *sys, *end, *buf = ptr;
     
     DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
-    if (setup_cis_mem(s) != 0) return;
-    mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
 	   locations in common memory */
 	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
-	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
-	mem->card_start = 0; mem->flags = MAP_ACTIVE;
-	set_cis_map(s, mem);
-	sys = s->cis_virt;
-	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
-	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
-	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
-	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
-	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	if (attr & IS_ATTR) {
+	    addr *= 2;
+	    flags = ICTRL0_AUTOINC;
+	}
+
+	sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
+	if (!sys)
+		return; /* FIXME: Error */
+
+	writeb(flags, sys+CISREG_ICTRL0);
+	writeb(addr & 0xff, sys+CISREG_IADDR0);
+	writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+	writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+	writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
 	for ( ; len > 0; len--, buf++)
-	    bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0);
+	    writeb(*buf, sys+CISREG_IDATA0);
     } else {
-	int inc = 1;
-	if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
-	mem->card_start = addr & ~(s->cap.map_size-1);
+	u_int inc = 1, card_offset, flags;
+
+	flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+	if (attr & IS_ATTR) {
+	    flags |= MAP_ATTRIB;
+	    inc++;
+	    addr *= 2;
+	}
+
+	card_offset = addr & ~(s->cap.map_size-1);
 	while (len) {
-	    set_cis_map(s, mem);
-	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    sys = set_cis_map(s, card_offset, flags);
+	    if (!sys)
+		return; /* FIXME: error */
+
+	    end = sys + s->cap.map_size;
+	    sys = sys + (addr & (s->cap.map_size-1));
 	    for ( ; len > 0; len--, buf++, sys += inc) {
-		if (sys == s->cis_virt+s->cap.map_size) break;
-		bus_writeb(s->cap.bus, *buf, sys);
+		if (sys == end)
+		    break;
+		writeb(*buf, sys);
 	    }
-	    mem->card_start += s->cap.map_size;
+	    card_offset += s->cap.map_size;
 	    addr = 0;
 	}
     }
@@ -201,98 +260,6 @@
 
 /*======================================================================
 
-    This is tricky... when we set up CIS memory, we try to validate
-    the memory window space allocations.
-    
-======================================================================*/
-
-/* Scratch pointer to the socket we use for validation */
-static socket_info_t *vs = NULL;
-
-/* Validation function for cards with a valid CIS */
-static int cis_readable(u_long base)
-{
-    cisinfo_t info1, info2;
-    int ret;
-    vs->cis_mem.sys_start = base;
-    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
-    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
-    ret = pcmcia_validate_cis(vs->clients, &info1);
-    /* invalidate mapping and CIS cache */
-    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
-    if ((ret != 0) || (info1.Chains == 0))
-	return 0;
-    vs->cis_mem.sys_start = base+vs->cap.map_size;
-    vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
-    vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
-			       vs->cap.map_size);
-    ret = pcmcia_validate_cis(vs->clients, &info2);
-    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
-    return ((ret == 0) && (info1.Chains == info2.Chains));
-}
-
-/* Validation function for simple memory cards */
-static int checksum(u_long base)
-{
-    int i, a, b, d;
-    vs->cis_mem.sys_start = base;
-    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
-    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
-    vs->cis_mem.card_start = 0;
-    vs->cis_mem.flags = MAP_ACTIVE;
-    vs->ss_entry->set_mem_map(vs->sock, &vs->cis_mem);
-    /* Don't bother checking every word... */
-    a = 0; b = -1;
-    for (i = 0; i < vs->cap.map_size; i += 44) {
-	d = bus_readl(vs->cap.bus, vs->cis_virt+i);
-	a += d; b &= d;
-    }
-    bus_iounmap(vs->cap.bus, vs->cis_virt);
-    return (b == -1) ? -1 : (a>>1);
-}
-
-static int checksum_match(u_long base)
-{
-    int a = checksum(base), b = checksum(base+vs->cap.map_size);
-    return ((a == b) && (a >= 0));
-}
-
-static int setup_cis_mem(socket_info_t *s)
-{
-    if (!(s->cap.features & SS_CAP_STATIC_MAP) &&
-	(s->cis_mem.sys_start == 0)) {
-	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
-	vs = s;
-	validate_mem(cis_readable, checksum_match, low, s);
-	s->cis_mem.sys_start = 0;
-	vs = NULL;
-	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
-			    s->cap.map_size, low, "card services", s)) {
-	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
-	    return -1;
-	}
-	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
-	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
-				  s->cap.map_size);
-    }
-    return 0;
-}
-
-void release_cis_mem(socket_info_t *s)
-{
-    if (s->cis_mem.sys_start != 0) {
-	s->cis_mem.flags &= ~MAP_ACTIVE;
-	s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
-	if (!(s->cap.features & SS_CAP_STATIC_MAP))
-	    release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
-	bus_iounmap(s->cap.bus, s->cis_virt);
-	s->cis_mem.sys_start = 0;
-	s->cis_virt = NULL;
-    }
-}
-
-/*======================================================================
-
     This is a wrapper around read_cis_mem, with the same interface,
     but which caches information, for cards whose CIS may not be
     readable all the time.
@@ -427,11 +394,9 @@
     tuple->TupleLink = tuple->Flags = 0;
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS) {
+	struct pci_dev *dev = s->cap.cb_dev;
 	u_int ptr;
-	struct pci_dev *dev = pci_find_slot (s->cap.cb_dev->subordinate->number, 0);
-	if (!dev)
-	    return CS_BAD_HANDLE;
-	pci_read_config_dword(dev, 0x28, &ptr);
+	pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr);
 	tuple->CISOffset = ptr & ~7;
 	SPACE(tuple->Flags) = (ptr & 7);
     } else
diff -urN linux-2.5.66-bk2/drivers/pcmcia/cs.c linux-2.5.66-bk3/drivers/pcmcia/cs.c
--- linux-2.5.66-bk2/drivers/pcmcia/cs.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/cs.c	Mon Mar 31 12:48:53 2003
@@ -59,7 +59,6 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
-#include <pcmcia/bus_ops.h>
 #include "cs_internal.h"
 
 #ifdef CONFIG_PCI
@@ -622,8 +621,10 @@
 		send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
 	} else if (s->state & SOCKET_SETUP_PENDING) {
 #ifdef CONFIG_CARDBUS
-	    if (s->state & SOCKET_CARDBUS)
+	    if (s->state & SOCKET_CARDBUS) {
 		cb_alloc(s);
+		s->state |= SOCKET_CARDBUS_CONFIG;
+	    }
 #endif
 	    send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
 	    s->state &= ~SOCKET_SETUP_PENDING;
@@ -1077,7 +1078,7 @@
 	config->Vcc = s->socket.Vcc;
 	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
 	config->Option = s->cap.cb_dev->subordinate->number;
-	if (s->cb_config) {
+	if (s->state & SOCKET_CARDBUS_CONFIG) {
 	    config->Attributes = CONF_VALID_CLIENT;
 	    config->IntType = INT_CARDBUS;
 	    config->AssignedIRQ = s->irq.AssignedIRQ;
@@ -1473,7 +1474,6 @@
     client->event_handler = req->event_handler;
     client->event_callback_args = req->event_callback_args;
     client->event_callback_args.client_handle = client;
-    client->event_callback_args.bus = s->cap.bus;
 
     if (s->state & SOCKET_CARDBUS)
 	client->state |= CLIENT_CARDBUS;
@@ -1522,11 +1522,8 @@
     s = SOCKET(handle);
     
 #ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS) {
-	cb_disable(s);
-	s->lock_count = 0;
+    if (handle->state & CLIENT_CARDBUS)
 	return CS_SUCCESS;
-    }
 #endif
     
     if (!(handle->state & CLIENT_STALE)) {
@@ -1573,9 +1570,8 @@
     s = SOCKET(handle);
     
 #ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS) {
+    if (handle->state & CLIENT_CARDBUS)
 	return CS_SUCCESS;
-    }
 #endif
     
     if (!(handle->state & CLIENT_STALE)) {
@@ -1622,10 +1618,10 @@
     }
     
     if (req->Attributes & IRQ_HANDLE_PRESENT) {
-	bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+	free_irq(req->AssignedIRQ, req->Instance);
     }
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
     if (req->AssignedIRQ != s->cap.pci_irq)
 	undo_irq(req->Attributes, req->AssignedIRQ);
 #endif
@@ -1678,16 +1674,8 @@
 	return CS_NO_CARD;
     
 #ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS) {
-	if (!(req->IntType & INT_CARDBUS))
-	    return CS_UNSUPPORTED_MODE;
-	if (s->lock_count != 0)
-	    return CS_CONFIGURATION_LOCKED;
-	cb_enable(s);
-	handle->state |= CLIENT_CONFIG_LOCKED;
-	s->lock_count++;
-	return CS_SUCCESS;
-    }
+    if (handle->state & CLIENT_CARDBUS)
+	return CS_UNSUPPORTED_MODE;
 #endif
     
     if (req->IntType & INT_CARDBUS)
@@ -1887,7 +1875,7 @@
     if (!s->cap.irq_mask) {
 	irq = s->cap.pci_irq;
 	ret = (irq) ? 0 : CS_IN_USE;
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
     } else if (s->irq.AssignedIRQ != 0) {
 	/* If the interrupt is already assigned, it must match */
 	irq = s->irq.AssignedIRQ;
@@ -1917,7 +1905,7 @@
     if (ret != 0) return ret;
 
     if (req->Attributes & IRQ_HANDLE_PRESENT) {
-	if (bus_request_irq(s->cap.bus, irq, req->Handler,
+	if (request_irq(irq, req->Handler,
 			    ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || 
 			     (s->functions > 1) ||
 			     (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,
diff -urN linux-2.5.66-bk2/drivers/pcmcia/cs_internal.h linux-2.5.66-bk3/drivers/pcmcia/cs_internal.h
--- linux-2.5.66-bk2/drivers/pcmcia/cs_internal.h	Mon Mar 24 13:59:52 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/cs_internal.h	Mon Mar 31 12:48:53 2003
@@ -136,7 +136,6 @@
 #ifdef CONFIG_CARDBUS
     struct resource *		cb_cis_res;
     u_char			*cb_cis_virt;
-    struct cb_config_t		*cb_config;
 #endif
     struct {
 	u_int			AssignedIRQ;
@@ -176,6 +175,7 @@
 #define SOCKET_IO_REQ(i)	(0x1000<<(i))
 #define SOCKET_REGION_INFO	0x4000
 #define SOCKET_CARDBUS		0x8000
+#define SOCKET_CARDBUS_CONFIG	0x10000
 
 #define CHECK_HANDLE(h) \
     (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
@@ -198,8 +198,6 @@
 /* In cardbus.c */
 int cb_alloc(socket_info_t *s);
 void cb_free(socket_info_t *s);
-void cb_enable(socket_info_t *s);
-void cb_disable(socket_info_t *s);
 int read_cb_mem(socket_info_t *s, int space, u_int addr, u_int len, void *ptr);
 void cb_release_cis_mem(socket_info_t *s);
 
@@ -234,8 +232,7 @@
 int copy_memory(memory_handle_t handle, copy_op_t *req);
 
 /* In rsrc_mgr */
-void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low, socket_info_t *s);
+void validate_mem(socket_info_t *s);
 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
 		   char *name, socket_info_t *s);
 int find_mem_region(u_long *base, u_long num, u_long align,
diff -urN linux-2.5.66-bk2/drivers/pcmcia/ds.c linux-2.5.66-bk3/drivers/pcmcia/ds.c
--- linux-2.5.66-bk2/drivers/pcmcia/ds.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/ds.c	Mon Mar 31 12:48:53 2003
@@ -48,6 +48,7 @@
 #include <linux/proc_fs.h>
 #include <linux/poll.h>
 #include <linux/pci.h>
+#include <linux/list.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -55,6 +56,7 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
 
 /*====================================================================*/
 
@@ -97,15 +99,18 @@
 } user_info_t;
 
 /* Socket state information */
-typedef struct socket_info_t {
-    client_handle_t	handle;
-    int			state;
-    user_info_t		*user;
-    int			req_pending, req_result;
-    wait_queue_head_t	queue, request;
-    struct timer_list	removal;
-    socket_bind_t	*bind;
-} socket_info_t;
+struct pcmcia_bus_socket {
+	client_handle_t		handle;
+	int			state;
+	user_info_t		*user;
+	int			req_pending, req_result;
+	wait_queue_head_t	queue, request;
+	struct timer_list	removal;
+	socket_bind_t		*bind;
+	struct device		*socket_dev;
+	struct list_head	socket_list;
+	unsigned int		socket_no; /* deprecated */
+};
 
 #define SOCKET_PRESENT		0x01
 #define SOCKET_BUSY		0x02
@@ -116,13 +121,13 @@
 /* Device driver ID passed to Card Services */
 static dev_info_t dev_info = "Driver Services";
 
-static int sockets = 0, major_dev = -1;
-static socket_info_t *socket_table = NULL;
+static int major_dev = -1;
 
-extern struct proc_dir_entry *proc_pccard;
+/* list of all sockets registered with the pcmcia bus driver */
+static DECLARE_RWSEM(bus_socket_list_rwsem);
+static LIST_HEAD(bus_socket_list);
 
-/* We use this to distinguish in-kernel from modular drivers */
-static int init_status = 1;
+extern struct proc_dir_entry *proc_pccard;
 
 /*====================================================================*/
 
@@ -135,6 +140,7 @@
 /*======================================================================*/
 
 static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
+static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
 
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
@@ -147,7 +153,6 @@
 		return -EINVAL;
 
  	driver->use_count = 0;
- 	driver->status = init_status;
 	driver->drv.bus = &pcmcia_bus_type;
 
 	return driver_register(&driver->drv);
@@ -160,17 +165,19 @@
 void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 {
 	socket_bind_t *b;
-	int i;
+	struct pcmcia_bus_socket *bus_sock;
 
 	if (driver->use_count > 0) {
 		/* Blank out any left-over device instances */
 		driver->attach = NULL; driver->detach = NULL;
-		for (i = 0; i < sockets; i++)
-			for (b = socket_table[i].bind; b; b = b->next)
+		down_read(&bus_socket_list_rwsem);
+		list_for_each_entry(bus_sock, &bus_socket_list, socket_list) {
+			for (b = bus_sock->bind; b; b = b->next)
 				if (b->driver == driver) 
 					b->instance = NULL;
- 	}
-
+		}
+		up_read(&bus_socket_list_rwsem);
+	}
 	driver_unregister(&driver->drv);
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
@@ -182,7 +189,7 @@
 {
     struct pcmcia_driver *driver;
     socket_bind_t *b;
-    int i;
+    struct pcmcia_bus_socket *bus_sock;
 
     DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
     driver = get_pcmcia_driver(dev_info);
@@ -199,15 +206,17 @@
     if (driver->use_count == 0) return 0;
     
     /* Instantiate any already-bound devices */
-    for (i = 0; i < sockets; i++)
-	for (b = socket_table[i].bind; b; b = b->next) {
+    down_read(&bus_socket_list_rwsem);
+    list_for_each_entry(bus_sock, &bus_socket_list, socket_list) {
+	for (b = bus_sock->bind; b; b = b->next) {
 	    if (b->driver != driver) continue;
 	    b->instance = driver->attach();
 	    if (b->instance == NULL)
 		printk(KERN_NOTICE "ds: unable to create instance "
 		       "of '%s'!\n", driver->drv.name);
 	}
-    
+    }
+    up_read(&bus_socket_list_rwsem);
     return 0;
 } /* register_pccard_driver */
 
@@ -238,8 +247,7 @@
 	struct pcmcia_driver *p_dev = container_of(driver, 
 						   struct pcmcia_driver, drv);
 
-	*p += sprintf(*p, "%-24.24s %d %d\n", driver->name, p_dev->status,
-		     p_dev->use_count);
+	*p += sprintf(*p, "%-24.24s 1 %d\n", driver->name, p_dev->use_count);
 	d = (void *) p;
 
 	return 0;
@@ -282,7 +290,7 @@
     user->event[user->event_head] = event;
 }
 
-static void handle_event(socket_info_t *s, event_t event)
+static void handle_event(struct pcmcia_bus_socket *s, event_t event)
 {
     user_info_t *user;
     for (user = s->user; user; user = user->next)
@@ -290,7 +298,7 @@
     wake_up_interruptible(&s->queue);
 }
 
-static int handle_request(socket_info_t *s, event_t event)
+static int handle_request(struct pcmcia_bus_socket *s, event_t event)
 {
     if (s->req_pending != 0)
 	return CS_IN_USE;
@@ -309,7 +317,7 @@
 
 static void handle_removal(u_long sn)
 {
-    socket_info_t *s = &socket_table[sn];
+    struct pcmcia_bus_socket *s = get_socket_info_by_nr(sn);
     handle_event(s, CS_EVENT_CARD_REMOVAL);
     s->state &= ~SOCKET_REMOVAL_PENDING;
 }
@@ -323,13 +331,11 @@
 static int ds_event(event_t event, int priority,
 		    event_callback_args_t *args)
 {
-    socket_info_t *s;
-    int i;
+    struct pcmcia_bus_socket *s;
 
     DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
 	  event, priority, args->client_handle);
     s = args->client_data;
-    i = s - socket_table;
     
     switch (event) {
 	
@@ -366,21 +372,21 @@
     
 ======================================================================*/
 
-static int bind_mtd(int i, mtd_info_t *mtd_info)
+static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info)
 {
     mtd_bind_t bind_req;
     int ret;
 
     bind_req.dev_info = &mtd_info->dev_info;
     bind_req.Attributes = mtd_info->Attributes;
-    bind_req.Socket = i;
+    bind_req.Socket = bus_sock->socket_no;
     bind_req.CardOffset = mtd_info->CardOffset;
     ret = pcmcia_bind_mtd(&bind_req);
     if (ret != CS_SUCCESS) {
 	cs_error(NULL, BindMTD, ret);
 	printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
 	       " offset 0x%x\n",
-	       (char *)bind_req.dev_info, i, bind_req.CardOffset);
+	       (char *)bind_req.dev_info, bus_sock->socket_no, bind_req.CardOffset);
 	return -ENODEV;
     }
     return 0;
@@ -395,14 +401,16 @@
     
 ======================================================================*/
 
-static int bind_request(int i, bind_info_t *bind_info)
+static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
     struct pcmcia_driver *driver;
     socket_bind_t *b;
     bind_req_t bind_req;
-    socket_info_t *s = &socket_table[i];
     int ret;
 
+    if (!s)
+	    return -EINVAL;
+
     DEBUG(2, "bind_request(%d, '%s')\n", i,
 	  (char *)bind_info->dev_info);
     driver = get_pcmcia_driver(&bind_info->dev_info);
@@ -423,14 +431,14 @@
 	return -EBUSY;
     }
 
-    bind_req.Socket = i;
+    bind_req.Socket = s->socket_no;
     bind_req.Function = bind_info->function;
     bind_req.dev_info = (dev_info_t *) driver->drv.name;
     ret = pcmcia_bind_device(&bind_req);
     if (ret != CS_SUCCESS) {
 	cs_error(NULL, BindDevice, ret);
 	printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
-	       (char *)dev_info, i);
+	       (char *)dev_info, s->socket_no);
 	return -ENODEV;
     }
 
@@ -462,9 +470,8 @@
 
 /*====================================================================*/
 
-static int get_device_info(int i, bind_info_t *bind_info, int first)
+static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
 {
-    socket_info_t *s = &socket_table[i];
     socket_bind_t *b;
     dev_node_t *node;
 
@@ -532,9 +539,8 @@
 
 /*====================================================================*/
 
-static int unbind_request(int i, bind_info_t *bind_info)
+static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
-    socket_info_t *s = &socket_table[i];
     socket_bind_t **b, *c;
 
     DEBUG(2, "unbind_request(%d, '%s')\n", i,
@@ -568,13 +574,15 @@
 static int ds_open(struct inode *inode, struct file *file)
 {
     socket_t i = minor(inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     user_info_t *user;
 
     DEBUG(0, "ds_open(socket %d)\n", i);
-    if ((i >= sockets) || (sockets == 0))
-	return -ENODEV;
-    s = &socket_table[i];
+
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return -ENODEV;
+
     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 	if (s->state & SOCKET_BUSY)
 	    return -EBUSY;
@@ -600,13 +608,15 @@
 static int ds_release(struct inode *inode, struct file *file)
 {
     socket_t i = minor(inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     user_info_t *user, **link;
 
     DEBUG(0, "ds_release(socket %d)\n", i);
-    if ((i >= sockets) || (sockets == 0))
-	return 0;
-    s = &socket_table[i];
+
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return 0;
+
     user = file->private_data;
     if (CHECK_USER(user))
 	goto out;
@@ -632,16 +642,18 @@
 		       size_t count, loff_t *ppos)
 {
     socket_t i = minor(file->f_dentry->d_inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     user_info_t *user;
 
     DEBUG(2, "ds_read(socket %d)\n", i);
     
-    if ((i >= sockets) || (sockets == 0))
-	return -ENODEV;
     if (count < 4)
 	return -EINVAL;
-    s = &socket_table[i];
+
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return -ENODEV;
+
     user = file->private_data;
     if (CHECK_USER(user))
 	return -EIO;
@@ -661,18 +673,20 @@
 			size_t count, loff_t *ppos)
 {
     socket_t i = minor(file->f_dentry->d_inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     user_info_t *user;
 
     DEBUG(2, "ds_write(socket %d)\n", i);
     
-    if ((i >= sockets) || (sockets == 0))
-	return -ENODEV;
     if (count != 4)
 	return -EINVAL;
     if ((file->f_flags & O_ACCMODE) == O_RDONLY)
 	return -EBADF;
-    s = &socket_table[i];
+
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return -ENODEV;
+
     user = file->private_data;
     if (CHECK_USER(user))
 	return -EIO;
@@ -694,14 +708,15 @@
 static u_int ds_poll(struct file *file, poll_table *wait)
 {
     socket_t i = minor(file->f_dentry->d_inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     user_info_t *user;
 
     DEBUG(2, "ds_poll(socket %d)\n", i);
     
-    if ((i >= sockets) || (sockets == 0))
-	return POLLERR;
-    s = &socket_table[i];
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return POLLERR;
+
     user = file->private_data;
     if (CHECK_USER(user))
 	return POLLERR;
@@ -717,16 +732,16 @@
 		    u_int cmd, u_long arg)
 {
     socket_t i = minor(inode->i_rdev);
-    socket_info_t *s;
+    struct pcmcia_bus_socket *s;
     u_int size;
     int ret, err;
     ds_ioctl_arg_t buf;
 
     DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
     
-    if ((i >= sockets) || (sockets == 0))
-	return -ENODEV;
-    s = &socket_table[i];
+    s = get_socket_info_by_nr(i);
+    if (!s)
+	    return -ENODEV;
     
     size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
     if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
@@ -827,20 +842,20 @@
 	break;
     case DS_BIND_REQUEST:
 	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-	err = bind_request(i, &buf.bind_info);
+	err = bind_request(s, &buf.bind_info);
 	break;
     case DS_GET_DEVICE_INFO:
-	err = get_device_info(i, &buf.bind_info, 1);
+	err = get_device_info(s, &buf.bind_info, 1);
 	break;
     case DS_GET_NEXT_DEVICE:
-	err = get_device_info(i, &buf.bind_info, 0);
+	err = get_device_info(s, &buf.bind_info, 0);
 	break;
     case DS_UNBIND_REQUEST:
-	err = unbind_request(i, &buf.bind_info);
+	err = unbind_request(s, &buf.bind_info);
 	break;
     case DS_BIND_MTD:
 	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-	err = bind_mtd(i, &buf.mtd_info);
+	err = bind_mtd(s, &buf.mtd_info);
 	break;
     default:
 	err = -EINVAL;
@@ -889,141 +904,199 @@
 
 /*====================================================================*/
 
-struct bus_type pcmcia_bus_type = {
-	.name = "pcmcia",
-};
-EXPORT_SYMBOL(pcmcia_bus_type);
-
-static int __init init_pcmcia_bus(void)
+static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr)
 {
-	bus_register(&pcmcia_bus_type);
-	return 0;
-}
+	client_reg_t client_reg;
+	bind_req_t bind;
+	struct pcmcia_bus_socket *s, *tmp_s;
+	int ret;
+	int i;
 
-static int __init init_pcmcia_ds(void)
-{
-    client_reg_t client_reg;
-    servinfo_t serv;
-    bind_req_t bind;
-    socket_info_t *s;
-    int i, ret;
-    
-    DEBUG(0, "%s\n", version);
- 
-    /*
-     * Ugly. But we want to wait for the socket threads to have started up.
-     * We really should let the drivers themselves drive some of this..
-     */
-    current->state = TASK_INTERRUPTIBLE;
-    schedule_timeout(HZ/4);
+	s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
+	if(!s)
+		return -ENOMEM;
+	memset(s, 0, sizeof(struct pcmcia_bus_socket));
+    
+	/*
+	 * Ugly. But we want to wait for the socket threads to have started up.
+	 * We really should let the drivers themselves drive some of this..
+	 */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ/4);
 
-    pcmcia_get_card_services_info(&serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ds: Card Services release does not match!\n");
-	return -1;
-    }
-    if (serv.Count == 0) {
-	printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
-	return -1;
-    }
-    
-    sockets = serv.Count;
-    socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
-    if (!socket_table) return -1;
-    for (i = 0, s = socket_table; i < sockets; i++, s++) {
-	s->state = 0;
-	s->user = NULL;
-	s->req_pending = 0;
 	init_waitqueue_head(&s->queue);
 	init_waitqueue_head(&s->request);
-	s->handle = NULL;
-	init_timer(&s->removal);
-	s->removal.data = i;
+
+	/* find the lowest, unused socket no. Please note that this is a
+	 * temporary workaround until "struct pcmcia_socket" is introduced
+	 * into cs.c which will include this number, and which will be
+	 * accessible to ds.c directly */
+	i = 0;
+ next_try:
+	list_for_each_entry(tmp_s, &bus_socket_list, socket_list) {
+		if (tmp_s->socket_no == i) {
+			i++;
+			goto next_try;
+		}
+	}
+	s->socket_no = i;
+
+	/* initialize data */
+	s->socket_dev = dev;
+	s->removal.data = s->socket_no;
 	s->removal.function = &handle_removal;
-	s->bind = NULL;
-    }
+	init_timer(&s->removal);
     
-    /* Set up hotline to Card Services */
-    client_reg.dev_info = bind.dev_info = &dev_info;
-    client_reg.Attributes = INFO_MASTER_CLIENT;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ds_event;
-    client_reg.Version = 0x0210;
-    for (i = 0; i < sockets; i++) {
-	bind.Socket = i;
+	/* Set up hotline to Card Services */
+	client_reg.dev_info = bind.dev_info = &dev_info;
+
+	bind.Socket = s->socket_no;
 	bind.Function = BIND_FN_ALL;
 	ret = pcmcia_bind_device(&bind);
 	if (ret != CS_SUCCESS) {
-	    cs_error(NULL, BindDevice, ret);
-	    break;
+		cs_error(NULL, BindDevice, ret);
+		kfree(s);
+		return -EINVAL;
 	}
-	client_reg.event_callback_args.client_data = &socket_table[i];
-	ret = pcmcia_register_client(&socket_table[i].handle,
-			   &client_reg);
+
+	client_reg.Attributes = INFO_MASTER_CLIENT;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &ds_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = s;
+	ret = pcmcia_register_client(&s->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
-	    cs_error(NULL, RegisterClient, ret);
-	    break;
+		cs_error(NULL, RegisterClient, ret);
+		kfree(s);
+		return -EINVAL;
 	}
-    }
-    
-    /* Set up character device for user mode clients */
-    i = register_chrdev(0, "pcmcia", &ds_fops);
-    if (i == -EBUSY)
-	printk(KERN_NOTICE "unable to find a free device # for "
-	       "Driver Services\n");
-    else
-	major_dev = i;
 
-#ifdef CONFIG_PROC_FS
-    if (proc_pccard)
-	create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
-    init_status = 0;
-#endif
-    return 0;
+	list_add(&s->socket_list, &bus_socket_list);
+
+	return 0;
 }
 
 
-static void __exit exit_pcmcia_ds(void)
+static int __devinit pcmcia_bus_add_socket_dev(struct device *dev)
 {
-    int i;
+	struct pcmcia_socket_class_data *cls_d = dev->class_data;
+	unsigned int i;
+	unsigned int ret = 0;
+
+	if (!cls_d)
+		return -ENODEV;
+
+	down_write(&bus_socket_list_rwsem);
+        for (i = 0; i < cls_d->nsock; i++)
+		ret += pcmcia_bus_add_socket(dev, i);
+	up_write(&bus_socket_list_rwsem);
+
+	return ret;
+}
+
+static int __devexit pcmcia_bus_remove_socket_dev(struct device *dev)
+{
+	struct pcmcia_socket_class_data *cls_d = dev->class_data;
+	struct list_head *list_loop;
+	struct list_head *tmp_storage;
+
+	if (!cls_d)
+		return -ENODEV;
+
+	down_write(&bus_socket_list_rwsem);
+	list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
+		struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list);
+		if (bus_sock->socket_dev == dev) {
+			pcmcia_deregister_client(bus_sock->handle);
+			list_del(&bus_sock->socket_list);
+			kfree(bus_sock);
+		}
+	}
+	up_write(&bus_socket_list_rwsem);
+	return 0;
+}
+
+
+/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
+static struct device_interface pcmcia_bus_interface = {
+	.name = "pcmcia-bus",
+	.devclass = &pcmcia_socket_class,
+	.add_device = &pcmcia_bus_add_socket_dev,
+	.remove_device = __devexit_p(&pcmcia_bus_remove_socket_dev),
+	.kset = { .subsys = &pcmcia_socket_class.subsys, },
+	.devnum = 0,
+};
+
+
+struct bus_type pcmcia_bus_type = {
+	.name = "pcmcia",
+};
+EXPORT_SYMBOL(pcmcia_bus_type);
+
+
+static int __init init_pcmcia_bus(void)
+{
+	int i;
+
+	bus_register(&pcmcia_bus_type);
+	interface_register(&pcmcia_bus_interface);
+
+	/* Set up character device for user mode clients */
+	i = register_chrdev(0, "pcmcia", &ds_fops);
+	if (i == -EBUSY)
+		printk(KERN_NOTICE "unable to find a free device # for "
+		       "Driver Services\n");
+	else
+		major_dev = i;
+
 #ifdef CONFIG_PROC_FS
-    if (proc_pccard)
-	remove_proc_entry("drivers", proc_pccard);
+	if (proc_pccard)
+		create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
 #endif
-    if (major_dev != -1)
-	unregister_chrdev(major_dev, "pcmcia");
-    for (i = 0; i < sockets; i++)
-	pcmcia_deregister_client(socket_table[i].handle);
-    sockets = 0;
-    kfree(socket_table);
-    bus_unregister(&pcmcia_bus_type);
+
+	return 0;
 }
+fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that 
+			       * pcmcia_socket_class is already registered */
 
-#ifdef MODULE
 
-/* init_pcmcia_bus must be done early, init_pcmcia_ds late. If we load this 
- * as a module, we can only specify one initcall, though... 
- */
-static int __init init_pcmcia_module(void) {
-	init_pcmcia_bus();
-	return init_pcmcia_ds();
-}
-module_init(init_pcmcia_module);
-
-#else /* !MODULE */
-subsys_initcall(init_pcmcia_bus);
-late_initcall(init_pcmcia_ds);
+static void __exit exit_pcmcia_bus(void)
+{
+	interface_unregister(&pcmcia_bus_interface);
+
+#ifdef CONFIG_PROC_FS
+	if (proc_pccard)
+		remove_proc_entry("drivers", proc_pccard);
 #endif
+	if (major_dev != -1)
+		unregister_chrdev(major_dev, "pcmcia");
+
+	bus_unregister(&pcmcia_bus_type);
+}
+module_exit(exit_pcmcia_bus);
 
-module_exit(exit_pcmcia_ds);
 
 
 /* helpers for backwards-compatible functions */
 
+
+static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr)
+{
+	struct pcmcia_bus_socket * s;
+	down_read(&bus_socket_list_rwsem);
+	list_for_each_entry(s, &bus_socket_list, socket_list)
+		if (s->socket_no == nr) {
+			up_read(&bus_socket_list_rwsem);
+			return s;
+		}
+	up_read(&bus_socket_list_rwsem);
+	return NULL;
+}
+
 /* backwards-compatible accessing of driver --- by name! */
 
 struct cmp_data {
diff -urN linux-2.5.66-bk2/drivers/pcmcia/hd64465_ss.c linux-2.5.66-bk3/drivers/pcmcia/hd64465_ss.c
--- linux-2.5.66-bk2/drivers/pcmcia/hd64465_ss.c	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/hd64465_ss.c	Mon Mar 31 12:48:53 2003
@@ -599,21 +599,6 @@
 
 /*============================================================*/
 
-static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io)
-{
-    	hs_socket_t *sp = &hs_sockets[sock];
-	int map = io->map;
-
-    	DPRINTK("hs_get_io_map(%d, %d)\n", sock, map);
-	if (map >= MAX_IO_WIN)
-	    return -EINVAL;
-	
-	*io = sp->io_maps[map];
-	return 0;
-}
-
-/*============================================================*/
-
 static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
 {
     	hs_socket_t *sp = &hs_sockets[sock];
@@ -696,21 +681,6 @@
 
 /*============================================================*/
 
-static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
-{
-    	hs_socket_t *sp = &hs_sockets[sock];
-	int map = mem->map;
-
-    	DPRINTK("hs_get_mem_map(%d, %d)\n", sock, map);
-	if (map >= MAX_WIN)
-	    return -EINVAL;
-	
-	*mem = sp->mem_maps[map];
-	return 0;
-}
-
-/*============================================================*/
-
 static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
 {
     	hs_socket_t *sp = &hs_sockets[sock];
@@ -894,9 +864,7 @@
 	.get_status		= hs_get_status,
 	.get_socket		= hs_get_socket,
 	.set_socket		= hs_set_socket,
-	.get_io_map		= hs_get_io_map,
 	.set_io_map		= hs_set_io_map,
-	.get_mem_map		= hs_get_mem_map,
 	.set_mem_map		= hs_set_mem_map,
 	.proc_setup		= hs_proc_setup,
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/i82092.c linux-2.5.66-bk3/drivers/pcmcia/i82092.c
--- linux-2.5.66-bk2/drivers/pcmcia/i82092.c	Mon Mar 24 14:01:52 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/i82092.c	Mon Mar 31 12:48:53 2003
@@ -63,9 +63,7 @@
 	.get_status		= i82092aa_get_status,
 	.get_socket		= i82092aa_get_socket,
 	.set_socket		= i82092aa_set_socket,
-	.get_io_map		= i82092aa_get_io_map,
 	.set_io_map		= i82092aa_set_io_map,
-	.get_mem_map		= i82092aa_get_mem_map,
 	.set_mem_map		= i82092aa_set_mem_map,
 	.proc_setup		= i82092aa_proc_setup,
 };
@@ -688,34 +686,6 @@
 	return 0;
 }
 
-static int i82092aa_get_io_map(unsigned int sock, struct pccard_io_map *io)
-{
-	unsigned char map, ioctl, addr;
-	
-	enter("i82092aa_get_io_map");
-	map = io->map;
-	if (map > 1) {
-		leave("i82092aa_get_io_map with -EINVAL");
-		return -EINVAL;
-	}
-	
-	/* FIXME: How does this fit in with the PCI resource (re)allocation */
-	io->start = indirect_read16(sock, I365_IO(map)+I365_W_START);
-	io->stop  = indirect_read16(sock, I365_IO(map)+I365_W_START);
-	
-	ioctl = indirect_read(sock,I365_IOCTL); /* IOCREG: I/O Control Register */
-	addr  = indirect_read(sock,I365_ADDRWIN); /* */
-	
-	io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; /* check this out later */
-	io->flags = 0;
-	
-	if (addr & I365_IOCTL_16BIT(map))
-		io->flags |= MAP_AUTOSZ;
-		
-	leave("i82092aa_get_io_map");
-	return 0;
-}
-
 static int i82092aa_set_io_map(unsigned sock, struct pccard_io_map *io)
 {
 	unsigned char map, ioctl;
@@ -759,64 +729,6 @@
 	return 0;
 }
 
-static int i82092aa_get_mem_map(unsigned sock, struct pccard_mem_map *mem)
-{
-	unsigned short base, i;
-	unsigned char map, addr;
-	
-	enter("i82092aa_get_mem_map");
-	
-	mem->flags = 0;
-	mem->speed = 0;
-	map = mem->map;
-	if (map > 4) {
-		leave("i82092aa_get_mem_map: -EINVAL");
-		return -EINVAL;
-	}
-	
-	addr = indirect_read(sock, I365_ADDRWIN);
-		
-	if (addr & I365_ENA_MEM(map))
-		mem->flags |= MAP_ACTIVE;		/* yes this mapping is active */
-	
-	base = I365_MEM(map); 
-	
-	/* Find the start address - this register also has mapping info */
-	
-	i = indirect_read16(sock,base+I365_W_START);
-	if (i & I365_MEM_16BIT)
-		mem->flags |= MAP_16BIT;
-	if (i & I365_MEM_0WS)
-		mem->flags |= MAP_0WS;
-	
-	mem->sys_start = ((unsigned long)(i & 0x0fff) << 12);
-	
-	/* Find the end address - this register also has speed info */
-	i = indirect_read16(sock,base+I365_W_STOP);
-	if (i & I365_MEM_WS0)
-		mem->speed = 1;
-	if (i & I365_MEM_WS1)
-		mem->speed += 2;
-	mem->speed = to_ns(mem->speed);
-	mem->sys_stop = ( (unsigned long)(i & 0x0fff) << 12) + 0x0fff;
-	
-	/* Find the card start address, also some more MAP attributes */
-	
-	i = indirect_read16(sock, base+I365_W_OFF);
-	if (i & I365_MEM_WRPROT)
-		mem->flags |= MAP_WRPROT;
-	if (i & I365_MEM_REG)
-		mem->flags |= MAP_ATTRIB;
-	mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start;
-	mem->card_start &=  0x3ffffff;
-	
-	printk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop);
-	
-	leave("i82092aa_get_mem_map");
-	return 0;
-	
-}
-
 static int i82092aa_set_mem_map(unsigned sock, struct pccard_mem_map *mem)
 {
 	unsigned short base, i;
diff -urN linux-2.5.66-bk2/drivers/pcmcia/i82092aa.h linux-2.5.66-bk3/drivers/pcmcia/i82092aa.h
--- linux-2.5.66-bk2/drivers/pcmcia/i82092aa.h	Mon Mar 24 14:00:01 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/i82092aa.h	Mon Mar 31 12:48:53 2003
@@ -29,9 +29,7 @@
 static int i82092aa_get_status(unsigned int sock, u_int *value);
 static int i82092aa_get_socket(unsigned int sock, socket_state_t *state);
 static int i82092aa_set_socket(unsigned int sock, socket_state_t *state);
-static int i82092aa_get_io_map(unsigned int sock, struct pccard_io_map *io);
 static int i82092aa_set_io_map(unsigned int sock, struct pccard_io_map *io);
-static int i82092aa_get_mem_map(unsigned int sock, struct pccard_mem_map *mem);
 static int i82092aa_set_mem_map(unsigned int sock, struct pccard_mem_map *mem);
 static int i82092aa_init(unsigned int s);
 static int i82092aa_suspend(unsigned int sock);
diff -urN linux-2.5.66-bk2/drivers/pcmcia/i82365.c linux-2.5.66-bk3/drivers/pcmcia/i82365.c
--- linux-2.5.66-bk2/drivers/pcmcia/i82365.c	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/i82365.c	Mon Mar 31 12:48:53 2003
@@ -1250,29 +1250,6 @@
 
 /*====================================================================*/
 
-static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
-{
-    u_char map, ioctl, addr;
-    
-    map = io->map;
-    if (map > 1) return -EINVAL;
-    io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
-    io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
-    ioctl = i365_get(sock, I365_IOCTL);
-    addr = i365_get(sock, I365_ADDRWIN);
-    io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
-    io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
-    io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
-    io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
-    io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
-    DEBUG(1, "i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
-	  "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
-	  io->start, io->stop);
-    return 0;
-} /* i365_get_io_map */
-
-/*====================================================================*/
-
 static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
 {
     u_char map, ioctl;
@@ -1302,42 +1279,6 @@
 
 /*====================================================================*/
 
-static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem)
-{
-    u_short base, i;
-    u_char map, addr;
-    
-    map = mem->map;
-    if (map > 4) return -EINVAL;
-    addr = i365_get(sock, I365_ADDRWIN);
-    mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
-    base = I365_MEM(map);
-    
-    i = i365_get_pair(sock, base+I365_W_START);
-    mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
-    mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
-    mem->sys_start = ((u_long)(i & 0x0fff) << 12);
-    
-    i = i365_get_pair(sock, base+I365_W_STOP);
-    mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
-    mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
-    mem->speed = to_ns(mem->speed);
-    mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
-    
-    i = i365_get_pair(sock, base+I365_W_OFF);
-    mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
-    mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0;
-    mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start;
-    mem->card_start &= 0x3ffffff;
-    
-    DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
-	  "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
-	  mem->sys_start, mem->sys_stop, mem->card_start);
-    return 0;
-} /* i365_get_mem_map */
-
-/*====================================================================*/
-  
 static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
 {
     u_short base, i;
@@ -1506,14 +1447,6 @@
 	LOCKED(i365_set_socket(sock, state));
 }
 
-static int pcic_get_io_map(unsigned int sock, struct pccard_io_map *io)
-{
-	if (socket[sock].flags & IS_ALIVE)
-		return -EINVAL;
-
-	LOCKED(i365_get_io_map(sock, io));
-}
-
 static int pcic_set_io_map(unsigned int sock, struct pccard_io_map *io)
 {
 	if (socket[sock].flags & IS_ALIVE)
@@ -1522,14 +1455,6 @@
 	LOCKED(i365_set_io_map(sock, io));
 }
 
-static int pcic_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
-{
-	if (socket[sock].flags & IS_ALIVE)
-		return -EINVAL;
-
-	LOCKED(i365_get_mem_map(sock, mem));
-}
-
 static int pcic_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
 {
 	if (socket[sock].flags & IS_ALIVE)
@@ -1571,9 +1496,7 @@
 	.get_status		= pcic_get_status,
 	.get_socket		= pcic_get_socket,
 	.set_socket		= pcic_set_socket,
-	.get_io_map		= pcic_get_io_map,
 	.set_io_map		= pcic_set_io_map,
-	.get_mem_map		= pcic_get_mem_map,
 	.set_mem_map		= pcic_set_mem_map,
 	.proc_setup		= pcic_proc_setup,
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/pci_socket.c linux-2.5.66-bk3/drivers/pcmcia/pci_socket.c
--- linux-2.5.66-bk2/drivers/pcmcia/pci_socket.c	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/pci_socket.c	Mon Mar 31 12:48:53 2003
@@ -105,15 +105,6 @@
 	return -EINVAL;
 }
 
-static int pci_get_io_map(unsigned int sock, struct pccard_io_map *io)
-{
-	pci_socket_t *socket = pci_socket_array + sock;
-
-	if (socket->op && socket->op->get_io_map)
-		return socket->op->get_io_map(socket, io);
-	return -EINVAL;
-}
-
 static int pci_set_io_map(unsigned int sock, struct pccard_io_map *io)
 {
 	pci_socket_t *socket = pci_socket_array + sock;
@@ -123,15 +114,6 @@
 	return -EINVAL;
 }
 
-static int pci_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
-{
-	pci_socket_t *socket = pci_socket_array + sock;
-
-	if (socket->op && socket->op->get_mem_map)
-		return socket->op->get_mem_map(socket, mem);
-	return -EINVAL;
-}
-
 static int pci_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
 {
 	pci_socket_t *socket = pci_socket_array + sock;
@@ -158,9 +140,7 @@
 	.get_status		= pci_get_status,
 	.get_socket		= pci_get_socket,
 	.set_socket		= pci_set_socket,
-	.get_io_map		= pci_get_io_map,
 	.set_io_map		= pci_set_io_map,
-	.get_mem_map		= pci_get_mem_map,
 	.set_mem_map		= pci_set_mem_map,
 	.proc_setup		= pci_proc_setup,
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/pci_socket.h linux-2.5.66-bk3/drivers/pcmcia/pci_socket.h
--- linux-2.5.66-bk2/drivers/pcmcia/pci_socket.h	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/pci_socket.h	Mon Mar 31 12:48:53 2003
@@ -37,9 +37,7 @@
 	int (*get_status)(struct pci_socket *, unsigned int *);
 	int (*get_socket)(struct pci_socket *, socket_state_t *);
 	int (*set_socket)(struct pci_socket *, socket_state_t *);
-	int (*get_io_map)(struct pci_socket *, struct pccard_io_map *);
 	int (*set_io_map)(struct pci_socket *, struct pccard_io_map *);
-	int (*get_mem_map)(struct pci_socket *, struct pccard_mem_map *);
 	int (*set_mem_map)(struct pci_socket *, struct pccard_mem_map *);
 	void (*proc_setup)(struct pci_socket *, struct proc_dir_entry *base);
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/ricoh.h linux-2.5.66-bk3/drivers/pcmcia/ricoh.h
--- linux-2.5.66-bk2/drivers/pcmcia/ricoh.h	Mon Mar 24 14:00:24 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/ricoh.h	Mon Mar 31 12:48:53 2003
@@ -170,9 +170,7 @@
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
-	yenta_get_io_map,
 	yenta_set_io_map,
-	yenta_get_mem_map,
 	yenta_set_mem_map,
 	yenta_proc_setup
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/rsrc_mgr.c linux-2.5.66-bk3/drivers/pcmcia/rsrc_mgr.c
--- linux-2.5.66-bk2/drivers/pcmcia/rsrc_mgr.c	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/rsrc_mgr.c	Mon Mar 31 12:48:53 2003
@@ -60,7 +60,7 @@
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
 INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
 INT_MODULE_PARM(mem_limit,	0x10000);
 #endif
@@ -83,7 +83,9 @@
 /* IO port resource database */
 static resource_map_t io_db = { 0, 0, &io_db };
 
-#ifdef CONFIG_ISA
+static DECLARE_MUTEX(rsrc_sem);
+
+#ifdef CONFIG_PCMCIA_PROBE
 
 typedef struct irq_info_t {
     u_int			Attributes;
@@ -269,7 +271,7 @@
     
 ======================================================================*/
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
 static void do_io_probe(ioaddr_t base, ioaddr_t num)
 {
     
@@ -333,15 +335,69 @@
 
 /*======================================================================
 
+    This is tricky... when we set up CIS memory, we try to validate
+    the memory window space allocations.
+    
+======================================================================*/
+
+/* Validation function for cards with a valid CIS */
+static int cis_readable(socket_info_t *s, u_long base)
+{
+    cisinfo_t info1, info2;
+    int ret;
+    s->cis_mem.sys_start = base;
+    s->cis_mem.sys_stop = base+s->cap.map_size-1;
+    s->cis_virt = ioremap(base, s->cap.map_size);
+    ret = pcmcia_validate_cis(s->clients, &info1);
+    /* invalidate mapping and CIS cache */
+    iounmap(s->cis_virt);
+    s->cis_used = 0;
+    if ((ret != 0) || (info1.Chains == 0))
+	return 0;
+    s->cis_mem.sys_start = base+s->cap.map_size;
+    s->cis_mem.sys_stop = base+2*s->cap.map_size-1;
+    s->cis_virt = ioremap(base+s->cap.map_size, s->cap.map_size);
+    ret = pcmcia_validate_cis(s->clients, &info2);
+    iounmap(s->cis_virt);
+    s->cis_used = 0;
+    return ((ret == 0) && (info1.Chains == info2.Chains));
+}
+
+/* Validation function for simple memory cards */
+static int checksum(socket_info_t *s, u_long base)
+{
+    int i, a, b, d;
+    s->cis_mem.sys_start = base;
+    s->cis_mem.sys_stop = base+s->cap.map_size-1;
+    s->cis_virt = ioremap(base, s->cap.map_size);
+    s->cis_mem.card_start = 0;
+    s->cis_mem.flags = MAP_ACTIVE;
+    s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
+    /* Don't bother checking every word... */
+    a = 0; b = -1;
+    for (i = 0; i < s->cap.map_size; i += 44) {
+	d = readl(s->cis_virt+i);
+	a += d; b &= d;
+    }
+    iounmap(s->cis_virt);
+    return (b == -1) ? -1 : (a>>1);
+}
+
+static int checksum_match(socket_info_t *s, u_long base)
+{
+    int a = checksum(s, base), b = checksum(s, base+s->cap.map_size);
+    return ((a == b) && (a >= 0));
+}
+
+/*======================================================================
+
     The memory probe.  If the memory list includes a 64K-aligned block
     below 1MB, we probe in 64K chunks, and as soon as we accumulate at
     least mem_limit free space, we quit.
     
 ======================================================================*/
 
-static int do_mem_probe(u_long base, u_long num,
-			int (*is_valid)(u_long), int (*do_cksum)(u_long),
-			socket_info_t *s)
+static int do_mem_probe(u_long base, u_long num, socket_info_t *s)
 {
     u_long i, j, bad, fail, step;
 
@@ -349,18 +405,21 @@
 	   base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    /* cis_readable wants to map 2x map_size */
+    if (step < 2 * s->cap.map_size)
+	step = 2 * s->cap.map_size;
     for (i = j = base; i < base+num; i = j + step) {
 	if (!fail) {	
 	    for (j = i; j < base+num; j += step)
 		if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
-		    is_valid(j))
+		    cis_readable(s, j))
 		    break;
 	    fail = ((i == base) && (j == base+num));
 	}
 	if (fail) {
 	    for (j = i; j < base+num; j += 2*step)
 		if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
-		    do_cksum(j) && do_cksum(j+step))
+		    checksum_match(s, j) && checksum_match(s, j + step))
 		    break;
 	}
 	if (i != j) {
@@ -374,16 +433,14 @@
     return (num - bad);
 }
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
 
-static u_long inv_probe(int (*is_valid)(u_long),
-			int (*do_cksum)(u_long),
-			resource_map_t *m, socket_info_t *s)
+static u_long inv_probe(resource_map_t *m, socket_info_t *s)
 {
     u_long ok;
     if (m == &mem_db)
 	return 0;
-    ok = inv_probe(is_valid, do_cksum, m->next, s);
+    ok = inv_probe(m->next, s);
     if (ok) {
 	if (m->base >= 0x100000)
 	    sub_interval(&mem_db, m->base, m->num);
@@ -391,32 +448,36 @@
     }
     if (m->base < 0x100000)
 	return 0;
-    return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
+    return do_mem_probe(m->base, m->num, s);
 }
 
-void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low, socket_info_t *s)
+void validate_mem(socket_info_t *s)
 {
     resource_map_t *m, *n;
     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
     static int hi = 0, lo = 0;
     u_long b, i, ok = 0;
-    
-    if (!probe_mem) return;
+    int force_low = !(s->cap.features & SS_CAP_PAGE_REGS);
+
+    if (!probe_mem)
+	return;
+
+    down(&rsrc_sem);
     /* We do up to four passes through the list */
     if (!force_low) {
-	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
-	    return;
+	if (hi++ || (inv_probe(mem_db.next, s) > 0))
+	    goto out;
 	printk(KERN_NOTICE "cs: warning: no high memory space "
 	       "available!\n");
     }
-    if (lo++) return;
+    if (lo++)
+	goto out;
     for (m = mem_db.next; m != &mem_db; m = n) {
 	n = m->next;
 	/* Only probe < 1 MB */
 	if (m->base >= 0x100000) continue;
 	if ((m->base | m->num) & 0xffff) {
-	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
+	    ok += do_mem_probe(m->base, m->num, s);
 	    continue;
 	}
 	/* Special probe for 64K-aligned block */
@@ -426,28 +487,31 @@
 		if (ok >= mem_limit)
 		    sub_interval(&mem_db, b, 0x10000);
 		else
-		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
+		    ok += do_mem_probe(b, 0x10000, s);
 	    }
 	}
     }
+ out:
+    up(&rsrc_sem);
 }
 
-#else /* CONFIG_ISA */
+#else /* CONFIG_PCMCIA_PROBE */
 
-void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low, socket_info_t *s)
+void validate_mem(socket_info_t *s)
 {
     resource_map_t *m;
     static int done = 0;
     
-    if (!probe_mem || done++)
-	return;
-    for (m = mem_db.next; m != &mem_db; m = m->next)
-	if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
-	    return;
+    if (probe_mem && done++ == 0) {
+	down(&rsrc_sem);
+	for (m = mem_db.next; m != &mem_db; m = m->next)
+	    if (do_mem_probe(m->base, m->num, s))
+		break;
+	up(&rsrc_sem);
+    }
 }
 
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_PCMCIA_PROBE */
 
 /*======================================================================
 
@@ -467,7 +531,9 @@
 {
     ioaddr_t try;
     resource_map_t *m;
-    
+    int ret = -1;
+
+    down(&rsrc_sem);
     for (m = io_db.next; m != &io_db; m = m->next) {
 	try = (m->base & ~(align-1)) + *base;
 	for (try = (try >= m->base) ? try : try+align;
@@ -475,12 +541,16 @@
 	     try += align) {
 	    if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
 		*base = try;
-		return 0;
+		ret = 0;
+		goto out;
 	    }
-	    if (!align) break;
+	    if (!align)
+		break;
 	}
     }
-    return -1;
+ out:
+    up(&rsrc_sem);
+    return ret;
 }
 
 int find_mem_region(u_long *base, u_long num, u_long align,
@@ -488,26 +558,35 @@
 {
     u_long try;
     resource_map_t *m;
+    int ret = -1;
 
+    down(&rsrc_sem);
     while (1) {
 	for (m = mem_db.next; m != &mem_db; m = m->next) {
 	    /* first pass >1MB, second pass <1MB */
-	    if ((force_low != 0) ^ (m->base < 0x100000)) continue;
+	    if ((force_low != 0) ^ (m->base < 0x100000))
+		continue;
+
 	    try = (m->base & ~(align-1)) + *base;
 	    for (try = (try >= m->base) ? try : try+align;
 		 (try >= m->base) && (try+num <= m->base+m->num);
 		 try += align) {
 		if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
 		    *base = try;
-		    return 0;
+		    ret = 0;
+		    goto out;
 		}
-		if (!align) break;
+		if (!align)
+		    break;
 	    }
 	}
-	if (force_low) break;
+	if (force_low)
+	    break;
 	force_low++;
     }
-    return -1;
+ out:
+    up(&rsrc_sem);
+    return ret;
 }
 
 /*======================================================================
@@ -518,7 +597,7 @@
     
 ======================================================================*/
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
 
 static void fake_irq(int i, void *d, struct pt_regs *r) { }
 static inline int check_irq(int irq)
@@ -532,66 +611,89 @@
 int try_irq(u_int Attributes, int irq, int specific)
 {
     irq_info_t *info = &irq_table[irq];
+    int ret = 0;
+
+    down(&rsrc_sem);
     if (info->Attributes & RES_ALLOCATED) {
 	switch (Attributes & IRQ_TYPE) {
 	case IRQ_TYPE_EXCLUSIVE:
-	    return CS_IN_USE;
+	    ret = CS_IN_USE;
+	    break;
 	case IRQ_TYPE_TIME:
 	    if ((info->Attributes & RES_IRQ_TYPE)
-		!= RES_IRQ_TYPE_TIME)
-		return CS_IN_USE;
-	    if (Attributes & IRQ_FIRST_SHARED)
-		return CS_BAD_ATTRIBUTE;
+		!= RES_IRQ_TYPE_TIME) {
+		ret = CS_IN_USE;
+		break;
+	    }
+	    if (Attributes & IRQ_FIRST_SHARED) {
+		ret = CS_BAD_ATTRIBUTE;
+		break;
+	    }
 	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
 	    info->time_share++;
 	    break;
 	case IRQ_TYPE_DYNAMIC_SHARING:
 	    if ((info->Attributes & RES_IRQ_TYPE)
-		!= RES_IRQ_TYPE_DYNAMIC)
-		return CS_IN_USE;
-	    if (Attributes & IRQ_FIRST_SHARED)
-		return CS_BAD_ATTRIBUTE;
+		!= RES_IRQ_TYPE_DYNAMIC) {
+		ret = CS_IN_USE;
+		break;
+	    }
+	    if (Attributes & IRQ_FIRST_SHARED) {
+		ret = CS_BAD_ATTRIBUTE;
+		break;
+	    }
 	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
 	    info->dyn_share++;
 	    break;
 	}
     } else {
-	if ((info->Attributes & RES_RESERVED) && !specific)
-	    return CS_IN_USE;
-	if (check_irq(irq) != 0)
-	    return CS_IN_USE;
+	if ((info->Attributes & RES_RESERVED) && !specific) {
+	    ret = CS_IN_USE;
+	    goto out;
+	}
+	if (check_irq(irq) != 0) {
+	    ret = CS_IN_USE;
+	    goto out;
+	}
 	switch (Attributes & IRQ_TYPE) {
 	case IRQ_TYPE_EXCLUSIVE:
 	    info->Attributes |= RES_ALLOCATED;
 	    break;
 	case IRQ_TYPE_TIME:
-	    if (!(Attributes & IRQ_FIRST_SHARED))
-		return CS_BAD_ATTRIBUTE;
+	    if (!(Attributes & IRQ_FIRST_SHARED)) {
+		ret = CS_BAD_ATTRIBUTE;
+		break;
+	    }
 	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
 	    info->time_share = 1;
 	    break;
 	case IRQ_TYPE_DYNAMIC_SHARING:
-	    if (!(Attributes & IRQ_FIRST_SHARED))
-		return CS_BAD_ATTRIBUTE;
+	    if (!(Attributes & IRQ_FIRST_SHARED)) {
+		ret = CS_BAD_ATTRIBUTE;
+		break;
+	    }
 	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
 	    info->dyn_share = 1;
 	    break;
 	}
     }
-    return 0;
+ out:
+    up(&rsrc_sem);
+    return ret;
 }
 
 #endif
 
 /*====================================================================*/
 
-#ifdef CONFIG_ISA
+#ifdef CONFIG_PCMCIA_PROBE
 
 void undo_irq(u_int Attributes, int irq)
 {
     irq_info_t *info;
 
     info = &irq_table[irq];
+    down(&rsrc_sem);
     switch (Attributes & IRQ_TYPE) {
     case IRQ_TYPE_EXCLUSIVE:
 	info->Attributes &= RES_RESERVED;
@@ -607,6 +709,7 @@
 	    info->Attributes &= RES_RESERVED;
 	break;
     }
+    up(&rsrc_sem);
 }
 
 #endif
@@ -629,6 +732,8 @@
 	return CS_BAD_SIZE;
 
     ret = CS_SUCCESS;
+
+    down(&rsrc_sem);
     switch (adj->Action) {
     case ADD_MANAGED_RESOURCE:
 	ret = add_interval(&mem_db, base, num);
@@ -647,6 +752,7 @@
     default:
 	ret = CS_UNSUPPORTED_FUNCTION;
     }
+    up(&rsrc_sem);
     
     return ret;
 }
@@ -655,7 +761,7 @@
 
 static int adjust_io(adjust_t *adj)
 {
-    int base, num;
+    int base, num, ret = CS_SUCCESS;
     
     base = adj->resource.io.BasePort;
     num = adj->resource.io.NumPorts;
@@ -664,11 +770,14 @@
     if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
 	return CS_BAD_SIZE;
 
+    down(&rsrc_sem);
     switch (adj->Action) {
     case ADD_MANAGED_RESOURCE:
-	if (add_interval(&io_db, base, num) != 0)
-	    return CS_IN_USE;
-#ifdef CONFIG_ISA
+	if (add_interval(&io_db, base, num) != 0) {
+	    ret = CS_IN_USE;
+	    break;
+	}
+#ifdef CONFIG_PCMCIA_PROBE
 	if (probe_io)
 	    do_io_probe(base, num);
 #endif
@@ -677,18 +786,20 @@
 	sub_interval(&io_db, base, num);
 	break;
     default:
-	return CS_UNSUPPORTED_FUNCTION;
+	ret = CS_UNSUPPORTED_FUNCTION;
 	break;
     }
+    up(&rsrc_sem);
 
-    return CS_SUCCESS;
+    return ret;
 }
 
 /*====================================================================*/
 
 static int adjust_irq(adjust_t *adj)
 {
-#ifdef CONFIG_ISA
+    int ret = CS_SUCCESS;
+#ifdef CONFIG_PCMCIA_PROBE
     int irq;
     irq_info_t *info;
     
@@ -696,33 +807,41 @@
     if ((irq < 0) || (irq > 15))
 	return CS_BAD_IRQ;
     info = &irq_table[irq];
-    
+
+    down(&rsrc_sem);
     switch (adj->Action) {
     case ADD_MANAGED_RESOURCE:
 	if (info->Attributes & RES_REMOVED)
 	    info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
 	else
-	    if (adj->Attributes & RES_ALLOCATED)
-		return CS_IN_USE;
+	    if (adj->Attributes & RES_ALLOCATED) {
+		ret = CS_IN_USE;
+		break;
+	    }
 	if (adj->Attributes & RES_RESERVED)
 	    info->Attributes |= RES_RESERVED;
 	else
 	    info->Attributes &= ~RES_RESERVED;
 	break;
     case REMOVE_MANAGED_RESOURCE:
-	if (info->Attributes & RES_REMOVED)
-	    return 0;
-	if (info->Attributes & RES_ALLOCATED)
-	    return CS_IN_USE;
+	if (info->Attributes & RES_REMOVED) {
+	    ret = 0;
+	    break;
+	}
+	if (info->Attributes & RES_ALLOCATED) {
+	    ret = CS_IN_USE;
+	    break;
+	}
 	info->Attributes |= RES_ALLOCATED|RES_REMOVED;
 	info->Attributes &= ~RES_RESERVED;
 	break;
     default:
-	return CS_UNSUPPORTED_FUNCTION;
+	ret = CS_UNSUPPORTED_FUNCTION;
 	break;
     }
+    up(&rsrc_sem);
 #endif
-    return CS_SUCCESS;
+    return ret;
 }
 
 /*====================================================================*/
diff -urN linux-2.5.66-bk2/drivers/pcmcia/sa1100_generic.c linux-2.5.66-bk3/drivers/pcmcia/sa1100_generic.c
--- linux-2.5.66-bk2/drivers/pcmcia/sa1100_generic.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/sa1100_generic.c	Mon Mar 31 12:48:53 2003
@@ -52,7 +52,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bus_ops.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -567,31 +566,6 @@
 }  /* sa1100_pcmcia_set_socket() */
 
 
-/* sa1100_pcmcia_get_io_map()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the get_io_map() operation for the in-kernel PCMCIA
- * service (formerly SS_GetIOMap in Card Services). Just returns an
- * I/O map descriptor which was assigned earlier by a set_io_map().
- *
- * Returns: 0 on success, -1 if the map index was out of range
- */
-static int
-sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  int ret = -1;
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if (map->map < MAX_IO_WIN) {
-    *map = skt->io_map[map->map];
-    ret = 0;
-  }
-
-  return ret;
-}
-
-
 /* sa1100_pcmcia_set_io_map()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the set_io_map() operation for the in-kernel PCMCIA
@@ -646,32 +620,6 @@
 }  /* sa1100_pcmcia_set_io_map() */
 
 
-/* sa1100_pcmcia_get_mem_map()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the get_mem_map() operation for the in-kernel PCMCIA
- * service (formerly SS_GetMemMap in Card Services). Just returns a
- *  memory map descriptor which was assigned earlier by a
- *  set_mem_map() request.
- *
- * Returns: 0 on success, -1 if the map index was out of range
- */
-static int
-sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  int ret = -1;
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if (map->map < MAX_WIN) {
-    *map = skt->pc_mem_map[map->map];
-    ret = 0;
-  }
-
-  return ret;
-}
-
-
 /* sa1100_pcmcia_set_mem_map()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the set_mem_map() operation for the in-kernel PCMCIA
@@ -841,9 +789,7 @@
   .get_status		= sa1100_pcmcia_get_status,
   .get_socket		= sa1100_pcmcia_get_socket,
   .set_socket		= sa1100_pcmcia_set_socket,
-  .get_io_map		= sa1100_pcmcia_get_io_map,
   .set_io_map		= sa1100_pcmcia_set_io_map,
-  .get_mem_map		= sa1100_pcmcia_get_mem_map,
   .set_mem_map		= sa1100_pcmcia_set_mem_map,
 #ifdef CONFIG_PROC_FS
   .proc_setup		= sa1100_pcmcia_proc_setup
diff -urN linux-2.5.66-bk2/drivers/pcmcia/tcic.c linux-2.5.66-bk3/drivers/pcmcia/tcic.c
--- linux-2.5.66-bk2/drivers/pcmcia/tcic.c	Mon Mar 24 14:00:45 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/tcic.c	Mon Mar 31 12:48:53 2003
@@ -806,44 +806,6 @@
   
 /*====================================================================*/
 
-static int tcic_get_io_map(unsigned int lsock, struct pccard_io_map *io)
-{
-    u_short psock = socket_table[lsock].psock;
-    u_short base, ioctl;
-    u_int addr;
-    
-    if (io->map > 1) return -EINVAL;
-    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
-    addr = TCIC_IWIN(psock, io->map);
-    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
-    base = tcic_getw(TCIC_DATA);
-    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
-    ioctl = tcic_getw(TCIC_DATA);
-
-    if (ioctl & TCIC_ICTL_TINY)
-	io->start = io->stop = base;
-    else {
-	io->start = base & (base-1);
-	io->stop = io->start + (base ^ (base-1));
-    }
-    io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK);
-    io->flags  = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0;
-    switch (ioctl & TCIC_ICTL_BW_MASK) {
-    case TCIC_ICTL_BW_DYN:
-	io->flags |= MAP_AUTOSZ; break;
-    case TCIC_ICTL_BW_16:
-	io->flags |= MAP_16BIT; break;
-    default:
-	break;
-    }
-    DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, "
-	  "%#4.4x-%#4.4x\n", lsock, io->map, io->flags,
-	  io->speed, io->start, io->stop);
-    return 0;
-} /* tcic_get_io_map */
-
-/*====================================================================*/
-
 static int tcic_set_io_map(unsigned int lsock, struct pccard_io_map *io)
 {
     u_short psock = socket_table[lsock].psock;
@@ -881,51 +843,6 @@
 
 /*====================================================================*/
 
-static int tcic_get_mem_map(unsigned int lsock, struct pccard_mem_map *mem)
-{
-    u_short psock = socket_table[lsock].psock;
-    u_short addr, ctl;
-    u_long base, mmap;
-    
-    if (mem->map > 3) return -EINVAL;
-    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
-    addr = TCIC_MWIN(psock, mem->map);
-    
-    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
-    base = tcic_getw(TCIC_DATA);
-    if (base & TCIC_MBASE_4K_BIT) {
-	mem->sys_start = base & TCIC_MBASE_HA_MASK;
-	mem->sys_stop = mem->sys_start;
-    } else {
-	base &= TCIC_MBASE_HA_MASK;
-	mem->sys_start = (base & (base-1));
-	mem->sys_stop = mem->sys_start + (base ^ (base-1));
-    }
-    mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT;
-    mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff;
-    
-    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
-    mmap = tcic_getw(TCIC_DATA);
-    mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0;
-    mmap &= TCIC_MMAP_CA_MASK;
-    mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT);
-    mem->card_start &= 0x3ffffff;
-    
-    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
-    ctl = tcic_getw(TCIC_DATA);
-    mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0;
-    mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT;
-    mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0;
-    mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK);
-    
-    DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, "
-	  "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags,
-	  mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
-    return 0;
-} /* tcic_get_mem_map */
-
-/*====================================================================*/
-  
 static int tcic_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem)
 {
     u_short psock = socket_table[lsock].psock;
@@ -1007,9 +924,7 @@
 	.get_status	   = tcic_get_status,
 	.get_socket	   = tcic_get_socket,
 	.set_socket	   = tcic_set_socket,
-	.get_io_map	   = tcic_get_io_map,
 	.set_io_map	   = tcic_set_io_map,
-	.get_mem_map	   = tcic_get_mem_map,
 	.set_mem_map	   = tcic_set_mem_map,
 	.proc_setup	   = tcic_proc_setup,
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/ti113x.h linux-2.5.66-bk3/drivers/pcmcia/ti113x.h
--- linux-2.5.66-bk2/drivers/pcmcia/ti113x.h	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/ti113x.h	Mon Mar 31 12:48:53 2003
@@ -185,9 +185,7 @@
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
-	yenta_get_io_map,
 	yenta_set_io_map,
-	yenta_get_mem_map,
 	yenta_set_mem_map,
 	yenta_proc_setup
 };
@@ -230,9 +228,7 @@
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
-	yenta_get_io_map,
 	yenta_set_io_map,
-	yenta_get_mem_map,
 	yenta_set_mem_map,
 	yenta_proc_setup
 };
@@ -272,9 +268,7 @@
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
-	yenta_get_io_map,
 	yenta_set_io_map,
-	yenta_get_mem_map,
 	yenta_set_mem_map,
 	yenta_proc_setup
 };
diff -urN linux-2.5.66-bk2/drivers/pcmcia/yenta.c linux-2.5.66-bk3/drivers/pcmcia/yenta.c
--- linux-2.5.66-bk2/drivers/pcmcia/yenta.c	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/drivers/pcmcia/yenta.c	Mon Mar 31 12:48:53 2003
@@ -27,7 +27,7 @@
 #include "i82365.h"
 
 #if 0
-#define DEBUG(x,args...)	printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x,args...)	printk("%s: " x, __FUNCTION__, ##args)
 #else
 #define DEBUG(x,args...)
 #endif
@@ -300,29 +300,6 @@
 	return 0;
 }
 
-static int yenta_get_io_map(pci_socket_t *socket, struct pccard_io_map *io)
-{
-	int map;
-	unsigned char ioctl, addr;
-
-	map = io->map;
-	if (map > 1)
-		return -EINVAL;
-
-	io->start = exca_readw(socket, I365_IO(map)+I365_W_START);
-	io->stop = exca_readw(socket, I365_IO(map)+I365_W_STOP);
-
-	ioctl = exca_readb(socket, I365_IOCTL);
-	addr = exca_readb(socket, I365_ADDRWIN);
-	io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
-	io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
-	io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
-	io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
-	io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
-
-	return 0;
-}
-
 static int yenta_set_io_map(pci_socket_t *socket, struct pccard_io_map *io)
 {
 	int map;
@@ -356,41 +333,6 @@
 	return 0;
 }
 
-static int yenta_get_mem_map(pci_socket_t *socket, struct pccard_mem_map *mem)
-{
-	int map;
-	unsigned char addr;
-	unsigned int start, stop, page, offset;
-
-	map = mem->map;
-	if (map > 4)
-		return -EINVAL;
-
-	addr = exca_readb(socket, I365_ADDRWIN);
-	mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
-
-	start = exca_readw(socket, I365_MEM(map) + I365_W_START);
-	mem->flags |= (start & I365_MEM_16BIT) ? MAP_16BIT : 0;
-	mem->flags |= (start & I365_MEM_0WS) ? MAP_0WS : 0;
-	start = (start & 0x0fff) << 12;
-
-	stop = exca_readw(socket, I365_MEM(map) + I365_W_STOP);
-	mem->speed = to_ns(stop >> 14);
-	stop = ((stop & 0x0fff) << 12) + 0x0fff;
-
-	offset = exca_readw(socket, I365_MEM(map) + I365_W_OFF);
-	mem->flags |= (offset & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
-	mem->flags |= (offset & I365_MEM_REG) ? MAP_ATTRIB : 0;
-	offset = ((offset & 0x3fff) << 12) + start;
-	mem->card_start = offset & 0x3ffffff;
-
-	page = exca_readb(socket, CB_MEM_PAGE(map)) << 24;
-	mem->sys_start = start + page;
-	mem->sys_stop = start + page;
-
-	return 0;
-}
-
 static int yenta_set_mem_map(pci_socket_t *socket, struct pccard_mem_map *mem)
 {
 	int map;
@@ -572,7 +514,6 @@
 	socket->cap.pci_irq = socket->cb_irq;
 	socket->cap.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
 	socket->cap.cb_dev = socket->dev;
-	socket->cap.bus = NULL;
 
 	printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
 }
@@ -935,9 +876,7 @@
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
-	yenta_get_io_map,
 	yenta_set_io_map,
-	yenta_get_mem_map,
 	yenta_set_mem_map,
 	yenta_proc_setup
 };
diff -urN linux-2.5.66-bk2/drivers/scsi/pcmcia/nsp_cs.c linux-2.5.66-bk3/drivers/scsi/pcmcia/nsp_cs.c
--- linux-2.5.66-bk2/drivers/scsi/pcmcia/nsp_cs.c	Mon Mar 24 14:01:47 2003
+++ linux-2.5.66-bk3/drivers/scsi/pcmcia/nsp_cs.c	Mon Mar 31 12:48:53 2003
@@ -62,7 +62,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
 
 #include "nsp_cs.h"
 
@@ -93,7 +92,6 @@
 	int	               ndev;
 	dev_node_t             node[8];
 	int                    stop;
-	struct bus_operations *bus;
 } scsi_info_t;
 
 
@@ -1948,7 +1946,6 @@
 	case CS_EVENT_CARD_INSERTION:
 		DEBUG(0, " event: insert\n");
 		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-		info->bus    =  args->bus;
 		nsp_cs_config(link);
 		break;
 
diff -urN linux-2.5.66-bk2/drivers/serial/21285.c linux-2.5.66-bk3/drivers/serial/21285.c
--- linux-2.5.66-bk2/drivers/serial/21285.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/drivers/serial/21285.c	Mon Mar 31 12:48:53 2003
@@ -501,10 +501,11 @@
 	.index		= -1,
 };
 
-static void __init rs285_console_init(void)
+static int __init rs285_console_init(void)
 {
 	serial21285_setup_ports();
 	register_console(&serial21285_console);
+	return 0;
 }
 console_initcall(rs285_console_init);
 
diff -urN linux-2.5.66-bk2/drivers/usb/Makefile linux-2.5.66-bk3/drivers/usb/Makefile
--- linux-2.5.66-bk2/drivers/usb/Makefile	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/drivers/usb/Makefile	Mon Mar 31 12:48:53 2003
@@ -14,6 +14,7 @@
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_AUDIO)		+= class/
 obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= class/
+obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
diff -urN linux-2.5.66-bk2/drivers/usb/class/audio.c linux-2.5.66-bk3/drivers/usb/class/audio.c
--- linux-2.5.66-bk2/drivers/usb/class/audio.c	Mon Mar 24 14:01:47 2003
+++ linux-2.5.66-bk3/drivers/usb/class/audio.c	Mon Mar 31 12:48:53 2003
@@ -172,7 +172,6 @@
 
 /*****************************************************************************/
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
diff -urN linux-2.5.66-bk2/drivers/usb/class/cdc-acm.c linux-2.5.66-bk3/drivers/usb/class/cdc-acm.c
--- linux-2.5.66-bk2/drivers/usb/class/cdc-acm.c	Mon Mar 24 14:00:54 2003
+++ linux-2.5.66-bk3/drivers/usb/class/cdc-acm.c	Mon Mar 31 12:48:53 2003
@@ -538,7 +538,7 @@
 
 		cfacm = dev->config + i;
 
-		dbg("probing config %d", cfacm->bConfigurationValue);
+		dbg("probing config %d", cfacm->desc.bConfigurationValue);
 
 		if (cfacm->desc.bNumInterfaces != 2 ||
 		    usb_interface_claimed(cfacm->interface + 0) ||
diff -urN linux-2.5.66-bk2/drivers/usb/core/buffer.c linux-2.5.66-bk3/drivers/usb/core/buffer.c
--- linux-2.5.66-bk2/drivers/usb/core/buffer.c	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk3/drivers/usb/core/buffer.c	Mon Mar 31 12:48:53 2003
@@ -7,7 +7,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
diff -urN linux-2.5.66-bk2/drivers/usb/core/hcd.c linux-2.5.66-bk3/drivers/usb/core/hcd.c
--- linux-2.5.66-bk2/drivers/usb/core/hcd.c	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk3/drivers/usb/core/hcd.c	Mon Mar 31 12:48:53 2003
@@ -1024,9 +1024,7 @@
 		 */
 		urb->transfer_flags |= URB_NO_DMA_MAP;
 		status = rh_urb_enqueue (hcd, urb);
-		if (status)
-			urb_unlink (urb);
-		return status;
+		goto done;
 	}
 
 	/* lower level hcd code should use *_dma exclusively,
@@ -1051,8 +1049,11 @@
 	}
 
 	status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	if (status)
+done:
+	if (status) {
+		usb_put_urb (urb);
 		urb_unlink (urb);
+	}
 	return status;
 }
 
diff -urN linux-2.5.66-bk2/drivers/usb/core/hub.c linux-2.5.66-bk3/drivers/usb/core/hub.c
--- linux-2.5.66-bk2/drivers/usb/core/hub.c	Mon Mar 24 14:00:24 2003
+++ linux-2.5.66-bk3/drivers/usb/core/hub.c	Mon Mar 31 12:48:53 2003
@@ -135,8 +135,7 @@
 
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
-		dbg("hub '%s' status %d for interrupt transfer",
-			urb->dev->devpath, urb->status);
+		dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status);
 		if ((++hub->nerrors < 10) || hub->error)
 			goto resubmit;
 		hub->error = urb->status;
@@ -158,10 +157,10 @@
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
 resubmit:
-	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0)
-		err ("hub '%s-%s' status %d for interrupt resubmit",
-			urb->dev->bus->bus_name, urb->dev->devpath,
-			status);
+	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
+			/* ENODEV means we raced disconnect() */
+			&& status != -ENODEV)
+		dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
 }
 
 /* USB 2.0 spec Section 11.24.2.3 */
@@ -648,12 +647,13 @@
 	struct usb_port_status *portsts;
 	int ret = -ENOMEM;
 
-	portsts = kmalloc(sizeof(*portsts), GFP_KERNEL);
+	portsts = kmalloc(sizeof(*portsts), GFP_NOIO);
 	if (portsts) {
 		ret = usb_get_port_status(hub, port + 1, portsts);
 		if (ret < 0)
-			err("%s(%s-%s) failed (err = %d)", __FUNCTION__,
-				hub->bus->bus_name, hub->devpath, ret);
+			dev_err (hubdev (hub),
+				"%s failed (err = %d)\n", __FUNCTION__,
+				ret);
 		else {
 			*status = le16_to_cpu(portsts->wPortStatus);
 			*change = le16_to_cpu(portsts->wPortChange); 
@@ -759,8 +759,8 @@
 
 	ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
 	if (ret)
-		err("cannot disable port %d of hub %s (err = %d)",
-			port + 1, hub->devpath, ret);
+		dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
+			port + 1, ret);
 }
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
@@ -983,12 +983,12 @@
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
-			dbg("resetting hub %s for error %d",
-				dev->devpath, hub->error);
+			dev_dbg (&hub->intf->dev, "resetting for error %d\n",
+				hub->error);
 
 			if (usb_hub_reset(hub)) {
-				err("error resetting hub %s - disconnecting",
-					dev->devpath);
+				dev_dbg (&hub->intf->dev,
+					"can't reset; disconnecting\n");
 				up(&hub->khubd_sem);
 				usb_hub_disconnect(dev);
 				continue;
@@ -1022,33 +1022,37 @@
 				if (!(portstatus & USB_PORT_STAT_ENABLE)
 				    && (portstatus & USB_PORT_STAT_CONNECTION)
 				    && (dev->children[i])) {
-					err("already running hub %s port %i "
+					dev_err (&hub->intf->dev,
+					    "port %i "
 					    "disabled by hub (EMI?), "
 					    "re-enabling...",
-						dev->devpath, i + 1);
+						i + 1);
 					usb_hub_port_connect_change(hub,
 						i, portstatus, portchange);
 				}
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				dbg("hub %s port %d suspend change",
-					dev->devpath, i + 1);
+				dev_dbg (&hub->intf->dev,
+					"suspend change on port %d\n",
+					i + 1);
 				usb_clear_port_feature(dev,
 					i + 1,  USB_PORT_FEAT_C_SUSPEND);
 			}
 			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-				err("hub %s port %d over-current change",
-					dev->devpath, i + 1);
+				dev_err (&hub->intf->dev,
+					"over-current change on port %d\n",
+					i + 1);
 				usb_clear_port_feature(dev,
 					i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
 				usb_hub_power_on(hub);
 			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				dbg("hub %s port %d reset change",
-					dev->devpath, i + 1);
+				dev_dbg (&hub->intf->dev,
+					"reset change on port %d\n",
+					i + 1);
 				usb_clear_port_feature(dev,
 					i + 1, USB_PORT_FEAT_C_RESET);
 			}
@@ -1056,16 +1060,16 @@
 
 		/* deal with hub status changes */
 		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status %s failed", dev->devpath);
+			dev_err (&hub->intf->dev, "get_hub_status failed\n");
 		else {
 			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
 			hubchange = le16_to_cpup(&hubsts.wHubChange);
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub %s power change", dev->devpath);
+				dev_dbg (&hub->intf->dev, "power change\n");
 				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub %s overcurrent change", dev->devpath);
+				dev_dbg (&hub->intf->dev, "overcurrent change\n");
 				wait_ms(500);	/* Cool down */
 				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                         	usb_hub_power_on(hub);
diff -urN linux-2.5.66-bk2/drivers/usb/core/message.c linux-2.5.66-bk3/drivers/usb/core/message.c
--- linux-2.5.66-bk2/drivers/usb/core/message.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk3/drivers/usb/core/message.c	Mon Mar 31 12:48:53 2003
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <asm/byteorder.h>
 
 #include "hcd.h"	/* for usbcore internals */
diff -urN linux-2.5.66-bk2/drivers/usb/core/usb-debug.c linux-2.5.66-bk3/drivers/usb/core/usb-debug.c
--- linux-2.5.66-bk2/drivers/usb/core/usb-debug.c	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk3/drivers/usb/core/usb-debug.c	Mon Mar 31 12:48:53 2003
@@ -5,7 +5,6 @@
  * face, but so that you can still use them..
  */
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
diff -urN linux-2.5.66-bk2/drivers/usb/core/usb.c linux-2.5.66-bk3/drivers/usb/core/usb.c
--- linux-2.5.66-bk2/drivers/usb/core/usb.c	Mon Mar 24 14:00:39 2003
+++ linux-2.5.66-bk3/drivers/usb/core/usb.c	Mon Mar 31 12:48:53 2003
@@ -866,14 +866,11 @@
 }
 
 /**
- * usb_connect - connects a new device during enumeration (usbcore-internal)
- * @dev: partially enumerated device
- *
- * Connect a new USB device. This basically just initializes
- * the USB device information and sets up the topology - it's
- * up to the low-level driver to reset the port and actually
- * do the setup (the upper levels don't know how to do that).
+ * usb_connect - pick device address (usbcore-internal)
+ * @dev: newly detected device (in DEFAULT state)
  *
+ * Picks a device address.  It's up to the hub (or root hub) driver
+ * to handle and manage enumeration, starting from the DEFAULT state.
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
  */
@@ -983,7 +980,7 @@
 }
 
 /*
- * By the time we get here, the device has gotten a new device ID
+ * By the time we get here, we chose a new device address
  * and is in the default state. We need to identify the thing and
  * get the ball rolling..
  *
diff -urN linux-2.5.66-bk2/drivers/usb/host/ohci-hcd.c linux-2.5.66-bk3/drivers/usb/host/ohci-hcd.c
--- linux-2.5.66-bk2/drivers/usb/host/ohci-hcd.c	Mon Mar 24 14:00:00 2003
+++ linux-2.5.66-bk3/drivers/usb/host/ohci-hcd.c	Mon Mar 31 12:48:53 2003
@@ -94,7 +94,6 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>  /* for in_interrupt () */
 #include <linux/usb.h>
-#include <linux/version.h>
 #include "../core/hcd.h"
 
 #include <asm/io.h>
diff -urN linux-2.5.66-bk2/drivers/usb/image/mdc800.c linux-2.5.66-bk3/drivers/usb/image/mdc800.c
--- linux-2.5.66-bk2/drivers/usb/image/mdc800.c	Mon Mar 24 14:00:44 2003
+++ linux-2.5.66-bk3/drivers/usb/image/mdc800.c	Mon Mar 31 12:48:53 2003
@@ -85,7 +85,6 @@
  * (20/10/1999)
  */
 
-#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/spinlock.h>
diff -urN linux-2.5.66-bk2/drivers/usb/media/ov511.c linux-2.5.66-bk3/drivers/usb/media/ov511.c
--- linux-2.5.66-bk2/drivers/usb/media/ov511.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk3/drivers/usb/media/ov511.c	Mon Mar 31 12:48:53 2003
@@ -36,7 +36,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
diff -urN linux-2.5.66-bk2/drivers/usb/media/stv680.c linux-2.5.66-bk3/drivers/usb/media/stv680.c
--- linux-2.5.66-bk2/drivers/usb/media/stv680.c	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk3/drivers/usb/media/stv680.c	Mon Mar 31 12:48:53 2003
@@ -60,7 +60,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
diff -urN linux-2.5.66-bk2/drivers/usb/misc/emi26.c linux-2.5.66-bk3/drivers/usb/misc/emi26.c
--- linux-2.5.66-bk2/drivers/usb/misc/emi26.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk3/drivers/usb/misc/emi26.c	Mon Mar 31 12:48:53 2003
@@ -78,19 +78,28 @@
 	return response;
 }
 
+#define FW_LOAD_SIZE		1023
+
 static int emi26_load_firmware (struct usb_device *dev)
 {
 	int err;
 	int i;
 	int pos = 0;	/* Position in hex record */
 	__u32 addr;	/* Address to write */
-	__u8 buf[1023];
+	__u8 *buf;
+
+	buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
+	if (!buf) {
+		err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM);
+		err = -ENOMEM;
+		goto wraperr;
+	}
 
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
 		err( "%s - error loading firmware: error = %d", __FUNCTION__, err);
-		return err;
+		goto wraperr;
 	}
 
 	/* 1. We need to put the loader for the FPGA into the EZ-USB */
@@ -98,7 +107,7 @@
 		err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
 		if (err < 0) {
 			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-			return err;
+			goto wraperr;
 		}
 	}
 
@@ -113,7 +122,7 @@
 		addr = g_bitstream[pos].address;
 
 		/* intel hex records are terminated with type 0 element */
-		while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < sizeof(buf))) {
+		while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < FW_LOAD_SIZE)) {
 			memcpy(buf + i, g_bitstream[pos].data, g_bitstream[pos].length);
 			i += g_bitstream[pos].length;
 			pos++;
@@ -121,7 +130,7 @@
 		err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
 		if (err < 0) {
 			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-			return err;
+			goto wraperr;
 		}
 	} while (i > 0);
 
@@ -129,7 +138,7 @@
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
 		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-		return err;
+		goto wraperr;
 	}
 
 	/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
@@ -137,7 +146,7 @@
 		err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
 		if (err < 0) {
 			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-			return err;
+			goto wraperr;
 		}
 	}
 
@@ -145,7 +154,7 @@
 	err = emi26_set_reset(dev,0);
 	if (err < 0) {
 		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-		return err;
+		goto wraperr;
 	}
 
 	/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -154,7 +163,7 @@
 			err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL);
 			if (err < 0) {
 				err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-				return err;
+				goto wraperr;
 			}
 		}
 	}
@@ -163,7 +172,7 @@
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
 		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-		return err;
+		goto wraperr;
 	}
 
 	for (i=0; g_Firmware[i].type == 0; i++) {
@@ -171,7 +180,7 @@
 			err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL);
 			if (err < 0) {
 				err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-				return err;
+				goto wraperr;
 			}
 		}
 	}
@@ -180,12 +189,16 @@
 	err = emi26_set_reset(dev,0);
 	if (err < 0) {
 		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
-		return err;
+		goto wraperr;
 	}
 
 	/* return 1 to fail the driver inialization
 	 * and give real driver change to load */
 	return 1;
+
+wraperr:
+	kfree(buf);
+	return err;
 }
 
 static __devinitdata struct usb_device_id id_table [] = {
diff -urN linux-2.5.66-bk2/drivers/usb/misc/speedtch.c linux-2.5.66-bk3/drivers/usb/misc/speedtch.c
--- linux-2.5.66-bk2/drivers/usb/misc/speedtch.c	Mon Mar 24 14:01:50 2003
+++ linux-2.5.66-bk3/drivers/usb/misc/speedtch.c	Mon Mar 31 12:48:53 2003
@@ -148,27 +148,15 @@
 
 #define UDSL_SKB(x)		((struct udsl_control *)(x)->cb)
 
-struct atmsar_vcc_data {
-	struct atmsar_vcc_data *next;
-
-	/* general atmsar flags, per connection */
-	int flags;
-	int type;
-
-	/* connection specific non-atmsar data */
+struct udsl_vcc_data {
+	/* vpi/vci lookup */
+	struct list_head list;
+	short vpi;
+	int vci;
 	struct atm_vcc *vcc;
-	struct k_atm_aal_stats *stats;
-	unsigned short mtu;	/* max is actually  65k for AAL5... */
-
-	/* cell data */
-	unsigned int vp;
-	unsigned int vc;
-	unsigned char gfc;
-	unsigned char pti;
-	unsigned int headerFlags;
-	unsigned long atmHeader;
 
 	/* raw cell reassembly */
+	unsigned short mtu;
 	struct sk_buff *reasBuffer;
 };
 
@@ -186,7 +174,7 @@
 
 	/* atm device part */
 	struct atm_dev *atm_dev;
-	struct atmsar_vcc_data *atmsar_vcc_list;
+	struct list_head vcc_list;
 
 	/* receiving */
 	struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
@@ -258,73 +246,46 @@
 **  decode  **
 *************/
 
-#define ATM_HDR_VPVC_MASK		(ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
-#define ATMSAR_USE_53BYTE_CELL		0x1L
+static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *instance, short vpi, int vci)
+{
+	struct udsl_vcc_data *vcc;
 
-struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
-				       struct atmsar_vcc_data **ctx)
+	list_for_each_entry (vcc, &instance->vcc_list, list)
+		if ((vcc->vpi == vpi) && (vcc->vci == vci))
+			return vcc;
+	return NULL;
+}
+
+static struct sk_buff *udsl_decode_rawcell (struct udsl_instance_data *instance, struct sk_buff *skb, struct udsl_vcc_data **ctx)
 {
+	if (!instance || !skb || !ctx)
+		return NULL;
+	if (!skb->data || !skb->tail)
+		return NULL;
+
 	while (skb->len) {
 		unsigned char *cell = skb->data;
 		unsigned char *cell_payload;
-		struct atmsar_vcc_data *vcc = list;
-		unsigned long atmHeader =
-		    ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
-		    ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
-
-		dbg ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx);
-		dbg ("atmsar_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
-
-		if (!list || !skb || !ctx)
-			return NULL;
-		if (!skb->data || !skb->tail)
-			return NULL;
+		struct udsl_vcc_data *vcc;
+		short vpi;
+		int vci;
+
+		vpi = ((cell[0] & 0x0f) << 4) | (cell[1] >> 4);
+		vci = ((cell[1] & 0x0f) << 12) | (cell[2] << 4) | (cell[3] >> 4);
+
+		dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx);
+		dbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
 
 		/* here should the header CRC check be... */
 
-		/* look up correct vcc */
-		for (;
-		     vcc
-		     && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
-		     vcc = vcc->next);
-
-		dbg ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d", vcc,
-			(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
-			(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
-
-		if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
-			cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
-
-			switch (vcc->type) {
-			case ATM_AAL0:
-				/* case ATM_AAL1: when we have a decode AAL1 function... */
-				{
-					struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
-
-					if (tmp) {
-						memcpy (tmp->tail, cell_payload, 48);
-						skb_put (tmp, 48);
-
-						if (vcc->stats)
-							atomic_inc (&vcc->stats->rx);
-
-						skb_pull (skb,
-							  (vcc->
-							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
-							   52));
-						dbg
-						    ("atmsar_decode_rawcell returns ATM_AAL0 pdu 0x%p with length %d",
-						     tmp, tmp->len);
-						return tmp;
-					};
-				}
-				break;
-			case ATM_AAL1:
-			case ATM_AAL2:
-			case ATM_AAL34:
-				/* not supported */
-				break;
-			case ATM_AAL5:
+		if (!(vcc = udsl_find_vcc (instance, vpi, vci)))
+			dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d", vpi, vci);
+		else {
+			dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci);
+
+			if (skb->len >= 53) {
+				cell_payload = cell + 5;
+
 				if (!vcc->reasBuffer)
 					vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
 
@@ -347,43 +308,36 @@
 						/* the aal5 buffer ends here, cut the buffer. */
 						/* buffer will always have at least one whole cell, so */
 						/* don't need to check return from skb_pull */
-						skb_pull (skb,
-							  (vcc->
-							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
-							   52));
+						skb_pull (skb, 53);
 						*ctx = vcc;
 						tmp = vcc->reasBuffer;
 						vcc->reasBuffer = NULL;
 
-						dbg
-						    ("atmsar_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d",
-						     tmp, tmp->len);
+						dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
 						return tmp;
 					}
 				}
-				break;
-			};
-			/* flush the cell */
-			/* buffer will always contain at least one whole cell, so don't */
-			/* need to check return value from skb_pull */
-			skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
-		} else {
-			/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
-			if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
-			    NULL)
-				return NULL;
+				/* flush the cell */
+				/* buffer will always contain at least one whole cell, so don't */
+				/* need to check return value from skb_pull */
+				skb_pull (skb, 53);
+			} else {
+				/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+				if (skb_pull (skb, 53) == NULL)
+					return NULL;
+			}
 		}
 	}
 
 	return NULL;
-};
+}
 
-struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_buff *skb)
 {
 	uint crc = 0xffffffff;
 	uint length, pdu_crc, pdu_length;
 
-	dbg ("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+	dbg ("udsl_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
 
 	if (skb->len && (skb->len % 48))
 		return NULL;
@@ -393,20 +347,18 @@
 	    (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
 	pdu_length = ((length + 47 + 8) / 48) * 48;
 
-	dbg ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d",
-		skb->len, length, pdu_crc, pdu_length);
+	dbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb->len, length, pdu_crc, pdu_length);
 
 	/* is skb long enough ? */
 	if (skb->len < pdu_length) {
-		if (ctx->stats)
-			atomic_inc (&ctx->stats->rx_err);
+		if (ctx->vcc->stats)
+			atomic_inc (&ctx->vcc->stats->rx_err);
 		return NULL;
 	}
 
 	/* is skb too long ? */
 	if (skb->len > pdu_length) {
-		dbg ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d",
-			skb->len, pdu_length);
+		dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -> %d", skb->len, pdu_length);
 		/* buffer is too long. we can try to recover
 		 * if we discard the first part of the skb.
 		 * the crc will decide whether this was ok
@@ -418,9 +370,9 @@
 
 	/* check crc */
 	if (pdu_crc != crc) {
-		dbg ("atmsar_decode_aal5: crc check failed!");
-		if (ctx->stats)
-			atomic_inc (&ctx->stats->rx_err);
+		dbg ("udsl_decode_aal5: crc check failed!");
+		if (ctx->vcc->stats)
+			atomic_inc (&ctx->vcc->stats->rx_err);
 		return NULL;
 	}
 
@@ -428,19 +380,20 @@
 	skb_trim (skb, length);
 
 	/* update stats */
-	if (ctx->stats)
-		atomic_inc (&ctx->stats->rx);
+	if (ctx->vcc->stats)
+		atomic_inc (&ctx->vcc->stats->rx);
 
-	dbg ("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
+	dbg ("udsl_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
 	return skb;
-};
+}
 
 
 /*************
 **  encode  **
 *************/
 
-static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) {
+static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb)
+{
 	struct udsl_control *ctrl = UDSL_SKB (skb);
 	unsigned int i, zero_padding;
 	unsigned char zero = 0;
@@ -480,7 +433,8 @@
 	ctrl->aal5_trailer [7] = crc;
 }
 
-unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) {
+static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p)
+{
 	struct udsl_control *ctrl = UDSL_SKB (skb);
 	unsigned char *target = *target_p;
 	unsigned int nc, ne, i;
@@ -569,7 +523,7 @@
 	unsigned char *data_start;
 	struct sk_buff *skb;
 	struct urb *urb;
-	struct atmsar_vcc_data *atmsar_vcc = NULL;
+	struct udsl_vcc_data *atmsar_vcc = NULL;
 	struct sk_buff *new = NULL, *tmp = NULL;
 	int err;
 
@@ -597,40 +551,28 @@
 			dbg ("skb->len = %d", skb->len);
 			PACKETDEBUG (skb->data, skb->len);
 
-			while ((new =
-				atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
-						       &atmsar_vcc)) != NULL) {
+			while ((new = udsl_decode_rawcell (instance, skb, &atmsar_vcc))) {
 				dbg ("(after cell processing)skb->len = %d", new->len);
 
-				switch (atmsar_vcc->type) {
-				case ATM_AAL5:
-					tmp = new;
-					new = atmsar_decode_aal5 (atmsar_vcc, new);
-
-					/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
-					if (new) {
-						dbg ("(after aal5 decap) skb->len = %d", new->len);
-						if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
-							PACKETDEBUG (new->data, new->len);
-							atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
-						} else {
-							dbg
-							    ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d",
-							     atomic_read (&atmsar_vcc->vcc->rx_inuse),
-							     atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
-							dev_kfree_skb (new);
-						}
+				tmp = new;
+				new = udsl_decode_aal5 (atmsar_vcc, new);
+
+				/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
+				if (new) {
+					dbg ("(after aal5 decap) skb->len = %d", new->len);
+					if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
+						PACKETDEBUG (new->data, new->len);
+						atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
 					} else {
-						dbg ("atmsar_decode_aal5 returned NULL!");
-						dev_kfree_skb (tmp);
+						dbg
+						    ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d",
+						     atomic_read (&atmsar_vcc->vcc->rx_inuse),
+						     atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
+						dev_kfree_skb (new);
 					}
-					break;
-				default:
-					/* not supported. we delete the skb. */
-					printk (KERN_INFO
-						"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
-					dev_kfree_skb (new);
-					break;
+				} else {
+					dbg ("udsl_decode_aal5 returned NULL!");
+					dev_kfree_skb (tmp);
 				}
 			}
 
@@ -901,95 +843,6 @@
 **  ATM  **
 **********/
 
-#define ATMSAR_DEF_MTU_AAL0		48
-#define ATMSAR_DEF_MTU_AAL1		47
-#define ATMSAR_DEF_MTU_AAL2		0  /* not supported */
-#define ATMSAR_DEF_MTU_AAL34		0  /* not supported */
-#define ATMSAR_DEF_MTU_AAL5		65535  /* max mtu ..    */
-
-struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
-				     ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
-{
-	struct atmsar_vcc_data *new;
-
-	if (!vcc)
-		return NULL;
-
-	new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
-
-	if (!new)
-		return NULL;
-
-	memset (new, 0, sizeof (struct atmsar_vcc_data));
-	new->vcc = vcc;
-	new->stats = vcc->stats;
-	new->type = type;
-	new->next = NULL;
-	new->gfc = gfc;
-	new->vp = vpi;
-	new->vc = vci;
-	new->pti = pti;
-
-	switch (type) {
-	case ATM_AAL0:
-		new->mtu = ATMSAR_DEF_MTU_AAL0;
-		break;
-	case ATM_AAL1:
-		new->mtu = ATMSAR_DEF_MTU_AAL1;
-		break;
-	case ATM_AAL2:
-		new->mtu = ATMSAR_DEF_MTU_AAL2;
-		break;
-	case ATM_AAL34:
-		/* not supported */
-		new->mtu = ATMSAR_DEF_MTU_AAL34;
-		break;
-	case ATM_AAL5:
-		new->mtu = ATMSAR_DEF_MTU_AAL5;
-		break;
-	}
-
-	new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
-	    | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
-	    | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
-	    | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
-	new->flags = flags;
-	new->next = NULL;
-	new->reasBuffer = NULL;
-
-	new->next = *list;
-	*list = new;
-
-	dbg ("Allocated new SARLib vcc 0x%p with vp %d vc %d", new, vpi, vci);
-
-	return new;
-}
-
-void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
-{
-	struct atmsar_vcc_data *work;
-
-	if (*list == vcc) {
-		*list = (*list)->next;
-	} else {
-		for (work = *list; work && work->next && (work->next != vcc); work = work->next);
-
-		/* return if not found */
-		if (work->next != vcc)
-			return;
-
-		work->next = work->next->next;
-	}
-
-	if (vcc->reasBuffer) {
-		dev_kfree_skb (vcc->reasBuffer);
-	}
-
-	dbg ("Allocated SARLib vcc 0x%p with vp %d vc %d", vcc, vcc->vp, vcc->vc);
-
-	kfree (vcc);
-}
-
 static void udsl_atm_dev_close (struct atm_dev *dev)
 {
 	struct udsl_instance_data *instance = dev->dev_data;
@@ -1061,11 +914,10 @@
 	return 0;
 }
 
-#define ATMSAR_SET_PTI		0x2L
-
 static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
 {
 	struct udsl_instance_data *instance = vcc->dev->dev_data;
+	struct udsl_vcc_data *new;
 
 	dbg ("udsl_atm_open called");
 
@@ -1074,63 +926,97 @@
 		return -ENODEV;
 	}
 
-	/* at the moment only AAL5 support */
+	if ((vpi == ATM_VPI_ANY) || (vci == ATM_VCI_ANY))
+		return -EINVAL;
+
+	/* only support AAL5 */
 	if (vcc->qos.aal != ATM_AAL5)
 		return -EINVAL;
 
-	MOD_INC_USE_COUNT;
+	down (&instance->serialize); /* vs self, udsl_atm_close */
 
-	vcc->dev_data =
-	    atmsar_open (&(instance->atmsar_vcc_list), vcc, ATM_AAL5, vpi, vci, 0, 0,
-			 ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
-	if (!vcc->dev_data) {
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;	/* this is the only reason atmsar_open can fail... */
+	if (udsl_find_vcc (instance, vpi, vci)) {
+		up (&instance->serialize);
+		return -EADDRINUSE;
+	}
+
+	if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL))) {
+		up (&instance->serialize);
+		return -ENOMEM;
 	}
 
+	memset (new, 0, sizeof (struct udsl_vcc_data));
+	new->vcc = vcc;
+	new->vpi = vpi;
+	new->vci = vci;
+	new->mtu = UDSL_MAX_AAL5_MRU;
+
+	vcc->dev_data = new;
 	vcc->vpi = vpi;
 	vcc->vci = vci;
+
+	tasklet_disable (&instance->receive_tasklet);
+	list_add (&new->list, &instance->vcc_list);
+	tasklet_enable (&instance->receive_tasklet);
+
 	set_bit (ATM_VF_ADDR, &vcc->flags);
 	set_bit (ATM_VF_PARTIAL, &vcc->flags);
 	set_bit (ATM_VF_READY, &vcc->flags);
 
-	((struct atmsar_vcc_data *)vcc->dev_data)->mtu = UDSL_MAX_AAL5_MRU;
+	up (&instance->serialize);
+
+	dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
+
+	MOD_INC_USE_COUNT;
 
 	if (instance->firmware_loaded)
 		udsl_fire_receivers (instance);
 
 	dbg ("udsl_atm_open successful");
+
 	return 0;
 }
 
 static void udsl_atm_close (struct atm_vcc *vcc)
 {
 	struct udsl_instance_data *instance = vcc->dev->dev_data;
+	struct udsl_vcc_data *vcc_data = vcc->dev_data;
 
 	dbg ("udsl_atm_close called");
 
-	if (!instance) {
-		dbg ("NULL instance!");
+	if (!instance || !vcc_data) {
+		dbg ("NULL data!");
 		return;
 	}
 
-	/* freeing resources */
-	/* cancel all sends on this vcc */
+	dbg ("Deallocating SARLib vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data->vpi, vcc_data->vci);
+
 	udsl_cancel_send (instance, vcc);
 
-	atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data);
+	down (&instance->serialize); /* vs self, udsl_atm_open */
+
+	tasklet_disable (&instance->receive_tasklet);
+	list_del (&vcc_data->list);
+	tasklet_enable (&instance->receive_tasklet);
+
+	if (vcc_data->reasBuffer)
+		kfree_skb (vcc_data->reasBuffer);
+	vcc_data->reasBuffer = NULL;
+
+	kfree (vcc_data);
 	vcc->dev_data = NULL;
-	clear_bit (ATM_VF_PARTIAL, &vcc->flags);
 
-	/* freeing address */
 	vcc->vpi = ATM_VPI_UNSPEC;
 	vcc->vci = ATM_VCI_UNSPEC;
+	clear_bit (ATM_VF_READY, &vcc->flags);
+	clear_bit (ATM_VF_PARTIAL, &vcc->flags);
 	clear_bit (ATM_VF_ADDR, &vcc->flags);
 
+	up (&instance->serialize);
+
 	MOD_DEC_USE_COUNT;
 
 	dbg ("udsl_atm_close successful");
-	return;
 }
 
 static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
@@ -1209,6 +1095,8 @@
 
 	instance->usb_dev = dev;
 
+	INIT_LIST_HEAD (&instance->vcc_list);
+
 	spin_lock_init (&instance->spare_receivers_lock);
 	INIT_LIST_HEAD (&instance->spare_receivers);
 
diff -urN linux-2.5.66-bk2/drivers/usb/misc/usbtest.c linux-2.5.66-bk3/drivers/usb/misc/usbtest.c
--- linux-2.5.66-bk2/drivers/usb/misc/usbtest.c	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/drivers/usb/misc/usbtest.c	Mon Mar 31 12:48:53 2003
@@ -881,6 +881,8 @@
 
 	init_completion (&completion);
 	urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
+	if (!urb)
+		return -ENOMEM;
 	if (async)
 		urb->transfer_flags |= URB_ASYNC_UNLINK;
 	urb->context = &completion;
@@ -1407,6 +1409,11 @@
 		.driver_info = (unsigned long) &fw_info,
 		},
 
+	/* "Gadget Zero" firmware runs under Linux */
+	{ USB_DEVICE (0x0525, 0xa4a0),
+		.driver_info = (unsigned long) &fw_info,
+		},
+
 #ifdef KEYSPAN_19Qi
 	/* Keyspan 19qi uses an21xx (original EZ-USB) */
 	// this does not coexist with the real Keyspan 19qi driver!
diff -urN linux-2.5.66-bk2/drivers/usb/net/cdc-ether.c linux-2.5.66-bk3/drivers/usb/net/cdc-ether.c
--- linux-2.5.66-bk2/drivers/usb/net/cdc-ether.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk3/drivers/usb/net/cdc-ether.c	Mon Mar 31 12:48:53 2003
@@ -269,22 +269,8 @@
 static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net )
 {
 	ether_dev_t	*ether_dev = net->priv;
-	int 	count;
 	int 	res;
 
-	// If we are told to transmit an ethernet frame that fits EXACTLY 
-	// into an integer number of USB packets, we force it to send one 
-	// more byte so the device will get a runt USB packet signalling the 
-	// end of the ethernet frame
-	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
-		// It was not an exact multiple
-		// no need to add anything extra
-		count = skb->len;
-	} else {
-		// Add one to make it NOT an exact multiple
-		count = skb->len + 1;
-	}
-
 	// Tell the kernel, "No more frames 'til we are done
 	// with this one.'
 	netif_stop_queue( net );
@@ -299,7 +285,10 @@
 			write_bulk_callback, ether_dev );
 
 	// Tell the URB how much it will be transporting today
-	ether_dev->tx_urb->transfer_buffer_length = count;
+	ether_dev->tx_urb->transfer_buffer_length = skb->len;
+
+	/* Deal with the zero length problem, I hope */
+	ether_dev->tx_urb->transfer_flags |= URB_ZERO_PACKET;
 	
 	// Send the URB on its merry way.
 	if ((res = usb_submit_urb(ether_dev->tx_urb, GFP_ATOMIC)))  {
diff -urN linux-2.5.66-bk2/drivers/usb/serial/kobil_sct.c linux-2.5.66-bk3/drivers/usb/serial/kobil_sct.c
--- linux-2.5.66-bk2/drivers/usb/serial/kobil_sct.c	Mon Mar 24 14:01:24 2003
+++ linux-2.5.66-bk3/drivers/usb/serial/kobil_sct.c	Mon Mar 31 12:48:53 2003
@@ -406,8 +406,6 @@
 	int result = 0;
 	int todo = 0;
 	struct kobil_private * priv;
-	int i;
-	char *data;
 
 	if (count == 0) {
 		dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
@@ -421,19 +419,6 @@
 		return -ENOMEM;
 	}
 
-	// BEGIN DEBUG
-	data = (unsigned char *) kmalloc((3 * count + 10) * sizeof(char), GFP_KERNEL);  
-	if (! data) {
-		return (-1);
-	}
-	memset(data, 0, (3 * count + 10));
-	for (i = 0; i < count; i++) { 
-		sprintf(data +3*i, "%02X ", buf[i]); 
-	} 
-	dbg(" %d --> %s", port->number, data );
-	kfree(data);
-	// END DEBUG
-
 	// Copy data to buffer
 	if (from_user) {
 		if (copy_from_user(priv->buf + priv->filled, buf, count)) {
@@ -443,6 +428,8 @@
 		memcpy (priv->buf + priv->filled, buf, count);
 	}
 
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->buf + priv->filled);
+
 	priv->filled = priv->filled + count;
 
 
diff -urN linux-2.5.66-bk2/drivers/usb/storage/isd200.c linux-2.5.66-bk3/drivers/usb/storage/isd200.c
--- linux-2.5.66-bk2/drivers/usb/storage/isd200.c	Mon Mar 24 14:00:38 2003
+++ linux-2.5.66-bk3/drivers/usb/storage/isd200.c	Mon Mar 31 12:48:53 2003
@@ -405,11 +405,14 @@
 {
 	union ata_cdb ata;
 	struct scsi_cmnd srb;
+	struct scsi_device srb_dev;
 	struct isd200_info *info = (struct isd200_info *)us->extra;
 	int status;
 
 	memset(&ata, 0, sizeof(ata));
 	memset(&srb, 0, sizeof(srb));
+	memset(&srb_dev, 0, sizeof(srb_dev));
+	srb.device = &srb_dev;
 
 	ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 	ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -479,6 +482,7 @@
 	}
 
 	memcpy(srb.cmnd, &ata, sizeof(ata.generic));
+	srb.cmd_len = sizeof(ata.generic);
 	status = usb_stor_Bulk_transport(&srb, us);
 	if (status == USB_STOR_TRANSPORT_GOOD)
 		status = ISD200_GOOD;
@@ -538,6 +542,7 @@
 	/* send the command to the transport layer */
 	srb->resid = 0;
 	memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic));
+	srb->cmd_len = sizeof(ataCdb->generic);
 	transferStatus = usb_stor_Bulk_transport(srb, us);
 
 	/* if the command gets aborted by the higher layers, we need to
diff -urN linux-2.5.66-bk2/drivers/usb/storage/scsiglue.c linux-2.5.66-bk3/drivers/usb/storage/scsiglue.c
--- linux-2.5.66-bk2/drivers/usb/storage/scsiglue.c	Mon Mar 24 14:00:38 2003
+++ linux-2.5.66-bk3/drivers/usb/storage/scsiglue.c	Mon Mar 31 12:48:53 2003
@@ -209,21 +209,14 @@
 	return result;
 }
 
-/* This resets the device port, and simulates the device
- * disconnect/reconnect for all drivers which have claimed
- * interfaces, including ourself. */
+/* This resets the device port */
+/* It refuses to work if there's more than one interface in
+   this device, so that other users are not affected. */
 /* This is always called with scsi_lock(srb->host) held */
 
-/* FIXME: This needs to be re-examined in the face of the new
- * hotplug system -- this will implicitly cause a detach/reattach of
- * usb-storage, which is not what we want now.
- *
- * Can we just skip over usb-storage in the while loop?
- */
 static int usb_storage_bus_reset( Scsi_Cmnd *srb )
 {
 	struct us_data *us;
-	int i;
 	int result;
 
 	/* we use the usb_reset_device() function to handle this for us */
@@ -231,36 +224,25 @@
 	scsi_unlock(srb->device->host);
 	us = (struct us_data *)srb->device->host->hostdata[0];
 
-	/* attempt to reset the port */
-	result = usb_reset_device(us->pusb_dev);
-	US_DEBUGP("usb_reset_device returns %d\n", result);
-	if (result < 0) {
-		scsi_lock(srb->device->host);
-		return FAILED;
+	/* The USB subsystem doesn't handle synchronisation between
+	   a device's several drivers. Therefore we reset only devices
+	   with one interface which we of course own.
+	*/
+	
+	//FIXME: needs locking against config changes
+	
+	if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) {
+		/* attempt to reset the port */
+		result = usb_reset_device(us->pusb_dev);
+		US_DEBUGP("usb_reset_device returns %d\n", result);
+	} else {
+		result = -EBUSY;
+		US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n");
 	}
 
-	/* FIXME: This needs to lock out driver probing while it's working
-	 * or we can have race conditions */
-	/* This functionality really should be provided by the khubd thread */
-	for (i = 0; i < us->pusb_dev->actconfig->desc.bNumInterfaces; i++) {
- 		struct usb_interface *intf =
-			&us->pusb_dev->actconfig->interface[i];
-
-		/* if this is an unclaimed interface, skip it */
-		if (!intf->driver) {
-			continue;
-		}
-
-		US_DEBUGP("Examining driver %s...", intf->driver->name);
-
-		/* simulate a disconnect and reconnect for all interfaces */
-		US_DEBUGPX("simulating disconnect/reconnect.\n");
-		usb_device_remove (&intf->dev);
-		usb_device_probe (&intf->dev);
-	}
 	US_DEBUGP("bus_reset() complete\n");
 	scsi_lock(srb->device->host);
-	return SUCCESS;
+	return result < 0 ? FAILED : SUCCESS;
 }
 
 /***********************************************************************
diff -urN linux-2.5.66-bk2/drivers/usb/storage/transport.c linux-2.5.66-bk3/drivers/usb/storage/transport.c
--- linux-2.5.66-bk2/drivers/usb/storage/transport.c	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk3/drivers/usb/storage/transport.c	Mon Mar 31 12:48:53 2003
@@ -126,6 +126,7 @@
 	us->current_urb->actual_length = 0;
 	us->current_urb->error_count = 0;
 	us->current_urb->transfer_flags = URB_ASYNC_UNLINK;
+	us->current_urb->status = 0;
 
 	/* submit the URB */
 	status = usb_submit_urb(us->current_urb, GFP_NOIO);
@@ -900,7 +901,7 @@
 	bcb.DataTransferLength = cpu_to_le32(transfer_length);
 	bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
 	bcb.Tag = srb->serial_number;
-	bcb.Lun = srb->cmnd[1] >> 5;
+	bcb.Lun = srb->device->lun;
 	if (us->flags & US_FL_SCM_MULT_TARG)
 		bcb.Lun |= srb->device->id << 4;
 	bcb.Length = srb->cmd_len;
diff -urN linux-2.5.66-bk2/drivers/usb/storage/usb.c linux-2.5.66-bk3/drivers/usb/storage/usb.c
--- linux-2.5.66-bk2/drivers/usb/storage/usb.c	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk3/drivers/usb/storage/usb.c	Mon Mar 31 12:48:53 2003
@@ -360,7 +360,7 @@
 		}
 
 		else if (us->srb->device->lun > us->max_lun) {
-			US_DEBUGP("Bad LUN (%d/%d)\n",
+			US_DEBUGP("Bad LUN (%d:%d)\n",
 				  us->srb->device->id, us->srb->device->lun);
 			us->srb->result = DID_BAD_TARGET << 16;
 		}
@@ -475,8 +475,6 @@
  */
 static void usb_stor_deallocate_urbs(struct us_data *ss)
 {
-	int result;
-
 	/* free the scatter-gather request block */
 	if (ss->current_sg) {
 		kfree(ss->current_sg);
@@ -486,8 +484,6 @@
 	/* free up the main URB for this device */
 	if (ss->current_urb) {
 		US_DEBUGP("-- releasing main URB\n");
-		result = usb_unlink_urb(ss->current_urb);
-		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
 		usb_free_urb(ss->current_urb);
 		ss->current_urb = NULL;
 	}
diff -urN linux-2.5.66-bk2/drivers/usb/usb-skeleton.c linux-2.5.66-bk3/drivers/usb/usb-skeleton.c
--- linux-2.5.66-bk2/drivers/usb/usb-skeleton.c	Mon Mar 24 14:00:23 2003
+++ linux-2.5.66-bk3/drivers/usb/usb-skeleton.c	Mon Mar 31 12:48:53 2003
@@ -72,13 +72,15 @@
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 
-/* Define these values to match your device */
+/* Define these values to match your devices */
 #define USB_SKEL_VENDOR_ID	0xfff0
 #define USB_SKEL_PRODUCT_ID	0xfff0
 
 /* table of devices that work with this driver */
 static struct usb_device_id skel_table [] = {
 	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+	/* "Gadget Zero" firmware runs under Linux */
+	{ USB_DEVICE(0x0525, 0xa4a0) },
 	{ }					/* Terminating entry */
 };
 
@@ -707,7 +709,7 @@
 	/* register this driver with the USB subsystem */
 	result = usb_register(&skel_driver);
 	if (result < 0) {
-		err("usb_register failed for the "__FILE__" driver. Error number %d",
+		err("usb_register failed. Error number %d",
 		    result);
 		return -1;
 	}
diff -urN linux-2.5.66-bk2/drivers/video/Makefile linux-2.5.66-bk3/drivers/video/Makefile
--- linux-2.5.66-bk2/drivers/video/Makefile	Mon Mar 24 14:00:01 2003
+++ linux-2.5.66-bk3/drivers/video/Makefile	Mon Mar 31 12:48:53 2003
@@ -31,7 +31,7 @@
 obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
-obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o cfbimgblt.o
 obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
diff -urN linux-2.5.66-bk2/drivers/video/cyber2000fb.c linux-2.5.66-bk3/drivers/video/cyber2000fb.c
--- linux-2.5.66-bk2/drivers/video/cyber2000fb.c	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk3/drivers/video/cyber2000fb.c	Mon Mar 31 12:48:53 2003
@@ -55,12 +55,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
 #include "cyber2000fb.h"
 
 struct cfb_info {
@@ -147,167 +141,114 @@
 /*
  * Hardware Cyber2000 Acceleration
  */
-static void cyber2000_accel_wait(struct cfb_info *cfb)
-{
-	int count = 100000;
-
-	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
-		if (!count--) {
-			debug_printf("accel_wait timed out\n");
-			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
-			return;
-		}
-		udelay(1);
-	}
-}
-
-static void cyber2000_accel_setup(struct display *display)
-{
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
-
-	cfb->dispsw->setup(display);
-}
-
 static void
-cyber2000_accel_bmove(struct display *display, int sy, int sx, int dy, int dx,
-		      int height, int width)
+cyber2000fb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
 {
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
-	struct fb_var_screeninfo *var = &display->var;
-	u_long src, dst;
-	u_int fh, fw, cmd = CO_CMD_L_PATTERN_FGCOL;
-
-	fw    = fontwidth(display);
-	sx    *= fw;
-	dx    *= fw;
-	width *= fw;
-	width -= 1;
-
-	if (sx < dx) {
-		sx += width;
-		dx += width;
-		cmd |= CO_CMD_L_INC_LEFT;
-	}
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	unsigned long dst, col;
 
-	fh     = fontheight(display);
-	sy     *= fh;
-	dy     *= fh;
-	height *= fh;
-	height -= 1;
-
-	if (sy < dy) {
-		sy += height;
-		dy += height;
-		cmd |= CO_CMD_L_INC_UP;
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_fillrect(info, rect);
+		return;
 	}
 
-	src    = sx + sy * var->xres_virtual;
-	dst    = dx + dy * var->xres_virtual;
+	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb);
 
-	cyber2000_accel_wait(cfb);
-	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
-	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
-	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
+	col = rect->color;
+	if (cfb->fb.var.bits_per_pixel > 8)
+		col = ((u32 *)cfb->fb.pseudo_palette)[col];
+	cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb);
 
-	if (var->bits_per_pixel == 24) {
+	dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual;
+	if (cfb->fb.var.bits_per_pixel == 24) {
 		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
 		dst *= 3;
-		src *= 3;
 	}
 
-	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
 	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
 	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
-	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
-	cyber2000fb_writew(CO_CMD_H_FGSRCMAP|CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
+	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
 }
 
 static void
-cyber2000_accel_clear(struct vc_data *conp, struct display *display, int sy,
-		      int sx, int height, int width)
+cyber2000fb_copyarea(struct fb_info *info, struct fb_copyarea *region)
 {
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
-	struct fb_var_screeninfo *var = &display->var;
-	u_long dst;
-	u_int fw, fh;
-	u32 bgx = attr_bgcol_ec(display, conp);
-
-	fw = fontwidth(display);
-	fh = fontheight(display);
-
-	dst    = sx * fw + sy * var->xres_virtual * fh;
-	width  = width * fw - 1;
-	height = height * fh - 1;
-
-	cyber2000_accel_wait(cfb);
-	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
-	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
-	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
+	unsigned long src, dst;
 
-	if (var->bits_per_pixel == 24) {
-		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
-		dst *= 3;
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_copyarea(info, region);
+		return;
 	}
 
-	if (var->bits_per_pixel == 16)
-		bgx = ((u16 *)display->dispsw_data)[bgx];
-	else if (var->bits_per_pixel >= 24)
-		bgx = ((u32 *)display->dispsw_data)[bgx];
-
-	cyber2000fb_writel(bgx, CO_REG_FGCOLOUR, cfb);
-	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
-	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
-	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
-	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
-}
+	if (region->sx < region->dx) {
+		region->sx += region->width - 1;
+		region->dx += region->width - 1;
+		cmd |= CO_CMD_L_INC_LEFT;
+	}
 
-static void
-cyber2000_accel_putc(struct vc_data *conp, struct display *display, int c,
-		     int yy, int xx)
-{
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+	if (region->sy < region->dy) {
+		region->sy += region->height - 1;
+		region->dy += region->height - 1;
+		cmd |= CO_CMD_L_INC_UP;
+	}
 
-	cyber2000_accel_wait(cfb);
-	cfb->dispsw->putc(conp, display, c, yy, xx);
+	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
+
+	src = region->sx + region->sy * cfb->fb.var.xres_virtual;
+	dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
+	if (cfb->fb.var.bits_per_pixel == 24) {
+		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
+		src *= 3;
+		dst *= 3;
+	}
+	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
+	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+	cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
+	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER,
+			   CO_REG_CMD_H, cfb);
 }
 
 static void
-cyber2000_accel_putcs(struct vc_data *conp, struct display *display,
-		      const unsigned short *s, int count, int yy, int xx)
+cyber2000fb_imageblit(struct fb_info *info, struct fb_image *image)
 {
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+	struct cfb_info *cfb = (struct cfb_info *)info;
 
-	cyber2000_accel_wait(cfb);
-	cfb->dispsw->putcs(conp, display, s, count, yy, xx);
+//	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_imageblit(info, image);
+		return;
+//	}
 }
 
-static void cyber2000_accel_revc(struct display *display, int xx, int yy)
+static int cyber2000fb_sync(struct fb_info *info)
 {
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
-
-	cyber2000_accel_wait(cfb);
-	cfb->dispsw->revc(display, xx, yy);
-}
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	int count = 100000;
 
-static void
-cyber2000_accel_clear_margins(struct vc_data *conp, struct display *display,
-			      int bottom_only)
-{
-	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT))
+		return 0;
 
-	cfb->dispsw->clear_margins(conp, display, bottom_only);
+	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
+		if (!count--) {
+			debug_printf("accel_wait timed out\n");
+			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+			break;
+		}
+		udelay(1);
+	}
+	return 0;
 }
 
-static struct display_switch fbcon_cyber_accel = {
-	.setup		= cyber2000_accel_setup,
-	.bmove		= cyber2000_accel_bmove,
-	.clear		= cyber2000_accel_clear,
-	.putc		= cyber2000_accel_putc,
-	.putcs		= cyber2000_accel_putcs,
-	.revc		= cyber2000_accel_revc,
-	.clear_margins	= cyber2000_accel_clear_margins,
-	.fontwidthmask	= FONTWIDTH(8)|FONTWIDTH(16)
-};
+/*
+ * ===========================================================================
+ */
 
 static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
 {
@@ -324,7 +265,7 @@
 		      u_int transp, struct fb_info *info)
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
-	struct fb_var_screeninfo *var = &cfb->display->var;
+	struct fb_var_screeninfo *var = &cfb->fb.var;
 	u32 pseudo_val;
 	int ret = 1;
 
@@ -332,7 +273,6 @@
 	default:
 		return 1;
 
-#ifdef FBCON_HAS_CFB8
 	/*
 	 * Pseudocolour:
 	 *         8     8
@@ -359,7 +299,6 @@
 		cyber2000fb_writeb(green, 0x3c9, cfb);
 		cyber2000fb_writeb(blue, 0x3c9, cfb);
 		return 0;
-#endif
 
 	/*
 	 * Direct colour:
@@ -455,13 +394,8 @@
 	/*
 	 * Now set our pseudo palette for the CFB16/24/32 drivers.
 	 */
-	if (regno < 16) {
-		if (var->bits_per_pixel == 16)
-			((u16 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
-		else
-			((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
-		ret = 0;
-	}
+	if (regno < 16)
+		((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
 
 	return ret;
 }
@@ -800,20 +734,16 @@
 }
 
 /*
- * Decode the info required for the hardware.
- * This involves the PLL parameters for the dot clock,
- * CRTC registers, and accelerator settings.
+ *    Set the User Defined Part of the Display
  */
 static int
-cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
-		       struct par_info *hw)
+cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	struct par_info hw;
 	unsigned int mem;
 	int err;
 
-	hw->width = var->xres_virtual;
-	hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
-
 	var->transp.msb_right	= 0;
 	var->red.msb_right	= 0;
 	var->green.msb_right	= 0;
@@ -822,10 +752,6 @@
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
 	case 8:	/* PSEUDOCOLOUR, 256 */
-		hw->co_pixfmt		= CO_PIXFMT_8BPP;
-		hw->pitch		= hw->width >> 3;
-		hw->extseqmisc		= EXT_SEQ_MISC_8;
-
 		var->transp.offset	= 0;
 		var->transp.length	= 0;
 		var->red.offset		= 0;
@@ -838,13 +764,8 @@
 #endif
 #ifdef FBCON_HAS_CFB16
 	case 16:/* DIRECTCOLOUR, 64k or 32k */
-		hw->co_pixfmt		= CO_PIXFMT_16BPP;
-		hw->pitch		= hw->width >> 2;
-
 		switch (var->green.length) {
 		case 6: /* RGB565, 64k */
-			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB565;
-
 			var->transp.offset	= 0;
 			var->transp.length	= 0;
 			var->red.offset		= 11;
@@ -857,8 +778,6 @@
 
 		default:
 		case 5: /* RGB555, 32k */
-			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB555;
-
 			var->transp.offset	= 0;
 			var->transp.length	= 0;
 			var->red.offset		= 10;
@@ -870,8 +789,6 @@
 			break;
 
 		case 4: /* RGB444, 4k + transparency? */
-			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB444;
-
 			var->transp.offset	= 12;
 			var->transp.length	= 4;
 			var->red.offset		= 8;
@@ -886,12 +803,6 @@
 #endif
 #ifdef FBCON_HAS_CFB24
 	case 24:/* TRUECOLOUR, 16m */
-		hw->co_pixfmt		= CO_PIXFMT_24BPP;
-		hw->width		*= 3;
-		hw->pitch		= hw->width >> 3;
-		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
-		hw->extseqmisc		= EXT_SEQ_MISC_24_RGB888;
-
 		var->transp.offset	= 0;
 		var->transp.length	= 0;
 		var->red.offset		= 16;
@@ -904,11 +815,6 @@
 #endif
 #ifdef FBCON_HAS_CFB32
 	case 32:/* TRUECOLOUR, 16m */
-		hw->co_pixfmt		= CO_PIXFMT_32BPP;
-		hw->pitch		= hw->width >> 1;
-		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
-		hw->extseqmisc		= EXT_SEQ_MISC_32;
-
 		var->transp.offset	= 24;
 		var->transp.length	= 8;
 		var->red.offset		= 16;
@@ -933,127 +839,107 @@
 	if (var->xres > var->xres_virtual)
 		var->xres = var->xres_virtual;
 
-	err = cyber2000fb_decode_clock(hw, cfb, var);
+	err = cyber2000fb_decode_clock(&hw, cfb, var);
 	if (err)
 		return err;
 
-	err = cyber2000fb_decode_crtc(hw, cfb, var);
+	err = cyber2000fb_decode_crtc(&hw, cfb, var);
 	if (err)
 		return err;
 
-	hw->width -= 1;
-	hw->fetch = hw->pitch;
-	if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
-		hw->fetch <<= 1;
-	hw->fetch += 1;
-
 	return 0;
 }
 
-/*
- *    Set the User Defined Part of the Display
- */
-static int
-cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
-		    struct fb_info *info)
+static int cyber2000fb_set_par(struct fb_info *info)
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
-	struct display *display;
+	struct fb_var_screeninfo *var = &cfb->fb.var;
 	struct par_info hw;
-	int err, chgvar;
-
-	/*
-	 * CONUPDATE and SMOOTH_XPAN are equal.  However,
-	 * SMOOTH_XPAN is only used internally by fbcon.
-	 */
-	if (var->vmode & FB_VMODE_CONUPDATE) {
-		var->vmode |= FB_VMODE_YWRAP;
-		var->xoffset = cfb->display->var.xoffset;
-		var->yoffset = cfb->display->var.yoffset;
-	}
-
-	err = cyber2000fb_decode_var(var, cfb, &hw);
-	if (err)
-		return err;
-
-	if (var->activate & FB_ACTIVATE_TEST)
-		return 0;
+	unsigned int mem;
 
-	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
-		return -EINVAL;
+	hw.width = var->xres_virtual;
+	hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
 
-	if (con < 0) {
-		display = cfb->fb.disp;
-	} else {
-		display = fb_display + con;
-	}
+	switch (var->bits_per_pixel) {
+	case 8:
+		hw.co_pixfmt		= CO_PIXFMT_8BPP;
+		hw.pitch		= hw.width >> 3;
+		hw.extseqmisc		= EXT_SEQ_MISC_8;
+		break;
 
-	chgvar = cfb->fb.var.xres != var->xres ||
-		 cfb->fb.var.yres != var->yres ||
-		 cfb->fb.var.xres_virtual != var->xres_virtual ||
-		 cfb->fb.var.yres_virtual != var->yres_virtual ||
-		 cfb->fb.var.bits_per_pixel != var->bits_per_pixel;
+	case 16:
+		hw.co_pixfmt		= CO_PIXFMT_16BPP;
+		hw.pitch		= hw.width >> 2;
 
-	if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) ||
-	    memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) ||
-	    memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue)))
-		chgvar = 1;
+		switch (var->green.length) {
+		case 6: /* RGB565, 64k */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB565;
+			break;
+		case 5: /* RGB555, 32k */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB555;
+			break;
+		case 4: /* RGB444, 4k + transparency? */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB444;
+			break;
+		default:
+			BUG();
+		}
+	case 24:/* TRUECOLOUR, 16m */
+		hw.co_pixfmt		= CO_PIXFMT_24BPP;
+		hw.width		*= 3;
+		hw.pitch		= hw.width >> 3;
+		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw.extseqmisc		= EXT_SEQ_MISC_24_RGB888;
+		break;
 
-	if (con >= 0 && chgvar == 0)
-		return 0;
+	case 32:/* TRUECOLOUR, 16m */
+		hw.co_pixfmt		= CO_PIXFMT_32BPP;
+		hw.pitch		= hw.width >> 1;
+		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw.extseqmisc		= EXT_SEQ_MISC_32;
+		break;
 
-	if (con < 0)
-		chgvar = 0;
+	default:
+		BUG();
+	}
 
 	/*
-	 * If we are setting all the virtual consoles, also set the
-	 * defaults used to create new consoles.
+	 * Sigh, this is absolutely disgusting, but caused by
+	 * the way the fbcon developers want to separate out
+	 * the "checking" and the "setting" of the video mode.
+	 *
+	 * If the mode is not suitable for the hardware here,
+	 * we can't prevent it being set by returning an error.
+	 *
+	 * In theory, since NetWinders contain just one VGA card,
+	 * we should never end up hitting this problem.
 	 */
-	err = var->activate;
-	var->activate = FB_ACTIVATE_NOW;
-	if (err & FB_ACTIVATE_ALL)
-		cfb->fb.disp->var = *var;
+	BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
+	BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
+
+	hw.width -= 1;
+	hw.fetch = hw.pitch;
+	if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
+		hw.fetch <<= 1;
+	hw.fetch += 1;
 
-	cfb->fb.var = *var;
 	cfb->fb.fix.line_length	= var->xres_virtual * var->bits_per_pixel / 8;
 
-	switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
-	case 8:	/* PSEUDOCOLOUR, 256 */
-		cfb->dispsw		= &fbcon_cfb8;
-		display->dispsw_data	= NULL;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 16:/* DIRECTCOLOUR */
-		cfb->dispsw		= &fbcon_cfb16;
-		display->dispsw_data	= cfb->fb.pseudo_palette;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	case 24:/* TRUECOLOUR, 16m */
-		cfb->dispsw		= &fbcon_cfb24;
-		display->dispsw_data	= cfb->fb.pseudo_palette;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:/* TRUECOLOUR, 16m */
-		cfb->dispsw		= &fbcon_cfb32;
-		display->dispsw_data	= cfb->fb.pseudo_palette;
-		break;
-#endif
-	default:/* in theory this should never happen */
-		printk(KERN_WARNING "%s: no support for %dbpp\n",
-		       cfb->fb.fix.id, var->bits_per_pixel);
-		cfb->dispsw = &fbcon_dummy;
-		break;
-	}
+	/*
+	 * Same here - if the size of the video mode exceeds the
+	 * available RAM, we can't prevent this mode being set.
+	 *
+	 * In theory, since NetWinders contain just one VGA card,
+	 * we should never end up hitting this problem.
+	 */
+	mem = cfb->fb.fix.line_length * var->yres_virtual;
+	BUG_ON(mem > cfb->fb.fix.smem_len);
 
 	/*
-	 * 8bpp displays are always pseudo colour.
-	 * 16bpp and above are direct colour or true colour, depending
-	 * on whether the RAMDAC palettes are bypassed.  (Direct colour
-	 * has palettes, true colour does not.)
+	 * 8bpp displays are always pseudo colour.  16bpp and above
+	 * are direct colour or true colour, depending on whether
+	 * the RAMDAC palettes are bypassed.  (Direct colour has
+	 * palettes, true colour does not.)
 	 */
 	if (var->bits_per_pixel == 8)
 		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -1062,20 +948,8 @@
 	else
 		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
 
-	if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
-		display->dispsw = &fbcon_cyber_accel;
-	else
-		display->dispsw = cfb->dispsw;
-
-	display->can_soft_blank = 1;
-	display->inverse	= 0;
-
 	cyber2000fb_set_timing(cfb, &hw);
 	cyber2000fb_update_start(cfb, var);
-	fb_set_cmap(&cfb->fb.cmap, 1, &cfb->fb);
-
-	if (chgvar && cfb->fb.changevar)
-		cfb->fb.changevar(con);
 
 	return 0;
 }
@@ -1085,85 +959,22 @@
  *    Pan or Wrap the Display
  */
 static int
-cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
+cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
-	u_int y_bottom;
-
-	y_bottom = var->yoffset;
-
-	if (!(var->vmode & FB_VMODE_YWRAP))
-		y_bottom += var->yres;
-
-	if (var->xoffset > (var->xres_virtual - var->xres))
-		return -EINVAL;
-	if (y_bottom > cfb->display->var.yres_virtual)
-		return -EINVAL;
 
 	if (cyber2000fb_update_start(cfb, var))
 		return -EINVAL;
 
-	cfb->display->var.xoffset = var->xoffset;
-	cfb->display->var.yoffset = var->yoffset;
+	cfb->fb.var.xoffset = var->xoffset;
+	cfb->fb.var.yoffset = var->yoffset;
+
 	if (var->vmode & FB_VMODE_YWRAP) {
-		cfb->display->var.vmode |= FB_VMODE_YWRAP;
+		cfb->fb.var.vmode |= FB_VMODE_YWRAP;
 	} else {
-		cfb->display->var.vmode &= ~FB_VMODE_YWRAP;
-	}
-
-	return 0;
-}
-
-
-/*
- *    Update the `var' structure (called by fbcon.c)
- *
- *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- *    Since it's called by a kernel driver, no range checking is done.
- */
-static int cyber2000fb_updatevar(int con, struct fb_info *info)
-{
-	struct cfb_info *cfb = (struct cfb_info *)info;
-
-	return cyber2000fb_update_start(cfb, &fb_display[con].var);
-}
-
-static int cyber2000fb_switch(int con, struct fb_info *info)
-{
-	struct cfb_info *cfb = (struct cfb_info *)info;
-	struct display *display = cfb->display;
-	struct fb_cmap *cmap;
-
-	if (display) {
-		/*
-		 * Save the old colormap and video mode.
-		 */
-		if (display->cmap.len)
-			fb_copy_cmap(&cfb->fb.cmap, &display->cmap, 0);
+		cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
 	}
 
-	cfb->display = display = fb_display + con;
-
-	/*
-	 * Install the new colormap and change the video mode.  By default,
-	 * fbcon sets all the colormaps and video modes to the default
-	 * values at bootup.
-	 *
-	 * Really, we want to set the colourmap size depending on the
-	 * depth of the new video mode.  For now, we leave it at its
-	 * default 256 entry.
-	 */
-	if (display->cmap.len)
-		cmap = &display->cmap;
-	else
-		cmap = fb_default_cmap(1 << display->var.bits_per_pixel);
-
-	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
-
-	display->var.activate = FB_ACTIVATE_NOW;
-	cyber2000fb_set_var(&display->var, con, &cfb->fb);
-
 	return 0;
 }
 
@@ -1243,12 +1054,16 @@
 
 static struct fb_ops cyber2000fb_ops = {
 	.owner		= THIS_MODULE,
-	.fb_set_var	= cyber2000fb_set_var,
-	.fb_get_cmap	= gen_get_cmap,
-	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= cyber2000fb_check_var,
+	.fb_set_par	= cyber2000fb_set_par,
 	.fb_setcolreg	= cyber2000fb_setcolreg,
-	.fb_pan_display	= cyber2000fb_pan_display,
 	.fb_blank	= cyber2000fb_blank,
+	.fb_pan_display	= cyber2000fb_pan_display,
+	.fb_fillrect	= cyber2000fb_fillrect,
+	.fb_copyarea	= cyber2000fb_copyarea,
+	.fb_imageblit	= cyber2000fb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_sync	= cyber2000fb_sync,
 };
 
 /*
@@ -1295,7 +1110,7 @@
 
 void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
 {
-	memcpy(var, &cfb->display->var, sizeof(struct fb_var_screeninfo));
+	memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
 }
 
 /*
@@ -1313,8 +1128,6 @@
 		info->info            = int_cfb_info;
 
 		strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
-
-		MOD_INC_USE_COUNT;
 	}
 
 	return int_cfb_info != NULL;
@@ -1325,7 +1138,6 @@
  */
 void cyber2000fb_detach(int idx)
 {
-	MOD_DEC_USE_COUNT;
 }
 
 EXPORT_SYMBOL(cyber2000fb_attach);
@@ -1411,13 +1223,13 @@
 {
 	struct cfb_info *cfb;
 
-	cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
+	cfb = kmalloc(sizeof(struct cfb_info) +
 		       sizeof(u32) * 16, GFP_KERNEL);
 
 	if (!cfb)
 		return NULL;
 
-	memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
+	memset(cfb, 0, sizeof(struct cfb_info));
 
 	cfb->id			= id;
 
@@ -1467,17 +1279,10 @@
 	cfb->fb.var.width	= -1;
 	cfb->fb.var.accel_flags	= FB_ACCELF_TEXT;
 
-	strcpy(cfb->fb.modename, cfb->fb.fix.id);
-	strcpy(cfb->fb.fontname, default_font);
-
 	cfb->fb.fbops		= &cyber2000fb_ops;
-	cfb->fb.changevar	= NULL;
-	cfb->fb.switch_con	= cyber2000fb_switch;
-	cfb->fb.updatevar	= cyber2000fb_updatevar;
 	cfb->fb.flags		= FBINFO_FLAG_DEFAULT;
 	cfb->fb.node		= NODEV;
-	cfb->fb.disp		= (struct display *)(cfb + 1);
-	cfb->fb.pseudo_palette	= (void *)(cfb->fb.disp + 1);
+	cfb->fb.pseudo_palette	= (void *)(cfb + 1);
 
 	fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
 
@@ -1575,7 +1380,7 @@
 	if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
 		cfb->fb.var.yres_virtual = cfb->fb.var.yres;
 
-	cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
+//	fb_set_var(&cfb->fb.var, -1, &cfb->fb);
 
 	/*
 	 * Calculate the hsync and vsync frequencies.  Note that
@@ -1614,8 +1419,7 @@
 	 * Restore the old video mode and the palette.
 	 * We also need to tell fbcon to redraw the console.
 	 */
-	cfb->fb.var.activate = FB_ACTIVATE_NOW;
-	cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
+	cyber2000fb_set_par(&cfb->fb);
 }
 
 #ifdef CONFIG_ARCH_SHARK
diff -urN linux-2.5.66-bk2/drivers/video/fbmem.c linux-2.5.66-bk3/drivers/video/fbmem.c
--- linux-2.5.66-bk2/drivers/video/fbmem.c	Mon Mar 24 13:59:46 2003
+++ linux-2.5.66-bk3/drivers/video/fbmem.c	Mon Mar 31 12:48:53 2003
@@ -1111,13 +1111,11 @@
 #elif defined(__mips__)
 	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
-#elif defined(__arm__)
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #elif defined(__hppa__)
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-#elif defined(__ia64__)
+#elif defined(__ia64__) || defined(__arm__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 #else
 #warning What do we have to do here??
diff -urN linux-2.5.66-bk2/fs/xfs/Makefile linux-2.5.66-bk3/fs/xfs/Makefile
--- linux-2.5.66-bk2/fs/xfs/Makefile	Mon Mar 24 14:01:11 2003
+++ linux-2.5.66-bk3/fs/xfs/Makefile	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms of version 2 of the GNU General Public License as
@@ -29,13 +29,7 @@
 #
 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 #
-# Makefile for XFS on Linux.
-#
-
 
-# This needs -I. because everything does #include <xfs.h> instead of "xfs.h".
-# The code is wrong, local files should be included using "xfs.h", not <xfs.h>
-# but I am not going to change every file at the moment.
 EXTRA_CFLAGS +=	 -Ifs/xfs -funsigned-char
 
 ifeq ($(CONFIG_XFS_DEBUG),y)
@@ -48,17 +42,22 @@
 obj-$(CONFIG_XFS_FS)		+= xfs.o
 
 
-xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
-
-xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
+xfs-$(CONFIG_XFS_QUOTA)		+= $(addprefix quota/, \
+				   xfs_dquot.o \
 				   xfs_dquot_item.o \
 				   xfs_trans_dquot.o \
 				   xfs_qm_syscalls.o \
-				   xfs_qm.o
+				   xfs_qm_bhv.o \
+				   xfs_qm.o)
 
+ifeq ($(CONFIG_XFS_QUOTA),y)
+xfs-$(CONFIG_PROC_FS)		+= quota/xfs_qm_stats.o
+endif
+
+xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
-xfs-$(CONFIG_FS_POSIX_CAP)	+= xfs_cap.o
-xfs-$(CONFIG_FS_POSIX_MAC)	+= xfs_mac.o
+xfs-$(CONFIG_XFS_POSIX_CAP)	+= xfs_cap.o
+xfs-$(CONFIG_XFS_POSIX_MAC)	+= xfs_mac.o
 xfs-$(CONFIG_PROC_FS)		+= linux/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)		+= linux/xfs_sysctl.o
 
@@ -127,6 +126,7 @@
 				   xfs_iops.o \
 				   xfs_lrw.o \
 				   xfs_super.o \
+				   xfs_vfs.o \
 				   xfs_vnode.o)
 
 # Objects in support/
@@ -139,6 +139,10 @@
 				   qsort.o \
 				   uuid.o)
 
+# Quota and DMAPI stubs
+xfs-y				+= xfs_dmops.o \
+				   xfs_qmops.o
+
 # If both xfs and kdb modules are built in then xfsidbg is built in.  If xfs is
 # a module and kdb modules are being compiled then xfsidbg must be a module, to
 # follow xfs.  If xfs is built in then xfsidbg tracks the kdb module state.
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_aops.c linux-2.5.66-bk3/fs/xfs/linux/xfs_aops.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_aops.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_aops.c	Mon Mar 31 12:48:53 2003
@@ -78,6 +78,7 @@
 				  XFS_BUF_OFFSET(bp), XFS_BUF_SIZE(bp));
 	XFS_BUF_SET_FSPRIVATE(bp, NULL);
 	XFS_BUF_CLR_IODONE_FUNC(bp);
+	XFS_BUF_UNDATAIO(bp);
 	xfs_biodone(bp);
 }
 
@@ -431,6 +432,7 @@
 	size = nblocks;		/* NB: using 64bit number here */
 	size <<= block_bits;	/* convert fsb's to byte range */
 
+	XFS_BUF_DATAIO(pb);
 	XFS_BUF_SET_SIZE(pb, size);
 	XFS_BUF_SET_OFFSET(pb, offset);
 	XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode)->v_fbhv);
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_behavior.c linux-2.5.66-bk3/fs/xfs/linux/xfs_behavior.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_behavior.c	Mon Mar 24 14:01:45 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_behavior.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -30,41 +30,77 @@
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  *
  */
+#include <xfs.h>
 
 /*
  * Source file used to associate/disassociate behaviors with virtualized
- * objects.  See behavior.h for more information about behaviors, etc.
+ * objects.  See xfs_behavior.h for more information about behaviors, etc.
  *
  * The implementation is split between functions in this file and macros
- * in behavior.h.
+ * in xfs_behavior.h.
  */
-#include <xfs.h>
-
-kmem_zone_t	*bhv_global_zone;
 
 /*
- * Global initialization function called out of main.
+ * Insert a new behavior descriptor into a behavior chain.
+ *
+ * The behavior chain is ordered based on the 'position' number which
+ * lives in the first field of the ops vector (higher numbers first).
+ *
+ * Attemps to insert duplicate ops result in an EINVAL return code.
+ * Otherwise, return 0 to indicate success.
  */
-void
-bhv_global_init(void)
+int
+bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp)
 {
+	bhv_desc_t	*curdesc, *prev;
+	int		position;
+
+	/*
+	 * Validate the position value of the new behavior.
+	 */
+	position = BHV_POSITION(bdp);
+	ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP);
+
 	/*
-	 * Initialize a behavior zone used by subsystems using behaviors
-	 * but without any private data.  In the UNIKERNEL case, this zone
-	 * is used only for behaviors that are not yet isolated to a single
-	 * cell.  The only such user is in pshm.c in which a dummy vnode is
-	 * obtained in support of vce avoidance logic.
+	 * Find location to insert behavior.  Check for duplicates.
 	 */
-	bhv_global_zone = kmem_zone_init(sizeof(bhv_desc_t), "bhv_global_zone");
+	prev = NULL;
+	for (curdesc = bhp->bh_first;
+	     curdesc != NULL;
+	     curdesc = curdesc->bd_next) {
+
+		/* Check for duplication. */
+		if (curdesc->bd_ops == bdp->bd_ops) {
+			ASSERT(0);
+			return EINVAL;
+		}
+
+		/* Find correct position */
+		if (position >= BHV_POSITION(curdesc)) {
+			ASSERT(position != BHV_POSITION(curdesc));
+			break;		/* found it */
+		}
+
+		prev = curdesc;
+	}
+
+	if (prev == NULL) {
+		/* insert at front of chain */
+		bdp->bd_next = bhp->bh_first;
+		bhp->bh_first = bdp;
+	} else {
+		/* insert after prev */
+		bdp->bd_next = prev->bd_next;
+		prev->bd_next = bdp;
+	}
+
+        return 0;
 }
 
 /*
  * Remove a behavior descriptor from a position in a behavior chain;
  * the postition is guaranteed not to be the first position.
  * Should only be called by the bhv_remove() macro.
- *
- * The act of modifying the chain is done atomically w.r.t. ops-in-progress
- * (see comment at top of behavior.h for more info on synchronization).
  */
 void
 bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
@@ -86,7 +122,6 @@
 
 	ASSERT(curdesc == bdp);
 	prev->bd_next = bdp->bd_next;	/* remove from after prev */
-					/* atomic wrt oip's */
 }
 
 /*
@@ -110,20 +145,28 @@
 }
 
 /*
- * Look for a specific ops vector on the specified behavior chain.
- * Return the associated behavior descriptor.  Or NULL, if not found.
- *
- * The caller has not read locked the behavior chain, so acquire the
- * lock before traversing the chain.
+ * Looks for the first behavior within a specified range of positions.
+ * Return the associated behavior descriptor.  Or NULL, if none found.
  */
 bhv_desc_t *
-bhv_lookup_unlocked(bhv_head_t *bhp, void *ops)
+bhv_lookup_range(bhv_head_t *bhp, int low, int high)
 {
-	bhv_desc_t	*bdp;
+	bhv_desc_t	*curdesc;
+
+	for (curdesc = bhp->bh_first;
+	     curdesc != NULL;
+	     curdesc = curdesc->bd_next) {
 
-	bdp = bhv_lookup(bhp, ops);
+		int	position = BHV_POSITION(curdesc);
 
-	return bdp;
+		if (position <= high) {
+			if (position >= low)
+				return curdesc;
+			return NULL;
+		}
+	}
+
+	return NULL;
 }
 
 /*
@@ -134,49 +177,36 @@
  * lock before traversing the chain.
  */
 bhv_desc_t *
-bhv_base_unlocked(bhv_head_t *bhp)
+bhv_base(bhv_head_t *bhp)
 {
 	bhv_desc_t	*curdesc;
 
 	for (curdesc = bhp->bh_first;
 	     curdesc != NULL;
 	     curdesc = curdesc->bd_next) {
-		if (curdesc->bd_next == NULL)
+
+		if (curdesc->bd_next == NULL) {
 			return curdesc;
+		}
 	}
+
 	return NULL;
 }
 
-#define BHVMAGIC (void *)0xf00d
-
-/* ARGSUSED */
 void
 bhv_head_init(
 	bhv_head_t *bhp,
 	char *name)
 {
 	bhp->bh_first = NULL;
-	bhp->bh_lockp = BHVMAGIC;
-}
-
-
-/* ARGSUSED */
-void
-bhv_head_reinit(
-	bhv_head_t *bhp)
-{
-	ASSERT(bhp->bh_first == NULL);
-	ASSERT(bhp->bh_lockp == BHVMAGIC);
 }
 
-
 void
 bhv_insert_initial(
 	bhv_head_t *bhp,
 	bhv_desc_t *bdp)
 {
 	ASSERT(bhp->bh_first == NULL);
-	ASSERT(bhp->bh_lockp == BHVMAGIC);
 	(bhp)->bh_first = bdp;
 }
 
@@ -185,7 +215,4 @@
 	bhv_head_t *bhp)
 {
 	ASSERT(bhp->bh_first == NULL);
-	ASSERT(bhp->bh_lockp == BHVMAGIC);
-	bhp->bh_lockp = NULL;
 }
-
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_behavior.h linux-2.5.66-bk3/fs/xfs/linux/xfs_behavior.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_behavior.h	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_behavior.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -91,8 +91,8 @@
  *     active object
  *
  */
-
-typedef void	bhv_head_lock_t;
+ 
+struct bhv_head_lock;
 
 /*
  * Behavior head.  Head of the chain of behaviors.
@@ -100,7 +100,7 @@
  */
 typedef struct bhv_head {
 	struct bhv_desc *bh_first;	/* first behavior in chain */
-	bhv_head_lock_t *bh_lockp;	/* pointer to lock info struct */
+	struct bhv_head_lock *bh_lockp;	/* pointer to lock info struct */
 } bhv_head_t;
 
 /*
@@ -128,10 +128,8 @@
 typedef bhv_identity_t bhv_position_t;
 
 #define BHV_IDENTITY_INIT(id,pos)	{id, pos}
-
 #define BHV_IDENTITY_INIT_POSITION(pos) BHV_IDENTITY_INIT(0, pos)
 
-
 /*
  * Define boundaries of position values.
  */
@@ -154,7 +152,7 @@
 
 extern void bhv_head_init(bhv_head_t *, char *);
 extern void bhv_head_destroy(bhv_head_t *);
-extern void bhv_head_reinit(bhv_head_t *);
+extern int  bhv_insert(bhv_head_t *, bhv_desc_t *);
 extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *);
 
 /*
@@ -196,7 +194,11 @@
  */
 extern void		bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp);
 extern bhv_desc_t *	bhv_lookup(bhv_head_t *bhp, void *ops);
-extern bhv_desc_t *	bhv_lookup_unlocked(bhv_head_t *bhp, void *ops);
-extern bhv_desc_t *	bhv_base_unlocked(bhv_head_t *bhp);
+extern bhv_desc_t *	bhv_lookup_range(bhv_head_t *bhp, int low, int high);
+extern bhv_desc_t *	bhv_base(bhv_head_t *bhp);
+
+/* No bhv locking on Linux */
+#define bhv_lookup_unlocked	bhv_lookup
+#define bhv_base_unlocked	bhv_base
 
 #endif /* __XFS_BEHAVIOR_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_file.c linux-2.5.66-bk3/fs/xfs/linux/xfs_file.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_file.c	Mon Mar 24 14:00:41 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_file.c	Mon Mar 31 12:48:53 2003
@@ -299,7 +299,9 @@
 	int		error;
 
 	if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
-		error = -xfs_dm_send_mmap_event(vma, 0);
+		xfs_mount_t	*mp = XFS_VFSTOM(vp->v_vfsp);
+
+		error = -XFS_SEND_MMAP(mp, vma, 0);
 		if (error)
 			return error;
 	}
@@ -345,8 +347,10 @@
 
 	if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
 		if ((vma->vm_flags & VM_MAYSHARE) &&
-		    (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)){
-			error = xfs_dm_send_mmap_event(vma, VM_WRITE);
+		    (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) {
+			xfs_mount_t	*mp = XFS_VFSTOM(vp->v_vfsp);
+
+			error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
 		    }
 	}
 	return error;
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_globals.c linux-2.5.66-bk3/fs/xfs/linux/xfs_globals.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_globals.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_globals.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -40,7 +40,7 @@
 /*
  * System memory size - used to scale certain data structures in XFS.
  */
-unsigned long	xfs_physmem;
+unsigned long xfs_physmem;
 
 /*
  * Tunable XFS parameters.  xfs_params is required even when CONFIG_SYSCTL=n,
@@ -51,24 +51,14 @@
 /*
  * Used to serialize atomicIncWithWrap.
  */
-spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED;
+spinlock_t xfs_atomic_spin = SPIN_LOCK_UNLOCKED;
 
 /*
  * Global system credential structure.
  */
 cred_t sys_cred_val, *sys_cred = &sys_cred_val;
 
-/*
- * The global quota manager. There is only one of these for the entire
- * system, _not_ one per file system. XQM keeps track of the overall
- * quota functionality, including maintaining the freelist and hash
- * tables of dquots.
- */
-struct xfs_qm	*xfs_Gqm;
-mutex_t		xfs_Gqm_lock;
-
 /* Export XFS symbols used by xfsidbg */
-EXPORT_SYMBOL(xfs_Gqm);
 EXPORT_SYMBOL(xfs_next_bit);
 EXPORT_SYMBOL(xfs_contig_bits);
 EXPORT_SYMBOL(xfs_bmbt_get_all);
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_globals.h linux-2.5.66-bk3/fs/xfs/linux/xfs_globals.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_globals.h	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_globals.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -39,11 +39,10 @@
 
 extern uint64_t xfs_panic_mask;		/* set to cause more panics */
 
-extern unsigned long	xfs_physmem;
+extern unsigned long xfs_physmem;
 
-extern struct cred *sys_cred;
+extern spinlock_t xfs_atomic_spin;
 
-extern struct xfs_qm	*xfs_Gqm;
-extern mutex_t		xfs_Gqm_lock;
+extern struct cred *sys_cred;
 
 #endif	/* __XFS_GLOBALS_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_ioctl.c linux-2.5.66-bk3/fs/xfs/linux/xfs_ioctl.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_ioctl.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_ioctl.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -130,7 +130,7 @@
 		int		lock_mode;
 
 		/* need to get access to the xfs_inode to read the generation */
-		bhv = VNODE_TO_FIRST_BHV(vp);
+		bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
 		ASSERT(bhv);
 		ip = XFS_BHVTOI(bhv);
 		ASSERT(ip);
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_iomap.c linux-2.5.66-bk3/fs/xfs/linux/xfs_iomap.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_iomap.c	Mon Mar 24 14:00:40 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_iomap.c	Mon Mar 31 12:48:53 2003
@@ -258,11 +258,10 @@
 	 * the ilock across a disk read.
 	 */
 
-	if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-			return XFS_ERROR(error);
-		}
-	}
+	error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
+	if (error)
+		return XFS_ERROR(error);
+
 	maps = min(XFS_WRITE_IMAPS, *nmaps);
 	nimaps = maps;
 
@@ -291,7 +290,7 @@
 	 * determine if reserving space on
 	 * the data or realtime partition.
 	 */
-	if ((rt = ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
+	if ((rt = XFS_IS_REALTIME_INODE(ip))) {
 		int	sbrtextsize, iprtextsize;
 
 		sbrtextsize = mp->m_sb.sb_rextsize;
@@ -333,11 +332,9 @@
 		goto error_out; /* Don't return in above if .. trans ..,
 					need lock to return */
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (xfs_trans_reserve_blkquota(tp, ip, resblks)) {
-			error = (EDQUOT);
-			goto error1;
-		}
+	if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) {
+		error = (EDQUOT);
+		goto error1;
 	}
 	nimaps = 1;
 
@@ -422,11 +419,9 @@
 	 * the ilock across a disk read.
 	 */
 
-	if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-			return XFS_ERROR(error);
-		}
-	}
+	error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+	if (error)
+		return XFS_ERROR(error);
 
 retry:
 	isize = ip->i_d.di_size;
@@ -538,11 +533,8 @@
 	 * Make sure that the dquots are there.
 	 */
 
-	if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-		if ((error = xfs_qm_dqattach(ip, 0))) {
-			return XFS_ERROR(error);
-		}
-	}
+	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+		return XFS_ERROR(error);
 
 	offset_fsb = map->br_startoff;
 	count_fsb = map->br_blockcount;
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_linux.h linux-2.5.66-bk3/fs/xfs/linux/xfs_linux.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_linux.h	Mon Mar 24 13:59:53 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_linux.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -44,6 +44,7 @@
 #include <linux/major.h>
 #include <linux/pagemap.h>
 #include <linux/vfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/page.h>
 #include <asm/div64.h>
@@ -160,6 +161,15 @@
 #define SYNCHRONIZE()	barrier()
 #define __return_address __builtin_return_address(0)
 
+/*
+ * IRIX (BSD) quotactl makes use of separate commands for user/group,
+ * whereas on Linux the syscall encodes this information into the cmd 
+ * field (see the QCMD macro in quota.h).  These macros help keep the
+ * code portable - they are not visible from the syscall interface.
+ */
+#define Q_XSETGQLIM	XQM_CMD(0x8)	/* set groups disk limits */
+#define Q_XGETGQUOTA	XQM_CMD(0x9)	/* get groups disk limits */
+
 /* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */
 /* we may well need to fine-tune this if it ever becomes an issue.  */
 #define DQUOT_MAX_HEURISTIC	1024	/* NR_DQUOTS */
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_lrw.c linux-2.5.66-bk3/fs/xfs/linux/xfs_lrw.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_lrw.c	Mon Mar 24 13:59:46 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_lrw.c	Mon Mar 31 12:48:53 2003
@@ -121,7 +121,8 @@
 	xfs_mount_t		*mp;
 	vnode_t			*vp;
 	unsigned long		seg;
-	int			direct = filp->f_flags & O_DIRECT;
+	int			direct = (filp->f_flags & O_DIRECT);
+	int			invisible = (filp->f_mode & FINVIS);
 
 	ip = XFS_BHVTOI(bdp);
 	vp = BHV_TO_VNODE(bdp);
@@ -180,13 +181,12 @@
 
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
-	    !(filp->f_mode & FINVIS)) {
+	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !invisible) {
 		int error;
 		vrwlock_t locktype = VRWLOCK_READ;
 
-		error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp,
-				size, FILP_DELAY_FLAG(filp), &locktype);
+		error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offp, size,
+				      FILP_DELAY_FLAG(filp), &locktype);
 		if (error) {
 			xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 			return -error;
@@ -198,7 +198,7 @@
 
 	XFS_STATS_ADD(xfsstats.xs_read_bytes, ret);
 
-	if (!(filp->f_mode & FINVIS))
+	if (!invisible)
 		xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 
 	return ret;
@@ -217,11 +217,13 @@
 	ssize_t			ret;
 	xfs_fsize_t		n;
 	xfs_inode_t		*ip;
+	xfs_mount_t		*mp;
 	vnode_t			*vp;
 	int			invisible = (filp->f_mode & FINVIS);
 
 	ip = XFS_BHVTOI(bdp);
 	vp = BHV_TO_VNODE(bdp);
+	mp = ip->i_mount;
 	vn_trace_entry(vp, "xfs_sendfile", (inst_t *)__return_address);
 
 	XFS_STATS_INC(xfsstats.xs_read_calls);
@@ -241,8 +243,8 @@
 		vrwlock_t locktype = VRWLOCK_READ;
 		int error;
 
-		error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp,
-				count, FILP_DELAY_FLAG(filp), &locktype);
+		error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offp, count,
+				      FILP_DELAY_FLAG(filp), &locktype);
 		if (error) {
 			xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 			return -error;
@@ -493,7 +495,8 @@
 	vnode_t			*vp;
 	unsigned long		seg;
 	int			iolock;
-	int			direct = file->f_flags & O_DIRECT;
+	int			direct = (file->f_flags & O_DIRECT);
+	int			invisible = (file->f_mode & FINVIS);
 	int			eventsent = 0;
 	vrwlock_t		locktype;
 
@@ -573,13 +576,13 @@
 	}
 
 	if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
-	    !(file->f_mode & FINVIS) && !eventsent)) {
+	    !invisible && !eventsent)) {
 		loff_t		savedsize = *offset;
 
 		xfs_iunlock(xip, XFS_ILOCK_EXCL);
-		error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp,
-				*offset, size,
-				FILP_DELAY_FLAG(file), &locktype);
+		error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, bdp,
+				      *offset, size,
+				      FILP_DELAY_FLAG(file), &locktype);
 		if (error) {
 			xfs_iunlock(xip, iolock);
 			return -error;
@@ -588,12 +591,11 @@
 		eventsent = 1;
 
 		/*
-		 * The iolock was dropped and reaquired in
-		 * xfs_dm_send_data_event so we have to recheck the size
-		 *  when appending.  We will only "goto start;" once,
-		 *  since having sent the event prevents another call
-		 *  to xfs_dm_send_data_event, which is what
-		 *  allows the size to change in the first place.
+		 * The iolock was dropped and reaquired in XFS_SEND_DATA
+		 * so we have to recheck the size when appending.
+		 * We will only "goto start;" once, since having sent the
+		 * event prevents another call to XFS_SEND_DATA, which is
+		 * what allows the size to change in the first place.
 		 */
 		if ((file->f_flags & O_APPEND) &&
 		    savedsize != xip->i_d.di_size) {
@@ -608,10 +610,8 @@
 	 *
 	 * We must update xfs' times since revalidate will overcopy xfs.
 	 */
-	if (size) {
-		if (!(file->f_mode & FINVIS))
-			xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-	}
+	if (size && !invisible)
+		xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
 	/*
 	 * If the offset is beyond the size of the file, we have a couple
@@ -658,11 +658,10 @@
 	ret = generic_file_write_nolock(file, iovp, segs, offset);
 
 	if ((ret == -ENOSPC) &&
-	    DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
-	    !(file->f_mode & FINVIS)) {
+	    DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && !invisible) {
 
 		xfs_rwunlock(bdp, locktype);
-		error = dm_send_namesp_event(DM_EVENT_NOSPACE, bdp,
+		error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, bdp,
 				DM_RIGHT_NULL, bdp, DM_RIGHT_NULL, NULL, NULL,
 				0, 0, 0); /* Delay flag intentionally  unused */
 		if (error)
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_stats.c linux-2.5.66-bk3/fs/xfs/linux/xfs_stats.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_stats.c	Mon Mar 24 14:01:26 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_stats.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -61,7 +61,6 @@
 		{ "xstrat",		XFSSTAT_END_WRITE_CONVERT	},
 		{ "rw",			XFSSTAT_END_READ_WRITE_OPS	},
 		{ "attr",		XFSSTAT_END_ATTRIBUTE_OPS	},
-		{ "qm",			XFSSTAT_END_QUOTA_OPS		},
 		{ "icluster",		XFSSTAT_END_INODE_CLUSTER	},
 		{ "vnodes",		XFSSTAT_END_VNODE_OPS		},
 	};
@@ -95,50 +94,17 @@
 	return len;
 }
 
-STATIC int
-xfs_read_xfsquota(
-	char		*buffer,
-	char		**start,
-	off_t		offset,
-	int		count,
-	int		*eof,
-	void		*data)
-{
-	int		len;
-
-	/* maximum; incore; ratio free to inuse; freelist */
-	len = sprintf(buffer, "%d\t%d\t%d\t%u\n",
-			ndquot,
-			xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
-			xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
-			xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0);
-
-	if (offset >= len) {
-		*start = buffer;
-		*eof = 1;
-		return 0;
-	}
-	*start = buffer + offset;
-	if ((len -= offset) > count)
-		return count;
-	*eof = 1;
-
-	return len;
-}
-
 void
 xfs_init_procfs(void)
 {
 	if (!proc_mkdir("fs/xfs", 0))
 		return;
 	create_proc_read_entry("fs/xfs/stat", 0, 0, xfs_read_xfsstats, NULL);
-	create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_read_xfsquota, NULL);
 }
 
 void
 xfs_cleanup_procfs(void)
 {
 	remove_proc_entry("fs/xfs/stat", NULL);
-	remove_proc_entry("fs/xfs/xqm", NULL);
 	remove_proc_entry("fs/xfs", NULL);
 }
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_stats.h linux-2.5.66-bk3/fs/xfs/linux/xfs_stats.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_stats.h	Mon Mar 24 14:00:13 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_stats.h	Mon Mar 31 12:48:53 2003
@@ -107,16 +107,7 @@
 	__uint32_t		xs_attr_set;
 	__uint32_t		xs_attr_remove;
 	__uint32_t		xs_attr_list;
-# define XFSSTAT_END_QUOTA_OPS		(XFSSTAT_END_ATTRIBUTE_OPS+8)
-	__uint32_t		xs_qm_dqreclaims;
-	__uint32_t		xs_qm_dqreclaim_misses;
-	__uint32_t		xs_qm_dquot_dups;
-	__uint32_t		xs_qm_dqcachemisses;
-	__uint32_t		xs_qm_dqcachehits;
-	__uint32_t		xs_qm_dqwants;
-	__uint32_t		xs_qm_dqshake_reclaims;
-	__uint32_t		xs_qm_dqinact_reclaims;
-# define XFSSTAT_END_INODE_CLUSTER	(XFSSTAT_END_QUOTA_OPS+3)
+# define XFSSTAT_END_INODE_CLUSTER	(XFSSTAT_END_ATTRIBUTE_OPS+3)
 	__uint32_t		xs_iflush_count;
 	__uint32_t		xs_icluster_flushcnt;
 	__uint32_t		xs_icluster_flushinode;
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_super.c linux-2.5.66-bk3/fs/xfs/linux/xfs_super.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_super.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_super.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -31,107 +31,68 @@
  */
 
 #include <xfs.h>
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
 #include <linux/namei.h>
-#include <linux/pagemap.h>
-#include <linux/major.h>
 #include <linux/init.h>
-#include <linux/ctype.h>
-#include <linux/seq_file.h>
 #include <linux/mount.h>
 #include "xfs_version.h"
 
-/* xfs_vfs[ops].c */
-extern int  xfs_init(void);
-extern void xfs_cleanup(void);
-
-/* For kernels which have the s_maxbytes field - set it */
-#ifdef MAX_NON_LFS
-# define set_max_bytes(sb)	((sb)->s_maxbytes = XFS_MAX_FILE_OFFSET)
-#else
-# define set_max_bytes(sb)	do { } while (0)
-#endif
-
-#ifdef CONFIG_XFS_POSIX_ACL
-# define set_posix_acl(sb)	((sb)->s_flags |= MS_POSIXACL)
-#else
-# define set_posix_acl(sb)	do { } while (0)
-#endif
-
-#ifdef CONFIG_XFS_QUOTA
-STATIC struct quotactl_ops linvfs_qops = {
-	.get_xstate		= linvfs_getxstate,
-	.set_xstate		= linvfs_setxstate,
-	.get_xquota		= linvfs_getxquota,
-	.set_xquota		= linvfs_setxquota,
-};
-# define set_quota_ops(sb)	((sb)->s_qcop = &linvfs_qops)
-#else
-# define set_quota_ops(sb)	do { } while (0)
-#endif
-
-#ifdef CONFIG_XFS_DMAPI
-int dmapi_init(void);
-void dmapi_uninit(void);
-#else
-#define dmapi_init()
-#define dmapi_uninit()
-#endif
-
+STATIC struct quotactl_ops linvfs_qops;
 STATIC struct super_operations linvfs_sops;
 STATIC struct export_operations linvfs_export_ops;
+STATIC kmem_cache_t * linvfs_inode_cachep;
 
 #define MNTOPT_LOGBUFS	"logbufs"	/* number of XFS log buffers */
-#define MNTOPT_LOGBSIZE "logbsize"	/* size of XFS log buffers */
+#define MNTOPT_LOGBSIZE	"logbsize"	/* size of XFS log buffers */
 #define MNTOPT_LOGDEV	"logdev"	/* log device */
 #define MNTOPT_RTDEV	"rtdev"		/* realtime I/O device */
-#define MNTOPT_DMAPI	"dmapi"		/* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_XDSM	"xdsm"		/* DMI enabled (DMAPI / XDSM) */
 #define MNTOPT_BIOSIZE	"biosize"	/* log2 of preferred buffered io size */
 #define MNTOPT_WSYNC	"wsync"		/* safe-mode nfs compatible mount */
 #define MNTOPT_INO64	"ino64"		/* force inodes into 64-bit range */
 #define MNTOPT_NOALIGN	"noalign"	/* turn off stripe alignment */
 #define MNTOPT_SUNIT	"sunit"		/* data volume stripe unit */
 #define MNTOPT_SWIDTH	"swidth"	/* data volume stripe width */
-#define MNTOPT_NORECOVERY "norecovery"	/* don't run XFS recovery */
-#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
-#define MNTOPT_QUOTA	"quota"		/* disk quotas */
-#define MNTOPT_NOQUOTA	"noquota"	/* no quotas */
-#define MNTOPT_UQUOTA	"usrquota"	/* user quota enabled */
-#define MNTOPT_GQUOTA	"grpquota"	/* group quota enabled */
-#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
-#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
-#define MNTOPT_QUOTANOENF  "qnoenforce" /* same as uqnoenforce */
-#define MNTOPT_NOUUID	"nouuid"	/* Ignore FS uuid */
-#define MNTOPT_NOLOGFLUSH  "nologflush"	/* Don't use hard flushes in
-					   log writing */
+#define MNTOPT_NOUUID	"nouuid"	/* ignore filesystem UUID */
 #define MNTOPT_MTPT	"mtpt"		/* filesystem mount point */
+#define MNTOPT_NORECOVERY   "norecovery"   /* don't run XFS recovery */
+#define MNTOPT_NOLOGFLUSH   "nologflush"   /* don't hard flush on log writes */
+#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
 
-STATIC int
+STATIC struct xfs_mount_args *
+args_allocate(
+	struct super_block	*sb)
+{
+	struct xfs_mount_args	*args;
+
+	args = kmem_zalloc(sizeof(struct xfs_mount_args), KM_SLEEP);
+	args->logbufs = args->logbufsize = -1;
+	strncpy(args->fsname, sb->s_id, MAXNAMELEN);
+
+	/* Copy the already-parsed mount(2) flags we're interested in */
+	if (sb->s_flags & MS_NOATIME)
+		args->flags |= XFSMNT_NOATIME;
+
+	/* Default to 32 bit inodes on Linux all the time */
+	args->flags |= XFSMNT_32BITINODES;
+
+	return args;
+}
+
+int
 xfs_parseargs(
+	struct bhv_desc		*bhv,
 	char			*options,
-	int			flags,
-	struct xfs_mount_args	*args)
+	struct xfs_mount_args	*args,
+	int			update)
 {
+	struct vfs		*vfsp = bhvtovfs(bhv);
 	char			*this_char, *value, *eov;
 	int			dsunit, dswidth, vol_dsunit, vol_dswidth;
-	int			logbufs, logbufsize;
 	int			iosize;
 
-	/* Default to 32 bit inodes on linux all the time */
-	args->flags |= XFSMNT_32BITINODES;
-
-	/* Copy the already-parsed mount(2) flags we're interested in */
-	if (flags & MS_NOATIME)
-		args->flags |= XFSMNT_NOATIME;
-
-	if (!options) {
-		args->logbufs = args->logbufsize = -1;
+	if (!options)
 		return 0;
-	}
 
-	logbufs = logbufsize = -1;
 	iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;
 
 	while ((this_char = strsep(&options, ",")) != NULL) {
@@ -146,22 +107,23 @@
 					MNTOPT_LOGBUFS);
 				return -EINVAL;
 			}
-			logbufs = simple_strtoul(value, &eov, 10);
+			args->logbufs = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
-			int	in_kilobytes = 0;
+			int	last, in_kilobytes = 0;
 
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
 					MNTOPT_LOGBSIZE);
 				return -EINVAL;
 			}
-			if (toupper(value[strlen(value)-1]) == 'K') {
+			last = strlen(value) - 1;
+			if (value[last] == 'K' || value[last] == 'k') {
 				in_kilobytes = 1;
-				value[strlen(value)-1] = '\0';
+				value[last] = '\0';
 			}
-			logbufsize = simple_strtoul(value, &eov, 10);
+			args->logbufsize = simple_strtoul(value, &eov, 10);
 			if (in_kilobytes)
-				logbufsize = logbufsize * 1024;
+				args->logbufsize <<= 10;
 		} else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
@@ -176,17 +138,6 @@
 				return -EINVAL;
 			}
 			strncpy(args->mtpt, value, MAXNAMELEN);
-#if CONFIG_XFS_DMAPI
-		} else if (!strcmp(this_char, MNTOPT_DMAPI)) {
-			args->flags |= XFSMNT_DMAPI;
-		} else if (!strcmp(this_char, MNTOPT_XDSM)) {
-			args->flags |= XFSMNT_DMAPI;
-#else
-		} else if (!strcmp(this_char, MNTOPT_DMAPI) ||
-			   !strcmp(this_char, MNTOPT_XDSM)) {
-			printk("XFS: this kernel does not support dmapi/xdsm.\n");
-			return -EINVAL;
-#endif
 		} else if (!strcmp(this_char, MNTOPT_RTDEV)) {
 			if (!value || !*value) {
 				printk("XFS: %s option requires an argument\n",
@@ -210,28 +161,12 @@
 		} else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
 			args->flags |= XFSMNT_NORECOVERY;
 		} else if (!strcmp(this_char, MNTOPT_INO64)) {
-#ifdef XFS_BIG_FILESYSTEMS
 			args->flags |= XFSMNT_INO64;
-#else
+#ifndef XFS_BIG_FILESYSTEMS
 			printk("XFS: %s option not allowed on this system\n",
 				MNTOPT_INO64);
 			return -EINVAL;
 #endif
-		} else if (!strcmp(this_char, MNTOPT_UQUOTA)) {
-			args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
-		} else if (!strcmp(this_char, MNTOPT_QUOTA)) {
-			args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
-		} else if (!strcmp(this_char, MNTOPT_UQUOTANOENF)) {
-			args->flags |= XFSMNT_UQUOTA;
-			args->flags &= ~XFSMNT_UQUOTAENF;
-		} else if (!strcmp(this_char, MNTOPT_QUOTANOENF)) {
-			args->flags |= XFSMNT_UQUOTA;
-			args->flags &= ~XFSMNT_UQUOTAENF;
-		} else if (!strcmp(this_char, MNTOPT_GQUOTA)) {
-			args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
-		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
-			args->flags |= XFSMNT_GQUOTA;
-			args->flags &= ~XFSMNT_GQUOTAENF;
 		} else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
 			args->flags |= XFSMNT_NOALIGN;
 		} else if (!strcmp(this_char, MNTOPT_SUNIT)) {
@@ -264,7 +199,7 @@
 	}
 
 	if (args->flags & XFSMNT_NORECOVERY) {
-		if ((flags & MS_RDONLY) == 0) {
+		if ((vfsp->vfs_flag & VFS_RDONLY) == 0) {
 			printk("XFS: no-recovery mounts must be read-only.\n");
 			return -EINVAL;
 		}
@@ -292,22 +227,21 @@
 		if (dsunit) {
 			args->sunit = dsunit;
 			args->flags |= XFSMNT_RETERR;
-		} else
+		} else {
 			args->sunit = vol_dsunit;
+		}
 		dswidth ? (args->swidth = dswidth) :
 			  (args->swidth = vol_dswidth);
-	} else
+	} else {
 		args->sunit = args->swidth = 0;
-
-	args->logbufs = logbufs;
-	args->logbufsize = logbufsize;
+	}
 
 	return 0;
 }
 
-STATIC int
+int
 xfs_showargs(
-	struct vfs		*vfsp,
+	struct bhv_desc		*bhv,
 	struct seq_file		*m)
 {
 	static struct proc_xfs_info {
@@ -322,7 +256,7 @@
 		{ 0, NULL }
 	};
 	struct proc_xfs_info	*xfs_infop;
-	struct xfs_mount	*mp = XFS_BHVTOM(vfsp->vfs_fbhv);
+	struct xfs_mount	*mp = XFS_BHVTOM(bhv);
 	char b[BDEVNAME_SIZE];
 
 	for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
@@ -330,18 +264,6 @@
 			seq_puts(m, xfs_infop->str);
 	}
 
-	if (mp->m_qflags & XFS_UQUOTA_ACCT) {
-		(mp->m_qflags & XFS_UQUOTA_ENFD) ?
-			seq_puts(m, "," MNTOPT_UQUOTA) :
-			seq_puts(m, "," MNTOPT_UQUOTANOENF);
-	}
-
-	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
-		(mp->m_qflags & XFS_GQUOTA_ENFD) ?
-			seq_puts(m, "," MNTOPT_GQUOTA) :
-			seq_puts(m, "," MNTOPT_GQUOTANOENF);
-	}
-
 	if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
 		seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log);
 
@@ -368,9 +290,6 @@
 		seq_printf(m, "," MNTOPT_SWIDTH "=%d",
 				(int)XFS_FSB_TO_BB(mp, mp->m_swidth));
 
-	if (vfsp->vfs_flag & VFS_DMI)
-		seq_puts(m, "," MNTOPT_DMAPI);
-
 	return 0;
 }
 
@@ -402,21 +321,21 @@
 
 STATIC __inline__ void
 xfs_revalidate_inode(
-	xfs_mount_t	*mp,
-	vnode_t		*vp,
-	xfs_inode_t	*ip)
+	xfs_mount_t		*mp,
+	vnode_t			*vp,
+	xfs_inode_t		*ip)
 {
-	struct inode	*inode = LINVFS_GET_IP(vp);
+	struct inode		*inode = LINVFS_GET_IP(vp);
 
 	inode->i_mode	= (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
 	inode->i_nlink	= ip->i_d.di_nlink;
 	inode->i_uid	= ip->i_d.di_uid;
 	inode->i_gid 	= ip->i_d.di_gid;
 	if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
-		inode->i_rdev	= NODEV;
+		inode->i_rdev = NODEV;
 	} else {
 		xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
-		inode->i_rdev	= XFS_DEV_TO_KDEVT(dev);
+		inode->i_rdev = XFS_DEV_TO_KDEVT(dev);
 	}
 	inode->i_blksize = PAGE_CACHE_SIZE;
 	inode->i_generation = ip->i_d.di_gen;
@@ -435,23 +354,24 @@
 
 void
 xfs_initialize_vnode(
-	bhv_desc_t	*bdp,
-	vnode_t		*vp,
-	bhv_desc_t	*inode_bhv,
-	int		unlock)
+	bhv_desc_t		*bdp,
+	vnode_t			*vp,
+	bhv_desc_t		*inode_bhv,
+	int			unlock)
 {
-	xfs_inode_t	*ip = XFS_BHVTOI(inode_bhv);
-	struct inode	*inode = LINVFS_GET_IP(vp);
+	xfs_inode_t		*ip = XFS_BHVTOI(inode_bhv);
+	struct inode		*inode = LINVFS_GET_IP(vp);
 
-	if (vp->v_fbhv == NULL) {
+	if (!inode_bhv->bd_vobj) {
 		vp->v_vfsp = bhvtovfs(bdp);
-		bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
-		bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
+		bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops);
+		bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
 	}
 
 	vp->v_type = IFTOVT(ip->i_d.di_mode);
+
 	/* Have we been called during the new inode create process,
-	 * in which case we are too early to fill in the linux inode.
+	 * in which case we are too early to fill in the Linux inode.
 	 */
 	if (vp->v_type == VNON)
 		return;
@@ -497,7 +417,7 @@
 	xfs_buftarg_t		*btp)
 {
 	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
-	kfree(btp);
+	kmem_free(btp, sizeof(*btp));
 }
 
 void
@@ -548,8 +468,6 @@
 	return btp;
 }
 
-STATIC kmem_cache_t * linvfs_inode_cachep;
-
 STATIC __inline__ unsigned int gfp_mask(void)
 {
 	/* If we're not in a transaction, FS activity is ok */
@@ -557,7 +475,6 @@
 	return GFP_KERNEL;
 }
 
-
 STATIC struct inode *
 linvfs_alloc_inode(
 	struct super_block	*sb)
@@ -606,119 +523,7 @@
 destroy_inodecache( void )
 {
 	if (kmem_cache_destroy(linvfs_inode_cachep))
-		printk(KERN_INFO
-			"linvfs_inode_cache: not all structures were freed\n");
-}
-
-static int
-linvfs_fill_super(
-	struct super_block	*sb,
-	void			*data,
-	int			silent)
-{
-	vfs_t			*vfsp;
-	vfsops_t		*vfsops;
-	vnode_t			*rootvp;
-	struct inode		*ip;
-	struct xfs_mount_args	*args;
-	struct statfs		statvfs;
-	int			error = EINVAL;
-
-	args = kmalloc(sizeof(struct xfs_mount_args), GFP_KERNEL);
-	if (!args)
-		return  -EINVAL;
-	memset(args, 0, sizeof(struct xfs_mount_args));
-	args->slcount = args->stimeout = args->ctimeout = -1;
-	strncpy(args->fsname, sb->s_id, MAXNAMELEN);
-	if (xfs_parseargs((char *)data, sb->s_flags, args))
-		goto out_null;
-
-	/*  Kludge in XFS until we have other VFS/VNODE FSs  */
-	vfsops = &xfs_vfsops;
-
-	/*  Set up the vfs_t structure	*/
-	vfsp = vfs_allocate();
-	if (!vfsp) {
-		error = ENOMEM;
-		goto out_null;
-	}
-
-	if (sb->s_flags & MS_RDONLY)
-		vfsp->vfs_flag |= VFS_RDONLY;
-
-	vfsp->vfs_super = sb;
-	set_max_bytes(sb);
-	set_quota_ops(sb);
-	sb->s_op = &linvfs_sops;
-	sb->s_export_op = &linvfs_export_ops;
-
-	sb_min_blocksize(sb, BBSIZE);
-
-	LINVFS_SET_VFS(sb, vfsp);
-
-	VFSOPS_MOUNT(vfsops, vfsp, args, NULL, error);
-	if (error)
-		goto fail_vfsop;
-
-	VFS_STATVFS(vfsp, &statvfs, NULL, error);
-	if (error)
-		goto fail_unmount;
-
-	sb->s_magic = XFS_SB_MAGIC;
-	sb->s_dirt = 1;
-	sb->s_blocksize = statvfs.f_bsize;
-	sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1;
-	set_posix_acl(sb);
-
-	VFS_ROOT(vfsp, &rootvp, error);
-	if (error)
-		goto fail_unmount;
-
-	ip = LINVFS_GET_IP(rootvp);
-
-	sb->s_root = d_alloc_root(ip);
-	if (!sb->s_root)
-		goto fail_vnrele;
-	if (is_bad_inode(sb->s_root->d_inode))
-		goto fail_vnrele;
-
-	/* Don't set the VFS_DMI flag until here because we don't want
-	 * to send events while replaying the log.
-	 */
-	if (args->flags & XFSMNT_DMAPI) {
-		vfsp->vfs_flag |= VFS_DMI;
-		VFSOPS_DMAPI_MOUNT(vfsops, vfsp, args->mtpt, args->fsname,
-				   error);
-
-		if (error) {
-			if (atomic_read(&sb->s_active) == 1)
-				vfsp->vfs_flag &= ~VFS_DMI;
-			goto fail_vnrele;
-		}
-	}
-
-	vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address);
-
-	kfree(args);
-	return 0;
-
-fail_vnrele:
-	if (sb->s_root) {
-		dput(sb->s_root);
-		sb->s_root = NULL;
-	} else {
-		VN_RELE(rootvp);
-	}
-
-fail_unmount:
-	VFS_UNMOUNT(vfsp, 0, NULL, error);
-
-fail_vfsop:
-	vfs_deallocate(vfsp);
-
-out_null:
-	kfree(args);
-	return -error;
+		printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__);
 }
 
 /*
@@ -789,8 +594,7 @@
 	sb->s_dirt = 0;
 	if (sb->s_flags & MS_RDONLY)
 		return;
-	VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR,
-		NULL, error);
+	VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error);
 }
 
 STATIC int
@@ -811,30 +615,21 @@
 	int			*flags,
 	char			*options)
 {
-	struct xfs_mount_args	*args;
-	vfs_t			*vfsp;
-	xfs_mount_t		*mp;
-	int			error = 0;
-
-	vfsp = LINVFS_GET_VFS(sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
+	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
+	xfs_mount_t		*mp = XFS_VFSTOM(vfsp);
+	struct xfs_mount_args	*args = args_allocate(sb);
+	int			error;
 
-	args = kmalloc(sizeof(struct xfs_mount_args), GFP_KERNEL);
-	if (!args)
-		return -ENOMEM;
-	memset(args, 0, sizeof(struct xfs_mount_args));
-	args->slcount = args->stimeout = args->ctimeout = -1;
-	if (xfs_parseargs(options, *flags, args)) {
-		error = -EINVAL;
+	VFS_PARSEARGS(vfsp, options, args, 1, error);
+	if (error)
 		goto out;
-	}
 
 	if (args->flags & XFSMNT_NOATIME)
 		mp->m_flags |= XFS_MOUNT_NOATIME;
 	else
 		mp->m_flags &= ~XFS_MOUNT_NOATIME;
 
-	set_posix_acl(sb);
+	set_posix_acl_flag(sb);
 	linvfs_write_super(sb);
 
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
@@ -842,14 +637,14 @@
 
 	if (*flags & MS_RDONLY) {
 		sb->s_flags |= MS_RDONLY;
-		XFS_log_write_unmount_ro(vfsp->vfs_fbhv);
+		XFS_log_write_unmount_ro(&mp->m_bhv);
 		vfsp->vfs_flag |= VFS_RDONLY;
 	} else {
 		vfsp->vfs_flag &= ~VFS_RDONLY;
 	}
 
 out:
-	kfree(args);
+	kmem_free(args, sizeof(*args));
 	return error;
 }
 
@@ -950,6 +745,151 @@
 	return result;
 }
 
+STATIC int
+linvfs_show_options(
+	struct seq_file		*m,
+	struct vfsmount		*mnt)
+{
+	struct vfs		*vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
+	int			error;
+
+	VFS_SHOWARGS(vfsp, m, error);
+	return error;
+}
+
+STATIC int
+linvfs_getxstate(
+	struct super_block	*sb,
+	struct fs_quota_stat	*fqs)
+{
+	struct vfs		*vfsp = LINVFS_GET_VFS(sb);
+	int			error;
+
+	VFS_QUOTACTL(vfsp, Q_XGETQSTAT, 0, (caddr_t)fqs, error);
+	return -error;
+}
+
+STATIC int
+linvfs_setxstate(
+	struct super_block	*sb,
+	unsigned int		flags,
+	int			op)
+{
+	struct vfs		*vfsp = LINVFS_GET_VFS(sb);
+	int			error;
+
+	VFS_QUOTACTL(vfsp, op, 0, (caddr_t)&flags, error);
+	return -error;
+}
+
+STATIC int
+linvfs_getxquota(
+	struct super_block	*sb,
+	int			type,
+	qid_t			id,
+	struct fs_disk_quota	*fdq)
+{
+	struct vfs		*vfsp = LINVFS_GET_VFS(sb);
+	int			error, getmode;
+
+	getmode = (type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETQUOTA;
+	VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error);
+	return -error;
+}
+
+STATIC int
+linvfs_setxquota(
+	struct super_block	*sb,
+	int			type,
+	qid_t			id,
+	struct fs_disk_quota	*fdq)
+{
+	struct vfs		*vfsp = LINVFS_GET_VFS(sb);
+	int			error, setmode;
+
+	setmode = (type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETQLIM;
+	VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error);
+	return -error;
+}
+
+STATIC int
+linvfs_fill_super(
+	struct super_block	*sb,
+	void			*data,
+	int			silent)
+{
+	vnode_t			*rootvp;
+	struct vfs		*vfsp = vfs_allocate();
+	struct xfs_mount_args	*args = args_allocate(sb);
+	struct statfs		statvfs;
+	int			error;
+
+	vfsp->vfs_super = sb;
+	LINVFS_SET_VFS(sb, vfsp);
+	if (sb->s_flags & MS_RDONLY)
+		vfsp->vfs_flag |= VFS_RDONLY;
+	bhv_insert_all_vfsops(vfsp);
+
+	VFS_PARSEARGS(vfsp, (char *)data, args, 0, error);
+	if (error) {
+		bhv_remove_all_vfsops(vfsp, 1);
+		goto fail_vfsop;
+	}
+
+	sb_min_blocksize(sb, BBSIZE);
+	sb->s_maxbytes = XFS_MAX_FILE_OFFSET;
+	sb->s_export_op = &linvfs_export_ops;
+	sb->s_qcop = &linvfs_qops;
+	sb->s_op = &linvfs_sops;
+
+	VFS_MOUNT(vfsp, args, NULL, error);
+	if (error) {
+		bhv_remove_all_vfsops(vfsp, 1);
+		goto fail_vfsop;
+	}
+
+	VFS_STATVFS(vfsp, &statvfs, NULL, error);
+	if (error)
+		goto fail_unmount;
+
+	sb->s_dirt = 1;
+	sb->s_magic = XFS_SB_MAGIC;
+	sb->s_blocksize = statvfs.f_bsize;
+	sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1;
+	set_posix_acl_flag(sb);
+
+	VFS_ROOT(vfsp, &rootvp, error);
+	if (error)
+		goto fail_unmount;
+
+	sb->s_root = d_alloc_root(LINVFS_GET_IP(rootvp));
+	if (!sb->s_root)
+		goto fail_vnrele;
+	if (is_bad_inode(sb->s_root->d_inode))
+		goto fail_vnrele;
+
+	vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address);
+
+	kmem_free(args, sizeof(*args));
+	return 0;
+
+fail_vnrele:
+	if (sb->s_root) {
+		dput(sb->s_root);
+		sb->s_root = NULL;
+	} else {
+		VN_RELE(rootvp);
+	}
+
+fail_unmount:
+	VFS_UNMOUNT(vfsp, 0, NULL, error);
+
+fail_vfsop:
+	vfs_deallocate(vfsp);
+	kmem_free(args, sizeof(*args));
+	return -error;
+}
+
 STATIC struct super_block *
 linvfs_get_sb(
 	struct file_system_type	*fs_type,
@@ -960,15 +900,6 @@
 	return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super);
 }
 
-STATIC int
-linvfs_show_options(
-	struct seq_file		*m,
-	struct vfsmount		*mnt)
-{
-	vfs_t			*vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
-
-	return xfs_showargs(vfsp, m);
-}
 
 STATIC struct export_operations linvfs_export_ops = {
 	.get_parent		= linvfs_get_parent,
@@ -989,6 +920,13 @@
 	.show_options		= linvfs_show_options,
 };
 
+STATIC struct quotactl_ops linvfs_qops = {
+	.get_xstate		= linvfs_getxstate,
+	.set_xstate		= linvfs_setxstate,
+	.get_xquota		= linvfs_getxquota,
+	.set_xquota		= linvfs_setxquota,
+};
+
 STATIC struct file_system_type xfs_fs_type = {
 	.owner			= THIS_MODULE,
 	.name			= "xfs",
@@ -997,6 +935,7 @@
 	.fs_flags		= FS_REQUIRES_DEV,
 };
 
+
 STATIC int __init
 init_xfs_fs( void )
 {
@@ -1008,37 +947,44 @@
 
 	printk(message);
 
-	error = init_inodecache();
-	if (error < 0)
-		return error;
-
 	si_meminfo(&si);
 	xfs_physmem = si.totalram;
 
+	error = init_inodecache();
+	if (error < 0)
+		goto undo_inodecache;
+
 	error = pagebuf_init();
 	if (error < 0)
-		goto out;
+		goto undo_pagebuf;
 
 	vn_init();
 	xfs_init();
-	dmapi_init();
+	vfs_initdmapi();
+	vfs_initquota();
 
 	error = register_filesystem(&xfs_fs_type);
 	if (error)
-		goto out;
+		goto undo_register;
 	return 0;
 
-out:
+undo_register:
+	pagebuf_terminate();
+
+undo_pagebuf:
 	destroy_inodecache();
+
+undo_inodecache:
 	return error;
 }
 
 STATIC void __exit
 exit_xfs_fs( void )
 {
-	dmapi_uninit();
-	xfs_cleanup();
 	unregister_filesystem(&xfs_fs_type);
+	xfs_cleanup();
+	vfs_exitquota();
+	vfs_exitdmapi();
 	pagebuf_terminate();
 	destroy_inodecache();
 }
@@ -1047,5 +993,6 @@
 module_exit(exit_xfs_fs);
 
 MODULE_AUTHOR("SGI <sgi.com>");
-MODULE_DESCRIPTION("SGI XFS " XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled");
+MODULE_DESCRIPTION(
+	"SGI XFS " XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled");
 MODULE_LICENSE("GPL");
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_super.h linux-2.5.66-bk3/fs/xfs/linux/xfs_super.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_super.h	Mon Mar 24 14:00:11 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_super.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -32,28 +32,38 @@
 #ifndef __XFS_SUPER_H__
 #define __XFS_SUPER_H__
 
-#ifdef CONFIG_XFS_POSIX_ACL
-# define XFS_ACL_STRING		"ACLs, "
-#else
-# define XFS_ACL_STRING
-#endif
-
 #ifdef CONFIG_XFS_DMAPI
-# define XFS_DMAPI_STRING	"DMAPI, "
-#else
-# define XFS_DMAPI_STRING
+# define vfs_insertdmapi(vfs)	vfs_insertops(vfsp, &xfs_dmops)
+# define vfs_initdmapi()	dmapi_init()
+# define vfs_exitdmapi()	dmapi_uninit()
+#else
+# define vfs_insertdmapi(vfs)	do { } while (0)
+# define vfs_initdmapi()	do { } while (0)
+# define vfs_exitdmapi()	do { } while (0)
 #endif
 
 #ifdef CONFIG_XFS_QUOTA
-# define XFS_QUOTA_STRING	"quota, "
+# define vfs_insertquota(vfs)	vfs_insertops(vfsp, &xfs_qmops)
+# define vfs_initquota()	xfs_qm_init()
+# define vfs_exitquota()	xfs_qm_exit()
+#else
+# define vfs_insertquota(vfs)	do { } while (0)
+# define vfs_initquota()	do { } while (0)
+# define vfs_exitquota()	do { } while (0)
+#endif
+
+#ifdef CONFIG_XFS_POSIX_ACL
+# define XFS_ACL_STRING		"ACLs, "
+# define set_posix_acl_flag(sb)	((sb)->s_flags |= MS_POSIXACL)
 #else
-# define XFS_QUOTA_STRING
+# define XFS_ACL_STRING
+# define set_posix_acl_flag(sb)	do { } while (0)
 #endif
 
 #ifdef CONFIG_XFS_RT
-# define XFS_RT_STRING		"realtime, "
+# define XFS_REALTIME_STRING	"realtime, "
 #else
-# define XFS_RT_STRING
+# define XFS_REALTIME_STRING
 #endif
 
 #ifdef CONFIG_XFS_VNODE_TRACING
@@ -68,9 +78,9 @@
 # define XFS_DBG_STRING		"no debug"
 #endif
 
-#define XFS_BUILD_OPTIONS	XFS_ACL_STRING XFS_DMAPI_STRING \
-				XFS_RT_STRING \
-				XFS_QUOTA_STRING XFS_VNTRACE_STRING \
+#define XFS_BUILD_OPTIONS	XFS_ACL_STRING \
+				XFS_REALTIME_STRING \
+				XFS_VNTRACE_STRING \
 				XFS_DBG_STRING /* DBG must be last */
 
 #define LINVFS_GET_VFS(s) \
@@ -82,6 +92,8 @@
 struct pb_target;
 struct block_device;
 
+extern int  xfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int);
+extern int  xfs_showargs(bhv_desc_t *, struct seq_file *);
 extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int);
 
 extern int  xfs_blkdev_get(struct xfs_mount *, const char *,
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_vfs.c linux-2.5.66-bk3/fs/xfs/linux/xfs_vfs.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_vfs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_vfs.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+
+int
+vfs_mount(
+	struct bhv_desc		*bdp,
+	struct xfs_mount_args	*args,
+	struct cred		*cr)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_mount)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_mount)(next, args, cr));
+}
+
+int
+vfs_parseargs(
+	struct bhv_desc		*bdp,
+	char			*s,
+	struct xfs_mount_args	*args,
+	int			f)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_parseargs)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_parseargs)(next, s, args, f));
+}
+
+int
+vfs_showargs(
+	struct bhv_desc		*bdp,
+	struct seq_file		*m)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_showargs)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_showargs)(next, m));
+}
+
+int
+vfs_unmount(
+	struct bhv_desc		*bdp,
+	int			fl,
+	struct cred		*cr)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_unmount)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_unmount)(next, fl, cr));
+}
+
+int
+vfs_root(
+	struct bhv_desc		*bdp,
+	struct vnode		**vpp)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_root)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_root)(next, vpp));
+}
+
+int
+vfs_statvfs(
+	struct bhv_desc		*bdp,
+	struct statfs		*sp,
+	struct vnode		*vp)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_statvfs)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_statvfs)(next, sp, vp));
+}
+
+int
+vfs_sync(
+	struct bhv_desc		*bdp,
+	int			fl,
+	struct cred		*cr)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_sync)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_sync)(next, fl, cr));
+}
+
+int
+vfs_vget(
+	struct bhv_desc		*bdp,
+	struct vnode		**vpp,
+	struct fid		*fidp)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_vget)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_vget)(next, vpp, fidp));
+}
+
+int
+vfs_dmapiops(
+	struct bhv_desc		*bdp,
+	caddr_t			addr)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_dmapiops)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_dmapiops)(next, addr));
+}
+
+int
+vfs_quotactl(
+	struct bhv_desc		*bdp,
+	int			cmd,
+	int			id,
+	caddr_t			addr)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_quotactl)
+		next = BHV_NEXT(next);
+	return ((*bhvtovfsops(next)->vfs_quotactl)(next, cmd, id, addr));
+}
+
+void
+vfs_init_vnode(
+	struct bhv_desc		*bdp,
+	struct vnode		*vp,
+	struct bhv_desc		*bp,
+	int			unlock)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_init_vnode)
+		next = BHV_NEXT(next);
+	((*bhvtovfsops(next)->vfs_init_vnode)(next, vp, bp, unlock));
+}
+
+void
+vfs_force_shutdown(
+	struct bhv_desc		*bdp,
+	int			fl,
+	char			*file,
+	int			line)
+{
+	struct bhv_desc		*next = bdp;
+
+	ASSERT(next);
+	while (! (bhvtovfsops(next))->vfs_force_shutdown)
+		next = BHV_NEXT(next);
+	((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line));
+}
+
+vfs_t *
+vfs_allocate( void )
+{
+	struct vfs		*vfsp;
+
+	vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
+	bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
+	return vfsp;
+}
+
+void
+vfs_deallocate(
+	struct vfs		*vfsp)
+{
+	bhv_head_destroy(VFS_BHVHEAD(vfsp));
+	kmem_free(vfsp, sizeof(vfs_t));
+}
+
+void
+vfs_insertops(
+	struct vfs		*vfsp,
+	struct bhv_vfsops	*vfsops)
+{
+	struct bhv_desc		*bdp;
+
+	bdp = kmem_alloc(sizeof(struct bhv_desc), KM_SLEEP);
+	bhv_desc_init(bdp, NULL, vfsp, vfsops);
+	bhv_insert(&vfsp->vfs_bh, bdp);
+}
+
+void
+vfs_insertbhv(
+	struct vfs		*vfsp,
+	struct bhv_desc		*bdp,
+	struct vfsops		*vfsops,
+	void			*mount)
+{
+	bhv_desc_init(bdp, mount, vfsp, vfsops);
+	bhv_insert_initial(&vfsp->vfs_bh, bdp);
+}
+
+void
+bhv_remove_vfsops(
+	struct vfs		*vfsp,
+	int			pos)
+{
+	struct bhv_desc		*bhv;
+
+	bhv = bhv_lookup_range(&vfsp->vfs_bh, pos, pos);
+	if (!bhv)
+		return;
+	bhv_remove(&vfsp->vfs_bh, bhv);
+	kmem_free(bhv, sizeof(*bhv));
+}
+
+void
+bhv_remove_all_vfsops(
+	struct vfs		*vfsp,
+	int			freebase)
+{
+	struct xfs_mount	*mp;
+
+	bhv_remove_vfsops(vfsp, VFS_POSITION_QM);
+	bhv_remove_vfsops(vfsp, VFS_POSITION_DM);
+	if (!freebase)
+		return;
+	mp = XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfsp), &xfs_vfsops));
+	VFS_REMOVEBHV(vfsp, &mp->m_bhv);
+	xfs_mount_free(mp, 0);
+}
+
+void
+bhv_insert_all_vfsops(
+	struct vfs		*vfsp)
+{
+	struct xfs_mount	*mp;
+
+	mp = xfs_mount_init();
+	vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+	vfs_insertdmapi(vfsp);
+	vfs_insertquota(vfsp);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_vfs.h linux-2.5.66-bk3/fs/xfs/linux/xfs_vfs.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_vfs.h	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_vfs.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -34,162 +34,154 @@
 
 #include <linux/vfs.h>
 
-struct statfs;
-struct vnode;
+struct fid;
 struct cred;
+struct vnode;
+struct statfs;
+struct seq_file;
 struct super_block;
-struct fid;
-struct dm_fcntl_vector;
 struct xfs_mount_args;
 
 typedef struct vfs {
-	u_int		vfs_flag;	/* flags */
-	fsid_t		vfs_fsid;	/* file system id */
-	fsid_t		*vfs_altfsid;	/* An ID fixed for life of FS */
-	bhv_head_t	vfs_bh;		/* head of vfs behavior chain */
-	struct super_block *vfs_super;	/* pointer to super block structure */
+	u_int			vfs_flag;	/* flags */
+	fsid_t			vfs_fsid;	/* file system ID */
+	fsid_t			*vfs_altfsid;	/* An ID fixed for life of FS */
+	bhv_head_t		vfs_bh;		/* head of vfs behavior chain */
+	struct super_block	*vfs_super;	/* Linux superblock structure */
 } vfs_t;
 
-#define vfs_fbhv	vfs_bh.bh_first		/* 1st on vfs behavior chain */
-#define VFS_FOPS(vfsp)	\
-	((vfsops_t *)((vfsp)->vfs_fbhv->bd_ops))/* ops for 1st behavior */
-
-
-#define bhvtovfs(bdp)	((struct vfs *)BHV_VOBJ(bdp))
-#define VFS_BHVHEAD(vfsp) (&(vfsp)->vfs_bh)
-
-
-#define VFS_RDONLY	0x0001		/* read-only vfs */
-#define VFS_GRPID	0x0002		/* group-ID assigned from directory */
-#define VFS_DMI		0x0004		/* filesystem has the DMI enabled */
-
-#define SYNC_ATTR	0x0001		/* sync attributes */
-#define SYNC_CLOSE	0x0002		/* close file system down */
-#define SYNC_DELWRI	0x0004		/* look at delayed writes */
-#define SYNC_WAIT	0x0008		/* wait for i/o to complete */
-#define SYNC_FSDATA	0x0020		/* flush fs data (e.g. superblocks) */
-#define SYNC_BDFLUSH	0x0010		/* BDFLUSH is calling -- don't block */
+#define vfs_fbhv		vfs_bh.bh_first	/* 1st on vfs behavior chain */
 
+#define bhvtovfs(bdp)		( (struct vfs *)BHV_VOBJ(bdp) )
+#define bhvtovfsops(bdp)	( (struct vfsops *)BHV_OPS(bdp) )
+#define VFS_BHVHEAD(vfs)	( &(vfs)->vfs_bh )
+#define VFS_REMOVEBHV(vfs, bdp)	( bhv_remove(VFS_BHVHEAD(vfs), bdp) )
+
+#define VFS_POSITION_BASE	BHV_POSITION_BASE	/* chain bottom */
+#define VFS_POSITION_TOP	BHV_POSITION_TOP	/* chain top */
+#define VFS_POSITION_INVALID	BHV_POSITION_INVALID	/* invalid pos. num */
+
+typedef enum {
+	VFS_BHV_UNKNOWN,	/* not specified */
+	VFS_BHV_XFS,		/* xfs */
+	VFS_BHV_DM,		/* data migration */
+	VFS_BHV_QM,		/* quota manager */
+	VFS_BHV_IO,		/* IO path */
+	VFS_BHV_END		/* housekeeping end-of-range */
+} vfs_bhv_t;
+
+#define VFS_POSITION_XFS	(BHV_POSITION_BASE)
+#define VFS_POSITION_DM		(VFS_POSITION_BASE+10)
+#define VFS_POSITION_QM		(VFS_POSITION_BASE+20)
+#define VFS_POSITION_IO		(VFS_POSITION_BASE+30)
+
+#define VFS_RDONLY		0x0001	/* read-only vfs */
+#define VFS_GRPID		0x0002	/* group-ID assigned from directory */
+#define VFS_DMI			0x0004	/* filesystem has the DMI enabled */
+#define VFS_END			0x0004	/* max flag */
+
+#define SYNC_ATTR		0x0001	/* sync attributes */
+#define SYNC_CLOSE		0x0002	/* close file system down */
+#define SYNC_DELWRI		0x0004	/* look at delayed writes */
+#define SYNC_WAIT		0x0008	/* wait for i/o to complete */
+#define SYNC_FSDATA		0x0020	/* flush fs data (e.g. superblocks) */
+#define SYNC_BDFLUSH		0x0010	/* BDFLUSH is calling -- don't block */
+
+typedef int	(*vfs_mount_t)(bhv_desc_t *,
+				struct xfs_mount_args *, struct cred *);
+typedef int	(*vfs_parseargs_t)(bhv_desc_t *, char *,
+				struct xfs_mount_args *, int);
+typedef	int	(*vfs_showargs_t)(bhv_desc_t *, struct seq_file *);
+typedef int	(*vfs_unmount_t)(bhv_desc_t *, int, struct cred *);
+typedef int	(*vfs_root_t)(bhv_desc_t *, struct vnode **);
+typedef int	(*vfs_statvfs_t)(bhv_desc_t *, struct statfs *, struct vnode *);
+typedef int	(*vfs_sync_t)(bhv_desc_t *, int, struct cred *);
+typedef int	(*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *);
+typedef int	(*vfs_dmapiops_t)(bhv_desc_t *, caddr_t);
+typedef int	(*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t);
+typedef void	(*vfs_init_vnode_t)(bhv_desc_t *,
+				struct vnode *, bhv_desc_t *, int);
+typedef void	(*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int);
 
 typedef struct vfsops {
-	int	(*vfs_mount)(struct vfs *, struct xfs_mount_args *,
-					struct cred *);
-					/* mount file system */
-	int	(*vfs_unmount)(bhv_desc_t *, int, struct cred *);
-					/* unmount file system */
-	int	(*vfs_root)(bhv_desc_t *, struct vnode **);
-					/* get root vnode */
-	int	(*vfs_statvfs)(bhv_desc_t *, struct statfs *, struct vnode *);
-					/* get file system statistics */
-	int	(*vfs_sync)(bhv_desc_t *, int, struct cred *);
-					/* flush files */
-	int	(*vfs_vget)(bhv_desc_t *, struct vnode **, struct fid *);
-					/* get vnode from fid */
-	int	(*vfs_dmapi_mount)(struct vfs *, char *, char *);
-					/* send dmapi mount event */
-	int	(*vfs_dmapi_fsys_vector)(bhv_desc_t *,
-					 struct dm_fcntl_vector *);
-	void	(*vfs_init_vnode)(bhv_desc_t *, struct vnode *,
-					bhv_desc_t *, int);
-	void	(*vfs_force_shutdown)(bhv_desc_t *,
-					int, char *, int);
+	bhv_position_t		vf_position;	/* behavior chain position */
+	vfs_mount_t		vfs_mount;	/* mount file system */
+	vfs_parseargs_t		vfs_parseargs;	/* parse mount options */
+	vfs_showargs_t		vfs_showargs;	/* unparse mount options */
+	vfs_unmount_t		vfs_unmount;	/* unmount file system */
+	vfs_root_t		vfs_root;	/* get root vnode */
+	vfs_statvfs_t		vfs_statvfs;	/* file system statistics */
+	vfs_sync_t		vfs_sync;	/* flush files */
+	vfs_vget_t		vfs_vget;	/* get vnode from fid */
+	vfs_dmapiops_t		vfs_dmapiops;	/* data migration */
+	vfs_quotactl_t		vfs_quotactl;	/* disk quota */
+	vfs_init_vnode_t	vfs_init_vnode;	/* initialize a new vnode */
+	vfs_force_shutdown_t	vfs_force_shutdown;	/* crash and burn */
 } vfsops_t;
 
-#define VFS_UNMOUNT(vfsp,f,cr, rv)	\
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_unmount))((vfsp)->vfs_fbhv, f, cr);	\
-}
-#define VFS_ROOT(vfsp, vpp, rv)		\
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_root))((vfsp)->vfs_fbhv, vpp);	\
-}
-#define VFS_STATVFS(vfsp, sp, vp, rv)	\
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_statvfs))((vfsp)->vfs_fbhv, sp, vp);\
-}
-#define VFS_SYNC(vfsp, flag, cr, rv) \
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_sync))((vfsp)->vfs_fbhv, flag, cr); \
-}
-#define VFS_VGET(vfsp, vpp, fidp, rv) \
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_vget))((vfsp)->vfs_fbhv, vpp, fidp);  \
-}
-
-#define VFS_INIT_VNODE(vfsp, vp, bhv, unlock) \
-{	\
-	(*(VFS_FOPS(vfsp)->vfs_init_vnode))((vfsp)->vfs_fbhv, vp, bhv, unlock);\
-}
-
-/* No behavior lock here */
-#define VFS_FORCE_SHUTDOWN(vfsp, flags) \
-	(*(VFS_FOPS(vfsp)->vfs_force_shutdown))((vfsp)->vfs_fbhv, flags, __FILE__, __LINE__);
-
-#define VFS_DMAPI_FSYS_VECTOR(vfsp, df, rv) \
-{	\
-	rv = (*(VFS_FOPS(vfsp)->vfs_dmapi_fsys_vector))((vfsp)->vfs_fbhv, df);	      \
-}
-
-
-#define VFSOPS_DMAPI_MOUNT(vfs_op, vfsp, dir_name, fsname, rv) \
-	rv = (*(vfs_op)->vfs_dmapi_mount)(vfsp, dir_name, fsname)
-#define VFSOPS_MOUNT(vfs_op, vfsp, args, cr, rv) \
-	rv = (*(vfs_op)->vfs_mount)(vfsp, args, cr)
-
-#define VFS_REMOVEBHV(vfsp, bdp)\
-{	\
-	bhv_remove(VFS_BHVHEAD(vfsp), bdp); \
-}
-
-#define PVFS_UNMOUNT(bdp,f,cr, rv)	\
-{	\
-	rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_unmount)(bdp, f, cr);	\
-}
-
-#define PVFS_SYNC(bdp, flag, cr, rv) \
-{	\
-	rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_sync)(bdp, flag, cr);	\
-}
-
-
-static __inline vfs_t *
-vfs_allocate(void)
-{
-	vfs_t	*vfsp;
-
-	vfsp = kmalloc(sizeof(vfs_t), GFP_KERNEL);
-	if (vfsp) {
-		memset(vfsp, 0, sizeof(vfs_t));
-		bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
-	}
-	return (vfsp);
-}
-
-static __inline void
-vfs_deallocate(
-	vfs_t		*vfsp)
-{
-	bhv_head_destroy(VFS_BHVHEAD(vfsp));
-	kfree(vfsp);
-}
+/*
+ * VFS's.  Operates on vfs structure pointers (starts at bhv head).
+ */
+#define VHEAD(v)			((v)->vfs_fbhv)
+#define VFS_MOUNT(v, ma,cr, rv)		((rv) = vfs_mount(VHEAD(v), ma,cr))
+#define VFS_PARSEARGS(v, o,ma,f, rv)	((rv) = vfs_parseargs(VHEAD(v), o,ma,f))
+#define VFS_SHOWARGS(v, m, rv)		((rv) = vfs_showargs(VHEAD(v), m))
+#define VFS_UNMOUNT(v, f,cr, rv)	((rv) = vfs_unmount(VHEAD(v), f,cr))
+#define VFS_ROOT(v, vpp, rv)		((rv) = vfs_root(VHEAD(v), vpp))
+#define VFS_STATVFS(v, sp,vp, rv)	((rv) = vfs_statvfs(VHEAD(v), sp,vp))
+#define VFS_SYNC(v, flag,cr, rv)	((rv) = vfs_sync(VHEAD(v), flag,cr))
+#define VFS_VGET(v, vpp,fidp, rv)	((rv) = vfs_vget(VHEAD(v), vpp,fidp))
+#define VFS_DMAPIOPS(v, p, rv)		((rv) = vfs_dmapiops(VHEAD(v), p))
+#define VFS_QUOTACTL(v, c,id,p, rv)	((rv) = vfs_quotactl(VHEAD(v), c,id,p))
+#define VFS_INIT_VNODE(v, vp,b,ul)	( vfs_init_vnode(VHEAD(v), vp,b,ul) )
+#define VFS_FORCE_SHUTDOWN(v, fl,f,l)	( vfs_force_shutdown(VHEAD(v), fl,f,l) )
 
 /*
- * Called by fs dependent VFS_MOUNT code to link the VFS base file system
- * dependent behavior with the VFS virtual object.
+ * PVFS's.  Operates on behavior descriptor pointers.
  */
-static __inline void
-vfs_insertbhv(
-	vfs_t		*vfsp,
-	bhv_desc_t	*bdp,
-	vfsops_t	*vfsops,
-	void		*mount)
-{
-	/*
-	 * Initialize behavior desc with ops and data and then
-	 * attach it to the vfs.
-	 */
-	bhv_desc_init(bdp, mount, vfsp, vfsops);
-	bhv_insert_initial(&vfsp->vfs_bh, bdp);
-}
+#define PVFS_MOUNT(b, ma,cr, rv)	((rv) = vfs_mount(b, ma,cr))
+#define PVFS_PARSEARGS(b, o,ma,f, rv)	((rv) = vfs_parseargs(b, o,ma,f))
+#define PVFS_SHOWARGS(b, m, rv)		((rv) = vfs_showargs(b, m))
+#define PVFS_UNMOUNT(b, f,cr, rv)	((rv) = vfs_unmount(b, f,cr))
+#define PVFS_ROOT(b, vpp, rv)		((rv) = vfs_root(b, vpp))
+#define PVFS_STATVFS(b, sp,vp, rv)	((rv) = vfs_statvfs(b, sp,vp))
+#define PVFS_SYNC(b, flag,cr, rv)	((rv) = vfs_sync(b, flag,cr))
+#define PVFS_VGET(b, vpp,fidp, rv)	((rv) = vfs_vget(b, vpp,fidp))
+#define PVFS_DMAPIOPS(b, p, rv)		((rv) = vfs_dmapiops(b, p))
+#define PVFS_QUOTACTL(b, c,id,p, rv)	((rv) = vfs_quotactl(b, c,id,p))
+#define PVFS_INIT_VNODE(b, vp,b2,ul)	( vfs_init_vnode(b, vp,b2,ul) )
+#define PVFS_FORCE_SHUTDOWN(b, fl,f,l)	( vfs_force_shutdown(b, fl,f,l) )
+
+extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *);
+extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int);
+extern int vfs_showargs(bhv_desc_t *, struct seq_file *);
+extern int vfs_unmount(bhv_desc_t *, int, struct cred *);
+extern int vfs_root(bhv_desc_t *, struct vnode **);
+extern int vfs_statvfs(bhv_desc_t *, struct statfs *, struct vnode *);
+extern int vfs_sync(bhv_desc_t *, int, struct cred *);
+extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *);
+extern int vfs_dmapiops(bhv_desc_t *, caddr_t);
+extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t);
+extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int);
+extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int);
+
+typedef struct bhv_vfsops {
+	struct vfsops		bhv_common;
+	void *			bhv_custom;
+} bhv_vfsops_t;
+
+#define vfs_bhv_lookup(v, id)	( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) )
+#define vfs_bhv_custom(b)	( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom )
+#define vfs_bhv_set_custom(b,o)	( (b)->bhv_custom = (void *)(o))
+#define vfs_bhv_clr_custom(b)	( (b)->bhv_custom = NULL )
+
+extern vfs_t *vfs_allocate(void);
+extern void vfs_deallocate(vfs_t *);
+extern void vfs_insertops(vfs_t *, bhv_vfsops_t *);
+extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *);
+
+extern void bhv_insert_all_vfsops(struct vfs *);
+extern void bhv_remove_all_vfsops(struct vfs *, int);
+extern void bhv_remove_vfsops(struct vfs *, int);
 
 #endif	/* __XFS_VFS_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_vnode.c linux-2.5.66-bk3/fs/xfs/linux/xfs_vnode.c
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_vnode.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_vnode.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,6 @@
  */
 
 #include <xfs.h>
-#include <linux/pagemap.h>
 
 
 uint64_t vn_generation;		/* vnode generation number */
@@ -73,19 +72,19 @@
  * Clean a vnode of filesystem-specific data and prepare it for reuse.
  */
 STATIC int
-vn_reclaim(struct vnode *vp)
+vn_reclaim(
+	struct vnode	*vp)
 {
-	int	error;
+	int		error;
 
 	XFS_STATS_INC(xfsstats.vn_reclaim);
-
 	vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address);
 
 	/*
 	 * Only make the VOP_RECLAIM call if there are behaviors
 	 * to call.
 	 */
-	if (vp->v_fbhv != NULL) {
+	if (vp->v_fbhv) {
 		VOP_RECLAIM(vp, error);
 		if (error)
 			return -error;
@@ -108,18 +107,19 @@
 }
 
 STATIC void
-vn_wakeup(struct vnode *vp)
+vn_wakeup(
+	struct vnode	*vp)
 {
 	VN_LOCK(vp);
-	if (vp->v_flag & VWAIT) {
+	if (vp->v_flag & VWAIT)
 		sv_broadcast(vptosync(vp));
-	}
 	vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED);
 	VN_UNLOCK(vp, 0);
 }
 
 int
-vn_wait(struct vnode *vp)
+vn_wait(
+	struct vnode	*vp)
 {
 	VN_LOCK(vp);
 	if (vp->v_flag & (VINACT | VRECLM)) {
@@ -132,7 +132,8 @@
 }
 
 struct vnode *
-vn_initialize(struct inode *inode)
+vn_initialize(
+	struct inode	*inode)
 {
 	struct vnode	*vp = LINVFS_GET_VP(inode);
 
@@ -165,7 +166,9 @@
  * Get a reference on a vnode.
  */
 vnode_t *
-vn_get(struct vnode *vp, vmap_t *vmap)
+vn_get(
+	struct vnode	*vp,
+	vmap_t		*vmap)
 {
 	struct inode	*inode;
 
@@ -175,7 +178,7 @@
 		return NULL;
 
 	inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino);
-	if (inode == NULL)		/* Inode not present */
+	if (!inode)	/* Inode not present */
 		return NULL;
 
 	vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
@@ -187,16 +190,17 @@
  * Revalidate the Linux inode from the vnode.
  */
 int
-vn_revalidate(struct vnode *vp)
+vn_revalidate(
+	struct vnode	*vp)
 {
-	int		error;
 	struct inode	*inode;
 	vattr_t		va;
+	int		error;
 
 	vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address);
 	ASSERT(vp->v_fbhv != NULL);
 
-	va.va_mask = XFS_AT_STAT|XFS_AT_GENCOUNT;
+	va.va_mask = XFS_AT_STAT;
 	VOP_GETATTR(vp, &va, 0, NULL, error);
 	if (!error) {
 		inode = LINVFS_GET_IP(vp);
@@ -206,12 +210,9 @@
 		inode->i_gid	    = va.va_gid;
 		inode->i_size	    = va.va_size;
 		inode->i_blocks	    = va.va_nblocks;
-		inode->i_mtime.tv_sec	    = va.va_mtime.tv_sec;
-		inode->i_mtime.tv_nsec	    = va.va_mtime.tv_nsec;
-		inode->i_ctime.tv_sec	    = va.va_ctime.tv_sec;
-		inode->i_ctime.tv_nsec	    = va.va_ctime.tv_nsec;
-		inode->i_atime.tv_sec	    = va.va_atime.tv_sec;
-		inode->i_atime.tv_nsec	    = va.va_atime.tv_nsec;
+		inode->i_mtime	    = va.va_mtime;
+		inode->i_ctime	    = va.va_ctime;
+		inode->i_atime	    = va.va_atime;
 		VUNMODIFY(vp);
 	}
 	return -error;
@@ -224,7 +225,9 @@
  * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock).
  */
 void
-vn_purge(struct vnode *vp, vmap_t *vmap)
+vn_purge(
+	struct vnode	*vp,
+	vmap_t		*vmap)
 {
 	vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
 
@@ -284,9 +287,10 @@
  * Add a reference to a referenced vnode.
  */
 struct vnode *
-vn_hold(struct vnode *vp)
+vn_hold(
+	struct vnode	*vp)
 {
-	struct inode *inode;
+	struct inode	*inode;
 
 	XFS_STATS_INC(xfsstats.vn_hold);
 
@@ -302,10 +306,11 @@
  *  Call VOP_INACTIVE on last reference.
  */
 void
-vn_rele(struct vnode *vp)
+vn_rele(
+	struct vnode	*vp)
 {
-	int	vcnt;
-	int	cache;
+	int		vcnt;
+	int		cache;
 
 	XFS_STATS_INC(xfsstats.vn_rele);
 
@@ -319,7 +324,7 @@
 	 * that i_count won't be decremented after we
 	 * return.
 	 */
-	if (vcnt == 0) {
+	if (!vcnt) {
 		/*
 		 * As soon as we turn this on, noone can find us in vn_get
 		 * until we turn off VINACT or VRECLM
@@ -331,19 +336,14 @@
 		 * Do not make the VOP_INACTIVE call if there
 		 * are no behaviors attached to the vnode to call.
 		 */
-		if (vp->v_fbhv != NULL) {
+		if (vp->v_fbhv)
 			VOP_INACTIVE(vp, NULL, cache);
-		}
 
 		VN_LOCK(vp);
-		if (vp->v_flag & VWAIT) {
-			if (vp->v_flag & VWAIT) {
-				sv_broadcast(vptosync(vp));
-			}
-		}
+		if (vp->v_flag & VWAIT)
+			sv_broadcast(vptosync(vp));
 
 		vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED);
-
 	}
 
 	VN_UNLOCK(vp, 0);
@@ -355,17 +355,16 @@
  * Finish the removal of a vnode.
  */
 void
-vn_remove(struct vnode *vp)
+vn_remove(
+	struct vnode	*vp)
 {
-	/* REFERENCED */
-	vmap_t	vmap;
+	vmap_t		vmap;
 
 	/* Make sure we don't do this to the same vnode twice */
 	if (!(vp->v_fbhv))
 		return;
 
 	XFS_STATS_INC(xfsstats.vn_remove);
-
 	vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address);
 
 	/*
diff -urN linux-2.5.66-bk2/fs/xfs/linux/xfs_vnode.h linux-2.5.66-bk3/fs/xfs/linux/xfs_vnode.h
--- linux-2.5.66-bk2/fs/xfs/linux/xfs_vnode.h	Mon Mar 24 14:01:50 2003
+++ linux-2.5.66-bk3/fs/xfs/linux/xfs_vnode.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -85,10 +85,16 @@
 typedef enum {
 	VN_BHV_UNKNOWN,		/* not specified */
 	VN_BHV_XFS,		/* xfs */
+	VN_BHV_DM,		/* data migration */
+	VN_BHV_QM,		/* quota manager */
+	VN_BHV_IO,		/* IO path */
 	VN_BHV_END		/* housekeeping end-of-range */
 } vn_bhv_t;
 
 #define VNODE_POSITION_XFS	(VNODE_POSITION_BASE)
+#define VNODE_POSITION_DM	(VNODE_POSITION_BASE+10)
+#define VNODE_POSITION_QM	(VNODE_POSITION_BASE+20)
+#define VNODE_POSITION_IO	(VNODE_POSITION_BASE+30)
 
 /*
  * Macros for dealing with the behavior descriptor inside of the vnode.
@@ -96,7 +102,6 @@
 #define BHV_TO_VNODE(bdp)	((vnode_t *)BHV_VOBJ(bdp))
 #define BHV_TO_VNODE_NULL(bdp)	((vnode_t *)BHV_VOBJNULL(bdp))
 
-#define VNODE_TO_FIRST_BHV(vp)		(BHV_HEAD_FIRST(&(vp)->v_bh))
 #define VN_BHV_HEAD(vp)			((bhv_head_t *)(&((vp)->v_bh)))
 #define vn_bhv_head_init(bhp,name)	bhv_head_init(bhp,name)
 #define vn_bhv_remove(bhp,bdp)		bhv_remove(bhp,bdp)
@@ -127,16 +132,6 @@
 #define VWAIT		       0x4	/* waiting for VINACT/VRECLM to end */
 #define VMODIFIED	       0x8	/* XFS inode state possibly differs */
 					/* to the Linux inode state.	*/
-#define VROOT		  0x100000	/* root of its file system	*/
-#define VNOSWAP		  0x200000	/* cannot be used as virt swap device */
-#define VISSWAP		  0x400000	/* vnode is part of virt swap device */
-#define VREPLICABLE	  0x800000	/* Vnode can have replicated pages */
-#define VNONREPLICABLE	 0x1000000	/* Vnode has writers. Don't replicate */
-#define VDOCMP		 0x2000000	/* Vnode has special VOP_CMP impl. */
-#define VSHARE		 0x4000000	/* vnode part of global cache	*/
-#define VFRLOCKS	 0x8000000	/* vnode has FR locks applied	*/
-#define VENF_LOCKING	0x10000000	/* enf. mode FR locking in effect */
-#define VOPLOCK		0x20000000	/* oplock set on the vnode	*/
 
 typedef enum vrwlock	{ VRWLOCK_NONE, VRWLOCK_READ,
 			  VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT,
@@ -267,163 +262,92 @@
  */
 #define _VOP_(op, vp)	(*((vnodeops_t *)(vp)->v_fops)->op)
 
-#define VOP_READ(vp,file,iov,segs,offset,cr,rv)				\
-{									\
-	rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr); \
-}
-#define VOP_WRITE(vp,file,iov,segs,offset,cr,rv)			\
-{									\
-	rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr);\
-}
-#define VOP_SENDFILE(vp,f,of,cnt,act,targ,cr,rv)			\
-{									\
-	rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,of,cnt,act,targ,cr);\
-}
+#define VOP_READ(vp,file,iov,segs,offset,cr,rv)			\
+	rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
+#define VOP_WRITE(vp,file,iov,segs,offset,cr,rv)		\
+	rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
+#define VOP_SENDFILE(vp,f,off,cnt,act,targ,cr,rv)		\
+	rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,cnt,act,targ,cr)
 #define VOP_BMAP(vp,of,sz,rw,b,n,rv)					\
-{									\
-	rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n);		\
-}
+	rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
 #define VOP_OPEN(vp, cr, rv)						\
-{									\
-	rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr);			\
-}
+	rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr)
 #define VOP_GETATTR(vp, vap, f, cr, rv)					\
-{									\
-	rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr);		\
-}
+	rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr)
 #define VOP_SETATTR(vp, vap, f, cr, rv)					\
-{									\
-	rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr);		\
-}
+	rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr)
 #define VOP_ACCESS(vp, mode, cr, rv)					\
-{									\
-	rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr);		\
-}
+	rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr)
 #define VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv)				\
-{									\
-	rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr);	\
-}
+	rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr)
 #define VOP_CREATE(dvp,d,vap,vpp,cr,rv)					\
-{									\
-	rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr);	\
-}
+	rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr)
 #define VOP_REMOVE(dvp,d,cr,rv)						\
-{									\
-	rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr);		\
-}
+	rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr)
 #define VOP_LINK(tdvp,fvp,d,cr,rv)					\
-{									\
-	rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr);		\
-}
+	rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr)
 #define VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv)				\
-{									\
-	rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr);	\
-}
+	rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr)
 #define VOP_MKDIR(dp,d,vap,vpp,cr,rv)					\
-{									\
-	rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr);		\
-}
+	rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr)
 #define	VOP_RMDIR(dp,d,cr,rv)	 					\
-{									\
-	rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr);			\
-}
+	rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr)
 #define VOP_READDIR(vp,uiop,cr,eofp,rv)					\
-{									\
-	rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp);		\
-}
+	rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp)
 #define VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv)				\
-{									\
-	rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr);	\
-}
+	rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr)
 #define VOP_READLINK(vp,uiop,cr,rv)					\
-{									\
-	rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr);		\
-}
+	rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr)
 #define VOP_FSYNC(vp,f,cr,b,e,rv)					\
-{									\
-	rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e);		\
-}
+	rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e)
 #define VOP_INACTIVE(vp, cr, rv)					\
-{									\
-	rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr);			\
-}
+	rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr)
 #define VOP_RELEASE(vp, rv)						\
-{									\
-	rv = _VOP_(vop_release, vp)((vp)->v_fbhv);			\
-}
+	rv = _VOP_(vop_release, vp)((vp)->v_fbhv)
 #define VOP_FID2(vp, fidp, rv)						\
-{									\
-	rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp);			\
-}
+	rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp)
 #define VOP_RWLOCK(vp,i)						\
-{									\
-	(void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i);			\
-}
+	(void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
 #define VOP_RWLOCK_TRY(vp,i)						\
 	_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
-
 #define VOP_RWUNLOCK(vp,i)						\
-{									\
-	(void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i);			\
-}
+	(void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i)
+#define VOP_FRLOCK(vp,c,fl,flags,offset,fr,rv)				\
+	rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr)
 #define VOP_RECLAIM(vp, rv)						\
-{									\
-	rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv);			\
-}
+	rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv)
 #define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv)		\
-{									\
-	rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred); \
-}
+	rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred)
 #define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv)		\
-{									\
-	rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred); \
-}
+	rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred)
 #define VOP_ATTR_REMOVE(vp, name, flags, cred, rv)			\
-{									\
-	rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred);	\
-}
+	rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred)
 #define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv)		\
-{									\
-	rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred);\
-}
+	rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred)
 #define VOP_LINK_REMOVED(vp, dvp, linkzero)				\
-{									\
-	(void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero); \
-}
+	(void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero)
 #define VOP_VNODE_CHANGE(vp, cmd, val)					\
-{									\
-	(void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val);	\
-}
+	(void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val)
 /*
  * These are page cache functions that now go thru VOPs.
  * 'last' parameter is unused and left in for IRIX compatibility
  */
 #define VOP_TOSS_PAGES(vp, first, last, fiopt)				\
-{									\
-	_VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt);	\
-}
+	_VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt)
 /*
  * 'last' parameter is unused and left in for IRIX compatibility
  */
 #define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt)			\
-{									\
-	_VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt); \
-}
+	_VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt)
 /*
  * 'last' parameter is unused and left in for IRIX compatibility
  */
 #define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv)		\
-{									\
-	rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt);\
-}
+	rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt)
 #define VOP_IOCTL(vp, inode, filp, cmd, arg, rv)			\
-{									\
-	rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg);	\
-}
+	rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg)
 #define VOP_IFLUSH(vp, flags, rv)					\
-{									\
-	rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags);		\
-}
+	rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags)
 
 /*
  * Flags for VOP_IFLUSH call
diff -urN linux-2.5.66-bk2/fs/xfs/pagebuf/page_buf.c linux-2.5.66-bk3/fs/xfs/pagebuf/page_buf.c
--- linux-2.5.66-bk2/fs/xfs/pagebuf/page_buf.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk3/fs/xfs/pagebuf/page_buf.c	Mon Mar 31 12:48:53 2003
@@ -1290,7 +1290,7 @@
 
 	if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
 		pb->pb_locked = 0;
-		pagebuf_iodone(pb, 0, 1);
+		pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 1);
 	}
 
 	bio_put(bio);
@@ -1434,7 +1434,7 @@
 
 	if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
 		pb->pb_locked = 0;
-		pagebuf_iodone(pb, 0, 0);
+		pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 1);
 	}
 
 	return 0;
@@ -1612,15 +1612,13 @@
 			refrigerator(PF_IOTHREAD);
 
 		if (pbd_active == 1) {
-			del_timer(&pb_daemon_timer);
-			pb_daemon_timer.expires = jiffies +
-					pb_params.p_un.flush_interval;
-			add_timer(&pb_daemon_timer);
+			mod_timer(&pb_daemon_timer,
+				  jiffies + pb_params.p_un.flush_interval);
 			interruptible_sleep_on(&pbd_waitq);
 		}
 
 		if (pbd_active == 0) {
-			del_timer(&pb_daemon_timer);
+			del_timer_sync(&pb_daemon_timer);
 		}
 
 		spin_lock(&pbd_delwrite_lock);
diff -urN linux-2.5.66-bk2/fs/xfs/pagebuf/page_buf.h linux-2.5.66-bk3/fs/xfs/pagebuf/page_buf.h
--- linux-2.5.66-bk2/fs/xfs/pagebuf/page_buf.h	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/fs/xfs/pagebuf/page_buf.h	Mon Mar 31 12:48:53 2003
@@ -96,6 +96,7 @@
 	PBF_MAPPABLE = (1 << 9),/* use directly-addressable pages	   */
 	PBF_STALE = (1 << 10),	/* buffer has been staled, do not find it  */
 	PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory  */
+	PBF_FS_DATAIOD = (1 << 12), /* schedule IO completion on fs datad  */
 
 	/* flags used only as arguments to access routines */
 	PBF_LOCK = (1 << 13),	/* lock requested			   */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot.c linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+
+/*
+   LOCK ORDER
+
+   inode lock		    (ilock)
+   dquot hash-chain lock    (hashlock)
+   xqm dquot freelist lock  (freelistlock
+   mount's dquot list lock  (mplistlock)
+   user dquot lock - lock ordering among dquots is based on the uid or gid
+   group dquot lock - similar to udquots. Between the two dquots, the udquot
+		      has to be locked first.
+   pin lock - the dquot lock must be held to take this lock.
+   flush lock - ditto.
+*/
+
+STATIC void		xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
+
+#ifdef DEBUG
+dev_t xfs_dqerror_dev = 0;
+int xfs_do_dqerror = 0;
+int xfs_dqreq_num = 0;
+int xfs_dqerror_mod = 33;
+#endif
+
+/*
+ * Allocate and initialize a dquot. We don't always allocate fresh memory;
+ * we try to reclaim a free dquot if the number of incore dquots are above
+ * a threshold.
+ * The only field inside the core that gets initialized at this point
+ * is the d_id field. The idea is to fill in the entire q_core
+ * when we read in the on disk dquot.
+ */
+xfs_dquot_t *
+xfs_qm_dqinit(
+	xfs_mount_t  *mp,
+	xfs_dqid_t   id,
+	uint	     type)
+{
+	xfs_dquot_t	*dqp;
+	boolean_t	brandnewdquot;
+
+	brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
+	dqp->dq_flags = type;
+	INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id);
+	dqp->q_mount = mp;
+
+	/*
+	 * No need to re-initialize these if this is a reclaimed dquot.
+	 */
+	if (brandnewdquot) {
+		dqp->dq_flnext = dqp->dq_flprev = dqp;
+		mutex_init(&dqp->q_qlock,  MUTEX_DEFAULT, "xdq");
+		initnsema(&dqp->q_flock, 1, "fdq");
+		sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
+
+#ifdef DQUOT_TRACING
+		dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);
+		xfs_dqtrace_entry(dqp, "DQINIT");
+#endif
+	} else {
+		/*
+		 * Only the q_core portion was zeroed in dqreclaim_one().
+		 * So, we need to reset others.
+		 */
+		 dqp->q_nrefs = 0;
+		 dqp->q_blkno = 0;
+		 dqp->MPL_NEXT = dqp->HL_NEXT = NULL;
+		 dqp->HL_PREVP = dqp->MPL_PREVP = NULL;
+		 dqp->q_bufoffset = 0;
+		 dqp->q_fileoffset = 0;
+		 dqp->q_transp = NULL;
+		 dqp->q_gdquot = NULL;
+		 dqp->q_res_bcount = 0;
+		 dqp->q_res_icount = 0;
+		 dqp->q_res_rtbcount = 0;
+		 dqp->q_pincount = 0;
+		 dqp->q_hash = 0;
+		 ASSERT(dqp->dq_flnext == dqp->dq_flprev);
+
+#ifdef DQUOT_TRACING
+		 ASSERT(dqp->q_trace);
+		 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
+#endif
+	 }
+
+	/*
+	 * log item gets initialized later
+	 */
+	return (dqp);
+}
+
+/*
+ * This is called to free all the memory associated with a dquot
+ */
+void
+xfs_qm_dqdestroy(
+	xfs_dquot_t	*dqp)
+{
+	ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));
+
+	mutex_destroy(&dqp->q_qlock);
+	freesema(&dqp->q_flock);
+	sv_destroy(&dqp->q_pinwait);
+
+#ifdef DQUOT_TRACING
+	if (dqp->q_trace)
+	     ktrace_free(dqp->q_trace);
+	dqp->q_trace = NULL;
+#endif
+	kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
+	atomic_dec(&xfs_Gqm->qm_totaldquots);
+}
+
+/*
+ * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
+ */
+STATIC void
+xfs_qm_dqinit_core(
+	xfs_dqid_t	 id,
+	uint		 type,
+	xfs_dqblk_t	 *d)
+{
+	/*
+	 * Caller has zero'd the entire dquot 'chunk' already.
+	 */
+	INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
+	INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
+	INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
+	INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
+}
+
+
+#ifdef DQUOT_TRACING
+/*
+ * Dquot tracing for debugging.
+ */
+/* ARGSUSED */
+void
+xfs_dqtrace_entry__(
+	xfs_dquot_t *dqp,
+	char *func,
+	void *retaddr,
+	xfs_inode_t *ip)
+{
+	xfs_dquot_t *udqp = NULL;
+	int ino;
+
+	ASSERT(dqp->q_trace);
+	if (ip) {
+		ino = ip->i_ino;
+		udqp = ip->i_udquot;
+	}
+	ktrace_enter(dqp->q_trace,
+		     (void *)(__psint_t)DQUOT_KTRACE_ENTRY,
+		     (void *)func,
+		     (void *)(__psint_t)dqp->q_nrefs,
+		     (void *)(__psint_t)dqp->dq_flags,
+		     (void *)(__psint_t)dqp->q_res_bcount,
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
+		     (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */
+		     (void *)(__psint_t)current_pid(),
+		     (void *)(__psint_t)ino,
+		     (void *)(__psint_t)retaddr,
+		     (void *)(__psint_t)udqp);
+	return;
+}
+#endif
+
+
+/*
+ * Check the limits and timers of a dquot and start or reset timers
+ * if necessary.
+ * This gets called even when quota enforcement is OFF, which makes our
+ * life a little less complicated. (We just don't reject any quota
+ * reservations in that case, when enforcement is off).
+ * We also return 0 as the values of the timers in Q_GETQUOTA calls, when
+ * enforcement's off.
+ * In contrast, warnings are a little different in that they don't
+ * 'automatically' get started when limits get exceeded.
+ */
+void
+xfs_qm_adjust_dqtimers(
+	xfs_mount_t		*mp,
+	xfs_disk_dquot_t	*d)
+{
+	/*
+	 * The dquot had better be locked. We are modifying it here.
+	 */
+
+	/*
+	 * root's limits are not real limits.
+	 */
+	if (INT_ISZERO(d->d_id, ARCH_CONVERT))
+		return;
+
+#ifdef QUOTADEBUG
+	if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT))
+		ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT));
+	if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT))
+		ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT));
+#endif
+	if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) {
+		if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
+		    (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) ||
+		    (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) &&
+		    (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
+			INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp));
+		}
+	} else {
+		if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
+		    (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) &&
+		    (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) ||
+		    (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
+			INT_ZERO(d->d_btimer, ARCH_CONVERT);
+		}
+	}
+
+	if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) {
+		if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) &&
+		    (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) ||
+		    (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) &&
+		    (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
+			INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp));
+		}
+	} else {
+		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) ||
+		    (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT)))  &&
+		    (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) ||
+		    (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
+			INT_ZERO(d->d_itimer, ARCH_CONVERT);
+		}
+	}
+}
+
+/*
+ * Increment or reset warnings of a given dquot.
+ */
+int
+xfs_qm_dqwarn(
+	xfs_disk_dquot_t	*d,
+	uint			flags)
+{
+	int	warned;
+
+	/*
+	 * root's limits are not real limits.
+	 */
+	if (INT_ISZERO(d->d_id, ARCH_CONVERT))
+		return (0);
+
+	warned = 0;
+	if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
+	    (INT_GET(d->d_bcount, ARCH_CONVERT) >=
+	     INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
+		if (flags & XFS_QMOPT_DOWARN) {
+			INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
+			warned++;
+		}
+	} else {
+		if (INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
+		    (INT_GET(d->d_bcount, ARCH_CONVERT) <
+		     INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
+			INT_ZERO(d->d_bwarns, ARCH_CONVERT);
+		}
+	}
+
+	if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
+	    (INT_GET(d->d_icount, ARCH_CONVERT) >=
+	     INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
+		if (flags & XFS_QMOPT_DOWARN) {
+			INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
+			warned++;
+		}
+	} else {
+		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) ||
+		    (INT_GET(d->d_icount, ARCH_CONVERT) <
+		     INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
+			INT_ZERO(d->d_iwarns, ARCH_CONVERT);
+		}
+	}
+#ifdef QUOTADEBUG
+	if (INT_GET(d->d_iwarns, ARCH_CONVERT))
+		cmn_err(CE_DEBUG,
+			"--------@@Inode warnings running : %Lu >= %Lu",
+			INT_GET(d->d_icount, ARCH_CONVERT),
+			INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
+	if (INT_GET(d->d_bwarns, ARCH_CONVERT))
+		cmn_err(CE_DEBUG,
+			"--------@@Blks warnings running : %Lu >= %Lu",
+			INT_GET(d->d_bcount, ARCH_CONVERT),
+			INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
+#endif
+	return (warned);
+}
+
+
+/*
+ * initialize a buffer full of dquots and log the whole thing
+ */
+STATIC void
+xfs_qm_init_dquot_blk(
+	xfs_trans_t	*tp,
+	xfs_mount_t	*mp,
+	xfs_dqid_t	id,
+	uint		type,
+	xfs_buf_t	*bp)
+{
+	xfs_dqblk_t	*d;
+	int		curid, i;
+
+	ASSERT(tp);
+	ASSERT(XFS_BUF_ISBUSY(bp));
+	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+
+	d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
+
+	/*
+	 * ID of the first dquot in the block - id's are zero based.
+	 */
+	curid = id - (id % XFS_QM_DQPERBLK(mp));
+	ASSERT(curid >= 0);
+	memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
+	for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
+		xfs_qm_dqinit_core(curid, type, d);
+	xfs_trans_dquot_buf(tp, bp,
+			    type & XFS_DQ_USER ?
+			    XFS_BLI_UDQUOT_BUF :
+			    XFS_BLI_GDQUOT_BUF);
+	xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
+}
+
+
+
+/*
+ * Allocate a block and fill it with dquots.
+ * This is called when the bmapi finds a hole.
+ */
+STATIC int
+xfs_qm_dqalloc(
+	xfs_trans_t	*tp,
+	xfs_mount_t	*mp,
+	xfs_dquot_t	*dqp,
+	xfs_inode_t	*quotip,
+	xfs_fileoff_t	offset_fsb,
+	xfs_buf_t	**O_bpp)
+{
+	xfs_fsblock_t	firstblock;
+	xfs_bmap_free_t flist;
+	xfs_bmbt_irec_t map;
+	int		nmaps, error, committed;
+	xfs_buf_t	*bp;
+
+	ASSERT(tp != NULL);
+	xfs_dqtrace_entry(dqp, "DQALLOC");
+
+	/*
+	 * Initialize the bmap freelist prior to calling bmapi code.
+	 */
+	XFS_BMAP_INIT(&flist, &firstblock);
+	xfs_ilock(quotip, XFS_ILOCK_EXCL);
+	/*
+	 * Return if this type of quotas is turned off while we didn't
+	 * have an inode lock
+	 */
+	if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+		xfs_iunlock(quotip, XFS_ILOCK_EXCL);
+		return (ESRCH);
+	}
+
+	/*
+	 * xfs_trans_commit normally decrements the vnode ref count
+	 * when it unlocks the inode. Since we want to keep the quota
+	 * inode around, we bump the vnode ref count now.
+	 */
+	VN_HOLD(XFS_ITOV(quotip));
+
+	xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
+	nmaps = 1;
+	if ((error = xfs_bmapi(tp, quotip,
+			      offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
+			      XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
+			      &firstblock,
+			      XFS_QM_DQALLOC_SPACE_RES(mp),
+			      &map, &nmaps, &flist))) {
+		goto error0;
+	}
+	ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
+	ASSERT(nmaps == 1);
+	ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
+	       (map.br_startblock != HOLESTARTBLOCK));
+
+	/*
+	 * Keep track of the blkno to save a lookup later
+	 */
+	dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
+
+	/* now we can just get the buffer (there's nothing to read yet) */
+	bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
+			       dqp->q_blkno,
+			       XFS_QI_DQCHUNKLEN(mp),
+			       0);
+	if (!bp || (error = XFS_BUF_GETERROR(bp)))
+		goto error1;
+	/*
+	 * Make a chunk of dquots out of this buffer and log
+	 * the entire thing.
+	 */
+	xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
+			      dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
+			      bp);
+
+	if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
+		goto error1;
+	}
+
+	*O_bpp = bp;
+	return 0;
+
+      error1:
+	xfs_bmap_cancel(&flist);
+      error0:
+	xfs_iunlock(quotip, XFS_ILOCK_EXCL);
+
+	return (error);
+}
+
+/*
+ * Maps a dquot to the buffer containing its on-disk version.
+ * This returns a ptr to the buffer containing the on-disk dquot
+ * in the bpp param, and a ptr to the on-disk dquot within that buffer
+ */
+STATIC int
+xfs_qm_dqtobp(
+	xfs_trans_t		*tp,
+	xfs_dquot_t		*dqp,
+	xfs_disk_dquot_t	**O_ddpp,
+	xfs_buf_t		**O_bpp,
+	uint			flags)
+{
+	xfs_bmbt_irec_t map;
+	int		nmaps, error;
+	xfs_buf_t	*bp;
+	xfs_inode_t	*quotip;
+	xfs_mount_t	*mp;
+	xfs_disk_dquot_t *ddq;
+	xfs_dqid_t	id;
+	boolean_t	newdquot;
+
+	mp = dqp->q_mount;
+	id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
+	nmaps = 1;
+	newdquot = B_FALSE;
+
+	/*
+	 * If we don't know where the dquot lives, find out.
+	 */
+	if (dqp->q_blkno == (xfs_daddr_t) 0) {
+		/* We use the id as an index */
+		dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id /
+						     XFS_QM_DQPERBLK(mp));
+		nmaps = 1;
+		quotip = XFS_DQ_TO_QIP(dqp);
+		xfs_ilock(quotip, XFS_ILOCK_SHARED);
+		/*
+		 * Return if this type of quotas is turned off while we didn't
+		 * have an inode lock
+		 */
+		if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+			xfs_iunlock(quotip, XFS_ILOCK_SHARED);
+			return (ESRCH);
+		}
+		/*
+		 * Find the block map; no allocations yet
+		 */
+		error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
+				  XFS_DQUOT_CLUSTER_SIZE_FSB,
+				  XFS_BMAPI_METADATA,
+				  NULL, 0, &map, &nmaps, NULL);
+
+		xfs_iunlock(quotip, XFS_ILOCK_SHARED);
+		if (error)
+			return (error);
+		ASSERT(nmaps == 1);
+		ASSERT(map.br_blockcount == 1);
+
+		/*
+		 * offset of dquot in the (fixed sized) dquot chunk.
+		 */
+		dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *
+			sizeof(xfs_dqblk_t);
+		if (map.br_startblock == HOLESTARTBLOCK) {
+			/*
+			 * We don't allocate unless we're asked to
+			 */
+			if (!(flags & XFS_QMOPT_DQALLOC))
+				return (ENOENT);
+
+			ASSERT(tp);
+			if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
+						dqp->q_fileoffset, &bp)))
+				return (error);
+			newdquot = B_TRUE;
+		} else {
+			/*
+			 * store the blkno etc so that we don't have to do the
+			 * mapping all the time
+			 */
+			dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
+		}
+	}
+	ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
+	ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
+
+	/*
+	 * Read in the buffer, unless we've just done the allocation
+	 * (in which case we already have the buf).
+	 */
+	if (! newdquot) {
+		xfs_dqtrace_entry(dqp, "DQTOBP READBUF");
+		if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
+					       dqp->q_blkno,
+					       XFS_QI_DQCHUNKLEN(mp),
+					       0, &bp))) {
+			return (error);
+		}
+		if (error || !bp)
+			return XFS_ERROR(error);
+	}
+	ASSERT(XFS_BUF_ISBUSY(bp));
+	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+
+	/*
+	 * calculate the location of the dquot inside the buffer.
+	 */
+	ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+
+	/*
+	 * A simple sanity check in case we got a corrupted dquot...
+	 */
+	if (xfs_qm_dqcheck(ddq, id,
+			   dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
+			   flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
+			   "dqtobp")) {
+		if (!(flags & XFS_QMOPT_DQREPAIR)) {
+			xfs_trans_brelse(tp, bp);
+			return XFS_ERROR(EIO);
+		}
+		XFS_BUF_BUSY(bp); /* We dirtied this */
+	}
+
+	*O_bpp = bp;
+	*O_ddpp = ddq;
+
+	return (0);
+}
+
+
+/*
+ * Read in the ondisk dquot using dqtobp() then copy it to an incore version,
+ * and release the buffer immediately.
+ *
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_dqread(
+	xfs_trans_t	*tp,
+	xfs_dqid_t	id,
+	xfs_dquot_t	*dqp,	/* dquot to get filled in */
+	uint		flags)
+{
+	xfs_disk_dquot_t *ddqp;
+	xfs_buf_t	 *bp;
+	int		 error;
+
+	/*
+	 * get a pointer to the on-disk dquot and the buffer containing it
+	 * dqp already knows its own type (GROUP/USER).
+	 */
+	xfs_dqtrace_entry(dqp, "DQREAD");
+	if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
+		return (error);
+	}
+
+	/* copy everything from disk dquot to the incore dquot */
+	memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
+	ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
+	xfs_qm_dquot_logitem_init(dqp);
+
+	/*
+	 * Reservation counters are defined as reservation plus current usage
+	 * to avoid having to add everytime.
+	 */
+	dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT);
+	dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT);
+	dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT);
+
+	/* Mark the buf so that this will stay incore a little longer */
+	XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
+
+	/*
+	 * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
+	 * So we need to release with xfs_trans_brelse().
+	 * The strategy here is identical to that of inodes; we lock
+	 * the dquot in xfs_qm_dqget() before making it accessible to
+	 * others. This is because dquots, like inodes, need a good level of
+	 * concurrency, and we don't want to take locks on the entire buffers
+	 * for dquot accesses.
+	 * Note also that the dquot buffer may even be dirty at this point, if
+	 * this particular dquot was repaired. We still aren't afraid to
+	 * brelse it because we have the changes incore.
+	 */
+	ASSERT(XFS_BUF_ISBUSY(bp));
+	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+	xfs_trans_brelse(tp, bp);
+
+	return (error);
+}
+
+
+/*
+ * allocate an incore dquot from the kernel heap,
+ * and fill its core with quota information kept on disk.
+ * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
+ * if it wasn't already allocated.
+ */
+STATIC int
+xfs_qm_idtodq(
+	xfs_mount_t	*mp,
+	xfs_dqid_t	id,	 /* gid or uid, depending on type */
+	uint		type,	 /* UDQUOT or GDQUOT */
+	uint		flags,	 /* DQALLOC, DQREPAIR */
+	xfs_dquot_t	**O_dqpp)/* OUT : incore dquot, not locked */
+{
+	xfs_dquot_t	*dqp;
+	int		error;
+	xfs_trans_t	*tp;
+	int		cancelflags=0;
+
+	dqp = xfs_qm_dqinit(mp, id, type);
+	tp = NULL;
+	if (flags & XFS_QMOPT_DQALLOC) {
+		tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
+		if ((error = xfs_trans_reserve(tp,
+				       XFS_QM_DQALLOC_SPACE_RES(mp),
+				       XFS_WRITE_LOG_RES(mp) +
+					      BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +
+					      128,
+				       0,
+				       XFS_TRANS_PERM_LOG_RES,
+				       XFS_WRITE_LOG_COUNT))) {
+			cancelflags = 0;
+			goto error0;
+		}
+		cancelflags = XFS_TRANS_RELEASE_LOG_RES;
+	}
+
+	/*
+	 * Read it from disk; xfs_dqread() takes care of
+	 * all the necessary initialization of dquot's fields (locks, etc)
+	 */
+	if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
+		/*
+		 * This can happen if quotas got turned off (ESRCH),
+		 * or if the dquot didn't exist on disk and we ask to
+		 * allocate (ENOENT).
+		 */
+		xfs_dqtrace_entry(dqp, "DQREAD FAIL");
+		cancelflags |= XFS_TRANS_ABORT;
+		goto error0;
+	}
+	if (tp) {
+		if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
+					     NULL)))
+			goto error1;
+	}
+
+	*O_dqpp = dqp;
+	ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+	return (0);
+
+ error0:
+	ASSERT(error);
+	if (tp)
+		xfs_trans_cancel(tp, cancelflags);
+ error1:
+	xfs_qm_dqdestroy(dqp);
+	*O_dqpp = NULL;
+	return (error);
+}
+
+/*
+ * Lookup a dquot in the incore dquot hashtable. We keep two separate
+ * hashtables for user and group dquots; and, these are global tables
+ * inside the XQM, not per-filesystem tables.
+ * The hash chain must be locked by caller, and it is left locked
+ * on return. Returning dquot is locked.
+ */
+STATIC int
+xfs_qm_dqlookup(
+	xfs_mount_t		*mp,
+	xfs_dqid_t		id,
+	xfs_dqhash_t		*qh,
+	xfs_dquot_t		**O_dqpp)
+{
+	xfs_dquot_t		*dqp;
+	uint			flist_locked;
+	xfs_dquot_t		*d;
+
+	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+
+	flist_locked = B_FALSE;
+
+	/*
+	 * Traverse the hashchain looking for a match
+	 */
+	for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {
+		/*
+		 * We already have the hashlock. We don't need the
+		 * dqlock to look at the id field of the dquot, since the
+		 * id can't be modified without the hashlock anyway.
+		 */
+		if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) {
+			xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");
+			/*
+			 * All in core dquots must be on the dqlist of mp
+			 */
+			ASSERT(dqp->MPL_PREVP != NULL);
+
+			xfs_dqlock(dqp);
+			if (dqp->q_nrefs == 0) {
+				ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));
+				if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
+					xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");
+
+					/*
+					 * We may have raced with dqreclaim_one()
+					 * (and lost). So, flag that we don't
+					 * want the dquot to be reclaimed.
+					 */
+					dqp->dq_flags |= XFS_DQ_WANT;
+					xfs_dqunlock(dqp);
+					xfs_qm_freelist_lock(xfs_Gqm);
+					xfs_dqlock(dqp);
+					dqp->dq_flags &= ~(XFS_DQ_WANT);
+				}
+				flist_locked = B_TRUE;
+			}
+
+			/*
+			 * id couldn't have changed; we had the hashlock all
+			 * along
+			 */
+			ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
+
+			if (flist_locked) {
+				if (dqp->q_nrefs != 0) {
+					xfs_qm_freelist_unlock(xfs_Gqm);
+					flist_locked = B_FALSE;
+				} else {
+					/*
+					 * take it off the freelist
+					 */
+					xfs_dqtrace_entry(dqp,
+							"DQLOOKUP: TAKEOFF FL");
+					XQM_FREELIST_REMOVE(dqp);
+					/* xfs_qm_freelist_print(&(xfs_Gqm->
+							qm_dqfreelist),
+							"after removal"); */
+				}
+			}
+
+			/*
+			 * grab a reference
+			 */
+			XFS_DQHOLD(dqp);
+
+			if (flist_locked)
+				xfs_qm_freelist_unlock(xfs_Gqm);
+			/*
+			 * move the dquot to the front of the hashchain
+			 */
+			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+			if (dqp->HL_PREVP != &qh->qh_next) {
+				xfs_dqtrace_entry(dqp,
+						  "DQLOOKUP: HASH MOVETOFRONT");
+				if ((d = dqp->HL_NEXT))
+					d->HL_PREVP = dqp->HL_PREVP;
+				*(dqp->HL_PREVP) = d;
+				d = qh->qh_next;
+				d->HL_PREVP = &dqp->HL_NEXT;
+				dqp->HL_NEXT = d;
+				dqp->HL_PREVP = &qh->qh_next;
+				qh->qh_next = dqp;
+			}
+			xfs_dqtrace_entry(dqp, "LOOKUP END");
+			*O_dqpp = dqp;
+			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+			return (0);
+		}
+	}
+
+	*O_dqpp = NULL;
+	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+	return (1);
+}
+
+/*
+ * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
+ * a locked dquot, doing an allocation (if requested) as needed.
+ * When both an inode and an id are given, the inode's id takes precedence.
+ * That is, if the id changes while we don't hold the ilock inside this
+ * function, the new dquot is returned, not necessarily the one requested
+ * in the id argument.
+ */
+int
+xfs_qm_dqget(
+	xfs_mount_t	*mp,
+	xfs_inode_t	*ip,	  /* locked inode (optional) */
+	xfs_dqid_t	id,	  /* gid or uid, depending on type */
+	uint		type,	  /* UDQUOT or GDQUOT */
+	uint		flags,	  /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
+	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */
+{
+	xfs_dquot_t	*dqp;
+	xfs_dqhash_t	*h;
+	uint		version;
+	int		error;
+
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+	if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
+	    (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
+		return (ESRCH);
+	}
+	h = XFS_DQ_HASH(mp, id, type);
+
+#ifdef DEBUG
+	if (xfs_do_dqerror) {
+		if ((xfs_dqerror_dev == mp->m_dev) &&
+		    (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
+			cmn_err(CE_DEBUG, "Returning error in dqget");
+			return (EIO);
+		}
+	}
+#endif
+
+ again:
+
+#ifdef DEBUG
+	ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
+	if (ip) {
+		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+		if (type == XFS_DQ_USER)
+			ASSERT(ip->i_udquot == NULL);
+		else
+			ASSERT(ip->i_gdquot == NULL);
+	}
+#endif
+	XFS_DQ_HASH_LOCK(h);
+
+	/*
+	 * Look in the cache (hashtable).
+	 * The chain is kept locked during lookup.
+	 */
+	if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
+		XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
+		/*
+		 * The dquot was found, moved to the front of the chain,
+		 * taken off the freelist if it was on it, and locked
+		 * at this point. Just unlock the hashchain and return.
+		 */
+		ASSERT(*O_dqpp);
+		ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
+		XFS_DQ_HASH_UNLOCK(h);
+		xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
+		return (0);	/* success */
+	}
+	XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
+
+	/*
+	 * Dquot cache miss. We don't want to keep the inode lock across
+	 * a (potential) disk read. Also we don't want to deal with the lock
+	 * ordering between quotainode and this inode. OTOH, dropping the inode
+	 * lock here means dealing with a chown that can happen before
+	 * we re-acquire the lock.
+	 */
+	if (ip)
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	/*
+	 * Save the hashchain version stamp, and unlock the chain, so that
+	 * we don't keep the lock across a disk read
+	 */
+	version = h->qh_version;
+	XFS_DQ_HASH_UNLOCK(h);
+
+	/*
+	 * Allocate the dquot on the kernel heap, and read the ondisk
+	 * portion off the disk. Also, do all the necessary initialization
+	 * This can return ENOENT if dquot didn't exist on disk and we didn't
+	 * ask it to allocate; ESRCH if quotas got turned off suddenly.
+	 */
+	if ((error = xfs_qm_idtodq(mp, id, type,
+				  flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
+					   XFS_QMOPT_DOWARN),
+				  &dqp))) {
+		if (ip)
+			xfs_ilock(ip, XFS_ILOCK_EXCL);
+		return (error);
+	}
+
+	/*
+	 * See if this is mount code calling to look at the overall quota limits
+	 * which are stored in the id == 0 user or group's dquot.
+	 * Since we may not have done a quotacheck by this point, just return
+	 * the dquot without attaching it to any hashtables, lists, etc, or even
+	 * taking a reference.
+	 * The caller must dqdestroy this once done.
+	 */
+	if (flags & XFS_QMOPT_DQSUSER) {
+		ASSERT(id == 0);
+		ASSERT(! ip);
+		goto dqret;
+	}
+
+	/*
+	 * Dquot lock comes after hashlock in the lock ordering
+	 */
+	ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+	if (ip) {
+		xfs_ilock(ip, XFS_ILOCK_EXCL);
+		if (! XFS_IS_DQTYPE_ON(mp, type)) {
+			/* inode stays locked on return */
+			xfs_qm_dqdestroy(dqp);
+			return XFS_ERROR(ESRCH);
+		}
+		/*
+		 * A dquot could be attached to this inode by now, since
+		 * we had dropped the ilock.
+		 */
+		if (type == XFS_DQ_USER) {
+			if (ip->i_udquot) {
+				xfs_qm_dqdestroy(dqp);
+				dqp = ip->i_udquot;
+				xfs_dqlock(dqp);
+				goto dqret;
+			}
+		} else {
+			if (ip->i_gdquot) {
+				xfs_qm_dqdestroy(dqp);
+				dqp = ip->i_gdquot;
+				xfs_dqlock(dqp);
+				goto dqret;
+			}
+		}
+	}
+
+	/*
+	 * Hashlock comes after ilock in lock order
+	 */
+	XFS_DQ_HASH_LOCK(h);
+	if (version != h->qh_version) {
+		xfs_dquot_t *tmpdqp;
+		/*
+		 * Now, see if somebody else put the dquot in the
+		 * hashtable before us. This can happen because we didn't
+		 * keep the hashchain lock. We don't have to worry about
+		 * lock order between the two dquots here since dqp isn't
+		 * on any findable lists yet.
+		 */
+		if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
+			/*
+			 * Duplicate found. Just throw away the new dquot
+			 * and start over.
+			 */
+			xfs_qm_dqput(tmpdqp);
+			XFS_DQ_HASH_UNLOCK(h);
+			xfs_qm_dqdestroy(dqp);
+			XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
+			goto again;
+		}
+	}
+
+	/*
+	 * Put the dquot at the beginning of the hash-chain and mp's list
+	 * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
+	 */
+	ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
+	dqp->q_hash = h;
+	XQM_HASHLIST_INSERT(h, dqp);
+
+	/*
+	 * Attach this dquot to this filesystem's list of all dquots,
+	 * kept inside the mount structure in m_quotainfo field
+	 */
+	xfs_qm_mplist_lock(mp);
+
+	/*
+	 * We return a locked dquot to the caller, with a reference taken
+	 */
+	xfs_dqlock(dqp);
+	dqp->q_nrefs = 1;
+
+	XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
+
+	xfs_qm_mplist_unlock(mp);
+	XFS_DQ_HASH_UNLOCK(h);
+ dqret:
+	ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
+	xfs_dqtrace_entry(dqp, "DQGET DONE");
+	*O_dqpp = dqp;
+	return (0);
+}
+
+
+/*
+ * Release a reference to the dquot (decrement ref-count)
+ * and unlock it. If there is a group quota attached to this
+ * dquot, carefully release that too without tripping over
+ * deadlocks'n'stuff.
+ */
+void
+xfs_qm_dqput(
+	xfs_dquot_t	*dqp)
+{
+	xfs_dquot_t	*gdqp;
+
+	ASSERT(dqp->q_nrefs > 0);
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	xfs_dqtrace_entry(dqp, "DQPUT");
+
+	if (dqp->q_nrefs != 1) {
+		dqp->q_nrefs--;
+		xfs_dqunlock(dqp);
+		return;
+	}
+
+	/*
+	 * drop the dqlock and acquire the freelist and dqlock
+	 * in the right order; but try to get it out-of-order first
+	 */
+	if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
+		xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT");
+		xfs_dqunlock(dqp);
+		xfs_qm_freelist_lock(xfs_Gqm);
+		xfs_dqlock(dqp);
+	}
+
+	while (1) {
+		gdqp = NULL;
+
+		/* We can't depend on nrefs being == 1 here */
+		if (--dqp->q_nrefs == 0) {
+			xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST");
+			/*
+			 * insert at end of the freelist.
+			 */
+			XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp);
+
+			/*
+			 * If we just added a udquot to the freelist, then
+			 * we want to release the gdquot reference that
+			 * it (probably) has. Otherwise it'll keep the
+			 * gdquot from getting reclaimed.
+			 */
+			if ((gdqp = dqp->q_gdquot)) {
+				/*
+				 * Avoid a recursive dqput call
+				 */
+				xfs_dqlock(gdqp);
+				dqp->q_gdquot = NULL;
+			}
+
+			/* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist),
+			   "@@@@@++ Free list (after append) @@@@@+");
+			   */
+		}
+		xfs_dqunlock(dqp);
+
+		/*
+		 * If we had a group quota inside the user quota as a hint,
+		 * release it now.
+		 */
+		if (! gdqp)
+			break;
+		dqp = gdqp;
+	}
+	xfs_qm_freelist_unlock(xfs_Gqm);
+}
+
+/*
+ * Release a dquot. Flush it if dirty, then dqput() it.
+ * dquot must not be locked.
+ */
+void
+xfs_qm_dqrele(
+	xfs_dquot_t	*dqp)
+{
+	ASSERT(dqp);
+	xfs_dqtrace_entry(dqp, "DQRELE");
+
+	xfs_dqlock(dqp);
+	/*
+	 * We don't care to flush it if the dquot is dirty here.
+	 * That will create stutters that we want to avoid.
+	 * Instead we do a delayed write when we try to reclaim
+	 * a dirty dquot. Also xfs_sync will take part of the burden...
+	 */
+	xfs_qm_dqput(dqp);
+}
+
+
+/*
+ * Write a modified dquot to disk.
+ * The dquot must be locked and the flush lock too taken by caller.
+ * The flush lock will not be unlocked until the dquot reaches the disk,
+ * but the dquot is free to be unlocked and modified by the caller
+ * in the interim. Dquot is still locked on return. This behavior is
+ * identical to that of inodes.
+ */
+int
+xfs_qm_dqflush(
+	xfs_dquot_t		*dqp,
+	uint			flags)
+{
+	xfs_mount_t		*mp;
+	xfs_buf_t		*bp;
+	xfs_disk_dquot_t	*ddqp;
+	int			error;
+	SPLDECL(s);
+
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
+	xfs_dqtrace_entry(dqp, "DQFLUSH");
+
+	/*
+	 * If not dirty, nada.
+	 */
+	if (!XFS_DQ_IS_DIRTY(dqp)) {
+		xfs_dqfunlock(dqp);
+		return (0);
+	}
+
+	/*
+	 * Cant flush a pinned dquot. Wait for it.
+	 */
+	xfs_qm_dqunpin_wait(dqp);
+
+	/*
+	 * This may have been unpinned because the filesystem is shutting
+	 * down forcibly. If that's the case we must not write this dquot
+	 * to disk, because the log record didn't make it to disk!
+	 */
+	if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
+		dqp->dq_flags &= ~(XFS_DQ_DIRTY);
+		xfs_dqfunlock(dqp);
+		return XFS_ERROR(EIO);
+	}
+
+	/*
+	 * Get the buffer containing the on-disk dquot
+	 * We don't need a transaction envelope because we know that the
+	 * the ondisk-dquot has already been allocated for.
+	 */
+	if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
+		xfs_dqtrace_entry(dqp, "DQTOBP FAIL");
+		ASSERT(error != ENOENT);
+		/*
+		 * Quotas could have gotten turned off (ESRCH)
+		 */
+		xfs_dqfunlock(dqp);
+		return (error);
+	}
+
+	if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
+			   "dqflush (incore copy)")) {
+		xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
+		return XFS_ERROR(EIO);
+	}
+
+	/* This is the only portion of data that needs to persist */
+	memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
+
+	/*
+	 * Clear the dirty field and remember the flush lsn for later use.
+	 */
+	dqp->dq_flags &= ~(XFS_DQ_DIRTY);
+	mp = dqp->q_mount;
+
+	/* lsn is 64 bits */
+	AIL_LOCK(mp, s);
+	dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
+	AIL_UNLOCK(mp, s);
+
+	/*
+	 * Attach an iodone routine so that we can remove this dquot from the
+	 * AIL and release the flush lock once the dquot is synced to disk.
+	 */
+	xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
+			      xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
+	/*
+	 * If the buffer is pinned then push on the log so we won't
+	 * get stuck waiting in the write for too long.
+	 */
+	if (XFS_BUF_ISPINNED(bp)) {
+		xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE");
+		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
+	}
+
+	if (flags & XFS_QMOPT_DELWRI) {
+		xfs_bdwrite(mp, bp);
+	} else if (flags & XFS_QMOPT_ASYNC) {
+		xfs_bawrite(mp, bp);
+	} else {
+		error = xfs_bwrite(mp, bp);
+	}
+	xfs_dqtrace_entry(dqp, "DQFLUSH END");
+	/*
+	 * dqp is still locked, but caller is free to unlock it now.
+	 */
+	return (error);
+
+}
+
+/*
+ * This is the dquot flushing I/O completion routine.  It is called
+ * from interrupt level when the buffer containing the dquot is
+ * flushed to disk.  It is responsible for removing the dquot logitem
+ * from the AIL if it has not been re-logged, and unlocking the dquot's
+ * flush lock. This behavior is very similar to that of inodes..
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_dqflush_done(
+	xfs_buf_t		*bp,
+	xfs_dq_logitem_t	*qip)
+{
+	xfs_dquot_t		*dqp;
+	SPLDECL(s);
+
+	dqp = qip->qli_dquot;
+
+	/*
+	 * We only want to pull the item from the AIL if its
+	 * location in the log has not changed since we started the flush.
+	 * Thus, we only bother if the dquot's lsn has
+	 * not changed. First we check the lsn outside the lock
+	 * since it's cheaper, and then we recheck while
+	 * holding the lock before removing the dquot from the AIL.
+	 */
+	if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
+	    qip->qli_item.li_lsn == qip->qli_flush_lsn) {
+
+		AIL_LOCK(dqp->q_mount, s);
+		/*
+		 * xfs_trans_delete_ail() drops the AIL lock.
+		 */
+		if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
+			xfs_trans_delete_ail(dqp->q_mount,
+					     (xfs_log_item_t*)qip, s);
+		else
+			AIL_UNLOCK(dqp->q_mount, s);
+	}
+
+	/*
+	 * Release the dq's flush lock since we're done with it.
+	 */
+	xfs_dqfunlock(dqp);
+}
+
+
+int
+xfs_qm_dqflock_nowait(
+	xfs_dquot_t *dqp)
+{
+	int locked;
+
+	locked = cpsema(&((dqp)->q_flock));
+
+	/* XXX ifdef these out */
+	if (locked)
+		(dqp)->dq_flags |= XFS_DQ_FLOCKED;
+	return (locked);
+}
+
+
+int
+xfs_qm_dqlock_nowait(
+	xfs_dquot_t *dqp)
+{
+	return (mutex_trylock(&((dqp)->q_qlock)));
+}
+
+void
+xfs_dqlock(
+	xfs_dquot_t *dqp)
+{
+	mutex_lock(&(dqp->q_qlock), PINOD);
+}
+
+void
+xfs_dqunlock(
+	xfs_dquot_t *dqp)
+{
+	mutex_unlock(&(dqp->q_qlock));
+	if (dqp->q_logitem.qli_dquot == dqp) {
+		/* Once was dqp->q_mount, but might just have been cleared */
+		xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
+					(xfs_log_item_t*)&(dqp->q_logitem));
+	}
+}
+
+
+void
+xfs_dqunlock_nonotify(
+	xfs_dquot_t *dqp)
+{
+	mutex_unlock(&(dqp->q_qlock));
+}
+
+void
+xfs_dqlock2(
+	xfs_dquot_t	*d1,
+	xfs_dquot_t	*d2)
+{
+	if (d1 && d2) {
+		ASSERT(d1 != d2);
+		if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
+			xfs_dqlock(d2);
+			xfs_dqlock(d1);
+		} else {
+			xfs_dqlock(d1);
+			xfs_dqlock(d2);
+		}
+	} else {
+		if (d1) {
+			xfs_dqlock(d1);
+		} else if (d2) {
+			xfs_dqlock(d2);
+		}
+	}
+}
+
+
+/*
+ * Take a dquot out of the mount's dqlist as well as the hashlist.
+ * This is called via unmount as well as quotaoff, and the purge
+ * will always succeed unless there are soft (temp) references
+ * outstanding.
+ *
+ * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
+ * that we're returning! XXXsup - not cool.
+ */
+/* ARGSUSED */
+int
+xfs_qm_dqpurge(
+	xfs_dquot_t	*dqp,
+	uint		flags)
+{
+	xfs_dqhash_t	*thishash;
+	xfs_mount_t	*mp;
+
+	mp = dqp->q_mount;
+
+	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+	ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
+
+	xfs_dqlock(dqp);
+	/*
+	 * We really can't afford to purge a dquot that is
+	 * referenced, because these are hard refs.
+	 * It shouldn't happen in general because we went thru _all_ inodes in
+	 * dqrele_all_inodes before calling this and didn't let the mountlock go.
+	 * However it is possible that we have dquots with temporary
+	 * references that are not attached to an inode. e.g. see xfs_setattr().
+	 */
+	if (dqp->q_nrefs != 0) {
+		xfs_dqunlock(dqp);
+		XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+		return (1);
+	}
+
+	ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
+
+	/*
+	 * If we're turning off quotas, we have to make sure that, for
+	 * example, we don't delete quota disk blocks while dquots are
+	 * in the process of getting written to those disk blocks.
+	 * This dquot might well be on AIL, and we can't leave it there
+	 * if we're turning off quotas. Basically, we need this flush
+	 * lock, and are willing to block on it.
+	 */
+	if (! xfs_qm_dqflock_nowait(dqp)) {
+		/*
+		 * Block on the flush lock after nudging dquot buffer,
+		 * if it is incore.
+		 */
+		xfs_qm_dqflock_pushbuf_wait(dqp);
+	}
+
+	/*
+	 * XXXIf we're turning this type of quotas off, we don't care
+	 * about the dirty metadata sitting in this dquot. OTOH, if
+	 * we're unmounting, we do care, so we flush it and wait.
+	 */
+	if (XFS_DQ_IS_DIRTY(dqp)) {
+		xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY");
+		/* dqflush unlocks dqflock */
+		/*
+		 * Given that dqpurge is a very rare occurrence, it is OK
+		 * that we're holding the hashlist and mplist locks
+		 * across the disk write. But, ... XXXsup
+		 *
+		 * We don't care about getting disk errors here. We need
+		 * to purge this dquot anyway, so we go ahead regardless.
+		 */
+		(void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC);
+		xfs_dqflock(dqp);
+	}
+	ASSERT(dqp->q_pincount == 0);
+	ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
+	       !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+
+	thishash = dqp->q_hash;
+	XQM_HASHLIST_REMOVE(thishash, dqp);
+	XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp);
+	/*
+	 * XXX Move this to the front of the freelist, if we can get the
+	 * freelist lock.
+	 */
+	ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
+
+	dqp->q_mount = NULL;;
+	dqp->q_hash = NULL;
+	dqp->dq_flags = XFS_DQ_INACTIVE;
+	memset(&dqp->q_core, 0, sizeof(dqp->q_core));
+	xfs_dqfunlock(dqp);
+	xfs_dqunlock(dqp);
+	XFS_DQ_HASH_UNLOCK(thishash);
+	return (0);
+}
+
+
+#ifdef QUOTADEBUG
+void
+xfs_qm_dqprint(xfs_dquot_t *dqp)
+{
+	cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------");
+	cmn_err(CE_DEBUG, "---- dquotID =  %d",
+		(int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- type    =  %s",
+		XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
+	cmn_err(CE_DEBUG, "---- fs      =  0x%p", dqp->q_mount);
+	cmn_err(CE_DEBUG, "---- blkno   =  0x%x", (int) dqp->q_blkno);
+	cmn_err(CE_DEBUG, "---- boffset =  0x%x", (int) dqp->q_bufoffset);
+	cmn_err(CE_DEBUG, "---- blkhlimit =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
+		(int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- blkslimit =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
+		(int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- inohlimit =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
+		(int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- inoslimit =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
+		(int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- bcount  =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+		(int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- icount  =  %Lu (0x%x)",
+		INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+		(int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- btimer  =  %d",
+		(int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---- itimer  =  %d",
+		(int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT));
+	cmn_err(CE_DEBUG, "---------------------------");
+}
+#endif
+
+/*
+ * Give the buffer a little push if it is incore and
+ * wait on the flush lock.
+ */
+void
+xfs_qm_dqflock_pushbuf_wait(
+	xfs_dquot_t	*dqp)
+{
+	xfs_buf_t	*bp;
+
+	/*
+	 * Check to see if the dquot has been flushed delayed
+	 * write.  If so, grab its buffer and send it
+	 * out immediately.  We'll be able to acquire
+	 * the flush lock when the I/O completes.
+	 */
+	bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
+		    XFS_QI_DQCHUNKLEN(dqp->q_mount),
+		    XFS_INCORE_TRYLOCK);
+	if (bp != NULL) {
+		if (XFS_BUF_ISDELAYWRITE(bp)) {
+			if (XFS_BUF_ISPINNED(bp)) {
+				xfs_log_force(dqp->q_mount,
+					      (xfs_lsn_t)0,
+					      XFS_LOG_FORCE);
+			}
+			xfs_bawrite(dqp->q_mount, bp);
+		} else {
+			xfs_buf_relse(bp);
+		}
+	}
+	xfs_dqflock(dqp);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot.h linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot.h
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot.h	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_DQUOT_H__
+#define __XFS_DQUOT_H__
+
+/*
+ * Dquots are structures that hold quota information about a user or a group,
+ * much like inodes are for files. In fact, dquots share many characteristics
+ * with inodes. However, dquots can also be a centralized resource, relative
+ * to a collection of inodes. In this respect, dquots share some characteristics
+ * of the superblock.
+ * XFS dquots exploit both those in its algorithms. They make every attempt
+ * to not be a bottleneck when quotas are on and have minimal impact, if any,
+ * when quotas are off.
+ */
+
+/*
+ * The hash chain headers (hash buckets)
+ */
+typedef struct xfs_dqhash {
+	struct xfs_dquot *qh_next;
+	mutex_t		  qh_lock;
+	uint		  qh_version;	/* ever increasing version */
+	uint		  qh_nelems;	/* number of dquots on the list */
+} xfs_dqhash_t;
+
+typedef struct xfs_dqlink {
+	struct xfs_dquot  *ql_next;	/* forward link */
+	struct xfs_dquot **ql_prevp;	/* pointer to prev ql_next */
+} xfs_dqlink_t;
+
+struct xfs_mount;
+struct xfs_trans;
+
+/*
+ * This is the marker which is designed to occupy the first few
+ * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers
+ * must come first.
+ * This serves as the marker ("sentinel") when we have to restart list
+ * iterations because of locking considerations.
+ */
+typedef struct xfs_dqmarker {
+	struct xfs_dquot*dqm_flnext;	/* link to freelist: must be first */
+	struct xfs_dquot*dqm_flprev;
+	xfs_dqlink_t	 dqm_mplist;	/* link to mount's list of dquots */
+	xfs_dqlink_t	 dqm_hashlist;	/* link to the hash chain */
+	uint		 dqm_flags;	/* various flags (XFS_DQ_*) */
+} xfs_dqmarker_t;
+
+/*
+ * The incore dquot structure
+ */
+typedef struct xfs_dquot {
+	xfs_dqmarker_t	 q_lists;	/* list ptrs, q_flags (marker) */
+	xfs_dqhash_t	*q_hash;	/* the hashchain header */
+	struct xfs_mount*q_mount;	/* filesystem this relates to */
+	struct xfs_trans*q_transp;	/* trans this belongs to currently */
+	uint		 q_nrefs;	/* # active refs from inodes */
+	xfs_daddr_t	 q_blkno;	/* blkno of dquot buffer */
+	int		 q_bufoffset;	/* off of dq in buffer (# dquots) */
+	xfs_fileoff_t	 q_fileoffset;	/* offset in quotas file */
+
+	struct xfs_dquot*q_gdquot;	/* group dquot, hint only */
+	xfs_disk_dquot_t q_core;	/* actual usage & quotas */
+	xfs_dq_logitem_t q_logitem;	/* dquot log item */
+	xfs_qcnt_t	 q_res_bcount;	/* total regular nblks used+reserved */
+	xfs_qcnt_t	 q_res_icount;	/* total inos allocd+reserved */
+	xfs_qcnt_t	 q_res_rtbcount;/* total realtime blks used+reserved */
+	mutex_t		 q_qlock;	/* quota lock */
+	sema_t		 q_flock;	/* flush lock */
+	uint		 q_pincount;	/* pin count for this dquot */
+	sv_t		 q_pinwait;	/* sync var for pinning */
+#ifdef DQUOT_TRACING
+	struct ktrace	*q_trace;	/* trace header structure */
+#endif
+} xfs_dquot_t;
+
+
+#define dq_flnext	q_lists.dqm_flnext
+#define dq_flprev	q_lists.dqm_flprev
+#define dq_mplist	q_lists.dqm_mplist
+#define dq_hashlist	q_lists.dqm_hashlist
+#define dq_flags	q_lists.dqm_flags
+
+#define XFS_DQHOLD(dqp)		((dqp)->q_nrefs++)
+
+/*
+ * Quota Accounting flags
+ */
+#define XFS_ALL_QUOTA_ACCT	(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
+#define XFS_ALL_QUOTA_ACTV	(XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
+#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
+				 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
+
+#define XFS_IS_QUOTA_RUNNING(mp)  ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
+#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+
+/*
+ * Quota Limit Enforcement flags
+ */
+#define XFS_IS_QUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
+#define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
+#define XFS_IS_GQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_GQUOTA_ENFD)
+
+#ifdef DEBUG
+static inline int
+XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
+{
+	if (mutex_trylock(&dqp->q_qlock)) {
+		mutex_unlock(&dqp->q_qlock);
+		return 0;
+	}
+	return 1;
+}
+#endif
+
+
+/*
+ * The following three routines simply manage the q_flock
+ * semaphore embedded in the dquot.  This semaphore synchronizes
+ * processes attempting to flush the in-core dquot back to disk.
+ */
+#define xfs_dqflock(dqp)	 { psema(&((dqp)->q_flock), PINOD | PRECALC);\
+				   (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
+#define xfs_dqfunlock(dqp)	 { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
+				   vsema(&((dqp)->q_flock)); \
+				   (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
+
+#define XFS_DQ_PINLOCK(dqp)	   mutex_spinlock( \
+				     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock))
+#define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
+				     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
+
+#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
+#define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
+#define XFS_DQ_IS_DIRTY(dqp)	((dqp)->dq_flags & XFS_DQ_DIRTY)
+#define XFS_QM_ISUDQ(dqp)	((dqp)->dq_flags & XFS_DQ_USER)
+#define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
+#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
+				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
+				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
+
+#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
+				     (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
+				     (XFS_IS_GQUOTA_ON((d)->q_mount))))
+#ifdef DQUOT_TRACING
+/*
+ * Dquot Tracing stuff.
+ */
+#define DQUOT_TRACE_SIZE	64
+#define DQUOT_KTRACE_ENTRY	1
+
+#define xfs_dqtrace_entry_ino(a,b,ip) \
+xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip))
+#define xfs_dqtrace_entry(a,b) \
+xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL)
+extern void		xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func,
+					    void *, xfs_inode_t *);
+#else
+#define xfs_dqtrace_entry(a,b)
+#define xfs_dqtrace_entry_ino(a,b,ip)
+#endif
+#ifdef QUOTADEBUG
+extern void		xfs_qm_dqprint(xfs_dquot_t *);
+#else
+#define xfs_qm_dqprint(a)
+#endif
+
+extern void		xfs_qm_dqdestroy(xfs_dquot_t *);
+extern int		xfs_qm_dqflush(xfs_dquot_t *, uint);
+extern int		xfs_qm_dqpurge(xfs_dquot_t *, uint);
+extern void		xfs_qm_dqunpin_wait(xfs_dquot_t *);
+extern int		xfs_qm_dqlock_nowait(xfs_dquot_t *);
+extern int		xfs_qm_dqflock_nowait(xfs_dquot_t *);
+extern void		xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
+extern void		xfs_qm_adjust_dqtimers(xfs_mount_t *,
+					xfs_disk_dquot_t *);
+extern int		xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
+extern int		xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
+					xfs_dqid_t, uint, uint, xfs_dquot_t **);
+extern void		xfs_qm_dqput(xfs_dquot_t *);
+extern void		xfs_qm_dqrele(xfs_dquot_t *);
+extern void		xfs_dqlock(xfs_dquot_t *);
+extern void		xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
+extern void		xfs_dqunlock(xfs_dquot_t *);
+extern void		xfs_dqunlock_nonotify(xfs_dquot_t *);
+
+#endif /* __XFS_DQUOT_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot_item.c linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot_item.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot_item.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot_item.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+
+/*
+ * returns the number of iovecs needed to log the given dquot item.
+ */
+/* ARGSUSED */
+STATIC uint
+xfs_qm_dquot_logitem_size(
+	xfs_dq_logitem_t	*logitem)
+{
+	/*
+	 * we need only two iovecs, one for the format, one for the real thing
+	 */
+	return (2);
+}
+
+/*
+ * fills in the vector of log iovecs for the given dquot log item.
+ */
+STATIC void
+xfs_qm_dquot_logitem_format(
+	xfs_dq_logitem_t	*logitem,
+	xfs_log_iovec_t		*logvec)
+{
+	ASSERT(logitem);
+	ASSERT(logitem->qli_dquot);
+
+	logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
+	logvec->i_len  = sizeof(xfs_dq_logformat_t);
+	logvec++;
+	logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
+	logvec->i_len  = sizeof(xfs_disk_dquot_t);
+
+	ASSERT(2 == logitem->qli_item.li_desc->lid_size);
+	logitem->qli_format.qlf_size = 2;
+
+}
+
+/*
+ * Increment the pin count of the given dquot.
+ * This value is protected by pinlock spinlock in the xQM structure.
+ */
+STATIC void
+xfs_qm_dquot_logitem_pin(
+	xfs_dq_logitem_t *logitem)
+{
+	unsigned long	s;
+	xfs_dquot_t *dqp;
+
+	dqp = logitem->qli_dquot;
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	s = XFS_DQ_PINLOCK(dqp);
+	dqp->q_pincount++;
+	XFS_DQ_PINUNLOCK(dqp, s);
+}
+
+/*
+ * Decrement the pin count of the given dquot, and wake up
+ * anyone in xfs_dqwait_unpin() if the count goes to 0.	 The
+ * dquot must have been previously pinned with a call to xfs_dqpin().
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_unpin(
+	xfs_dq_logitem_t *logitem,
+	int		  stale)
+{
+	unsigned long	s;
+	xfs_dquot_t *dqp;
+
+	dqp = logitem->qli_dquot;
+	ASSERT(dqp->q_pincount > 0);
+	s = XFS_DQ_PINLOCK(dqp);
+	dqp->q_pincount--;
+	if (dqp->q_pincount == 0) {
+		sv_broadcast(&dqp->q_pinwait);
+	}
+	XFS_DQ_PINUNLOCK(dqp, s);
+}
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_unpin_remove(
+	xfs_dq_logitem_t *logitem,
+	xfs_trans_t	 *tp)
+{
+	xfs_qm_dquot_logitem_unpin(logitem, 0);
+}
+
+/*
+ * Given the logitem, this writes the corresponding dquot entry to disk
+ * asynchronously. This is called with the dquot entry securely locked;
+ * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
+ * at the end.
+ */
+STATIC void
+xfs_qm_dquot_logitem_push(
+	xfs_dq_logitem_t	*logitem)
+{
+	xfs_dquot_t	*dqp;
+
+	dqp = logitem->qli_dquot;
+
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
+
+	/*
+	 * Since we were able to lock the dquot's flush lock and
+	 * we found it on the AIL, the dquot must be dirty.  This
+	 * is because the dquot is removed from the AIL while still
+	 * holding the flush lock in xfs_dqflush_done().  Thus, if
+	 * we found it in the AIL and were able to obtain the flush
+	 * lock without sleeping, then there must not have been
+	 * anyone in the process of flushing the dquot.
+	 */
+	xfs_qm_dqflush(dqp, XFS_B_DELWRI);
+	xfs_dqunlock(dqp);
+}
+
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_dquot_logitem_committed(
+	xfs_dq_logitem_t	*l,
+	xfs_lsn_t		lsn)
+{
+	/*
+	 * We always re-log the entire dquot when it becomes dirty,
+	 * so, the latest copy _is_ the only one that matters.
+	 */
+	return (lsn);
+}
+
+
+/*
+ * This is called to wait for the given dquot to be unpinned.
+ * Most of these pin/unpin routines are plagiarized from inode code.
+ */
+void
+xfs_qm_dqunpin_wait(
+	xfs_dquot_t	*dqp)
+{
+	SPLDECL(s);
+
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	if (dqp->q_pincount == 0) {
+		return;
+	}
+
+	/*
+	 * Give the log a push so we don't wait here too long.
+	 */
+	xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
+	s = XFS_DQ_PINLOCK(dqp);
+	if (dqp->q_pincount == 0) {
+		XFS_DQ_PINUNLOCK(dqp, s);
+		return;
+	}
+	sv_wait(&(dqp->q_pinwait), PINOD,
+		&(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
+}
+
+/*
+ * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
+ * the dquot is locked by us, but the flush lock isn't. So, here we are
+ * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
+ * If so, we want to push it out to help us take this item off the AIL as soon
+ * as possible.
+ *
+ * We must not be holding the AIL_LOCK at this point. Calling incore() to
+ * search the buffercache can be a time consuming thing, and AIL_LOCK is a
+ * spinlock.
+ */
+STATIC void
+xfs_qm_dquot_logitem_pushbuf(
+	xfs_dq_logitem_t    *qip)
+{
+	xfs_dquot_t	*dqp;
+	xfs_mount_t	*mp;
+	xfs_buf_t	*bp;
+	uint		dopush;
+
+	dqp = qip->qli_dquot;
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+	/*
+	 * The qli_pushbuf_flag keeps others from
+	 * trying to duplicate our effort.
+	 */
+	ASSERT(qip->qli_pushbuf_flag != 0);
+	ASSERT(qip->qli_push_owner == get_thread_id());
+
+	/*
+	 * If flushlock isn't locked anymore, chances are that the
+	 * inode flush completed and the inode was taken off the AIL.
+	 * So, just get out.
+	 */
+	if ((valusema(&(dqp->q_flock)) > 0)  ||
+	    ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+		qip->qli_pushbuf_flag = 0;
+		xfs_dqunlock(dqp);
+		return;
+	}
+	mp = dqp->q_mount;
+	bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
+		    XFS_QI_DQCHUNKLEN(mp),
+		    XFS_INCORE_TRYLOCK);
+	if (bp != NULL) {
+		if (XFS_BUF_ISDELAYWRITE(bp)) {
+			dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
+				  (valusema(&(dqp->q_flock)) <= 0));
+			qip->qli_pushbuf_flag = 0;
+			xfs_dqunlock(dqp);
+
+			if (XFS_BUF_ISPINNED(bp)) {
+				xfs_log_force(mp, (xfs_lsn_t)0,
+					      XFS_LOG_FORCE);
+			}
+			if (dopush) {
+#ifdef XFSRACEDEBUG
+				delay_for_intr();
+				delay(300);
+#endif
+				xfs_bawrite(mp, bp);
+			} else {
+				xfs_buf_relse(bp);
+			}
+		} else {
+			qip->qli_pushbuf_flag = 0;
+			xfs_dqunlock(dqp);
+			xfs_buf_relse(bp);
+		}
+		return;
+	}
+
+	qip->qli_pushbuf_flag = 0;
+	xfs_dqunlock(dqp);
+}
+
+/*
+ * This is called to attempt to lock the dquot associated with this
+ * dquot log item.  Don't sleep on the dquot lock or the flush lock.
+ * If the flush lock is already held, indicating that the dquot has
+ * been or is in the process of being flushed, then see if we can
+ * find the dquot's buffer in the buffer cache without sleeping.  If
+ * we can and it is marked delayed write, then we want to send it out.
+ * We delay doing so until the push routine, though, to avoid sleeping
+ * in any device strategy routines.
+ */
+STATIC uint
+xfs_qm_dquot_logitem_trylock(
+	xfs_dq_logitem_t	*qip)
+{
+	xfs_dquot_t		*dqp;
+	uint			retval;
+
+	dqp = qip->qli_dquot;
+	if (dqp->q_pincount > 0)
+		return (XFS_ITEM_PINNED);
+
+	if (! xfs_qm_dqlock_nowait(dqp))
+		return (XFS_ITEM_LOCKED);
+
+	retval = XFS_ITEM_SUCCESS;
+	if (! xfs_qm_dqflock_nowait(dqp)) {
+		/*
+		 * The dquot is already being flushed.	It may have been
+		 * flushed delayed write, however, and we don't want to
+		 * get stuck waiting for that to complete.  So, we want to check
+		 * to see if we can lock the dquot's buffer without sleeping.
+		 * If we can and it is marked for delayed write, then we
+		 * hold it and send it out from the push routine.  We don't
+		 * want to do that now since we might sleep in the device
+		 * strategy routine.  We also don't want to grab the buffer lock
+		 * here because we'd like not to call into the buffer cache
+		 * while holding the AIL_LOCK.
+		 * Make sure to only return PUSHBUF if we set pushbuf_flag
+		 * ourselves.  If someone else is doing it then we don't
+		 * want to go to the push routine and duplicate their efforts.
+		 */
+		if (qip->qli_pushbuf_flag == 0) {
+			qip->qli_pushbuf_flag = 1;
+			ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
+#ifdef DEBUG
+			qip->qli_push_owner = get_thread_id();
+#endif
+			/*
+			 * The dquot is left locked.
+			 */
+			retval = XFS_ITEM_PUSHBUF;
+		} else {
+			retval = XFS_ITEM_FLUSHING;
+			xfs_dqunlock_nonotify(dqp);
+		}
+	}
+
+	ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
+	return (retval);
+}
+
+
+/*
+ * Unlock the dquot associated with the log item.
+ * Clear the fields of the dquot and dquot log item that
+ * are specific to the current transaction.  If the
+ * hold flags is set, do not unlock the dquot.
+ */
+STATIC void
+xfs_qm_dquot_logitem_unlock(
+	xfs_dq_logitem_t    *ql)
+{
+	xfs_dquot_t	*dqp;
+
+	ASSERT(ql != NULL);
+	dqp = ql->qli_dquot;
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+	/*
+	 * Clear the transaction pointer in the dquot
+	 */
+	dqp->q_transp = NULL;
+
+	/*
+	 * dquots are never 'held' from getting unlocked at the end of
+	 * a transaction.  Their locking and unlocking is hidden inside the
+	 * transaction layer, within trans_commit. Hence, no LI_HOLD flag
+	 * for the logitem.
+	 */
+	xfs_dqunlock(dqp);
+}
+
+
+/*
+ * The transaction with the dquot locked has aborted.  The dquot
+ * must not be dirty within the transaction.  We simply unlock just
+ * as if the transaction had been cancelled.
+ */
+STATIC void
+xfs_qm_dquot_logitem_abort(
+	xfs_dq_logitem_t    *ql)
+{
+	xfs_qm_dquot_logitem_unlock(ql);
+}
+
+/*
+ * this needs to stamp an lsn into the dquot, I think.
+ * rpc's that look at user dquot's would then have to
+ * push on the dependency recorded in the dquot
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_committing(
+	xfs_dq_logitem_t	*l,
+	xfs_lsn_t		lsn)
+{
+	return;
+}
+
+
+/*
+ * This is the ops vector for dquots
+ */
+struct xfs_item_ops xfs_dquot_item_ops = {
+	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
+	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+					xfs_qm_dquot_logitem_format,
+	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
+	.iop_unpin	= (void(*)(xfs_log_item_t*, int))
+					xfs_qm_dquot_logitem_unpin,
+	.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
+					xfs_qm_dquot_logitem_unpin_remove,
+	.iop_trylock	= (uint(*)(xfs_log_item_t*))
+					xfs_qm_dquot_logitem_trylock,
+	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
+	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_dquot_logitem_committed,
+	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
+	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
+	.iop_pushbuf	= (void(*)(xfs_log_item_t*))
+					xfs_qm_dquot_logitem_pushbuf,
+	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_dquot_logitem_committing
+};
+
+/*
+ * Initialize the dquot log item for a newly allocated dquot.
+ * The dquot isn't locked at this point, but it isn't on any of the lists
+ * either, so we don't care.
+ */
+void
+xfs_qm_dquot_logitem_init(
+	struct xfs_dquot *dqp)
+{
+	xfs_dq_logitem_t  *lp;
+	lp = &dqp->q_logitem;
+
+	lp->qli_item.li_type = XFS_LI_DQUOT;
+	lp->qli_item.li_ops = &xfs_dquot_item_ops;
+	lp->qli_item.li_mountp = dqp->q_mount;
+	lp->qli_dquot = dqp;
+	lp->qli_format.qlf_type = XFS_LI_DQUOT;
+	lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
+	lp->qli_format.qlf_blkno = dqp->q_blkno;
+	lp->qli_format.qlf_len = 1;
+	/*
+	 * This is just the offset of this dquot within its buffer
+	 * (which is currently 1 FSB and probably won't change).
+	 * Hence 32 bits for this offset should be just fine.
+	 * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t))
+	 * here, and recompute it at recovery time.
+	 */
+	lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset;
+}
+
+/*------------------  QUOTAOFF LOG ITEMS  -------------------*/
+
+/*
+ * This returns the number of iovecs needed to log the given quotaoff item.
+ * We only need 1 iovec for an quotaoff item.  It just logs the
+ * quotaoff_log_format structure.
+ */
+/*ARGSUSED*/
+STATIC uint
+xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
+{
+	return (1);
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given quotaoff log item. We use only 1 iovec, and we point that
+ * at the quotaoff_log_format structure embedded in the quotaoff item.
+ * It is at this point that we assert that all of the extent
+ * slots in the quotaoff item have been filled.
+ */
+STATIC void
+xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t	*qf,
+			   xfs_log_iovec_t	*log_vector)
+{
+	ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
+
+	log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
+	log_vector->i_len = sizeof(xfs_qoff_logitem_t);
+	qf->qql_format.qf_size = 1;
+}
+
+
+/*
+ * Pinning has no meaning for an quotaoff item, so just return.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
+{
+	return;
+}
+
+
+/*
+ * Since pinning has no meaning for an quotaoff item, unpinning does
+ * not either.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
+{
+	return;
+}
+
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
+{
+	return;
+}
+
+/*
+ * Quotaoff items have no locking, so just return success.
+ */
+/*ARGSUSED*/
+STATIC uint
+xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
+{
+	return XFS_ITEM_LOCKED;
+}
+
+/*
+ * Quotaoff items have no locking or pushing, so return failure
+ * so that the caller doesn't bother with us.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
+{
+	return;
+}
+
+/*
+ * The quotaoff-start-item is logged only once and cannot be moved in the log,
+ * so simply return the lsn at which it's been logged.
+ */
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
+{
+	return (lsn);
+}
+
+/*
+ * The transaction of which this QUOTAOFF is a part has been aborted.
+ * Just clean up after ourselves.
+ * Shouldn't this never happen in the case of qoffend logitems? XXX
+ */
+STATIC void
+xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
+{
+	kmem_free(qf, sizeof(xfs_qoff_logitem_t));
+}
+
+/*
+ * There isn't much you can do to push on an quotaoff item.  It is simply
+ * stuck waiting for the log to be flushed to disk.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
+{
+	return;
+}
+
+
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_qoffend_logitem_committed(
+	xfs_qoff_logitem_t *qfe,
+	xfs_lsn_t lsn)
+{
+	xfs_qoff_logitem_t	*qfs;
+	SPLDECL(s);
+
+	qfs = qfe->qql_start_lip;
+	AIL_LOCK(qfs->qql_item.li_mountp,s);
+	/*
+	 * Delete the qoff-start logitem from the AIL.
+	 * xfs_trans_delete_ail() drops the AIL lock.
+	 */
+	xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s);
+	kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
+	kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
+	return (xfs_lsn_t)-1;
+}
+
+/*
+ * XXX rcc - don't know quite what to do with this.  I think we can
+ * just ignore it.  The only time that isn't the case is if we allow
+ * the client to somehow see that quotas have been turned off in which
+ * we can't allow that to get back until the quotaoff hits the disk.
+ * So how would that happen?  Also, do we need different routines for
+ * quotaoff start and quotaoff end?  I suspect the answer is yes but
+ * to be sure, I need to look at the recovery code and see how quota off
+ * recovery is handled (do we roll forward or back or do something else).
+ * If we roll forwards or backwards, then we need two separate routines,
+ * one that does nothing and one that stamps in the lsn that matters
+ * (truly makes the quotaoff irrevocable).  If we do something else,
+ * then maybe we don't need two.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+{
+	return;
+}
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+{
+	return;
+}
+
+struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
+	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
+	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+					xfs_qm_qoff_logitem_format,
+	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
+	.iop_unpin	= (void(*)(xfs_log_item_t* ,int))
+					xfs_qm_qoff_logitem_unpin,
+	.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
+					xfs_qm_qoff_logitem_unpin_remove,
+	.iop_trylock	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
+	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
+	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_qoffend_logitem_committed,
+	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+	.iop_pushbuf	= NULL,
+	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_qoffend_logitem_committing
+};
+
+/*
+ * This is the ops vector shared by all quotaoff-start log items.
+ */
+struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
+	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
+	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+					xfs_qm_qoff_logitem_format,
+	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
+	.iop_unpin	= (void(*)(xfs_log_item_t*, int))
+					xfs_qm_qoff_logitem_unpin,
+	.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
+					xfs_qm_qoff_logitem_unpin_remove,
+	.iop_trylock	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
+	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
+	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_qoff_logitem_committed,
+	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+	.iop_pushbuf	= NULL,
+	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+					xfs_qm_qoff_logitem_committing
+};
+
+/*
+ * Allocate and initialize an quotaoff item of the correct quota type(s).
+ */
+xfs_qoff_logitem_t *
+xfs_qm_qoff_logitem_init(
+	struct xfs_mount *mp,
+	xfs_qoff_logitem_t *start,
+	uint flags)
+{
+	xfs_qoff_logitem_t	*qf;
+
+	qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
+
+	qf->qql_item.li_type = XFS_LI_QUOTAOFF;
+	if (start)
+		qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops;
+	else
+		qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops;
+	qf->qql_item.li_mountp = mp;
+	qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
+	qf->qql_format.qf_flags = flags;
+	qf->qql_start_lip = start;
+	return (qf);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot_item.h linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot_item.h
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_dquot_item.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_dquot_item.h	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_DQUOT_ITEM_H__
+#define __XFS_DQUOT_ITEM_H__
+
+struct xfs_dquot;
+struct xfs_trans;
+struct xfs_mount;
+struct xfs_qoff_logitem;
+
+typedef struct xfs_dq_logitem {
+	xfs_log_item_t		 qli_item;	   /* common portion */
+	struct xfs_dquot	*qli_dquot;	   /* dquot ptr */
+	xfs_lsn_t		 qli_flush_lsn;	   /* lsn at last flush */
+	unsigned short		 qli_pushbuf_flag; /* 1 bit used in push_ail */
+#ifdef DEBUG
+	uint64_t		 qli_push_owner;
+#endif
+	xfs_dq_logformat_t	 qli_format;	   /* logged structure */
+} xfs_dq_logitem_t;
+
+typedef struct xfs_qoff_logitem {
+	xfs_log_item_t		 qql_item;	/* common portion */
+	struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
+	xfs_qoff_logformat_t	 qql_format;	/* logged structure */
+} xfs_qoff_logitem_t;
+
+
+extern void		   xfs_qm_dquot_logitem_init(struct xfs_dquot *);
+extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
+					struct xfs_qoff_logitem *, uint);
+extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
+					struct xfs_qoff_logitem *, uint);
+extern void		   xfs_trans_log_quotaoff_item(struct xfs_trans *,
+					struct xfs_qoff_logitem *);
+
+#endif	/* __XFS_DQUOT_ITEM_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm.c linux-2.5.66-bk3/fs/xfs/quota/xfs_qm.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,2794 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+/*
+ * The global quota manager. There is only one of these for the entire
+ * system, _not_ one per file system. XQM keeps track of the overall
+ * quota functionality, including maintaining the freelist and hash
+ * tables of dquots.
+ */
+mutex_t xfs_Gqm_lock;
+struct xfs_qm	*xfs_Gqm;
+EXPORT_SYMBOL(xfs_Gqm);	/* used by xfsidbg */
+
+kmem_zone_t	*qm_dqzone;
+kmem_zone_t	*qm_dqtrxzone;
+
+STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);
+STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);
+STATIC int	xfs_qm_quotacheck(xfs_mount_t *);
+
+STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
+STATIC void	xfs_qm_shake(void);
+
+#ifdef DEBUG
+extern mutex_t	qcheck_lock;
+#endif
+
+#ifdef QUOTADEBUG
+#define XQM_LIST_PRINT(l, NXT, title) \
+{ \
+	xfs_dquot_t	*dqp; int i = 0; \
+	cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
+	for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \
+		cmn_err(CE_DEBUG, "   %d.  \"%d (%s)\"   " \
+				  "bcnt = %d, icnt = %d, refs = %d", \
+			++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \
+			DQFLAGTO_TYPESTR(dqp),	     \
+			(int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \
+			(int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \
+			(int) dqp->q_nrefs);  } \
+}
+#else
+#define XQM_LIST_PRINT(l, NXT, title) do { } while (0)
+#endif
+
+/*
+ * Initialize the XQM structure.
+ * Note that there is not one quota manager per file system.
+ */
+STATIC struct xfs_qm *
+xfs_Gqm_init(void)
+{
+	xfs_qm_t		*xqm;
+	int			hsize, i;
+
+	xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
+	ASSERT(xqm);
+
+	/*
+	 * Initialize the dquot hash tables.
+	 */
+	hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ?
+		XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH;
+	xqm->qm_dqhashmask = hsize - 1;
+
+	xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
+						      sizeof(xfs_dqhash_t),
+						      KM_SLEEP);
+	xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
+						      sizeof(xfs_dqhash_t),
+						      KM_SLEEP);
+	ASSERT(xqm->qm_usr_dqhtable != NULL);
+	ASSERT(xqm->qm_grp_dqhtable != NULL);
+
+	for (i = 0; i < hsize; i++) {
+		xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
+		xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
+	}
+
+	/*
+	 * Freelist of all dquots of all file systems
+	 */
+	xfs_qm_freelist_init(&(xqm->qm_dqfreelist));
+
+	/*
+	 * dquot zone. we register our own low-memory callback.
+	 */
+	if (!qm_dqzone) {
+		xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
+						"xfs_dquots");
+		qm_dqzone = xqm->qm_dqzone;
+	} else
+		xqm->qm_dqzone = qm_dqzone;
+
+	kmem_shake_register(xfs_qm_shake);
+
+	/*
+	 * The t_dqinfo portion of transactions.
+	 */
+	if (!qm_dqtrxzone) {
+		xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
+						   "xfs_dqtrx");
+		qm_dqtrxzone = xqm->qm_dqtrxzone;
+	} else
+		xqm->qm_dqtrxzone = qm_dqtrxzone;
+
+	atomic_set(&xqm->qm_totaldquots, 0);
+	xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
+	xqm->qm_nrefs = 0;
+#ifdef DEBUG
+	mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");
+#endif
+	return xqm;
+}
+
+/*
+ * Destroy the global quota manager when its reference count goes to zero.
+ */
+void
+xfs_qm_destroy(
+	struct xfs_qm	*xqm)
+{
+	int		hsize, i;
+
+	ASSERT(xqm != NULL);
+	ASSERT(xqm->qm_nrefs == 0);
+	kmem_shake_deregister(xfs_qm_shake);
+	hsize = xqm->qm_dqhashmask + 1;
+	for (i = 0; i < hsize; i++) {
+		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
+		xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
+	}
+	kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));
+	kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
+	xqm->qm_usr_dqhtable = NULL;
+	xqm->qm_grp_dqhtable = NULL;
+	xqm->qm_dqhashmask = 0;
+	xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));
+#ifdef DEBUG
+	mutex_destroy(&qcheck_lock);
+#endif
+	kmem_free(xqm, sizeof(xfs_qm_t));
+}
+
+/*
+ * Called at mount time to let XQM know that another file system is
+ * starting quotas. This isn't crucial information as the individual mount
+ * structures are pretty independent, but it helps the XQM keep a
+ * global view of what's going on.
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_hold_quotafs_ref(
+	struct xfs_mount *mp)
+{
+	/*
+	 * Need to lock the xfs_Gqm structure for things like this. For example,
+	 * the structure could disappear between the entry to this routine and
+	 * a HOLD operation if not locked.
+	 */
+	XFS_QM_LOCK(xfs_Gqm);
+
+	if (xfs_Gqm == NULL) {
+		if ((xfs_Gqm = xfs_Gqm_init()) == NULL) {
+			return (XFS_ERROR(EINVAL));
+		}
+	}
+	/*
+	 * We can keep a list of all filesystems with quotas mounted for
+	 * debugging and statistical purposes, but ...
+	 * Just take a reference and get out.
+	 */
+	XFS_QM_HOLD(xfs_Gqm);
+	XFS_QM_UNLOCK(xfs_Gqm);
+
+	return 0;
+}
+
+
+/*
+ * Release the reference that a filesystem took at mount time,
+ * so that we know when we need to destroy the entire quota manager.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_rele_quotafs_ref(
+	struct xfs_mount *mp)
+{
+	xfs_dquot_t	*dqp, *nextdqp;
+
+	ASSERT(xfs_Gqm);
+	ASSERT(xfs_Gqm->qm_nrefs > 0);
+
+	/*
+	 * Go thru the freelist and destroy all inactive dquots.
+	 */
+	xfs_qm_freelist_lock(xfs_Gqm);
+
+	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
+	     dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {
+		xfs_dqlock(dqp);
+		nextdqp = dqp->dq_flnext;
+		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+			ASSERT(dqp->q_mount == NULL);
+			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+			ASSERT(dqp->HL_PREVP == NULL);
+			ASSERT(dqp->MPL_PREVP == NULL);
+			XQM_FREELIST_REMOVE(dqp);
+			xfs_dqunlock(dqp);
+			xfs_qm_dqdestroy(dqp);
+		} else {
+			xfs_dqunlock(dqp);
+		}
+		dqp = nextdqp;
+	}
+	xfs_qm_freelist_unlock(xfs_Gqm);
+
+	/*
+	 * Destroy the entire XQM. If somebody mounts with quotaon, this'll
+	 * be restarted.
+	 */
+	XFS_QM_LOCK(xfs_Gqm);
+	XFS_QM_RELE(xfs_Gqm);
+	if (xfs_Gqm->qm_nrefs == 0) {
+		xfs_qm_destroy(xfs_Gqm);
+		xfs_Gqm = NULL;
+	}
+	XFS_QM_UNLOCK(xfs_Gqm);
+}
+
+/*
+ * This is called at mount time from xfs_mountfs to initialize the quotainfo
+ * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
+ * so already.	Note that the superblock has not been read in yet.
+ */
+void
+xfs_qm_mount_quotainit(
+	xfs_mount_t	*mp,
+	uint		flags)
+{
+	/*
+	 * User or group quotas has to be on.
+	 */
+	ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
+
+	/*
+	 * Initialize the flags in the mount structure. From this point
+	 * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.
+	 * Note that we enforce nothing if accounting is off.
+	 * ie.	XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.
+	 * It isn't necessary to take the quotaoff lock to do this; this is
+	 * called from mount.
+	 */
+	if (flags & XFSMNT_UQUOTA) {
+		mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
+		if (flags & XFSMNT_UQUOTAENF)
+			mp->m_qflags |= XFS_UQUOTA_ENFD;
+	}
+	if (flags & XFSMNT_GQUOTA) {
+		mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
+		if (flags & XFSMNT_GQUOTAENF)
+			mp->m_qflags |= XFS_GQUOTA_ENFD;
+	}
+}
+
+/*
+ * Just destroy the quotainfo structure.
+ */
+void
+xfs_qm_unmount_quotadestroy(
+	xfs_mount_t	*mp)
+{
+	if (mp->m_quotainfo)
+		xfs_qm_destroy_quotainfo(mp);
+}
+
+
+/*
+ * This is called from xfs_mountfs to start quotas and initialize all
+ * necessary data structures like quotainfo.  This is also responsible for
+ * running a quotacheck as necessary.  We are guaranteed that the superblock
+ * is consistently read in at this point.
+ */
+int
+xfs_qm_mount_quotas(
+	xfs_mount_t	*mp)
+{
+	unsigned long	s;
+	int		error = 0;
+	uint		sbf;
+
+	/*
+	 * If a file system had quotas running earlier, but decided to
+	 * mount without -o quota/uquota/gquota options, revoke the
+	 * quotachecked license, and bail out.
+	 */
+	if (! XFS_IS_QUOTA_ON(mp) &&
+	    (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
+		mp->m_qflags = 0;
+		goto write_changes;
+	}
+
+	/*
+	 * If quotas on realtime volumes is not supported, we disable
+	 * quotas immediately.
+	 */
+	if (mp->m_sb.sb_rextents) {
+		cmn_err(CE_NOTE,
+			"Cannot turn on quotas for realtime filesystem %s",
+			mp->m_fsname);
+		mp->m_qflags = 0;
+		goto write_changes;
+	}
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+	cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
+#endif
+
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+	/*
+	 * Allocate the quotainfo structure inside the mount struct, and
+	 * create quotainode(s), and change/rev superblock if necessary.
+	 */
+	if ((error = xfs_qm_init_quotainfo(mp))) {
+		/*
+		 * We must turn off quotas.
+		 */
+		ASSERT(mp->m_quotainfo == NULL);
+		mp->m_qflags = 0;
+		goto write_changes;
+	}
+	/*
+	 * If any of the quotas are not consistent, do a quotacheck.
+	 */
+	if (XFS_QM_NEED_QUOTACHECK(mp)) {
+#ifdef DEBUG
+		cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
+#endif
+		if ((error = xfs_qm_quotacheck(mp))) {
+			cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
+				"Disabling quotas.",
+				error);
+			/*
+			 * We must turn off quotas.
+			 */
+			ASSERT(mp->m_quotainfo != NULL);
+			ASSERT(xfs_Gqm != NULL);
+			xfs_qm_destroy_quotainfo(mp);
+			mp->m_qflags = 0;
+			goto write_changes;
+		}
+#ifdef DEBUG
+		cmn_err(CE_NOTE, "Done quotacheck.");
+#endif
+	}
+ write_changes:
+	/*
+	 * We actually don't have to acquire the SB_LOCK at all.
+	 * This can only be called from mount, and that's single threaded. XXX
+	 */
+	s = XFS_SB_LOCK(mp);
+	sbf = mp->m_sb.sb_qflags;
+	mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
+	XFS_SB_UNLOCK(mp, s);
+
+	if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
+		if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
+			/*
+			 * We could only have been turning quotas off.
+			 * We aren't in very good shape actually because
+			 * the incore structures are convinced that quotas are
+			 * off, but the on disk superblock doesn't know that !
+			 */
+			ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
+			xfs_fs_cmn_err(CE_ALERT, mp,
+				"XFS mount_quotas: Superblock update failed!");
+		}
+	}
+
+	if (error) {
+		xfs_fs_cmn_err(CE_WARN, mp,
+			"Failed to initialize disk quotas.");
+	}
+	return XFS_ERROR(error);
+}
+
+/*
+ * Called from the vfsops layer.
+ */
+int
+xfs_qm_unmount_quotas(
+	xfs_mount_t	*mp)
+{
+	xfs_inode_t	*uqp, *gqp;
+	int		error = 0;
+
+	/*
+	 * Release the dquots that root inode, et al might be holding,
+	 * before we flush quotas and blow away the quotainfo structure.
+	 */
+	ASSERT(mp->m_rootip);
+	xfs_qm_dqdetach(mp->m_rootip);
+	if (mp->m_rbmip)
+		xfs_qm_dqdetach(mp->m_rbmip);
+	if (mp->m_rsumip)
+		xfs_qm_dqdetach(mp->m_rsumip);
+
+	/*
+	 * Flush out the quota inodes.
+	 */
+	uqp = gqp = NULL;
+	if (mp->m_quotainfo) {
+		if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
+			xfs_ilock(uqp, XFS_ILOCK_EXCL);
+			xfs_iflock(uqp);
+			error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
+			xfs_iunlock(uqp, XFS_ILOCK_EXCL);
+			if (unlikely(error == EFSCORRUPTED)) {
+				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
+						 XFS_ERRLEVEL_LOW, mp);
+				goto out;
+			}
+		}
+		if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
+			xfs_ilock(gqp, XFS_ILOCK_EXCL);
+			xfs_iflock(gqp);
+			error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
+			xfs_iunlock(gqp, XFS_ILOCK_EXCL);
+			if (unlikely(error == EFSCORRUPTED)) {
+				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
+						 XFS_ERRLEVEL_LOW, mp);
+				goto out;
+			}
+		}
+	}
+	if (uqp) {
+		 XFS_PURGE_INODE(uqp);
+		 mp->m_quotainfo->qi_uquotaip = NULL;
+	}
+	if (gqp) {
+		XFS_PURGE_INODE(gqp);
+		mp->m_quotainfo->qi_gquotaip = NULL;
+	}
+out:
+	return XFS_ERROR(error);
+}
+
+/*
+ * Flush all dquots of the given file system to disk. The dquots are
+ * _not_ purged from memory here, just their data written to disk.
+ */
+int
+xfs_qm_dqflush_all(
+	xfs_mount_t	*mp,
+	int		flags)
+{
+	int		recl;
+	xfs_dquot_t	*dqp;
+	int		niters;
+	int		error;
+
+	if (mp->m_quotainfo == NULL)
+		return (0);
+	niters = 0;
+again:
+	xfs_qm_mplist_lock(mp);
+	FOREACH_DQUOT_IN_MP(dqp, mp) {
+		xfs_dqlock(dqp);
+		if (! XFS_DQ_IS_DIRTY(dqp)) {
+			xfs_dqunlock(dqp);
+			continue;
+		}
+		xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");
+		/* XXX a sentinel would be better */
+		recl = XFS_QI_MPLRECLAIMS(mp);
+		if (! xfs_qm_dqflock_nowait(dqp)) {
+			/*
+			 * If we can't grab the flush lock then check
+			 * to see if the dquot has been flushed delayed
+			 * write.  If so, grab its buffer and send it
+			 * out immediately.  We'll be able to acquire
+			 * the flush lock when the I/O completes.
+			 */
+			xfs_qm_dqflock_pushbuf_wait(dqp);
+		}
+		/*
+		 * Let go of the mplist lock. We don't want to hold it
+		 * across a disk write.
+		 */
+		xfs_qm_mplist_unlock(mp);
+		error = xfs_qm_dqflush(dqp, flags);
+		xfs_dqunlock(dqp);
+		if (error)
+			return (error);
+
+		xfs_qm_mplist_lock(mp);
+		if (recl != XFS_QI_MPLRECLAIMS(mp)) {
+			xfs_qm_mplist_unlock(mp);
+			/* XXX restart limit */
+			goto again;
+		}
+	}
+
+	xfs_qm_mplist_unlock(mp);
+	/* return ! busy */
+	return (0);
+}
+/*
+ * Release the group dquot pointers the user dquots may be
+ * carrying around as a hint. mplist is locked on entry and exit.
+ */
+STATIC void
+xfs_qm_detach_gdquots(
+	xfs_mount_t	*mp)
+{
+	xfs_dquot_t	*dqp, *gdqp;
+	int		nrecl;
+
+ again:
+	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+	dqp = XFS_QI_MPLNEXT(mp);
+	while (dqp) {
+		xfs_dqlock(dqp);
+		if ((gdqp = dqp->q_gdquot)) {
+			xfs_dqlock(gdqp);
+			dqp->q_gdquot = NULL;
+		}
+		xfs_dqunlock(dqp);
+
+		if (gdqp) {
+			/*
+			 * Can't hold the mplist lock across a dqput.
+			 * XXXmust convert to marker based iterations here.
+			 */
+			nrecl = XFS_QI_MPLRECLAIMS(mp);
+			xfs_qm_mplist_unlock(mp);
+			xfs_qm_dqput(gdqp);
+
+			xfs_qm_mplist_lock(mp);
+			if (nrecl != XFS_QI_MPLRECLAIMS(mp))
+				goto again;
+		}
+		dqp = dqp->MPL_NEXT;
+	}
+}
+
+/*
+ * Go through all the incore dquots of this file system and take them
+ * off the mplist and hashlist, if the dquot type matches the dqtype
+ * parameter. This is used when turning off quota accounting for
+ * users and/or groups, as well as when the filesystem is unmounting.
+ */
+STATIC int
+xfs_qm_dqpurge_int(
+	xfs_mount_t	*mp,
+	uint		flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
+{
+	xfs_dquot_t	*dqp;
+	uint		dqtype;
+	int		nrecl;
+	xfs_dquot_t	*nextdqp;
+	int		nmisses;
+
+	if (mp->m_quotainfo == NULL)
+		return (0);
+
+	dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
+	dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
+
+	xfs_qm_mplist_lock(mp);
+
+	/*
+	 * In the first pass through all incore dquots of this filesystem,
+	 * we release the group dquot pointers the user dquots may be
+	 * carrying around as a hint. We need to do this irrespective of
+	 * what's being turned off.
+	 */
+	xfs_qm_detach_gdquots(mp);
+
+      again:
+	nmisses = 0;
+	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+	/*
+	 * Try to get rid of all of the unwanted dquots. The idea is to
+	 * get them off mplist and hashlist, but leave them on freelist.
+	 */
+	dqp = XFS_QI_MPLNEXT(mp);
+	while (dqp) {
+		/*
+		 * It's OK to look at the type without taking dqlock here.
+		 * We're holding the mplist lock here, and that's needed for
+		 * a dqreclaim.
+		 */
+		if ((dqp->dq_flags & dqtype) == 0) {
+			dqp = dqp->MPL_NEXT;
+			continue;
+		}
+
+		if (! xfs_qm_dqhashlock_nowait(dqp)) {
+			nrecl = XFS_QI_MPLRECLAIMS(mp);
+			xfs_qm_mplist_unlock(mp);
+			XFS_DQ_HASH_LOCK(dqp->q_hash);
+			xfs_qm_mplist_lock(mp);
+
+			/*
+			 * XXXTheoretically, we can get into a very long
+			 * ping pong game here.
+			 * No one can be adding dquots to the mplist at
+			 * this point, but somebody might be taking things off.
+			 */
+			if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
+				XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+				goto again;
+			}
+		}
+
+		/*
+		 * Take the dquot off the mplist and hashlist. It may remain on
+		 * freelist in INACTIVE state.
+		 */
+		nextdqp = dqp->MPL_NEXT;
+		nmisses += xfs_qm_dqpurge(dqp, flags);
+		dqp = nextdqp;
+	}
+	xfs_qm_mplist_unlock(mp);
+	return nmisses;
+}
+
+int
+xfs_qm_dqpurge_all(
+	xfs_mount_t	*mp,
+	uint		flags)
+{
+	int		ndquots;
+
+	/*
+	 * Purge the dquot cache.
+	 * None of the dquots should really be busy at this point.
+	 */
+	if (mp->m_quotainfo) {
+		while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
+			delay(ndquots * 10);
+		}
+	}
+	return 0;
+}
+
+STATIC int
+xfs_qm_dqattach_one(
+	xfs_inode_t	*ip,
+	xfs_dqid_t	id,
+	uint		type,
+	uint		doalloc,
+	uint		dolock,
+	xfs_dquot_t	*udqhint, /* hint */
+	xfs_dquot_t	**IO_idqpp)
+{
+	xfs_dquot_t	*dqp;
+	int		error;
+
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	error = 0;
+	/*
+	 * See if we already have it in the inode itself. IO_idqpp is
+	 * &i_udquot or &i_gdquot. This made the code look weird, but
+	 * made the logic a lot simpler.
+	 */
+	if ((dqp = *IO_idqpp)) {
+		if (dolock)
+			xfs_dqlock(dqp);
+		xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
+		goto done;
+	}
+
+	/*
+	 * udqhint is the i_udquot field in inode, and is non-NULL only
+	 * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
+	 * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
+	 * the user dquot.
+	 */
+	ASSERT(!udqhint || type == XFS_DQ_GROUP);
+	if (udqhint && !dolock)
+		xfs_dqlock(udqhint);
+
+	/*
+	 * No need to take dqlock to look at the id.
+	 * The ID can't change until it gets reclaimed, and it won't
+	 * be reclaimed as long as we have a ref from inode and we hold
+	 * the ilock.
+	 */
+	if (udqhint &&
+	    (dqp = udqhint->q_gdquot) &&
+	    (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) {
+		ASSERT(XFS_DQ_IS_LOCKED(udqhint));
+		xfs_dqlock(dqp);
+		XFS_DQHOLD(dqp);
+		ASSERT(*IO_idqpp == NULL);
+		*IO_idqpp = dqp;
+		if (!dolock) {
+			xfs_dqunlock(dqp);
+			xfs_dqunlock(udqhint);
+		}
+		goto done;
+	}
+	/*
+	 * We can't hold a dquot lock when we call the dqget code.
+	 * We'll deadlock in no time, because of (not conforming to)
+	 * lock ordering - the inodelock comes before any dquot lock,
+	 * and we may drop and reacquire the ilock in xfs_qm_dqget().
+	 */
+	if (udqhint)
+		xfs_dqunlock(udqhint);
+	/*
+	 * Find the dquot from somewhere. This bumps the
+	 * reference count of dquot and returns it locked.
+	 * This can return ENOENT if dquot didn't exist on
+	 * disk and we didn't ask it to allocate;
+	 * ESRCH if quotas got turned off suddenly.
+	 */
+	if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
+				 doalloc|XFS_QMOPT_DOWARN, &dqp))) {
+		if (udqhint && dolock)
+			xfs_dqlock(udqhint);
+		goto done;
+	}
+
+	xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
+	/*
+	 * dqget may have dropped and re-acquired the ilock, but it guarantees
+	 * that the dquot returned is the one that should go in the inode.
+	 */
+	*IO_idqpp = dqp;
+	ASSERT(dqp);
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	if (! dolock) {
+		xfs_dqunlock(dqp);
+		ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint));
+		goto done;
+	}
+	if (! udqhint)
+		goto done;
+
+	ASSERT(udqhint);
+	ASSERT(dolock);
+	ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	if (! xfs_qm_dqlock_nowait(udqhint)) {
+		xfs_dqunlock(dqp);
+		xfs_dqlock(udqhint);
+		xfs_dqlock(dqp);
+	}
+      done:
+#ifdef QUOTADEBUG
+	if (udqhint) {
+		if (dolock)
+			ASSERT(XFS_DQ_IS_LOCKED(udqhint));
+		else
+			ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
+	}
+	if (! error) {
+		if (dolock)
+			ASSERT(XFS_DQ_IS_LOCKED(dqp));
+		else
+			ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+	}
+#endif
+	return (error);
+}
+
+
+/*
+ * Given a udquot and gdquot, attach a ptr to the group dquot in the
+ * udquot as a hint for future lookups. The idea sounds simple, but the
+ * execution isn't, because the udquot might have a group dquot attached
+ * already and getting rid of that gets us into lock ordering contraints.
+ * The process is complicated more by the fact that the dquots may or may not
+ * be locked on entry.
+ */
+STATIC void
+xfs_qm_dqattach_grouphint(
+	xfs_dquot_t	*udq,
+	xfs_dquot_t	*gdq,
+	uint		locked)
+{
+	xfs_dquot_t	*tmp;
+
+#ifdef QUOTADEBUG
+	if (locked) {
+		ASSERT(XFS_DQ_IS_LOCKED(udq));
+		ASSERT(XFS_DQ_IS_LOCKED(gdq));
+	} else {
+		ASSERT(! XFS_DQ_IS_LOCKED(udq));
+		ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+	}
+#endif
+	if (! locked)
+		xfs_dqlock(udq);
+
+	if ((tmp = udq->q_gdquot)) {
+		if (tmp == gdq) {
+			if (! locked)
+				xfs_dqunlock(udq);
+			return;
+		}
+
+		udq->q_gdquot = NULL;
+		/*
+		 * We can't keep any dqlocks when calling dqrele,
+		 * because the freelist lock comes before dqlocks.
+		 */
+		xfs_dqunlock(udq);
+		if (locked)
+			xfs_dqunlock(gdq);
+		/*
+		 * we took a hard reference once upon a time in dqget,
+		 * so give it back when the udquot no longer points at it
+		 * dqput() does the unlocking of the dquot.
+		 */
+		xfs_qm_dqrele(tmp);
+
+		ASSERT(! XFS_DQ_IS_LOCKED(udq));
+		ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+		xfs_dqlock(udq);
+		xfs_dqlock(gdq);
+
+	} else {
+		ASSERT(XFS_DQ_IS_LOCKED(udq));
+		if (! locked) {
+			ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+			xfs_dqlock(gdq);
+		}
+	}
+
+	ASSERT(XFS_DQ_IS_LOCKED(udq));
+	ASSERT(XFS_DQ_IS_LOCKED(gdq));
+	/*
+	 * Somebody could have attached a gdquot here,
+	 * when we dropped the uqlock. If so, just do nothing.
+	 */
+	if (udq->q_gdquot == NULL) {
+		XFS_DQHOLD(gdq);
+		udq->q_gdquot = gdq;
+	}
+	if (! locked) {
+		xfs_dqunlock(gdq);
+		xfs_dqunlock(udq);
+	}
+}
+
+
+/*
+ * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
+ * in to account.
+ * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
+ * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
+ * much made this code a complete mess, but it has been pretty useful.
+ * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
+ * Inode may get unlocked and relocked in here, and the caller must deal with
+ * the consequences.
+ */
+int
+xfs_qm_dqattach(
+	xfs_inode_t	*ip,
+	uint		flags)
+{
+	xfs_mount_t	*mp = ip->i_mount;
+	uint		nquotas = 0;
+	int		error = 0;
+
+	if ((! XFS_IS_QUOTA_ON(mp)) ||
+	    (! XFS_NOT_DQATTACHED(mp, ip)) ||
+	    (ip->i_ino == mp->m_sb.sb_uquotino) ||
+	    (ip->i_ino == mp->m_sb.sb_gquotino))
+		return (0);
+
+	ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
+	       XFS_ISLOCKED_INODE_EXCL(ip));
+
+	if (! (flags & XFS_QMOPT_ILOCKED))
+		xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+	if (XFS_IS_UQUOTA_ON(mp)) {
+		error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
+						flags & XFS_QMOPT_DQALLOC,
+						flags & XFS_QMOPT_DQLOCK,
+						NULL, &ip->i_udquot);
+		if (error)
+			goto done;
+		nquotas++;
+	}
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+						flags & XFS_QMOPT_DQALLOC,
+						flags & XFS_QMOPT_DQLOCK,
+						ip->i_udquot, &ip->i_gdquot);
+		/*
+		 * Don't worry about the udquot that we may have
+		 * attached above. It'll get detached, if not already.
+		 */
+		if (error)
+			goto done;
+		nquotas++;
+	}
+
+	/*
+	 * Attach this group quota to the user quota as a hint.
+	 * This WON'T, in general, result in a thrash.
+	 */
+	if (nquotas == 2) {
+		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+		ASSERT(ip->i_udquot);
+		ASSERT(ip->i_gdquot);
+
+		/*
+		 * We may or may not have the i_udquot locked at this point,
+		 * but this check is OK since we don't depend on the i_gdquot to
+		 * be accurate 100% all the time. It is just a hint, and this
+		 * will succeed in general.
+		 */
+		if (ip->i_udquot->q_gdquot == ip->i_gdquot)
+			goto done;
+		/*
+		 * Attach i_gdquot to the gdquot hint inside the i_udquot.
+		 */
+		xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
+					 flags & XFS_QMOPT_DQLOCK);
+	}
+
+      done:
+
+#ifdef QUOTADEBUG
+	if (! error) {
+		if (ip->i_udquot) {
+			if (flags & XFS_QMOPT_DQLOCK)
+				ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
+			else
+				ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
+		}
+		if (ip->i_gdquot) {
+			if (flags & XFS_QMOPT_DQLOCK)
+				ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
+			else
+				ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
+		}
+		if (XFS_IS_UQUOTA_ON(mp))
+			ASSERT(ip->i_udquot);
+		if (XFS_IS_GQUOTA_ON(mp))
+			ASSERT(ip->i_gdquot);
+	}
+#endif
+
+	if (! (flags & XFS_QMOPT_ILOCKED))
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+#ifdef QUOTADEBUG
+	else
+		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+#endif
+	return (error);
+}
+
+/*
+ * Release dquots (and their references) if any.
+ * The inode should be locked EXCL except when this's called by
+ * xfs_ireclaim.
+ */
+void
+xfs_qm_dqdetach(
+	xfs_inode_t	*ip)
+{
+	if (!(ip->i_udquot || ip->i_gdquot))
+		return;
+
+	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
+	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
+	if (ip->i_udquot)
+		xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
+	if (ip->i_udquot) {
+		xfs_qm_dqrele(ip->i_udquot);
+		ip->i_udquot = NULL;
+	}
+	if (ip->i_gdquot) {
+		xfs_qm_dqrele(ip->i_gdquot);
+		ip->i_gdquot = NULL;
+	}
+}
+
+/*
+ * This is called by VFS_SYNC and flags arg determines the caller,
+ * and its motives, as done in xfs_sync.
+ *
+ * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
+ * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
+ * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
+ */
+
+int
+xfs_qm_sync(
+	xfs_mount_t	*mp,
+	short		flags)
+{
+	int		recl, restarts;
+	xfs_dquot_t	*dqp;
+	uint		flush_flags;
+	boolean_t	nowait;
+	int		error;
+
+	restarts = 0;
+	/*
+	 * We won't block unless we are asked to.
+	 */
+	nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
+
+  again:
+	xfs_qm_mplist_lock(mp);
+	/*
+	 * dqpurge_all() also takes the mplist lock and iterate thru all dquots
+	 * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
+	 * when we have the mplist lock, we know that dquots will be consistent
+	 * as long as we have it locked.
+	 */
+	if (! XFS_IS_QUOTA_ON(mp)) {
+		xfs_qm_mplist_unlock(mp);
+		return (0);
+	}
+	FOREACH_DQUOT_IN_MP(dqp, mp) {
+		/*
+		 * If this is vfs_sync calling, then skip the dquots that
+		 * don't 'seem' to be dirty. ie. don't acquire dqlock.
+		 * This is very similar to what xfs_sync does with inodes.
+		 */
+		if (flags & SYNC_BDFLUSH) {
+			if (! XFS_DQ_IS_DIRTY(dqp))
+				continue;
+		}
+
+		if (nowait) {
+			/*
+			 * Try to acquire the dquot lock. We are NOT out of
+			 * lock order, but we just don't want to wait for this
+			 * lock, unless somebody wanted us to.
+			 */
+			if (! xfs_qm_dqlock_nowait(dqp))
+				continue;
+		} else {
+			xfs_dqlock(dqp);
+		}
+
+		/*
+		 * Now, find out for sure if this dquot is dirty or not.
+		 */
+		if (! XFS_DQ_IS_DIRTY(dqp)) {
+			xfs_dqunlock(dqp);
+			continue;
+		}
+
+		/* XXX a sentinel would be better */
+		recl = XFS_QI_MPLRECLAIMS(mp);
+		if (! xfs_qm_dqflock_nowait(dqp)) {
+			if (nowait) {
+				xfs_dqunlock(dqp);
+				continue;
+			}
+			/*
+			 * If we can't grab the flush lock then if the caller
+			 * really wanted us to give this our best shot,
+			 * see if we can give a push to the buffer before we wait
+			 * on the flush lock. At this point, we know that
+			 * eventhough the dquot is being flushed,
+			 * it has (new) dirty data.
+			 */
+			xfs_qm_dqflock_pushbuf_wait(dqp);
+		}
+		/*
+		 * Let go of the mplist lock. We don't want to hold it
+		 * across a disk write
+		 */
+		flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
+		xfs_qm_mplist_unlock(mp);
+		xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
+		error = xfs_qm_dqflush(dqp, flush_flags);
+		xfs_dqunlock(dqp);
+		if (error && XFS_FORCED_SHUTDOWN(mp))
+			return(0);	/* Need to prevent umount failure */
+		else if (error)
+			return (error);
+
+		xfs_qm_mplist_lock(mp);
+		if (recl != XFS_QI_MPLRECLAIMS(mp)) {
+			if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
+				break;
+
+			xfs_qm_mplist_unlock(mp);
+			goto again;
+		}
+	}
+
+	xfs_qm_mplist_unlock(mp);
+	return (0);
+}
+
+
+/*
+ * This initializes all the quota information that's kept in the
+ * mount structure
+ */
+int
+xfs_qm_init_quotainfo(
+	xfs_mount_t	*mp)
+{
+	xfs_quotainfo_t *qinf;
+	int		error;
+	xfs_dquot_t	*dqp;
+
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+	/*
+	 * Tell XQM that we exist as soon as possible.
+	 */
+	if ((error = xfs_qm_hold_quotafs_ref(mp))) {
+		return (error);
+	}
+
+	qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
+
+	/*
+	 * See if quotainodes are setup, and if not, allocate them,
+	 * and change the superblock accordingly.
+	 */
+	if ((error = xfs_qm_init_quotainos(mp))) {
+		kmem_free(qinf, sizeof(xfs_quotainfo_t));
+		mp->m_quotainfo = NULL;
+		return (error);
+	}
+
+	spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin");
+	xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
+	qinf->qi_dqreclaims = 0;
+
+	/* mutex used to serialize quotaoffs */
+	mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff");
+
+	/* Precalc some constants */
+	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
+	ASSERT(qinf->qi_dqchunklen);
+	qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
+	do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
+
+	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
+
+	/*
+	 * We try to get the limits from the superuser's limits fields.
+	 * This is quite hacky, but it is standard quota practice.
+	 * We look at the USR dquot with id == 0 first, but if user quotas
+	 * are not enabled we goto the GRP dquot with id == 0.
+	 * We don't really care to keep separate default limits for user
+	 * and group quotas, at least not at this point.
+	 */
+	error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
+			     (XFS_IS_UQUOTA_RUNNING(mp)) ?
+			     XFS_DQ_USER : XFS_DQ_GROUP,
+			     XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
+			     &dqp);
+	if (! error) {
+		/*
+		 * The warnings and timers set the grace period given to
+		 * a user or group before he or she can not perform any
+		 * more writing. If it is zero, a default is used.
+		 */
+		qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ?
+			INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT;
+		qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ?
+			INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT;
+		qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ?
+			INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT;
+		qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ?
+			INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT;
+		qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ?
+			INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT;
+
+		/*
+		 * We sent the XFS_QMOPT_DQSUSER flag to dqget because
+		 * we don't want this dquot cached. We haven't done a
+		 * quotacheck yet, and quotacheck doesn't like incore dquots.
+		 */
+		xfs_qm_dqdestroy(dqp);
+	} else {
+		qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
+		qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
+		qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
+		qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
+		qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
+	}
+
+	return (0);
+}
+
+
+/*
+ * Gets called when unmounting a filesystem or when all quotas get
+ * turned off.
+ * This purges the quota inodes, destroys locks and frees itself.
+ */
+void
+xfs_qm_destroy_quotainfo(
+	xfs_mount_t	*mp)
+{
+	xfs_quotainfo_t *qi;
+
+	qi = mp->m_quotainfo;
+	ASSERT(qi != NULL);
+	ASSERT(xfs_Gqm != NULL);
+
+	/*
+	 * Release the reference that XQM kept, so that we know
+	 * when the XQM structure should be freed. We cannot assume
+	 * that xfs_Gqm is non-null after this point.
+	 */
+	xfs_qm_rele_quotafs_ref(mp);
+
+	spinlock_destroy(&qi->qi_pinlock);
+	xfs_qm_list_destroy(&qi->qi_dqlist);
+
+	if (qi->qi_uquotaip) {
+		XFS_PURGE_INODE(qi->qi_uquotaip);
+		qi->qi_uquotaip = NULL; /* paranoia */
+	}
+	if (qi->qi_gquotaip) {
+		XFS_PURGE_INODE(qi->qi_gquotaip);
+		qi->qi_gquotaip = NULL;
+	}
+	mutex_destroy(&qi->qi_quotaofflock);
+	kmem_free(qi, sizeof(xfs_quotainfo_t));
+	mp->m_quotainfo = NULL;
+}
+
+
+
+/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_list_init(
+	xfs_dqlist_t	*list,
+	char		*str,
+	int		n)
+{
+	mutex_init(&list->qh_lock, MUTEX_DEFAULT, str);
+	list->qh_next = NULL;
+	list->qh_version = 0;
+	list->qh_nelems = 0;
+}
+
+STATIC void
+xfs_qm_list_destroy(
+	xfs_dqlist_t	*list)
+{
+	mutex_destroy(&(list->qh_lock));
+}
+
+
+/*
+ * Stripped down version of dqattach. This doesn't attach, or even look at the
+ * dquots attached to the inode. The rationale is that there won't be any
+ * attached at the time this is called from quotacheck.
+ */
+STATIC int
+xfs_qm_dqget_noattach(
+	xfs_inode_t	*ip,
+	xfs_dquot_t	**O_udqpp,
+	xfs_dquot_t	**O_gdqpp)
+{
+	int		error;
+	xfs_mount_t	*mp;
+	xfs_dquot_t	*udqp, *gdqp;
+
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	mp = ip->i_mount;
+	udqp = NULL;
+	gdqp = NULL;
+
+	if (XFS_IS_UQUOTA_ON(mp)) {
+		ASSERT(ip->i_udquot == NULL);
+		/*
+		 * We want the dquot allocated if it doesn't exist.
+		 */
+		if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
+					 XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
+					 &udqp))) {
+			/*
+			 * Shouldn't be able to turn off quotas here.
+			 */
+			ASSERT(error != ESRCH);
+			ASSERT(error != ENOENT);
+			return (error);
+		}
+		ASSERT(udqp);
+	}
+
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		ASSERT(ip->i_gdquot == NULL);
+		if (udqp)
+			xfs_dqunlock(udqp);
+		if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+					 XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
+					 &gdqp))) {
+			if (udqp)
+				xfs_qm_dqrele(udqp);
+			ASSERT(error != ESRCH);
+			ASSERT(error != ENOENT);
+			return (error);
+		}
+		ASSERT(gdqp);
+
+		/* Reacquire the locks in the right order */
+		if (udqp) {
+			if (! xfs_qm_dqlock_nowait(udqp)) {
+				xfs_dqunlock(gdqp);
+				xfs_dqlock(udqp);
+				xfs_dqlock(gdqp);
+			}
+		}
+	}
+
+	*O_udqpp = udqp;
+	*O_gdqpp = gdqp;
+
+#ifdef QUOTADEBUG
+	if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
+	if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
+#endif
+	return (0);
+}
+
+/*
+ * Create an inode and return with a reference already taken, but unlocked
+ * This is how we create quota inodes
+ */
+STATIC int
+xfs_qm_qino_alloc(
+	xfs_mount_t	*mp,
+	xfs_inode_t	**ip,
+	__int64_t	sbfields,
+	uint		flags)
+{
+	xfs_trans_t	*tp;
+	int		error;
+	unsigned long s;
+	cred_t		zerocr;
+	int		committed;
+
+	tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE);
+	if ((error = xfs_trans_reserve(tp,
+				      XFS_QM_QINOCREATE_SPACE_RES(mp),
+				      XFS_CREATE_LOG_RES(mp), 0,
+				      XFS_TRANS_PERM_LOG_RES,
+				      XFS_CREATE_LOG_COUNT))) {
+		xfs_trans_cancel(tp, 0);
+		return (error);
+	}
+	memset(&zerocr, 0, sizeof(zerocr));
+
+	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
+				   &zerocr, 0, 1, ip, &committed))) {
+		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+				 XFS_TRANS_ABORT);
+		return (error);
+	}
+
+	/*
+	 * Keep an extra reference to this quota inode. This inode is
+	 * locked exclusively and joined to the transaction already.
+	 */
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
+	VN_HOLD(XFS_ITOV((*ip)));
+
+	/*
+	 * Make the changes in the superblock, and log those too.
+	 * sbfields arg may contain fields other than *QUOTINO;
+	 * VERSIONNUM for example.
+	 */
+	s = XFS_SB_LOCK(mp);
+	if (flags & XFS_QMOPT_SBVERSION) {
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+		unsigned oldv = mp->m_sb.sb_versionnum;
+#endif
+		ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb));
+		ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+				   XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
+		       (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+			XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
+
+		XFS_SB_VERSION_ADDQUOTA(&mp->m_sb);
+		mp->m_sb.sb_uquotino = NULLFSINO;
+		mp->m_sb.sb_gquotino = NULLFSINO;
+
+		/* qflags will get updated _after_ quotacheck */
+		mp->m_sb.sb_qflags = 0;
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+		cmn_err(CE_NOTE,
+			"Old superblock version %x, converting to %x.",
+			oldv, mp->m_sb.sb_versionnum);
+#endif
+	}
+	if (flags & XFS_QMOPT_UQUOTA)
+		mp->m_sb.sb_uquotino = (*ip)->i_ino;
+	else
+		mp->m_sb.sb_gquotino = (*ip)->i_ino;
+	XFS_SB_UNLOCK(mp, s);
+	xfs_mod_sb(tp, sbfields);
+
+	if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
+				     NULL))) {
+		xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
+		return (error);
+	}
+	return (0);
+}
+
+
+STATIC int
+xfs_qm_reset_dqcounts(
+	xfs_mount_t	*mp,
+	xfs_buf_t	*bp,
+	xfs_dqid_t	id,
+	uint		type)
+{
+	xfs_disk_dquot_t	*ddq;
+	int			j;
+
+	xfs_buftrace("RESET DQUOTS", bp);
+	/*
+	 * Reset all counters and timers. They'll be
+	 * started afresh by xfs_qm_quotacheck.
+	 */
+#ifdef DEBUG
+	j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
+	do_div(j, sizeof(xfs_dqblk_t));
+	ASSERT(XFS_QM_DQPERBLK(mp) == j);
+#endif
+	ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
+	for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) {
+		/*
+		 * Do a sanity check, and if needed, repair the dqblk. Don't
+		 * output any warnings because it's perfectly possible to
+		 * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
+		 */
+		(void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
+				      "xfs_quotacheck");
+		INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL);
+		INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL);
+		INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
+		INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
+		INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
+		INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
+		INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
+		ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
+	}
+
+	return (0);
+}
+
+STATIC int
+xfs_qm_dqiter_bufs(
+	xfs_mount_t	*mp,
+	xfs_dqid_t	firstid,
+	xfs_fsblock_t	bno,
+	xfs_filblks_t	blkcnt,
+	uint		flags)
+{
+	xfs_buf_t	*bp;
+	int		error;
+	int		notcommitted;
+	int		incr;
+
+	ASSERT(blkcnt > 0);
+	notcommitted = 0;
+	incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
+		XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
+	error = 0;
+
+	/*
+	 * Blkcnt arg can be a very big number, and might even be
+	 * larger than the log itself. So, we have to break it up into
+	 * manageable-sized transactions.
+	 * Note that we don't start a permanent transaction here; we might
+	 * not be able to get a log reservation for the whole thing up front,
+	 * and we don't really care to either, because we just discard
+	 * everything if we were to crash in the middle of this loop.
+	 */
+	while (blkcnt--) {
+		error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
+			      XFS_FSB_TO_DADDR(mp, bno),
+			      (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp);
+		if (error)
+			break;
+
+		(void) xfs_qm_reset_dqcounts(mp, bp, firstid,
+					     flags & XFS_QMOPT_UQUOTA ?
+					     XFS_DQ_USER : XFS_DQ_GROUP);
+		xfs_bdwrite(mp, bp);
+		/*
+		 * goto the next block.
+		 */
+		bno++;
+		firstid += XFS_QM_DQPERBLK(mp);
+	}
+	return (error);
+}
+
+/*
+ * Iterate over all allocated USR/GRP dquots in the system, calling a
+ * caller supplied function for every chunk of dquots that we find.
+ */
+STATIC int
+xfs_qm_dqiterate(
+	xfs_mount_t	*mp,
+	xfs_inode_t	*qip,
+	uint		flags)
+{
+	xfs_bmbt_irec_t		*map;
+	int			i, nmaps;	/* number of map entries */
+	int			error;		/* return value */
+	xfs_fileoff_t		lblkno;
+	xfs_filblks_t		maxlblkcnt;
+	xfs_dqid_t		firstid;
+	xfs_fsblock_t		rablkno;
+	xfs_filblks_t		rablkcnt;
+
+	error = 0;
+	/*
+	 * This looks racey, but we can't keep an inode lock across a
+	 * trans_reserve. But, this gets called during quotacheck, and that
+	 * happens only at mount time which is single threaded.
+	 */
+	if (qip->i_d.di_nblocks == 0)
+		return (0);
+
+	map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
+
+	lblkno = 0;
+	maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET);
+	do {
+		nmaps = XFS_DQITER_MAP_SIZE;
+		/*
+		 * We aren't changing the inode itself. Just changing
+		 * some of its data. No new blocks are added here, and
+		 * the inode is never added to the transaction.
+		 */
+		xfs_ilock(qip, XFS_ILOCK_SHARED);
+		error = xfs_bmapi(NULL, qip, lblkno,
+				  maxlblkcnt - lblkno,
+				  XFS_BMAPI_METADATA,
+				  NULL,
+				  0, map, &nmaps, NULL);
+		xfs_iunlock(qip, XFS_ILOCK_SHARED);
+		if (error)
+			break;
+
+		ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
+		for (i = 0; i < nmaps; i++) {
+			ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
+			ASSERT(map[i].br_blockcount);
+
+
+			lblkno += map[i].br_blockcount;
+
+			if (map[i].br_startblock == HOLESTARTBLOCK)
+				continue;
+
+			firstid = (xfs_dqid_t) map[i].br_startoff *
+				XFS_QM_DQPERBLK(mp);
+			/*
+			 * Do a read-ahead on the next extent.
+			 */
+			if ((i+1 < nmaps) &&
+			    (map[i+1].br_startblock != HOLESTARTBLOCK)) {
+				rablkcnt =  map[i+1].br_blockcount;
+				rablkno = map[i+1].br_startblock;
+				while (rablkcnt--) {
+					xfs_baread(mp->m_ddev_targp,
+					       XFS_FSB_TO_DADDR(mp, rablkno),
+					       (int)XFS_QI_DQCHUNKLEN(mp));
+					rablkno++;
+				}
+			}
+			/*
+			 * Iterate thru all the blks in the extent and
+			 * reset the counters of all the dquots inside them.
+			 */
+			if ((error = xfs_qm_dqiter_bufs(mp,
+						       firstid,
+						       map[i].br_startblock,
+						       map[i].br_blockcount,
+						       flags))) {
+				break;
+			}
+		}
+
+		if (error)
+			break;
+	} while (nmaps > 0);
+
+	kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
+
+	return (error);
+}
+
+/*
+ * Called by dqusage_adjust in doing a quotacheck.
+ * Given the inode, and a dquot (either USR or GRP, doesn't matter),
+ * this updates its incore copy as well as the buffer copy. This is
+ * so that once the quotacheck is done, we can just log all the buffers,
+ * as opposed to logging numerous updates to individual dquots.
+ */
+STATIC void
+xfs_qm_quotacheck_dqadjust(
+	xfs_dquot_t		*dqp,
+	xfs_qcnt_t		nblks,
+	xfs_qcnt_t		rtblks)
+{
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	xfs_dqtrace_entry(dqp, "QCHECK DQADJUST");
+	/*
+	 * Adjust the inode count and the block count to reflect this inode's
+	 * resource usage.
+	 */
+	INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1);
+	dqp->q_res_icount++;
+	if (nblks) {
+		INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks);
+		dqp->q_res_bcount += nblks;
+	}
+	if (rtblks) {
+		INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks);
+		dqp->q_res_rtbcount += rtblks;
+	}
+
+	/*
+	 * Adjust the timers since we just changed usages
+	 */
+	if (! XFS_IS_SUSER_DQUOT(dqp))
+		xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
+
+	dqp->dq_flags |= XFS_DQ_DIRTY;
+}
+
+STATIC int
+xfs_qm_get_rtblks(
+	xfs_inode_t	*ip,
+	xfs_qcnt_t	*O_rtblks)
+{
+	xfs_filblks_t	rtblks;			/* total rt blks */
+	xfs_ifork_t	*ifp;			/* inode fork pointer */
+	xfs_extnum_t	nextents;		/* number of extent entries */
+	xfs_bmbt_rec_t	*base;			/* base of extent array */
+	xfs_bmbt_rec_t	*ep;			/* pointer to an extent entry */
+	int		error;
+
+	ASSERT(XFS_IS_REALTIME_INODE(ip));
+	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+		if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
+			return (error);
+	}
+	rtblks = 0;
+	nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
+	base = &ifp->if_u1.if_extents[0];
+	for (ep = base; ep < &base[nextents]; ep++)
+		rtblks += xfs_bmbt_get_blockcount(ep);
+	*O_rtblks = (xfs_qcnt_t)rtblks;
+	return (0);
+}
+
+/*
+ * callback routine supplied to bulkstat(). Given an inumber, find its
+ * dquots and update them to account for resources taken by that inode.
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_dqusage_adjust(
+	xfs_mount_t	*mp,		/* mount point for filesystem */
+	xfs_trans_t	*tp,		/* transaction pointer - NULL */
+	xfs_ino_t	ino,		/* inode number to get data for */
+	void		*buffer,	/* not used */
+	xfs_daddr_t	bno,		/* starting block of inode cluster */
+	void		*dip,		/* on-disk inode pointer (not used) */
+	int		*res)		/* result code value */
+{
+	xfs_inode_t	*ip;
+	xfs_dquot_t	*udqp, *gdqp;
+	xfs_qcnt_t	nblks, rtblks;
+	int		error;
+
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+	/*
+	 * rootino must have its resources accounted for, not so with the quota
+	 * inodes.
+	 */
+	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+		*res = BULKSTAT_RV_NOTHING;
+		return XFS_ERROR(EINVAL);
+	}
+
+	/*
+	 * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
+	 * interface expects the inode to be exclusively locked because that's
+	 * the case in all other instances. It's OK that we do this because
+	 * quotacheck is done only at mount time.
+	 */
+	if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) {
+		*res = BULKSTAT_RV_NOTHING;
+		return (error);
+	}
+
+	if (ip->i_d.di_mode == 0) {
+		xfs_iput_new(ip, XFS_ILOCK_EXCL);
+		*res = BULKSTAT_RV_NOTHING;
+		return XFS_ERROR(ENOENT);
+	}
+
+	/*
+	 * Obtain the locked dquots. In case of an error (eg. allocation
+	 * fails for ENOSPC), we return the negative of the error number
+	 * to bulkstat, so that it can get propagated to quotacheck() and
+	 * making us disable quotas for the file system.
+	 */
+	if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
+		xfs_iput(ip, XFS_ILOCK_EXCL);
+		*res = BULKSTAT_RV_GIVEUP;
+		return (error);
+	}
+
+	rtblks = 0;
+	if (! XFS_IS_REALTIME_INODE(ip)) {
+		nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
+	} else {
+		/*
+		 * Walk thru the extent list and count the realtime blocks.
+		 */
+		if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
+			xfs_iput(ip, XFS_ILOCK_EXCL);
+			if (udqp)
+				xfs_qm_dqput(udqp);
+			if (gdqp)
+				xfs_qm_dqput(gdqp);
+			*res = BULKSTAT_RV_GIVEUP;
+			return (error);
+		}
+		nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
+	}
+	ASSERT(ip->i_delayed_blks == 0);
+
+	/*
+	 * We can't release the inode while holding its dquot locks.
+	 * The inode can go into inactive and might try to acquire the dquotlocks.
+	 * So, just unlock here and do a vn_rele at the end.
+	 */
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+	/*
+	 * Add the (disk blocks and inode) resources occupied by this
+	 * inode to its dquots. We do this adjustment in the incore dquot,
+	 * and also copy the changes to its buffer.
+	 * We don't care about putting these changes in a transaction
+	 * envelope because if we crash in the middle of a 'quotacheck'
+	 * we have to start from the beginning anyway.
+	 * Once we're done, we'll log all the dquot bufs.
+	 *
+	 * The *QUOTA_ON checks below may look pretty racey, but quotachecks
+	 * and quotaoffs don't race. (Quotachecks happen at mount time only).
+	 */
+	if (XFS_IS_UQUOTA_ON(mp)) {
+		ASSERT(udqp);
+		xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
+		xfs_qm_dqput(udqp);
+	}
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		ASSERT(gdqp);
+		xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
+		xfs_qm_dqput(gdqp);
+	}
+	/*
+	 * Now release the inode. This will send it to 'inactive', and
+	 * possibly even free blocks.
+	 */
+	VN_RELE(XFS_ITOV(ip));
+
+	/*
+	 * Goto next inode.
+	 */
+	*res = BULKSTAT_RV_DIDONE;
+	return (0);
+}
+
+/*
+ * Walk thru all the filesystem inodes and construct a consistent view
+ * of the disk quota world.
+ */
+STATIC int
+xfs_qm_quotacheck(
+	xfs_mount_t	*mp)
+{
+	int		done, count, error;
+	xfs_ino_t	lastino;
+	size_t		structsz;
+	xfs_inode_t	*uip, *gip;
+	uint		flags;
+
+	count = INT_MAX;
+	structsz = 1;
+	lastino = 0;
+	flags = 0;
+
+	ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp));
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+	/*
+	 * There should be no cached dquots. The (simplistic) quotacheck
+	 * algorithm doesn't like that.
+	 */
+	ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0);
+
+	cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
+
+	/*
+	 * First we go thru all the dquots on disk, USR and GRP, and reset
+	 * their counters to zero. We need a clean slate.
+	 * We don't log our changes till later.
+	 */
+	if ((uip = XFS_QI_UQIP(mp))) {
+		if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA)))
+			goto error_return;
+		flags |= XFS_UQUOTA_CHKD;
+	}
+
+	if ((gip = XFS_QI_GQIP(mp))) {
+		if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
+			goto error_return;
+		flags |= XFS_GQUOTA_CHKD;
+	}
+
+	do {
+		/*
+		 * Iterate thru all the inodes in the file system,
+		 * adjusting the corresponding dquot counters in core.
+		 */
+		if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
+				     xfs_qm_dqusage_adjust,
+				     structsz, NULL,
+				     BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
+				     &done)))
+			break;
+
+	} while (! done);
+
+	/*
+	 * We can get this error if we couldn't do a dquot allocation inside
+	 * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
+	 * dirty dquots that might be cached, we just want to get rid of them
+	 * and turn quotaoff. The dquots won't be attached to any of the inodes
+	 * at this point (because we intentionally didn't in dqget_noattach).
+	 */
+	if (error) {
+		xfs_qm_dqpurge_all(mp,
+				   XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
+				   XFS_QMOPT_QUOTAOFF);
+		goto error_return;
+	}
+	/*
+	 * We've made all the changes that we need to make incore.
+	 * Now flush_them down to disk buffers.
+	 */
+	xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI);
+
+	/*
+	 * We didn't log anything, because if we crashed, we'll have to
+	 * start the quotacheck from scratch anyway. However, we must make
+	 * sure that our dquot changes are secure before we put the
+	 * quotacheck'd stamp on the superblock. So, here we do a synchronous
+	 * flush.
+	 */
+	XFS_bflush(mp->m_ddev_targp);
+
+	/*
+	 * If one type of quotas is off, then it will lose its
+	 * quotachecked status, since we won't be doing accounting for
+	 * that type anymore.
+	 */
+	mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
+	mp->m_qflags |= flags;
+
+	XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
+
+ error_return:
+	cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+	return (error);
+}
+
+/*
+ * This is called after the superblock has been read in and we're ready to
+ * iget the quota inodes.
+ */
+STATIC int
+xfs_qm_init_quotainos(
+	xfs_mount_t	*mp)
+{
+	xfs_inode_t	*uip, *gip;
+	int		error;
+	__int64_t	sbflags;
+	uint		flags;
+
+	ASSERT(mp->m_quotainfo);
+	uip = gip = NULL;
+	sbflags = 0;
+	flags = 0;
+
+	/*
+	 * Get the uquota and gquota inodes
+	 */
+	if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
+		if (XFS_IS_UQUOTA_ON(mp) &&
+		    mp->m_sb.sb_uquotino != NULLFSINO) {
+			ASSERT(mp->m_sb.sb_uquotino > 0);
+			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+					     0, &uip, 0)))
+				return XFS_ERROR(error);
+		}
+		if (XFS_IS_GQUOTA_ON(mp) &&
+		    mp->m_sb.sb_gquotino != NULLFSINO) {
+			ASSERT(mp->m_sb.sb_gquotino > 0);
+			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+					     0, &gip, 0))) {
+				if (uip)
+					VN_RELE(XFS_ITOV(uip));
+				return XFS_ERROR(error);
+			}
+		}
+	} else {
+		flags |= XFS_QMOPT_SBVERSION;
+		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+			    XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+	}
+
+	/*
+	 * Create the two inodes, if they don't exist already. The changes
+	 * made above will get added to a transaction and logged in one of
+	 * the qino_alloc calls below.  If the device is readonly,
+	 * temporarily switch to read-write to do this.
+	 */
+	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
+		if ((error = xfs_qm_qino_alloc(mp, &uip,
+					      sbflags | XFS_SB_UQUOTINO,
+					      flags | XFS_QMOPT_UQUOTA)))
+			return XFS_ERROR(error);
+
+		flags &= ~XFS_QMOPT_SBVERSION;
+	}
+	if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
+		if ((error = xfs_qm_qino_alloc(mp, &gip,
+					      sbflags | XFS_SB_GQUOTINO,
+					      flags | XFS_QMOPT_GQUOTA))) {
+			if (uip)
+				VN_RELE(XFS_ITOV(uip));
+
+			return XFS_ERROR(error);
+		}
+	}
+
+	XFS_QI_UQIP(mp) = uip;
+	XFS_QI_GQIP(mp) = gip;
+
+	return (0);
+}
+
+
+/*
+ * Traverse the freelist of dquots and attempt to reclaim a maximum of
+ * 'howmany' dquots. This operation races with dqlookup(), and attempts to
+ * favor the lookup function ...
+ * XXXsup merge this with qm_reclaim_one().
+ */
+STATIC int
+xfs_qm_shake_freelist(
+	int howmany)
+{
+	int		nreclaimed;
+	xfs_dqhash_t	*hash;
+	xfs_dquot_t	*dqp, *nextdqp;
+	int		restarts;
+	int		nflushes;
+
+	if (howmany <= 0)
+		return (0);
+
+	nreclaimed = 0;
+	restarts = 0;
+	nflushes = 0;
+
+#ifdef QUOTADEBUG
+	cmn_err(CE_DEBUG, "Shake free 0x%x", howmany);
+#endif
+	/* lock order is : hashchainlock, freelistlock, mplistlock */
+ tryagain:
+	xfs_qm_freelist_lock(xfs_Gqm);
+
+	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
+	     ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
+	      nreclaimed < howmany); ) {
+		xfs_dqlock(dqp);
+
+		/*
+		 * We are racing with dqlookup here. Naturally we don't
+		 * want to reclaim a dquot that lookup wants.
+		 */
+		if (dqp->dq_flags & XFS_DQ_WANT) {
+			xfs_dqunlock(dqp);
+			xfs_qm_freelist_unlock(xfs_Gqm);
+			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+				return (nreclaimed != howmany);
+			XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+			goto tryagain;
+		}
+
+		/*
+		 * If the dquot is inactive, we are assured that it is
+		 * not on the mplist or the hashlist, and that makes our
+		 * life easier.
+		 */
+		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+			ASSERT(dqp->q_mount == NULL);
+			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+			ASSERT(dqp->HL_PREVP == NULL);
+			ASSERT(dqp->MPL_PREVP == NULL);
+			XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
+			nextdqp = dqp->dq_flnext;
+			goto off_freelist;
+		}
+
+		ASSERT(dqp->MPL_PREVP);
+		/*
+		 * Try to grab the flush lock. If this dquot is in the process of
+		 * getting flushed to disk, we don't want to reclaim it.
+		 */
+		if (! xfs_qm_dqflock_nowait(dqp)) {
+			xfs_dqunlock(dqp);
+			dqp = dqp->dq_flnext;
+			continue;
+		}
+
+		/*
+		 * We have the flush lock so we know that this is not in the
+		 * process of being flushed. So, if this is dirty, flush it
+		 * DELWRI so that we don't get a freelist infested with
+		 * dirty dquots.
+		 */
+		if (XFS_DQ_IS_DIRTY(dqp)) {
+			xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");
+			/*
+			 * We flush it delayed write, so don't bother
+			 * releasing the mplock.
+			 */
+			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
+			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
+			dqp = dqp->dq_flnext;
+			continue;
+		}
+		/*
+		 * We're trying to get the hashlock out of order. This races
+		 * with dqlookup; so, we giveup and goto the next dquot if
+		 * we couldn't get the hashlock. This way, we won't starve
+		 * a dqlookup process that holds the hashlock that is
+		 * waiting for the freelist lock.
+		 */
+		if (! xfs_qm_dqhashlock_nowait(dqp)) {
+			xfs_dqfunlock(dqp);
+			xfs_dqunlock(dqp);
+			dqp = dqp->dq_flnext;
+			continue;
+		}
+		/*
+		 * This races with dquot allocation code as well as dqflush_all
+		 * and reclaim code. So, if we failed to grab the mplist lock,
+		 * giveup everything and start over.
+		 */
+		hash = dqp->q_hash;
+		ASSERT(hash);
+		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
+			/* XXX put a sentinel so that we can come back here */
+			xfs_dqfunlock(dqp);
+			xfs_dqunlock(dqp);
+			XFS_DQ_HASH_UNLOCK(hash);
+			xfs_qm_freelist_unlock(xfs_Gqm);
+			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+				return (nreclaimed != howmany);
+			goto tryagain;
+		}
+		xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
+#ifdef QUOTADEBUG
+		cmn_err(CE_DEBUG, "Shake 0x%p, ID 0x%x\n",
+			dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
+#endif
+		ASSERT(dqp->q_nrefs == 0);
+		nextdqp = dqp->dq_flnext;
+		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
+		XQM_HASHLIST_REMOVE(hash, dqp);
+		xfs_dqfunlock(dqp);
+		xfs_qm_mplist_unlock(dqp->q_mount);
+		XFS_DQ_HASH_UNLOCK(hash);
+
+ off_freelist:
+		XQM_FREELIST_REMOVE(dqp);
+		xfs_dqunlock(dqp);
+		nreclaimed++;
+		XQM_STATS_INC(xqmstats.xs_qm_dqshake_reclaims);
+		xfs_qm_dqdestroy(dqp);
+		dqp = nextdqp;
+	}
+	xfs_qm_freelist_unlock(xfs_Gqm);
+	return (nreclaimed != howmany);
+}
+
+
+/*
+ * The shake manager routine called by shaked() when memory is
+ * running low.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_shake(void)
+{
+	int	ndqused, nfree, n;
+
+	if (!xfs_Gqm)
+		return;
+
+	nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
+	/* incore dquots in all f/s's */
+	ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
+
+	ASSERT(ndqused >= 0);
+
+	if (nfree <= ndqused && nfree < ndquot)
+		return;
+
+	ndqused *= xfs_Gqm->qm_dqfree_ratio;	/* target # of free dquots */
+	n = nfree - ndqused - ndquot;		/* # over target */
+
+	(void) xfs_qm_shake_freelist(MAX(nfree, n));
+}
+
+
+/*
+ * Just pop the least recently used dquot off the freelist and
+ * recycle it. The returned dquot is locked.
+ */
+STATIC xfs_dquot_t *
+xfs_qm_dqreclaim_one(void)
+{
+	xfs_dquot_t	*dqpout;
+	xfs_dquot_t	*dqp;
+	int		restarts;
+	int		nflushes;
+
+	restarts = 0;
+	dqpout = NULL;
+	nflushes = 0;
+
+	/* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
+ startagain:
+	xfs_qm_freelist_lock(xfs_Gqm);
+
+	FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
+		xfs_dqlock(dqp);
+
+		/*
+		 * We are racing with dqlookup here. Naturally we don't
+		 * want to reclaim a dquot that lookup wants. We release the
+		 * freelist lock and start over, so that lookup will grab
+		 * both the dquot and the freelistlock.
+		 */
+		if (dqp->dq_flags & XFS_DQ_WANT) {
+			ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
+			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");
+			xfs_dqunlock(dqp);
+			xfs_qm_freelist_unlock(xfs_Gqm);
+			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+				return (NULL);
+			XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+			goto startagain;
+		}
+
+		/*
+		 * If the dquot is inactive, we are assured that it is
+		 * not on the mplist or the hashlist, and that makes our
+		 * life easier.
+		 */
+		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+			ASSERT(dqp->q_mount == NULL);
+			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+			ASSERT(dqp->HL_PREVP == NULL);
+			ASSERT(dqp->MPL_PREVP == NULL);
+			XQM_FREELIST_REMOVE(dqp);
+			xfs_dqunlock(dqp);
+			dqpout = dqp;
+			XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
+			break;
+		}
+
+		ASSERT(dqp->q_hash);
+		ASSERT(dqp->MPL_PREVP);
+
+		/*
+		 * Try to grab the flush lock. If this dquot is in the process of
+		 * getting flushed to disk, we don't want to reclaim it.
+		 */
+		if (! xfs_qm_dqflock_nowait(dqp)) {
+			xfs_dqunlock(dqp);
+			continue;
+		}
+
+		/*
+		 * We have the flush lock so we know that this is not in the
+		 * process of being flushed. So, if this is dirty, flush it
+		 * DELWRI so that we don't get a freelist infested with
+		 * dirty dquots.
+		 */
+		if (XFS_DQ_IS_DIRTY(dqp)) {
+			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");
+			/*
+			 * We flush it delayed write, so don't bother
+			 * releasing the freelist lock.
+			 */
+			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
+			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
+			continue;
+		}
+
+		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
+			xfs_dqfunlock(dqp);
+			xfs_dqunlock(dqp);
+			continue;
+		}
+
+		if (! xfs_qm_dqhashlock_nowait(dqp))
+			goto mplistunlock;
+
+		ASSERT(dqp->q_nrefs == 0);
+		xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");
+		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
+		XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
+		XQM_FREELIST_REMOVE(dqp);
+		dqpout = dqp;
+		XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+ mplistunlock:
+		xfs_qm_mplist_unlock(dqp->q_mount);
+		xfs_dqfunlock(dqp);
+		xfs_dqunlock(dqp);
+		if (dqpout)
+			break;
+	}
+
+	xfs_qm_freelist_unlock(xfs_Gqm);
+	return (dqpout);
+}
+
+
+/*------------------------------------------------------------------*/
+
+/*
+ * Return a new incore dquot. Depending on the number of
+ * dquots in the system, we either allocate a new one on the kernel heap,
+ * or reclaim a free one.
+ * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
+ * to reclaim an existing one from the freelist.
+ */
+boolean_t
+xfs_qm_dqalloc_incore(
+	xfs_dquot_t **O_dqpp)
+{
+	xfs_dquot_t	*dqp;
+
+	/*
+	 * Check against high water mark to see if we want to pop
+	 * a nincompoop dquot off the freelist.
+	 */
+	if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
+		/*
+		 * Try to recycle a dquot from the freelist.
+		 */
+		if ((dqp = xfs_qm_dqreclaim_one())) {
+			XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
+			/*
+			 * Just zero the core here. The rest will get
+			 * reinitialized by caller. XXX we shouldn't even
+			 * do this zero ...
+			 */
+			memset(&dqp->q_core, 0, sizeof(dqp->q_core));
+			*O_dqpp = dqp;
+			return (B_FALSE);
+		}
+		XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
+	}
+
+	/*
+	 * Allocate a brand new dquot on the kernel heap and return it
+	 * to the caller to initialize.
+	 */
+	ASSERT(xfs_Gqm->qm_dqzone != NULL);
+	*O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
+	atomic_inc(&xfs_Gqm->qm_totaldquots);
+
+	return (B_TRUE);
+}
+
+
+/*
+ * Start a transaction and write the incore superblock changes to
+ * disk. flags parameter indicates which fields have changed.
+ */
+int
+xfs_qm_write_sb_changes(
+	xfs_mount_t	*mp,
+	__int64_t	flags)
+{
+	xfs_trans_t	*tp;
+	int		error;
+
+#ifdef QUOTADEBUG
+	cmn_err(CE_NOTE, "Writing superblock quota changes :%s", mp->m_fsname);
+#endif
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+	if ((error = xfs_trans_reserve(tp, 0,
+				      mp->m_sb.sb_sectsize + 128, 0,
+				      0,
+				      XFS_DEFAULT_LOG_COUNT))) {
+		xfs_trans_cancel(tp, 0);
+		return (error);
+	}
+
+	xfs_mod_sb(tp, flags);
+	(void) xfs_trans_commit(tp, 0, NULL);
+
+	return (0);
+}
+
+
+/* --------------- utility functions for vnodeops ---------------- */
+
+
+/*
+ * Given an inode, a uid and gid (from cred_t) make sure that we have
+ * allocated relevant dquot(s) on disk, and that we won't exceed inode
+ * quotas by creating this file.
+ * This also attaches dquot(s) to the given inode after locking it,
+ * and returns the dquots corresponding to the uid and/or gid.
+ *
+ * in	: inode (unlocked)
+ * out	: udquot, gdquot with references taken and unlocked
+ */
+int
+xfs_qm_vop_dqalloc(
+	xfs_mount_t	*mp,
+	xfs_inode_t	*ip,
+	uid_t		uid,
+	gid_t		gid,
+	uint		flags,
+	xfs_dquot_t	**O_udqpp,
+	xfs_dquot_t	**O_gdqpp)
+{
+	int		error;
+	xfs_dquot_t	*uq, *gq;
+	uint		lockflags;
+
+	if (!XFS_IS_QUOTA_ON(mp))
+		return 0;
+
+	lockflags = XFS_ILOCK_EXCL;
+	xfs_ilock(ip, lockflags);
+
+	if ((flags & XFS_QMOPT_INHERIT) &&
+	    XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))
+		gid = ip->i_d.di_gid;
+
+	/*
+	 * Attach the dquot(s) to this inode, doing a dquot allocation
+	 * if necessary. The dquot(s) will not be locked.
+	 */
+	if (XFS_NOT_DQATTACHED(mp, ip)) {
+		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
+					    XFS_QMOPT_ILOCKED))) {
+			xfs_iunlock(ip, lockflags);
+			return (error);
+		}
+	}
+
+	uq = gq = NULL;
+	if ((flags & XFS_QMOPT_UQUOTA) &&
+	    XFS_IS_UQUOTA_ON(mp)) {
+		if (ip->i_d.di_uid != uid) {
+			/*
+			 * What we need is the dquot that has this uid, and
+			 * if we send the inode to dqget, the uid of the inode
+			 * takes priority over what's sent in the uid argument.
+			 * We must unlock inode here before calling dqget if
+			 * we're not sending the inode, because otherwise
+			 * we'll deadlock by doing trans_reserve while
+			 * holding ilock.
+			 */
+			xfs_iunlock(ip, lockflags);
+			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
+						 XFS_DQ_USER,
+						 XFS_QMOPT_DQALLOC |
+						 XFS_QMOPT_DOWARN,
+						 &uq))) {
+				ASSERT(error != ENOENT);
+				return (error);
+			}
+			/*
+			 * Get the ilock in the right order.
+			 */
+			xfs_dqunlock(uq);
+			lockflags = XFS_ILOCK_SHARED;
+			xfs_ilock(ip, lockflags);
+		} else {
+			/*
+			 * Take an extra reference, because we'll return
+			 * this to caller
+			 */
+			ASSERT(ip->i_udquot);
+			uq = ip->i_udquot;
+			xfs_dqlock(uq);
+			XFS_DQHOLD(uq);
+			xfs_dqunlock(uq);
+		}
+	}
+	if ((flags & XFS_QMOPT_GQUOTA) &&
+	    XFS_IS_GQUOTA_ON(mp)) {
+		if (ip->i_d.di_gid != gid) {
+			xfs_iunlock(ip, lockflags);
+			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
+						 XFS_DQ_GROUP,
+						 XFS_QMOPT_DQALLOC |
+						 XFS_QMOPT_DOWARN,
+						 &gq))) {
+				if (uq)
+					xfs_qm_dqrele(uq);
+				ASSERT(error != ENOENT);
+				return (error);
+			}
+			xfs_dqunlock(gq);
+			lockflags = XFS_ILOCK_SHARED;
+			xfs_ilock(ip, lockflags);
+		} else {
+			ASSERT(ip->i_gdquot);
+			gq = ip->i_gdquot;
+			xfs_dqlock(gq);
+			XFS_DQHOLD(gq);
+			xfs_dqunlock(gq);
+		}
+	}
+	if (uq)
+		xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
+
+	xfs_iunlock(ip, lockflags);
+	if (O_udqpp)
+		*O_udqpp = uq;
+	else if (uq)
+		xfs_qm_dqrele(uq);
+	if (O_gdqpp)
+		*O_gdqpp = gq;
+	else if (gq)
+		xfs_qm_dqrele(gq);
+	return (0);
+}
+
+/*
+ * Actually transfer ownership, and do dquot modifications.
+ * These were already reserved.
+ */
+xfs_dquot_t *
+xfs_qm_vop_chown(
+	xfs_trans_t	*tp,
+	xfs_inode_t	*ip,
+	xfs_dquot_t	**IO_olddq,
+	xfs_dquot_t	*newdq)
+{
+	xfs_dquot_t	*prevdq;
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
+
+	/* old dquot */
+	prevdq = *IO_olddq;
+	ASSERT(prevdq);
+	ASSERT(prevdq != newdq);
+
+	xfs_trans_mod_dquot(tp, prevdq,
+			    XFS_TRANS_DQ_BCOUNT,
+			    -(ip->i_d.di_nblocks));
+	xfs_trans_mod_dquot(tp, prevdq,
+			    XFS_TRANS_DQ_ICOUNT,
+			    -1);
+
+	/* the sparkling new dquot */
+	xfs_trans_mod_dquot(tp, newdq,
+			    XFS_TRANS_DQ_BCOUNT,
+			    ip->i_d.di_nblocks);
+	xfs_trans_mod_dquot(tp, newdq,
+			    XFS_TRANS_DQ_ICOUNT,
+			    1);
+
+	/*
+	 * Take an extra reference, because the inode
+	 * is going to keep this dquot pointer even
+	 * after the trans_commit.
+	 */
+	xfs_dqlock(newdq);
+	XFS_DQHOLD(newdq);
+	xfs_dqunlock(newdq);
+	*IO_olddq = newdq;
+
+	return (prevdq);
+}
+
+/*
+ * Quota reservations for setattr(AT_UID|AT_GID).
+ */
+int
+xfs_qm_vop_chown_reserve(
+	xfs_trans_t	*tp,
+	xfs_inode_t	*ip,
+	xfs_dquot_t	*udqp,
+	xfs_dquot_t	*gdqp,
+	uint		flags)
+{
+	int		error;
+	xfs_mount_t	*mp;
+	uint		delblks;
+	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
+
+	ASSERT(XFS_ISLOCKED_INODE(ip));
+	mp = ip->i_mount;
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+	delblks = ip->i_delayed_blks;
+	delblksudq = delblksgdq = unresudq = unresgdq = NULL;
+
+	if (XFS_IS_UQUOTA_ON(mp) && udqp &&
+	    ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
+		delblksudq = udqp;
+		/*
+		 * If there are delayed allocation blocks, then we have to
+		 * unreserve those from the old dquot, and add them to the
+		 * new dquot.
+		 */
+		if (delblks) {
+			ASSERT(ip->i_udquot);
+			unresudq = ip->i_udquot;
+		}
+	}
+	if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
+	    ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
+		delblksgdq = gdqp;
+		if (delblks) {
+			ASSERT(ip->i_gdquot);
+			unresgdq = ip->i_gdquot;
+		}
+	}
+
+	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
+				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
+				flags | XFS_QMOPT_RES_REGBLKS)))
+		return (error);
+
+	/*
+	 * Do the delayed blks reservations/unreservations now. Since, these
+	 * are done without the help of a transaction, if a reservation fails
+	 * its previous reservations won't be automatically undone by trans
+	 * code. So, we have to do it manually here.
+	 */
+	if (delblks) {
+		/*
+		 * Do the reservations first. Unreservation can't fail.
+		 */
+		ASSERT(delblksudq || delblksgdq);
+		ASSERT(unresudq || unresgdq);
+		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
+				flags | XFS_QMOPT_RES_REGBLKS)))
+			return (error);
+		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
+				XFS_QMOPT_RES_REGBLKS);
+	}
+
+	return (0);
+}
+
+int
+xfs_qm_vop_rename_dqattach(
+	xfs_inode_t	**i_tab)
+{
+	xfs_inode_t	*ip;
+	int		i;
+	int		error;
+
+	ip = i_tab[0];
+
+	if (! XFS_IS_QUOTA_ON(ip->i_mount))
+		return (0);
+
+	if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+		error = xfs_qm_dqattach(ip, 0);
+		if (error)
+			return (error);
+	}
+	for (i = 1; (i < 4 && i_tab[i]); i++) {
+		/*
+		 * Watch out for duplicate entries in the table.
+		 */
+		if ((ip = i_tab[i]) != i_tab[i-1]) {
+			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+				error = xfs_qm_dqattach(ip, 0);
+				if (error)
+					return (error);
+			}
+		}
+	}
+	return (0);
+}
+
+void
+xfs_qm_vop_dqattach_and_dqmod_newinode(
+	xfs_trans_t	*tp,
+	xfs_inode_t	*ip,
+	xfs_dquot_t	*udqp,
+	xfs_dquot_t	*gdqp)
+{
+	if (!XFS_IS_QUOTA_ON(tp->t_mountp))
+		return;
+
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
+
+	if (udqp) {
+		xfs_dqlock(udqp);
+		XFS_DQHOLD(udqp);
+		xfs_dqunlock(udqp);
+		ASSERT(ip->i_udquot == NULL);
+		ip->i_udquot = udqp;
+		ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT));
+		xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
+	}
+	if (gdqp) {
+		xfs_dqlock(gdqp);
+		XFS_DQHOLD(gdqp);
+		xfs_dqunlock(gdqp);
+		ASSERT(ip->i_gdquot == NULL);
+		ip->i_gdquot = gdqp;
+		ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT));
+		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
+	}
+}
+
+/* ------------- list stuff -----------------*/
+void
+xfs_qm_freelist_init(xfs_frlist_t *ql)
+{
+	ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
+	mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf");
+	ql->qh_version = 0;
+	ql->qh_nelems = 0;
+}
+
+void
+xfs_qm_freelist_destroy(xfs_frlist_t *ql)
+{
+	xfs_dquot_t	*dqp, *nextdqp;
+
+	mutex_lock(&ql->qh_lock, PINOD);
+	for (dqp = ql->qh_next;
+	     dqp != (xfs_dquot_t *)ql; ) {
+		xfs_dqlock(dqp);
+		nextdqp = dqp->dq_flnext;
+#ifdef QUOTADEBUG
+		cmn_err(CE_DEBUG, "FREELIST destroy 0x%p", dqp);
+#endif
+		XQM_FREELIST_REMOVE(dqp);
+		xfs_dqunlock(dqp);
+		xfs_qm_dqdestroy(dqp);
+		dqp = nextdqp;
+	}
+	/*
+	 * Don't bother about unlocking.
+	 */
+	mutex_destroy(&ql->qh_lock);
+
+	ASSERT(ql->qh_nelems == 0);
+}
+
+void
+xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
+{
+	dq->dq_flnext = ql->qh_next;
+	dq->dq_flprev = (xfs_dquot_t *)ql;
+	ql->qh_next = dq;
+	dq->dq_flnext->dq_flprev = dq;
+	xfs_Gqm->qm_dqfreelist.qh_nelems++;
+	xfs_Gqm->qm_dqfreelist.qh_version++;
+}
+
+void
+xfs_qm_freelist_unlink(xfs_dquot_t *dq)
+{
+	xfs_dquot_t *next = dq->dq_flnext;
+	xfs_dquot_t *prev = dq->dq_flprev;
+
+	next->dq_flprev = prev;
+	prev->dq_flnext = next;
+	dq->dq_flnext = dq->dq_flprev = dq;
+	xfs_Gqm->qm_dqfreelist.qh_nelems--;
+	xfs_Gqm->qm_dqfreelist.qh_version++;
+}
+
+void
+xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
+{
+	xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
+}
+
+int
+xfs_qm_dqhashlock_nowait(
+	xfs_dquot_t *dqp)
+{
+	int locked;
+
+	locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
+	return (locked);
+}
+
+int
+xfs_qm_freelist_lock_nowait(
+	xfs_qm_t *xqm)
+{
+	int locked;
+
+	locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
+	return (locked);
+}
+
+int
+xfs_qm_mplist_nowait(
+	xfs_mount_t	*mp)
+{
+	int locked;
+
+	ASSERT(mp->m_quotainfo);
+	locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
+	return (locked);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm.h linux-2.5.66-bk3/fs/xfs/quota/xfs_qm.h
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm.h	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QM_H__
+#define __XFS_QM_H__
+
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
+#include "xfs_quota_priv.h"
+#include "xfs_qm_stats.h"
+
+struct xfs_qm;
+struct xfs_inode;
+
+extern mutex_t		xfs_Gqm_lock;
+extern struct xfs_qm	*xfs_Gqm;
+extern kmem_zone_t	*qm_dqzone;
+extern kmem_zone_t	*qm_dqtrxzone;
+
+/*
+ * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
+ * iterate over the mountpt's dquot list in one call.
+ */
+#define XFS_QM_SYNC_MAX_RESTARTS	7
+
+/*
+ * Ditto, for xfs_qm_dqreclaim_one.
+ */
+#define XFS_QM_RECLAIM_MAX_RESTARTS	4
+
+/*
+ * Ideal ratio of free to in use dquots. Quota manager makes an attempt
+ * to keep this balance.
+ */
+#define XFS_QM_DQFREE_RATIO		2
+
+/*
+ * Dquot hashtable constants/threshold values.
+ */
+#define XFS_QM_NCSIZE_THRESHOLD		5000
+#define XFS_QM_HASHSIZE_LOW		32
+#define XFS_QM_HASHSIZE_HIGH		64
+
+/*
+ * We output a cmn_err when quotachecking a quota file with more than
+ * this many fsbs.
+ */
+#define XFS_QM_BIG_QCHECK_NBLKS		500
+
+/*
+ * This defines the unit of allocation of dquots.
+ * Currently, it is just one file system block, and a 4K blk contains 30
+ * (136 * 30 = 4080) dquots. It's probably not worth trying to make
+ * this more dynamic.
+ * XXXsup However, if this number is changed, we have to make sure that we don't
+ * implicitly assume that we do allocations in chunks of a single filesystem
+ * block in the dquot/xqm code.
+ */
+#define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
+/*
+ * When doing a quotacheck, we log dquot clusters of this many FSBs at most
+ * in a single transaction. We don't want to ask for too huge a log reservation.
+ */
+#define XFS_QM_MAX_DQCLUSTER_LOGSZ	3
+
+typedef xfs_dqhash_t	xfs_dqlist_t;
+/*
+ * The freelist head. The first two fields match the first two in the
+ * xfs_dquot_t structure (in xfs_dqmarker_t)
+ */
+typedef struct xfs_frlist {
+       struct xfs_dquot *qh_next;
+       struct xfs_dquot *qh_prev;
+       mutex_t		 qh_lock;
+       uint		 qh_version;
+       uint		 qh_nelems;
+} xfs_frlist_t;
+
+/*
+ * Quota Manager (global) structure. Lives only in core.
+ */
+typedef struct xfs_qm {
+	xfs_dqlist_t	*qm_usr_dqhtable;/* udquot hash table */
+	xfs_dqlist_t	*qm_grp_dqhtable;/* gdquot hash table */
+	uint		 qm_dqhashmask;	 /* # buckets in dq hashtab - 1 */
+	xfs_frlist_t	 qm_dqfreelist;	 /* freelist of dquots */
+	atomic_t	 qm_totaldquots; /* total incore dquots */
+	uint		 qm_nrefs;	 /* file systems with quota on */
+	int		 qm_dqfree_ratio;/* ratio of free to inuse dquots */
+	kmem_zone_t	*qm_dqzone;	 /* dquot mem-alloc zone */
+	kmem_zone_t	*qm_dqtrxzone;	 /* t_dqinfo of transactions */
+} xfs_qm_t;
+
+/*
+ * Various quota information for individual filesystems.
+ * The mount structure keeps a pointer to this.
+ */
+typedef struct xfs_quotainfo {
+	xfs_inode_t	*qi_uquotaip;	 /* user quota inode */
+	xfs_inode_t	*qi_gquotaip;	 /* group quota inode */
+	lock_t		 qi_pinlock;	 /* dquot pinning mutex */
+	xfs_dqlist_t	 qi_dqlist;	 /* all dquots in filesys */
+	int		 qi_dqreclaims;	 /* a change here indicates
+					    a removal in the dqlist */
+	time_t		 qi_btimelimit;	 /* limit for blks timer */
+	time_t		 qi_itimelimit;	 /* limit for inodes timer */
+	time_t		 qi_rtbtimelimit;/* limit for rt blks timer */
+	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for num warnings */
+	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for num warnings */
+	mutex_t		 qi_quotaofflock;/* to serialize quotaoff */
+	/* Some useful precalculated constants */
+	xfs_filblks_t	 qi_dqchunklen;	 /* # BBs in a chunk of dqs */
+	uint		 qi_dqperchunk;	 /* # ondisk dqs in above chunk */
+} xfs_quotainfo_t;
+
+
+extern xfs_dqtrxops_t	xfs_trans_dquot_ops;
+
+extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
+extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
+			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
+extern void	xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
+extern void	xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
+
+/*
+ * We keep the usr and grp dquots separately so that locking will be easier
+ * to do at commit time. All transactions that we know of at this point
+ * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
+ */
+#define XFS_QM_TRANS_MAXDQS		2
+typedef struct xfs_dquot_acct {
+	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
+	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
+} xfs_dquot_acct_t;
+
+/*
+ * Users are allowed to have a usage exceeding their softlimit for
+ * a period this long.
+ */
+#define XFS_QM_BTIMELIMIT	DQ_BTIMELIMIT
+#define XFS_QM_RTBTIMELIMIT	DQ_BTIMELIMIT
+#define XFS_QM_ITIMELIMIT	DQ_FTIMELIMIT
+
+#define XFS_QM_BWARNLIMIT	5
+#define XFS_QM_IWARNLIMIT	5
+
+#define XFS_QM_LOCK(xqm)	(mutex_lock(&xqm##_lock, PINOD))
+#define XFS_QM_UNLOCK(xqm)	(mutex_unlock(&xqm##_lock))
+#define XFS_QM_HOLD(xqm)	((xqm)->qm_nrefs++)
+#define XFS_QM_RELE(xqm)	((xqm)->qm_nrefs--)
+
+extern int		xfs_qm_init_quotainfo(xfs_mount_t *);
+extern void		xfs_qm_destroy_quotainfo(xfs_mount_t *);
+extern int		xfs_qm_mount_quotas(xfs_mount_t *);
+extern void		xfs_qm_mount_quotainit(xfs_mount_t *, uint);
+extern void		xfs_qm_unmount_quotadestroy(xfs_mount_t *);
+extern int		xfs_qm_unmount_quotas(xfs_mount_t *);
+extern int		xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
+extern int		xfs_qm_sync(xfs_mount_t *, short);
+
+/* dquot stuff */
+extern void		xfs_qm_dqunlink(xfs_dquot_t *);
+extern boolean_t	xfs_qm_dqalloc_incore(xfs_dquot_t **);
+extern int		xfs_qm_dqattach(xfs_inode_t *, uint);
+extern void		xfs_qm_dqdetach(xfs_inode_t *);
+extern int		xfs_qm_dqpurge_all(xfs_mount_t *, uint);
+extern void		xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
+
+/* vop stuff */
+extern int		xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
+					uid_t, gid_t, uint,
+					xfs_dquot_t **, xfs_dquot_t **);
+extern void		xfs_qm_vop_dqattach_and_dqmod_newinode(
+					xfs_trans_t *, xfs_inode_t *,
+					xfs_dquot_t *, xfs_dquot_t *);
+extern int		xfs_qm_vop_rename_dqattach(xfs_inode_t **);
+extern xfs_dquot_t *	xfs_qm_vop_chown(xfs_trans_t *, xfs_inode_t *,
+					xfs_dquot_t **, xfs_dquot_t *);
+extern int		xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
+					xfs_dquot_t *, xfs_dquot_t *, uint);
+
+/* list stuff */
+extern void		xfs_qm_freelist_init(xfs_frlist_t *);
+extern void		xfs_qm_freelist_destroy(xfs_frlist_t *);
+extern void		xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
+extern void		xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
+extern void		xfs_qm_freelist_unlink(xfs_dquot_t *);
+extern int		xfs_qm_freelist_lock_nowait(xfs_qm_t *);
+extern int		xfs_qm_mplist_nowait(xfs_mount_t *);
+extern int		xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
+
+/* system call interface */
+extern int		xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
+
+#ifdef DEBUG
+extern int		xfs_qm_internalqcheck(xfs_mount_t *);
+#else
+#define xfs_qm_internalqcheck(mp)	(0)
+#endif
+
+#endif /* __XFS_QM_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_bhv.c linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_bhv.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_bhv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_bhv.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include <linux/init.h>
+#include "xfs_qm.h"
+
+#define MNTOPT_QUOTA	"quota"		/* disk quotas (user) */
+#define MNTOPT_NOQUOTA	"noquota"	/* no quotas */
+#define MNTOPT_USRQUOTA	"usrquota"	/* user quota enabled */
+#define MNTOPT_GRPQUOTA	"grpquota"	/* group quota enabled */
+#define MNTOPT_UQUOTA	"uquota"	/* user quota (IRIX variant) */
+#define MNTOPT_GQUOTA	"gquota"	/* group quota (IRIX variant) */
+#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
+#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
+#define MNTOPT_QUOTANOENF  "qnoenforce"	/* same as uqnoenforce */
+
+STATIC int
+xfs_qm_parseargs(
+	struct bhv_desc		*bhv,
+	char			*options,
+	struct xfs_mount_args	*args,
+	int			update)
+{
+	size_t			length;
+	char			*local_options = options;
+	char			*this_char;
+	int			error;
+	int			referenced = update;
+
+	while ((this_char = strsep(&local_options, ",")) != NULL) {
+		length = strlen(this_char);
+		if (local_options)
+			length++;
+
+		if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
+			args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
+			args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
+			referenced = update;
+		} else if (!strcmp(this_char, MNTOPT_QUOTA) ||
+			   !strcmp(this_char, MNTOPT_UQUOTA) ||
+			   !strcmp(this_char, MNTOPT_USRQUOTA)) {
+			args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
+			referenced = 1;
+		} else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
+			   !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
+			args->flags |= XFSMNT_UQUOTA;
+			args->flags &= ~XFSMNT_UQUOTAENF;
+			referenced = 1;
+		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
+			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
+			args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
+			referenced = 1;
+		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
+			args->flags |= XFSMNT_GQUOTA;
+			args->flags &= ~XFSMNT_GQUOTAENF;
+			referenced = 1;
+		} else {
+			if (local_options)
+				*(local_options-1) = ',';
+			continue;
+		}
+
+		while (length--)
+			*this_char++ = ',';
+	}
+
+	PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
+	if (!error && !referenced)
+		bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
+	return error;
+}
+
+STATIC int
+xfs_qm_showargs(
+	struct bhv_desc		*bhv,
+	struct seq_file		*m)
+{
+	struct vfs		*vfsp = bhvtovfs(bhv);
+	struct xfs_mount	*mp = XFS_VFSTOM(vfsp);
+	int			error;
+
+	if (mp->m_qflags & XFS_UQUOTA_ACCT) {
+		(mp->m_qflags & XFS_UQUOTA_ENFD) ?
+			seq_puts(m, "," MNTOPT_USRQUOTA) :
+			seq_puts(m, "," MNTOPT_UQUOTANOENF);
+	}
+
+	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+		(mp->m_qflags & XFS_GQUOTA_ENFD) ?
+			seq_puts(m, "," MNTOPT_GRPQUOTA) :
+			seq_puts(m, "," MNTOPT_GQUOTANOENF);
+	}
+
+	if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
+		seq_puts(m, "," MNTOPT_NOQUOTA);
+
+	PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
+	return error;
+}
+
+STATIC int
+xfs_qm_mount(
+	struct bhv_desc		*bhv,
+	struct xfs_mount_args	*args,
+	struct cred		*cr)
+{
+	struct vfs		*vfsp = bhvtovfs(bhv);
+	struct xfs_mount	*mp = XFS_VFSTOM(vfsp);
+	int			error;
+
+	if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
+		xfs_qm_mount_quotainit(mp, args->flags);
+	PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
+	return error;
+}
+
+STATIC int
+xfs_qm_syncall(
+	struct bhv_desc		*bhv,
+	int			flags,
+	cred_t			*credp)
+{
+	struct vfs		*vfsp = bhvtovfs(bhv);
+	struct xfs_mount	*mp = XFS_VFSTOM(vfsp);
+	int			error;
+
+	/*
+	 * Get the Quota Manager to flush the dquots.
+	 */
+	if (XFS_IS_QUOTA_ON(mp)) {
+		if ((error = xfs_qm_sync(mp, flags))) {
+			/*
+			 * If we got an IO error, we will be shutting down.
+			 * So, there's nothing more for us to do here.
+			 */
+			ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
+			if (XFS_FORCED_SHUTDOWN(mp)) {
+				return XFS_ERROR(error);
+			}
+		}
+	}
+	PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
+	return error;
+}
+
+/*
+ * When xfsquotas isn't installed and the superblock had quotas, we need to
+ * clear the quotaflags from superblock.
+ */
+STATIC void
+xfs_mount_reset_sbqflags(
+	xfs_mount_t		*mp)
+{
+	xfs_trans_t		*tp;
+	unsigned long		s;
+
+	mp->m_qflags = 0;
+	/*
+	 * It is OK to look at sb_qflags here in mount path,
+	 * without SB_LOCK.
+	 */
+	if (mp->m_sb.sb_qflags == 0)
+		return;
+	s = XFS_SB_LOCK(mp);
+	mp->m_sb.sb_qflags = 0;
+	XFS_SB_UNLOCK(mp, s);
+
+	/*
+	 * if the fs is readonly, let the incore superblock run
+	 * with quotas off but don't flush the update out to disk
+	 */
+	if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
+		return;
+#ifdef QUOTADEBUG
+	xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+	if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+				      XFS_DEFAULT_LOG_COUNT)) {
+		xfs_trans_cancel(tp, 0);
+		return;
+	}
+	xfs_mod_sb(tp, XFS_SB_QFLAGS);
+	xfs_trans_commit(tp, 0, NULL);
+}
+
+STATIC int
+xfs_qm_newmount(
+	xfs_mount_t	*mp,
+	uint		*needquotamount,
+	uint		*quotaflags)
+{
+	uint		quotaondisk;
+	uint		uquotaondisk = 0, gquotaondisk = 0;
+
+	*quotaflags = 0;
+	*needquotamount = B_FALSE;
+
+	quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+		mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
+
+	if (quotaondisk) {
+		uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
+		gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
+	}
+
+	/*
+	 * If the device itself is read-only, we can't allow
+	 * the user to change the state of quota on the mount -
+	 * this would generate a transaction on the ro device,
+	 * which would lead to an I/O error and shutdown
+	 */
+
+	if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
+	    (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
+	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
+	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
+	    xfs_dev_is_read_only(mp, "changing quota state")) {
+		cmn_err(CE_WARN,
+			"XFS: please mount with%s%s%s.",
+			(!quotaondisk ? "out quota" : ""),
+			(uquotaondisk ? " usrquota" : ""),
+			(gquotaondisk ? " grpquota" : ""));
+		return XFS_ERROR(EPERM);
+	}
+
+	if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
+		/*
+		 * Call mount_quotas at this point only if we won't have to do
+		 * a quotacheck.
+		 */
+		if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
+			/*
+			 * If the xfs quota code isn't installed,
+			 * we have to reset the quotachk'd bit.
+			 * If an error occured, qm_mount_quotas code
+			 * has already disabled quotas. So, just finish
+			 * mounting, and get on with the boring life
+			 * without disk quotas.
+			 */
+			if (xfs_qm_mount_quotas(mp))
+				xfs_mount_reset_sbqflags(mp);
+		} else {
+			/*
+			 * Clear the quota flags, but remember them. This
+			 * is so that the quota code doesn't get invoked
+			 * before we're ready. This can happen when an
+			 * inode goes inactive and wants to free blocks,
+			 * or via xfs_log_mount_finish.
+			 */
+			*needquotamount = B_TRUE;
+			*quotaflags = mp->m_qflags;
+			mp->m_qflags = 0;
+		}
+	}
+
+	return 0;
+}
+
+STATIC int
+xfs_qm_endmount(
+	xfs_mount_t	*mp,
+	uint		needquotamount,
+	uint		quotaflags)
+{
+	if (needquotamount) {
+		ASSERT(mp->m_qflags == 0);
+		mp->m_qflags = quotaflags;
+		if (xfs_qm_mount_quotas(mp))
+			xfs_mount_reset_sbqflags(mp);
+	}
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+	if (! (XFS_IS_QUOTA_ON(mp)))
+		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
+	else
+		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
+#endif
+
+#ifdef QUOTADEBUG
+	if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
+		cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
+#endif
+
+	return 0;
+}
+
+STATIC void
+xfs_qm_dqrele_null(
+	xfs_dquot_t	*dq)
+{
+	/*
+	 * Called from XFS, where we always check first for a NULL dquot.
+	 */
+	if (!dq)
+		return;
+	xfs_qm_dqrele(dq);
+}
+
+
+struct xfs_qmops xfs_qmcore_xfs = {
+	.xfs_qminit		= xfs_qm_newmount,
+	.xfs_qmdone		= xfs_qm_unmount_quotadestroy,
+	.xfs_qmmount		= xfs_qm_endmount,
+	.xfs_qmunmount		= xfs_qm_unmount_quotas,
+	.xfs_dqrele		= xfs_qm_dqrele_null,
+	.xfs_dqattach		= xfs_qm_dqattach,
+	.xfs_dqdetach		= xfs_qm_dqdetach,
+	.xfs_dqpurgeall		= xfs_qm_dqpurge_all,
+	.xfs_dqvopalloc		= xfs_qm_vop_dqalloc,
+	.xfs_dqvopcreate	= xfs_qm_vop_dqattach_and_dqmod_newinode,
+	.xfs_dqvoprename	= xfs_qm_vop_rename_dqattach,
+	.xfs_dqvopchown		= xfs_qm_vop_chown,
+	.xfs_dqvopchownresv	= xfs_qm_vop_chown_reserve,
+	.xfs_dqtrxops		= &xfs_trans_dquot_ops,
+};
+
+struct bhv_vfsops xfs_qmops = { {
+	BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
+	.vfs_parseargs		= xfs_qm_parseargs,
+	.vfs_showargs		= xfs_qm_showargs,
+	.vfs_mount		= xfs_qm_mount,
+	.vfs_sync		= xfs_qm_syncall,
+	.vfs_quotactl		= xfs_qm_quotactl, },
+};
+
+
+void __init
+xfs_qm_init(void)
+{
+	static char	message[] __initdata =
+		KERN_INFO "SGI XFS Quota Management subsystem\n";
+
+	printk(message);
+	mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock");
+	vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs);
+	xfs_qm_init_procfs();
+}
+
+void __exit
+xfs_qm_exit(void)
+{
+	vfs_bhv_clr_custom(&xfs_qmops);
+	xfs_qm_cleanup_procfs();
+	if (qm_dqzone)
+		kmem_cache_destroy(qm_dqzone);
+	if (qm_dqtrxzone)
+		kmem_cache_destroy(qm_dqtrxzone);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_stats.c linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_stats.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_stats.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_stats.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include <linux/proc_fs.h>
+#include "xfs_qm.h"
+
+struct xqmstats xqmstats;
+
+STATIC int
+xfs_qm_read_xfsquota(
+	char		*buffer,
+	char		**start,
+	off_t		offset,
+	int		count,
+	int		*eof,
+	void		*data)
+{
+	int		len;
+
+	/* maximum; incore; ratio free to inuse; freelist */
+	len = sprintf(buffer, "%d\t%d\t%d\t%u\n",
+			ndquot,
+			xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
+			xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
+			xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0);
+
+	if (offset >= len) {
+		*start = buffer;
+		*eof = 1;
+		return 0;
+	}
+	*start = buffer + offset;
+	if ((len -= offset) > count)
+		return count;
+	*eof = 1;
+
+	return len;
+}
+
+STATIC int
+xfs_qm_read_stats(
+	char		*buffer,
+	char		**start,
+	off_t		offset,
+	int		count,
+	int		*eof,
+	void		*data)
+{
+	int		len;
+
+	/* quota performance statistics */
+	len = sprintf(buffer, "qm %u %u %u %u %u %u %u %u\n",
+			xqmstats.xs_qm_dqreclaims,
+			xqmstats.xs_qm_dqreclaim_misses,
+			xqmstats.xs_qm_dquot_dups,
+			xqmstats.xs_qm_dqcachemisses,
+			xqmstats.xs_qm_dqcachehits,
+			xqmstats.xs_qm_dqwants,
+			xqmstats.xs_qm_dqshake_reclaims,
+			xqmstats.xs_qm_dqinact_reclaims);
+
+	if (offset >= len) {
+		*start = buffer;
+		*eof = 1;
+		return 0;
+	}
+	*start = buffer + offset;
+	if ((len -= offset) > count)
+		return count;
+	*eof = 1;
+
+	return len;
+}
+
+void
+xfs_qm_init_procfs(void)
+{
+	create_proc_read_entry("fs/xfs/xqmstat", 0, 0, xfs_qm_read_stats, NULL);
+	create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_qm_read_xfsquota, NULL);
+}
+
+void
+xfs_qm_cleanup_procfs(void)
+{
+	remove_proc_entry("fs/xfs/xqm", NULL);
+	remove_proc_entry("fs/xfs/xqmstat", NULL);
+}
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_stats.h linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_stats.h
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_stats.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_stats.h	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QM_STATS_H__
+#define __XFS_QM_STATS_H__
+
+
+#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
+
+/*
+ * XQM global statistics
+ */
+struct xqmstats {
+	__uint32_t		xs_qm_dqreclaims;
+	__uint32_t		xs_qm_dqreclaim_misses;
+	__uint32_t		xs_qm_dquot_dups;
+	__uint32_t		xs_qm_dqcachemisses;
+	__uint32_t		xs_qm_dqcachehits;
+	__uint32_t		xs_qm_dqwants;
+	__uint32_t		xs_qm_dqshake_reclaims;
+	__uint32_t		xs_qm_dqinact_reclaims;
+};
+
+extern struct xqmstats xqmstats;
+
+# define XQM_STATS_INC(count)	( (count)++ )
+
+extern void xfs_qm_init_procfs(void);
+extern void xfs_qm_cleanup_procfs(void);
+
+#else
+
+# define XQM_STATS_INC(count)	do { } while (0)
+
+static __inline void xfs_qm_init_procfs(void) { };
+static __inline void xfs_qm_cleanup_procfs(void) { };
+
+#endif
+
+#endif	/* __XFS_QM_STATS_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_syscalls.c linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_syscalls.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_qm_syscalls.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_qm_syscalls.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,1410 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+#ifdef DEBUG
+# define qdprintk(s, args...)	cmn_err(CE_DEBUG, s, ## args)
+#else
+# define qdprintk(s, args...)	do { } while (0)
+#endif
+
+STATIC int	xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
+STATIC int	xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
+					fs_disk_quota_t *);
+STATIC int	xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
+STATIC int	xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
+					fs_disk_quota_t *);
+STATIC int	xfs_qm_scall_quotaon(xfs_mount_t *, uint);
+STATIC int	xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
+STATIC int	xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
+STATIC int	xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
+					uint);
+STATIC uint	xfs_qm_import_flags(uint);
+STATIC uint	xfs_qm_export_flags(uint);
+STATIC uint	xfs_qm_import_qtype_flags(uint);
+STATIC uint	xfs_qm_export_qtype_flags(uint);
+STATIC void	xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
+					fs_disk_quota_t *);
+
+
+/*
+ * The main distribution switch of all XFS quotactl system calls.
+ */
+int
+xfs_qm_quotactl(
+	struct bhv_desc *bdp,
+	int		cmd,
+	int		id,
+	xfs_caddr_t	addr)
+{
+	xfs_mount_t	*mp;
+	int 		error;
+	struct vfs	*vfsp;
+
+	vfsp = bhvtovfs(bdp);
+        mp = XFS_VFSTOM(vfsp);
+
+	if (addr == NULL && cmd != Q_SYNC)
+		return XFS_ERROR(EINVAL);
+	if (id < 0 && cmd != Q_SYNC)
+		return XFS_ERROR(EINVAL);
+
+	/*
+	 * The following commands are valid even when quotaoff.
+	 */
+	switch (cmd) {
+	      	/* 
+		 * truncate quota files. quota must be off.
+		 */
+	      case Q_XQUOTARM:
+		if (XFS_IS_QUOTA_ON(mp) || addr == NULL)
+			return XFS_ERROR(EINVAL);
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		return (xfs_qm_scall_trunc_qfiles(mp, 
+			       xfs_qm_import_qtype_flags(*(uint *)addr)));
+		/*
+		 * Get quota status information.
+		 */
+	      case Q_XGETQSTAT:
+		return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
+
+		/*
+		 * QUOTAON for root f/s and quota enforcement on others..
+		 * Quota accounting for non-root f/s's must be turned on
+		 * at mount time.
+		 */
+	      case Q_XQUOTAON:
+		if (addr == NULL)
+			return XFS_ERROR(EINVAL);
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		return (xfs_qm_scall_quotaon(mp,
+					  xfs_qm_import_flags(*(uint *)addr)));
+	      case Q_XQUOTAOFF:
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		break;
+		
+	      default:
+		break;
+	}
+
+	if (! XFS_IS_QUOTA_ON(mp))
+		return XFS_ERROR(ESRCH);
+
+	switch (cmd) {
+	      case Q_XQUOTAOFF:
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		error = xfs_qm_scall_quotaoff(mp,
+					    xfs_qm_import_flags(*(uint *)addr),
+					    B_FALSE);
+		break;
+
+		/* 
+		 * Defaults to XFS_GETUQUOTA. 
+		 */
+	      case Q_XGETQUOTA:
+		error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, 
+					(fs_disk_quota_t *)addr);
+		break;
+		/*
+		 * Set limits, both hard and soft. Defaults to Q_SETUQLIM.
+		 */
+	      case Q_XSETQLIM:
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
+					     (fs_disk_quota_t *)addr);
+		break;
+
+	       case Q_XSETGQLIM:
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			return XFS_ERROR(EROFS);
+		error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
+					     (fs_disk_quota_t *)addr);
+		break;
+
+	      		
+	      case Q_XGETGQUOTA:
+		error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, 
+					(fs_disk_quota_t *)addr);
+		break;
+
+		/*
+		 * Quotas are entirely undefined after quotaoff in XFS quotas.
+		 * For instance, there's no way to set limits when quotaoff.
+		 */
+
+	      default:
+		error = XFS_ERROR(EINVAL);
+		break;
+	}
+
+	return (error);
+}
+
+/*
+ * Turn off quota accounting and/or enforcement for all udquots and/or
+ * gdquots. Called only at unmount time.
+ *
+ * This assumes that there are no dquots of this file system cached
+ * incore, and modifies the ondisk dquot directly. Therefore, for example,
+ * it is an error to call this twice, without purging the cache.
+ */
+STATIC int
+xfs_qm_scall_quotaoff(
+	xfs_mount_t		*mp,
+	uint			flags,
+	boolean_t		force)
+{
+	uint			dqtype;
+	unsigned long	s;
+	int			error;
+	uint			inactivate_flags;
+	xfs_qoff_logitem_t	*qoffstart;
+	int			nculprits;
+
+	if (!force && !capable(CAP_SYS_ADMIN))
+		return XFS_ERROR(EPERM);
+	/*
+	 * No file system can have quotas enabled on disk but not in core.
+	 * Note that quota utilities (like quotaoff) _expect_
+	 * errno == EEXIST here.
+	 */
+	if ((mp->m_qflags & flags) == 0)
+		return XFS_ERROR(EEXIST);
+	error = 0;
+
+	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
+
+	/*
+	 * We don't want to deal with two quotaoffs messing up each other,
+	 * so we're going to serialize it. quotaoff isn't exactly a performance
+	 * critical thing.
+	 * If quotaoff, then we must be dealing with the root filesystem.
+	 */
+	ASSERT(mp->m_quotainfo);
+	if (mp->m_quotainfo)
+		mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+
+	ASSERT(mp->m_quotainfo);
+
+	/*
+	 * If we're just turning off quota enforcement, change mp and go.
+	 */
+	if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
+		mp->m_qflags &= ~(flags);
+
+		s = XFS_SB_LOCK(mp);
+		mp->m_sb.sb_qflags = mp->m_qflags;
+		XFS_SB_UNLOCK(mp, s);
+		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+		/* XXX what to do if error ? Revert back to old vals incore ? */
+		error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
+		return (error);
+	}
+
+	dqtype = 0;
+	inactivate_flags = 0;
+	/*
+	 * If accounting is off, we must turn enforcement off, clear the
+	 * quota 'CHKD' certificate to make it known that we have to
+	 * do a quotacheck the next time this quota is turned on.
+	 */
+	if (flags & XFS_UQUOTA_ACCT) {
+		dqtype |= XFS_QMOPT_UQUOTA;
+		flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
+		inactivate_flags |= XFS_UQUOTA_ACTIVE;
+	}
+	if (flags & XFS_GQUOTA_ACCT) {
+		dqtype |= XFS_QMOPT_GQUOTA;
+		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
+		inactivate_flags |= XFS_GQUOTA_ACTIVE;
+	}
+
+	/*
+	 * Nothing to do?  Don't complain. This happens when we're just
+	 * turning off quota enforcement.
+	 */
+	if ((mp->m_qflags & flags) == 0) {
+		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+		return (0);
+	}
+
+	/*
+	 * Write the LI_QUOTAOFF log record, and do SB changes atomically,
+	 * and synchronously.
+	 */
+	xfs_qm_log_quotaoff(mp, &qoffstart, flags);
+
+	/*
+	 * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
+	 * to take care of the race between dqget and quotaoff. We don't take
+	 * any special locks to reset these bits. All processes need to check
+	 * these bits *after* taking inode lock(s) to see if the particular
+	 * quota type is in the process of being turned off. If *ACTIVE, it is
+	 * guaranteed that all dquot structures and all quotainode ptrs will all
+	 * stay valid as long as that inode is kept locked.
+	 *
+	 * There is no turning back after this.
+	 */
+	mp->m_qflags &= ~inactivate_flags;
+
+	/*
+	 * Give back all the dquot reference(s) held by inodes.
+	 * Here we go thru every single incore inode in this file system, and
+	 * do a dqrele on the i_udquot/i_gdquot that it may have.
+	 * Essentially, as long as somebody has an inode locked, this guarantees
+	 * that quotas will not be turned off. This is handy because in a
+	 * transaction once we lock the inode(s) and check for quotaon, we can
+	 * depend on the quota inodes (and other things) being valid as long as
+	 * we keep the lock(s).
+	 */
+	xfs_qm_dqrele_all_inodes(mp, flags);
+
+	/*
+	 * Next we make the changes in the quota flag in the mount struct.
+	 * This isn't protected by a particular lock directly, because we
+	 * don't want to take a mrlock everytime we depend on quotas being on.
+	 */
+	mp->m_qflags &= ~(flags);
+
+	/*
+	 * Go through all the dquots of this file system and purge them,
+	 * according to what was turned off. We may not be able to get rid
+	 * of all dquots, because dquots can have temporary references that
+	 * are not attached to inodes. eg. xfs_setattr, xfs_create.
+	 * So, if we couldn't purge all the dquots from the filesystem,
+	 * we can't get rid of the incore data structures.
+	 */
+	while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
+		delay(10 * nculprits);
+
+	/*
+	 * Transactions that had started before ACTIVE state bit was cleared
+	 * could have logged many dquots, so they'd have higher LSNs than
+	 * the first QUOTAOFF log record does. If we happen to crash when
+	 * the tail of the log has gone past the QUOTAOFF record, but
+	 * before the last dquot modification, those dquots __will__
+	 * recover, and that's not good.
+	 *
+	 * So, we have QUOTAOFF start and end logitems; the start
+	 * logitem won't get overwritten until the end logitem appears...
+	 */
+	xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
+
+	/*
+	 * If quotas is completely disabled, close shop.
+	 */
+	if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
+		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+		xfs_qm_destroy_quotainfo(mp);
+		return (0);
+	}
+
+	/*
+	 * Release our quotainode references, and vn_purge them,
+	 * if we don't need them anymore.
+	 */
+	if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
+		XFS_PURGE_INODE(XFS_QI_UQIP(mp));
+		XFS_QI_UQIP(mp) = NULL;
+	}
+	if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
+		XFS_PURGE_INODE(XFS_QI_GQIP(mp));
+		XFS_QI_GQIP(mp) = NULL;
+	}
+	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+	return (error);
+}
+
+STATIC int
+xfs_qm_scall_trunc_qfiles(
+	xfs_mount_t	*mp,
+	uint		flags)
+{
+	int		error;
+	xfs_inode_t	*qip;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return XFS_ERROR(EPERM);
+	error = 0;
+	if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) {
+		qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
+		return XFS_ERROR(EINVAL);
+	}
+
+	if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
+		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
+		if (! error) {
+			(void) xfs_truncate_file(mp, qip);
+			VN_RELE(XFS_ITOV(qip));
+		}
+	}
+
+	if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
+		error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
+		if (! error) {
+			(void) xfs_truncate_file(mp, qip);
+			VN_RELE(XFS_ITOV(qip));
+		}
+	}
+
+	return (error);
+}
+
+
+/*
+ * Switch on (a given) quota enforcement for a filesystem.  This takes
+ * effect immediately.
+ * (Switching on quota accounting must be done at mount time.)
+ */
+STATIC int
+xfs_qm_scall_quotaon(
+	xfs_mount_t	*mp,
+	uint		flags)
+{
+	int		error;
+	unsigned long s;
+	uint		qf;
+	uint		accflags;
+	__int64_t	sbflags;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return XFS_ERROR(EPERM);
+
+	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
+	/*
+	 * Switching on quota accounting must be done at mount time.
+	 */
+	accflags = flags & XFS_ALL_QUOTA_ACCT;
+	flags &= ~(XFS_ALL_QUOTA_ACCT);
+
+	sbflags = 0;
+
+	if (flags == 0) {
+		qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
+		return XFS_ERROR(EINVAL);
+	}
+
+	/* No fs can turn on quotas with a delayed effect */
+	ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
+
+	/*
+	 * Can't enforce without accounting. We check the superblock
+	 * qflags here instead of m_qflags because rootfs can have
+	 * quota acct on ondisk without m_qflags' knowing.
+	 */
+	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
+	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
+	    (flags & XFS_UQUOTA_ENFD))
+	    ||
+	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
+	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
+	    (flags & XFS_GQUOTA_ENFD))) {
+		qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
+			flags, mp->m_sb.sb_qflags);
+		return XFS_ERROR(EINVAL);
+	}
+	/*
+	 * If everything's upto-date incore, then don't waste time.
+	 */
+	if ((mp->m_qflags & flags) == flags)
+		return XFS_ERROR(EEXIST);
+
+	/*
+	 * Change sb_qflags on disk but not incore mp->qflags
+	 * if this is the root filesystem.
+	 */
+	s = XFS_SB_LOCK(mp);
+	qf = mp->m_sb.sb_qflags;
+	mp->m_sb.sb_qflags = qf | flags;
+	XFS_SB_UNLOCK(mp, s);
+
+	/*
+	 * There's nothing to change if it's the same.
+	 */
+	if ((qf & flags) == flags && sbflags == 0)
+		return XFS_ERROR(EEXIST);
+	sbflags |= XFS_SB_QFLAGS;
+
+	if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
+		return (error);
+	/*
+	 * If we aren't trying to switch on quota enforcement, we are done.
+	 */
+	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
+	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
+	    (flags & XFS_ALL_QUOTA_ENFD) == 0)
+		return (0);
+
+	if (! XFS_IS_QUOTA_RUNNING(mp))
+		return XFS_ERROR(ESRCH);
+
+	/*
+	 * Switch on quota enforcement in core.
+	 */
+	mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
+	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+	return (0);
+}
+
+
+
+/*
+ * Return quota status information, such as uquota-off, enforcements, etc.
+ */
+STATIC int
+xfs_qm_scall_getqstat(
+	xfs_mount_t	*mp,
+	fs_quota_stat_t *out)
+{
+	xfs_inode_t	*uip, *gip;
+	boolean_t	tempuqip, tempgqip;
+
+	uip = gip = NULL;
+	tempuqip = tempgqip = B_FALSE;
+	memset(out, 0, sizeof(fs_quota_stat_t));
+
+	out->qs_version = FS_QSTAT_VERSION;
+	if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
+		out->qs_uquota.qfs_ino = NULLFSINO;
+		out->qs_gquota.qfs_ino = NULLFSINO;
+		return (0);
+	}
+	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
+							(XFS_ALL_QUOTA_ACCT|
+							 XFS_ALL_QUOTA_ENFD));
+	out->qs_pad = 0;
+	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
+	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+
+	if (mp->m_quotainfo) {
+		uip = mp->m_quotainfo->qi_uquotaip;
+		gip = mp->m_quotainfo->qi_gquotaip;
+	}
+	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
+		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
+			tempuqip = B_TRUE;
+	}
+	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
+		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
+			tempgqip = B_TRUE;
+	}
+	if (uip) {
+		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
+		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
+		if (tempuqip)
+			VN_RELE(XFS_ITOV(uip));
+	}
+	if (gip) {
+		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
+		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
+		if (tempgqip)
+			VN_RELE(XFS_ITOV(gip));
+	}
+	if (mp->m_quotainfo) {
+		out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
+		out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
+		out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
+		out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
+		out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
+		out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
+	}
+	return (0);
+}
+
+/*
+ * Adjust quota limits, and start/stop timers accordingly.
+ */
+STATIC int
+xfs_qm_scall_setqlim(
+	xfs_mount_t		*mp,
+	xfs_dqid_t		id,
+	uint			type,
+	fs_disk_quota_t		*newlim)
+{
+	xfs_disk_dquot_t	*ddq;
+	xfs_dquot_t		*dqp;
+	xfs_trans_t		*tp;
+	int			error;
+	xfs_qcnt_t		hard, soft;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return XFS_ERROR(EPERM);
+
+	if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
+		return (0);
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
+	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
+				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
+		xfs_trans_cancel(tp, 0);
+		return (error);
+	}
+
+	/*
+	 * We don't want to race with a quotaoff so take the quotaoff lock.
+	 * (We don't hold an inode lock, so there's nothing else to stop
+	 * a quotaoff from happening). (XXXThis doesn't currently happen
+	 * because we take the vfslock before calling xfs_qm_sysent).
+	 */
+	mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+
+	/*
+	 * Get the dquot (locked), and join it to the transaction.
+	 * Allocate the dquot if this doesn't exist.
+	 */
+	if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
+		xfs_trans_cancel(tp, XFS_TRANS_ABORT);
+		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+		ASSERT(error != ENOENT);
+		return (error);
+	}
+	xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET");
+	xfs_trans_dqjoin(tp, dqp);
+	ddq = &dqp->q_core;
+
+	/*
+	 * Make sure that hardlimits are >= soft limits before changing.
+	 */
+	hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
+		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
+			INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT);
+	soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
+		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
+			INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT);
+	if (hard == 0 || hard >= soft) {
+		INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
+		INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
+	}
+	else {
+		qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
+	}
+	hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
+		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
+			INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT);
+	soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
+		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
+			INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT);
+	if (hard == 0 || hard >= soft) {
+		INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
+		INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
+	}
+	else
+		qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
+
+	hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
+		(xfs_qcnt_t) newlim->d_ino_hardlimit :
+		INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT);
+	soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
+		(xfs_qcnt_t) newlim->d_ino_softlimit :
+		INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT);
+	if (hard == 0 || hard >= soft) {
+		INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
+		INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
+	}
+	else
+		qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
+
+	if (id == 0) {
+		/*
+		 * Timelimits for the super user set the relative time
+		 * the other users can be over quota for this file system.
+		 * If it is zero a default is used.
+		 */
+		if (newlim->d_fieldmask & FS_DQ_BTIMER) {
+			mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
+			INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer);
+		}
+		if (newlim->d_fieldmask & FS_DQ_ITIMER) {
+			mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
+			INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer);
+		}
+		if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
+			mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
+			INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
+		}
+	} else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
+		/*
+		 * If the user is now over quota, start the timelimit.
+		 * The user will not be 'warned'.
+		 * Note that we keep the timers ticking, whether enforcement
+		 * is on or off. We don't really want to bother with iterating
+		 * over all ondisk dquots and turning the timers on/off.
+		 */
+		xfs_qm_adjust_dqtimers(mp, ddq);
+	}
+	dqp->dq_flags |= XFS_DQ_DIRTY;
+	xfs_trans_log_dquot(tp, dqp);
+
+	xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
+	xfs_trans_commit(tp, 0, NULL);
+	xfs_qm_dqprint(dqp);
+	xfs_qm_dqrele(dqp);
+	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+	return (0);
+}
+
+STATIC int
+xfs_qm_scall_getquota(
+	xfs_mount_t	*mp,
+	xfs_dqid_t	id,
+	uint		type,
+	fs_disk_quota_t *out)
+{
+	xfs_dquot_t	*dqp;
+	int		error;
+
+	/*
+	 * Try to get the dquot. We don't want it allocated on disk, so
+	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
+	 * exist, we'll get ENOENT back.
+	 */
+	if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
+		return (error);
+	}
+
+	xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS");
+	/*
+	 * If everything's NULL, this dquot doesn't quite exist as far as
+	 * our utility programs are concerned.
+	 */
+	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+		xfs_qm_dqput(dqp);
+		return XFS_ERROR(ENOENT);
+	}
+	/* xfs_qm_dqprint(dqp); */
+	/*
+	 * Convert the disk dquot to the exportable format
+	 */
+	xfs_qm_export_dquot(mp, &dqp->q_core, out);
+	xfs_qm_dqput(dqp);
+	return (error ? XFS_ERROR(EFAULT) : 0);
+}
+
+
+STATIC int
+xfs_qm_log_quotaoff_end(
+	xfs_mount_t		*mp,
+	xfs_qoff_logitem_t	*startqoff,
+	uint			flags)
+{
+	xfs_trans_t	       *tp;
+	int			error;
+	xfs_qoff_logitem_t     *qoffi;
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
+
+	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
+				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
+		xfs_trans_cancel(tp, 0);
+		return (error);
+	}
+
+	qoffi = xfs_trans_get_qoff_item(tp, startqoff,
+					flags & XFS_ALL_QUOTA_ACCT);
+	xfs_trans_log_quotaoff_item(tp, qoffi);
+
+	/*
+	 * We have to make sure that the transaction is secure on disk before we
+	 * return and actually stop quota accounting. So, make it synchronous.
+	 * We don't care about quotoff's performance.
+	 */
+	xfs_trans_set_sync(tp);
+	error = xfs_trans_commit(tp, 0, NULL);
+	return (error);
+}
+
+
+STATIC int
+xfs_qm_log_quotaoff(
+	xfs_mount_t	       *mp,
+	xfs_qoff_logitem_t     **qoffstartp,
+	uint		       flags)
+{
+	xfs_trans_t	       *tp;
+	int			error;
+	unsigned long	s;
+	xfs_qoff_logitem_t     *qoffi=NULL;
+	uint			oldsbqflag=0;
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
+	if ((error = xfs_trans_reserve(tp, 0,
+				      sizeof(xfs_qoff_logitem_t) * 2 +
+				      mp->m_sb.sb_sectsize + 128,
+				      0,
+				      0,
+				      XFS_DEFAULT_LOG_COUNT))) {
+		goto error0;
+	}
+
+	qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
+	xfs_trans_log_quotaoff_item(tp, qoffi);
+
+	s = XFS_SB_LOCK(mp);
+	oldsbqflag = mp->m_sb.sb_qflags;
+	mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
+	XFS_SB_UNLOCK(mp, s);
+
+	xfs_mod_sb(tp, XFS_SB_QFLAGS);
+
+	/*
+	 * We have to make sure that the transaction is secure on disk before we
+	 * return and actually stop quota accounting. So, make it synchronous.
+	 * We don't care about quotoff's performance.
+	 */
+	xfs_trans_set_sync(tp);
+	error = xfs_trans_commit(tp, 0, NULL);
+
+error0:
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		/*
+		 * No one else is modifying sb_qflags, so this is OK.
+		 * We still hold the quotaofflock.
+		 */
+		s = XFS_SB_LOCK(mp);
+		mp->m_sb.sb_qflags = oldsbqflag;
+		XFS_SB_UNLOCK(mp, s);
+	}
+	*qoffstartp = qoffi;
+	return (error);
+}
+
+
+/*
+ * Translate an internal style on-disk-dquot to the exportable format.
+ * The main differences are that the counters/limits are all in Basic
+ * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
+ * to be converted to the native endianness.
+ */
+STATIC void
+xfs_qm_export_dquot(
+	xfs_mount_t		*mp,
+	xfs_disk_dquot_t	*src,
+	struct fs_disk_quota	*dst)
+{
+	memset(dst, 0, sizeof(*dst));
+	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
+	dst->d_flags =
+		xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
+	dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
+	dst->d_blk_hardlimit = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
+	dst->d_blk_softlimit = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
+	dst->d_ino_hardlimit = (__uint64_t)
+		INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
+	dst->d_ino_softlimit = (__uint64_t)
+		INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
+	dst->d_bcount = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
+	dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
+	dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
+	dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
+	dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
+	dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);
+
+	dst->d_rtb_hardlimit = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
+	dst->d_rtb_softlimit = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
+	dst->d_rtbcount = (__uint64_t)
+		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
+	dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
+	dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);
+
+	/*
+	 * Internally, we don't reset all the timers when quota enforcement
+	 * gets turned off. No need to confuse the userlevel code,
+	 * so return zeroes in that case.
+	 */
+	if (! XFS_IS_QUOTA_ENFORCED(mp)) {
+		dst->d_btimer = 0;
+		dst->d_itimer = 0;
+		dst->d_rtbtimer = 0;
+	}
+
+#ifdef DEBUG
+	if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
+		if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
+		    (dst->d_blk_softlimit > 0)) {
+			ASSERT(dst->d_btimer != 0);
+		}
+		if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
+		    (dst->d_ino_softlimit > 0)) {
+			ASSERT(dst->d_itimer != 0);
+		}
+	}
+#endif
+}
+
+STATIC uint
+xfs_qm_import_qtype_flags(
+	uint uflags)
+{
+	/*
+	 * Can't be both at the same time.
+	 */
+	if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
+	     (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
+	    ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
+		return (0);
+
+	return (uflags & XFS_USER_QUOTA) ?
+		XFS_DQ_USER : XFS_DQ_GROUP;
+}
+
+STATIC uint
+xfs_qm_export_qtype_flags(
+	uint flags)
+{
+	/*
+	 * Can't be both at the same time.
+	 */
+	ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
+		(XFS_GROUP_QUOTA | XFS_USER_QUOTA));
+	ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
+
+	return (flags & XFS_DQ_USER) ?
+		XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+}
+
+STATIC uint
+xfs_qm_import_flags(
+	uint uflags)
+{
+	uint flags = 0;
+
+	if (uflags & XFS_QUOTA_UDQ_ACCT)
+		flags |= XFS_UQUOTA_ACCT;
+	if (uflags & XFS_QUOTA_GDQ_ACCT)
+		flags |= XFS_GQUOTA_ACCT;
+	if (uflags & XFS_QUOTA_UDQ_ENFD)
+		flags |= XFS_UQUOTA_ENFD;
+	if (uflags & XFS_QUOTA_GDQ_ENFD)
+		flags |= XFS_GQUOTA_ENFD;
+	return (flags);
+}
+
+
+STATIC uint
+xfs_qm_export_flags(
+	uint flags)
+{
+	uint uflags;
+
+	uflags = 0;
+	if (flags & XFS_UQUOTA_ACCT)
+		uflags |= XFS_QUOTA_UDQ_ACCT;
+	if (flags & XFS_GQUOTA_ACCT)
+		uflags |= XFS_QUOTA_GDQ_ACCT;
+	if (flags & XFS_UQUOTA_ENFD)
+		uflags |= XFS_QUOTA_UDQ_ENFD;
+	if (flags & XFS_GQUOTA_ENFD)
+		uflags |= XFS_QUOTA_GDQ_ENFD;
+	return (uflags);
+}
+
+
+/*
+ * Go thru all the inodes in the file system, releasing their dquots.
+ * Note that the mount structure gets modified to indicate that quotas are off
+ * AFTER this, in the case of quotaoff. This also gets called from
+ * xfs_rootumount.
+ */
+void
+xfs_qm_dqrele_all_inodes(
+	struct xfs_mount *mp,
+	uint		 flags)
+{
+	vmap_t		vmap;
+	xfs_inode_t	*ip, *topino;
+	uint		ireclaims;
+	vnode_t		*vp;
+	boolean_t	vnode_refd;
+
+	ASSERT(mp->m_quotainfo);
+
+again:
+	XFS_MOUNT_ILOCK(mp);
+	ip = mp->m_inodes;
+	if (ip == NULL) {
+		XFS_MOUNT_IUNLOCK(mp);
+		return;
+	}
+	do {
+		/* Skip markers inserted by xfs_sync */
+		if (ip->i_mount == NULL) {
+			ip = ip->i_mnext;
+			continue;
+		}
+		/* Root inode, rbmip and rsumip have associated blocks */
+		if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
+			ASSERT(ip->i_udquot == NULL);
+			ASSERT(ip->i_gdquot == NULL);
+			ip = ip->i_mnext;
+			continue;
+		}
+		vp = XFS_ITOV_NULL(ip);
+		if (!vp) {
+			ASSERT(ip->i_udquot == NULL);
+			ASSERT(ip->i_gdquot == NULL);
+			ip = ip->i_mnext;
+			continue;
+		}
+		vnode_refd = B_FALSE;
+		if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
+			/*
+			 * Sample vp mapping while holding the mplock, lest
+			 * we come across a non-existent vnode.
+			 */
+			VMAP(vp, vmap);
+			ireclaims = mp->m_ireclaims;
+			topino = mp->m_inodes;
+			XFS_MOUNT_IUNLOCK(mp);
+
+			/* XXX restart limit ? */
+			if ( ! (vp = vn_get(vp, &vmap)))
+				goto again;
+			xfs_ilock(ip, XFS_ILOCK_EXCL);
+			vnode_refd = B_TRUE;
+		} else {
+			ireclaims = mp->m_ireclaims;
+			topino = mp->m_inodes;
+			XFS_MOUNT_IUNLOCK(mp);
+		}
+
+		/*
+		 * We don't keep the mountlock across the dqrele() call,
+		 * since it can take a while..
+		 */
+		if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
+			xfs_qm_dqrele(ip->i_udquot);
+			ip->i_udquot = NULL;
+		}
+		if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+			xfs_qm_dqrele(ip->i_gdquot);
+			ip->i_gdquot = NULL;
+		}
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+		/*
+		 * Wait until we've dropped the ilock and mountlock to
+		 * do the vn_rele. Or be condemned to an eternity in the
+		 * inactive code in hell.
+		 */
+		if (vnode_refd)
+			VN_RELE(vp);
+		XFS_MOUNT_ILOCK(mp);
+		/*
+		 * If an inode was inserted or removed, we gotta
+		 * start over again.
+		 */
+		if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
+			/* XXX use a sentinel */
+			XFS_MOUNT_IUNLOCK(mp);
+			goto again;
+		}
+		ip = ip->i_mnext;
+	} while (ip != mp->m_inodes);
+
+	XFS_MOUNT_IUNLOCK(mp);
+}
+
+/*------------------------------------------------------------------------*/
+#ifdef DEBUG
+/*
+ * This contains all the test functions for XFS disk quotas.
+ * Currently it does a quota accounting check. ie. it walks through
+ * all inodes in the file system, calculating the dquot accounting fields,
+ * and prints out any inconsistencies.
+ */
+xfs_dqhash_t *qmtest_udqtab;
+xfs_dqhash_t *qmtest_gdqtab;
+int	      qmtest_hashmask;
+int	      qmtest_nfails;
+mutex_t	      qcheck_lock;
+
+#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
+				 (__psunsigned_t)(id)) & \
+				(qmtest_hashmask - 1))
+
+#define DQTEST_HASH(mp, id, type)   ((type & XFS_DQ_USER) ? \
+				     (qmtest_udqtab + \
+				      DQTEST_HASHVAL(mp, id)) : \
+				     (qmtest_gdqtab + \
+				      DQTEST_HASHVAL(mp, id)))
+
+#define DQTEST_LIST_PRINT(l, NXT, title) \
+{ \
+	  xfs_dqtest_t	*dqp; int i = 0;\
+	  cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
+	  for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
+	       dqp = (xfs_dqtest_t *)dqp->NXT) { \
+		cmn_err(CE_DEBUG, "  %d\. \"%d (%s)\"  bcnt = %d, icnt = %d", \
+			 ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp),	     \
+			 dqp->d_bcount, dqp->d_icount); } \
+}
+
+typedef struct dqtest {
+	xfs_dqmarker_t	q_lists;
+	xfs_dqhash_t	*q_hash;	/* the hashchain header */
+	xfs_mount_t	*q_mount;	/* filesystem this relates to */
+	xfs_dqid_t	d_id;		/* user id or group id */
+	xfs_qcnt_t	d_bcount;	/* # disk blocks owned by the user */
+	xfs_qcnt_t	d_icount;	/* # inodes owned by the user */
+} xfs_dqtest_t;
+
+STATIC void
+xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
+{
+	xfs_dquot_t *d;
+	if (((d) = (h)->qh_next))
+		(d)->HL_PREVP = &((dqp)->HL_NEXT);
+	(dqp)->HL_NEXT = d;
+	(dqp)->HL_PREVP = &((h)->qh_next);
+	(h)->qh_next = (xfs_dquot_t *)dqp;
+	(h)->qh_version++;
+	(h)->qh_nelems++;
+}
+STATIC void
+xfs_qm_dqtest_print(
+	xfs_dqtest_t	*d)
+{
+	cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
+	cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
+	cmn_err(CE_DEBUG, "---- type     = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP");
+	cmn_err(CE_DEBUG, "---- fs       = 0x%p", d->q_mount);
+	cmn_err(CE_DEBUG, "---- bcount   = %Lu (0x%x)",
+		d->d_bcount, (int)d->d_bcount);
+	cmn_err(CE_DEBUG, "---- icount   = %Lu (0x%x)",
+		d->d_icount, (int)d->d_icount);
+	cmn_err(CE_DEBUG, "---------------------------");
+}
+
+STATIC void
+xfs_qm_dqtest_failed(
+	xfs_dqtest_t	*d,
+	xfs_dquot_t	*dqp,
+	char		*reason,
+	xfs_qcnt_t	a,
+	xfs_qcnt_t	b,
+	int		error)
+{
+	qmtest_nfails++;
+	if (error)
+		cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s",
+		       INT_GET(d->d_id, ARCH_CONVERT), error, reason);
+	else
+		cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]",
+		       INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b);
+	xfs_qm_dqtest_print(d);
+	if (dqp)
+		xfs_qm_dqprint(dqp);
+}
+
+STATIC int
+xfs_dqtest_cmp2(
+	xfs_dqtest_t	*d,
+	xfs_dquot_t	*dqp)
+{
+	int err = 0;
+	if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) {
+		xfs_qm_dqtest_failed(d, dqp, "icount mismatch",
+			INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+			d->d_icount, 0);
+		err++;
+	}
+	if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) {
+		xfs_qm_dqtest_failed(d, dqp, "bcount mismatch",
+			INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+			d->d_bcount, 0);
+		err++;
+	}
+	if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
+	    INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >=
+	    INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
+		if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) &&
+		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+			cmn_err(CE_DEBUG,
+				"%d [%s] [0x%p] BLK TIMER NOT STARTED",
+				d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+			err++;
+		}
+	}
+	if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
+	    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+	    INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
+		if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
+		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+			cmn_err(CE_DEBUG,
+				"%d [%s] [0x%p] INO TIMER NOT STARTED",
+				d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+			err++;
+		}
+	}
+#ifdef QUOTADEBUG
+	if (!err) {
+		cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
+			d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
+	}
+#endif
+	return (err);
+}
+
+STATIC void
+xfs_dqtest_cmp(
+	xfs_dqtest_t	*d)
+{
+	xfs_dquot_t	*dqp;
+	int		error;
+
+	/* xfs_qm_dqtest_print(d); */
+	if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0,
+				 &dqp))) {
+		xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error);
+		return;
+	}
+	xfs_dqtest_cmp2(d, dqp);
+	xfs_qm_dqput(dqp);
+}
+
+STATIC int
+xfs_qm_internalqcheck_dqget(
+	xfs_mount_t	*mp,
+	xfs_dqid_t	id,
+	uint		type,
+	xfs_dqtest_t	**O_dq)
+{
+	xfs_dqtest_t	*d;
+	xfs_dqhash_t	*h;
+
+	h = DQTEST_HASH(mp, id, type);
+	for (d = (xfs_dqtest_t *) h->qh_next; d != NULL;
+	     d = (xfs_dqtest_t *) d->HL_NEXT) {
+		/* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */
+		if (d->d_id == id && mp == d->q_mount) {
+			*O_dq = d;
+			return (0);
+		}
+	}
+	d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP);
+	d->dq_flags = type;
+	d->d_id = id;
+	d->q_mount = mp;
+	d->q_hash = h;
+	xfs_qm_hashinsert(h, d);
+	*O_dq = d;
+	return (0);
+}
+
+STATIC void
+xfs_qm_internalqcheck_get_dquots(
+	xfs_mount_t	*mp,
+	xfs_dqid_t	uid,
+	xfs_dqid_t	gid,
+	xfs_dqtest_t	**ud,
+	xfs_dqtest_t	**gd)
+{
+	if (XFS_IS_UQUOTA_ON(mp))
+		xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
+	if (XFS_IS_GQUOTA_ON(mp))
+		xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
+}
+
+
+STATIC void
+xfs_qm_internalqcheck_dqadjust(
+	xfs_inode_t		*ip,
+	xfs_dqtest_t		*d)
+{
+	d->d_icount++;
+	d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;
+}
+
+STATIC int
+xfs_qm_internalqcheck_adjust(
+	xfs_mount_t	*mp,		/* mount point for filesystem */
+	xfs_trans_t	*tp,		/* transaction pointer */
+	xfs_ino_t	ino,		/* inode number to get data for */
+	void		*buffer,	/* not used */
+	xfs_daddr_t	bno,		/* starting block of inode cluster */
+	void		*dip,		/* not used */
+	int		*res)		/* bulkstat result code */
+{
+	xfs_inode_t		*ip;
+	xfs_dqtest_t		*ud, *gd;
+	uint			lock_flags;
+	boolean_t		ipreleased;
+	int			error;
+
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+		*res = BULKSTAT_RV_NOTHING;
+		qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
+			(unsigned long long) ino,
+			(unsigned long long) mp->m_sb.sb_uquotino,
+			(unsigned long long) mp->m_sb.sb_gquotino);
+		return XFS_ERROR(EINVAL);
+	}
+	ipreleased = B_FALSE;
+ again:
+	lock_flags = XFS_ILOCK_SHARED;
+	if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) {
+		*res = BULKSTAT_RV_NOTHING;
+		return (error);
+	}
+
+	if (ip->i_d.di_mode == 0) {
+		xfs_iput_new(ip, lock_flags);
+		*res = BULKSTAT_RV_NOTHING;
+		return XFS_ERROR(ENOENT);
+	}
+
+	/*
+	 * This inode can have blocks after eof which can get released
+	 * when we send it to inactive. Since we don't check the dquot
+	 * until the after all our calculations are done, we must get rid
+	 * of those now.
+	 */
+	if (! ipreleased) {
+		xfs_iput(ip, lock_flags);
+		ipreleased = B_TRUE;
+		goto again;
+	}
+	xfs_qm_internalqcheck_get_dquots(mp,
+					(xfs_dqid_t) ip->i_d.di_uid,
+					(xfs_dqid_t) ip->i_d.di_gid,
+					&ud, &gd);
+	if (XFS_IS_UQUOTA_ON(mp)) {
+		ASSERT(ud);
+		xfs_qm_internalqcheck_dqadjust(ip, ud);
+	}
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		ASSERT(gd);
+		xfs_qm_internalqcheck_dqadjust(ip, gd);
+	}
+	xfs_iput(ip, lock_flags);
+	*res = BULKSTAT_RV_DIDONE;
+	return (0);
+}
+
+
+/* PRIVATE, debugging */
+int
+xfs_qm_internalqcheck(
+	xfs_mount_t	*mp)
+{
+	xfs_ino_t	lastino;
+	int		done, count;
+	int		i;
+	xfs_dqtest_t	*d, *e;
+	xfs_dqhash_t	*h1;
+	int		error;
+
+	lastino = 0;
+	qmtest_hashmask = 32;
+	count = 5;
+	done = 0;
+	qmtest_nfails = 0;
+
+	if (! XFS_IS_QUOTA_ON(mp))
+		return XFS_ERROR(ESRCH);
+
+	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
+	XFS_bflush(mp->m_ddev_targp);
+	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
+	XFS_bflush(mp->m_ddev_targp);
+
+	mutex_lock(&qcheck_lock, PINOD);
+	/* There should be absolutely no quota activity while this
+	   is going on. */
+	qmtest_udqtab = kmem_zalloc(qmtest_hashmask *
+				    sizeof(xfs_dqhash_t), KM_SLEEP);
+	qmtest_gdqtab = kmem_zalloc(qmtest_hashmask *
+				    sizeof(xfs_dqhash_t), KM_SLEEP);
+	do {
+		/*
+		 * Iterate thru all the inodes in the file system,
+		 * adjusting the corresponding dquot counters
+		 */
+		if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
+				 xfs_qm_internalqcheck_adjust,
+				 0, NULL, BULKSTAT_FG_IGET, &done))) {
+			break;
+		}
+	} while (! done);
+	if (error) {
+		cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
+	}
+	cmn_err(CE_DEBUG, "Checking results against system dquots");
+	for (i = 0; i < qmtest_hashmask; i++) {
+		h1 = &qmtest_udqtab[i];
+		for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
+			xfs_dqtest_cmp(d);
+			e = (xfs_dqtest_t *) d->HL_NEXT;
+			kmem_free(d, sizeof(xfs_dqtest_t));
+			d = e;
+		}
+		h1 = &qmtest_gdqtab[i];
+		for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
+			xfs_dqtest_cmp(d);
+			e = (xfs_dqtest_t *) d->HL_NEXT;
+			kmem_free(d, sizeof(xfs_dqtest_t));
+			d = e;
+		}
+	}
+
+	if (qmtest_nfails) {
+		cmn_err(CE_DEBUG, "******** quotacheck failed  ********");
+		cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails);
+	} else {
+		cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
+	}
+	kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
+	kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
+	mutex_unlock(&qcheck_lock);
+	return (qmtest_nfails);
+}
+
+#endif /* DEBUG */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_quota_priv.h linux-2.5.66-bk3/fs/xfs/quota/xfs_quota_priv.h
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_quota_priv.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_quota_priv.h	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QUOTA_PRIV_H__
+#define __XFS_QUOTA_PRIV_H__
+
+/*
+ * Number of bmaps that we ask from bmapi when doing a quotacheck.
+ * We make this restriction to keep the memory usage to a minimum.
+ */
+#define XFS_DQITER_MAP_SIZE	10
+
+/* Number of dquots that fit in to a dquot block */
+#define XFS_QM_DQPERBLK(mp)	((mp)->m_quotainfo->qi_dqperchunk)
+
+#define XFS_ISLOCKED_INODE(ip)		(ismrlocked(&(ip)->i_lock, \
+					    MR_UPDATE | MR_ACCESS) != 0)
+#define XFS_ISLOCKED_INODE_EXCL(ip)	(ismrlocked(&(ip)->i_lock, \
+					    MR_UPDATE) != 0)
+
+#define XFS_DQ_IS_ADDEDTO_TRX(t, d)	((d)->q_transp == (t))
+
+#define XFS_QI_MPLRECLAIMS(mp)	((mp)->m_quotainfo->qi_dqreclaims)
+#define XFS_QI_UQIP(mp)		((mp)->m_quotainfo->qi_uquotaip)
+#define XFS_QI_GQIP(mp)		((mp)->m_quotainfo->qi_gquotaip)
+#define XFS_QI_DQCHUNKLEN(mp)	((mp)->m_quotainfo->qi_dqchunklen)
+#define XFS_QI_BTIMELIMIT(mp)	((mp)->m_quotainfo->qi_btimelimit)
+#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
+#define XFS_QI_ITIMELIMIT(mp)	((mp)->m_quotainfo->qi_itimelimit)
+#define XFS_QI_BWARNLIMIT(mp)	((mp)->m_quotainfo->qi_bwarnlimit)
+#define XFS_QI_IWARNLIMIT(mp)	((mp)->m_quotainfo->qi_iwarnlimit)
+#define XFS_QI_QOFFLOCK(mp)	((mp)->m_quotainfo->qi_quotaofflock)
+
+#define XFS_QI_MPL_LIST(mp)	((mp)->m_quotainfo->qi_dqlist)
+#define XFS_QI_MPLLOCK(mp)	((mp)->m_quotainfo->qi_dqlist.qh_lock)
+#define XFS_QI_MPLNEXT(mp)	((mp)->m_quotainfo->qi_dqlist.qh_next)
+#define XFS_QI_MPLNDQUOTS(mp)	((mp)->m_quotainfo->qi_dqlist.qh_nelems)
+
+#define XQMLCK(h)			(mutex_lock(&((h)->qh_lock), PINOD))
+#define XQMUNLCK(h)			(mutex_unlock(&((h)->qh_lock)))
+#ifdef DEBUG
+struct xfs_dqhash;
+static inline int XQMISLCKD(struct xfs_dqhash *h)
+{
+	if (mutex_trylock(&h->qh_lock)) {
+		mutex_unlock(&h->qh_lock);
+		return 0;
+	}
+	return 1;
+}
+#endif
+
+#define XFS_DQ_HASH_LOCK(h)		XQMLCK(h)
+#define XFS_DQ_HASH_UNLOCK(h)		XQMUNLCK(h)
+#define XFS_DQ_IS_HASH_LOCKED(h)	XQMISLCKD(h)
+
+#define xfs_qm_mplist_lock(mp)		XQMLCK(&(XFS_QI_MPL_LIST(mp)))
+#define xfs_qm_mplist_unlock(mp)	XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
+#define XFS_QM_IS_MPLIST_LOCKED(mp)	XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
+
+#define xfs_qm_freelist_lock(qm)	XQMLCK(&((qm)->qm_dqfreelist))
+#define xfs_qm_freelist_unlock(qm)	XQMUNLCK(&((qm)->qm_dqfreelist))
+#define XFS_QM_IS_FREELIST_LOCKED(qm)	XQMISLCKD(&((qm)->qm_dqfreelist))
+
+/*
+ * Hash into a bucket in the dquot hash table, based on <mp, id>.
+ */
+#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
+				 (__psunsigned_t)(id)) & \
+				(xfs_Gqm->qm_dqhashmask - 1))
+#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
+				     (xfs_Gqm->qm_usr_dqhtable + \
+				      XFS_DQ_HASHVAL(mp, id)) : \
+				     (xfs_Gqm->qm_grp_dqhtable + \
+				      XFS_DQ_HASHVAL(mp, id)))
+#define XFS_IS_DQTYPE_ON(mp, type)   (type == XFS_DQ_USER ? \
+				      XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
+#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
+	INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \
+	INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT)	      && \
+	INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT)      && \
+	INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT))
+
+#define HL_PREVP	dq_hashlist.ql_prevp
+#define HL_NEXT		dq_hashlist.ql_next
+#define MPL_PREVP	dq_mplist.ql_prevp
+#define MPL_NEXT	dq_mplist.ql_next
+
+
+#define _LIST_REMOVE(h, dqp, PVP, NXT)				\
+	{							\
+		 xfs_dquot_t *d;				\
+		 if (((d) = (dqp)->NXT))				\
+			 (d)->PVP = (dqp)->PVP;			\
+		 *((dqp)->PVP) = d;				\
+		 (dqp)->NXT = NULL;				\
+		 (dqp)->PVP = NULL;				\
+		 (h)->qh_version++;				\
+		 (h)->qh_nelems--;				\
+	}
+
+#define _LIST_INSERT(h, dqp, PVP, NXT)				\
+	{							\
+		 xfs_dquot_t *d;				\
+		 if (((d) = (h)->qh_next))			\
+			 (d)->PVP = &((dqp)->NXT);		\
+		 (dqp)->NXT = d;				\
+		 (dqp)->PVP = &((h)->qh_next);			\
+		 (h)->qh_next = dqp;				\
+		 (h)->qh_version++;				\
+		 (h)->qh_nelems++;				\
+	 }
+
+#define FOREACH_DQUOT_IN_MP(dqp, mp) \
+	for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT)
+
+#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist)	\
+for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
+     (dqp) = (dqp)->dq_flnext)
+
+#define XQM_HASHLIST_INSERT(h, dqp)	\
+	 _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT)
+
+#define XQM_FREELIST_INSERT(h, dqp)	\
+	 xfs_qm_freelist_append(h, dqp)
+
+#define XQM_MPLIST_INSERT(h, dqp)	\
+	 _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT)
+
+#define XQM_HASHLIST_REMOVE(h, dqp)	\
+	 _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT)
+#define XQM_FREELIST_REMOVE(dqp)	\
+	 xfs_qm_freelist_unlink(dqp)
+#define XQM_MPLIST_REMOVE(h, dqp)	\
+	{ _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \
+	  XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; }
+
+#define XFS_DQ_IS_LOGITEM_INITD(dqp)	((dqp)->q_logitem.qli_dquot == (dqp))
+
+#define XFS_QM_DQP_TO_DQACCT(tp, dqp)	(XFS_QM_ISUDQ(dqp) ? \
+					 (tp)->t_dqinfo->dqa_usrdquots : \
+					 (tp)->t_dqinfo->dqa_grpdquots)
+#define XFS_IS_SUSER_DQUOT(dqp)		\
+	(INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT))
+
+#define XFS_PURGE_INODE(ip)		\
+	{				\
+	  vmap_t dqvmap;		\
+	  vnode_t *dqvp;		\
+	  dqvp = XFS_ITOV(ip);		\
+	  VMAP(dqvp, dqvmap);		\
+	  VN_RELE(dqvp);		\
+	}
+
+#define DQFLAGTO_TYPESTR(d)	(((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
+				 (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
+#define DQFLAGTO_DIRTYSTR(d)	(XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
+
+#endif	/* __XFS_QUOTA_PRIV_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/quota/xfs_trans_dquot.c linux-2.5.66-bk3/fs/xfs/quota/xfs_trans_dquot.c
--- linux-2.5.66-bk2/fs/xfs/quota/xfs_trans_dquot.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/quota/xfs_trans_dquot.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+STATIC void	xfs_trans_alloc_dqinfo(xfs_trans_t *);
+
+/*
+ * Add the locked dquot to the transaction.
+ * The dquot must be locked, and it cannot be associated with any
+ * transaction.
+ */
+void
+xfs_trans_dqjoin(
+	xfs_trans_t	*tp,
+	xfs_dquot_t	*dqp)
+{
+	xfs_dq_logitem_t    *lp;
+
+	ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp));
+	lp = &dqp->q_logitem;
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	(void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
+
+	/*
+	 * Initialize i_transp so we can later determine if this dquot is
+	 * associated with this transaction.
+	 */
+	dqp->q_transp = tp;
+}
+
+
+/*
+ * This is called to mark the dquot as needing
+ * to be logged when the transaction is committed.  The dquot must
+ * already be associated with the given transaction.
+ * Note that it marks the entire transaction as dirty. In the ordinary
+ * case, this gets called via xfs_trans_commit, after the transaction
+ * is already dirty. However, there's nothing stop this from getting
+ * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY
+ * flag.
+ */
+void
+xfs_trans_log_dquot(
+	xfs_trans_t	*tp,
+	xfs_dquot_t	*dqp)
+{
+	xfs_log_item_desc_t	*lidp;
+
+	ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+	lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
+	ASSERT(lidp != NULL);
+
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	lidp->lid_flags |= XFS_LID_DIRTY;
+}
+
+/*
+ * Carry forward whatever is left of the quota blk reservation to
+ * the spanky new transaction
+ */
+STATIC void
+xfs_trans_dup_dqinfo(
+	xfs_trans_t	*otp,
+	xfs_trans_t	*ntp)
+{
+	xfs_dqtrx_t	*oq, *nq;
+	int		i,j;
+	xfs_dqtrx_t	*oqa, *nqa;
+
+	if (!otp->t_dqinfo)
+		return;
+
+	xfs_trans_alloc_dqinfo(ntp);
+	oqa = otp->t_dqinfo->dqa_usrdquots;
+	nqa = ntp->t_dqinfo->dqa_usrdquots;
+
+	/*
+	 * Because the quota blk reservation is carried forward,
+	 * it is also necessary to carry forward the DQ_DIRTY flag.
+	 */
+	if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
+		ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
+
+	for (j = 0; j < 2; j++) {
+		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+			if (oqa[i].qt_dquot == NULL)
+				break;
+			oq = &oqa[i];
+			nq = &nqa[i];
+
+			nq->qt_dquot = oq->qt_dquot;
+			nq->qt_bcount_delta = nq->qt_icount_delta = 0;
+			nq->qt_rtbcount_delta = 0;
+
+			/*
+			 * Transfer whatever is left of the reservations.
+			 */
+			nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used;
+			oq->qt_blk_res = oq->qt_blk_res_used;
+
+			nq->qt_rtblk_res = oq->qt_rtblk_res -
+				oq->qt_rtblk_res_used;
+			oq->qt_rtblk_res = oq->qt_rtblk_res_used;
+
+			nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used;
+			oq->qt_ino_res = oq->qt_ino_res_used;
+
+		}
+		oqa = otp->t_dqinfo->dqa_grpdquots;
+		nqa = ntp->t_dqinfo->dqa_grpdquots;
+	}
+}
+
+/*
+ * Wrap around mod_dquot to account for both user and group quotas.
+ */
+void
+xfs_trans_mod_dquot_byino(
+	xfs_trans_t	*tp,
+	xfs_inode_t	*ip,
+	uint		field,
+	long		delta)
+{
+	xfs_mount_t	*mp;
+
+	ASSERT(tp);
+	mp = tp->t_mountp;
+
+	if (!XFS_IS_QUOTA_ON(mp) ||
+	    ip->i_ino == mp->m_sb.sb_uquotino ||
+	    ip->i_ino == mp->m_sb.sb_gquotino)
+		return;
+
+	if (tp->t_dqinfo == NULL)
+		xfs_trans_alloc_dqinfo(tp);
+
+	if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) {
+		(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
+	}
+	if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) {
+		(void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
+	}
+}
+
+STATIC xfs_dqtrx_t *
+xfs_trans_get_dqtrx(
+	xfs_trans_t	*tp,
+	xfs_dquot_t	*dqp)
+{
+	int		i;
+	xfs_dqtrx_t	*qa;
+
+	for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+		qa = XFS_QM_DQP_TO_DQACCT(tp, dqp);
+
+		if (qa[i].qt_dquot == NULL ||
+		    qa[i].qt_dquot == dqp) {
+			return (&qa[i]);
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * Make the changes in the transaction structure.
+ * The moral equivalent to xfs_trans_mod_sb().
+ * We don't touch any fields in the dquot, so we don't care
+ * if it's locked or not (most of the time it won't be).
+ */
+void
+xfs_trans_mod_dquot(
+	xfs_trans_t	*tp,
+	xfs_dquot_t	*dqp,
+	uint		field,
+	long		delta)
+{
+	xfs_dqtrx_t	*qtrx;
+
+	ASSERT(tp);
+	qtrx = NULL;
+
+	if (tp->t_dqinfo == NULL)
+		xfs_trans_alloc_dqinfo(tp);
+	/*
+	 * Find either the first free slot or the slot that belongs
+	 * to this dquot.
+	 */
+	qtrx = xfs_trans_get_dqtrx(tp, dqp);
+	ASSERT(qtrx);
+	if (qtrx->qt_dquot == NULL)
+		qtrx->qt_dquot = dqp;
+
+	switch (field) {
+
+		/*
+		 * regular disk blk reservation
+		 */
+	      case XFS_TRANS_DQ_RES_BLKS:
+		qtrx->qt_blk_res += (ulong)delta;
+		break;
+
+		/*
+		 * inode reservation
+		 */
+	      case XFS_TRANS_DQ_RES_INOS:
+		qtrx->qt_ino_res += (ulong)delta;
+		break;
+
+		/*
+		 * disk blocks used.
+		 */
+	      case XFS_TRANS_DQ_BCOUNT:
+		if (qtrx->qt_blk_res && delta > 0) {
+			qtrx->qt_blk_res_used += (ulong)delta;
+			ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used);
+		}
+		qtrx->qt_bcount_delta += delta;
+		break;
+
+	      case XFS_TRANS_DQ_DELBCOUNT:
+		qtrx->qt_delbcnt_delta += delta;
+		break;
+
+		/*
+		 * Inode Count
+		 */
+	      case XFS_TRANS_DQ_ICOUNT:
+		if (qtrx->qt_ino_res && delta > 0) {
+			qtrx->qt_ino_res_used += (ulong)delta;
+			ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used);
+		}
+		qtrx->qt_icount_delta += delta;
+		break;
+
+		/*
+		 * rtblk reservation
+		 */
+	      case XFS_TRANS_DQ_RES_RTBLKS:
+		qtrx->qt_rtblk_res += (ulong)delta;
+		break;
+
+		/*
+		 * rtblk count
+		 */
+	      case XFS_TRANS_DQ_RTBCOUNT:
+		if (qtrx->qt_rtblk_res && delta > 0) {
+			qtrx->qt_rtblk_res_used += (ulong)delta;
+			ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used);
+		}
+		qtrx->qt_rtbcount_delta += delta;
+		break;
+
+	      case XFS_TRANS_DQ_DELRTBCOUNT:
+		qtrx->qt_delrtb_delta += delta;
+		break;
+
+	      default:
+		ASSERT(0);
+	}
+	tp->t_flags |= XFS_TRANS_DQ_DIRTY;
+}
+
+
+/*
+ * Given an array of dqtrx structures, lock all the dquots associated
+ * and join them to the transaction, provided they have been modified.
+ * We know that the highest number of dquots (of one type - usr OR grp),
+ * involved in a transaction is 2 and that both usr and grp combined - 3.
+ * So, we don't attempt to make this very generic.
+ */
+STATIC void
+xfs_trans_dqlockedjoin(
+	xfs_trans_t	*tp,
+	xfs_dqtrx_t	*q)
+{
+	ASSERT(q[0].qt_dquot != NULL);
+	if (q[1].qt_dquot == NULL) {
+		xfs_dqlock(q[0].qt_dquot);
+		xfs_trans_dqjoin(tp, q[0].qt_dquot);
+	} else {
+		ASSERT(XFS_QM_TRANS_MAXDQS == 2);
+		xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
+		xfs_trans_dqjoin(tp, q[0].qt_dquot);
+		xfs_trans_dqjoin(tp, q[1].qt_dquot);
+	}
+}
+
+
+/*
+ * Called by xfs_trans_commit() and similar in spirit to
+ * xfs_trans_apply_sb_deltas().
+ * Go thru all the dquots belonging to this transaction and modify the
+ * INCORE dquot to reflect the actual usages.
+ * Unreserve just the reservations done by this transaction.
+ * dquot is still left locked at exit.
+ */
+void
+xfs_trans_apply_dquot_deltas(
+	xfs_trans_t		*tp)
+{
+	int			i, j;
+	xfs_dquot_t		*dqp;
+	xfs_dqtrx_t		*qtrx, *qa;
+	xfs_disk_dquot_t	*d;
+	long			totalbdelta;
+	long			totalrtbdelta;
+
+	if (! (tp->t_flags & XFS_TRANS_DQ_DIRTY))
+		return;
+
+	ASSERT(tp->t_dqinfo);
+	qa = tp->t_dqinfo->dqa_usrdquots;
+	for (j = 0; j < 2; j++) {
+		if (qa[0].qt_dquot == NULL) {
+			qa = tp->t_dqinfo->dqa_grpdquots;
+			continue;
+		}
+
+		/*
+		 * Lock all of the dquots and join them to the transaction.
+		 */
+		xfs_trans_dqlockedjoin(tp, qa);
+
+		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+			qtrx = &qa[i];
+			/*
+			 * The array of dquots is filled
+			 * sequentially, not sparsely.
+			 */
+			if ((dqp = qtrx->qt_dquot) == NULL)
+				break;
+
+			ASSERT(XFS_DQ_IS_LOCKED(dqp));
+			ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+
+			/*
+			 * adjust the actual number of blocks used
+			 */
+			d = &dqp->q_core;
+
+			/*
+			 * The issue here is - sometimes we don't make a blkquota
+			 * reservation intentionally to be fair to users
+			 * (when the amount is small). On the other hand,
+			 * delayed allocs do make reservations, but that's
+			 * outside of a transaction, so we have no
+			 * idea how much was really reserved.
+			 * So, here we've accumulated delayed allocation blks and
+			 * non-delay blks. The assumption is that the
+			 * delayed ones are always reserved (outside of a
+			 * transaction), and the others may or may not have
+			 * quota reservations.
+			 */
+			totalbdelta = qtrx->qt_bcount_delta +
+				qtrx->qt_delbcnt_delta;
+			totalrtbdelta = qtrx->qt_rtbcount_delta +
+				qtrx->qt_delrtb_delta;
+#ifdef QUOTADEBUG
+			if (totalbdelta < 0)
+				ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
+				       (xfs_qcnt_t) -totalbdelta);
+
+			if (totalrtbdelta < 0)
+				ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
+				       (xfs_qcnt_t) -totalrtbdelta);
+
+			if (qtrx->qt_icount_delta < 0)
+				ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
+				       (xfs_qcnt_t) -qtrx->qt_icount_delta);
+#endif
+			if (totalbdelta)
+				INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
+
+			if (qtrx->qt_icount_delta)
+				INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
+
+			if (totalrtbdelta)
+				INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
+
+			/*
+			 * Start/reset the timer(s) if needed.
+			 */
+			xfs_qm_adjust_dqtimers(tp->t_mountp, d);
+
+			dqp->dq_flags |= XFS_DQ_DIRTY;
+			/*
+			 * add this to the list of items to get logged
+			 */
+			xfs_trans_log_dquot(tp, dqp);
+			/*
+			 * Take off what's left of the original reservation.
+			 * In case of delayed allocations, there's no
+			 * reservation that a transaction structure knows of.
+			 */
+			if (qtrx->qt_blk_res != 0) {
+				if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+					if (qtrx->qt_blk_res >
+					    qtrx->qt_blk_res_used)
+						dqp->q_res_bcount -= (xfs_qcnt_t)
+							(qtrx->qt_blk_res -
+							 qtrx->qt_blk_res_used);
+					else
+						dqp->q_res_bcount -= (xfs_qcnt_t)
+							(qtrx->qt_blk_res_used -
+							 qtrx->qt_blk_res);
+				}
+			} else {
+				/*
+				 * These blks were never reserved, either inside
+				 * a transaction or outside one (in a delayed
+				 * allocation). Also, this isn't always a
+				 * negative number since we sometimes
+				 * deliberately skip quota reservations.
+				 */
+				if (qtrx->qt_bcount_delta) {
+					dqp->q_res_bcount +=
+					      (xfs_qcnt_t)qtrx->qt_bcount_delta;
+				}
+			}
+			/*
+			 * Adjust the RT reservation.
+			 */
+			if (qtrx->qt_rtblk_res != 0) {
+				if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+					if (qtrx->qt_rtblk_res >
+					    qtrx->qt_rtblk_res_used)
+					       dqp->q_res_rtbcount -= (xfs_qcnt_t)
+						       (qtrx->qt_rtblk_res -
+							qtrx->qt_rtblk_res_used);
+					else
+					       dqp->q_res_rtbcount -= (xfs_qcnt_t)
+						       (qtrx->qt_rtblk_res_used -
+							qtrx->qt_rtblk_res);
+				}
+			} else {
+				if (qtrx->qt_rtbcount_delta)
+					dqp->q_res_rtbcount +=
+					    (xfs_qcnt_t)qtrx->qt_rtbcount_delta;
+			}
+
+			/*
+			 * Adjust the inode reservation.
+			 */
+			if (qtrx->qt_ino_res != 0) {
+				ASSERT(qtrx->qt_ino_res >=
+				       qtrx->qt_ino_res_used);
+				if (qtrx->qt_ino_res > qtrx->qt_ino_res_used)
+					dqp->q_res_icount -= (xfs_qcnt_t)
+						(qtrx->qt_ino_res -
+						 qtrx->qt_ino_res_used);
+			} else {
+				if (qtrx->qt_icount_delta)
+					dqp->q_res_icount +=
+					    (xfs_qcnt_t)qtrx->qt_icount_delta;
+			}
+
+
+#ifdef QUOTADEBUG
+			if (qtrx->qt_rtblk_res != 0)
+				cmn_err(CE_DEBUG, "RT res %d for 0x%p\n",
+					(int) qtrx->qt_rtblk_res, dqp);
+#endif
+			ASSERT(dqp->q_res_bcount >=
+				INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+			ASSERT(dqp->q_res_icount >=
+				INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+			ASSERT(dqp->q_res_rtbcount >=
+				INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
+		}
+		/*
+		 * Do the group quotas next
+		 */
+		qa = tp->t_dqinfo->dqa_grpdquots;
+	}
+}
+
+/*
+ * Release the reservations, and adjust the dquots accordingly.
+ * This is called only when the transaction is being aborted. If by
+ * any chance we have done dquot modifications incore (ie. deltas) already,
+ * we simply throw those away, since that's the expected behavior
+ * when a transaction is curtailed without a commit.
+ */
+STATIC void
+xfs_trans_unreserve_and_mod_dquots(
+	xfs_trans_t		*tp)
+{
+	int			i, j;
+	xfs_dquot_t		*dqp;
+	xfs_dqtrx_t		*qtrx, *qa;
+	boolean_t		locked;
+
+	if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
+		return;
+
+	qa = tp->t_dqinfo->dqa_usrdquots;
+
+	for (j = 0; j < 2; j++) {
+		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+			qtrx = &qa[i];
+			/*
+			 * We assume that the array of dquots is filled
+			 * sequentially, not sparsely.
+			 */
+			if ((dqp = qtrx->qt_dquot) == NULL)
+				break;
+			/*
+			 * Unreserve the original reservation. We don't care
+			 * about the number of blocks used field, or deltas.
+			 * Also we don't bother to zero the fields.
+			 */
+			locked = B_FALSE;
+			if (qtrx->qt_blk_res) {
+				xfs_dqlock(dqp);
+				locked = B_TRUE;
+				dqp->q_res_bcount -=
+					(xfs_qcnt_t)qtrx->qt_blk_res;
+			}
+			if (qtrx->qt_ino_res) {
+				if (!locked) {
+					xfs_dqlock(dqp);
+					locked = B_TRUE;
+				}
+				dqp->q_res_icount -=
+					(xfs_qcnt_t)qtrx->qt_ino_res;
+			}
+
+			if (qtrx->qt_rtblk_res) {
+				if (!locked) {
+					xfs_dqlock(dqp);
+					locked = B_TRUE;
+				}
+				dqp->q_res_rtbcount -=
+					(xfs_qcnt_t)qtrx->qt_rtblk_res;
+			}
+			if (locked)
+				xfs_dqunlock(dqp);
+
+		}
+		qa = tp->t_dqinfo->dqa_grpdquots;
+	}
+}
+
+/*
+ * This reserves disk blocks and inodes against a dquot.
+ * Flags indicate if the dquot is to be locked here and also
+ * if the blk reservation is for RT or regular blocks.
+ * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
+ * Returns EDQUOT if quota is exceeded.
+ */
+STATIC int
+xfs_trans_dqresv(
+	xfs_trans_t	*tp,
+	xfs_dquot_t	*dqp,
+	long		nblks,
+	long		ninos,
+	uint		flags)
+{
+	int		error;
+	xfs_qcnt_t	hardlimit;
+	xfs_qcnt_t	softlimit;
+	time_t		btimer;
+	xfs_qcnt_t	*resbcountp;
+
+	if (! (flags & XFS_QMOPT_DQLOCK)) {
+		xfs_dqlock(dqp);
+	}
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+	if (flags & XFS_TRANS_DQ_RES_BLKS) {
+		hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
+		softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
+		btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
+		resbcountp = &dqp->q_res_bcount;
+	} else {
+		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
+		hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
+		softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
+		btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
+		resbcountp = &dqp->q_res_rtbcount;
+	}
+	error = 0;
+
+	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
+	    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
+	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
+#ifdef QUOTADEBUG
+		cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
+			  " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
+#endif
+		if (nblks > 0) {
+			/*
+			 * dquot is locked already. See if we'd go over the
+			 * hardlimit or exceed the timelimit if we allocate
+			 * nblks.
+			 */
+			if (hardlimit > 0ULL &&
+			     (hardlimit <= nblks + *resbcountp)) {
+				error = EDQUOT;
+				goto error_return;
+			}
+
+			if (softlimit > 0ULL &&
+			     (softlimit <= nblks + *resbcountp)) {
+				/*
+				 * If timer or warnings has expired,
+				 * return EDQUOT
+				 */
+				if ((btimer != 0 && get_seconds() > btimer) ||
+				    (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
+				     INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
+				     XFS_QI_BWARNLIMIT(dqp->q_mount))) {
+					error = EDQUOT;
+					goto error_return;
+				}
+			}
+		}
+		if (ninos > 0) {
+			if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL &&
+			    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+			    INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) {
+				error = EDQUOT;
+				goto error_return;
+			} else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL &&
+				   INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+				   INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
+				/*
+				 * If timer or warnings has expired,
+				 * return EDQUOT
+				 */
+				if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
+				     get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
+				    (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
+				     INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
+				     XFS_QI_IWARNLIMIT(dqp->q_mount))) {
+					error = EDQUOT;
+					goto error_return;
+				}
+			}
+		}
+	}
+
+	/*
+	 * Change the reservation, but not the actual usage.
+	 * Note that q_res_bcount = q_core.d_bcount + resv
+	 */
+	(*resbcountp) += (xfs_qcnt_t)nblks;
+	if (ninos != 0)
+		dqp->q_res_icount += (xfs_qcnt_t)ninos;
+
+	/*
+	 * note the reservation amt in the trans struct too,
+	 * so that the transaction knows how much was reserved by
+	 * it against this particular dquot.
+	 * We don't do this when we are reserving for a delayed allocation,
+	 * because we don't have the luxury of a transaction envelope then.
+	 */
+	if (tp) {
+		ASSERT(tp->t_dqinfo);
+		ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
+		if (nblks != 0)
+			xfs_trans_mod_dquot(tp, dqp,
+					    flags & XFS_QMOPT_RESBLK_MASK,
+					    nblks);
+		if (ninos != 0)
+			xfs_trans_mod_dquot(tp, dqp,
+					    XFS_TRANS_DQ_RES_INOS,
+					    ninos);
+	}
+	ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+	ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
+	ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+
+error_return:
+	if (! (flags & XFS_QMOPT_DQLOCK)) {
+		xfs_dqunlock(dqp);
+	}
+	return (error);
+}
+
+
+/*
+ * Given a dquot(s), make disk block and/or inode reservations against them.
+ * The fact that this does the reservation against both the usr and
+ * grp quotas is important, because this follows a both-or-nothing
+ * approach.
+ *
+ * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
+ *	   XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
+ *	   XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
+ *	   XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
+ * dquots are unlocked on return, if they were not locked by caller.
+ */
+int
+xfs_trans_reserve_quota_bydquots(
+	xfs_trans_t	*tp,
+	xfs_mount_t	*mp,
+	xfs_dquot_t	*udqp,
+	xfs_dquot_t	*gdqp,
+	long		nblks,
+	long		ninos,
+	uint		flags)
+{
+	int		resvd;
+
+	if (! XFS_IS_QUOTA_ON(mp))
+		return (0);
+
+	if (tp && tp->t_dqinfo == NULL)
+		xfs_trans_alloc_dqinfo(tp);
+
+	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
+	resvd = 0;
+
+	if (udqp) {
+		if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags))
+			return (EDQUOT);
+		resvd = 1;
+	}
+
+	if (gdqp) {
+		if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) {
+			/*
+			 * can't do it, so backout previous reservation
+			 */
+			if (resvd) {
+				xfs_trans_dqresv(tp, udqp,  -nblks, -ninos,
+						 flags);
+			}
+			return (EDQUOT);
+		}
+	}
+
+	/*
+	 * Didnt change anything critical, so, no need to log
+	 */
+	return (0);
+}
+
+
+/*
+ * Lock the dquot and change the reservation if we can.
+ * This doesn't change the actual usage, just the reservation.
+ * The inode sent in is locked.
+ *
+ * Returns 0 on success, EDQUOT or other errors otherwise
+ */
+STATIC int
+xfs_trans_reserve_quota_nblks(
+	xfs_trans_t	*tp,
+	xfs_mount_t	*mp,
+	xfs_inode_t	*ip,
+	long		nblks,
+	long		ninos,
+	uint		type)
+{
+	int		error;
+
+	if (!XFS_IS_QUOTA_ON(mp))
+		return (0);
+
+	ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
+	ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
+
+#ifdef QUOTADEBUG
+	if (ip->i_udquot)
+		ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
+	if (ip->i_gdquot)
+		ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
+#endif
+
+	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
+	ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
+	       (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
+
+	/*
+	 * Reserve nblks against these dquots, with trans as the mediator.
+	 */
+	error = xfs_trans_reserve_quota_bydquots(tp, mp,
+						 ip->i_udquot, ip->i_gdquot,
+						 nblks, ninos,
+						 type);
+	return (error);
+}
+
+/*
+ * This routine is called to allocate a quotaoff log item.
+ */
+xfs_qoff_logitem_t *
+xfs_trans_get_qoff_item(
+	xfs_trans_t		*tp,
+	xfs_qoff_logitem_t	*startqoff,
+	uint			flags)
+{
+	xfs_qoff_logitem_t	*q;
+
+	ASSERT(tp != NULL);
+
+	q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags);
+	ASSERT(q != NULL);
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	(void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
+
+	return (q);
+}
+
+
+/*
+ * This is called to mark the quotaoff logitem as needing
+ * to be logged when the transaction is committed.  The logitem must
+ * already be associated with the given transaction.
+ */
+void
+xfs_trans_log_quotaoff_item(
+	xfs_trans_t		*tp,
+	xfs_qoff_logitem_t	*qlp)
+{
+	xfs_log_item_desc_t	*lidp;
+
+	lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
+	ASSERT(lidp != NULL);
+
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	lidp->lid_flags |= XFS_LID_DIRTY;
+}
+
+STATIC void
+xfs_trans_alloc_dqinfo(
+	xfs_trans_t	*tp)
+{
+	(tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
+}
+
+STATIC void
+xfs_trans_free_dqinfo(
+	xfs_trans_t	*tp)
+{
+	if (!tp->t_dqinfo)
+		return;
+	kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
+	(tp)->t_dqinfo = NULL;
+}
+
+xfs_dqtrxops_t	xfs_trans_dquot_ops = {
+	.qo_dup_dqinfo			= xfs_trans_dup_dqinfo,
+	.qo_free_dqinfo			= xfs_trans_free_dqinfo,
+	.qo_mod_dquot_byino		= xfs_trans_mod_dquot_byino,
+	.qo_apply_dquot_deltas		= xfs_trans_apply_dquot_deltas,
+	.qo_reserve_quota_nblks		= xfs_trans_reserve_quota_nblks,
+	.qo_reserve_quota_bydquots	= xfs_trans_reserve_quota_bydquots,
+	.qo_unreserve_and_mod_dquots	= xfs_trans_unreserve_and_mod_dquots,
+};
diff -urN linux-2.5.66-bk2/fs/xfs/support/atomic.h linux-2.5.66-bk3/fs/xfs/support/atomic.h
--- linux-2.5.66-bk2/fs/xfs/support/atomic.h	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk3/fs/xfs/support/atomic.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -43,20 +43,20 @@
  * This is used for two variables in XFS, one of which is a debug trace
  * buffer index. They are not accessed via any other atomic operations
  * so this is safe. All other atomic increments and decrements in XFS
- * now use the linux built in functions.
+ * now use the Linux built-in functions.
  */
 
-extern spinlock_t Atomic_spin;
+extern spinlock_t xfs_atomic_spin;
 
 static __inline__ int atomicIncWithWrap(int *ip, int val)
 {
 	unsigned long flags;
 	int ret;
-	spin_lock_irqsave(&Atomic_spin, flags);
+	spin_lock_irqsave(&xfs_atomic_spin, flags);
 	ret = *ip;
 	(*ip)++;
 	if (*ip == val) *ip = 0;
-	spin_unlock_irqrestore(&Atomic_spin, flags);
+	spin_unlock_irqrestore(&xfs_atomic_spin, flags);
 	return ret;
 }
 
diff -urN linux-2.5.66-bk2/fs/xfs/support/debug.c linux-2.5.66-bk3/fs/xfs/support/debug.c
--- linux-2.5.66-bk2/fs/xfs/support/debug.c	Mon Mar 24 14:00:00 2003
+++ linux-2.5.66-bk3/fs/xfs/support/debug.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -55,7 +55,7 @@
     BUG();
 }
 
-#if (defined(DEBUG) || defined(INDUCE_IO_ERRROR))
+#if ((defined(DEBUG) || defined(INDUCE_IO_ERRROR)) && !defined(NO_WANT_RANDOM))
 
 unsigned long
 random(void)
@@ -79,7 +79,7 @@
 	return current->pid;
 }
 
-#endif /* DEBUG */
+#endif /* DEBUG || INDUCE_IO_ERRROR || !NO_WANT_RANDOM */
 
 void
 cmn_err(register int level, char *fmt, ...)
diff -urN linux-2.5.66-bk2/fs/xfs/support/mrlock.c linux-2.5.66-bk3/fs/xfs/support/mrlock.c
--- linux-2.5.66-bk2/fs/xfs/support/mrlock.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk3/fs/xfs/support/mrlock.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -272,15 +272,3 @@
 	}
 	MRUNLOCK(mrp);
 }
-
-int
-mrislocked_access(mrlock_t *mrp)
-{
-	return(mrp->mr_count > 0);
-}
-
-int
-mrislocked_update(mrlock_t *mrp)
-{
-	return(mrp->mr_count < 0);
-}
diff -urN linux-2.5.66-bk2/fs/xfs/support/mrlock.h linux-2.5.66-bk3/fs/xfs/support/mrlock.h
--- linux-2.5.66-bk2/fs/xfs/support/mrlock.h	Mon Mar 24 14:00:54 2003
+++ linux-2.5.66-bk3/fs/xfs/support/mrlock.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -80,7 +80,9 @@
 extern void	mrfree(mrlock_t *);
 
 #define mrinit(mrp, name)	mrlock_init(mrp, MRLOCK_BARRIER, name, -1)
-#define mraccess(mrp)	mraccessf(mrp, 0)	/* grab for READ/ACCESS */
-#define mrupdate(mrp)	mrupdatef(mrp, 0)	/* grab for WRITE/UPDATE */
+#define mraccess(mrp)		mraccessf(mrp, 0) /* grab for READ/ACCESS */
+#define mrupdate(mrp)		mrupdatef(mrp, 0) /* grab for WRITE/UPDATE */
+#define mrislocked_access(mrp)	((mrp)->mr_count > 0)
+#define mrislocked_update(mrp)	((mrp)->mr_count < 0)
 
 #endif /* __XFS_SUPPORT_MRLOCK_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/support/mutex.h linux-2.5.66-bk3/fs/xfs/support/mutex.h
--- linux-2.5.66-bk2/fs/xfs/support/mutex.h	Mon Mar 24 13:59:53 2003
+++ linux-2.5.66-bk3/fs/xfs/support/mutex.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  * Portions Copyright (c) 2002 Christoph Hellwig.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -46,7 +46,6 @@
 typedef struct semaphore	mutex_t;
 
 #define mutex_init(lock, type, name)		sema_init(lock, 1)
-#define init_mutex(ptr, type, name, sequence)	sema_init(lock, 1)
 #define mutex_destroy(lock)			sema_init(lock, -99)
 #define mutex_lock(lock, num)			down(lock)
 #define mutex_trylock(lock)			(down_trylock(lock) ? 0 : 1)
diff -urN linux-2.5.66-bk2/fs/xfs/support/time.h linux-2.5.66-bk3/fs/xfs/support/time.h
--- linux-2.5.66-bk2/fs/xfs/support/time.h	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/fs/xfs/support/time.h	Mon Mar 31 12:48:53 2003
@@ -45,11 +45,7 @@
 
 static inline void nanotime(struct timespec *tvp)
 {
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	tvp->tv_sec = tv.tv_sec;
-	tvp->tv_nsec = tv.tv_usec * 1000;
+	*tvp = CURRENT_TIME;
 }
 
 #endif /* __XFS_SUPPORT_TIME_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs.h linux-2.5.66-bk3/fs/xfs/xfs.h
--- linux-2.5.66-bk2/fs/xfs/xfs.h	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -66,6 +66,9 @@
 #include <xfs_dir.h>
 #include <xfs_dir2.h>
 #include <xfs_imap.h>
+#include <xfs_alloc.h>
+#include <xfs_dmapi.h>
+#include <xfs_quota.h>
 #include <xfs_mount.h>
 #include <xfs_alloc_btree.h>
 #include <xfs_bmap_btree.h>
@@ -77,17 +80,11 @@
 #include <xfs_dir2_sf.h>
 #include <xfs_dinode.h>
 #include <xfs_inode.h>
-#include <xfs_alloc.h>
 #include <xfs_bmap.h>
 #include <xfs_bit.h>
 #include <xfs_rtalloc.h>
 #include <xfs_error.h>
-#include <xfs_quota.h>
 #include <xfs_itable.h>
-#include <xfs_dqblk.h>
-#include <xfs_dquot_item.h>
-#include <xfs_dquot.h>
-#include <xfs_qm.h>
 #include <xfs_rw.h>
 #include <xfs_da_btree.h>
 #include <xfs_dir_leaf.h>
@@ -108,6 +105,5 @@
 #include <xfs_trans_priv.h>
 #include <xfs_trans_space.h>
 #include <xfs_utils.h>
-#include <xfs_dmapi.h>
 
 #endif	/* __XFS_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_attr.c linux-2.5.66-bk3/fs/xfs/xfs_attr.c
--- linux-2.5.66-bk2/fs/xfs/xfs_attr.c	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_attr.c	Mon Mar 31 12:48:53 2003
@@ -197,10 +197,8 @@
 	/*
 	 * Attach the dquots to the inode.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if ((error = xfs_qm_dqattach(dp, 0)))
-			return (error);
-	}
+	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
+		return (error);
 
 	/*
 	 * If the inode doesn't have an attribute fork, add one.
@@ -280,19 +278,13 @@
 	}
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (rsvd) {
-			error = xfs_trans_reserve_blkquota_force(args.trans,
-					dp, nblks);
-		} else {
-			error = xfs_trans_reserve_blkquota(args.trans,
-					dp, nblks);
-		}
-		if (error) {
-			xfs_iunlock(dp, XFS_ILOCK_EXCL);
-			xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
-			return (error);
-		}
+	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
+			 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
+				XFS_QMOPT_RES_REGBLKS);
+	if (error) {
+		xfs_iunlock(dp, XFS_ILOCK_EXCL);
+		xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
+		return (error);
 	}
 
 	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
@@ -483,12 +475,9 @@
 	/*
 	 * Attach the dquots to the inode.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (XFS_NOT_DQATTACHED(mp, dp)) {
-			if ((error = xfs_qm_dqattach(dp, 0)))
-				return (error);
-		}
-	}
+	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
+		return (error);
+
 	/*
 	 * Start our first transaction of the day.
 	 *
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_bmap.c linux-2.5.66-bk3/fs/xfs/xfs_bmap.c
--- linux-2.5.66-bk2/fs/xfs/xfs_bmap.c	Mon Mar 24 14:01:27 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_bmap.c	Mon Mar 31 12:48:53 2003
@@ -2145,7 +2145,7 @@
 	 */
 	mp = ap->ip->i_mount;
 	nullfb = ap->firstblock == NULLFSBLOCK;
-	rt = (ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata;
+	rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata;
 	fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
 #ifdef __KERNEL__
 	if (rt) {
@@ -2467,14 +2467,10 @@
 			 * Adjust the disk quota also. This was reserved
 			 * earlier.
 			 */
-			if (XFS_IS_QUOTA_ON(mp) &&
-			    ap->ip->i_ino != mp->m_sb.sb_uquotino &&
-			    ap->ip->i_ino != mp->m_sb.sb_gquotino)
-				xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
-					ap->wasdel ?
-						XFS_TRANS_DQ_DELRTBCOUNT :
+			XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+				ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
 						XFS_TRANS_DQ_RTBCOUNT,
-					(long)ralen);
+				(long) ralen);
 		} else
 			ap->alen = 0;
 #endif	/* __KERNEL__ */
@@ -2691,14 +2687,10 @@
 			 * Adjust the disk quota also. This was reserved
 			 * earlier.
 			 */
-			if (XFS_IS_QUOTA_ON(mp) &&
-			    ap->ip->i_ino != mp->m_sb.sb_uquotino &&
-			    ap->ip->i_ino != mp->m_sb.sb_gquotino)
-				xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
-					ap->wasdel ?
-						XFS_TRANS_DQ_DELBCOUNT :
+			XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+				ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT :
 						XFS_TRANS_DQ_BCOUNT,
-					(long)args.len);
+				(long) args.len);
 		} else {
 			ap->rval = NULLFSBLOCK;
 			ap->alen = 0;
@@ -2755,10 +2747,7 @@
 		return error;
 	xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
 	ip->i_d.di_nblocks--;
-	if (XFS_IS_QUOTA_ON(mp) &&
-	    ip->i_ino != mp->m_sb.sb_uquotino &&
-	    ip->i_ino != mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
 	xfs_trans_binval(tp, cbp);
 	if (cur->bc_bufs[0] == cbp)
 		cur->bc_bufs[0] = NULL;
@@ -2854,10 +2843,7 @@
 				goto done;
 			do_fx = 0;
 			nblks = len * mp->m_sb.sb_rextsize;
-			if (XFS_IS_QUOTA_ON(mp) &&
-			    ip->i_ino != mp->m_sb.sb_uquotino &&
-			    ip->i_ino != mp->m_sb.sb_gquotino)
-				qfield = XFS_TRANS_DQ_RTBCOUNT;
+			qfield = XFS_TRANS_DQ_RTBCOUNT;
 		}
 		/*
 		 * Ordinary allocation.
@@ -2865,10 +2851,7 @@
 		else {
 			do_fx = 1;
 			nblks = del->br_blockcount;
-			if (XFS_IS_QUOTA_ON(mp) &&
-			    ip->i_ino != mp->m_sb.sb_uquotino &&
-			    ip->i_ino != mp->m_sb.sb_gquotino)
-				qfield = XFS_TRANS_DQ_BCOUNT;
+			qfield = XFS_TRANS_DQ_BCOUNT;
 		}
 		/*
 		 * Set up del_endblock and cur for later.
@@ -3088,7 +3071,8 @@
 	 * Adjust quota data.
 	 */
 	if (qfield)
-		xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks);
+		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, qfield, (long)-nblks);
+
 	/*
 	 * Account for change in delayed indirect blocks.
 	 * Nothing to do for disk quota accounting here.
@@ -3239,10 +3223,7 @@
 	*firstblock = cur->bc_private.b.firstblock = args.fsbno;
 	cur->bc_private.b.allocated++;
 	ip->i_d.di_nblocks++;
-	if (XFS_IS_QUOTA_ON(mp) &&
-	    ip->i_ino != mp->m_sb.sb_uquotino &&
-	    ip->i_ino != mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
+	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
 	abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
 	/*
 	 * Fill in the child block.
@@ -3385,11 +3366,8 @@
 		xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
 		XFS_IFORK_NEXT_SET(ip, whichfork, 1);
 		ip->i_d.di_nblocks = 1;
-		if (XFS_IS_QUOTA_ON(args.mp) &&
-		    ip->i_ino != args.mp->m_sb.sb_uquotino &&
-		    ip->i_ino != args.mp->m_sb.sb_gquotino)
-			xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT,
-				1L);
+		XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
+			XFS_TRANS_DQ_BCOUNT, 1L);
 		flags |= XFS_ILOG_FEXT(whichfork);
 	} else
 		ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
@@ -3772,18 +3750,13 @@
 			XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
 		goto error0;
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (rsvd) {
-			error = xfs_trans_reserve_blkquota_force(tp, ip, blks);
-		} else {
-			error = xfs_trans_reserve_blkquota(tp, ip, blks);
-		}
-
-		if (error) {
-			xfs_iunlock(ip, XFS_ILOCK_EXCL);
-			xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
-			return error;
-		}
+	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, blks, 0, rsvd ?
+			XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
+			XFS_QMOPT_RES_REGBLKS);
+	if (error) {
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
+		return error;
 	}
 	if (XFS_IFORK_Q(ip))
 		goto error1;
@@ -4655,8 +4628,8 @@
 	cur = NULL;
 	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
 		ASSERT(wr && tp);
-		if ((error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
-				&logflags, whichfork)))
+		if ((error = xfs_bmap_local_to_extents(tp, ip,
+				firstblock, total, &logflags, whichfork)))
 			goto error0;
 	}
 	if (wr && *firstblock == NULLFSBLOCK) {
@@ -4730,9 +4703,8 @@
 				 * We return EDQUOT if we haven't allocated
 				 * blks already inside this loop;
 				 */
-				if (XFS_IS_QUOTA_ON(ip->i_mount) &&
-				    xfs_trans_reserve_blkquota(NULL, ip,
-					    (long)alen)) {
+				if (XFS_TRANS_RESERVE_BLKQUOTA(
+						mp, NULL, ip, (long)alen)) {
 					if (n == 0) {
 						*nmap = 0;
 						ASSERT(cur == NULL);
@@ -4740,12 +4712,10 @@
 					}
 					break;
 				}
-				if (xfs_mod_incore_sb(ip->i_mount,
-						XFS_SBS_FDBLOCKS,
+				if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
 						-(alen + indlen), rsvd)) {
-					if (XFS_IS_QUOTA_ON(ip->i_mount))
-						xfs_trans_unreserve_blkquota(
-							NULL, ip, (long)alen);
+					XFS_TRANS_UNRESERVE_BLKQUOTA(
+						mp, NULL, ip, (long)alen);
 					break;
 				}
 				ip->i_delayed_blks += alen;
@@ -4808,15 +4778,11 @@
 				alen = bma.alen;
 				aoff = bma.off;
 				ASSERT(*firstblock == NULLFSBLOCK ||
-				       XFS_FSB_TO_AGNO(ip->i_mount,
-					       *firstblock) ==
-				       XFS_FSB_TO_AGNO(ip->i_mount,
-					       bma.firstblock) ||
+				       XFS_FSB_TO_AGNO(mp, *firstblock) ==
+				       XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
 				       (flist->xbf_low &&
-					XFS_FSB_TO_AGNO(ip->i_mount,
-						*firstblock) <
-					XFS_FSB_TO_AGNO(ip->i_mount,
-						bma.firstblock)));
+					XFS_FSB_TO_AGNO(mp, *firstblock) <
+					XFS_FSB_TO_AGNO(mp, bma.firstblock)));
 				*firstblock = bma.firstblock;
 				if (cur)
 					cur->bc_private.b.firstblock =
@@ -4824,7 +4790,7 @@
 				if (abno == NULLFSBLOCK)
 					break;
 				if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-					cur = xfs_btree_init_cursor(ip->i_mount,
+					cur = xfs_btree_init_cursor(mp,
 						tp, NULL, 0, XFS_BTNUM_BMAP,
 						ip, whichfork);
 					cur->bc_private.b.firstblock =
@@ -4941,7 +4907,7 @@
 			 */
 			ASSERT(mval->br_blockcount <= len);
 			if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-				cur = xfs_btree_init_cursor(ip->i_mount,
+				cur = xfs_btree_init_cursor(mp,
 					tp, NULL, 0, XFS_BTNUM_BMAP,
 					ip, whichfork);
 				cur->bc_private.b.firstblock =
@@ -5063,12 +5029,12 @@
 	if (cur) {
 		if (!error) {
 			ASSERT(*firstblock == NULLFSBLOCK ||
-			       XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) ==
-			       XFS_FSB_TO_AGNO(ip->i_mount,
+			       XFS_FSB_TO_AGNO(mp, *firstblock) ==
+			       XFS_FSB_TO_AGNO(mp,
 				       cur->bc_private.b.firstblock) ||
 			       (flist->xbf_low &&
-				XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) <
-				XFS_FSB_TO_AGNO(ip->i_mount,
+				XFS_FSB_TO_AGNO(mp, *firstblock) <
+				XFS_FSB_TO_AGNO(mp,
 					cur->bc_private.b.firstblock)));
 			*firstblock = cur->bc_private.b.firstblock;
 		}
@@ -5378,16 +5344,11 @@
 			ASSERT(STARTBLOCKVAL(del.br_startblock) > 0);
 			xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
 				(int)del.br_blockcount, rsvd);
-			if (XFS_IS_QUOTA_ON(ip->i_mount)) {
-				ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
-				ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
-				if (!isrt)
-					xfs_trans_unreserve_blkquota(NULL, ip,
-					      (long)del.br_blockcount);
-				else
-					xfs_trans_unreserve_rtblkquota(NULL, ip,
-					      (long)del.br_blockcount);
-			}
+			/* Unreserve our quota space */
+			XFS_TRANS_RESERVE_QUOTA_NBLKS(
+				mp, NULL, ip, -((long)del.br_blockcount), 0,
+				isrt ?	XFS_QMOPT_RES_RTBLKS :
+					XFS_QMOPT_RES_REGBLKS);
 			ip->i_delayed_blks -= del.br_blockcount;
 			if (cur)
 				cur->bc_private.b.flags |=
@@ -5556,8 +5517,7 @@
 	    && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)
 	    && whichfork == XFS_DATA_FORK) {
 
-		error = xfs_dm_send_data_event(DM_EVENT_READ, bdp,
-				0, 0, 0, NULL);
+		error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, 0, 0, 0, NULL);
 		if (error)
 			return XFS_ERROR(error);
 	}
@@ -5579,7 +5539,6 @@
 		   ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
 		   ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
 		return XFS_ERROR(EINVAL);
-
 	if (whichfork == XFS_DATA_FORK) {
 		if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) {
 			prealloced = 1;
@@ -5928,10 +5887,13 @@
 				thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
 					xfs_bmbt, block, j, dmxr);
 			}
-			if (INT_GET(*thispa, ARCH_CONVERT) == INT_GET(*pp, ARCH_CONVERT)) {
-				printk("xfs_check_block: thispa(%d) == pp(%d) %Ld\n",
-						j, i, INT_GET(*thispa, ARCH_CONVERT));
-				panic("xfs_check_block: ptrs are equal in node\n");
+			if (INT_GET(*thispa, ARCH_CONVERT) ==
+			    INT_GET(*pp, ARCH_CONVERT)) {
+				cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
+					__FUNCTION__, j, i,
+					INT_GET(*thispa, ARCH_CONVERT));
+				panic("%s: ptrs are equal in node\n",
+					__FUNCTION__);
 			}
 		}
 	}
@@ -6089,12 +6051,13 @@
 	return;
 
 error0:
-	printk("at error0\n");
+	cmn_err(CE_WARN, "%s: at error0", __FUNCTION__);
 	if (bp_release)
 		xfs_trans_brelse(NULL, bp);
 error_norelse:
-	printk("xfs_bmap_check_leaf_extents: BAD after btree leaves for %d extents\n", i);
-	panic("xfs_bmap_check_leaf_extents: CORRUPTED BTREE OR SOMETHING");
+	cmn_err(CE_WARN, "%s: BAD after btree leaves for %d extents",
+		i, __FUNCTION__);
+	panic("%s: CORRUPTED BTREE OR SOMETHING", __FUNCTION__);
 	return;
 }
 #endif
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_bmap.h linux-2.5.66-bk3/fs/xfs/xfs_bmap.h
--- linux-2.5.66-bk2/fs/xfs/xfs_bmap.h	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_bmap.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -76,10 +76,6 @@
 #define XFS_BMAPI_IGSTATE	0x200	/* Ignore state - */
 					/* combine contig. space */
 #define XFS_BMAPI_CONTIG	0x400	/* must allocate only one extent */
-#define XFS_BMAPI_DIRECT_IO	0x800	/* Flag from cxfs client, not used
-					 * by xfs directly. Indicates alloc
-					 * request is for direct I/O not
-					 * extent conversion by server */
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAPI_AFLAG)
 int xfs_bmapi_aflag(int w);
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_bmap_btree.c linux-2.5.66-bk3/fs/xfs/xfs_bmap_btree.c
--- linux-2.5.66-bk2/fs/xfs/xfs_bmap_btree.c	Mon Mar 24 14:00:42 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_bmap_btree.c	Mon Mar 31 12:48:53 2003
@@ -629,8 +629,8 @@
 	xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS);
 	if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) {
 		if ((error = xfs_btree_read_bufl(mp, cur->bc_tp,
-				INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rrbp,
-				XFS_BMAP_BTREE_REF))) {
+				INT_GET(left->bb_rightsib, ARCH_CONVERT),
+				0, &rrbp, XFS_BMAP_BTREE_REF))) {
 			XFS_BMBT_TRACE_CURSOR(cur, ERROR);
 			goto error0;
 		}
@@ -646,10 +646,7 @@
 		cur->bc_private.b.flist, mp);
 	cur->bc_private.b.ip->i_d.di_nblocks--;
 	xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-	if (XFS_IS_QUOTA_ON(mp) &&
-	    cur->bc_private.b.ip->i_ino != mp->m_sb.sb_uquotino &&
-	    cur->bc_private.b.ip->i_ino != mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(cur->bc_tp, cur->bc_private.b.ip,
+	XFS_TRANS_MOD_DQUOT_BYINO(mp, cur->bc_tp, cur->bc_private.b.ip,
 			XFS_TRANS_DQ_BCOUNT, -1L);
 	xfs_trans_binval(cur->bc_tp, rbp);
 	if (bp != lbp) {
@@ -986,13 +983,10 @@
 #endif
 	memcpy(pp, cpp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
 	xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1,
-		cur->bc_private.b.flist, cur->bc_mp);
+			cur->bc_private.b.flist, cur->bc_mp);
 	ip->i_d.di_nblocks--;
-	if (XFS_IS_QUOTA_ON(cur->bc_mp) &&
-	    ip->i_ino != cur->bc_mp->m_sb.sb_uquotino &&
-	    ip->i_ino != cur->bc_mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(cur->bc_tp, ip, XFS_TRANS_DQ_BCOUNT,
-			-1L);
+	XFS_TRANS_MOD_DQUOT_BYINO(cur->bc_mp, cur->bc_tp, ip,
+			XFS_TRANS_DQ_BCOUNT, -1L);
 	xfs_trans_binval(cur->bc_tp, cbp);
 	cur->bc_bufs[level - 1] = NULL;
 	INT_MOD(block->bb_level, ARCH_CONVERT, -1);
@@ -1589,10 +1583,7 @@
 	cur->bc_private.b.allocated++;
 	cur->bc_private.b.ip->i_d.di_nblocks++;
 	xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-	if (XFS_IS_QUOTA_ON(args.mp) &&
-	    cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino &&
-	    cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
+	XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
 			XFS_TRANS_DQ_BCOUNT, 1L);
 	rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0);
 	right = XFS_BUF_TO_BMBT_BLOCK(rbp);
@@ -2390,11 +2381,8 @@
 	cur->bc_private.b.firstblock = args.fsbno;
 	cur->bc_private.b.allocated++;
 	cur->bc_private.b.ip->i_d.di_nblocks++;
-	if (XFS_IS_QUOTA_ON(args.mp) &&
-	    cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino &&
-	    cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino)
-		xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
-					  XFS_TRANS_DQ_BCOUNT, 1L);
+	XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
+			  XFS_TRANS_DQ_BCOUNT, 1L);
 	bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0);
 	cblock = XFS_BUF_TO_BMBT_BLOCK(bp);
 	*cblock = *block;
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_buf.h linux-2.5.66-bk3/fs/xfs/xfs_buf.h
--- linux-2.5.66-bk2/fs/xfs/xfs_buf.h	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_buf.h	Mon Mar 31 12:48:53 2003
@@ -124,6 +124,9 @@
 typedef struct pb_target xfs_buftarg_t;
 #define xfs_buftarg pb_target
 
+#define XFS_BUF_DATAIO(x)	((x)->pb_flags |= PBF_FS_DATAIOD)
+#define XFS_BUF_UNDATAIO(x)	((x)->pb_flags &= ~PBF_FS_DATAIOD)
+
 #define XFS_BUF_IODONE_FUNC(buf)	(buf)->pb_iodone
 #define XFS_BUF_SET_IODONE_FUNC(buf, func)	\
 			(buf)->pb_iodone = (func)
@@ -244,7 +247,7 @@
 
 
 #define xfs_biodone(pb)		    \
-	    pagebuf_iodone(pb, 0, 0)
+	    pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 0)
 
 #define xfs_incore(buftarg,blkno,len,lockit) \
 	    pagebuf_find(buftarg, blkno ,len, lockit)
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_clnt.h linux-2.5.66-bk3/fs/xfs/xfs_clnt.h
--- linux-2.5.66-bk2/fs/xfs/xfs_clnt.h	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_clnt.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -64,16 +64,6 @@
 	int	sunit;		/* stripe unit (BBs) */
 	int	swidth;		/* stripe width (BBs), multiple of sunit */
 	uchar_t iosizelog;	/* log2 of the preferred I/O size */
-
-	/*  The remainder is for CXFS support.	*/
-	char	**servlist;	/* Table of hosts which may be servers */
-	int	*servlistlen;	/* Table of hostname lengths. */
-	int	slcount;	/* Count of hosts which may be servers. */
-	int	stimeout;	/* Server timeout in milliseconds */
-	int	ctimeout;	/* Client timeout in milliseconds */
-	char	*server;	/* Designated server hostname (for remount). */
-	int	servlen;	/* Length of server hostname (for remount). */
-	int	servcell;	/* Server cell (internal testing only) */
 };
 
 /*
@@ -101,17 +91,6 @@
 #define XFSMNT_IOSIZE		0x00002000	/* optimize for I/O size */
 #define XFSMNT_OSYNCISOSYNC	0x00004000	/* o_sync is REALLY o_sync */
 						/* (osyncisdsync is now default) */
-#define XFSMNT_CLNTONLY		0x00008000	/* cxfs mount as client only */
-#define XFSMNT_UNSHARED		0x00010000	/* cxfs filesystem mounted
-						 * unshared */
-#define XFSMNT_CHGCLNTONLY	0x00020000	/* changing client only flag */
-						/* (for remount only) */
-#define XFSMNT_SERVCELL		0x00040000	/* setting server cell */
-						/* (allowed on remount) */
-#define XFSMNT_MAKESERVER	0x00080000	/* become the server (remount */
-						/* only) */
-#define XFSMNT_NOTSERVER	0x00100000	/* give up being the server */
-						/* (remount only) */
 #define XFSMNT_32BITINODES	0x00200000	/* restrict inodes to 32
 						 * bits of address space */
 #define XFSMNT_GQUOTA		0x00400000	/* group quota accounting */
@@ -121,10 +100,4 @@
 #define XFSMNT_DMAPI		0x02000000	/* enable dmapi/xdsm */
 #define XFSMNT_NOLOGFLUSH	0x04000000	/* Don't flush for log blocks */
 
-/* Did we get any args for CXFS to consume? */
-#define XFSARGS_FOR_CXFSARR(ap)		\
-	((ap)->servlist || (ap)->slcount >= 0 || \
-	 (ap)->stimeout >= 0 || (ap)->ctimeout >= 0 || \
-	 (ap)->flags & (XFSMNT_CLNTONLY | XFSMNT_UNSHARED))
-
 #endif	/* __XFS_CLNT_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dmapi.h linux-2.5.66-bk3/fs/xfs/xfs_dmapi.h
--- linux-2.5.66-bk2/fs/xfs/xfs_dmapi.h	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dmapi.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -32,11 +32,6 @@
 #ifndef __XFS_DMAPI_H__
 #define __XFS_DMAPI_H__
 
-#ifdef CONFIG_XFS_DMAPI
-
-#include <dmapi/dmapi.h>
-#include <dmapi/dmapi_kern.h>
-
 /*	Values used to define the on-disk version of dm_attrname_t. All
  *	on-disk attribute names start with the 8-byte string "SGI_DMI_".
  *
@@ -48,6 +43,42 @@
 #define DMATTR_PREFIXLEN	8
 #define DMATTR_PREFIXSTRING	"SGI_DMI_"
 
+typedef enum {
+	DM_EVENT_INVALID	= -1,
+	DM_EVENT_CANCEL		= 0,		/* not supported */
+	DM_EVENT_MOUNT		= 1,
+	DM_EVENT_PREUNMOUNT	= 2,
+	DM_EVENT_UNMOUNT	= 3,
+	DM_EVENT_DEBUT		= 4,		/* not supported */
+	DM_EVENT_CREATE		= 5,
+	DM_EVENT_CLOSE		= 6,		/* not supported */
+	DM_EVENT_POSTCREATE	= 7,
+	DM_EVENT_REMOVE		= 8,
+	DM_EVENT_POSTREMOVE	= 9,
+	DM_EVENT_RENAME		= 10,
+	DM_EVENT_POSTRENAME	= 11,
+	DM_EVENT_LINK		= 12,
+	DM_EVENT_POSTLINK	= 13,
+	DM_EVENT_SYMLINK	= 14,
+	DM_EVENT_POSTSYMLINK	= 15,
+	DM_EVENT_READ		= 16,
+	DM_EVENT_WRITE		= 17,
+	DM_EVENT_TRUNCATE	= 18,
+	DM_EVENT_ATTRIBUTE	= 19,
+	DM_EVENT_DESTROY	= 20,
+	DM_EVENT_NOSPACE	= 21,
+	DM_EVENT_USER		= 22,
+	DM_EVENT_MAX		= 23
+} dm_eventtype_t;
+#define HAVE_DM_EVENTTYPE_T
+
+typedef enum {
+	DM_RIGHT_NULL,
+	DM_RIGHT_SHARED,
+	DM_RIGHT_EXCL
+} dm_right_t;
+#define HAVE_DM_RIGHT_T
+
 /* Defines for determining if an event message should be sent. */
 #define DM_EVENT_ENABLED(vfsp, ip, event) ( \
 	unlikely ((vfsp)->vfs_flag & VFS_DMI) && \
@@ -61,21 +92,6 @@
 		  ((io)->io_mount->m_dmevmask & (1 << event)) ) \
 	)
 
-/*
- *	Macros to turn caller specified delay/block flags into
- *	dm_send_xxxx_event flag DM_FLAGS_NDELAY.
- */
-
-#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
-			DM_FLAGS_NDELAY : 0)
-#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
-
-
-
-/* events valid in dm_set_eventlist() when called with a filesystem handle.
-   These events are not persistent.
-*/
-
 #define DM_XFS_VALID_FS_EVENTS		( \
 	(1 << DM_EVENT_PREUNMOUNT)	| \
 	(1 << DM_EVENT_UNMOUNT)		| \
@@ -120,7 +136,6 @@
 	(1 << DM_EVENT_ATTRIBUTE)	| \
 	(1 << DM_EVENT_DESTROY)		)
 
-
 /* Events supported by the XFS filesystem. */
 #define DM_XFS_SUPPORTED_EVENTS		( \
 	(1 << DM_EVENT_MOUNT)		| \
@@ -144,162 +159,34 @@
 	(1 << DM_EVENT_DESTROY)		)
 
 
-extern int
-xfs_dm_mount(
-	vfs_t		*vfsp,
-	char		*dir_name,
-	char		*fsname);
-
-extern int
-xfs_dm_get_fsys_vector(
-	bhv_desc_t	*bdp,
-	dm_fcntl_vector_t *vecrq);
-
-extern int
-xfs_dm_send_data_event(
-	dm_eventtype_t	event,
-	bhv_desc_t	*bdp,
-	xfs_off_t	offset,
-	size_t		length,
-	int		flags,
-	vrwlock_t	*locktype);
-
-extern int
-xfs_dm_send_mmap_event(
-	struct vm_area_struct *vma,
-	unsigned int	wantflag);
-
-#else /* CONFIG_XFS_DMAPI */
-
-/*
- *	Flags needed to build with dmapi disabled.
- */
-
-typedef enum {
-	DM_EVENT_INVALID	= -1,
-	DM_EVENT_CANCEL		= 0,		/* not supported */
-	DM_EVENT_MOUNT		= 1,
-	DM_EVENT_PREUNMOUNT	= 2,
-	DM_EVENT_UNMOUNT	= 3,
-	DM_EVENT_DEBUT		= 4,		/* not supported */
-	DM_EVENT_CREATE		= 5,
-	DM_EVENT_CLOSE		= 6,		/* not supported */
-	DM_EVENT_POSTCREATE	= 7,
-	DM_EVENT_REMOVE		= 8,
-	DM_EVENT_POSTREMOVE	= 9,
-	DM_EVENT_RENAME		= 10,
-	DM_EVENT_POSTRENAME	= 11,
-	DM_EVENT_LINK		= 12,
-	DM_EVENT_POSTLINK	= 13,
-	DM_EVENT_SYMLINK	= 14,
-	DM_EVENT_POSTSYMLINK	= 15,
-	DM_EVENT_READ		= 16,
-	DM_EVENT_WRITE		= 17,
-	DM_EVENT_TRUNCATE	= 18,
-	DM_EVENT_ATTRIBUTE	= 19,
-	DM_EVENT_DESTROY	= 20,
-	DM_EVENT_NOSPACE	= 21,
-	DM_EVENT_USER		= 22,
-	DM_EVENT_MAX		= 23
-} dm_eventtype_t;
-
-typedef enum {
-	DM_RIGHT_NULL,
-	DM_RIGHT_SHARED,
-	DM_RIGHT_EXCL
-} dm_right_t;
-
-/*
- *	Defines for determining if an event message should be sent.
- */
-#define DM_EVENT_ENABLED(vfsp, ip, event)	0
-#define DM_EVENT_ENABLED_IO(vfsp, io, event)	0
-
 /*
- *	Stubbed out DMAPI delay macros.
+ *	Definitions used for the flags field on dm_send_*_event().
  */
 
-#define FILP_DELAY_FLAG(filp)			0
-#define AT_DELAY_FLAG(f)			0
+#define DM_FLAGS_NDELAY		0x001	/* return EAGAIN after dm_pending() */
+#define DM_FLAGS_UNWANTED	0x002	/* event not in fsys dm_eventset_t */
 
 /*
- *	Events supported by the XFS filesystem.
+ *	Macros to turn caller specified delay/block flags into
+ *	dm_send_xxxx_event flag DM_FLAGS_NDELAY.
  */
 
-#define DM_XFS_VALID_FS_EVENTS			0
-#define DM_XFS_VALID_FILE_EVENTS		0
-#define DM_XFS_VALID_DIRECTORY_EVENTS		0
-#define DM_XFS_SUPPORTED_EVENTS			0
+#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
+			DM_FLAGS_NDELAY : 0)
+#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
 
 /*
- *	Dummy definitions used for the flags field on dm_send_*_event().
+ *	Macros to turn caller specified delay/block flags into
+ *	dm_send_xxxx_event flag DM_FLAGS_NDELAY.
  */
 
-#define DM_FLAGS_NDELAY		0x001	/* return EAGAIN after dm_pending() */
-#define DM_FLAGS_UNWANTED	0x002	/* event not in fsys dm_eventset_t */
-
-/*
- *	Stubs for XFS DMAPI utility routines.
- */
+#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
+			DM_FLAGS_NDELAY : 0)
 
-static __inline int
-xfs_dm_send_data_event(
-	dm_eventtype_t	event,
-	bhv_desc_t	*bdp,
-	xfs_off_t	offset,
-	size_t		length,
-	int		flags,
-	vrwlock_t	*locktype)
-{
-	return ENOSYS;
-}
-
-static __inline int
-xfs_dm_send_mmap_event(
-	struct vm_area_struct *vma,
-	unsigned int	wantflag)
-{
-	return 0;
-}
 
-/*
- *	Stubs for routines needed for the X/Open version of DMAPI.
- */
+extern struct bhv_vfsops xfs_dmops;
 
-static __inline int
-dm_send_destroy_event(
-	bhv_desc_t	*bdp,
-	dm_right_t	vp_right)
-{
-	return ENOSYS;
-}
-
-static __inline int
-dm_send_namesp_event(
-	dm_eventtype_t	event,
-	bhv_desc_t	*bdp1,
-	dm_right_t	vp1_right,
-	bhv_desc_t	*bdp2,
-	dm_right_t	vp2_right,
-	char		*name1,
-	char		*name2,
-	mode_t		mode,
-	int		retcode,
-	int		flags)
-{
-	return ENOSYS;
-}
-
-static __inline void
-dm_send_unmount_event(
-	vfs_t		*vfsp,
-	vnode_t		*vp,
-	dm_right_t	vfsp_right,
-	mode_t		mode,
-	int		retcode,
-	int		flags)
-{
-}
+extern void xfs_dm_init(void);
+extern void xfs_dm_exit(void);
 
-#endif	/* CONFIG_XFS_DMAPI */
 #endif	/* __XFS_DMAPI_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dmops.c linux-2.5.66-bk3/fs/xfs/xfs_dmops.c
--- linux-2.5.66-bk2/fs/xfs/xfs_dmops.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/xfs_dmops.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <xfs.h>
+
+#ifndef CONFIG_XFS_DMAPI
+xfs_dmops_t	xfs_dmcore_xfs = {
+	.xfs_send_data		= (xfs_send_data_t)fs_nosys,
+	.xfs_send_mmap		= (xfs_send_mmap_t)fs_noerr,
+	.xfs_send_destroy	= (xfs_send_destroy_t)fs_nosys,
+	.xfs_send_namesp	= (xfs_send_namesp_t)fs_nosys,
+	.xfs_send_unmount	= (xfs_send_unmount_t)fs_noval,
+};
+#endif /* CONFIG_XFS_DMAPI */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dqblk.h linux-2.5.66-bk3/fs/xfs/xfs_dqblk.h
--- linux-2.5.66-bk2/fs/xfs/xfs_dqblk.h	Mon Mar 24 14:01:20 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dqblk.h	Wed Dec 31 16:00:00 1969
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_DQBLK_H__
-#define __XFS_DQBLK_H__
-
-/*
- * The ondisk form of a dquot structure.
- */
-#define XFS_DQUOT_MAGIC		0x4451		/* 'DQ' */
-#define XFS_DQUOT_VERSION	(u_int8_t)0x01	/* latest version number */
-
-/*
- * This is the main portion of the on-disk representation of quota
- * information for a user. This is the q_core of the xfs_dquot_t that
- * is kept in kernel memory. We pad this with some more expansion room
- * to construct the on disk structure.
- */
-typedef struct	xfs_disk_dquot {
-/*16*/	u_int16_t	d_magic;	/* dquot magic = XFS_DQUOT_MAGIC */
-/*8 */	u_int8_t	d_version;	/* dquot version */
-/*8 */	u_int8_t	d_flags;	/* XFS_DQ_USER/PROJ/GROUP */
-/*32*/	xfs_dqid_t	d_id;		/* user,project,group id */
-/*64*/	xfs_qcnt_t	d_blk_hardlimit;/* absolute limit on disk blks */
-/*64*/	xfs_qcnt_t	d_blk_softlimit;/* preferred limit on disk blks */
-/*64*/	xfs_qcnt_t	d_ino_hardlimit;/* maximum # allocated inodes */
-/*64*/	xfs_qcnt_t	d_ino_softlimit;/* preferred inode limit */
-/*64*/	xfs_qcnt_t	d_bcount;	/* disk blocks owned by the user */
-/*64*/	xfs_qcnt_t	d_icount;	/* inodes owned by the user */
-/*32*/	__int32_t	d_itimer;	/* zero if within inode limits if not,
-					   this is when we refuse service */
-/*32*/	__int32_t	d_btimer;	/* similar to above; for disk blocks */
-/*16*/	xfs_qwarncnt_t	d_iwarns;	/* warnings issued wrt num inodes */
-/*16*/	xfs_qwarncnt_t	d_bwarns;	/* warnings issued wrt disk blocks */
-/*32*/	__int32_t	d_pad0;		/* 64 bit align */
-/*64*/	xfs_qcnt_t	d_rtb_hardlimit;/* absolute limit on realtime blks */
-/*64*/	xfs_qcnt_t	d_rtb_softlimit;/* preferred limit on RT disk blks */
-/*64*/	xfs_qcnt_t	d_rtbcount;	/* realtime blocks owned */
-/*32*/	__int32_t	d_rtbtimer;	/* similar to above; for RT disk blocks */
-/*16*/	xfs_qwarncnt_t	d_rtbwarns;	/* warnings issued wrt RT disk blocks */
-/*16*/	__uint16_t	d_pad;
-} xfs_disk_dquot_t;
-
-/*
- * This is what goes on disk. This is separated from the xfs_disk_dquot because
- * carrying the unnecessary padding would be a waste of memory.
- */
-typedef struct xfs_dqblk {
-	xfs_disk_dquot_t  dd_diskdq;	/* portion that lives incore as well */
-	char		  dd_fill[32];	/* filling for posterity */
-} xfs_dqblk_t;
-
-/*
- * flags for q_flags field in the dquot.
- */
-#define XFS_DQ_USER		0x0001		/* a user quota */
-/* #define XFS_DQ_PROJ		0x0002		-- project quota (IRIX) */
-#define XFS_DQ_GROUP		0x0004		/* a group quota */
-#define XFS_DQ_FLOCKED		0x0008		/* flush lock taken */
-#define XFS_DQ_DIRTY		0x0010		/* dquot is dirty */
-#define XFS_DQ_WANT		0x0020		/* for lookup/reclaim race */
-#define XFS_DQ_INACTIVE		0x0040		/* dq off mplist & hashlist */
-#define XFS_DQ_MARKER		0x0080		/* sentinel */
-
-/*
- * In the worst case, when both user and group quotas are on,
- * we can have a max of three dquots changing in a single transaction.
- */
-#define XFS_DQUOT_LOGRES(mp)	(sizeof(xfs_disk_dquot_t) * 3)
-
-#endif	/* __XFS_DQBLK_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dquot.c linux-2.5.66-bk3/fs/xfs/xfs_dquot.c
--- linux-2.5.66-bk2/fs/xfs/xfs_dquot.c	Mon Mar 24 14:00:21 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dquot.c	Wed Dec 31 16:00:00 1969
@@ -1,1660 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
-   LOCK ORDER
-
-   inode lock		    (ilock)
-   dquot hash-chain lock    (hashlock)
-   xqm dquot freelist lock  (freelistlock
-   mount's dquot list lock  (mplistlock)
-   user dquot lock - lock ordering among dquots is based on the uid or gid
-   group dquot lock - similar to udquots. Between the two dquots, the udquot
-		      has to be locked first.
-   pin lock - the dquot lock must be held to take this lock.
-   flush lock - ditto.
-*/
-
-STATIC void		xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
-
-#ifdef DEBUG
-dev_t xfs_dqerror_dev = 0;
-int xfs_do_dqerror = 0;
-int xfs_dqreq_num = 0;
-int xfs_dqerror_mod = 33;
-#endif
-
-/*
- * Allocate and initialize a dquot. We don't always allocate fresh memory;
- * we try to reclaim a free dquot if the number of incore dquots are above
- * a threshold.
- * The only field inside the core that gets initialized at this point
- * is the d_id field. The idea is to fill in the entire q_core
- * when we read in the on disk dquot.
- */
-xfs_dquot_t *
-xfs_qm_dqinit(
-	xfs_mount_t  *mp,
-	xfs_dqid_t   id,
-	uint	     type)
-{
-	xfs_dquot_t	*dqp;
-	boolean_t	brandnewdquot;
-
-	brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
-	dqp->dq_flags = type;
-	INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id);
-	dqp->q_mount = mp;
-
-	/*
-	 * No need to re-initialize these if this is a reclaimed dquot.
-	 */
-	if (brandnewdquot) {
-		dqp->dq_flnext = dqp->dq_flprev = dqp;
-		mutex_init(&dqp->q_qlock,  MUTEX_DEFAULT, "xdq");
-		initnsema(&dqp->q_flock, 1, "fdq");
-		sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
-
-#ifdef DQUOT_TRACING
-		dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);
-		xfs_dqtrace_entry(dqp, "DQINIT");
-#endif
-	} else {
-		/*
-		 * Only the q_core portion was zeroed in dqreclaim_one().
-		 * So, we need to reset others.
-		 */
-		 dqp->q_nrefs = 0;
-		 dqp->q_blkno = 0;
-		 dqp->MPL_NEXT = dqp->HL_NEXT = NULL;
-		 dqp->HL_PREVP = dqp->MPL_PREVP = NULL;
-		 dqp->q_bufoffset = 0;
-		 dqp->q_fileoffset = 0;
-		 dqp->q_transp = NULL;
-		 dqp->q_gdquot = NULL;
-		 dqp->q_res_bcount = 0;
-		 dqp->q_res_icount = 0;
-		 dqp->q_res_rtbcount = 0;
-		 dqp->q_pincount = 0;
-		 dqp->q_hash = 0;
-		 ASSERT(dqp->dq_flnext == dqp->dq_flprev);
-
-#ifdef DQUOT_TRACING
-		 ASSERT(dqp->q_trace);
-		 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
-#endif
-	 }
-
-	/*
-	 * log item gets initialized later
-	 */
-	return (dqp);
-}
-
-/*
- * This is called to free all the memory associated with a dquot
- */
-void
-xfs_qm_dqdestroy(
-	xfs_dquot_t	*dqp)
-{
-	ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));
-
-	mutex_destroy(&dqp->q_qlock);
-	freesema(&dqp->q_flock);
-	sv_destroy(&dqp->q_pinwait);
-
-#ifdef DQUOT_TRACING
-	if (dqp->q_trace)
-	     ktrace_free(dqp->q_trace);
-	dqp->q_trace = NULL;
-#endif
-	kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
-	atomic_dec(&xfs_Gqm->qm_totaldquots);
-}
-
-/*
- * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
- */
-STATIC void
-xfs_qm_dqinit_core(
-	xfs_dqid_t	 id,
-	uint		 type,
-	xfs_dqblk_t	 *d)
-{
-	/*
-	 * Caller has zero'd the entire dquot 'chunk' already.
-	 */
-	INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
-	INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
-	INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
-	INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
-}
-
-
-#ifdef DQUOT_TRACING
-/*
- * Dquot tracing for debugging.
- */
-/* ARGSUSED */
-void
-xfs_dqtrace_entry__(
-	xfs_dquot_t *dqp,
-	char *func,
-	void *retaddr,
-	xfs_inode_t *ip)
-{
-	xfs_dquot_t *udqp = NULL;
-	int ino;
-
-	ASSERT(dqp->q_trace);
-	if (ip) {
-		ino = ip->i_ino;
-		udqp = ip->i_udquot;
-	}
-	ktrace_enter(dqp->q_trace,
-		     (void *)(__psint_t)DQUOT_KTRACE_ENTRY,
-		     (void *)func,
-		     (void *)(__psint_t)dqp->q_nrefs,
-		     (void *)(__psint_t)dqp->dq_flags,
-		     (void *)(__psint_t)dqp->q_res_bcount,
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
-		     (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */
-		     (void *)(__psint_t)current_pid(),
-		     (void *)(__psint_t)ino,
-		     (void *)(__psint_t)retaddr,
-		     (void *)(__psint_t)udqp);
-	return;
-}
-#endif
-
-
-/*
- * Check the limits and timers of a dquot and start or reset timers
- * if necessary.
- * This gets called even when quota enforcement is OFF, which makes our
- * life a little less complicated. (We just don't reject any quota
- * reservations in that case, when enforcement is off).
- * We also return 0 as the values of the timers in Q_GETQUOTA calls, when
- * enforcement's off.
- * In contrast, warnings are a little different in that they don't
- * 'automatically' get started when limits get exceeded.
- */
-void
-xfs_qm_adjust_dqtimers(
-	xfs_mount_t		*mp,
-	xfs_disk_dquot_t	*d)
-{
-	/*
-	 * The dquot had better be locked. We are modifying it here.
-	 */
-
-	/*
-	 * root's limits are not real limits.
-	 */
-	if (INT_ISZERO(d->d_id, ARCH_CONVERT))
-		return;
-
-#ifdef QUOTADEBUG
-	if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT))
-		ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT));
-	if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT))
-		ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT));
-#endif
-	if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) {
-		if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
-		    (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) ||
-		    (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) &&
-		    (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
-			INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp));
-		}
-	} else {
-		if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
-		    (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) &&
-		    (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) ||
-		    (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
-			INT_ZERO(d->d_btimer, ARCH_CONVERT);
-		}
-	}
-
-	if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) {
-		if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) &&
-		    (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) ||
-		    (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) &&
-		    (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
-			INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp));
-		}
-	} else {
-		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) ||
-		    (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT)))  &&
-		    (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) ||
-		    (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
-			INT_ZERO(d->d_itimer, ARCH_CONVERT);
-		}
-	}
-}
-
-/*
- * Increment or reset warnings of a given dquot.
- */
-int
-xfs_qm_dqwarn(
-	xfs_disk_dquot_t	*d,
-	uint			flags)
-{
-	int	warned;
-
-	/*
-	 * root's limits are not real limits.
-	 */
-	if (INT_ISZERO(d->d_id, ARCH_CONVERT))
-		return (0);
-
-	warned = 0;
-	if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
-	    (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
-		if (flags & XFS_QMOPT_DOWARN) {
-			INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
-			warned++;
-		}
-	} else {
-		if (INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
-		    (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
-			INT_ZERO(d->d_bwarns, ARCH_CONVERT);
-		}
-	}
-
-	if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
-	    (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
-		if (flags & XFS_QMOPT_DOWARN) {
-			INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
-			warned++;
-		}
-	} else {
-		if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) ||
-		    (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
-			INT_ZERO(d->d_iwarns, ARCH_CONVERT);
-		}
-	}
-#ifdef QUOTADEBUG
-	if (INT_GET(d->d_iwarns, ARCH_CONVERT))
-		printk("--------@@Inode warnings running : %Lu >= %Lu\n",
-		       INT_GET(d->d_icount, ARCH_CONVERT), INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
-	if (INT_GET(d->d_bwarns, ARCH_CONVERT))
-		printk("--------@@Blks warnings running : %Lu >= %Lu\n",
-		       INT_GET(d->d_bcount, ARCH_CONVERT), INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
-#endif
-	return (warned);
-}
-
-
-/*
- * initialize a buffer full of dquots and log the whole thing
- */
-STATIC void
-xfs_qm_init_dquot_blk(
-	xfs_trans_t	*tp,
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,
-	uint		type,
-	xfs_buf_t	*bp)
-{
-	xfs_dqblk_t	*d;
-	int		curid, i;
-
-	ASSERT(tp);
-	ASSERT(XFS_BUF_ISBUSY(bp));
-	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-
-	d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
-
-	/*
-	 * ID of the first dquot in the block - id's are zero based.
-	 */
-	curid = id - (id % XFS_QM_DQPERBLK(mp));
-	ASSERT(curid >= 0);
-	memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
-	for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
-		xfs_qm_dqinit_core(curid, type, d);
-	xfs_trans_dquot_buf(tp, bp,
-			    type & XFS_DQ_USER ?
-			    XFS_BLI_UDQUOT_BUF :
-			    XFS_BLI_GDQUOT_BUF);
-	xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
-}
-
-
-
-/*
- * Allocate a block and fill it with dquots.
- * This is called when the bmapi finds a hole.
- */
-STATIC int
-xfs_qm_dqalloc(
-	xfs_trans_t	*tp,
-	xfs_mount_t	*mp,
-	xfs_dquot_t	*dqp,
-	xfs_inode_t	*quotip,
-	xfs_fileoff_t	offset_fsb,
-	xfs_buf_t	**O_bpp)
-{
-	xfs_fsblock_t	firstblock;
-	xfs_bmap_free_t flist;
-	xfs_bmbt_irec_t map;
-	int		nmaps, error, committed;
-	xfs_buf_t	*bp;
-
-	ASSERT(tp != NULL);
-	xfs_dqtrace_entry(dqp, "DQALLOC");
-
-	/*
-	 * Initialize the bmap freelist prior to calling bmapi code.
-	 */
-	XFS_BMAP_INIT(&flist, &firstblock);
-	xfs_ilock(quotip, XFS_ILOCK_EXCL);
-	/*
-	 * Return if this type of quotas is turned off while we didn't
-	 * have an inode lock
-	 */
-	if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
-		xfs_iunlock(quotip, XFS_ILOCK_EXCL);
-		return (ESRCH);
-	}
-
-	/*
-	 * xfs_trans_commit normally decrements the vnode ref count
-	 * when it unlocks the inode. Since we want to keep the quota
-	 * inode around, we bump the vnode ref count now.
-	 */
-	VN_HOLD(XFS_ITOV(quotip));
-
-	xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
-	nmaps = 1;
-	if ((error = xfs_bmapi(tp, quotip,
-			      offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
-			      XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
-			      &firstblock,
-			      XFS_QM_DQALLOC_SPACE_RES(mp),
-			      &map, &nmaps, &flist))) {
-		goto error0;
-	}
-	ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
-	ASSERT(nmaps == 1);
-	ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
-	       (map.br_startblock != HOLESTARTBLOCK));
-
-	/*
-	 * Keep track of the blkno to save a lookup later
-	 */
-	dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
-
-	/* now we can just get the buffer (there's nothing to read yet) */
-	bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
-			       dqp->q_blkno,
-			       XFS_QI_DQCHUNKLEN(mp),
-			       0);
-	if (!bp || (error = XFS_BUF_GETERROR(bp)))
-		goto error1;
-	/*
-	 * Make a chunk of dquots out of this buffer and log
-	 * the entire thing.
-	 */
-	xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
-			      dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
-			      bp);
-
-	if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
-		goto error1;
-	}
-
-	*O_bpp = bp;
-	return 0;
-
-      error1:
-	xfs_bmap_cancel(&flist);
-      error0:
-	xfs_iunlock(quotip, XFS_ILOCK_EXCL);
-
-	return (error);
-}
-
-/*
- * Maps a dquot to the buffer containing its on-disk version.
- * This returns a ptr to the buffer containing the on-disk dquot
- * in the bpp param, and a ptr to the on-disk dquot within that buffer
- */
-STATIC int
-xfs_qm_dqtobp(
-	xfs_trans_t		*tp,
-	xfs_dquot_t		*dqp,
-	xfs_disk_dquot_t	**O_ddpp,
-	xfs_buf_t		**O_bpp,
-	uint			flags)
-{
-	xfs_bmbt_irec_t map;
-	int		nmaps, error;
-	xfs_buf_t	*bp;
-	xfs_inode_t	*quotip;
-	xfs_mount_t	*mp;
-	xfs_disk_dquot_t *ddq;
-	xfs_dqid_t	id;
-	boolean_t	newdquot;
-
-	mp = dqp->q_mount;
-	id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
-	nmaps = 1;
-	newdquot = B_FALSE;
-
-	/*
-	 * If we don't know where the dquot lives, find out.
-	 */
-	if (dqp->q_blkno == (xfs_daddr_t) 0) {
-		/* We use the id as an index */
-		dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id /
-						     XFS_QM_DQPERBLK(mp));
-		nmaps = 1;
-		quotip = XFS_DQ_TO_QIP(dqp);
-		xfs_ilock(quotip, XFS_ILOCK_SHARED);
-		/*
-		 * Return if this type of quotas is turned off while we didn't
-		 * have an inode lock
-		 */
-		if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
-			xfs_iunlock(quotip, XFS_ILOCK_SHARED);
-			return (ESRCH);
-		}
-		/*
-		 * Find the block map; no allocations yet
-		 */
-		error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
-				  XFS_DQUOT_CLUSTER_SIZE_FSB,
-				  XFS_BMAPI_METADATA,
-				  NULL, 0, &map, &nmaps, NULL);
-
-		xfs_iunlock(quotip, XFS_ILOCK_SHARED);
-		if (error)
-			return (error);
-		ASSERT(nmaps == 1);
-		ASSERT(map.br_blockcount == 1);
-
-		/*
-		 * offset of dquot in the (fixed sized) dquot chunk.
-		 */
-		dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *
-			sizeof(xfs_dqblk_t);
-		if (map.br_startblock == HOLESTARTBLOCK) {
-			/*
-			 * We don't allocate unless we're asked to
-			 */
-			if (!(flags & XFS_QMOPT_DQALLOC))
-				return (ENOENT);
-
-			ASSERT(tp);
-			if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
-						dqp->q_fileoffset, &bp)))
-				return (error);
-			newdquot = B_TRUE;
-		} else {
-			/*
-			 * store the blkno etc so that we don't have to do the
-			 * mapping all the time
-			 */
-			dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
-		}
-	}
-	ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
-	ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
-
-	/*
-	 * Read in the buffer, unless we've just done the allocation
-	 * (in which case we already have the buf).
-	 */
-	if (! newdquot) {
-		xfs_dqtrace_entry(dqp, "DQTOBP READBUF");
-		if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
-					       dqp->q_blkno,
-					       XFS_QI_DQCHUNKLEN(mp),
-					       0, &bp))) {
-			return (error);
-		}
-		if (error || !bp)
-			return XFS_ERROR(error);
-	}
-	ASSERT(XFS_BUF_ISBUSY(bp));
-	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-
-	/*
-	 * calculate the location of the dquot inside the buffer.
-	 */
-	ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
-
-	/*
-	 * A simple sanity check in case we got a corrupted dquot...
-	 */
-	if (xfs_qm_dqcheck(ddq, id,
-			   dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
-			   flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
-			   "dqtobp")) {
-		if (!(flags & XFS_QMOPT_DQREPAIR)) {
-			xfs_trans_brelse(tp, bp);
-			return XFS_ERROR(EIO);
-		}
-		XFS_BUF_BUSY(bp); /* We dirtied this */
-	}
-
-	*O_bpp = bp;
-	*O_ddpp = ddq;
-
-	return (0);
-}
-
-
-/*
- * Read in the ondisk dquot using dqtobp() then copy it to an incore version,
- * and release the buffer immediately.
- *
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_dqread(
-	xfs_trans_t	*tp,
-	xfs_dqid_t	id,
-	xfs_dquot_t	*dqp,	/* dquot to get filled in */
-	uint		flags)
-{
-	xfs_disk_dquot_t *ddqp;
-	xfs_buf_t	 *bp;
-	int		 error;
-
-	/*
-	 * get a pointer to the on-disk dquot and the buffer containing it
-	 * dqp already knows its own type (GROUP/USER).
-	 */
-	xfs_dqtrace_entry(dqp, "DQREAD");
-	if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
-		return (error);
-	}
-
-	/* copy everything from disk dquot to the incore dquot */
-	memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
-	ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
-	xfs_qm_dquot_logitem_init(dqp);
-
-	/*
-	 * Reservation counters are defined as reservation plus current usage
-	 * to avoid having to add everytime.
-	 */
-	dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT);
-	dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT);
-	dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT);
-
-	/* Mark the buf so that this will stay incore a little longer */
-	XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
-
-	/*
-	 * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
-	 * So we need to release with xfs_trans_brelse().
-	 * The strategy here is identical to that of inodes; we lock
-	 * the dquot in xfs_qm_dqget() before making it accessible to
-	 * others. This is because dquots, like inodes, need a good level of
-	 * concurrency, and we don't want to take locks on the entire buffers
-	 * for dquot accesses.
-	 * Note also that the dquot buffer may even be dirty at this point, if
-	 * this particular dquot was repaired. We still aren't afraid to
-	 * brelse it because we have the changes incore.
-	 */
-	ASSERT(XFS_BUF_ISBUSY(bp));
-	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-	xfs_trans_brelse(tp, bp);
-
-	return (error);
-}
-
-
-/*
- * allocate an incore dquot from the kernel heap,
- * and fill its core with quota information kept on disk.
- * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
- * if it wasn't already allocated.
- */
-STATIC int
-xfs_qm_idtodq(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,	 /* gid or uid, depending on type */
-	uint		type,	 /* UDQUOT or GDQUOT */
-	uint		flags,	 /* DQALLOC, DQREPAIR */
-	xfs_dquot_t	**O_dqpp)/* OUT : incore dquot, not locked */
-{
-	xfs_dquot_t	*dqp;
-	int		error;
-	xfs_trans_t	*tp;
-	int		cancelflags=0;
-
-	dqp = xfs_qm_dqinit(mp, id, type);
-	tp = NULL;
-	if (flags & XFS_QMOPT_DQALLOC) {
-		tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
-		if ((error = xfs_trans_reserve(tp,
-				       XFS_QM_DQALLOC_SPACE_RES(mp),
-				       XFS_WRITE_LOG_RES(mp) +
-					      BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +
-					      128,
-				       0,
-				       XFS_TRANS_PERM_LOG_RES,
-				       XFS_WRITE_LOG_COUNT))) {
-			cancelflags = 0;
-			goto error0;
-		}
-		cancelflags = XFS_TRANS_RELEASE_LOG_RES;
-	}
-
-	/*
-	 * Read it from disk; xfs_dqread() takes care of
-	 * all the necessary initialization of dquot's fields (locks, etc)
-	 */
-	if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
-		/*
-		 * This can happen if quotas got turned off (ESRCH),
-		 * or if the dquot didn't exist on disk and we ask to
-		 * allocate (ENOENT).
-		 */
-		xfs_dqtrace_entry(dqp, "DQREAD FAIL");
-		cancelflags |= XFS_TRANS_ABORT;
-		goto error0;
-	}
-	if (tp) {
-		if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-					     NULL)))
-			goto error1;
-	}
-
-	*O_dqpp = dqp;
-	ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-	return (0);
-
- error0:
-	ASSERT(error);
-	if (tp)
-		xfs_trans_cancel(tp, cancelflags);
- error1:
-	xfs_qm_dqdestroy(dqp);
-	*O_dqpp = NULL;
-	return (error);
-}
-
-/*
- * Lookup a dquot in the incore dquot hashtable. We keep two separate
- * hashtables for user and group dquots; and, these are global tables
- * inside the XQM, not per-filesystem tables.
- * The hash chain must be locked by caller, and it is left locked
- * on return. Returning dquot is locked.
- */
-STATIC int
-xfs_qm_dqlookup(
-	xfs_mount_t		*mp,
-	xfs_dqid_t		id,
-	xfs_dqhash_t		*qh,
-	xfs_dquot_t		**O_dqpp)
-{
-	xfs_dquot_t		*dqp;
-	uint			flist_locked;
-	xfs_dquot_t		*d;
-
-	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-
-	flist_locked = B_FALSE;
-
-	/*
-	 * Traverse the hashchain looking for a match
-	 */
-	for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {
-		/*
-		 * We already have the hashlock. We don't need the
-		 * dqlock to look at the id field of the dquot, since the
-		 * id can't be modified without the hashlock anyway.
-		 */
-		if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) {
-			xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");
-			/*
-			 * All in core dquots must be on the dqlist of mp
-			 */
-			ASSERT(dqp->MPL_PREVP != NULL);
-
-			xfs_dqlock(dqp);
-			if (dqp->q_nrefs == 0) {
-				ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));
-				if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
-					xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");
-
-					/*
-					 * We may have raced with dqreclaim_one()
-					 * (and lost). So, flag that we don't
-					 * want the dquot to be reclaimed.
-					 */
-					dqp->dq_flags |= XFS_DQ_WANT;
-					xfs_dqunlock(dqp);
-					xfs_qm_freelist_lock(xfs_Gqm);
-					xfs_dqlock(dqp);
-					dqp->dq_flags &= ~(XFS_DQ_WANT);
-				}
-				flist_locked = B_TRUE;
-			}
-
-			/*
-			 * id couldn't have changed; we had the hashlock all
-			 * along
-			 */
-			ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
-
-			if (flist_locked) {
-				if (dqp->q_nrefs != 0) {
-					xfs_qm_freelist_unlock(xfs_Gqm);
-					flist_locked = B_FALSE;
-				} else {
-					/*
-					 * take it off the freelist
-					 */
-					xfs_dqtrace_entry(dqp,
-							"DQLOOKUP: TAKEOFF FL");
-					XQM_FREELIST_REMOVE(dqp);
-					/* xfs_qm_freelist_print(&(xfs_Gqm->
-							qm_dqfreelist),
-							"after removal"); */
-				}
-			}
-
-			/*
-			 * grab a reference
-			 */
-			XFS_DQHOLD(dqp);
-
-			if (flist_locked)
-				xfs_qm_freelist_unlock(xfs_Gqm);
-			/*
-			 * move the dquot to the front of the hashchain
-			 */
-			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-			if (dqp->HL_PREVP != &qh->qh_next) {
-				xfs_dqtrace_entry(dqp,
-						  "DQLOOKUP: HASH MOVETOFRONT");
-				if ((d = dqp->HL_NEXT))
-					d->HL_PREVP = dqp->HL_PREVP;
-				*(dqp->HL_PREVP) = d;
-				d = qh->qh_next;
-				d->HL_PREVP = &dqp->HL_NEXT;
-				dqp->HL_NEXT = d;
-				dqp->HL_PREVP = &qh->qh_next;
-				qh->qh_next = dqp;
-			}
-			xfs_dqtrace_entry(dqp, "LOOKUP END");
-			*O_dqpp = dqp;
-			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-			return (0);
-		}
-	}
-
-	*O_dqpp = NULL;
-	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-	return (1);
-}
-
-/*
- * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
- * a locked dquot, doing an allocation (if requested) as needed.
- * When both an inode and an id are given, the inode's id takes precedence.
- * That is, if the id changes while we don't hold the ilock inside this
- * function, the new dquot is returned, not necessarily the one requested
- * in the id argument.
- */
-int
-xfs_qm_dqget(
-	xfs_mount_t	*mp,
-	xfs_inode_t	*ip,	  /* locked inode (optional) */
-	xfs_dqid_t	id,	  /* gid or uid, depending on type */
-	uint		type,	  /* UDQUOT or GDQUOT */
-	uint		flags,	  /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
-	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */
-{
-	xfs_dquot_t	*dqp;
-	xfs_dqhash_t	*h;
-	uint		version;
-	int		error;
-
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-	if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
-	    (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
-		return (ESRCH);
-	}
-	h = XFS_DQ_HASH(mp, id, type);
-
-#ifdef DEBUG
-	if (xfs_do_dqerror) {
-		if ((xfs_dqerror_dev == mp->m_dev) &&
-		    (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
-			printk("Returning error in dqget\n");
-			return (EIO);
-		}
-	}
-#endif
-
- again:
-
-#ifdef DEBUG
-	ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
-	if (ip) {
-		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-		if (type == XFS_DQ_USER)
-			ASSERT(ip->i_udquot == NULL);
-		else
-			ASSERT(ip->i_gdquot == NULL);
-	}
-#endif
-	XFS_DQ_HASH_LOCK(h);
-
-	/*
-	 * Look in the cache (hashtable).
-	 * The chain is kept locked during lookup.
-	 */
-	if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
-		XFS_STATS_INC(xfsstats.xs_qm_dqcachehits);
-		/*
-		 * The dquot was found, moved to the front of the chain,
-		 * taken off the freelist if it was on it, and locked
-		 * at this point. Just unlock the hashchain and return.
-		 */
-		ASSERT(*O_dqpp);
-		ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
-		XFS_DQ_HASH_UNLOCK(h);
-		xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
-		return (0);	/* success */
-	}
-	XFS_STATS_INC(xfsstats.xs_qm_dqcachemisses);
-
-	/*
-	 * Dquot cache miss. We don't want to keep the inode lock across
-	 * a (potential) disk read. Also we don't want to deal with the lock
-	 * ordering between quotainode and this inode. OTOH, dropping the inode
-	 * lock here means dealing with a chown that can happen before
-	 * we re-acquire the lock.
-	 */
-	if (ip)
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-	/*
-	 * Save the hashchain version stamp, and unlock the chain, so that
-	 * we don't keep the lock across a disk read
-	 */
-	version = h->qh_version;
-	XFS_DQ_HASH_UNLOCK(h);
-
-	/*
-	 * Allocate the dquot on the kernel heap, and read the ondisk
-	 * portion off the disk. Also, do all the necessary initialization
-	 * This can return ENOENT if dquot didn't exist on disk and we didn't
-	 * ask it to allocate; ESRCH if quotas got turned off suddenly.
-	 */
-	if ((error = xfs_qm_idtodq(mp, id, type,
-				  flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
-					   XFS_QMOPT_DOWARN),
-				  &dqp))) {
-		if (ip)
-			xfs_ilock(ip, XFS_ILOCK_EXCL);
-		return (error);
-	}
-
-	/*
-	 * See if this is mount code calling to look at the overall quota limits
-	 * which are stored in the id == 0 user or group's dquot.
-	 * Since we may not have done a quotacheck by this point, just return
-	 * the dquot without attaching it to any hashtables, lists, etc, or even
-	 * taking a reference.
-	 * The caller must dqdestroy this once done.
-	 */
-	if (flags & XFS_QMOPT_DQSUSER) {
-		ASSERT(id == 0);
-		ASSERT(! ip);
-		goto dqret;
-	}
-
-	/*
-	 * Dquot lock comes after hashlock in the lock ordering
-	 */
-	ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-	if (ip) {
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		if (! XFS_IS_DQTYPE_ON(mp, type)) {
-			/* inode stays locked on return */
-			xfs_qm_dqdestroy(dqp);
-			return XFS_ERROR(ESRCH);
-		}
-		/*
-		 * A dquot could be attached to this inode by now, since
-		 * we had dropped the ilock.
-		 */
-		if (type == XFS_DQ_USER) {
-			if (ip->i_udquot) {
-				xfs_qm_dqdestroy(dqp);
-				dqp = ip->i_udquot;
-				xfs_dqlock(dqp);
-				goto dqret;
-			}
-		} else {
-			if (ip->i_gdquot) {
-				xfs_qm_dqdestroy(dqp);
-				dqp = ip->i_gdquot;
-				xfs_dqlock(dqp);
-				goto dqret;
-			}
-		}
-	}
-
-	/*
-	 * Hashlock comes after ilock in lock order
-	 */
-	XFS_DQ_HASH_LOCK(h);
-	if (version != h->qh_version) {
-		xfs_dquot_t *tmpdqp;
-		/*
-		 * Now, see if somebody else put the dquot in the
-		 * hashtable before us. This can happen because we didn't
-		 * keep the hashchain lock. We don't have to worry about
-		 * lock order between the two dquots here since dqp isn't
-		 * on any findable lists yet.
-		 */
-		if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
-			/*
-			 * Duplicate found. Just throw away the new dquot
-			 * and start over.
-			 */
-			xfs_qm_dqput(tmpdqp);
-			XFS_DQ_HASH_UNLOCK(h);
-			xfs_qm_dqdestroy(dqp);
-			XFS_STATS_INC(xfsstats.xs_qm_dquot_dups);
-			goto again;
-		}
-	}
-
-	/*
-	 * Put the dquot at the beginning of the hash-chain and mp's list
-	 * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
-	 */
-	ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
-	dqp->q_hash = h;
-	XQM_HASHLIST_INSERT(h, dqp);
-
-	/*
-	 * Attach this dquot to this filesystem's list of all dquots,
-	 * kept inside the mount structure in m_quotainfo field
-	 */
-	xfs_qm_mplist_lock(mp);
-
-	/*
-	 * We return a locked dquot to the caller, with a reference taken
-	 */
-	xfs_dqlock(dqp);
-	dqp->q_nrefs = 1;
-
-	XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
-
-	xfs_qm_mplist_unlock(mp);
-	XFS_DQ_HASH_UNLOCK(h);
- dqret:
-	ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
-	xfs_dqtrace_entry(dqp, "DQGET DONE");
-	*O_dqpp = dqp;
-	return (0);
-}
-
-
-/*
- * Release a reference to the dquot (decrement ref-count)
- * and unlock it. If there is a group quota attached to this
- * dquot, carefully release that too without tripping over
- * deadlocks'n'stuff.
- */
-void
-xfs_qm_dqput(
-	xfs_dquot_t	*dqp)
-{
-	xfs_dquot_t	*gdqp;
-
-	ASSERT(dqp->q_nrefs > 0);
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	xfs_dqtrace_entry(dqp, "DQPUT");
-
-	if (dqp->q_nrefs != 1) {
-		dqp->q_nrefs--;
-		xfs_dqunlock(dqp);
-		return;
-	}
-
-	/*
-	 * drop the dqlock and acquire the freelist and dqlock
-	 * in the right order; but try to get it out-of-order first
-	 */
-	if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
-		xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT");
-		xfs_dqunlock(dqp);
-		xfs_qm_freelist_lock(xfs_Gqm);
-		xfs_dqlock(dqp);
-	}
-
-	while (1) {
-		gdqp = NULL;
-
-		/* We can't depend on nrefs being == 1 here */
-		if (--dqp->q_nrefs == 0) {
-			xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST");
-			/*
-			 * insert at end of the freelist.
-			 */
-			XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp);
-
-			/*
-			 * If we just added a udquot to the freelist, then
-			 * we want to release the gdquot reference that
-			 * it (probably) has. Otherwise it'll keep the
-			 * gdquot from getting reclaimed.
-			 */
-			if ((gdqp = dqp->q_gdquot)) {
-				/*
-				 * Avoid a recursive dqput call
-				 */
-				xfs_dqlock(gdqp);
-				dqp->q_gdquot = NULL;
-			}
-
-			/* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist),
-			   "@@@@@++ Free list (after append) @@@@@+");
-			   */
-		}
-		xfs_dqunlock(dqp);
-
-		/*
-		 * If we had a group quota inside the user quota as a hint,
-		 * release it now.
-		 */
-		if (! gdqp)
-			break;
-		dqp = gdqp;
-	}
-	xfs_qm_freelist_unlock(xfs_Gqm);
-}
-
-/*
- * Release a dquot. Flush it if dirty, then dqput() it.
- * dquot must not be locked.
- */
-void
-xfs_qm_dqrele(
-	xfs_dquot_t	*dqp)
-{
-	ASSERT(dqp);
-	xfs_dqtrace_entry(dqp, "DQRELE");
-
-	xfs_dqlock(dqp);
-	/*
-	 * We don't care to flush it if the dquot is dirty here.
-	 * That will create stutters that we want to avoid.
-	 * Instead we do a delayed write when we try to reclaim
-	 * a dirty dquot. Also xfs_sync will take part of the burden...
-	 */
-	xfs_qm_dqput(dqp);
-}
-
-
-/*
- * Write a modified dquot to disk.
- * The dquot must be locked and the flush lock too taken by caller.
- * The flush lock will not be unlocked until the dquot reaches the disk,
- * but the dquot is free to be unlocked and modified by the caller
- * in the interim. Dquot is still locked on return. This behavior is
- * identical to that of inodes.
- */
-int
-xfs_qm_dqflush(
-	xfs_dquot_t		*dqp,
-	uint			flags)
-{
-	xfs_mount_t		*mp;
-	xfs_buf_t		*bp;
-	xfs_disk_dquot_t	*ddqp;
-	int			error;
-	SPLDECL(s);
-
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
-	xfs_dqtrace_entry(dqp, "DQFLUSH");
-
-	/*
-	 * If not dirty, nada.
-	 */
-	if (!XFS_DQ_IS_DIRTY(dqp)) {
-		xfs_dqfunlock(dqp);
-		return (0);
-	}
-
-	/*
-	 * Cant flush a pinned dquot. Wait for it.
-	 */
-	xfs_qm_dqunpin_wait(dqp);
-
-	/*
-	 * This may have been unpinned because the filesystem is shutting
-	 * down forcibly. If that's the case we must not write this dquot
-	 * to disk, because the log record didn't make it to disk!
-	 */
-	if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
-		dqp->dq_flags &= ~(XFS_DQ_DIRTY);
-		xfs_dqfunlock(dqp);
-		return XFS_ERROR(EIO);
-	}
-
-	/*
-	 * Get the buffer containing the on-disk dquot
-	 * We don't need a transaction envelope because we know that the
-	 * the ondisk-dquot has already been allocated for.
-	 */
-	if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
-		xfs_dqtrace_entry(dqp, "DQTOBP FAIL");
-		ASSERT(error != ENOENT);
-		/*
-		 * Quotas could have gotten turned off (ESRCH)
-		 */
-		xfs_dqfunlock(dqp);
-		return (error);
-	}
-
-	if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
-			   "dqflush (incore copy)")) {
-		xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
-		return XFS_ERROR(EIO);
-	}
-
-	/* This is the only portion of data that needs to persist */
-	memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
-
-	/*
-	 * Clear the dirty field and remember the flush lsn for later use.
-	 */
-	dqp->dq_flags &= ~(XFS_DQ_DIRTY);
-	mp = dqp->q_mount;
-
-	/* lsn is 64 bits */
-	AIL_LOCK(mp, s);
-	dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
-	AIL_UNLOCK(mp, s);
-
-	/*
-	 * Attach an iodone routine so that we can remove this dquot from the
-	 * AIL and release the flush lock once the dquot is synced to disk.
-	 */
-	xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
-			      xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
-	/*
-	 * If the buffer is pinned then push on the log so we won't
-	 * get stuck waiting in the write for too long.
-	 */
-	if (XFS_BUF_ISPINNED(bp)) {
-		xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE");
-		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-	}
-
-	if (flags & XFS_QMOPT_DELWRI) {
-		xfs_bdwrite(mp, bp);
-	} else if (flags & XFS_QMOPT_ASYNC) {
-		xfs_bawrite(mp, bp);
-	} else {
-		error = xfs_bwrite(mp, bp);
-	}
-	xfs_dqtrace_entry(dqp, "DQFLUSH END");
-	/*
-	 * dqp is still locked, but caller is free to unlock it now.
-	 */
-	return (error);
-
-}
-
-/*
- * This is the dquot flushing I/O completion routine.  It is called
- * from interrupt level when the buffer containing the dquot is
- * flushed to disk.  It is responsible for removing the dquot logitem
- * from the AIL if it has not been re-logged, and unlocking the dquot's
- * flush lock. This behavior is very similar to that of inodes..
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_dqflush_done(
-	xfs_buf_t		*bp,
-	xfs_dq_logitem_t	*qip)
-{
-	xfs_dquot_t		*dqp;
-	SPLDECL(s);
-
-	dqp = qip->qli_dquot;
-
-	/*
-	 * We only want to pull the item from the AIL if its
-	 * location in the log has not changed since we started the flush.
-	 * Thus, we only bother if the dquot's lsn has
-	 * not changed. First we check the lsn outside the lock
-	 * since it's cheaper, and then we recheck while
-	 * holding the lock before removing the dquot from the AIL.
-	 */
-	if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-	    qip->qli_item.li_lsn == qip->qli_flush_lsn) {
-
-		AIL_LOCK(dqp->q_mount, s);
-		/*
-		 * xfs_trans_delete_ail() drops the AIL lock.
-		 */
-		if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
-			xfs_trans_delete_ail(dqp->q_mount,
-					     (xfs_log_item_t*)qip, s);
-		else
-			AIL_UNLOCK(dqp->q_mount, s);
-	}
-
-	/*
-	 * Release the dq's flush lock since we're done with it.
-	 */
-	xfs_dqfunlock(dqp);
-}
-
-
-int
-xfs_qm_dqflock_nowait(
-	xfs_dquot_t *dqp)
-{
-	int locked;
-
-	locked = cpsema(&((dqp)->q_flock));
-
-	/* XXX ifdef these out */
-	if (locked)
-		(dqp)->dq_flags |= XFS_DQ_FLOCKED;
-	return (locked);
-}
-
-
-int
-xfs_qm_dqlock_nowait(
-	xfs_dquot_t *dqp)
-{
-	return (mutex_trylock(&((dqp)->q_qlock)));
-}
-
-void
-xfs_dqlock(
-	xfs_dquot_t *dqp)
-{
-	mutex_lock(&(dqp->q_qlock), PINOD);
-}
-
-void
-xfs_dqunlock(
-	xfs_dquot_t *dqp)
-{
-	mutex_unlock(&(dqp->q_qlock));
-	if (dqp->q_logitem.qli_dquot == dqp) {
-		/* Once was dqp->q_mount, but might just have been cleared */
-		xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
-					(xfs_log_item_t*)&(dqp->q_logitem));
-	}
-}
-
-
-void
-xfs_dqunlock_nonotify(
-	xfs_dquot_t *dqp)
-{
-	mutex_unlock(&(dqp->q_qlock));
-}
-
-void
-xfs_dqlock2(
-	xfs_dquot_t	*d1,
-	xfs_dquot_t	*d2)
-{
-	if (d1 && d2) {
-		ASSERT(d1 != d2);
-		if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
-			xfs_dqlock(d2);
-			xfs_dqlock(d1);
-		} else {
-			xfs_dqlock(d1);
-			xfs_dqlock(d2);
-		}
-	} else {
-		if (d1) {
-			xfs_dqlock(d1);
-		} else if (d2) {
-			xfs_dqlock(d2);
-		}
-	}
-}
-
-
-/*
- * A rarely used accessor. This exists because we don't really want
- * to expose the internals of a dquot to the outside world.
- */
-xfs_dqid_t
-xfs_qm_dqid(
-	xfs_dquot_t	*dqp)
-{
-	return (INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-}
-
-
-/*
- * Take a dquot out of the mount's dqlist as well as the hashlist.
- * This is called via unmount as well as quotaoff, and the purge
- * will always succeed unless there are soft (temp) references
- * outstanding.
- *
- * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
- * that we're returning! XXXsup - not cool.
- */
-/* ARGSUSED */
-int
-xfs_qm_dqpurge(
-	xfs_dquot_t	*dqp,
-	uint		flags)
-{
-	xfs_dqhash_t	*thishash;
-	xfs_mount_t	*mp;
-
-	mp = dqp->q_mount;
-
-	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-	ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
-
-	xfs_dqlock(dqp);
-	/*
-	 * We really can't afford to purge a dquot that is
-	 * referenced, because these are hard refs.
-	 * It shouldn't happen in general because we went thru _all_ inodes in
-	 * dqrele_all_inodes before calling this and didn't let the mountlock go.
-	 * However it is possible that we have dquots with temporary
-	 * references that are not attached to an inode. e.g. see xfs_setattr().
-	 */
-	if (dqp->q_nrefs != 0) {
-		xfs_dqunlock(dqp);
-		XFS_DQ_HASH_UNLOCK(dqp->q_hash);
-		return (1);
-	}
-
-	ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
-
-	/*
-	 * If we're turning off quotas, we have to make sure that, for
-	 * example, we don't delete quota disk blocks while dquots are
-	 * in the process of getting written to those disk blocks.
-	 * This dquot might well be on AIL, and we can't leave it there
-	 * if we're turning off quotas. Basically, we need this flush
-	 * lock, and are willing to block on it.
-	 */
-	if (! xfs_qm_dqflock_nowait(dqp)) {
-		/*
-		 * Block on the flush lock after nudging dquot buffer,
-		 * if it is incore.
-		 */
-		xfs_qm_dqflock_pushbuf_wait(dqp);
-	}
-
-	/*
-	 * XXXIf we're turning this type of quotas off, we don't care
-	 * about the dirty metadata sitting in this dquot. OTOH, if
-	 * we're unmounting, we do care, so we flush it and wait.
-	 */
-	if (XFS_DQ_IS_DIRTY(dqp)) {
-		xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY");
-		/* dqflush unlocks dqflock */
-		/*
-		 * Given that dqpurge is a very rare occurrence, it is OK
-		 * that we're holding the hashlist and mplist locks
-		 * across the disk write. But, ... XXXsup
-		 *
-		 * We don't care about getting disk errors here. We need
-		 * to purge this dquot anyway, so we go ahead regardless.
-		 */
-		(void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC);
-		xfs_dqflock(dqp);
-	}
-	ASSERT(dqp->q_pincount == 0);
-	ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
-	       !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
-
-	thishash = dqp->q_hash;
-	XQM_HASHLIST_REMOVE(thishash, dqp);
-	XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp);
-	/*
-	 * XXX Move this to the front of the freelist, if we can get the
-	 * freelist lock.
-	 */
-	ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
-
-	dqp->q_mount = NULL;;
-	dqp->q_hash = NULL;
-	dqp->dq_flags = XFS_DQ_INACTIVE;
-	memset(&dqp->q_core, 0, sizeof(dqp->q_core));
-	xfs_dqfunlock(dqp);
-	xfs_dqunlock(dqp);
-	XFS_DQ_HASH_UNLOCK(thishash);
-	return (0);
-}
-
-
-/*
- * Do some primitive error checking on ondisk dquot
- * data structures. Not just for debugging, actually;
- * this can be useful for detecting data corruption mainly due to
- * disk failures.
- */
-/* ARGSUSED */
-int
-xfs_qm_dqcheck(
-	xfs_disk_dquot_t *ddq,
-	xfs_dqid_t	 id,
-	uint		 type,	  /* used only when IO_dorepair is true */
-	uint		 flags,
-	char		 *str)
-{
-	int errs;
-
-	errs = 0;
-	/* ASSERT(flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN)); */
-	/*
-	 * We can encounter an uninitialized dquot buffer for 2 reasons:
-	 * 1. If we crash while deleting the quotainode(s), and those blks get used
-	 *    for some user data. This is because we take the path of regular
-	 *    file deletion; however, the size field of quotainodes is never
-	 *    updated, so all the tricks that we play in itruncate_finish
-	 *    don't quite matter.
-	 *
-	 * 2. We don't play the quota buffers when there's a quotaoff logitem.
-	 *    But the allocation will be replayed so we'll end up with an
-	 *    uninitialized quota block.
-	 *
-	 * This is all fine; things are still consistent, and we haven't lost
-	 * any quota information. Just don't complain about bad dquot blks.
-	 */
-	if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) {
-		if (flags & XFS_QMOPT_DOWARN)
-			cmn_err(CE_ALERT,
-			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
-			str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC);
-		errs++;
-	}
-	if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) {
-		if (flags & XFS_QMOPT_DOWARN)
-			cmn_err(CE_ALERT,
-			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
-			str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION);
-		errs++;
-	}
-
-	if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) {
-		if (flags & XFS_QMOPT_DOWARN)
-			cmn_err(CE_ALERT,
-			"%s : XFS dquot ID 0x%x, unknown flags 0x%x",
-			str, id, INT_GET(ddq->d_flags, ARCH_CONVERT));
-		errs++;
-	}
-
-	if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) {
-		if (flags & XFS_QMOPT_DOWARN)
-			cmn_err(CE_ALERT,
-			"%s : ondisk-dquot 0x%x, ID mismatch: "
-			"0x%x expected, found id 0x%x",
-			str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT));
-		errs++;
-	}
-
-	if (! errs) {
-		if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
-		    INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
-			if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
-				if (flags & XFS_QMOPT_DOWARN)
-					cmn_err(CE_ALERT,
-					"%s : Dquot ID 0x%x (0x%x) "
-					"BLK TIMER NOT STARTED",
-					str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
-				errs++;
-			}
-		}
-		if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
-		    INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
-			if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
-				if (flags & XFS_QMOPT_DOWARN)
-					cmn_err(CE_ALERT,
-					"%s : Dquot ID 0x%x (0x%x) "
-					"INODE TIMER NOT STARTED",
-					str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
-				errs++;
-			}
-		}
-	}
-
-	if (!errs || !(flags & XFS_QMOPT_DQREPAIR))
-		return (errs);
-
-	if (flags & XFS_QMOPT_DOWARN)
-		cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id);
-
-	/*
-	 * Typically, a repair is only requested by quotacheck.
-	 */
-	ASSERT(id != -1);
-	ASSERT(flags & XFS_QMOPT_DQREPAIR);
-	memset(ddq, 0, sizeof(xfs_dqblk_t));
-	xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq);
-	return (errs);
-}
-
-#ifdef QUOTADEBUG
-void
-xfs_qm_dqprint(xfs_dquot_t *dqp)
-{
-	printk( "-----------KERNEL DQUOT----------------\n");
-	printk( "---- dquot ID	=  %d\n", (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-	printk( "---- type	=  %s\n", XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
-	printk( "---- fs	=  0x%p\n", dqp->q_mount);
-	printk( "---- blkno	=  0x%x\n", (int) dqp->q_blkno);
-	printk( "---- boffset	=  0x%x\n", (int) dqp->q_bufoffset);
-	printk( "---- blkhlimit =  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
-	       (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT));
-	printk( "---- blkslimit =  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
-	       (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT));
-	printk( "---- inohlimit =  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
-	       (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT));
-	printk( "---- inoslimit =  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
-	       (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT));
-	printk( "---- bcount	=  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
-	       (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-	printk( "---- icount	=  %Lu (0x%x)\n",
-	       INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
-	       (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-	printk( "---- btimer	=  %d\n", (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT));
-	printk( "---- itimer	=  %d\n", (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT));
-
-	printk( "---------------------------\n");
-}
-#endif
-
-/*
- * Give the buffer a little push if it is incore and
- * wait on the flush lock.
- */
-void
-xfs_qm_dqflock_pushbuf_wait(
-	xfs_dquot_t	*dqp)
-{
-	xfs_buf_t	*bp;
-
-	/*
-	 * Check to see if the dquot has been flushed delayed
-	 * write.  If so, grab its buffer and send it
-	 * out immediately.  We'll be able to acquire
-	 * the flush lock when the I/O completes.
-	 */
-	bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
-		    XFS_QI_DQCHUNKLEN(dqp->q_mount),
-		    XFS_INCORE_TRYLOCK);
-	if (bp != NULL) {
-		if (XFS_BUF_ISDELAYWRITE(bp)) {
-			if (XFS_BUF_ISPINNED(bp)) {
-				xfs_log_force(dqp->q_mount,
-					      (xfs_lsn_t)0,
-					      XFS_LOG_FORCE);
-			}
-			xfs_bawrite(dqp->q_mount, bp);
-		} else {
-			xfs_buf_relse(bp);
-		}
-	}
-	xfs_dqflock(dqp);
-}
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dquot.h linux-2.5.66-bk3/fs/xfs/xfs_dquot.h
--- linux-2.5.66-bk2/fs/xfs/xfs_dquot.h	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dquot.h	Wed Dec 31 16:00:00 1969
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_DQUOT_H__
-#define __XFS_DQUOT_H__
-
-/*
- * Dquots are structures that hold quota information about a user or a group,
- * much like inodes are for files. In fact, dquots share many characteristics
- * with inodes. However, dquots can also be a centralized resource, relative
- * to a collection of inodes. In this respect, dquots share some characteristics
- * of the superblock.
- * XFS dquots exploit both those in its algorithms. They make every attempt
- * to not be a bottleneck when quotas are on and have minimal impact, if any,
- * when quotas are off.
- */
-
-/*
- * The hash chain headers (hash buckets)
- */
-typedef struct xfs_dqhash {
-	struct xfs_dquot *qh_next;
-	mutex_t		  qh_lock;
-	uint		  qh_version;	/* ever increasing version */
-	uint		  qh_nelems;	/* number of dquots on the list */
-} xfs_dqhash_t;
-
-typedef struct xfs_dqlink {
-	struct xfs_dquot  *ql_next;	/* forward link */
-	struct xfs_dquot **ql_prevp;	/* pointer to prev ql_next */
-} xfs_dqlink_t;
-
-struct xfs_mount;
-struct xfs_trans;
-
-/*
- * This is the marker which is designed to occupy the first few
- * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers
- * must come first.
- * This serves as the marker ("sentinel") when we have to restart list
- * iterations because of locking considerations.
- */
-typedef struct xfs_dqmarker {
-	struct xfs_dquot*dqm_flnext;	/* link to freelist: must be first */
-	struct xfs_dquot*dqm_flprev;
-	xfs_dqlink_t	 dqm_mplist;	/* link to mount's list of dquots */
-	xfs_dqlink_t	 dqm_hashlist;	/* link to the hash chain */
-	uint		 dqm_flags;	/* various flags (XFS_DQ_*) */
-} xfs_dqmarker_t;
-
-/*
- * The incore dquot structure
- */
-typedef struct xfs_dquot {
-	xfs_dqmarker_t	 q_lists;	/* list ptrs, q_flags (marker) */
-	xfs_dqhash_t	*q_hash;	/* the hashchain header */
-	struct xfs_mount*q_mount;	/* filesystem this relates to */
-	struct xfs_trans*q_transp;	/* trans this belongs to currently */
-	uint		 q_nrefs;	/* # active refs from inodes */
-	xfs_daddr_t	 q_blkno;	/* blkno of dquot buffer */
-	int		 q_bufoffset;	/* off of dq in buffer (# dquots) */
-	xfs_fileoff_t	 q_fileoffset;	/* offset in quotas file */
-
-	struct xfs_dquot*q_gdquot;	/* group dquot, hint only */
-	xfs_disk_dquot_t q_core;	/* actual usage & quotas */
-	xfs_dq_logitem_t q_logitem;	/* dquot log item */
-	xfs_qcnt_t	 q_res_bcount;	/* total regular nblks used+reserved */
-	xfs_qcnt_t	 q_res_icount;	/* total inos allocd+reserved */
-	xfs_qcnt_t	 q_res_rtbcount;/* total realtime blks used+reserved */
-	mutex_t		 q_qlock;	/* quota lock */
-	sema_t		 q_flock;	/* flush lock */
-	uint		 q_pincount;	/* pin count for this dquot */
-	sv_t		 q_pinwait;	/* sync var for pinning */
-#ifdef DQUOT_TRACING
-	struct ktrace	*q_trace;	/* trace header structure */
-#endif
-} xfs_dquot_t;
-
-
-#define dq_flnext	q_lists.dqm_flnext
-#define dq_flprev	q_lists.dqm_flprev
-#define dq_mplist	q_lists.dqm_mplist
-#define dq_hashlist	q_lists.dqm_hashlist
-#define dq_flags	q_lists.dqm_flags
-
-#define XFS_DQHOLD(dqp)		((dqp)->q_nrefs++)
-
-/*
- * Quota Accounting flags
- */
-#define XFS_ALL_QUOTA_ACCT	(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
-#define XFS_ALL_QUOTA_ACTV	(XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
-#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-				 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
-
-#define XFS_IS_QUOTA_RUNNING(mp)  ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-
-/*
- * Quota Limit Enforcement flags
- */
-#define XFS_IS_QUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
-#define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
-#define XFS_IS_GQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_GQUOTA_ENFD)
-
-#ifdef DEBUG
-static inline int
-XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
-{
-	if (mutex_trylock(&dqp->q_qlock)) {
-		mutex_unlock(&dqp->q_qlock);
-		return 0;
-	}
-	return 1;
-}
-#endif
-
-/*
- * The following three routines simply manage the q_flock
- * semaphore embedded in the dquot.  This semaphore synchronizes
- * processes attempting to flush the in-core dquot back to disk.
- */
-#define xfs_dqflock(dqp)	 { psema(&((dqp)->q_flock), PINOD | PRECALC);\
-				   (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
-#define xfs_dqfunlock(dqp)	 { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
-				   vsema(&((dqp)->q_flock)); \
-				   (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
-
-#define XFS_DQ_PINLOCK(dqp)	   mutex_spinlock( \
-				     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock))
-#define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
-				     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
-
-#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
-#define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
-#define XFS_DQ_IS_DIRTY(dqp)	((dqp)->dq_flags & XFS_DQ_DIRTY)
-#define XFS_QM_ISUDQ(dqp)	((dqp)->dq_flags & XFS_DQ_USER)
-#define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
-#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
-				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
-				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
-
-#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
-				     (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
-				     (XFS_IS_GQUOTA_ON((d)->q_mount))))
-#ifdef DQUOT_TRACING
-/*
- * Dquot Tracing stuff.
- */
-#define DQUOT_TRACE_SIZE	64
-#define DQUOT_KTRACE_ENTRY	1
-
-#define xfs_dqtrace_entry_ino(a,b,ip) \
-xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip))
-#define xfs_dqtrace_entry(a,b) \
-xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL)
-extern void		xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func,
-					    void *, xfs_inode_t *);
-#else
-#define xfs_dqtrace_entry(a,b)
-#define xfs_dqtrace_entry_ino(a,b,ip)
-#endif
-#ifdef QUOTADEBUG
-extern void		xfs_qm_dqprint(xfs_dquot_t *);
-#else
-#define xfs_qm_dqprint(a)
-#endif
-
-extern xfs_dquot_t	*xfs_qm_dqinit(xfs_mount_t *, xfs_dqid_t, uint);
-extern void		xfs_qm_dqdestroy(xfs_dquot_t *);
-extern int		xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern int		xfs_qm_dqpurge(xfs_dquot_t *, uint);
-extern void		xfs_qm_dqunpin_wait(xfs_dquot_t *);
-extern int		xfs_qm_dqlock_nowait(xfs_dquot_t *);
-extern int		xfs_qm_dqflock_nowait(xfs_dquot_t *);
-extern void		xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
-extern void		xfs_qm_adjust_dqtimers(xfs_mount_t *,
-					       xfs_disk_dquot_t *);
-extern int		xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
-
-#endif /* __XFS_DQUOT_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dquot_item.c linux-2.5.66-bk3/fs/xfs/xfs_dquot_item.c
--- linux-2.5.66-bk2/fs/xfs/xfs_dquot_item.c	Mon Mar 24 14:00:04 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dquot_item.c	Wed Dec 31 16:00:00 1969
@@ -1,680 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
- * returns the number of iovecs needed to log the given dquot item.
- */
-/* ARGSUSED */
-STATIC uint
-xfs_qm_dquot_logitem_size(
-	xfs_dq_logitem_t	*logitem)
-{
-	/*
-	 * we need only two iovecs, one for the format, one for the real thing
-	 */
-	return (2);
-}
-
-/*
- * fills in the vector of log iovecs for the given dquot log item.
- */
-STATIC void
-xfs_qm_dquot_logitem_format(
-	xfs_dq_logitem_t	*logitem,
-	xfs_log_iovec_t		*logvec)
-{
-	ASSERT(logitem);
-	ASSERT(logitem->qli_dquot);
-
-	logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
-	logvec->i_len  = sizeof(xfs_dq_logformat_t);
-	logvec++;
-	logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
-	logvec->i_len  = sizeof(xfs_disk_dquot_t);
-
-	ASSERT(2 == logitem->qli_item.li_desc->lid_size);
-	logitem->qli_format.qlf_size = 2;
-
-}
-
-/*
- * Increment the pin count of the given dquot.
- * This value is protected by pinlock spinlock in the xQM structure.
- */
-STATIC void
-xfs_qm_dquot_logitem_pin(
-	xfs_dq_logitem_t *logitem)
-{
-	unsigned long	s;
-	xfs_dquot_t *dqp;
-
-	dqp = logitem->qli_dquot;
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	s = XFS_DQ_PINLOCK(dqp);
-	dqp->q_pincount++;
-	XFS_DQ_PINUNLOCK(dqp, s);
-}
-
-/*
- * Decrement the pin count of the given dquot, and wake up
- * anyone in xfs_dqwait_unpin() if the count goes to 0.	 The
- * dquot must have been previously pinned with a call to xfs_dqpin().
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin(
-	xfs_dq_logitem_t *logitem,
-	int		  stale)
-{
-	unsigned long	s;
-	xfs_dquot_t *dqp;
-
-	dqp = logitem->qli_dquot;
-	ASSERT(dqp->q_pincount > 0);
-	s = XFS_DQ_PINLOCK(dqp);
-	dqp->q_pincount--;
-	if (dqp->q_pincount == 0) {
-		sv_broadcast(&dqp->q_pinwait);
-	}
-	XFS_DQ_PINUNLOCK(dqp, s);
-}
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin_remove(
-	xfs_dq_logitem_t *logitem,
-	xfs_trans_t	 *tp)
-{
-	xfs_qm_dquot_logitem_unpin(logitem, 0);
-}
-
-/*
- * Given the logitem, this writes the corresponding dquot entry to disk
- * asynchronously. This is called with the dquot entry securely locked;
- * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
- * at the end.
- */
-STATIC void
-xfs_qm_dquot_logitem_push(
-	xfs_dq_logitem_t	*logitem)
-{
-	xfs_dquot_t	*dqp;
-
-	dqp = logitem->qli_dquot;
-
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
-
-	/*
-	 * Since we were able to lock the dquot's flush lock and
-	 * we found it on the AIL, the dquot must be dirty.  This
-	 * is because the dquot is removed from the AIL while still
-	 * holding the flush lock in xfs_dqflush_done().  Thus, if
-	 * we found it in the AIL and were able to obtain the flush
-	 * lock without sleeping, then there must not have been
-	 * anyone in the process of flushing the dquot.
-	 */
-	xfs_qm_dqflush(dqp, XFS_B_DELWRI);
-	xfs_dqunlock(dqp);
-}
-
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_dquot_logitem_committed(
-	xfs_dq_logitem_t	*l,
-	xfs_lsn_t		lsn)
-{
-	/*
-	 * We always re-log the entire dquot when it becomes dirty,
-	 * so, the latest copy _is_ the only one that matters.
-	 */
-	return (lsn);
-}
-
-
-/*
- * This is called to wait for the given dquot to be unpinned.
- * Most of these pin/unpin routines are plagiarized from inode code.
- */
-void
-xfs_qm_dqunpin_wait(
-	xfs_dquot_t	*dqp)
-{
-	SPLDECL(s);
-
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	if (dqp->q_pincount == 0) {
-		return;
-	}
-
-	/*
-	 * Give the log a push so we don't wait here too long.
-	 */
-	xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
-	s = XFS_DQ_PINLOCK(dqp);
-	if (dqp->q_pincount == 0) {
-		XFS_DQ_PINUNLOCK(dqp, s);
-		return;
-	}
-	sv_wait(&(dqp->q_pinwait), PINOD,
-		&(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
-}
-
-/*
- * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
- * the dquot is locked by us, but the flush lock isn't. So, here we are
- * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
- * If so, we want to push it out to help us take this item off the AIL as soon
- * as possible.
- *
- * We must not be holding the AIL_LOCK at this point. Calling incore() to
- * search the buffercache can be a time consuming thing, and AIL_LOCK is a
- * spinlock.
- */
-STATIC void
-xfs_qm_dquot_logitem_pushbuf(
-	xfs_dq_logitem_t    *qip)
-{
-	xfs_dquot_t	*dqp;
-	xfs_mount_t	*mp;
-	xfs_buf_t	*bp;
-	uint		dopush;
-
-	dqp = qip->qli_dquot;
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-	/*
-	 * The qli_pushbuf_flag keeps others from
-	 * trying to duplicate our effort.
-	 */
-	ASSERT(qip->qli_pushbuf_flag != 0);
-	ASSERT(qip->qli_push_owner == get_thread_id());
-
-	/*
-	 * If flushlock isn't locked anymore, chances are that the
-	 * inode flush completed and the inode was taken off the AIL.
-	 * So, just get out.
-	 */
-	if ((valusema(&(dqp->q_flock)) > 0)  ||
-	    ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
-		qip->qli_pushbuf_flag = 0;
-		xfs_dqunlock(dqp);
-		return;
-	}
-	mp = dqp->q_mount;
-	bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
-		    XFS_QI_DQCHUNKLEN(mp),
-		    XFS_INCORE_TRYLOCK);
-	if (bp != NULL) {
-		if (XFS_BUF_ISDELAYWRITE(bp)) {
-			dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-				  (valusema(&(dqp->q_flock)) <= 0));
-			qip->qli_pushbuf_flag = 0;
-			xfs_dqunlock(dqp);
-
-			if (XFS_BUF_ISPINNED(bp)) {
-				xfs_log_force(mp, (xfs_lsn_t)0,
-					      XFS_LOG_FORCE);
-			}
-			if (dopush) {
-#ifdef XFSRACEDEBUG
-				delay_for_intr();
-				delay(300);
-#endif
-				xfs_bawrite(mp, bp);
-			} else {
-				xfs_buf_relse(bp);
-			}
-		} else {
-			qip->qli_pushbuf_flag = 0;
-			xfs_dqunlock(dqp);
-			xfs_buf_relse(bp);
-		}
-		return;
-	}
-
-	qip->qli_pushbuf_flag = 0;
-	xfs_dqunlock(dqp);
-}
-
-/*
- * This is called to attempt to lock the dquot associated with this
- * dquot log item.  Don't sleep on the dquot lock or the flush lock.
- * If the flush lock is already held, indicating that the dquot has
- * been or is in the process of being flushed, then see if we can
- * find the dquot's buffer in the buffer cache without sleeping.  If
- * we can and it is marked delayed write, then we want to send it out.
- * We delay doing so until the push routine, though, to avoid sleeping
- * in any device strategy routines.
- */
-STATIC uint
-xfs_qm_dquot_logitem_trylock(
-	xfs_dq_logitem_t	*qip)
-{
-	xfs_dquot_t		*dqp;
-	uint			retval;
-
-	dqp = qip->qli_dquot;
-	if (dqp->q_pincount > 0)
-		return (XFS_ITEM_PINNED);
-
-	if (! xfs_qm_dqlock_nowait(dqp))
-		return (XFS_ITEM_LOCKED);
-
-	retval = XFS_ITEM_SUCCESS;
-	if (! xfs_qm_dqflock_nowait(dqp)) {
-		/*
-		 * The dquot is already being flushed.	It may have been
-		 * flushed delayed write, however, and we don't want to
-		 * get stuck waiting for that to complete.  So, we want to check
-		 * to see if we can lock the dquot's buffer without sleeping.
-		 * If we can and it is marked for delayed write, then we
-		 * hold it and send it out from the push routine.  We don't
-		 * want to do that now since we might sleep in the device
-		 * strategy routine.  We also don't want to grab the buffer lock
-		 * here because we'd like not to call into the buffer cache
-		 * while holding the AIL_LOCK.
-		 * Make sure to only return PUSHBUF if we set pushbuf_flag
-		 * ourselves.  If someone else is doing it then we don't
-		 * want to go to the push routine and duplicate their efforts.
-		 */
-		if (qip->qli_pushbuf_flag == 0) {
-			qip->qli_pushbuf_flag = 1;
-			ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
-#ifdef DEBUG
-			qip->qli_push_owner = get_thread_id();
-#endif
-			/*
-			 * The dquot is left locked.
-			 */
-			retval = XFS_ITEM_PUSHBUF;
-		} else {
-			retval = XFS_ITEM_FLUSHING;
-			xfs_dqunlock_nonotify(dqp);
-		}
-	}
-
-	ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
-	return (retval);
-}
-
-
-/*
- * Unlock the dquot associated with the log item.
- * Clear the fields of the dquot and dquot log item that
- * are specific to the current transaction.  If the
- * hold flags is set, do not unlock the dquot.
- */
-STATIC void
-xfs_qm_dquot_logitem_unlock(
-	xfs_dq_logitem_t    *ql)
-{
-	xfs_dquot_t	*dqp;
-
-	ASSERT(ql != NULL);
-	dqp = ql->qli_dquot;
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-	/*
-	 * Clear the transaction pointer in the dquot
-	 */
-	dqp->q_transp = NULL;
-
-	/*
-	 * dquots are never 'held' from getting unlocked at the end of
-	 * a transaction.  Their locking and unlocking is hidden inside the
-	 * transaction layer, within trans_commit. Hence, no LI_HOLD flag
-	 * for the logitem.
-	 */
-	xfs_dqunlock(dqp);
-}
-
-
-/*
- * The transaction with the dquot locked has aborted.  The dquot
- * must not be dirty within the transaction.  We simply unlock just
- * as if the transaction had been cancelled.
- */
-STATIC void
-xfs_qm_dquot_logitem_abort(
-	xfs_dq_logitem_t    *ql)
-{
-	xfs_qm_dquot_logitem_unlock(ql);
-}
-
-/*
- * this needs to stamp an lsn into the dquot, I think.
- * rpc's that look at user dquot's would then have to
- * push on the dependency recorded in the dquot
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_committing(
-	xfs_dq_logitem_t	*l,
-	xfs_lsn_t		lsn)
-{
-	return;
-}
-
-
-/*
- * This is the ops vector for dquots
- */
-struct xfs_item_ops xfs_dquot_item_ops = {
-	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
-	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-					xfs_qm_dquot_logitem_format,
-	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
-	.iop_unpin	= (void(*)(xfs_log_item_t*, int))
-					xfs_qm_dquot_logitem_unpin,
-	.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
-					xfs_qm_dquot_logitem_unpin_remove,
-	.iop_trylock	= (uint(*)(xfs_log_item_t*))
-					xfs_qm_dquot_logitem_trylock,
-	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
-	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_dquot_logitem_committed,
-	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
-	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
-	.iop_pushbuf	= (void(*)(xfs_log_item_t*))
-					xfs_qm_dquot_logitem_pushbuf,
-	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_dquot_logitem_committing
-};
-
-/*
- * Initialize the dquot log item for a newly allocated dquot.
- * The dquot isn't locked at this point, but it isn't on any of the lists
- * either, so we don't care.
- */
-void
-xfs_qm_dquot_logitem_init(
-	struct xfs_dquot *dqp)
-{
-	xfs_dq_logitem_t  *lp;
-	lp = &dqp->q_logitem;
-
-	lp->qli_item.li_type = XFS_LI_DQUOT;
-	lp->qli_item.li_ops = &xfs_dquot_item_ops;
-	lp->qli_item.li_mountp = dqp->q_mount;
-	lp->qli_dquot = dqp;
-	lp->qli_format.qlf_type = XFS_LI_DQUOT;
-	lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
-	lp->qli_format.qlf_blkno = dqp->q_blkno;
-	lp->qli_format.qlf_len = 1;
-	/*
-	 * This is just the offset of this dquot within its buffer
-	 * (which is currently 1 FSB and probably won't change).
-	 * Hence 32 bits for this offset should be just fine.
-	 * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t))
-	 * here, and recompute it at recovery time.
-	 */
-	lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset;
-}
-
-/*------------------  QUOTAOFF LOG ITEMS  -------------------*/
-
-/*
- * This returns the number of iovecs needed to log the given quotaoff item.
- * We only need 1 iovec for an quotaoff item.  It just logs the
- * quotaoff_log_format structure.
- */
-/*ARGSUSED*/
-STATIC uint
-xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
-{
-	return (1);
-}
-
-/*
- * This is called to fill in the vector of log iovecs for the
- * given quotaoff log item. We use only 1 iovec, and we point that
- * at the quotaoff_log_format structure embedded in the quotaoff item.
- * It is at this point that we assert that all of the extent
- * slots in the quotaoff item have been filled.
- */
-STATIC void
-xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t	*qf,
-			   xfs_log_iovec_t	*log_vector)
-{
-	ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
-
-	log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
-	log_vector->i_len = sizeof(xfs_qoff_logitem_t);
-	qf->qql_format.qf_size = 1;
-}
-
-
-/*
- * Pinning has no meaning for an quotaoff item, so just return.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
-{
-	return;
-}
-
-
-/*
- * Since pinning has no meaning for an quotaoff item, unpinning does
- * not either.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
-{
-	return;
-}
-
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
-{
-	return;
-}
-
-/*
- * Quotaoff items have no locking, so just return success.
- */
-/*ARGSUSED*/
-STATIC uint
-xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
-{
-	return XFS_ITEM_LOCKED;
-}
-
-/*
- * Quotaoff items have no locking or pushing, so return failure
- * so that the caller doesn't bother with us.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
-{
-	return;
-}
-
-/*
- * The quotaoff-start-item is logged only once and cannot be moved in the log,
- * so simply return the lsn at which it's been logged.
- */
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
-{
-	return (lsn);
-}
-
-/*
- * The transaction of which this QUOTAOFF is a part has been aborted.
- * Just clean up after ourselves.
- * Shouldn't this never happen in the case of qoffend logitems? XXX
- */
-STATIC void
-xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
-{
-	kmem_free(qf, sizeof(xfs_qoff_logitem_t));
-}
-
-/*
- * There isn't much you can do to push on an quotaoff item.  It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
-{
-	return;
-}
-
-
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_qoffend_logitem_committed(
-	xfs_qoff_logitem_t *qfe,
-	xfs_lsn_t lsn)
-{
-	xfs_qoff_logitem_t	*qfs;
-	SPLDECL(s);
-
-	qfs = qfe->qql_start_lip;
-	AIL_LOCK(qfs->qql_item.li_mountp,s);
-	/*
-	 * Delete the qoff-start logitem from the AIL.
-	 * xfs_trans_delete_ail() drops the AIL lock.
-	 */
-	xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s);
-	kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
-	kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
-	return (xfs_lsn_t)-1;
-}
-
-/*
- * XXX rcc - don't know quite what to do with this.  I think we can
- * just ignore it.  The only time that isn't the case is if we allow
- * the client to somehow see that quotas have been turned off in which
- * we can't allow that to get back until the quotaoff hits the disk.
- * So how would that happen?  Also, do we need different routines for
- * quotaoff start and quotaoff end?  I suspect the answer is yes but
- * to be sure, I need to look at the recovery code and see how quota off
- * recovery is handled (do we roll forward or back or do something else).
- * If we roll forwards or backwards, then we need two separate routines,
- * one that does nothing and one that stamps in the lsn that matters
- * (truly makes the quotaoff irrevocable).  If we do something else,
- * then maybe we don't need two.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
-	return;
-}
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
-	return;
-}
-
-struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
-	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-					xfs_qm_qoff_logitem_format,
-	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-	.iop_unpin	= (void(*)(xfs_log_item_t* ,int))
-					xfs_qm_qoff_logitem_unpin,
-	.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-					xfs_qm_qoff_logitem_unpin_remove,
-	.iop_trylock	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_qoffend_logitem_committed,
-	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
-	.iop_pushbuf	= NULL,
-	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_qoffend_logitem_committing
-};
-
-/*
- * This is the ops vector shared by all quotaoff-start log items.
- */
-struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
-	.iop_size	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-	.iop_format	= (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-					xfs_qm_qoff_logitem_format,
-	.iop_pin	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-	.iop_unpin	= (void(*)(xfs_log_item_t*, int))
-					xfs_qm_qoff_logitem_unpin,
-	.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-					xfs_qm_qoff_logitem_unpin_remove,
-	.iop_trylock	= (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-	.iop_unlock	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-	.iop_committed	= (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_qoff_logitem_committed,
-	.iop_push	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-	.iop_abort	= (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
-	.iop_pushbuf	= NULL,
-	.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-					xfs_qm_qoff_logitem_committing
-};
-
-/*
- * Allocate and initialize an quotaoff item of the correct quota type(s).
- */
-xfs_qoff_logitem_t *
-xfs_qm_qoff_logitem_init(
-	struct xfs_mount *mp,
-	xfs_qoff_logitem_t *start,
-	uint flags)
-{
-	xfs_qoff_logitem_t	*qf;
-
-	qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
-
-	qf->qql_item.li_type = XFS_LI_QUOTAOFF;
-	if (start)
-		qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops;
-	else
-		qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops;
-	qf->qql_item.li_mountp = mp;
-	qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
-	qf->qql_format.qf_flags = flags;
-	qf->qql_start_lip = start;
-	return (qf);
-}
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_dquot_item.h linux-2.5.66-bk3/fs/xfs/xfs_dquot_item.h
--- linux-2.5.66-bk2/fs/xfs/xfs_dquot_item.h	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_dquot_item.h	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_DQUOT_ITEM_H__
-#define __XFS_DQUOT_ITEM_H__
-
-/*
- * These are the structures used to lay out dquots and quotaoff
- * records on the log. Quite similar to those of inodes.
- */
-
-/*
- * log format struct for dquots.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- */
-typedef struct xfs_dq_logformat {
-	__uint16_t		qlf_type;      /* dquot log item type */
-	__uint16_t		qlf_size;      /* size of this item */
-	xfs_dqid_t		qlf_id;	       /* usr/grp id number : 32 bits */
-	__int64_t		qlf_blkno;     /* blkno of dquot buffer */
-	__int32_t		qlf_len;       /* len of dquot buffer */
-	__uint32_t		qlf_boffset;   /* off of dquot in buffer */
-} xfs_dq_logformat_t;
-
-/*
- * log format struct for QUOTAOFF records.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
- * to the first and ensures that the first logitem is taken out of the AIL
- * only when the last one is securely committed.
- */
-typedef struct xfs_qoff_logformat {
-	unsigned short		qf_type;	/* quotaoff log item type */
-	unsigned short		qf_size;	/* size of this item */
-	unsigned int		qf_flags;	/* USR and/or GRP */
-	char			qf_pad[12];	/* padding for future */
-} xfs_qoff_logformat_t;
-
-
-#ifdef __KERNEL__
-
-struct xfs_dquot;
-struct xfs_trans;
-struct xfs_mount;
-typedef struct xfs_dq_logitem {
-	xfs_log_item_t		 qli_item;	   /* common portion */
-	struct xfs_dquot	*qli_dquot;	   /* dquot ptr */
-	xfs_lsn_t		 qli_flush_lsn;	   /* lsn at last flush */
-	unsigned short		 qli_pushbuf_flag; /* one bit used in push_ail */
-#ifdef DEBUG
-	uint64_t		 qli_push_owner;
-#endif
-	xfs_dq_logformat_t	 qli_format;	   /* logged structure */
-} xfs_dq_logitem_t;
-
-
-typedef struct xfs_qoff_logitem {
-	xfs_log_item_t		 qql_item;	/* common portion */
-	struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
-	xfs_qoff_logformat_t	 qql_format;	/* logged structure */
-} xfs_qoff_logitem_t;
-
-
-extern void		   xfs_qm_dquot_logitem_init(struct xfs_dquot *);
-extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
-						    xfs_qoff_logitem_t *, uint);
-extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
-						   xfs_qoff_logitem_t *, uint);
-extern void		   xfs_trans_log_quotaoff_item(struct xfs_trans *,
-						       xfs_qoff_logitem_t *);
-
-#endif	/* __KERNEL__ */
-
-#endif	/* __XFS_DQUOT_ITEM_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_iget.c linux-2.5.66-bk3/fs/xfs/xfs_iget.c
--- linux-2.5.66-bk2/fs/xfs/xfs_iget.c	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_iget.c	Mon Mar 31 12:48:53 2003
@@ -591,9 +591,7 @@
 	 * Release dquots (and their references) if any. An inode may escape
 	 * xfs_inactive and get here via vn_alloc->vn_reclaim path.
 	 */
-	if (ip->i_udquot || ip->i_gdquot) {
-		xfs_qm_dqdettach_inode(ip);
-	}
+	XFS_QM_DQDETACH(ip->i_mount, ip);
 
 	/*
 	 * Pull our behavior descriptor from the vnode chain.
@@ -611,11 +609,8 @@
 
 /*
  * This routine removes an about-to-be-destroyed inode from
- * all of the lists in which it is lcoated with the exception
- * of the behavior chain.  It is used by xfs_ireclaim and
- * by cxfs relocation cocde, in which case, we are removing
- * the xfs_inode but leaving the vnode alone since it has
- * been transformed into a client vnode.
+ * all of the lists in which it is located with the exception
+ * of the behavior chain. 
  */
 void
 xfs_iextract(
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_inode.c linux-2.5.66-bk3/fs/xfs/xfs_inode.c
--- linux-2.5.66-bk2/fs/xfs/xfs_inode.c	Mon Mar 24 14:01:46 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_inode.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -1190,25 +1190,6 @@
 	ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
 	ip->i_d.di_anextents = 0;
 
-#if DEBUG
-	{
-		uint	badflags = VNOSWAP |
-			       VISSWAP |
-			       VREPLICABLE |
-			   /*  VNONREPLICABLE | XXX uncomment this */
-			       VDOCMP |
-			       VFRLOCKS;
-
-		/*
-		 * For shared mounts, VNOSWAP is set in xfs_iget
-		 */
-		if (tp->t_mountp->m_cxfstype != XFS_CXFS_NOT)
-			badflags &= ~VNOSWAP;
-
-		ASSERT(!(vp->v_flag & badflags));
-	}
-#endif /* DEBUG */
-
 	/*
 	 * Log the new values stuffed into the inode.
 	 */
@@ -3599,16 +3580,19 @@
 
 	nanotime(&tv);
 	if (flags & XFS_ICHGTIME_MOD) {
-		inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
-		inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
+		inode->i_mtime = tv;
+		ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
+		ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
 	}
 	if (flags & XFS_ICHGTIME_ACC) {
-		inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
-		inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
+		inode->i_atime  = tv;
+		ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
+		ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
 	}
 	if (flags & XFS_ICHGTIME_CHG) {
-		inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
-		inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
+		inode->i_ctime  = tv;
+		ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
+		ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
 	}
 
 	/*
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_inode.h linux-2.5.66-bk3/fs/xfs/xfs_inode.h
--- linux-2.5.66-bk2/fs/xfs/xfs_inode.h	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_inode.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -154,11 +154,7 @@
  * Flags in the flags field
  */
 
-#define XFS_IOCORE_ISXFS	0x01
-#define XFS_IOCORE_ISCXFS	0x02
-#define XFS_IOCORE_RT		0x04
-
-#define IO_IS_XFS(io)	((io)->io_flags & XFS_IOCORE_ISXFS)
+#define XFS_IOCORE_RT		0x1
 
 /*
  * xfs_iocore prototypes
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_iocore.c linux-2.5.66-bk3/fs/xfs/xfs_iocore.c
--- linux-2.5.66-bk2/fs/xfs/xfs_iocore.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_iocore.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -33,15 +33,25 @@
 #include <xfs.h>
 
 
-static xfs_fsize_t
+STATIC xfs_fsize_t
 xfs_size_fn(
-	xfs_inode_t	*ip)
+	xfs_inode_t		*ip)
 {
 	return (ip->i_d.di_size);
 }
 
+STATIC int
+xfs_ioinit(
+	struct vfs		*vfsp,
+	struct xfs_mount_args	*mntargs,
+	int			flags)
+{
+	return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp),
+			   vfsp->vfs_super->s_bdev->bd_dev, flags);
+}
+
 xfs_ioops_t	xfs_iocore_xfs = {
-	.xfs_ioinit		= (xfs_ioinit_t) fs_noerr,
+	.xfs_ioinit		= (xfs_ioinit_t) xfs_ioinit,
 	.xfs_bmapi_func		= (xfs_bmapi_t) xfs_bmapi,
 	.xfs_bmap_eof_func	= (xfs_bmap_eof_t) xfs_bmap_eof,
 	.xfs_iomap_write_direct =
@@ -67,11 +77,9 @@
 {
 	xfs_iocore_t	*io = &ip->i_iocore;
 
-	io->io_flags = XFS_IOCORE_ISXFS;
-	if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
+	io->io_flags = 0;
+	if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
 		io->io_flags |= XFS_IOCORE_RT;
-	}
-
 	io->io_dmevmask = ip->i_d.di_dmevmask;
 	io->io_dmstate = ip->i_d.di_dmstate;
 }
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_log_recover.c linux-2.5.66-bk3/fs/xfs/xfs_log_recover.c
--- linux-2.5.66-bk2/fs/xfs/xfs_log_recover.c	Mon Mar 24 14:00:44 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_log_recover.c	Mon Mar 31 12:48:53 2003
@@ -136,16 +136,15 @@
 /*
  * check log record header for recovery
  */
-
 static void
 xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head)
 {
     int b;
 
-    printk("xlog_header_check_dump:\n	 SB : uuid = ");
+    printk("%s:  SB : uuid = ", __FUNCTION__);
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
     printk(", fmt = %d\n",XLOG_FMT);
-    printk("    log: uuid = ");
+    printk("    log : uuid = ");
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
     printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
 }
@@ -1813,7 +1812,6 @@
 		 */
 		error = 0;
 		if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
-			/* OK, if this returns ENOSYS */
 			error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
 					       item->ri_buf[i].i_addr,
 					       -1, 0, XFS_QMOPT_DOWARN,
@@ -1821,9 +1819,9 @@
 		}
 		if (!error)
 			memcpy(xfs_buf_offset(bp,
-					(uint)bit << XFS_BLI_SHIFT),	/* dest */
-				item->ri_buf[i].i_addr,			/* source */
-				nbits<<XFS_BLI_SHIFT);			/* length */
+				(uint)bit << XFS_BLI_SHIFT),	/* dest */
+				item->ri_buf[i].i_addr,		/* source */
+				nbits<<XFS_BLI_SHIFT);		/* length */
 		i++;
 		bit += nbits;
 	}
@@ -1832,6 +1830,120 @@
 	ASSERT(i == item->ri_total);
 }	/* xlog_recover_do_reg_buffer */
 
+/*
+ * Do some primitive error checking on ondisk dquot data structures.
+ */
+int
+xfs_qm_dqcheck(
+	xfs_disk_dquot_t *ddq,
+	xfs_dqid_t	 id,
+	uint		 type,	  /* used only when IO_dorepair is true */
+	uint		 flags,
+	char		 *str)
+{
+	xfs_dqblk_t	 *d = (xfs_dqblk_t *)ddq;
+	int		errs = 0;
+
+	/*
+	 * We can encounter an uninitialized dquot buffer for 2 reasons:
+	 * 1. If we crash while deleting the quotainode(s), and those blks got
+	 *    used for user data. This is because we take the path of regular
+	 *    file deletion; however, the size field of quotainodes is never
+	 *    updated, so all the tricks that we play in itruncate_finish
+	 *    don't quite matter.
+	 *
+	 * 2. We don't play the quota buffers when there's a quotaoff logitem.
+	 *    But the allocation will be replayed so we'll end up with an
+	 *    uninitialized quota block.
+	 *
+	 * This is all fine; things are still consistent, and we haven't lost
+	 * any quota information. Just don't complain about bad dquot blks.
+	 */
+	if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) {
+		if (flags & XFS_QMOPT_DOWARN)
+			cmn_err(CE_ALERT,
+			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
+			str, id,
+			INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC);
+		errs++;
+	}
+	if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) {
+		if (flags & XFS_QMOPT_DOWARN)
+			cmn_err(CE_ALERT,
+			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
+			str, id,
+			INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION);
+		errs++;
+	}
+
+	if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER &&
+	    INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) {
+		if (flags & XFS_QMOPT_DOWARN)
+			cmn_err(CE_ALERT,
+			"%s : XFS dquot ID 0x%x, unknown flags 0x%x",
+			str, id, INT_GET(ddq->d_flags, ARCH_CONVERT));
+		errs++;
+	}
+
+	if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) {
+		if (flags & XFS_QMOPT_DOWARN)
+			cmn_err(CE_ALERT,
+			"%s : ondisk-dquot 0x%x, ID mismatch: "
+			"0x%x expected, found id 0x%x",
+			str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT));
+		errs++;
+	}
+
+	if (! errs) {
+		if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
+		    INT_GET(ddq->d_bcount, ARCH_CONVERT) >=
+				INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
+			if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) &&
+			    !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
+				if (flags & XFS_QMOPT_DOWARN)
+					cmn_err(CE_ALERT,
+					"%s : Dquot ID 0x%x (0x%x) "
+					"BLK TIMER NOT STARTED",
+					str, (int)
+					INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
+				errs++;
+			}
+		}
+		if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
+		    INT_GET(ddq->d_icount, ARCH_CONVERT) >=
+				INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
+			if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) &&
+			    !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
+				if (flags & XFS_QMOPT_DOWARN)
+					cmn_err(CE_ALERT,
+					"%s : Dquot ID 0x%x (0x%x) "
+					"INODE TIMER NOT STARTED",
+					str, (int)
+					INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
+				errs++;
+			}
+		}
+	}
+
+	if (!errs || !(flags & XFS_QMOPT_DQREPAIR))
+		return errs;
+
+	if (flags & XFS_QMOPT_DOWARN)
+		cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id);
+
+	/*
+	 * Typically, a repair is only requested by quotacheck.
+	 */
+	ASSERT(id != -1);
+	ASSERT(flags & XFS_QMOPT_DQREPAIR);
+	memset(d, 0, sizeof(xfs_dqblk_t));
+	INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
+	INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
+	INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
+	INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
+
+	return errs;
+}
 
 /*
  * Perform a dquot buffer recovery.
@@ -2335,8 +2447,6 @@
 			   dq_f->qlf_id,
 			   0, XFS_QMOPT_DOWARN,
 			   "xlog_recover_do_dquot_trans (log copy)"))) {
-		if (error == ENOSYS)
-			return (0);
 		return XFS_ERROR(EIO);
 	}
 	ASSERT(dq_f->qlf_len == 1);
@@ -2923,8 +3033,6 @@
 
 	/*
 	 * Prevent any DMAPI event from being sent while in this function.
-	 * Not a problem for xfs since the file system isn't mounted
-	 * yet.	 It is a problem for cxfs recovery.
 	 */
 	mp_dmevmask = mp->m_dmevmask;
 	mp->m_dmevmask = 0;
@@ -2982,11 +3090,8 @@
 					 * Prevent any DMAPI event from
 					 * being sent when the
 					 * reference on the inode is
-					 * dropped.  Not a problem for
-					 * xfs since the file system
-					 * isn't mounted yet.  It is a
-					 * problem for cxfs recovery.
-					 */
+					 * dropped.
+                                         */
 					ip->i_d.di_dmevmask = 0;
 
 					/*
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_macros.c linux-2.5.66-bk3/fs/xfs/xfs_macros.c
--- linux-2.5.66-bk2/fs/xfs/xfs_macros.c	Mon Mar 24 14:00:15 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_macros.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -358,6 +358,14 @@
 }
 #endif
 
+#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_VFSTOM)
+xfs_mount_t *
+xfs_vfstom(vfs_t *vfs)
+{
+	return XFS_VFSTOM(vfs);
+}
+#endif
+
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BM_MAXLEVELS)
 int
 xfs_bm_maxlevels(xfs_mount_t *mp, int w)
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_mount.c linux-2.5.66-bk3/fs/xfs/xfs_mount.c
--- linux-2.5.66-bk2/fs/xfs/xfs_mount.c	Mon Mar 24 14:00:16 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_mount.c	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -32,16 +32,14 @@
 
 #include <xfs.h>
 
-STATIC void	xfs_mount_reset_sbqflags(xfs_mount_t *);
 STATIC void	xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
 STATIC int	xfs_uuid_mount(xfs_mount_t *);
+STATIC void	xfs_uuid_unmount(xfs_mount_t *mp);
 
 mutex_t		xfs_uuidtabmon;		/* monitor for uuidtab */
 STATIC int	xfs_uuidtab_size;
 STATIC uuid_t	*xfs_uuidtab;
 
-STATIC void	xfs_uuid_unmount(xfs_mount_t *);
-
 void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t);
 
 static struct {
@@ -120,10 +118,9 @@
 	spinlock_init(&mp->m_freeze_lock, "xfs_freeze");
 	init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0);
 	atomic_set(&mp->m_active_trans, 0);
-	mp->m_cxfstype = XFS_CXFS_NOT;
 
 	return mp;
-}	/* xfs_mount_init */
+}
 
 /*
  * Free up the resources associated with a mount structure.  Assume that
@@ -146,34 +143,29 @@
 		for (agno = 0; agno < mp->m_maxagi; agno++)
 			if (mp->m_perag[agno].pagb_list)
 				kmem_free(mp->m_perag[agno].pagb_list,
-				  sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS);
+						sizeof(xfs_perag_busy_t) *
+							XFS_PAGB_NUM_SLOTS);
 		kmem_free(mp->m_perag,
 			  sizeof(xfs_perag_t) * mp->m_sb.sb_agcount);
 	}
 
-#if 0
-	/*
-	 * XXXdpd - Doesn't work now for shutdown case.
-	 * Should at least free the memory.
-	 */
-	ASSERT(mp->m_ail.ail_back == (xfs_log_item_t*)&(mp->m_ail));
-	ASSERT(mp->m_ail.ail_forw == (xfs_log_item_t*)&(mp->m_ail));
-#endif
 	AIL_LOCK_DESTROY(&mp->m_ail_lock);
 	spinlock_destroy(&mp->m_sb_lock);
 	mutex_destroy(&mp->m_ilock);
 	freesema(&mp->m_growlock);
+	if (mp->m_quotainfo)
+		XFS_QM_DONE(mp);
 
-	if (mp->m_fsname != NULL) {
+	if (mp->m_fsname != NULL)
 		kmem_free(mp->m_fsname, mp->m_fsname_len);
-	}
-	if (mp->m_quotainfo != NULL) {
-		xfs_qm_unmount_quotadestroy(mp);
-	}
 
 	if (remove_bhv) {
-		VFS_REMOVEBHV(XFS_MTOVFS(mp), &mp->m_bhv);
+		struct vfs	*vfsp = XFS_MTOVFS(mp);
+
+		bhv_remove_all_vfsops(vfsp, 0);
+		VFS_REMOVEBHV(vfsp, &mp->m_bhv);
 	}
+
 	spinlock_destroy(&mp->m_freeze_lock);
 	sv_destroy(&mp->m_wait_unfreeze);
 	kmem_free(mp, sizeof(xfs_mount_t));
@@ -605,21 +597,17 @@
 {
 	xfs_buf_t	*bp;
 	xfs_sb_t	*sbp = &(mp->m_sb);
-	int		error = 0;
 	xfs_inode_t	*rip;
 	vnode_t		*rvp = 0;
-	int		readio_log;
-	int		writeio_log;
+	int		readio_log, writeio_log;
 	vmap_t		vmap;
 	xfs_daddr_t	d;
-	extern xfs_ioops_t xfs_iocore_xfs;	/* from xfs_iocore.c */
 	__uint64_t	ret64;
-	uint		quotaflags, quotaondisk;
-	uint		uquotaondisk = 0, gquotaondisk = 0;
-	boolean_t	needquotamount;
 	__int64_t	update_flags;
+	uint		quotamount, quotaflags;
 	int		agno, noio;
 	int		uuid_mounted = 0;
+	int		error = 0;
 
 	noio = dev == 0 && mp->m_sb_bp != NULL;
 	if (mp->m_sb_bp == NULL) {
@@ -644,7 +632,8 @@
 		if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
 		    (BBTOB(mp->m_swidth) & mp->m_blockmask)) {
 			if (mp->m_flags & XFS_MOUNT_RETERR) {
-				cmn_err(CE_WARN, "XFS: alignment check 1 failed");
+				cmn_err(CE_WARN,
+					"XFS: alignment check 1 failed");
 				error = XFS_ERROR(EINVAL);
 				goto error1;
 			}
@@ -664,7 +653,8 @@
 				mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
 			} else {
 				if (mp->m_flags & XFS_MOUNT_RETERR) {
-					cmn_err(CE_WARN, "XFS: alignment check 3 failed");
+					cmn_err(CE_WARN,
+					"XFS: alignment check 3 failed");
 					error = XFS_ERROR(EINVAL);
 					goto error1;
 				}
@@ -718,7 +708,8 @@
 	 * since a single partition filesystem is identical to a single
 	 * partition volume/filesystem.
 	 */
-	if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && (mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
+	if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&
+	    (mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
 		if (xfs_uuid_mount(mp)) {
 			error = XFS_ERROR(EINVAL);
 			goto error1;
@@ -859,9 +850,6 @@
 		return(0);
 	}
 
-	/* Initialize the I/O function vector with XFS functions */
-	mp->m_io_ops = xfs_iocore_xfs;
-
 	/*
 	 *  Copies the low order bits of the timestamp and the randomly
 	 *  set "sequence" number out of a UUID.
@@ -953,54 +941,22 @@
 
 	ASSERT(rip != NULL);
 	rvp = XFS_ITOV(rip);
+	VMAP(rvp, vmap);
+
 	if (unlikely((rip->i_d.di_mode & IFMT) != IFDIR)) {
 		cmn_err(CE_WARN, "XFS: corrupted root inode");
-		VMAP(rvp, vmap);
 		prdev("Root inode %llu is not a directory",
 		      mp->m_dev, (unsigned long long)rip->i_ino);
 		xfs_iunlock(rip, XFS_ILOCK_EXCL);
-		VN_RELE(rvp);
-		vn_purge(rvp, &vmap);
 		XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
 				 mp);
 		error = XFS_ERROR(EFSCORRUPTED);
-		goto error3;
+		goto error4;
 	}
 	mp->m_rootip = rip;	/* save it */
 
 	xfs_iunlock(rip, XFS_ILOCK_EXCL);
 
-	quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
-		mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
-
-	if (quotaondisk) {
-		uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
-		gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
-	}
-
-	/*
-	 * If the device itself is read-only, we can't allow
-	 * the user to change the state of quota on the mount -
-	 * this would generate a transaction on the ro device,
-	 * which would lead to an I/O error and shutdown
-	 */
-
-	if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
-	    (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
-	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
-	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
-	    xfs_dev_is_read_only(mp, "changing quota state")) {
-		cmn_err(CE_WARN,
-			"XFS: please mount with%s%s%s.",
-			(!quotaondisk ? "out quota" : ""),
-			(uquotaondisk ? " usrquota" : ""),
-			(gquotaondisk ? " grpquota" : ""));
-		VN_RELE(rvp);
-		vn_remove(rvp);
-		error = XFS_ERROR(EPERM);
-		goto error3;
-	}
-
 	/*
 	 * Initialize realtime inode pointers in the mount structure
 	 */
@@ -1009,10 +965,7 @@
 		 * Free up the root inode.
 		 */
 		cmn_err(CE_WARN, "XFS: failed to read RT inodes");
-		VMAP(rvp, vmap);
-		VN_RELE(rvp);
-		vn_purge(rvp, &vmap);
-		goto error3;
+		goto error4;
 	}
 
 	/*
@@ -1022,41 +975,11 @@
 	if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY))
 		xfs_mount_log_sbunit(mp, update_flags);
 
-	quotaflags = 0;
-	needquotamount = B_FALSE;
-
 	/*
-	 * Figure out if we'll need to do a quotacheck.
+	 * Initialise the XFS quota management subsystem for this mount
 	 */
-	if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
-		/*
-		 * Call mount_quotas at this point only if we won't have to do
-		 * a quotacheck.
-		 */
-		if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
-			/*
-			 * If the xfs quota code isn't installed,
-			 * we have to reset the quotachk'd bit.
-			 * If an error occurred, qm_mount_quotas code
-			 * has already disabled quotas. So, just finish
-			 * mounting, and get on with the boring life
-			 * without disk quotas.
-			 */
-			if (xfs_qm_mount_quotas(mp))
-				xfs_mount_reset_sbqflags(mp);
-		} else {
-			/*
-			 * Clear the quota flags, but remember them. This
-			 * is so that the quota code doesn't get invoked
-			 * before we're ready. This can happen when an
-			 * inode goes inactive and wants to free blocks,
-			 * or via xfs_log_mount_finish.
-			 */
-			quotaflags = mp->m_qflags;
-			mp->m_qflags = 0;
-			needquotamount = B_TRUE;
-		}
-	}
+	if ((error = XFS_QM_INIT(mp, &quotamount, &quotaflags)))
+		goto error4;
 
 	/*
 	 * Finish recovering the file system.  This part needed to be
@@ -1066,30 +989,23 @@
 	error = xfs_log_mount_finish(mp, mfsi_flags);
 	if (error) {
 		cmn_err(CE_WARN, "XFS: log mount finish failed");
-		goto error3;
-	}
-
-	if (needquotamount) {
-		ASSERT(mp->m_qflags == 0);
-		mp->m_qflags = quotaflags;
-		if (xfs_qm_mount_quotas(mp))
-			xfs_mount_reset_sbqflags(mp);
+		goto error4;
 	}
 
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-	if (! (XFS_IS_QUOTA_ON(mp)))
-		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
-	else
-		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
-#endif
-
-#ifdef QUOTADEBUG
-	if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
-		cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
-#endif
+	/*
+	 * Complete the quota initialisation, post-log-replay component.
+	 */
+	if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags)))
+		goto error4;
 
-	return (0);
+	return 0;
 
+ error4:
+	/*
+	 * Free up the root inode.
+	 */
+	VN_RELE(rvp);
+	vn_purge(rvp, &vmap);
  error3:
 	xfs_log_unmount_dealloc(mp);
  error2:
@@ -1118,25 +1034,15 @@
 int
 xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
 {
-	int		ndquots;
+	struct vfs	*vfsp = XFS_MTOVFS(mp);
 #if defined(DEBUG) || defined(INDUCE_IO_ERROR)
 	int64_t		fsid;
 #endif
 
 	xfs_iflush_all(mp, XFS_FLUSH_ALL);
 
-	/*
-	 * Purge the dquot cache.
-	 * None of the dquots should really be busy at this point.
-	 */
-	if (mp->m_quotainfo) {
-		while ((ndquots = xfs_qm_dqpurge_all(mp,
-						  XFS_QMOPT_UQUOTA|
-						  XFS_QMOPT_GQUOTA|
-						  XFS_QMOPT_UMOUNTING))) {
-			delay(ndquots * 10);
-		}
-	}
+	XFS_QM_DQPURGEALL(mp,
+		XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING);
 
 	/*
 	 * Flush out the log synchronously so that we know for sure
@@ -1178,14 +1084,14 @@
 	/*
 	 * clear all error tags on this filesystem
 	 */
-	memcpy(&fsid, &(XFS_MTOVFS(mp)->vfs_fsid), sizeof(int64_t));
-	(void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
+	memcpy(&fsid, &vfsp->vfs_fsid, sizeof(int64_t));
+	xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
 #endif
-
+	XFS_IODONE(vfsp);
 	xfs_mount_free(mp, 1);
 	return 0;
 }
-
+ 
 void
 xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr)
 {
@@ -1652,47 +1558,6 @@
 }
 
 /*
- * When xfsquotas isn't installed and the superblock had quotas, we need to
- * clear the quotaflags from superblock.
- */
-STATIC void
-xfs_mount_reset_sbqflags(
-	xfs_mount_t	*mp)
-{
-	xfs_trans_t	*tp;
-	unsigned long		s;
-
-	mp->m_qflags = 0;
-	/*
-	 * It is OK to look at sb_qflags here in mount path,
-	 * without SB_LOCK.
-	 */
-	if (mp->m_sb.sb_qflags == 0)
-		return;
-	s = XFS_SB_LOCK(mp);
-	mp->m_sb.sb_qflags = 0;
-	XFS_SB_UNLOCK(mp, s);
-
-	/*
-	 * if the fs is readonly, let the incore superblock run
-	 * with quotas off but don't flush the update out to disk
-	 */
-	if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
-		return;
-#ifdef QUOTADEBUG
-	xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-	if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
-				      XFS_DEFAULT_LOG_COUNT)) {
-		xfs_trans_cancel(tp, 0);
-		return;
-	}
-	xfs_mod_sb(tp, XFS_SB_QFLAGS);
-	(void)xfs_trans_commit(tp, 0, NULL);
-}
-
-/*
  * Used to log changes to the superblock unit and width fields which could
  * be altered by the mount options. Only the first superblock is updated.
  */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_mount.h linux-2.5.66-bk3/fs/xfs/xfs_mount.h
--- linux-2.5.66-bk2/fs/xfs/xfs_mount.h	Mon Mar 24 13:59:53 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_mount.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -75,7 +75,6 @@
 struct xfs_chash;
 struct xfs_inode;
 struct xfs_perag;
-struct xfs_quotainfo;
 struct xfs_iocore;
 struct xfs_bmbt_irec;
 struct xfs_bmap_free;
@@ -87,15 +86,120 @@
 #define AIL_LOCK(mp,s)		s=mutex_spinlock(&(mp)->m_ail_lock)
 #define AIL_UNLOCK(mp,s)	mutex_spinunlock(&(mp)->m_ail_lock, s)
 
+
+/*
+ * Prototypes and functions for the Data Migration subsystem.
+ */
+
+typedef int	(*xfs_send_data_t)(int, struct bhv_desc *,
+			xfs_off_t, size_t, int, vrwlock_t *);
+typedef int	(*xfs_send_mmap_t)(struct vm_area_struct *, uint);
+typedef int	(*xfs_send_destroy_t)(struct bhv_desc *, dm_right_t);
+typedef int	(*xfs_send_namesp_t)(dm_eventtype_t, struct bhv_desc *,
+			dm_right_t, struct bhv_desc *, dm_right_t,
+			char *, char *, mode_t, int, int);
+typedef void	(*xfs_send_unmount_t)(struct vfs *, struct vnode *,
+			dm_right_t, mode_t, int, int);
+
+typedef struct xfs_dmops {
+	xfs_send_data_t		xfs_send_data;
+	xfs_send_mmap_t		xfs_send_mmap;
+	xfs_send_destroy_t	xfs_send_destroy;
+	xfs_send_namesp_t	xfs_send_namesp;
+	xfs_send_unmount_t	xfs_send_unmount;
+} xfs_dmops_t;
+
+#define XFS_SEND_DATA(mp, ev,bdp,off,len,fl,lock) \
+	(*(mp)->m_dm_ops.xfs_send_data)(ev,bdp,off,len,fl,lock)
+#define XFS_SEND_MMAP(mp, vma,fl) \
+	(*(mp)->m_dm_ops.xfs_send_mmap)(vma,fl)
+#define XFS_SEND_DESTROY(mp, bdp,right) \
+	(*(mp)->m_dm_ops.xfs_send_destroy)(bdp,right)
+#define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \
+	(*(mp)->m_dm_ops.xfs_send_namesp)(ev,b1,r1,b2,r2,n1,n2,mode,rval,fl)
+#define XFS_SEND_UNMOUNT(mp, vfsp,vp,right,mode,rval,fl) \
+	(*(mp)->m_dm_ops.xfs_send_unmount)(vfsp,vp,right,mode,rval,fl)
+
+
+/*
+ * Prototypes and functions for the Quota Management subsystem.
+ */
+
+struct xfs_dquot;
+struct xfs_dqtrxops;
+struct xfs_quotainfo;
+
+typedef int	(*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
+typedef int	(*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
+typedef int	(*xfs_qmunmount_t)(struct xfs_mount *);
+typedef void	(*xfs_qmdone_t)(struct xfs_mount *);
+typedef void	(*xfs_dqrele_t)(struct xfs_dquot *);
+typedef int	(*xfs_dqattach_t)(struct xfs_inode *, uint);
+typedef void	(*xfs_dqdetach_t)(struct xfs_inode *);
+typedef int	(*xfs_dqpurgeall_t)(struct xfs_mount *, uint);
+typedef int	(*xfs_dqvopalloc_t)(struct xfs_mount *,
+			struct xfs_inode *, uid_t, gid_t, uint,
+			struct xfs_dquot **, struct xfs_dquot **);
+typedef void	(*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *,
+			struct xfs_dquot *, struct xfs_dquot *);
+typedef int	(*xfs_dqvoprename_t)(struct xfs_inode **);
+typedef struct xfs_dquot * (*xfs_dqvopchown_t)(
+			struct xfs_trans *, struct xfs_inode *,
+			struct xfs_dquot **, struct xfs_dquot *);
+typedef int	(*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
+			struct xfs_dquot *, struct xfs_dquot *, uint);
+
+typedef struct xfs_qmops {
+	xfs_qminit_t		xfs_qminit;
+	xfs_qmdone_t		xfs_qmdone;
+	xfs_qmmount_t		xfs_qmmount;
+	xfs_qmunmount_t		xfs_qmunmount;
+	xfs_dqrele_t		xfs_dqrele;
+	xfs_dqattach_t		xfs_dqattach;
+	xfs_dqdetach_t		xfs_dqdetach;
+	xfs_dqpurgeall_t	xfs_dqpurgeall;
+	xfs_dqvopalloc_t	xfs_dqvopalloc;
+	xfs_dqvopcreate_t	xfs_dqvopcreate;
+	xfs_dqvoprename_t	xfs_dqvoprename;
+	xfs_dqvopchown_t	xfs_dqvopchown;
+	xfs_dqvopchownresv_t	xfs_dqvopchownresv;
+	struct xfs_dqtrxops	*xfs_dqtrxops;
+} xfs_qmops_t;
+
+#define XFS_QM_INIT(mp, mnt, fl) \
+	(*(mp)->m_qm_ops.xfs_qminit)(mp, mnt, fl)
+#define XFS_QM_MOUNT(mp, mnt, fl) \
+	(*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl)
+#define XFS_QM_UNMOUNT(mp) \
+	(*(mp)->m_qm_ops.xfs_qmunmount)(mp)
+#define XFS_QM_DONE(mp) \
+	(*(mp)->m_qm_ops.xfs_qmdone)(mp)
+#define XFS_QM_DQRELE(mp, dq) \
+	(*(mp)->m_qm_ops.xfs_dqrele)(dq)
+#define XFS_QM_DQATTACH(mp, ip, fl) \
+	(*(mp)->m_qm_ops.xfs_dqattach)(ip, fl)
+#define XFS_QM_DQDETACH(mp, ip) \
+	(*(mp)->m_qm_ops.xfs_dqdetach)(ip)
+#define XFS_QM_DQPURGEALL(mp, fl) \
+	(*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl)
+#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, fl, dq1, dq2) \
+	(*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, fl, dq1, dq2)
+#define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \
+	(*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2)
+#define XFS_QM_DQVOPRENAME(mp, ip) \
+	(*(mp)->m_qm_ops.xfs_dqvoprename)(ip)
+#define XFS_QM_DQVOPCHOWN(mp, tp, ip, dqp, dq) \
+	(*(mp)->m_qm_ops.xfs_dqvopchown)(tp, ip, dqp, dq)
+#define XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, dq1, dq2, fl) \
+	(*(mp)->m_qm_ops.xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl)
+
+
 /*
  * Prototypes and functions for I/O core modularization.
  */
  
-struct flid;
-struct buf;
-
 typedef int		(*xfs_ioinit_t)(struct vfs *,
-				struct xfs_mount_args *, int *);
+				struct xfs_mount_args *, int);
 typedef int		(*xfs_bmapi_t)(struct xfs_trans *, void *,
 				xfs_fileoff_t, xfs_filblks_t, int,
 				xfs_fsblock_t *, xfs_extlen_t,
@@ -137,61 +241,42 @@
 	xfs_iodone_t			xfs_iodone;
 } xfs_ioops_t;
 
-
 #define XFS_IOINIT(vfsp, args, flags) \
 	(*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags)
-
 #define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist)	\
 	(*(mp)->m_io_ops.xfs_bmapi_func) \
 		(trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist)
-
 #define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \
 	(*(mp)->m_io_ops.xfs_bmap_eof_func) \
 		((io)->io_obj, endoff, whichfork, eof)
-
 #define XFS_IOMAP_WRITE_DIRECT(mp, io, offset, count, flags, mval, nmap, found)\
 	(*(mp)->m_io_ops.xfs_iomap_write_direct) \
 		((io)->io_obj, offset, count, flags, mval, nmap, found)
-
 #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \
 	(*(mp)->m_io_ops.xfs_iomap_write_delay) \
 		((io)->io_obj, offset, count, flags, mval, nmap)
-
 #define XFS_IOMAP_WRITE_ALLOCATE(mp, io, mval, nmap) \
 	(*(mp)->m_io_ops.xfs_iomap_write_allocate) \
 		((io)->io_obj, mval, nmap)
-
 #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \
 	(*(mp)->m_io_ops.xfs_iomap_write_unwritten) \
 		((io)->io_obj, offset, count)
-
 #define XFS_LCK_MAP_SHARED(mp, io) \
 	(*(mp)->m_io_ops.xfs_lck_map_shared)((io)->io_obj)
-
 #define XFS_ILOCK(mp, io, mode) \
 	(*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode)
-
 #define XFS_ILOCK_NOWAIT(mp, io, mode) \
 	(*(mp)->m_io_ops.xfs_ilock_nowait)((io)->io_obj, mode)
-
 #define XFS_IUNLOCK(mp, io, mode) \
 	(*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode)
-
 #define XFS_ILOCK_DEMOTE(mp, io, mode) \
 	(*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode)
-
 #define XFS_SIZE(mp, io) \
 	(*(mp)->m_io_ops.xfs_size_func)((io)->io_obj)
-
 #define XFS_IODONE(vfsp) \
 	(*(mp)->m_io_ops.xfs_iodone)(vfsp)
 
 
-/*
- * Prototypes and functions for the XFS realtime subsystem.
- */
-
-
 typedef struct xfs_mount {
 	bhv_desc_t		m_bhv;		/* vfs xfs behavior */
 	xfs_tid_t		m_tid;		/* next unused tid for fs */
@@ -289,13 +374,9 @@
 	int			m_chsize;	/* size of next field */
 	struct xfs_chash	*m_chash;	/* fs private inode per-cluster
 						 * hash table */
+	struct xfs_dmops	m_dm_ops;	/* vector of DMI ops */
+	struct xfs_qmops	m_qm_ops;	/* vector of XQM ops */
 	struct xfs_ioops	m_io_ops;	/* vector of I/O ops */
-	struct xfs_expinfo	*m_expinfo;	/* info to export to other
-						   cells. */
-	uint64_t		m_shadow_pinmask;
-						/* which bits matter in rpc
-						   log item pin masks */
-	uint			m_cxfstype;	/* mounted shared, etc. */
 	lock_t			m_freeze_lock;	/* Lock for m_frozen */
 	uint			m_frozen;	/* FS frozen for shutdown or
 						 * snapshot */
@@ -324,8 +405,7 @@
 #define XFS_MOUNT_NOALIGN	0x00000080	/* turn off stripe alignment
 						   allocations */
 			     /* 0x00000100	-- currently unused */
-#define XFS_MOUNT_REGISTERED	0x00000200	/* registered with cxfs master
-						   cell logic */
+                             /*	0x00000200	-- currently unused */
 #define XFS_MOUNT_NORECOVERY	0x00000400	/* no recovery - dirty fs */
 #define XFS_MOUNT_SHARED	0x00000800	/* shared mount */
 #define XFS_MOUNT_DFLT_IOSIZE	0x00001000	/* set default i/o size */
@@ -336,14 +416,6 @@
 						 * 32 bits in size */
 #define XFS_MOUNT_NOLOGFLUSH	0x00010000
 
-/*
- * Flags for m_cxfstype
- */
-#define XFS_CXFS_NOT		0x00000001	/* local mount */
-#define XFS_CXFS_SERVER		0x00000002	/* we're the CXFS server */
-#define XFS_CXFS_CLIENT		0x00000004	/* We're a CXFS client */
-#define XFS_CXFS_REC_ENABLED	0x00000008	/* recovery is enabled */
-
 #define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
 
 /*
@@ -370,15 +442,17 @@
 #define XFS_WSYNC_READIO_LOG	15	/* 32K */
 #define XFS_WSYNC_WRITEIO_LOG	14	/* 16K */
 
-#define xfs_force_shutdown(m,f)	VFS_FORCE_SHUTDOWN(XFS_MTOVFS(m),f)
+#define xfs_force_shutdown(m,f)	\
+	VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
+
 /*
  * Flags sent to xfs_force_shutdown.
  */
 #define XFS_METADATA_IO_ERROR	0x1
 #define XFS_LOG_IO_ERROR	0x2
 #define XFS_FORCE_UMOUNT	0x4
-#define XFS_CORRUPT_INCORE	0x8	/* corrupt in-memory data structures */
-#define XFS_SHUTDOWN_REMOTE_REQ 0x10	/* shutdown came from remote cell */
+#define XFS_CORRUPT_INCORE	0x8	/* Corrupt in-memory data structures */
+#define XFS_SHUTDOWN_REMOTE_REQ 0x10	/* Shutdown came from remote cell */
 
 /*
  * xflags for xfs_syncsub
@@ -388,9 +462,7 @@
 /*
  * Flags for xfs_mountfs
  */
-#define XFS_MFSI_SECOND		0x01	/* Is a cxfs secondary mount -- skip */
-					/* stuff which should only be done */
-					/* once. */
+#define XFS_MFSI_SECOND		0x01	/* Secondary mount -- skip stuff */
 #define XFS_MFSI_CLIENT		0x02	/* Is a client -- skip lots of stuff */
 #define XFS_MFSI_NOUNLINK	0x08	/* Skip unlinked inode processing in */
 					/* log recovery */
@@ -410,6 +482,13 @@
 #else
 #define XFS_BHVTOM(bdp)		((xfs_mount_t *)BHV_PDATA(bdp))
 #endif
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_VFSTOM)
+xfs_mount_t *xfs_vfstom(vfs_t *vfs);
+#define XFS_VFSTOM(vfs) xfs_vfstom(vfs)
+#else
+#define XFS_VFSTOM(vfs)		\
+	(XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops)))
+#endif
 
 
 /*
@@ -447,7 +526,7 @@
  */
 typedef struct xfs_mod_sb {
 	xfs_sb_field_t	msb_field;	/* Field to modify, see below */
-	int		msb_delta;	/* change to make to the specified field */
+	int		msb_delta;	/* Change to make to specified field */
 } xfs_mod_sb_t;
 
 #define XFS_MOUNT_ILOCK(mp)	mutex_lock(&((mp)->m_ilock), PINOD)
@@ -455,24 +534,26 @@
 #define XFS_SB_LOCK(mp)		mutex_spinlock(&(mp)->m_sb_lock)
 #define XFS_SB_UNLOCK(mp,s)	mutex_spinunlock(&(mp)->m_sb_lock,(s))
 
-void		xfs_mod_sb(xfs_trans_t *, __int64_t);
-xfs_mount_t	*xfs_mount_init(void);
-void		xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
-int		xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int);
-
-int		xfs_unmountfs(xfs_mount_t *, struct cred *);
-void		xfs_unmountfs_close(xfs_mount_t *, struct cred *);
-int		xfs_unmountfs_writesb(xfs_mount_t *);
-int		xfs_unmount_flush(xfs_mount_t *, int);
-int		xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int);
-int		xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int);
-int		xfs_readsb(xfs_mount_t *mp);
-struct xfs_buf	*xfs_getsb(xfs_mount_t *, int);
-void		xfs_freesb(xfs_mount_t *);
-void		xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
-int		xfs_syncsub(xfs_mount_t *, int, int, int *);
-void		xfs_initialize_perag(xfs_mount_t *, int);
-void		xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t);
+extern xfs_mount_t *xfs_mount_init(void);
+extern void	xfs_mod_sb(xfs_trans_t *, __int64_t);
+extern void	xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
+extern int	xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int);
+
+extern int	xfs_unmountfs(xfs_mount_t *, struct cred *);
+extern void	xfs_unmountfs_close(xfs_mount_t *, struct cred *);
+extern int	xfs_unmountfs_writesb(xfs_mount_t *);
+extern int	xfs_unmount_flush(xfs_mount_t *, int);
+extern int	xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int);
+extern int	xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
+			uint, int);
+extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
+extern int	xfs_readsb(xfs_mount_t *mp);
+extern void	xfs_freesb(xfs_mount_t *);
+extern void	xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
+extern int	xfs_syncsub(xfs_mount_t *, int, int, int *);
+extern void	xfs_initialize_perag(xfs_mount_t *, int);
+extern void	xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t,
+			__int64_t);
 
 /*
  * Flags for freeze operations.
@@ -480,11 +561,19 @@
 #define XFS_FREEZE_WRITE	1
 #define XFS_FREEZE_TRANS	2
 
-void		xfs_start_freeze(xfs_mount_t *, int);
-void		xfs_finish_freeze(xfs_mount_t *);
-void		xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int);
+extern void	xfs_start_freeze(xfs_mount_t *, int);
+extern void	xfs_finish_freeze(xfs_mount_t *);
+extern void	xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int);
+
+extern struct vfsops xfs_vfsops;
+extern struct vnodeops xfs_vnodeops;
+
+extern struct xfs_dmops xfs_dmcore_xfs;
+extern struct xfs_qmops xfs_qmcore_xfs;
+extern struct xfs_ioops xfs_iocore_xfs;
 
-extern	struct vfsops xfs_vfsops;
+extern int 	xfs_init(void);
+extern void	xfs_cleanup(void);
 
 #endif	/* __KERNEL__ */
 
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_qm.c linux-2.5.66-bk3/fs/xfs/xfs_qm.c
--- linux-2.5.66-bk2/fs/xfs/xfs_qm.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_qm.c	Wed Dec 31 16:00:00 1969
@@ -1,2810 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-kmem_zone_t	*qm_dqzone;
-kmem_zone_t	*qm_dqtrxzone;
-
-STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);
-STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);
-STATIC int	xfs_qm_quotacheck(xfs_mount_t *);
-
-STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
-STATIC void	xfs_qm_shake(void);
-
-#ifdef DEBUG
-extern mutex_t	qcheck_lock;
-#endif
-
-#ifdef QUOTADEBUG
-#define XQM_LIST_PRINT(l, NXT, title) \
-{ \
-	  xfs_dquot_t	*dqp; int i = 0;\
-	  printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \
-	  for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \
-	    printk("\t%d.\t\"%d (%s)\"\t bcnt = %d, icnt = %d refs = %d\n", \
-			 ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \
-			 DQFLAGTO_TYPESTR(dqp),	     \
-			 (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \
-			 (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \
-			 (int) dqp->q_nrefs);  } \
-}
-#endif
-
-/*
- * Initialize the XQM structure.
- * Note that there is not one quota manager per file system.
- */
-struct xfs_qm *
-xfs_qm_init(void)
-{
-	xfs_qm_t		*xqm;
-	int			hsize, i;
-
-	xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
-	ASSERT(xqm);
-
-	/*
-	 * Initialize the dquot hash tables.
-	 */
-	hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ?
-		XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH;
-	xqm->qm_dqhashmask = hsize - 1;
-
-	/*
-	 * XXXsup We could keep reference counts on usr and grp quotas
-	 * inside XQM separately, and avoid having two hashtables even
-	 * when only one 'type' is active in the system.
-	 */
-	xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
-						      sizeof(xfs_dqhash_t),
-						      KM_SLEEP);
-	xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
-						      sizeof(xfs_dqhash_t),
-						      KM_SLEEP);
-	ASSERT(xqm->qm_usr_dqhtable != NULL);
-	ASSERT(xqm->qm_grp_dqhtable != NULL);
-
-	for (i = 0; i < hsize; i++) {
-		xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
-		xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
-	}
-
-	/*
-	 * Freelist of all dquots of all file systems
-	 */
-	xfs_qm_freelist_init(&(xqm->qm_dqfreelist));
-
-	/*
-	 * dquot zone. we register our own low-memory callback.
-	 */
-	if (!qm_dqzone) {
-		xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
-						"xfs_dquots");
-		qm_dqzone = xqm->qm_dqzone;
-	} else
-		xqm->qm_dqzone = qm_dqzone;
-
-	kmem_shake_register(xfs_qm_shake);
-
-	/*
-	 * The t_dqinfo portion of transactions.
-	 */
-	if (!qm_dqtrxzone) {
-		xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
-						   "xfs_dqtrx");
-		qm_dqtrxzone = xqm->qm_dqtrxzone;
-	} else
-		xqm->qm_dqtrxzone = qm_dqtrxzone;
-
-	atomic_set(&xqm->qm_totaldquots, 0);
-	xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
-	xqm->qm_nrefs = 0;
-#ifdef DEBUG
-	mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");
-#endif
-	return (xqm);
-}
-
-/*
- * Destroy the global quota manager when its reference count goes to zero.
- */
-void
-xfs_qm_destroy(
-	struct xfs_qm *xqm)
-{
-	int	hsize, i;
-
-	ASSERT(xqm != NULL);
-	ASSERT(xqm->qm_nrefs == 0);
-	kmem_shake_deregister(xfs_qm_shake);
-	hsize = xqm->qm_dqhashmask + 1;
-	for (i = 0; i < hsize; i++) {
-		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
-		xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
-	}
-	kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));
-	kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
-	xqm->qm_usr_dqhtable = NULL;
-	xqm->qm_grp_dqhtable = NULL;
-	xqm->qm_dqhashmask = 0;
-	xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));
-#ifdef DEBUG
-	mutex_destroy(&qcheck_lock);
-#endif
-	kmem_free(xqm, sizeof(xfs_qm_t));
-}
-
-/*
- * Called at mount time to let XQM know that another file system is
- * starting quotas. This isn't crucial information as the individual mount
- * structures are pretty independent, but it helps the XQM keep a
- * global view of what's going on.
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_hold_quotafs_ref(
-	struct xfs_mount *mp)
-{
-	/*
-	 * Need to lock the xfs_Gqm structure for things like this. For example,
-	 * the structure could disappear between the entry to this routine and
-	 * a HOLD operation if not locked.
-	 */
-	XFS_QM_LOCK(xfs_Gqm);
-
-	if (xfs_Gqm == NULL) {
-		if ((xfs_Gqm = xfs_qm_init()) == NULL) {
-			return (XFS_ERROR(EINVAL));
-		}
-	}
-	/*
-	 * We can keep a list of all filesystems with quotas mounted for
-	 * debugging and statistical purposes, but ...
-	 * Just take a reference and get out.
-	 */
-	XFS_QM_HOLD(xfs_Gqm);
-	XFS_QM_UNLOCK(xfs_Gqm);
-
-	return 0;
-}
-
-
-/*
- * Release the reference that a filesystem took at mount time,
- * so that we know when we need to destroy the entire quota manager.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_rele_quotafs_ref(
-	struct xfs_mount *mp)
-{
-	xfs_dquot_t	*dqp, *nextdqp;
-
-	ASSERT(xfs_Gqm);
-	ASSERT(xfs_Gqm->qm_nrefs > 0);
-
-	/*
-	 * Go thru the freelist and destroy all inactive dquots.
-	 */
-	xfs_qm_freelist_lock(xfs_Gqm);
-
-	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
-	     dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {
-		xfs_dqlock(dqp);
-		nextdqp = dqp->dq_flnext;
-		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-			ASSERT(dqp->q_mount == NULL);
-			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-			ASSERT(dqp->HL_PREVP == NULL);
-			ASSERT(dqp->MPL_PREVP == NULL);
-			XQM_FREELIST_REMOVE(dqp);
-			xfs_dqunlock(dqp);
-			xfs_qm_dqdestroy(dqp);
-		} else {
-			xfs_dqunlock(dqp);
-		}
-		dqp = nextdqp;
-	}
-	xfs_qm_freelist_unlock(xfs_Gqm);
-
-	/*
-	 * Destroy the entire XQM. If somebody mounts with quotaon, this'll
-	 * be restarted.
-	 */
-	XFS_QM_LOCK(xfs_Gqm);
-	XFS_QM_RELE(xfs_Gqm);
-	if (xfs_Gqm->qm_nrefs == 0) {
-		xfs_qm_destroy(xfs_Gqm);
-		xfs_Gqm = NULL;
-	}
-	XFS_QM_UNLOCK(xfs_Gqm);
-}
-
-/*
- * This is called at mount time from xfs_mountfs to initialize the quotainfo
- * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
- * so already.	Note that the superblock has not been read in yet.
- */
-void
-xfs_qm_mount_quotainit(
-	xfs_mount_t	*mp,
-	uint		flags)
-{
-	/*
-	 * User or group quotas has to be on.
-	 */
-	ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
-
-	/*
-	 * Initialize the flags in the mount structure. From this point
-	 * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.
-	 * Note that we enforce nothing if accounting is off.
-	 * ie.	XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.
-	 * It isn't necessary to take the quotaoff lock to do this; this is
-	 * called from mount.
-	 */
-	if (flags & XFSMNT_UQUOTA) {
-		mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
-		if (flags & XFSMNT_UQUOTAENF)
-			mp->m_qflags |= XFS_UQUOTA_ENFD;
-	}
-	if (flags & XFSMNT_GQUOTA) {
-		mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
-		if (flags & XFSMNT_GQUOTAENF)
-			mp->m_qflags |= XFS_GQUOTA_ENFD;
-	}
-}
-
-/*
- * Just destroy the quotainfo structure.
- */
-void
-xfs_qm_unmount_quotadestroy(
-	xfs_mount_t	*mp)
-{
-	xfs_qm_destroy_quotainfo(mp);
-}
-
-
-/*
- * This is called from xfs_mountfs to start quotas and initialize all
- * necessary data structures like quotainfo.  This is also responsible for
- * running a quotacheck as necessary.  We are guaranteed that the superblock
- * is consistently read in at this point.
- */
-int
-xfs_qm_mount_quotas(
-	xfs_mount_t	*mp)
-{
-	unsigned long	s;
-	int		error = 0;
-	uint		sbf;
-
-	/*
-	 * If a file system had quotas running earlier, but decided to
-	 * mount without -o quota/uquota/gquota options, revoke the
-	 * quotachecked license, and bail out.
-	 */
-	if (! XFS_IS_QUOTA_ON(mp) &&
-	    (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
-		mp->m_qflags = 0;
-		goto write_changes;
-	}
-
-	/*
-	 * If quotas on realtime volumes is not supported, we disable
-	 * quotas immediately.
-	 */
-	if (mp->m_sb.sb_rextents) {
-		cmn_err(CE_NOTE,
-			"Cannot turn on quotas for realtime filesystem %s",
-			mp->m_fsname);
-		mp->m_qflags = 0;
-		goto write_changes;
-	}
-
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-	cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
-#endif
-
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-	/*
-	 * Allocate the quotainfo structure inside the mount struct, and
-	 * create quotainode(s), and change/rev superblock if necessary.
-	 */
-	if ((error = xfs_qm_init_quotainfo(mp))) {
-		/*
-		 * We must turn off quotas.
-		 */
-		ASSERT(mp->m_quotainfo == NULL);
-		mp->m_qflags = 0;
-		goto write_changes;
-	}
-	/*
-	 * If any of the quotas are not consistent, do a quotacheck.
-	 */
-	if (XFS_QM_NEED_QUOTACHECK(mp)) {
-#ifdef DEBUG
-		cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
-#endif
-		if ((error = xfs_qm_quotacheck(mp))) {
-			cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
-				"Disabling quotas.",
-				error);
-			/*
-			 * We must turn off quotas.
-			 */
-			ASSERT(mp->m_quotainfo != NULL);
-			ASSERT(xfs_Gqm != NULL);
-			xfs_qm_destroy_quotainfo(mp);
-			mp->m_qflags = 0;
-			goto write_changes;
-		}
-#ifdef DEBUG
-		cmn_err(CE_NOTE, "Done quotacheck.");
-#endif
-	}
- write_changes:
-	/*
-	 * We actually don't have to acquire the SB_LOCK at all.
-	 * This can only be called from mount, and that's single threaded. XXX
-	 */
-	s = XFS_SB_LOCK(mp);
-	sbf = mp->m_sb.sb_qflags;
-	mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
-	XFS_SB_UNLOCK(mp, s);
-
-	if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
-		if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
-			/*
-			 * We could only have been turning quotas off.
-			 * We aren't in very good shape actually because
-			 * the incore structures are convinced that quotas are
-			 * off, but the on disk superblock doesn't know that !
-			 */
-			ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
-			xfs_fs_cmn_err(CE_ALERT, mp,
-				"XFS mount_quotas: Superblock update failed!");
-		}
-	}
-
-	if (error) {
-		xfs_fs_cmn_err(CE_WARN, mp,
-			"Failed to initialize disk quotas.");
-	}
-	return XFS_ERROR(error);
-}
-
-/*
- * Called from the vfsops layer.
- */
-int
-xfs_qm_unmount_quotas(
-	xfs_mount_t	*mp)
-{
-	xfs_inode_t	*uqp, *gqp;
-	int		error;
-
-	error = 0;
-
-	/*
-	 * Release the dquots that root inode, et al might be holding,
-	 * before we flush quotas and blow away the quotainfo structure.
-	 */
-	ASSERT(mp->m_rootip);
-	if (mp->m_rootip->i_udquot || mp->m_rootip->i_gdquot)
-		xfs_qm_dqdettach_inode(mp->m_rootip);
-	if (mp->m_rbmip &&
-	    (mp->m_rbmip->i_udquot || mp->m_rbmip->i_gdquot))
-		xfs_qm_dqdettach_inode(mp->m_rbmip);
-	if (mp->m_rsumip &&
-	    (mp->m_rsumip->i_udquot || mp->m_rsumip->i_gdquot))
-		xfs_qm_dqdettach_inode(mp->m_rsumip);
-
-	/*
-	 * Flush out the quota inodes.
-	 */
-	uqp = gqp = NULL;
-	if (mp->m_quotainfo) {
-		if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
-			xfs_ilock(uqp, XFS_ILOCK_EXCL);
-			xfs_iflock(uqp);
-			error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
-			xfs_iunlock(uqp, XFS_ILOCK_EXCL);
-			if (unlikely(error == EFSCORRUPTED)) {
-				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
-						 XFS_ERRLEVEL_LOW, mp);
-				goto out;
-			}
-		}
-		if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
-			xfs_ilock(gqp, XFS_ILOCK_EXCL);
-			xfs_iflock(gqp);
-			error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
-			xfs_iunlock(gqp, XFS_ILOCK_EXCL);
-			if (unlikely(error == EFSCORRUPTED)) {
-				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
-						 XFS_ERRLEVEL_LOW, mp);
-				goto out;
-			}
-		}
-	}
-	if (uqp) {
-		 XFS_PURGE_INODE(uqp);
-		 mp->m_quotainfo->qi_uquotaip = NULL;
-	}
-	if (gqp) {
-		XFS_PURGE_INODE(gqp);
-		mp->m_quotainfo->qi_gquotaip = NULL;
-	}
-out:
-	return XFS_ERROR(error);
-}
-
-/*
- * Flush all dquots of the given file system to disk. The dquots are
- * _not_ purged from memory here, just their data written to disk.
- */
-int
-xfs_qm_dqflush_all(
-	xfs_mount_t	*mp,
-	int		flags)
-{
-	int		recl;
-	xfs_dquot_t	*dqp;
-	int		niters;
-	int		error;
-
-	if (mp->m_quotainfo == NULL)
-		return (0);
-	niters = 0;
-again:
-	xfs_qm_mplist_lock(mp);
-	FOREACH_DQUOT_IN_MP(dqp, mp) {
-		xfs_dqlock(dqp);
-		if (! XFS_DQ_IS_DIRTY(dqp)) {
-			xfs_dqunlock(dqp);
-			continue;
-		}
-		xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");
-		/* XXX a sentinel would be better */
-		recl = XFS_QI_MPLRECLAIMS(mp);
-		if (! xfs_qm_dqflock_nowait(dqp)) {
-			/*
-			 * If we can't grab the flush lock then check
-			 * to see if the dquot has been flushed delayed
-			 * write.  If so, grab its buffer and send it
-			 * out immediately.  We'll be able to acquire
-			 * the flush lock when the I/O completes.
-			 */
-			xfs_qm_dqflock_pushbuf_wait(dqp);
-		}
-		/*
-		 * Let go of the mplist lock. We don't want to hold it
-		 * across a disk write.
-		 */
-		xfs_qm_mplist_unlock(mp);
-		error = xfs_qm_dqflush(dqp, flags);
-		xfs_dqunlock(dqp);
-		if (error)
-			return (error);
-
-		xfs_qm_mplist_lock(mp);
-		if (recl != XFS_QI_MPLRECLAIMS(mp)) {
-			xfs_qm_mplist_unlock(mp);
-			/* XXX restart limit */
-			goto again;
-		}
-	}
-
-	xfs_qm_mplist_unlock(mp);
-	/* return ! busy */
-	return (0);
-}
-/*
- * Release the group dquot pointers the user dquots may be
- * carrying around as a hint. mplist is locked on entry and exit.
- */
-STATIC void
-xfs_qm_detach_gdquots(
-	xfs_mount_t	*mp)
-{
-	xfs_dquot_t	*dqp, *gdqp;
-	int		nrecl;
-
- again:
-	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-	dqp = XFS_QI_MPLNEXT(mp);
-	while (dqp) {
-		xfs_dqlock(dqp);
-		if ((gdqp = dqp->q_gdquot)) {
-			xfs_dqlock(gdqp);
-			dqp->q_gdquot = NULL;
-		}
-		xfs_dqunlock(dqp);
-
-		if (gdqp) {
-			/*
-			 * Can't hold the mplist lock across a dqput.
-			 * XXXmust convert to marker based iterations here.
-			 */
-			nrecl = XFS_QI_MPLRECLAIMS(mp);
-			xfs_qm_mplist_unlock(mp);
-			xfs_qm_dqput(gdqp);
-
-			xfs_qm_mplist_lock(mp);
-			if (nrecl != XFS_QI_MPLRECLAIMS(mp))
-				goto again;
-		}
-		dqp = dqp->MPL_NEXT;
-	}
-}
-
-/*
- * Go through all the incore dquots of this file system and take them
- * off the mplist and hashlist, if the dquot type matches the dqtype
- * parameter. This is used when turning off quota accounting for
- * users and/or groups, as well as when the filesystem is unmounting.
- */
-int
-xfs_qm_dqpurge_all(
-		   xfs_mount_t	*mp,
-		   uint		flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
-{
-	xfs_dquot_t	*dqp;
-	uint		dqtype;
-	int		nrecl;
-	xfs_dquot_t	*nextdqp;
-	int		nmisses;
-
-	if (mp->m_quotainfo == NULL)
-		return (0);
-
-	dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
-	dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
-
-	xfs_qm_mplist_lock(mp);
-
-	/*
-	 * In the first pass through all incore dquots of this filesystem,
-	 * we release the group dquot pointers the user dquots may be
-	 * carrying around as a hint. We need to do this irrespective of
-	 * what's being turned off.
-	 */
-	xfs_qm_detach_gdquots(mp);
-
-      again:
-	nmisses = 0;
-	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-	/*
-	 * Try to get rid of all of the unwanted dquots. The idea is to
-	 * get them off mplist and hashlist, but leave them on freelist.
-	 */
-	dqp = XFS_QI_MPLNEXT(mp);
-	while (dqp) {
-		/*
-		 * It's OK to look at the type without taking dqlock here.
-		 * We're holding the mplist lock here, and that's needed for
-		 * a dqreclaim.
-		 */
-		if ((dqp->dq_flags & dqtype) == 0) {
-			dqp = dqp->MPL_NEXT;
-			continue;
-		}
-
-		if (! xfs_qm_dqhashlock_nowait(dqp)) {
-			nrecl = XFS_QI_MPLRECLAIMS(mp);
-			xfs_qm_mplist_unlock(mp);
-			XFS_DQ_HASH_LOCK(dqp->q_hash);
-			xfs_qm_mplist_lock(mp);
-
-			/*
-			 * XXXTheoretically, we can get into a very long
-			 * ping pong game here.
-			 * No one can be adding dquots to the mplist at
-			 * this point, but somebody might be taking things off.
-			 */
-			if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
-				XFS_DQ_HASH_UNLOCK(dqp->q_hash);
-				goto again;
-			}
-		}
-
-		/*
-		 * Take the dquot off the mplist and hashlist. It may remain on
-		 * freelist in INACTIVE state.
-		 */
-		nextdqp = dqp->MPL_NEXT;
-		nmisses += xfs_qm_dqpurge(dqp, flags);
-		dqp = nextdqp;
-	}
-	xfs_qm_mplist_unlock(mp);
-	return (nmisses);
-}
-
-STATIC int
-xfs_qm_dqattach_one(
-	xfs_inode_t	*ip,
-	xfs_dqid_t	id,
-	uint		type,
-	uint		doalloc,
-	uint		dolock,
-	xfs_dquot_t	*udqhint, /* hint */
-	xfs_dquot_t	**IO_idqpp)
-{
-	xfs_dquot_t	*dqp;
-	int		error;
-
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	error = 0;
-	/*
-	 * See if we already have it in the inode itself. IO_idqpp is
-	 * &i_udquot or &i_gdquot. This made the code look weird, but
-	 * made the logic a lot simpler.
-	 */
-	if ((dqp = *IO_idqpp)) {
-		if (dolock)
-			xfs_dqlock(dqp);
-		xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
-		goto done;
-	}
-
-	/*
-	 * udqhint is the i_udquot field in inode, and is non-NULL only
-	 * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
-	 * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
-	 * the user dquot.
-	 */
-	ASSERT(!udqhint || type == XFS_DQ_GROUP);
-	if (udqhint && !dolock)
-		xfs_dqlock(udqhint);
-
-	/*
-	 * No need to take dqlock to look at the id.
-	 * The ID can't change until it gets reclaimed, and it won't
-	 * be reclaimed as long as we have a ref from inode and we hold
-	 * the ilock.
-	 */
-	if (udqhint &&
-	    (dqp = udqhint->q_gdquot) &&
-	    (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) {
-		ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-		xfs_dqlock(dqp);
-		XFS_DQHOLD(dqp);
-		ASSERT(*IO_idqpp == NULL);
-		*IO_idqpp = dqp;
-		if (!dolock) {
-			xfs_dqunlock(dqp);
-			xfs_dqunlock(udqhint);
-		}
-		/* XXX XFS_STATS */
-		goto done;
-	}
-	/*
-	 * We can't hold a dquot lock when we call the dqget code.
-	 * We'll deadlock in no time, because of (not conforming to)
-	 * lock ordering - the inodelock comes before any dquot lock,
-	 * and we may drop and reacquire the ilock in xfs_qm_dqget().
-	 */
-	if (udqhint)
-		xfs_dqunlock(udqhint);
-	/*
-	 * Find the dquot from somewhere. This bumps the
-	 * reference count of dquot and returns it locked.
-	 * This can return ENOENT if dquot didn't exist on
-	 * disk and we didn't ask it to allocate;
-	 * ESRCH if quotas got turned off suddenly.
-	 */
-	if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
-				 doalloc|XFS_QMOPT_DOWARN, &dqp))) {
-		if (udqhint && dolock)
-			xfs_dqlock(udqhint);
-		goto done;
-	}
-
-	xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
-	/*
-	 * dqget may have dropped and re-acquired the ilock, but it guarantees
-	 * that the dquot returned is the one that should go in the inode.
-	 */
-	*IO_idqpp = dqp;
-	ASSERT(dqp);
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	if (! dolock) {
-		xfs_dqunlock(dqp);
-		ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint));
-		goto done;
-	}
-	if (! udqhint)
-		goto done;
-
-	ASSERT(udqhint);
-	ASSERT(dolock);
-	ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	if (! xfs_qm_dqlock_nowait(udqhint)) {
-		xfs_dqunlock(dqp);
-		xfs_dqlock(udqhint);
-		xfs_dqlock(dqp);
-	}
-      done:
-#ifdef QUOTADEBUG
-	if (udqhint) {
-		if (dolock)
-			ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-		else
-			ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
-	}
-	if (! error) {
-		if (dolock)
-			ASSERT(XFS_DQ_IS_LOCKED(dqp));
-		else
-			ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-	}
-#endif
-	return (error);
-}
-
-
-/*
- * Given a udquot and gdquot, attach a ptr to the group dquot in the
- * udquot as a hint for future lookups. The idea sounds simple, but the
- * execution isn't, because the udquot might have a group dquot attached
- * already and getting rid of that gets us into lock ordering contraints.
- * The process is complicated more by the fact that the dquots may or may not
- * be locked on entry.
- */
-STATIC void
-xfs_qm_dqattach_grouphint(
-	xfs_dquot_t	*udq,
-	xfs_dquot_t	*gdq,
-	uint		locked)
-{
-	xfs_dquot_t	*tmp;
-
-#ifdef QUOTADEBUG
-	if (locked) {
-		ASSERT(XFS_DQ_IS_LOCKED(udq));
-		ASSERT(XFS_DQ_IS_LOCKED(gdq));
-	} else {
-		ASSERT(! XFS_DQ_IS_LOCKED(udq));
-		ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-	}
-#endif
-	if (! locked)
-		xfs_dqlock(udq);
-
-	if ((tmp = udq->q_gdquot)) {
-		if (tmp == gdq) {
-			if (! locked)
-				xfs_dqunlock(udq);
-			return;
-		}
-
-		udq->q_gdquot = NULL;
-		/*
-		 * We can't keep any dqlocks when calling dqrele,
-		 * because the freelist lock comes before dqlocks.
-		 */
-		xfs_dqunlock(udq);
-		if (locked)
-			xfs_dqunlock(gdq);
-		/*
-		 * we took a hard reference once upon a time in dqget,
-		 * so give it back when the udquot no longer points at it
-		 * dqput() does the unlocking of the dquot.
-		 */
-		xfs_qm_dqrele(tmp);
-
-		ASSERT(! XFS_DQ_IS_LOCKED(udq));
-		ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-		xfs_dqlock(udq);
-		xfs_dqlock(gdq);
-
-	} else {
-		ASSERT(XFS_DQ_IS_LOCKED(udq));
-		if (! locked) {
-			ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-			xfs_dqlock(gdq);
-		}
-	}
-
-	ASSERT(XFS_DQ_IS_LOCKED(udq));
-	ASSERT(XFS_DQ_IS_LOCKED(gdq));
-	/*
-	 * Somebody could have attached a gdquot here,
-	 * when we dropped the uqlock. If so, just do nothing.
-	 */
-	if (udq->q_gdquot == NULL) {
-		XFS_DQHOLD(gdq);
-		udq->q_gdquot = gdq;
-	}
-	if (! locked) {
-		xfs_dqunlock(gdq);
-		xfs_dqunlock(udq);
-	}
-}
-
-
-/*
- * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
- * in to account.
- * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
- * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
- * much made this code a complete mess, but it has been pretty useful.
- * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
- * Inode may get unlocked and relocked in here, and the caller must deal with
- * the consequences.
- */
-int
-xfs_qm_dqattach(
-		xfs_inode_t	*ip,
-		uint		flags)
-{
-	int		error;
-	xfs_mount_t	*mp;
-	uint		nquotas;
-
-	mp = ip->i_mount;
-	ASSERT(ip->i_ino != mp->m_sb.sb_uquotino &&
-	       ip->i_ino != mp->m_sb.sb_gquotino);
-
-	ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
-	       XFS_ISLOCKED_INODE_EXCL(ip));
-
-	nquotas = 0;
-	error = 0;
-	if (! (flags & XFS_QMOPT_ILOCKED))
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-	if (XFS_IS_UQUOTA_ON(mp)) {
-		if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
-						flags & XFS_QMOPT_DQALLOC,
-						flags & XFS_QMOPT_DQLOCK,
-						NULL, &ip->i_udquot)))
-			goto done;
-		nquotas++;
-	}
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	if (XFS_IS_GQUOTA_ON(mp)) {
-		if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-						flags & XFS_QMOPT_DQALLOC,
-						flags & XFS_QMOPT_DQLOCK,
-						ip->i_udquot, &ip->i_gdquot)))
-			/*
-			 * Don't worry about the udquot that we may have
-			 * attached above. It'll get dettached, if not already.
-			 */
-			goto done;
-		nquotas++;
-	}
-
-	/*
-	 * Attach this group quota to the user quota as a hint.
-	 * This WON'T, in general, result in a thrash.
-	 */
-	if (nquotas == 2) {
-		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-		ASSERT(ip->i_udquot);
-		ASSERT(ip->i_gdquot);
-
-		/*
-		 * We may or may not have the i_udquot locked at this point,
-		 * but this check is OK since we don't depend on the i_gdquot to
-		 * be accurate 100% all the time. It is just a hint, and this
-		 * will succeed in general.
-		 */
-		if (ip->i_udquot->q_gdquot == ip->i_gdquot)
-			goto done;
-		/*
-		 * Attach i_gdquot to the gdquot hint inside the i_udquot.
-		 */
-		xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
-					 flags & XFS_QMOPT_DQLOCK);
-	}
-
-      done:
-
-#ifdef QUOTADEBUG
-	if (! error) {
-		if (ip->i_udquot) {
-			if (flags & XFS_QMOPT_DQLOCK)
-				ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
-			else
-				ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
-		}
-		if (ip->i_gdquot) {
-			if (flags & XFS_QMOPT_DQLOCK)
-				ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
-			else
-				ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
-		}
-		if (XFS_IS_UQUOTA_ON(mp))
-			ASSERT(ip->i_udquot);
-		if (XFS_IS_GQUOTA_ON(mp))
-			ASSERT(ip->i_gdquot);
-	}
-#endif
-
-	if (! (flags & XFS_QMOPT_ILOCKED))
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-#ifdef QUOTADEBUG
-	else
-		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-#endif
-	return (error);
-}
-
-/*
- * Release dquots (and their references) if any.
- * The inode should be locked EXCL except when this's called by
- * xfs_ireclaim.
- */
-void
-xfs_qm_dqdettach_inode(
-	xfs_inode_t	*ip)
-{
-	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
-	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
-	if (ip->i_udquot)
-		xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
-	if (ip->i_udquot) {
-		xfs_qm_dqrele(ip->i_udquot);
-		ip->i_udquot = NULL;
-	}
-	if (ip->i_gdquot) {
-		xfs_qm_dqrele(ip->i_gdquot);
-		ip->i_gdquot = NULL;
-	}
-}
-
-int
-xfs_qm_unmount(
-	xfs_mount_t	*mp)
-{
-	vnode_t		*vp;
-
-	if (XFS_IS_UQUOTA_ON(mp)) {
-		vp = XFS_ITOV(XFS_QI_UQIP(mp));
-		VN_RELE(vp);
-		if (vn_count(vp) > 1)
-			cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d",
-				vp, vn_count(vp));
-	}
-	if (XFS_IS_GQUOTA_ON(mp)) {
-		vp = XFS_ITOV(XFS_QI_GQIP(mp));
-		VN_RELE(vp);
-		if (vn_count(vp) > 1)
-			cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d",
-				vp, vn_count(vp));
-	}
-
-	return (0);
-}
-
-
-/*
- * This is called by xfs_sync and flags arg determines the caller,
- * and its motives, as done in xfs_sync.
- *
- * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
- * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
- * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
- */
-
-int
-xfs_qm_sync(
-	xfs_mount_t	*mp,
-	short		flags)
-{
-	int		recl, restarts;
-	xfs_dquot_t	*dqp;
-	uint		flush_flags;
-	boolean_t	nowait;
-	int		error;
-
-	restarts = 0;
-	/*
-	 * We won't block unless we are asked to.
-	 */
-	nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
-
-  again:
-	xfs_qm_mplist_lock(mp);
-	/*
-	 * dqpurge_all() also takes the mplist lock and iterate thru all dquots
-	 * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
-	 * when we have the mplist lock, we know that dquots will be consistent
-	 * as long as we have it locked.
-	 */
-	if (! XFS_IS_QUOTA_ON(mp)) {
-		xfs_qm_mplist_unlock(mp);
-		return (0);
-	}
-	FOREACH_DQUOT_IN_MP(dqp, mp) {
-		/*
-		 * If this is vfs_sync calling, then skip the dquots that
-		 * don't 'seem' to be dirty. ie. don't acquire dqlock.
-		 * This is very similar to what xfs_sync does with inodes.
-		 */
-		if (flags & SYNC_BDFLUSH) {
-			if (! XFS_DQ_IS_DIRTY(dqp))
-				continue;
-		}
-
-		if (nowait) {
-			/*
-			 * Try to acquire the dquot lock. We are NOT out of
-			 * lock order, but we just don't want to wait for this
-			 * lock, unless somebody wanted us to.
-			 */
-			if (! xfs_qm_dqlock_nowait(dqp))
-				continue;
-		} else {
-			xfs_dqlock(dqp);
-		}
-
-		/*
-		 * Now, find out for sure if this dquot is dirty or not.
-		 */
-		if (! XFS_DQ_IS_DIRTY(dqp)) {
-			xfs_dqunlock(dqp);
-			continue;
-		}
-
-		/* XXX a sentinel would be better */
-		recl = XFS_QI_MPLRECLAIMS(mp);
-		if (! xfs_qm_dqflock_nowait(dqp)) {
-			if (nowait) {
-				xfs_dqunlock(dqp);
-				continue;
-			}
-			/*
-			 * If we can't grab the flush lock then if the caller
-			 * really wanted us to give this our best shot,
-			 * see if we can give a push to the buffer before we wait
-			 * on the flush lock. At this point, we know that
-			 * eventhough the dquot is being flushed,
-			 * it has (new) dirty data.
-			 */
-			xfs_qm_dqflock_pushbuf_wait(dqp);
-		}
-		/*
-		 * Let go of the mplist lock. We don't want to hold it
-		 * across a disk write
-		 */
-		flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
-		xfs_qm_mplist_unlock(mp);
-		xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
-		error = xfs_qm_dqflush(dqp, flush_flags);
-		xfs_dqunlock(dqp);
-		if (error && XFS_FORCED_SHUTDOWN(mp))
-			return(0);	/* Need to prevent umount failure */
-		else if (error)
-			return (error);
-
-		xfs_qm_mplist_lock(mp);
-		if (recl != XFS_QI_MPLRECLAIMS(mp)) {
-			if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
-				break;
-
-			xfs_qm_mplist_unlock(mp);
-			goto again;
-		}
-	}
-
-	xfs_qm_mplist_unlock(mp);
-	return (0);
-}
-
-
-/*
- * This initializes all the quota information that's kept in the
- * mount structure
- */
-int
-xfs_qm_init_quotainfo(
-	xfs_mount_t	*mp)
-{
-	xfs_quotainfo_t *qinf;
-	int		error;
-	xfs_dquot_t	*dqp;
-
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-	/*
-	 * Tell XQM that we exist as soon as possible.
-	 */
-	if ((error = xfs_qm_hold_quotafs_ref(mp))) {
-		return (error);
-	}
-
-	qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
-
-	/*
-	 * See if quotainodes are setup, and if not, allocate them,
-	 * and change the superblock accordingly.
-	 */
-	if ((error = xfs_qm_init_quotainos(mp))) {
-		kmem_free(qinf, sizeof(xfs_quotainfo_t));
-		mp->m_quotainfo = NULL;
-		return (error);
-	}
-
-	spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin");
-	xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
-	qinf->qi_dqreclaims = 0;
-
-	/* mutex used to serialize quotaoffs */
-	mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff");
-
-	/* Precalc some constants */
-	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
-	ASSERT(qinf->qi_dqchunklen);
-	qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
-	do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
-
-	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
-
-	/*
-	 * We try to get the limits from the superuser's limits fields.
-	 * This is quite hacky, but it is standard quota practice.
-	 * We look at the USR dquot with id == 0 first, but if user quotas
-	 * are not enabled we goto the GRP dquot with id == 0.
-	 * We don't really care to keep separate default limits for user
-	 * and group quotas, at least not at this point.
-	 */
-	error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
-			     (XFS_IS_UQUOTA_RUNNING(mp)) ?
-			     XFS_DQ_USER : XFS_DQ_GROUP,
-			     XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
-			     &dqp);
-	if (! error) {
-		/*
-		 * The warnings and timers set the grace period given to
-		 * a user or group before he or she can not perform any
-		 * more writing. If it is zero, a default is used.
-		 */
-		qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ?
-			INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT;
-		qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ?
-			INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT;
-		qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ?
-			INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT;
-		qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ?
-			INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT;
-		qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ?
-			INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT;
-
-		/*
-		 * We sent the XFS_QMOPT_DQSUSER flag to dqget because
-		 * we don't want this dquot cached. We haven't done a
-		 * quotacheck yet, and quotacheck doesn't like incore dquots.
-		 */
-		xfs_qm_dqdestroy(dqp);
-	} else {
-		qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
-		qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
-		qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
-		qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
-		qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
-	}
-
-	return (0);
-}
-
-
-/*
- * Gets called when unmounting a filesystem or when all quotas get
- * turned off.
- * This purges the quota inodes, destroys locks and frees itself.
- */
-void
-xfs_qm_destroy_quotainfo(
-	xfs_mount_t	*mp)
-{
-	xfs_quotainfo_t *qi;
-
-	qi = mp->m_quotainfo;
-	ASSERT(qi != NULL);
-	ASSERT(xfs_Gqm != NULL);
-
-	/*
-	 * Release the reference that XQM kept, so that we know
-	 * when the XQM structure should be freed. We cannot assume
-	 * that xfs_Gqm is non-null after this point.
-	 */
-	xfs_qm_rele_quotafs_ref(mp);
-
-	spinlock_destroy(&qi->qi_pinlock);
-	xfs_qm_list_destroy(&qi->qi_dqlist);
-
-	if (qi->qi_uquotaip) {
-		XFS_PURGE_INODE(qi->qi_uquotaip);
-		qi->qi_uquotaip = NULL; /* paranoia */
-	}
-	if (qi->qi_gquotaip) {
-		XFS_PURGE_INODE(qi->qi_gquotaip);
-		qi->qi_gquotaip = NULL;
-	}
-	mutex_destroy(&qi->qi_quotaofflock);
-	kmem_free(qi, sizeof(xfs_quotainfo_t));
-	mp->m_quotainfo = NULL;
-}
-
-
-
-/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_list_init(
-	xfs_dqlist_t	*list,
-	char		*str,
-	int		n)
-{
-	mutex_init(&list->qh_lock, MUTEX_DEFAULT, str);
-	list->qh_next = NULL;
-	list->qh_version = 0;
-	list->qh_nelems = 0;
-}
-
-STATIC void
-xfs_qm_list_destroy(
-	xfs_dqlist_t	*list)
-{
-	mutex_destroy(&(list->qh_lock));
-}
-
-
-/*
- * Stripped down version of dqattach. This doesn't attach, or even look at the
- * dquots attached to the inode. The rationale is that there won't be any
- * attached at the time this is called from quotacheck.
- */
-STATIC int
-xfs_qm_dqget_noattach(
-	xfs_inode_t	*ip,
-	xfs_dquot_t	**O_udqpp,
-	xfs_dquot_t	**O_gdqpp)
-{
-	int		error;
-	xfs_mount_t	*mp;
-	xfs_dquot_t	*udqp, *gdqp;
-
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	mp = ip->i_mount;
-	udqp = NULL;
-	gdqp = NULL;
-
-	if (XFS_IS_UQUOTA_ON(mp)) {
-		ASSERT(ip->i_udquot == NULL);
-		/*
-		 * We want the dquot allocated if it doesn't exist.
-		 */
-		if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
-					 XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
-					 &udqp))) {
-			/*
-			 * Shouldn't be able to turn off quotas here.
-			 */
-			ASSERT(error != ESRCH);
-			ASSERT(error != ENOENT);
-			return (error);
-		}
-		ASSERT(udqp);
-	}
-
-	if (XFS_IS_GQUOTA_ON(mp)) {
-		ASSERT(ip->i_gdquot == NULL);
-		if (udqp)
-			xfs_dqunlock(udqp);
-		if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-					 XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
-					 &gdqp))) {
-			if (udqp)
-				xfs_qm_dqrele(udqp);
-			ASSERT(error != ESRCH);
-			ASSERT(error != ENOENT);
-			return (error);
-		}
-		ASSERT(gdqp);
-
-		/* Reacquire the locks in the right order */
-		if (udqp) {
-			if (! xfs_qm_dqlock_nowait(udqp)) {
-				xfs_dqunlock(gdqp);
-				xfs_dqlock(udqp);
-				xfs_dqlock(gdqp);
-			}
-		}
-	}
-
-	*O_udqpp = udqp;
-	*O_gdqpp = gdqp;
-
-#ifdef QUOTADEBUG
-	if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
-	if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
-#endif
-	return (0);
-}
-
-/*
- * Create an inode and return with a reference already taken, but unlocked
- * This is how we create quota inodes
- */
-STATIC int
-xfs_qm_qino_alloc(
-	xfs_mount_t	*mp,
-	xfs_inode_t	**ip,
-	__int64_t	sbfields,
-	uint		flags)
-{
-	xfs_trans_t	*tp;
-	int		error;
-	unsigned long s;
-	cred_t		zerocr;
-	int		committed;
-
-	tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE);
-	if ((error = xfs_trans_reserve(tp,
-				      XFS_QM_QINOCREATE_SPACE_RES(mp),
-				      XFS_CREATE_LOG_RES(mp), 0,
-				      XFS_TRANS_PERM_LOG_RES,
-				      XFS_CREATE_LOG_COUNT))) {
-		xfs_trans_cancel(tp, 0);
-		return (error);
-	}
-	memset(&zerocr, 0, sizeof(zerocr));
-
-	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
-				   &zerocr, 0, 1, ip, &committed))) {
-		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-				 XFS_TRANS_ABORT);
-		return (error);
-	}
-
-	/*
-	 * Keep an extra reference to this quota inode. This inode is
-	 * locked exclusively and joined to the transaction already.
-	 */
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
-	VN_HOLD(XFS_ITOV((*ip)));
-
-	/*
-	 * Make the changes in the superblock, and log those too.
-	 * sbfields arg may contain fields other than *QUOTINO;
-	 * VERSIONNUM for example.
-	 */
-	s = XFS_SB_LOCK(mp);
-	if (flags & XFS_QMOPT_SBVERSION) {
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-		unsigned oldv = mp->m_sb.sb_versionnum;
-#endif
-		ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb));
-		ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-				   XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
-		       (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-			XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
-
-		XFS_SB_VERSION_ADDQUOTA(&mp->m_sb);
-		mp->m_sb.sb_uquotino = NULLFSINO;
-		mp->m_sb.sb_gquotino = NULLFSINO;
-
-		/* qflags will get updated _after_ quotacheck */
-		mp->m_sb.sb_qflags = 0;
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-		cmn_err(CE_NOTE,
-			"Old superblock version %x, converting to %x.",
-			oldv, mp->m_sb.sb_versionnum);
-#endif
-	}
-	if (flags & XFS_QMOPT_UQUOTA)
-		mp->m_sb.sb_uquotino = (*ip)->i_ino;
-	else
-		mp->m_sb.sb_gquotino = (*ip)->i_ino;
-	XFS_SB_UNLOCK(mp, s);
-	xfs_mod_sb(tp, sbfields);
-
-	if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-				     NULL))) {
-		xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
-		return (error);
-	}
-	return (0);
-}
-
-
-STATIC int
-xfs_qm_reset_dqcounts(
-	xfs_mount_t	*mp,
-	xfs_buf_t	*bp,
-	xfs_dqid_t	id,
-	uint		type)
-{
-	xfs_disk_dquot_t	*ddq;
-	int			j;
-
-	xfs_buftrace("RESET DQUOTS", bp);
-	/*
-	 * Reset all counters and timers. They'll be
-	 * started afresh by xfs_qm_quotacheck.
-	 */
-#ifdef DEBUG
-	j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
-	do_div(j, sizeof(xfs_dqblk_t));
-	ASSERT(XFS_QM_DQPERBLK(mp) == j);
-#endif
-	ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
-	for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) {
-		/*
-		 * Do a sanity check, and if needed, repair the dqblk. Don't
-		 * output any warnings because it's perfectly possible to
-		 * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
-		 */
-		(void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
-				      "xfs_quotacheck");
-		INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL);
-		INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL);
-		INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
-		INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
-		INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
-		INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
-		INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
-		ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
-	}
-
-	return (0);
-}
-
-STATIC int
-xfs_qm_dqiter_bufs(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	firstid,
-	xfs_fsblock_t	bno,
-	xfs_filblks_t	blkcnt,
-	uint		flags)
-{
-	xfs_buf_t	*bp;
-	int		error;
-	int		notcommitted;
-	int		incr;
-
-	ASSERT(blkcnt > 0);
-	notcommitted = 0;
-	incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
-		XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
-	error = 0;
-
-	/*
-	 * Blkcnt arg can be a very big number, and might even be
-	 * larger than the log itself. So, we have to break it up into
-	 * manageable-sized transactions.
-	 * Note that we don't start a permanent transaction here; we might
-	 * not be able to get a log reservation for the whole thing up front,
-	 * and we don't really care to either, because we just discard
-	 * everything if we were to crash in the middle of this loop.
-	 */
-	while (blkcnt--) {
-		error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
-			      XFS_FSB_TO_DADDR(mp, bno),
-			      (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp);
-		if (error)
-			break;
-
-		(void) xfs_qm_reset_dqcounts(mp, bp, firstid,
-					     flags & XFS_QMOPT_UQUOTA ?
-					     XFS_DQ_USER : XFS_DQ_GROUP);
-		xfs_bdwrite(mp, bp);
-		/*
-		 * goto the next block.
-		 */
-		bno++;
-		firstid += XFS_QM_DQPERBLK(mp);
-	}
-	return (error);
-}
-
-/*
- * Iterate over all allocated USR/GRP dquots in the system, calling a
- * caller supplied function for every chunk of dquots that we find.
- */
-STATIC int
-xfs_qm_dqiterate(
-	xfs_mount_t	*mp,
-	xfs_inode_t	*qip,
-	uint		flags)
-{
-	xfs_bmbt_irec_t		*map;
-	int			i, nmaps;	/* number of map entries */
-	int			error;		/* return value */
-	xfs_fileoff_t		lblkno;
-	xfs_filblks_t		maxlblkcnt;
-	xfs_dqid_t		firstid;
-	xfs_fsblock_t		rablkno;
-	xfs_filblks_t		rablkcnt;
-
-	error = 0;
-	/*
-	 * This looks racey, but we can't keep an inode lock across a
-	 * trans_reserve. But, this gets called during quotacheck, and that
-	 * happens only at mount time which is single threaded.
-	 */
-	if (qip->i_d.di_nblocks == 0)
-		return (0);
-
-	map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
-
-	lblkno = 0;
-	maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET);
-	do {
-		nmaps = XFS_DQITER_MAP_SIZE;
-		/*
-		 * We aren't changing the inode itself. Just changing
-		 * some of its data. No new blocks are added here, and
-		 * the inode is never added to the transaction.
-		 */
-		xfs_ilock(qip, XFS_ILOCK_SHARED);
-		error = xfs_bmapi(NULL, qip, lblkno,
-				  maxlblkcnt - lblkno,
-				  XFS_BMAPI_METADATA,
-				  NULL,
-				  0, map, &nmaps, NULL);
-		xfs_iunlock(qip, XFS_ILOCK_SHARED);
-		if (error)
-			break;
-
-		ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
-		for (i = 0; i < nmaps; i++) {
-			ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
-			ASSERT(map[i].br_blockcount);
-
-
-			lblkno += map[i].br_blockcount;
-
-			if (map[i].br_startblock == HOLESTARTBLOCK)
-				continue;
-
-			firstid = (xfs_dqid_t) map[i].br_startoff *
-				XFS_QM_DQPERBLK(mp);
-			/*
-			 * Do a read-ahead on the next extent.
-			 */
-			if ((i+1 < nmaps) &&
-			    (map[i+1].br_startblock != HOLESTARTBLOCK)) {
-				rablkcnt =  map[i+1].br_blockcount;
-				rablkno = map[i+1].br_startblock;
-				while (rablkcnt--) {
-					xfs_baread(mp->m_ddev_targp,
-					       XFS_FSB_TO_DADDR(mp, rablkno),
-					       (int)XFS_QI_DQCHUNKLEN(mp));
-					rablkno++;
-				}
-			}
-			/*
-			 * Iterate thru all the blks in the extent and
-			 * reset the counters of all the dquots inside them.
-			 */
-			if ((error = xfs_qm_dqiter_bufs(mp,
-						       firstid,
-						       map[i].br_startblock,
-						       map[i].br_blockcount,
-						       flags))) {
-				break;
-			}
-		}
-
-		if (error)
-			break;
-	} while (nmaps > 0);
-
-	kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
-
-	return (error);
-}
-
-/*
- * Called by dqusage_adjust in doing a quotacheck.
- * Given the inode, and a dquot (either USR or GRP, doesn't matter),
- * this updates its incore copy as well as the buffer copy. This is
- * so that once the quotacheck is done, we can just log all the buffers,
- * as opposed to logging numerous updates to individual dquots.
- */
-STATIC void
-xfs_qm_quotacheck_dqadjust(
-	xfs_dquot_t		*dqp,
-	xfs_qcnt_t		nblks,
-	xfs_qcnt_t		rtblks)
-{
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	xfs_dqtrace_entry(dqp, "QCHECK DQADJUST");
-	/*
-	 * Adjust the inode count and the block count to reflect this inode's
-	 * resource usage.
-	 */
-	INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1);
-	dqp->q_res_icount++;
-	if (nblks) {
-		INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks);
-		dqp->q_res_bcount += nblks;
-	}
-	if (rtblks) {
-		INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks);
-		dqp->q_res_rtbcount += rtblks;
-	}
-
-	/*
-	 * Adjust the timers since we just changed usages
-	 */
-	if (! XFS_IS_SUSER_DQUOT(dqp))
-		xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
-
-	dqp->dq_flags |= XFS_DQ_DIRTY;
-}
-
-STATIC int
-xfs_qm_get_rtblks(
-	xfs_inode_t	*ip,
-	xfs_qcnt_t	*O_rtblks)
-{
-	xfs_filblks_t	rtblks;			/* total rt blks */
-	xfs_ifork_t	*ifp;			/* inode fork pointer */
-	xfs_extnum_t	nextents;		/* number of extent entries */
-	xfs_bmbt_rec_t	*base;			/* base of extent array */
-	xfs_bmbt_rec_t	*ep;			/* pointer to an extent entry */
-	int		error;
-
-	ASSERT(XFS_IS_REALTIME_INODE(ip));
-	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-		if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
-			return (error);
-	}
-	rtblks = 0;
-	nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
-	base = &ifp->if_u1.if_extents[0];
-	for (ep = base; ep < &base[nextents]; ep++)
-		rtblks += xfs_bmbt_get_blockcount(ep);
-	*O_rtblks = (xfs_qcnt_t)rtblks;
-	return (0);
-}
-
-/*
- * callback routine supplied to bulkstat(). Given an inumber, find its
- * dquots and update them to account for resources taken by that inode.
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_dqusage_adjust(
-	xfs_mount_t	*mp,		/* mount point for filesystem */
-	xfs_trans_t	*tp,		/* transaction pointer - NULL */
-	xfs_ino_t	ino,		/* inode number to get data for */
-	void		*buffer,	/* not used */
-	xfs_daddr_t	bno,		/* starting block of inode cluster */
-	void		*dip,		/* on-disk inode pointer (not used) */
-	int		*res)		/* result code value */
-{
-	xfs_inode_t	*ip;
-	xfs_dquot_t	*udqp, *gdqp;
-	xfs_qcnt_t	nblks, rtblks;
-	int		error;
-
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-	/*
-	 * rootino must have its resources accounted for, not so with the quota
-	 * inodes.
-	 */
-	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
-		*res = BULKSTAT_RV_NOTHING;
-		return XFS_ERROR(EINVAL);
-	}
-
-	/*
-	 * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
-	 * interface expects the inode to be exclusively locked because that's
-	 * the case in all other instances. It's OK that we do this because
-	 * quotacheck is done only at mount time.
-	 */
-	if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) {
-		*res = BULKSTAT_RV_NOTHING;
-		return (error);
-	}
-
-	if (ip->i_d.di_mode == 0) {
-		xfs_iput_new(ip, XFS_ILOCK_EXCL);
-		*res = BULKSTAT_RV_NOTHING;
-		return XFS_ERROR(ENOENT);
-	}
-
-	/*
-	 * Obtain the locked dquots. In case of an error (eg. allocation
-	 * fails for ENOSPC), we return the negative of the error number
-	 * to bulkstat, so that it can get propagated to quotacheck() and
-	 * making us disable quotas for the file system.
-	 */
-	if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
-		xfs_iput(ip, XFS_ILOCK_EXCL);
-		*res = BULKSTAT_RV_GIVEUP;
-		return (error);
-	}
-
-	rtblks = 0;
-	if (! XFS_IS_REALTIME_INODE(ip)) {
-		nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
-	} else {
-		/*
-		 * Walk thru the extent list and count the realtime blocks.
-		 */
-		if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
-			xfs_iput(ip, XFS_ILOCK_EXCL);
-			if (udqp)
-				xfs_qm_dqput(udqp);
-			if (gdqp)
-				xfs_qm_dqput(gdqp);
-			*res = BULKSTAT_RV_GIVEUP;
-			return (error);
-		}
-		nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
-	}
-	ASSERT(ip->i_delayed_blks == 0);
-
-	/*
-	 * We can't release the inode while holding its dquot locks.
-	 * The inode can go into inactive and might try to acquire the dquotlocks.
-	 * So, just unlock here and do a vn_rele at the end.
-	 */
-	xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-	/*
-	 * Add the (disk blocks and inode) resources occupied by this
-	 * inode to its dquots. We do this adjustment in the incore dquot,
-	 * and also copy the changes to its buffer.
-	 * We don't care about putting these changes in a transaction
-	 * envelope because if we crash in the middle of a 'quotacheck'
-	 * we have to start from the beginning anyway.
-	 * Once we're done, we'll log all the dquot bufs.
-	 *
-	 * The *QUOTA_ON checks below may look pretty racey, but quotachecks
-	 * and quotaoffs don't race. (Quotachecks happen at mount time only).
-	 */
-	if (XFS_IS_UQUOTA_ON(mp)) {
-		ASSERT(udqp);
-		xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
-		xfs_qm_dqput(udqp);
-	}
-	if (XFS_IS_GQUOTA_ON(mp)) {
-		ASSERT(gdqp);
-		xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
-		xfs_qm_dqput(gdqp);
-	}
-	/*
-	 * Now release the inode. This will send it to 'inactive', and
-	 * possibly even free blocks.
-	 */
-	VN_RELE(XFS_ITOV(ip));
-
-	/*
-	 * Goto next inode.
-	 */
-	*res = BULKSTAT_RV_DIDONE;
-	return (0);
-}
-
-/*
- * Walk thru all the filesystem inodes and construct a consistent view
- * of the disk quota world.
- */
-STATIC int
-xfs_qm_quotacheck(
-	xfs_mount_t	*mp)
-{
-	int		done, count, error;
-	xfs_ino_t	lastino;
-	size_t		structsz;
-	xfs_inode_t	*uip, *gip;
-	uint		flags;
-
-	count = INT_MAX;
-	structsz = 1;
-	lastino = 0;
-	flags = 0;
-
-	ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp));
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-	/*
-	 * There should be no cached dquots. The (simplistic) quotacheck
-	 * algorithm doesn't like that.
-	 */
-	ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0);
-
-	cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
-
-	/*
-	 * First we go thru all the dquots on disk, USR and GRP, and reset
-	 * their counters to zero. We need a clean slate.
-	 * We don't log our changes till later.
-	 */
-	if ((uip = XFS_QI_UQIP(mp))) {
-		if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA)))
-			goto error_return;
-		flags |= XFS_UQUOTA_CHKD;
-	}
-
-	if ((gip = XFS_QI_GQIP(mp))) {
-		if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
-			goto error_return;
-		flags |= XFS_GQUOTA_CHKD;
-	}
-
-	do {
-		/*
-		 * Iterate thru all the inodes in the file system,
-		 * adjusting the corresponding dquot counters in core.
-		 */
-		if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
-				     xfs_qm_dqusage_adjust,
-				     structsz, NULL,
-				     BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
-				     &done)))
-			break;
-
-	} while (! done);
-
-	/*
-	 * We can get this error if we couldn't do a dquot allocation inside
-	 * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
-	 * dirty dquots that might be cached, we just want to get rid of them
-	 * and turn quotaoff. The dquots won't be attached to any of the inodes
-	 * at this point (because we intentionally didn't in dqget_noattach).
-	 */
-	if (error) {
-		xfs_qm_dqpurge_all(mp,
-				   XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
-				   XFS_QMOPT_QUOTAOFF);
-		goto error_return;
-	}
-	/*
-	 * We've made all the changes that we need to make incore.
-	 * Now flush_them down to disk buffers.
-	 */
-	xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI);
-
-	/*
-	 * We didn't log anything, because if we crashed, we'll have to
-	 * start the quotacheck from scratch anyway. However, we must make
-	 * sure that our dquot changes are secure before we put the
-	 * quotacheck'd stamp on the superblock. So, here we do a synchronous
-	 * flush.
-	 */
-	XFS_bflush(mp->m_ddev_targp);
-
-	/*
-	 * If one type of quotas is off, then it will lose its
-	 * quotachecked status, since we won't be doing accounting for
-	 * that type anymore.
-	 */
-	mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
-	mp->m_qflags |= flags;
-
-#ifdef QUOTADEBUG
-	XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
-#endif
-
- error_return:
-	cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
-	return (error);
-}
-
-/*
- * This is called after the superblock has been read in and we're ready to
- * iget the quota inodes.
- */
-STATIC int
-xfs_qm_init_quotainos(
-	xfs_mount_t	*mp)
-{
-	xfs_inode_t	*uip, *gip;
-	int		error;
-	__int64_t	sbflags;
-	uint		flags;
-
-	ASSERT(mp->m_quotainfo);
-	uip = gip = NULL;
-	sbflags = 0;
-	flags = 0;
-
-	/*
-	 * Get the uquota and gquota inodes
-	 */
-	if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
-		if (XFS_IS_UQUOTA_ON(mp) &&
-		    mp->m_sb.sb_uquotino != NULLFSINO) {
-			ASSERT(mp->m_sb.sb_uquotino > 0);
-			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-					     0, &uip, 0)))
-				return XFS_ERROR(error);
-		}
-		if (XFS_IS_GQUOTA_ON(mp) &&
-		    mp->m_sb.sb_gquotino != NULLFSINO) {
-			ASSERT(mp->m_sb.sb_gquotino > 0);
-			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-					     0, &gip, 0))) {
-				if (uip)
-					VN_RELE(XFS_ITOV(uip));
-				return XFS_ERROR(error);
-			}
-		}
-	} else {
-		flags |= XFS_QMOPT_SBVERSION;
-		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-			    XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
-	}
-
-	/*
-	 * Create the two inodes, if they don't exist already. The changes
-	 * made above will get added to a transaction and logged in one of
-	 * the qino_alloc calls below.  If the device is readonly,
-	 * temporarily switch to read-write to do this.
-	 */
-	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
-		if ((error = xfs_qm_qino_alloc(mp, &uip,
-					      sbflags | XFS_SB_UQUOTINO,
-					      flags | XFS_QMOPT_UQUOTA)))
-			return XFS_ERROR(error);
-
-		flags &= ~XFS_QMOPT_SBVERSION;
-	}
-	if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
-		if ((error = xfs_qm_qino_alloc(mp, &gip,
-					      sbflags | XFS_SB_GQUOTINO,
-					      flags | XFS_QMOPT_GQUOTA))) {
-			if (uip)
-				VN_RELE(XFS_ITOV(uip));
-
-			return XFS_ERROR(error);
-		}
-	}
-
-	XFS_QI_UQIP(mp) = uip;
-	XFS_QI_GQIP(mp) = gip;
-
-	return (0);
-}
-
-
-/*
- * Traverse the freelist of dquots and attempt to reclaim a maximum of
- * 'howmany' dquots. This operation races with dqlookup(), and attempts to
- * favor the lookup function ...
- * XXXsup merge this with qm_reclaim_one().
- */
-STATIC int
-xfs_qm_shake_freelist(
-	int howmany)
-{
-	int		nreclaimed;
-	xfs_dqhash_t	*hash;
-	xfs_dquot_t	*dqp, *nextdqp;
-	int		restarts;
-	int		nflushes;
-
-	if (howmany <= 0)
-		return (0);
-
-	nreclaimed = 0;
-	restarts = 0;
-	nflushes = 0;
-
-#ifdef QUOTADEBUG
-	printk("Shake free 0x%x\n", howmany);
-#endif
-	/* lock order is : hashchainlock, freelistlock, mplistlock */
- tryagain:
-	xfs_qm_freelist_lock(xfs_Gqm);
-
-	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
-	     ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
-	      nreclaimed < howmany); ) {
-		xfs_dqlock(dqp);
-
-		/*
-		 * We are racing with dqlookup here. Naturally we don't
-		 * want to reclaim a dquot that lookup wants.
-		 */
-		if (dqp->dq_flags & XFS_DQ_WANT) {
-			xfs_dqunlock(dqp);
-			xfs_qm_freelist_unlock(xfs_Gqm);
-			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-				return (nreclaimed != howmany);
-			XFS_STATS_INC(xfsstats.xs_qm_dqwants);
-			goto tryagain;
-		}
-
-		/*
-		 * If the dquot is inactive, we are assured that it is
-		 * not on the mplist or the hashlist, and that makes our
-		 * life easier.
-		 */
-		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-			ASSERT(dqp->q_mount == NULL);
-			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-			ASSERT(dqp->HL_PREVP == NULL);
-			ASSERT(dqp->MPL_PREVP == NULL);
-			XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims);
-			nextdqp = dqp->dq_flnext;
-			goto off_freelist;
-		}
-
-		ASSERT(dqp->MPL_PREVP);
-		/*
-		 * Try to grab the flush lock. If this dquot is in the process of
-		 * getting flushed to disk, we don't want to reclaim it.
-		 */
-		if (! xfs_qm_dqflock_nowait(dqp)) {
-			xfs_dqunlock(dqp);
-			dqp = dqp->dq_flnext;
-			continue;
-		}
-
-		/*
-		 * We have the flush lock so we know that this is not in the
-		 * process of being flushed. So, if this is dirty, flush it
-		 * DELWRI so that we don't get a freelist infested with
-		 * dirty dquots.
-		 */
-		if (XFS_DQ_IS_DIRTY(dqp)) {
-			xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");
-			/*
-			 * We flush it delayed write, so don't bother
-			 * releasing the mplock.
-			 */
-			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
-			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-			dqp = dqp->dq_flnext;
-			continue;
-		}
-		/*
-		 * We're trying to get the hashlock out of order. This races
-		 * with dqlookup; so, we giveup and goto the next dquot if
-		 * we couldn't get the hashlock. This way, we won't starve
-		 * a dqlookup process that holds the hashlock that is
-		 * waiting for the freelist lock.
-		 */
-		if (! xfs_qm_dqhashlock_nowait(dqp)) {
-			xfs_dqfunlock(dqp);
-			xfs_dqunlock(dqp);
-			dqp = dqp->dq_flnext;
-			continue;
-		}
-		/*
-		 * This races with dquot allocation code as well as dqflush_all
-		 * and reclaim code. So, if we failed to grab the mplist lock,
-		 * giveup everything and start over.
-		 */
-		hash = dqp->q_hash;
-		ASSERT(hash);
-		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
-			/* XXX put a sentinel so that we can come back here */
-			xfs_dqfunlock(dqp);
-			xfs_dqunlock(dqp);
-			XFS_DQ_HASH_UNLOCK(hash);
-			xfs_qm_freelist_unlock(xfs_Gqm);
-			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-				return (nreclaimed != howmany);
-			goto tryagain;
-		}
-		xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
-#ifdef QUOTADEBUG
-		printk("Shake 0x%p, ID 0x%x\n", dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-#endif
-		ASSERT(dqp->q_nrefs == 0);
-		nextdqp = dqp->dq_flnext;
-		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
-		XQM_HASHLIST_REMOVE(hash, dqp);
-		xfs_dqfunlock(dqp);
-		xfs_qm_mplist_unlock(dqp->q_mount);
-		XFS_DQ_HASH_UNLOCK(hash);
-
- off_freelist:
-		XQM_FREELIST_REMOVE(dqp);
-		xfs_dqunlock(dqp);
-		nreclaimed++;
-		XFS_STATS_INC(xfsstats.xs_qm_dqshake_reclaims);
-		xfs_qm_dqdestroy(dqp);
-		dqp = nextdqp;
-	}
-	xfs_qm_freelist_unlock(xfs_Gqm);
-	return (nreclaimed != howmany);
-}
-
-
-/*
- * The shake manager routine called by shaked() when memory is
- * running low.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_shake(void)
-{
-	int	ndqused, nfree, n;
-
-	if (!xfs_Gqm)
-		return;
-
-	nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
-	/* incore dquots in all f/s's */
-	ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
-
-	ASSERT(ndqused >= 0);
-
-	if (nfree <= ndqused && nfree < ndquot)
-		return;
-
-	ndqused *= xfs_Gqm->qm_dqfree_ratio;	/* target # of free dquots */
-	n = nfree - ndqused - ndquot;		/* # over target */
-
-	(void) xfs_qm_shake_freelist(MAX(nfree, n));
-}
-
-
-/*
- * Just pop the least recently used dquot off the freelist and
- * recycle it. The returned dquot is locked.
- */
-STATIC xfs_dquot_t *
-xfs_qm_dqreclaim_one(void)
-{
-	xfs_dquot_t	*dqpout;
-	xfs_dquot_t	*dqp;
-	int		restarts;
-	int		nflushes;
-
-	restarts = 0;
-	dqpout = NULL;
-	nflushes = 0;
-
-	/* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
- startagain:
-	xfs_qm_freelist_lock(xfs_Gqm);
-
-	FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
-		xfs_dqlock(dqp);
-
-		/*
-		 * We are racing with dqlookup here. Naturally we don't
-		 * want to reclaim a dquot that lookup wants. We release the
-		 * freelist lock and start over, so that lookup will grab
-		 * both the dquot and the freelistlock.
-		 */
-		if (dqp->dq_flags & XFS_DQ_WANT) {
-			ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
-			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");
-			xfs_dqunlock(dqp);
-			xfs_qm_freelist_unlock(xfs_Gqm);
-			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-				return (NULL);
-			XFS_STATS_INC(xfsstats.xs_qm_dqwants);
-			goto startagain;
-		}
-
-		/*
-		 * If the dquot is inactive, we are assured that it is
-		 * not on the mplist or the hashlist, and that makes our
-		 * life easier.
-		 */
-		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-			ASSERT(dqp->q_mount == NULL);
-			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-			ASSERT(dqp->HL_PREVP == NULL);
-			ASSERT(dqp->MPL_PREVP == NULL);
-			XQM_FREELIST_REMOVE(dqp);
-			xfs_dqunlock(dqp);
-			dqpout = dqp;
-			XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims);
-			break;
-		}
-
-		ASSERT(dqp->q_hash);
-		ASSERT(dqp->MPL_PREVP);
-
-		/*
-		 * Try to grab the flush lock. If this dquot is in the process of
-		 * getting flushed to disk, we don't want to reclaim it.
-		 */
-		if (! xfs_qm_dqflock_nowait(dqp)) {
-			xfs_dqunlock(dqp);
-			continue;
-		}
-
-		/*
-		 * We have the flush lock so we know that this is not in the
-		 * process of being flushed. So, if this is dirty, flush it
-		 * DELWRI so that we don't get a freelist infested with
-		 * dirty dquots.
-		 */
-		if (XFS_DQ_IS_DIRTY(dqp)) {
-			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");
-			/*
-			 * We flush it delayed write, so don't bother
-			 * releasing the freelist lock.
-			 */
-			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
-			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-			continue;
-		}
-
-		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
-			xfs_dqfunlock(dqp);
-			xfs_dqunlock(dqp);
-			continue;
-		}
-
-		if (! xfs_qm_dqhashlock_nowait(dqp))
-			goto mplistunlock;
-
-		ASSERT(dqp->q_nrefs == 0);
-		xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");
-		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
-		XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
-		XQM_FREELIST_REMOVE(dqp);
-		dqpout = dqp;
-		XFS_DQ_HASH_UNLOCK(dqp->q_hash);
- mplistunlock:
-		xfs_qm_mplist_unlock(dqp->q_mount);
-		xfs_dqfunlock(dqp);
-		xfs_dqunlock(dqp);
-		if (dqpout)
-			break;
-	}
-
-	xfs_qm_freelist_unlock(xfs_Gqm);
-	return (dqpout);
-}
-
-
-/*------------------------------------------------------------------*/
-
-/*
- * Return a new incore dquot. Depending on the number of
- * dquots in the system, we either allocate a new one on the kernel heap,
- * or reclaim a free one.
- * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
- * to reclaim an existing one from the freelist.
- */
-boolean_t
-xfs_qm_dqalloc_incore(
-	xfs_dquot_t **O_dqpp)
-{
-	xfs_dquot_t	*dqp;
-
-	/*
-	 * Check against high water mark to see if we want to pop
-	 * a nincompoop dquot off the freelist.
-	 */
-	if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
-		/*
-		 * Try to recycle a dquot from the freelist.
-		 */
-		if ((dqp = xfs_qm_dqreclaim_one())) {
-			XFS_STATS_INC(xfsstats.xs_qm_dqreclaims);
-			/*
-			 * Just zero the core here. The rest will get
-			 * reinitialized by caller. XXX we shouldn't even
-			 * do this zero ...
-			 */
-			memset(&dqp->q_core, 0, sizeof(dqp->q_core));
-			*O_dqpp = dqp;
-			return (B_FALSE);
-		}
-		XFS_STATS_INC(xfsstats.xs_qm_dqreclaim_misses);
-	}
-
-	/*
-	 * Allocate a brand new dquot on the kernel heap and return it
-	 * to the caller to initialize.
-	 */
-	ASSERT(xfs_Gqm->qm_dqzone != NULL);
-	*O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
-	atomic_inc(&xfs_Gqm->qm_totaldquots);
-
-	return (B_TRUE);
-}
-
-
-/*
- * Start a transaction and write the incore superblock changes to
- * disk. flags parameter indicates which fields have changed.
- */
-int
-xfs_qm_write_sb_changes(
-	xfs_mount_t	*mp,
-	__int64_t	flags)
-{
-	xfs_trans_t	*tp;
-	int		error;
-
-#ifdef QUOTADEBUG
-	cmn_err(CE_NOTE,
-		"Writing superblock quota changes :%s",
-		mp->m_fsname);
-#endif
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-	if ((error = xfs_trans_reserve(tp, 0,
-				      mp->m_sb.sb_sectsize + 128, 0,
-				      0,
-				      XFS_DEFAULT_LOG_COUNT))) {
-		xfs_trans_cancel(tp, 0);
-		return (error);
-	}
-
-	xfs_mod_sb(tp, flags);
-	(void) xfs_trans_commit(tp, 0, NULL);
-
-	return (0);
-}
-
-
-/* --------------- utility functions for vnodeops ---------------- */
-
-
-/*
- * Given an inode, a uid and gid (from cred_t) make sure that we have
- * allocated relevant dquot(s) on disk, and that we won't exceed inode
- * quotas by creating this file.
- * This also attaches dquot(s) to the given inode after locking it,
- * and returns the dquots corresponding to the uid and/or gid.
- *
- * in	: inode (unlocked)
- * out	: udquot, gdquot with references taken and unlocked
- */
-int
-xfs_qm_vop_dqalloc(
-	xfs_mount_t	*mp,
-	xfs_inode_t	*ip,
-	uid_t		uid,
-	gid_t		gid,
-	uint		flags,
-	xfs_dquot_t	**O_udqpp,
-	xfs_dquot_t	**O_gdqpp)
-{
-	int		error;
-	xfs_dquot_t	*uq, *gq;
-	uint		lockflags;
-
-	lockflags = XFS_ILOCK_EXCL;
-	xfs_ilock(ip, lockflags);
-
-	if ((flags & XFS_QMOPT_INHERIT) &&
-	    XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))
-		gid = ip->i_d.di_gid;
-
-	/*
-	 * Attach the dquot(s) to this inode, doing a dquot allocation
-	 * if necessary. The dquot(s) will not be locked.
-	 */
-	if (XFS_NOT_DQATTACHED(mp, ip)) {
-		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
-					    XFS_QMOPT_ILOCKED))) {
-			xfs_iunlock(ip, lockflags);
-			return (error);
-		}
-	}
-
-	uq = gq = NULL;
-	if ((flags & XFS_QMOPT_UQUOTA) &&
-	    XFS_IS_UQUOTA_ON(mp)) {
-		if (ip->i_d.di_uid != uid) {
-			/*
-			 * What we need is the dquot that has this uid, and
-			 * if we send the inode to dqget, the uid of the inode
-			 * takes priority over what's sent in the uid argument.
-			 * We must unlock inode here before calling dqget if
-			 * we're not sending the inode, because otherwise
-			 * we'll deadlock by doing trans_reserve while
-			 * holding ilock.
-			 */
-			xfs_iunlock(ip, lockflags);
-			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
-						 XFS_DQ_USER,
-						 XFS_QMOPT_DQALLOC |
-						 XFS_QMOPT_DOWARN,
-						 &uq))) {
-				ASSERT(error != ENOENT);
-				return (error);
-			}
-			/*
-			 * Get the ilock in the right order.
-			 */
-			xfs_dqunlock(uq);
-			lockflags = XFS_ILOCK_SHARED;
-			xfs_ilock(ip, lockflags);
-		} else {
-			/*
-			 * Take an extra reference, because we'll return
-			 * this to caller
-			 */
-			ASSERT(ip->i_udquot);
-			uq = ip->i_udquot;
-			xfs_dqlock(uq);
-			XFS_DQHOLD(uq);
-			xfs_dqunlock(uq);
-		}
-	}
-	if ((flags & XFS_QMOPT_GQUOTA) &&
-	    XFS_IS_GQUOTA_ON(mp)) {
-		if (ip->i_d.di_gid != gid) {
-			xfs_iunlock(ip, lockflags);
-			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
-						 XFS_DQ_GROUP,
-						 XFS_QMOPT_DQALLOC |
-						 XFS_QMOPT_DOWARN,
-						 &gq))) {
-				if (uq)
-					xfs_qm_dqrele(uq);
-				ASSERT(error != ENOENT);
-				return (error);
-			}
-			xfs_dqunlock(gq);
-			lockflags = XFS_ILOCK_SHARED;
-			xfs_ilock(ip, lockflags);
-		} else {
-			ASSERT(ip->i_gdquot);
-			gq = ip->i_gdquot;
-			xfs_dqlock(gq);
-			XFS_DQHOLD(gq);
-			xfs_dqunlock(gq);
-		}
-	}
-	if (uq)
-		xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
-
-	xfs_iunlock(ip, lockflags);
-	if (O_udqpp)
-		*O_udqpp = uq;
-	else if (uq)
-		xfs_qm_dqrele(uq);
-	if (O_gdqpp)
-		*O_gdqpp = gq;
-	else if (gq)
-		xfs_qm_dqrele(gq);
-	return (0);
-}
-
-/*
- * Actually transfer ownership, and do dquot modifications.
- * These were already reserved.
- */
-xfs_dquot_t *
-xfs_qm_vop_chown(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	xfs_dquot_t	**IO_olddq,
-	xfs_dquot_t	*newdq)
-{
-	xfs_dquot_t	*prevdq;
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-
-	/* old dquot */
-	prevdq = *IO_olddq;
-	ASSERT(prevdq);
-	ASSERT(prevdq != newdq);
-
-	xfs_trans_mod_dquot(tp, prevdq,
-			    XFS_TRANS_DQ_BCOUNT,
-			    -(ip->i_d.di_nblocks));
-	xfs_trans_mod_dquot(tp, prevdq,
-			    XFS_TRANS_DQ_ICOUNT,
-			    -1);
-
-	/* the sparkling new dquot */
-	xfs_trans_mod_dquot(tp, newdq,
-			    XFS_TRANS_DQ_BCOUNT,
-			    ip->i_d.di_nblocks);
-	xfs_trans_mod_dquot(tp, newdq,
-			    XFS_TRANS_DQ_ICOUNT,
-			    1);
-
-	/*
-	 * Take an extra reference, because the inode
-	 * is going to keep this dquot pointer even
-	 * after the trans_commit.
-	 */
-	xfs_dqlock(newdq);
-	XFS_DQHOLD(newdq);
-	xfs_dqunlock(newdq);
-	*IO_olddq = newdq;
-
-	return (prevdq);
-}
-
-/*
- * Quota reservations for setattr(AT_UID|AT_GID).
- */
-int
-xfs_qm_vop_chown_reserve(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp,
-	uint		privileged)
-{
-	int		error;
-	xfs_mount_t	*mp;
-	uint		delblks;
-	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
-
-	ASSERT(XFS_ISLOCKED_INODE(ip));
-	mp = ip->i_mount;
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-	delblks = ip->i_delayed_blks;
-	delblksudq = delblksgdq = unresudq = unresgdq = NULL;
-
-	if (XFS_IS_UQUOTA_ON(mp) && udqp &&
-	    ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
-		delblksudq = udqp;
-		/*
-		 * If there are delayed allocation blocks, then we have to
-		 * unreserve those from the old dquot, and add them to the
-		 * new dquot.
-		 */
-		if (delblks) {
-			ASSERT(ip->i_udquot);
-			unresudq = ip->i_udquot;
-		}
-	}
-	if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
-	    ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
-		delblksgdq = gdqp;
-		if (delblks) {
-			ASSERT(ip->i_gdquot);
-			unresgdq = ip->i_gdquot;
-		}
-	}
-
-	if ((error = xfs_trans_reserve_quota(tp, delblksudq,
-					    delblksgdq,
-					    ip->i_d.di_nblocks, 1,
-					    privileged)))
-		return (error);
-
-
-	/*
-	 * Do the delayed blks reservations/unreservations now. Since, these
-	 * are done without the help of a transaction, if a reservation fails
-	 * its previous reservations won't be automatically undone by trans
-	 * code. So, we have to do it manually here.
-	 */
-	if (delblks) {
-		/*
-		 * Do the reservations first. Unreservation can't fail.
-		 */
-		ASSERT(delblksudq || delblksgdq);
-		ASSERT(unresudq || unresgdq);
-		if ((error = xfs_trans_reserve_quota(NULL,
-						    delblksudq, delblksgdq,
-						    (xfs_qcnt_t)delblks, 0,
-						    privileged)))
-			return (error);
-		(void) xfs_trans_unreserve_quota(NULL,
-						 unresudq, unresgdq,
-						 (xfs_qcnt_t)delblks, 0,
-						 0);
-	}
-
-	return (0);
-}
-
-int
-xfs_qm_vop_rename_dqattach(
-	xfs_inode_t	**i_tab)
-{
-	xfs_inode_t	*ip;
-	int		i;
-	int		error;
-
-	ip = i_tab[0];
-
-	if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-		error = xfs_qm_dqattach(ip, 0);
-		if (error)
-			return (error);
-	}
-	for (i = 1; (i < 4 && i_tab[i]); i++) {
-		/*
-		 * Watch out for duplicate entries in the table.
-		 */
-		if ((ip = i_tab[i]) != i_tab[i-1]) {
-			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-				error = xfs_qm_dqattach(ip, 0);
-				if (error)
-					return (error);
-			}
-		}
-	}
-	return (0);
-}
-
-void
-xfs_qm_vop_dqattach_and_dqmod_newinode(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp)
-{
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
-
-	if (udqp) {
-		xfs_dqlock(udqp);
-		XFS_DQHOLD(udqp);
-		xfs_dqunlock(udqp);
-		ASSERT(ip->i_udquot == NULL);
-		ip->i_udquot = udqp;
-		ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT));
-		xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
-	}
-	if (gdqp) {
-		xfs_dqlock(gdqp);
-		XFS_DQHOLD(gdqp);
-		xfs_dqunlock(gdqp);
-		ASSERT(ip->i_gdquot == NULL);
-		ip->i_gdquot = gdqp;
-		ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT));
-		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
-	}
-}
-
-/* ------------- list stuff -----------------*/
-void
-xfs_qm_freelist_init(xfs_frlist_t *ql)
-{
-	ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
-	mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf");
-	ql->qh_version = 0;
-	ql->qh_nelems = 0;
-}
-
-void
-xfs_qm_freelist_destroy(xfs_frlist_t *ql)
-{
-	xfs_dquot_t	*dqp, *nextdqp;
-
-	mutex_lock(&ql->qh_lock, PINOD);
-	for (dqp = ql->qh_next;
-	     dqp != (xfs_dquot_t *)ql; ) {
-		xfs_dqlock(dqp);
-		nextdqp = dqp->dq_flnext;
-#ifdef QUOTADEBUG
-		printk("FREELIST destroy 0x%p\n", dqp);
-#endif
-		XQM_FREELIST_REMOVE(dqp);
-		xfs_dqunlock(dqp);
-		xfs_qm_dqdestroy(dqp);
-		dqp = nextdqp;
-	}
-	/*
-	 * Don't bother about unlocking.
-	 */
-	mutex_destroy(&ql->qh_lock);
-
-	ASSERT(ql->qh_nelems == 0);
-}
-
-void
-xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
-{
-	dq->dq_flnext = ql->qh_next;
-	dq->dq_flprev = (xfs_dquot_t *)ql;
-	ql->qh_next = dq;
-	dq->dq_flnext->dq_flprev = dq;
-	xfs_Gqm->qm_dqfreelist.qh_nelems++;
-	xfs_Gqm->qm_dqfreelist.qh_version++;
-}
-
-void
-xfs_qm_freelist_unlink(xfs_dquot_t *dq)
-{
-	xfs_dquot_t *next = dq->dq_flnext;
-	xfs_dquot_t *prev = dq->dq_flprev;
-
-	next->dq_flprev = prev;
-	prev->dq_flnext = next;
-	dq->dq_flnext = dq->dq_flprev = dq;
-	xfs_Gqm->qm_dqfreelist.qh_nelems--;
-	xfs_Gqm->qm_dqfreelist.qh_version++;
-}
-
-#ifdef QUOTADEBUG
-void
-xfs_qm_freelist_print(xfs_frlist_t *qlist, char *title)
-{
-	xfs_dquot_t *dq;
-	int i = 0;
-	printk("%s (#%d)\n", title, (int) qlist->qh_nelems);
-	FOREACH_DQUOT_IN_FREELIST(dq, qlist) {
-		printk("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d "
-		       "refs = %d\n",
-		       ++i, INT_GET(dq->q_core.d_id, ARCH_CONVERT),
-		       DQFLAGTO_TYPESTR(dq), dq,
-		       (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT),
-		       (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT),
-		       (int) dq->q_nrefs);
-	}
-}
-#endif
-
-void
-xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
-{
-	xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
-}
-
-int
-xfs_qm_dqhashlock_nowait(
-	xfs_dquot_t *dqp)
-{
-	int locked;
-
-	locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
-	return (locked);
-}
-
-int
-xfs_qm_freelist_lock_nowait(
-	xfs_qm_t *xqm)
-{
-	int locked;
-
-	locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
-	return (locked);
-}
-
-int
-xfs_qm_mplist_nowait(
-	xfs_mount_t	*mp)
-{
-	int locked;
-
-	ASSERT(mp->m_quotainfo);
-	locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
-	return (locked);
-}
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_qm.h linux-2.5.66-bk3/fs/xfs/xfs_qm.h
--- linux-2.5.66-bk2/fs/xfs/xfs_qm.h	Mon Mar 24 14:00:14 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_qm.h	Wed Dec 31 16:00:00 1969
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_QM_H__
-#define __XFS_QM_H__
-
-struct	xfs_dqhash;
-struct	xfs_inode;
-struct	xfs_dquot;
-
-extern kmem_zone_t	*qm_dqzone;
-extern kmem_zone_t	*qm_dqtrxzone;
-
-/*
- * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
- * iterate over the mountpt's dquot list in one call.
- */
-#define XFS_QM_SYNC_MAX_RESTARTS	7
-
-/*
- * Ditto, for xfs_qm_dqreclaim_one.
- */
-#define XFS_QM_RECLAIM_MAX_RESTARTS	4
-
-/*
- * Ideal ratio of free to in use dquots. Quota manager makes an attempt
- * to keep this balance.
- */
-#define XFS_QM_DQFREE_RATIO		2
-
-/*
- * Dquot hashtable constants/threshold values.
- */
-#define XFS_QM_NCSIZE_THRESHOLD		5000
-#define XFS_QM_HASHSIZE_LOW		32
-#define XFS_QM_HASHSIZE_HIGH		64
-
-/*
- * We output a cmn_err when quotachecking a quota file with more than
- * this many fsbs.
- */
-#define XFS_QM_BIG_QCHECK_NBLKS		500
-
-/*
- * This defines the unit of allocation of dquots.
- * Currently, it is just one file system block, and a 4K blk contains 30
- * (136 * 30 = 4080) dquots. It's probably not worth trying to make
- * this more dynamic.
- * XXXsup However, if this number is changed, we have to make sure that we don't
- * implicitly assume that we do allocations in chunks of a single filesystem
- * block in the dquot/xqm code.
- */
-#define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
-/*
- * When doing a quotacheck, we log dquot clusters of this many FSBs at most
- * in a single transaction. We don't want to ask for too huge a log reservation.
- */
-#define XFS_QM_MAX_DQCLUSTER_LOGSZ	3
-
-typedef xfs_dqhash_t	xfs_dqlist_t;
-/*
- * The freelist head. The first two fields match the first two in the
- * xfs_dquot_t structure (in xfs_dqmarker_t)
- */
-typedef struct xfs_frlist {
-       struct xfs_dquot *qh_next;
-       struct xfs_dquot *qh_prev;
-       mutex_t		 qh_lock;
-       uint		 qh_version;
-       uint		 qh_nelems;
-} xfs_frlist_t;
-
-/*
- * Quota Manager (global) structure. Lives only in core.
- */
-typedef struct xfs_qm {
-	xfs_dqlist_t	*qm_usr_dqhtable;/* udquot hash table */
-	xfs_dqlist_t	*qm_grp_dqhtable;/* gdquot hash table */
-	uint		 qm_dqhashmask;	 /* # buckets in dq hashtab - 1 */
-	xfs_frlist_t	 qm_dqfreelist;	 /* freelist of dquots */
-	atomic_t	 qm_totaldquots; /* total incore dquots */
-	uint		 qm_nrefs;	 /* file systems with quota on */
-	int		 qm_dqfree_ratio;/* ratio of free to inuse dquots */
-	kmem_zone_t	*qm_dqzone;	 /* dquot mem-alloc zone */
-	kmem_zone_t	*qm_dqtrxzone;	 /* t_dqinfo of transactions */
-} xfs_qm_t;
-
-/*
- * Various quota information for individual filesystems.
- * The mount structure keeps a pointer to this.
- */
-typedef struct xfs_quotainfo {
-	xfs_inode_t	*qi_uquotaip;	 /* user quota inode */
-	xfs_inode_t	*qi_gquotaip;	 /* group quota inode */
-	lock_t		 qi_pinlock;	 /* dquot pinning mutex */
-	xfs_dqlist_t	 qi_dqlist;	 /* all dquots in filesys */
-	int		 qi_dqreclaims;	 /* a change here indicates
-					    a removal in the dqlist */
-	time_t		 qi_btimelimit;	 /* limit for blks timer */
-	time_t		 qi_itimelimit;	 /* limit for inodes timer */
-	time_t		 qi_rtbtimelimit;/* limit for rt blks timer */
-	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for num warnings */
-	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for num warnings */
-	mutex_t		 qi_quotaofflock;/* to serialize quotaoff */
-	/* Some useful precalculated constants */
-	xfs_filblks_t	 qi_dqchunklen;	 /* # BBs in a chunk of dqs */
-	uint		 qi_dqperchunk;	 /* # ondisk dqs in above chunk */
-} xfs_quotainfo_t;
-
-
-/*
- * The structure kept inside the xfs_trans_t keep track of dquot changes
- * within a transaction and apply them later.
- */
-typedef struct xfs_dqtrx {
-	struct xfs_dquot *qt_dquot;	  /* the dquot this refers to */
-	ulong		qt_blk_res;	  /* blks reserved on a dquot */
-	ulong		qt_blk_res_used;  /* blks used from the reservation */
-	ulong		qt_ino_res;	  /* inode reserved on a dquot */
-	ulong		qt_ino_res_used;  /* inodes used from the reservation */
-	long		qt_bcount_delta;  /* dquot blk count changes */
-	long		qt_delbcnt_delta; /* delayed dquot blk count changes */
-	long		qt_icount_delta;  /* dquot inode count changes */
-	ulong		qt_rtblk_res;	  /* # blks reserved on a dquot */
-	ulong		qt_rtblk_res_used;/* # blks used from reservation */
-	long		qt_rtbcount_delta;/* dquot realtime blk changes */
-	long		qt_delrtb_delta;  /* delayed RT blk count changes */
-} xfs_dqtrx_t;
-
-/*
- * We keep the usr and grp dquots separately so that locking will be easier
- * to do at commit time. All transactions that we know of at this point
- * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
- */
-#define XFS_QM_TRANS_MAXDQS		2
-typedef struct xfs_dquot_acct {
-	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
-	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
-} xfs_dquot_acct_t;
-
-/*
- * Users are allowed to have a usage exceeding their softlimit for
- * a period this long.
- */
-#define XFS_QM_BTIMELIMIT	DQ_BTIMELIMIT
-#define XFS_QM_RTBTIMELIMIT	DQ_BTIMELIMIT
-#define XFS_QM_ITIMELIMIT	DQ_FTIMELIMIT
-
-#define XFS_QM_BWARNLIMIT	5
-#define XFS_QM_IWARNLIMIT	5
-
-#define XFS_QM_LOCK(xqm)	(mutex_lock(&xqm##_lock, PINOD))
-#define XFS_QM_UNLOCK(xqm)	(mutex_unlock(&xqm##_lock))
-#define XFS_QM_HOLD(xqm)	((xqm)->qm_nrefs++)
-#define XFS_QM_RELE(xqm)	((xqm)->qm_nrefs--)
-
-extern int		xfs_qm_init_quotainfo(xfs_mount_t *);
-extern void		xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern void		xfs_qm_dqunlink(xfs_dquot_t *);
-extern boolean_t	xfs_qm_dqalloc_incore(xfs_dquot_t **);
-extern int		xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
-
-/* list stuff */
-extern void		xfs_qm_freelist_init(xfs_frlist_t *);
-extern void		xfs_qm_freelist_destroy(xfs_frlist_t *);
-extern void		xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
-extern void		xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
-extern void		xfs_qm_freelist_unlink(xfs_dquot_t *);
-extern int		xfs_qm_freelist_lock_nowait(xfs_qm_t *);
-extern int		xfs_qm_mplist_nowait(xfs_mount_t *);
-extern int		xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
-
-/* system call interface */
-extern int linvfs_getxstate(struct super_block *, struct fs_quota_stat *);
-extern int linvfs_setxstate(struct super_block *, unsigned int, int);
-extern int linvfs_getxquota(struct super_block *, int, qid_t, struct fs_disk_quota *);
-extern int linvfs_setxquota(struct super_block *, int, qid_t, struct fs_disk_quota *);
-
-#ifdef DEBUG
-extern int		xfs_qm_internalqcheck(xfs_mount_t *);
-#else
-#define xfs_qm_internalqcheck(mp)	(0)
-#endif
-
-#ifdef QUOTADEBUG
-extern void		xfs_qm_freelist_print(xfs_frlist_t *, char *);
-#else
-#define xfs_qm_freelist_print(a, b)	do { } while (0)
-#endif
-
-#endif /* __XFS_QM_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_qm_syscalls.c linux-2.5.66-bk3/fs/xfs/xfs_qm_syscalls.c
--- linux-2.5.66-bk2/fs/xfs/xfs_qm_syscalls.c	Mon Mar 24 14:00:54 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_qm_syscalls.c	Wed Dec 31 16:00:00 1969
@@ -1,1374 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-#ifdef DEBUG
-# define qdprintk(s, args...)		printk(s, ## args)
-#else
-# define qdprintk(s, args...)		do { } while (0)
-#endif
-
-STATIC int	xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
-STATIC int	xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
-					fs_disk_quota_t *);
-STATIC int	xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
-STATIC int	xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
-					fs_disk_quota_t *);
-STATIC int	xfs_qm_scall_quotaon(xfs_mount_t *, uint);
-STATIC int	xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
-STATIC int	xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
-STATIC int	xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
-					uint);
-STATIC uint	xfs_qm_import_flags(uint);
-STATIC uint	xfs_qm_export_flags(uint);
-STATIC uint	xfs_qm_import_qtype_flags(uint);
-STATIC uint	xfs_qm_export_qtype_flags(uint);
-STATIC void	xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
-					fs_disk_quota_t *);
-
-
-int
-linvfs_getxstate(
-	struct super_block	*sb,
-	struct fs_quota_stat	*fqs)
-{
-	xfs_mount_t		*mp;
-	vfs_t			*vfsp;
-
-	vfsp = LINVFS_GET_VFS(sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-	return -xfs_qm_scall_getqstat(mp, fqs);
-}
-
-int
-linvfs_setxstate(
-	struct super_block	*sb,
-	unsigned int		flags,
-	int			op)
-{
-	xfs_mount_t		*mp;
-	vfs_t			*vfsp;
-	uint			qflags;
-
-	vfsp = LINVFS_GET_VFS(sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-	if (vfsp->vfs_flag & VFS_RDONLY)
-		return -EROFS;
-
-	switch (op) {
-	case Q_XQUOTARM:
-		if (XFS_IS_QUOTA_ON(mp)) {
-			qdprintk("cannot remove, quota on: flags=%x\n", flags);
-			return -EINVAL;
-		}
-		qflags = xfs_qm_import_qtype_flags(flags);
-		return -xfs_qm_scall_trunc_qfiles(mp, qflags);
-	case Q_XQUOTAON:
-		qflags = xfs_qm_import_flags(flags);
-		return -xfs_qm_scall_quotaon(mp, qflags);
-	case Q_XQUOTAOFF:
-		qflags = xfs_qm_import_flags(flags);
-		if (!XFS_IS_QUOTA_ON(mp))
-			return -ESRCH;
-		return -xfs_qm_scall_quotaoff(mp, qflags, B_FALSE);
-	}
-	qdprintk("cannot set state, invalid op: op=%x flags=%x\n", op, flags);
-	return -EINVAL;
-}
-
-int
-linvfs_getxquota(
-	struct super_block	*sb,
-	int			type,
-	qid_t			id,
-	struct fs_disk_quota	*fdq)
-{
-	xfs_mount_t		*mp;
-	vfs_t			*vfsp;
-	int			qtype;
-
-	vfsp = LINVFS_GET_VFS(sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-	if (!XFS_IS_QUOTA_ON(mp))
-		return -ESRCH;
-	qtype = (type == GRPQUOTA)? XFS_DQ_GROUP : XFS_DQ_USER;
-	return -xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, qtype, fdq);
-}
-
-int
-linvfs_setxquota(
-	struct super_block	*sb,
-	int			type,
-	qid_t			id,
-	struct fs_disk_quota	*fdq)
-{
-	xfs_mount_t		*mp;
-	vfs_t			*vfsp;
-	int			qtype;
-
-	vfsp = LINVFS_GET_VFS(sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-	if (!XFS_IS_QUOTA_ON(mp))
-		return -ESRCH;
-	if (vfsp->vfs_flag & VFS_RDONLY)
-		return -EROFS;
-	qtype = (type == GRPQUOTA)? XFS_DQ_GROUP : XFS_DQ_USER;
-	return xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, qtype, fdq);
-}
-
-
-/*
- * Turn off quota accounting and/or enforcement for all udquots and/or
- * gdquots. Called only at unmount time.
- *
- * This assumes that there are no dquots of this file system cached
- * incore, and modifies the ondisk dquot directly. Therefore, for example,
- * it is an error to call this twice, without purging the cache.
- */
-STATIC int
-xfs_qm_scall_quotaoff(
-	xfs_mount_t		*mp,
-	uint			flags,
-	boolean_t		force)
-{
-	uint			dqtype;
-	unsigned long	s;
-	int			error;
-	uint			inactivate_flags;
-	xfs_qoff_logitem_t	*qoffstart;
-	int			nculprits;
-
-	if (!force && !capable(CAP_SYS_ADMIN))
-		return XFS_ERROR(EPERM);
-	/*
-	 * No file system can have quotas enabled on disk but not in core.
-	 * Note that quota utilities (like quotaoff) _expect_
-	 * errno == EEXIST here.
-	 */
-	if ((mp->m_qflags & flags) == 0)
-		return XFS_ERROR(EEXIST);
-	error = 0;
-
-	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
-
-	/*
-	 * We don't want to deal with two quotaoffs messing up each other,
-	 * so we're going to serialize it. quotaoff isn't exactly a performance
-	 * critical thing.
-	 * If quotaoff, then we must be dealing with the root filesystem.
-	 */
-	ASSERT(mp->m_quotainfo);
-	if (mp->m_quotainfo)
-		mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-
-	ASSERT(mp->m_quotainfo);
-
-	/*
-	 * If we're just turning off quota enforcement, change mp and go.
-	 */
-	if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
-		mp->m_qflags &= ~(flags);
-
-		s = XFS_SB_LOCK(mp);
-		mp->m_sb.sb_qflags = mp->m_qflags;
-		XFS_SB_UNLOCK(mp, s);
-		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-		/* XXX what to do if error ? Revert back to old vals incore ? */
-		error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
-		return (error);
-	}
-
-	dqtype = 0;
-	inactivate_flags = 0;
-	/*
-	 * If accounting is off, we must turn enforcement off, clear the
-	 * quota 'CHKD' certificate to make it known that we have to
-	 * do a quotacheck the next time this quota is turned on.
-	 */
-	if (flags & XFS_UQUOTA_ACCT) {
-		dqtype |= XFS_QMOPT_UQUOTA;
-		flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
-		inactivate_flags |= XFS_UQUOTA_ACTIVE;
-	}
-	if (flags & XFS_GQUOTA_ACCT) {
-		dqtype |= XFS_QMOPT_GQUOTA;
-		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
-		inactivate_flags |= XFS_GQUOTA_ACTIVE;
-	}
-
-	/*
-	 * Nothing to do?  Don't complain. This happens when we're just
-	 * turning off quota enforcement.
-	 */
-	if ((mp->m_qflags & flags) == 0) {
-		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-		return (0);
-	}
-
-	/*
-	 * Write the LI_QUOTAOFF log record, and do SB changes atomically,
-	 * and synchronously.
-	 */
-	xfs_qm_log_quotaoff(mp, &qoffstart, flags);
-
-	/*
-	 * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
-	 * to take care of the race between dqget and quotaoff. We don't take
-	 * any special locks to reset these bits. All processes need to check
-	 * these bits *after* taking inode lock(s) to see if the particular
-	 * quota type is in the process of being turned off. If *ACTIVE, it is
-	 * guaranteed that all dquot structures and all quotainode ptrs will all
-	 * stay valid as long as that inode is kept locked.
-	 *
-	 * There is no turning back after this.
-	 */
-	mp->m_qflags &= ~inactivate_flags;
-
-	/*
-	 * Give back all the dquot reference(s) held by inodes.
-	 * Here we go thru every single incore inode in this file system, and
-	 * do a dqrele on the i_udquot/i_gdquot that it may have.
-	 * Essentially, as long as somebody has an inode locked, this guarantees
-	 * that quotas will not be turned off. This is handy because in a
-	 * transaction once we lock the inode(s) and check for quotaon, we can
-	 * depend on the quota inodes (and other things) being valid as long as
-	 * we keep the lock(s).
-	 */
-	xfs_qm_dqrele_all_inodes(mp, flags);
-
-	/*
-	 * Next we make the changes in the quota flag in the mount struct.
-	 * This isn't protected by a particular lock directly, because we
-	 * don't want to take a mrlock everytime we depend on quotas being on.
-	 */
-	mp->m_qflags &= ~(flags);
-
-	/*
-	 * Go through all the dquots of this file system and purge them,
-	 * according to what was turned off. We may not be able to get rid
-	 * of all dquots, because dquots can have temporary references that
-	 * are not attached to inodes. eg. xfs_setattr, xfs_create.
-	 * So, if we couldn't purge all the dquots from the filesystem,
-	 * we can't get rid of the incore data structures.
-	 */
-	while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
-		delay(10 * nculprits);
-
-	/*
-	 * Transactions that had started before ACTIVE state bit was cleared
-	 * could have logged many dquots, so they'd have higher LSNs than
-	 * the first QUOTAOFF log record does. If we happen to crash when
-	 * the tail of the log has gone past the QUOTAOFF record, but
-	 * before the last dquot modification, those dquots __will__
-	 * recover, and that's not good.
-	 *
-	 * So, we have QUOTAOFF start and end logitems; the start
-	 * logitem won't get overwritten until the end logitem appears...
-	 */
-	xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
-
-	/*
-	 * If quotas is completely disabled, close shop.
-	 */
-	if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
-		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-		xfs_qm_destroy_quotainfo(mp);
-		return (0);
-	}
-
-	/*
-	 * Release our quotainode references, and vn_purge them,
-	 * if we don't need them anymore.
-	 */
-	if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
-		XFS_PURGE_INODE(XFS_QI_UQIP(mp));
-		XFS_QI_UQIP(mp) = NULL;
-	}
-	if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
-		XFS_PURGE_INODE(XFS_QI_GQIP(mp));
-		XFS_QI_GQIP(mp) = NULL;
-	}
-	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-	return (error);
-}
-
-STATIC int
-xfs_qm_scall_trunc_qfiles(
-	xfs_mount_t	*mp,
-	uint		flags)
-{
-	int		error;
-	xfs_inode_t	*qip;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return XFS_ERROR(EPERM);
-	error = 0;
-	if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) {
-		qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
-		return XFS_ERROR(EINVAL);
-	}
-
-	if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
-		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
-		if (! error) {
-			(void) xfs_truncate_file(mp, qip);
-			VN_RELE(XFS_ITOV(qip));
-		}
-	}
-
-	if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
-		error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
-		if (! error) {
-			(void) xfs_truncate_file(mp, qip);
-			VN_RELE(XFS_ITOV(qip));
-		}
-	}
-
-	return (error);
-}
-
-
-/*
- * Switch on (a given) quota enforcement for a filesystem.  This takes
- * effect immediately.
- * (Switching on quota accounting must be done at mount time.)
- */
-STATIC int
-xfs_qm_scall_quotaon(
-	xfs_mount_t	*mp,
-	uint		flags)
-{
-	int		error;
-	unsigned long s;
-	uint		qf;
-	uint		accflags;
-	__int64_t	sbflags;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return XFS_ERROR(EPERM);
-
-	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
-	/*
-	 * Switching on quota accounting must be done at mount time.
-	 */
-	accflags = flags & XFS_ALL_QUOTA_ACCT;
-	flags &= ~(XFS_ALL_QUOTA_ACCT);
-
-	sbflags = 0;
-
-	if (flags == 0) {
-		qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
-		return XFS_ERROR(EINVAL);
-	}
-
-	/* No fs can turn on quotas with a delayed effect */
-	ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
-
-	/*
-	 * Can't enforce without accounting. We check the superblock
-	 * qflags here instead of m_qflags because rootfs can have
-	 * quota acct on ondisk without m_qflags' knowing.
-	 */
-	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
-	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
-	    (flags & XFS_UQUOTA_ENFD))
-	    ||
-	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
-	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
-	    (flags & XFS_GQUOTA_ENFD))) {
-		qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
-			flags, mp->m_sb.sb_qflags);
-		return XFS_ERROR(EINVAL);
-	}
-	/*
-	 * If everything's upto-date incore, then don't waste time.
-	 */
-	if ((mp->m_qflags & flags) == flags)
-		return XFS_ERROR(EEXIST);
-
-	/*
-	 * Change sb_qflags on disk but not incore mp->qflags
-	 * if this is the root filesystem.
-	 */
-	s = XFS_SB_LOCK(mp);
-	qf = mp->m_sb.sb_qflags;
-	mp->m_sb.sb_qflags = qf | flags;
-	XFS_SB_UNLOCK(mp, s);
-
-	/*
-	 * There's nothing to change if it's the same.
-	 */
-	if ((qf & flags) == flags && sbflags == 0)
-		return XFS_ERROR(EEXIST);
-	sbflags |= XFS_SB_QFLAGS;
-
-	if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
-		return (error);
-	/*
-	 * If we aren't trying to switch on quota enforcement, we are done.
-	 */
-	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
-	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
-	    (flags & XFS_ALL_QUOTA_ENFD) == 0)
-		return (0);
-
-	if (! XFS_IS_QUOTA_RUNNING(mp))
-		return XFS_ERROR(ESRCH);
-
-	/*
-	 * Switch on quota enforcement in core.
-	 */
-	mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
-	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-	return (0);
-}
-
-
-
-/*
- * Return quota status information, such as uquota-off, enforcements, etc.
- */
-STATIC int
-xfs_qm_scall_getqstat(
-	xfs_mount_t	*mp,
-	fs_quota_stat_t *out)
-{
-	xfs_inode_t	*uip, *gip;
-	boolean_t	tempuqip, tempgqip;
-
-	uip = gip = NULL;
-	tempuqip = tempgqip = B_FALSE;
-	memset(out, 0, sizeof(fs_quota_stat_t));
-
-	out->qs_version = FS_QSTAT_VERSION;
-	if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
-		out->qs_uquota.qfs_ino = NULLFSINO;
-		out->qs_gquota.qfs_ino = NULLFSINO;
-		return (0);
-	}
-	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
-							(XFS_ALL_QUOTA_ACCT|
-							 XFS_ALL_QUOTA_ENFD));
-	out->qs_pad = 0;
-	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
-	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
-	if (mp->m_quotainfo) {
-		uip = mp->m_quotainfo->qi_uquotaip;
-		gip = mp->m_quotainfo->qi_gquotaip;
-	}
-	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
-		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
-			tempuqip = B_TRUE;
-	}
-	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
-		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
-			tempgqip = B_TRUE;
-	}
-	if (uip) {
-		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
-		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
-		if (tempuqip)
-			VN_RELE(XFS_ITOV(uip));
-	}
-	if (gip) {
-		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
-		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
-		if (tempgqip)
-			VN_RELE(XFS_ITOV(gip));
-	}
-	if (mp->m_quotainfo) {
-		out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
-		out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
-		out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
-		out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
-		out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
-		out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
-	}
-	return (0);
-}
-
-/*
- * Adjust quota limits, and start/stop timers accordingly.
- */
-STATIC int
-xfs_qm_scall_setqlim(
-	xfs_mount_t		*mp,
-	xfs_dqid_t		id,
-	uint			type,
-	fs_disk_quota_t		*newlim)
-{
-	xfs_disk_dquot_t	*ddq;
-	xfs_dquot_t		*dqp;
-	xfs_trans_t		*tp;
-	int			error;
-	xfs_qcnt_t		hard, soft;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return XFS_ERROR(EPERM);
-
-	if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
-		return (0);
-
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
-	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
-				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
-		xfs_trans_cancel(tp, 0);
-		return (error);
-	}
-
-	/*
-	 * We don't want to race with a quotaoff so take the quotaoff lock.
-	 * (We don't hold an inode lock, so there's nothing else to stop
-	 * a quotaoff from happening). (XXXThis doesn't currently happen
-	 * because we take the vfslock before calling xfs_qm_sysent).
-	 */
-	mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-
-	/*
-	 * Get the dquot (locked), and join it to the transaction.
-	 * Allocate the dquot if this doesn't exist.
-	 */
-	if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
-		xfs_trans_cancel(tp, XFS_TRANS_ABORT);
-		mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-		ASSERT(error != ENOENT);
-		return (error);
-	}
-	xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET");
-	xfs_trans_dqjoin(tp, dqp);
-	ddq = &dqp->q_core;
-
-	/*
-	 * Make sure that hardlimits are >= soft limits before changing.
-	 */
-	hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
-		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
-			INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT);
-	soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
-		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
-			INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT);
-	if (hard == 0 || hard >= soft) {
-		INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
-		INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
-	}
-	else {
-		qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
-	}
-	hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
-		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
-			INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT);
-	soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
-		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
-			INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT);
-	if (hard == 0 || hard >= soft) {
-		INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
-		INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
-	}
-	else
-		qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
-
-	hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
-		(xfs_qcnt_t) newlim->d_ino_hardlimit :
-		INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT);
-	soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
-		(xfs_qcnt_t) newlim->d_ino_softlimit :
-		INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT);
-	if (hard == 0 || hard >= soft) {
-		INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
-		INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
-	}
-	else
-		qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
-
-	if (id == 0) {
-		/*
-		 * Timelimits for the super user set the relative time
-		 * the other users can be over quota for this file system.
-		 * If it is zero a default is used.
-		 */
-		if (newlim->d_fieldmask & FS_DQ_BTIMER) {
-			mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
-			INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer);
-		}
-		if (newlim->d_fieldmask & FS_DQ_ITIMER) {
-			mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
-			INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer);
-		}
-		if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
-			mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
-			INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
-		}
-	} else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
-		/*
-		 * If the user is now over quota, start the timelimit.
-		 * The user will not be 'warned'.
-		 * Note that we keep the timers ticking, whether enforcement
-		 * is on or off. We don't really want to bother with iterating
-		 * over all ondisk dquots and turning the timers on/off.
-		 */
-		xfs_qm_adjust_dqtimers(mp, ddq);
-	}
-	dqp->dq_flags |= XFS_DQ_DIRTY;
-	xfs_trans_log_dquot(tp, dqp);
-
-	xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
-	xfs_trans_commit(tp, 0, NULL);
-	xfs_qm_dqprint(dqp);
-	xfs_qm_dqrele(dqp);
-	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-	return (0);
-}
-
-STATIC int
-xfs_qm_scall_getquota(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,
-	uint		type,
-	fs_disk_quota_t *out)
-{
-	xfs_dquot_t	*dqp;
-	int		error;
-
-	/*
-	 * Try to get the dquot. We don't want it allocated on disk, so
-	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
-	 * exist, we'll get ENOENT back.
-	 */
-	if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
-		return (error);
-	}
-
-	xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS");
-	/*
-	 * If everything's NULL, this dquot doesn't quite exist as far as
-	 * our utility programs are concerned.
-	 */
-	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
-		xfs_qm_dqput(dqp);
-		return XFS_ERROR(ENOENT);
-	}
-	/* xfs_qm_dqprint(dqp); */
-	/*
-	 * Convert the disk dquot to the exportable format
-	 */
-	xfs_qm_export_dquot(mp, &dqp->q_core, out);
-	xfs_qm_dqput(dqp);
-	return (error ? XFS_ERROR(EFAULT) : 0);
-}
-
-
-STATIC int
-xfs_qm_log_quotaoff_end(
-	xfs_mount_t		*mp,
-	xfs_qoff_logitem_t	*startqoff,
-	uint			flags)
-{
-	xfs_trans_t	       *tp;
-	int			error;
-	xfs_qoff_logitem_t     *qoffi;
-
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
-
-	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
-				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
-		xfs_trans_cancel(tp, 0);
-		return (error);
-	}
-
-	qoffi = xfs_trans_get_qoff_item(tp, startqoff,
-					flags & XFS_ALL_QUOTA_ACCT);
-	xfs_trans_log_quotaoff_item(tp, qoffi);
-
-	/*
-	 * We have to make sure that the transaction is secure on disk before we
-	 * return and actually stop quota accounting. So, make it synchronous.
-	 * We don't care about quotoff's performance.
-	 */
-	xfs_trans_set_sync(tp);
-	error = xfs_trans_commit(tp, 0, NULL);
-	return (error);
-}
-
-
-STATIC int
-xfs_qm_log_quotaoff(
-	xfs_mount_t	       *mp,
-	xfs_qoff_logitem_t     **qoffstartp,
-	uint		       flags)
-{
-	xfs_trans_t	       *tp;
-	int			error;
-	unsigned long	s;
-	xfs_qoff_logitem_t     *qoffi=NULL;
-	uint			oldsbqflag=0;
-
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
-	if ((error = xfs_trans_reserve(tp, 0,
-				      sizeof(xfs_qoff_logitem_t) * 2 +
-				      mp->m_sb.sb_sectsize + 128,
-				      0,
-				      0,
-				      XFS_DEFAULT_LOG_COUNT))) {
-		goto error0;
-	}
-
-	qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
-	xfs_trans_log_quotaoff_item(tp, qoffi);
-
-	s = XFS_SB_LOCK(mp);
-	oldsbqflag = mp->m_sb.sb_qflags;
-	mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
-	XFS_SB_UNLOCK(mp, s);
-
-	xfs_mod_sb(tp, XFS_SB_QFLAGS);
-
-	/*
-	 * We have to make sure that the transaction is secure on disk before we
-	 * return and actually stop quota accounting. So, make it synchronous.
-	 * We don't care about quotoff's performance.
-	 */
-	xfs_trans_set_sync(tp);
-	error = xfs_trans_commit(tp, 0, NULL);
-
-error0:
-	if (error) {
-		xfs_trans_cancel(tp, 0);
-		/*
-		 * No one else is modifying sb_qflags, so this is OK.
-		 * We still hold the quotaofflock.
-		 */
-		s = XFS_SB_LOCK(mp);
-		mp->m_sb.sb_qflags = oldsbqflag;
-		XFS_SB_UNLOCK(mp, s);
-	}
-	*qoffstartp = qoffi;
-	return (error);
-}
-
-
-/*
- * Translate an internal style on-disk-dquot to the exportable format.
- * The main differences are that the counters/limits are all in Basic
- * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
- * to be converted to the native endianness.
- */
-STATIC void
-xfs_qm_export_dquot(
-	xfs_mount_t		*mp,
-	xfs_disk_dquot_t	*src,
-	struct fs_disk_quota	*dst)
-{
-	memset(dst, 0, sizeof(*dst));
-	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
-	dst->d_flags =
-		xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
-	dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
-	dst->d_blk_hardlimit = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
-	dst->d_blk_softlimit = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
-	dst->d_ino_hardlimit = (__uint64_t)
-		INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
-	dst->d_ino_softlimit = (__uint64_t)
-		INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
-	dst->d_bcount = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
-	dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
-	dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
-	dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
-	dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
-	dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);
-
-	dst->d_rtb_hardlimit = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
-	dst->d_rtb_softlimit = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
-	dst->d_rtbcount = (__uint64_t)
-		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
-	dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
-	dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);
-
-	/*
-	 * Internally, we don't reset all the timers when quota enforcement
-	 * gets turned off. No need to confuse the userlevel code,
-	 * so return zeroes in that case.
-	 */
-	if (! XFS_IS_QUOTA_ENFORCED(mp)) {
-		dst->d_btimer = 0;
-		dst->d_itimer = 0;
-		dst->d_rtbtimer = 0;
-	}
-
-#ifdef DEBUG
-	if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
-		if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
-		    (dst->d_blk_softlimit > 0)) {
-			ASSERT(dst->d_btimer != 0);
-		}
-		if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
-		    (dst->d_ino_softlimit > 0)) {
-			ASSERT(dst->d_itimer != 0);
-		}
-	}
-#endif
-}
-
-STATIC uint
-xfs_qm_import_qtype_flags(
-	uint uflags)
-{
-	/*
-	 * Can't be both at the same time.
-	 */
-	if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
-	     (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
-	    ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
-		return (0);
-
-	return (uflags & XFS_USER_QUOTA) ?
-		XFS_DQ_USER : XFS_DQ_GROUP;
-}
-
-STATIC uint
-xfs_qm_export_qtype_flags(
-	uint flags)
-{
-	/*
-	 * Can't be both at the same time.
-	 */
-	ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
-		(XFS_GROUP_QUOTA | XFS_USER_QUOTA));
-	ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
-
-	return (flags & XFS_DQ_USER) ?
-		XFS_USER_QUOTA : XFS_GROUP_QUOTA;
-}
-
-STATIC uint
-xfs_qm_import_flags(
-	uint uflags)
-{
-	uint flags = 0;
-
-	if (uflags & XFS_QUOTA_UDQ_ACCT)
-		flags |= XFS_UQUOTA_ACCT;
-	if (uflags & XFS_QUOTA_GDQ_ACCT)
-		flags |= XFS_GQUOTA_ACCT;
-	if (uflags & XFS_QUOTA_UDQ_ENFD)
-		flags |= XFS_UQUOTA_ENFD;
-	if (uflags & XFS_QUOTA_GDQ_ENFD)
-		flags |= XFS_GQUOTA_ENFD;
-	return (flags);
-}
-
-
-STATIC uint
-xfs_qm_export_flags(
-	uint flags)
-{
-	uint uflags;
-
-	uflags = 0;
-	if (flags & XFS_UQUOTA_ACCT)
-		uflags |= XFS_QUOTA_UDQ_ACCT;
-	if (flags & XFS_GQUOTA_ACCT)
-		uflags |= XFS_QUOTA_GDQ_ACCT;
-	if (flags & XFS_UQUOTA_ENFD)
-		uflags |= XFS_QUOTA_UDQ_ENFD;
-	if (flags & XFS_GQUOTA_ENFD)
-		uflags |= XFS_QUOTA_GDQ_ENFD;
-	return (uflags);
-}
-
-
-/*
- * Go thru all the inodes in the file system, releasing their dquots.
- * Note that the mount structure gets modified to indicate that quotas are off
- * AFTER this, in the case of quotaoff. This also gets called from
- * xfs_rootumount.
- */
-void
-xfs_qm_dqrele_all_inodes(
-	struct xfs_mount *mp,
-	uint		 flags)
-{
-	vmap_t		vmap;
-	xfs_inode_t	*ip, *topino;
-	uint		ireclaims;
-	vnode_t		*vp;
-	boolean_t	vnode_refd;
-
-	ASSERT(mp->m_quotainfo);
-
-again:
-	XFS_MOUNT_ILOCK(mp);
-	ip = mp->m_inodes;
-	if (ip == NULL) {
-		XFS_MOUNT_IUNLOCK(mp);
-		return;
-	}
-	do {
-		/* Skip markers inserted by xfs_sync */
-		if (ip->i_mount == NULL) {
-			ip = ip->i_mnext;
-			continue;
-		}
-		/* Root inode, rbmip and rsumip have associated blocks */
-		if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
-			ASSERT(ip->i_udquot == NULL);
-			ASSERT(ip->i_gdquot == NULL);
-			ip = ip->i_mnext;
-			continue;
-		}
-		vp = XFS_ITOV_NULL(ip);
-		if (!vp) {
-			ASSERT(ip->i_udquot == NULL);
-			ASSERT(ip->i_gdquot == NULL);
-			ip = ip->i_mnext;
-			continue;
-		}
-		vnode_refd = B_FALSE;
-		if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
-			/*
-			 * Sample vp mapping while holding the mplock, lest
-			 * we come across a non-existent vnode.
-			 */
-			VMAP(vp, vmap);
-			ireclaims = mp->m_ireclaims;
-			topino = mp->m_inodes;
-			XFS_MOUNT_IUNLOCK(mp);
-
-			/* XXX restart limit ? */
-			if ( ! (vp = vn_get(vp, &vmap)))
-				goto again;
-			xfs_ilock(ip, XFS_ILOCK_EXCL);
-			vnode_refd = B_TRUE;
-		} else {
-			ireclaims = mp->m_ireclaims;
-			topino = mp->m_inodes;
-			XFS_MOUNT_IUNLOCK(mp);
-		}
-
-		/*
-		 * We don't keep the mountlock across the dqrele() call,
-		 * since it can take a while..
-		 */
-		if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
-			xfs_qm_dqrele(ip->i_udquot);
-			ip->i_udquot = NULL;
-		}
-		if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
-			xfs_qm_dqrele(ip->i_gdquot);
-			ip->i_gdquot = NULL;
-		}
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-		/*
-		 * Wait until we've dropped the ilock and mountlock to
-		 * do the vn_rele. Or be condemned to an eternity in the
-		 * inactive code in hell.
-		 */
-		if (vnode_refd)
-			VN_RELE(vp);
-		XFS_MOUNT_ILOCK(mp);
-		/*
-		 * If an inode was inserted or removed, we gotta
-		 * start over again.
-		 */
-		if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
-			/* XXX use a sentinel */
-			XFS_MOUNT_IUNLOCK(mp);
-			goto again;
-		}
-		ip = ip->i_mnext;
-	} while (ip != mp->m_inodes);
-
-	XFS_MOUNT_IUNLOCK(mp);
-}
-
-/*------------------------------------------------------------------------*/
-#ifdef DEBUG
-/*
- * This contains all the test functions for XFS disk quotas.
- * Currently it does a quota accounting check. ie. it walks through
- * all inodes in the file system, calculating the dquot accounting fields,
- * and prints out any inconsistencies.
- */
-xfs_dqhash_t *qmtest_udqtab;
-xfs_dqhash_t *qmtest_gdqtab;
-int	      qmtest_hashmask;
-int	      qmtest_nfails;
-mutex_t	      qcheck_lock;
-
-#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-				 (__psunsigned_t)(id)) & \
-				(qmtest_hashmask - 1))
-
-#define DQTEST_HASH(mp, id, type)   ((type & XFS_DQ_USER) ? \
-				     (qmtest_udqtab + \
-				      DQTEST_HASHVAL(mp, id)) : \
-				     (qmtest_gdqtab + \
-				      DQTEST_HASHVAL(mp, id)))
-
-#define DQTEST_LIST_PRINT(l, NXT, title) \
-{ \
-	  xfs_dqtest_t	*dqp; int i = 0;\
-	  printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \
-	  for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
-	       dqp = (xfs_dqtest_t *)dqp->NXT) { \
-	    printk("\t%d\.\t\"%d (%s)\"\t bcnt = %d, icnt = %d\n", \
-			 ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp),	     \
-			 dqp->d_bcount, dqp->d_icount); } \
-}
-
-typedef struct dqtest {
-	xfs_dqmarker_t	q_lists;
-	xfs_dqhash_t	*q_hash;	/* the hashchain header */
-	xfs_mount_t	*q_mount;	/* filesystem this relates to */
-	xfs_dqid_t	d_id;		/* user id or group id */
-	xfs_qcnt_t	d_bcount;	/* # disk blocks owned by the user */
-	xfs_qcnt_t	d_icount;	/* # inodes owned by the user */
-} xfs_dqtest_t;
-
-STATIC void
-xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
-{
-	xfs_dquot_t *d;
-	if (((d) = (h)->qh_next))
-		(d)->HL_PREVP = &((dqp)->HL_NEXT);
-	(dqp)->HL_NEXT = d;
-	(dqp)->HL_PREVP = &((h)->qh_next);
-	(h)->qh_next = (xfs_dquot_t *)dqp;
-	(h)->qh_version++;
-	(h)->qh_nelems++;
-}
-STATIC void
-xfs_qm_dqtest_print(
-	xfs_dqtest_t	*d)
-{
-	printk("-----------DQTEST DQUOT----------------\n");
-	printk("---- dquot ID =	 %d\n", d->d_id);
-	printk("---- type     =	 %s\n", XFS_QM_ISUDQ(d) ? "USR" : "GRP");
-	printk("---- fs	      =	 0x%p\n", d->q_mount);
-	printk("---- bcount   =	 %Lu (0x%x)\n", d->d_bcount, (int)d->d_bcount);
-	printk("---- icount   =	 %Lu (0x%x)\n", d->d_icount, (int)d->d_icount);
-	printk("---------------------------\n");
-}
-
-STATIC void
-xfs_qm_dqtest_failed(
-	xfs_dqtest_t	*d,
-	xfs_dquot_t	*dqp,
-	char		*reason,
-	xfs_qcnt_t	a,
-	xfs_qcnt_t	b,
-	int		error)
-{
-	qmtest_nfails++;
-	if (error)
-		printk("quotacheck failed for %d, error = %d\nreason = %s\n",
-		       INT_GET(d->d_id, ARCH_CONVERT), error, reason);
-	else
-		printk("quotacheck failed for %d (%s) [%d != %d]\n",
-		       INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b);
-	xfs_qm_dqtest_print(d);
-	if (dqp)
-		xfs_qm_dqprint(dqp);
-}
-
-STATIC int
-xfs_dqtest_cmp2(
-	xfs_dqtest_t	*d,
-	xfs_dquot_t	*dqp)
-{
-	int err = 0;
-	if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) {
-		xfs_qm_dqtest_failed(d, dqp, "icount mismatch",
-				     INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), d->d_icount, 0);
-		err++;
-	}
-	if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) {
-		xfs_qm_dqtest_failed(d, dqp, "bcount mismatch",
-				     INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), d->d_bcount, 0);
-		err++;
-	}
-	if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
-	    INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
-		if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) &&
-		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
-			printk("%d [%s] [0x%p] BLK TIMER NOT STARTED\n",
-			       d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
-			err++;
-		}
-	}
-	if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
-	    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
-		if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
-		    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
-			printk("%d [%s] [0x%p] INO TIMER NOT STARTED\n",
-			       d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
-			err++;
-		}
-	}
-#if 0
-	if (!err) {
-		printk("%d [%s] [0x%p] qchecked\n",
-		       d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
-	}
-#endif
-	return (err);
-}
-
-STATIC void
-xfs_dqtest_cmp(
-	xfs_dqtest_t	*d)
-{
-	xfs_dquot_t	*dqp;
-	int		error;
-
-	/* xfs_qm_dqtest_print(d); */
-	if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0,
-				 &dqp))) {
-		xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error);
-		return;
-	}
-	xfs_dqtest_cmp2(d, dqp);
-	xfs_qm_dqput(dqp);
-}
-
-STATIC int
-xfs_qm_internalqcheck_dqget(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,
-	uint		type,
-	xfs_dqtest_t	**O_dq)
-{
-	xfs_dqtest_t	*d;
-	xfs_dqhash_t	*h;
-
-	h = DQTEST_HASH(mp, id, type);
-	for (d = (xfs_dqtest_t *) h->qh_next; d != NULL;
-	     d = (xfs_dqtest_t *) d->HL_NEXT) {
-		/* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */
-		if (d->d_id == id && mp == d->q_mount) {
-			*O_dq = d;
-			return (0);
-		}
-	}
-	d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP);
-	d->dq_flags = type;
-	d->d_id = id;
-	d->q_mount = mp;
-	d->q_hash = h;
-	xfs_qm_hashinsert(h, d);
-	*O_dq = d;
-	return (0);
-}
-
-STATIC void
-xfs_qm_internalqcheck_get_dquots(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	uid,
-	xfs_dqid_t	gid,
-	xfs_dqtest_t	**ud,
-	xfs_dqtest_t	**gd)
-{
-	if (XFS_IS_UQUOTA_ON(mp))
-		xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
-	if (XFS_IS_GQUOTA_ON(mp))
-		xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
-}
-
-
-STATIC void
-xfs_qm_internalqcheck_dqadjust(
-	xfs_inode_t		*ip,
-	xfs_dqtest_t		*d)
-{
-	d->d_icount++;
-	d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;
-}
-
-STATIC int
-xfs_qm_internalqcheck_adjust(
-	xfs_mount_t	*mp,		/* mount point for filesystem */
-	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_ino_t	ino,		/* inode number to get data for */
-	void		*buffer,	/* not used */
-	xfs_daddr_t	bno,		/* starting block of inode cluster */
-	void		*dip,		/* not used */
-	int		*res)		/* bulkstat result code */
-{
-	xfs_inode_t		*ip;
-	xfs_dqtest_t		*ud, *gd;
-	uint			lock_flags;
-	boolean_t		ipreleased;
-	int			error;
-
-	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
-		*res = BULKSTAT_RV_NOTHING;
-		qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
-			(unsigned long long) ino,
-			(unsigned long long) mp->m_sb.sb_uquotino,
-			(unsigned long long) mp->m_sb.sb_gquotino);
-		return XFS_ERROR(EINVAL);
-	}
-	ipreleased = B_FALSE;
- again:
-	lock_flags = XFS_ILOCK_SHARED;
-	if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) {
-		*res = BULKSTAT_RV_NOTHING;
-		return (error);
-	}
-
-	if (ip->i_d.di_mode == 0) {
-		xfs_iput_new(ip, lock_flags);
-		*res = BULKSTAT_RV_NOTHING;
-		return XFS_ERROR(ENOENT);
-	}
-
-	/*
-	 * This inode can have blocks after eof which can get released
-	 * when we send it to inactive. Since we don't check the dquot
-	 * until the after all our calculations are done, we must get rid
-	 * of those now.
-	 */
-	if (! ipreleased) {
-		xfs_iput(ip, lock_flags);
-		ipreleased = B_TRUE;
-		goto again;
-	}
-	xfs_qm_internalqcheck_get_dquots(mp,
-					(xfs_dqid_t) ip->i_d.di_uid,
-					(xfs_dqid_t) ip->i_d.di_gid,
-					&ud, &gd);
-	if (XFS_IS_UQUOTA_ON(mp)) {
-		ASSERT(ud);
-		xfs_qm_internalqcheck_dqadjust(ip, ud);
-	}
-	if (XFS_IS_GQUOTA_ON(mp)) {
-		ASSERT(gd);
-		xfs_qm_internalqcheck_dqadjust(ip, gd);
-	}
-	xfs_iput(ip, lock_flags);
-	*res = BULKSTAT_RV_DIDONE;
-	return (0);
-}
-
-
-/* PRIVATE, debugging */
-int
-xfs_qm_internalqcheck(
-	xfs_mount_t	*mp)
-{
-	xfs_ino_t	lastino;
-	int		done, count;
-	int		i;
-	xfs_dqtest_t	*d, *e;
-	xfs_dqhash_t	*h1;
-	int		error;
-
-	lastino = 0;
-	qmtest_hashmask = 32;
-	count = 5;
-	done = 0;
-	qmtest_nfails = 0;
-
-	if (! XFS_IS_QUOTA_ON(mp))
-		return XFS_ERROR(ESRCH);
-
-	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-	XFS_bflush(mp->m_ddev_targp);
-	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-	XFS_bflush(mp->m_ddev_targp);
-
-	mutex_lock(&qcheck_lock, PINOD);
-	/* There should be absolutely no quota activity while this
-	   is going on. */
-	qmtest_udqtab = kmem_zalloc(qmtest_hashmask *
-				    sizeof(xfs_dqhash_t), KM_SLEEP);
-	qmtest_gdqtab = kmem_zalloc(qmtest_hashmask *
-				    sizeof(xfs_dqhash_t), KM_SLEEP);
-	do {
-		/*
-		 * Iterate thru all the inodes in the file system,
-		 * adjusting the corresponding dquot counters
-		 */
-		if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
-				 xfs_qm_internalqcheck_adjust,
-				 0, NULL, BULKSTAT_FG_IGET, &done))) {
-			break;
-		}
-	} while (! done);
-	if (error) {
-		printk("Bulkstat returned error 0x%x\n",
-		       error);
-	}
-	printk("Checking results against system dquots\n");
-	for (i = 0; i < qmtest_hashmask; i++) {
-		h1 = &qmtest_udqtab[i];
-		for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
-			xfs_dqtest_cmp(d);
-			e = (xfs_dqtest_t *) d->HL_NEXT;
-			kmem_free(d, sizeof(xfs_dqtest_t));
-			d = e;
-		}
-		h1 = &qmtest_gdqtab[i];
-		for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
-			xfs_dqtest_cmp(d);
-			e = (xfs_dqtest_t *) d->HL_NEXT;
-			kmem_free(d, sizeof(xfs_dqtest_t));
-			d = e;
-		}
-	}
-
-	if (qmtest_nfails) {
-		printk("**************	quotacheck failed  **************\n");
-		printk("failures = %d\n", qmtest_nfails);
-	} else {
-		printk("**************	quotacheck successful! **************\n");
-	}
-	kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
-	kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
-	mutex_unlock(&qcheck_lock);
-	return (qmtest_nfails);
-}
-
-#endif /* DEBUG */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_qmops.c linux-2.5.66-bk3/fs/xfs/xfs_qmops.c
--- linux-2.5.66-bk2/fs/xfs/xfs_qmops.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk3/fs/xfs/xfs_qmops.c	Mon Mar 31 12:48:53 2003
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <xfs.h>
+
+#ifndef CONFIG_XFS_QUOTA
+STATIC struct xfs_dquot *
+xfs_dqvopchown_default(
+	struct xfs_trans	*tp,
+	struct xfs_inode	*ip,
+	struct xfs_dquot	**dqp,
+	struct xfs_dquot	*dq)
+{
+	return NULL;
+}
+
+xfs_qmops_t	xfs_qmcore_xfs = {
+	.xfs_qminit		= (xfs_qminit_t) fs_noerr,
+	.xfs_qmdone		= (xfs_qmdone_t) fs_noerr,
+	.xfs_qmmount		= (xfs_qmmount_t) fs_noerr,
+	.xfs_qmunmount		= (xfs_qmunmount_t) fs_noerr,
+	.xfs_dqrele		= (xfs_dqrele_t) fs_noerr,
+	.xfs_dqattach		= (xfs_dqattach_t) fs_noerr,
+	.xfs_dqdetach		= (xfs_dqdetach_t) fs_noerr,
+	.xfs_dqpurgeall		= (xfs_dqpurgeall_t) fs_noerr,
+	.xfs_dqvopalloc		= (xfs_dqvopalloc_t) fs_noerr,
+	.xfs_dqvopcreate	= (xfs_dqvopcreate_t) fs_noerr,
+	.xfs_dqvoprename	= (xfs_dqvoprename_t) fs_noerr,
+	.xfs_dqvopchown		= xfs_dqvopchown_default,
+	.xfs_dqvopchownresv	= (xfs_dqvopchownresv_t) fs_noerr,
+};
+#endif /* CONFIG_XFS_QUOTA */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_quota.h linux-2.5.66-bk3/fs/xfs/xfs_quota.h
--- linux-2.5.66-bk2/fs/xfs/xfs_quota.h	Mon Mar 24 14:01:47 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_quota.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -33,6 +33,12 @@
 #define __XFS_QUOTA_H__
 
 /*
+ * The ondisk form of a dquot structure.
+ */
+#define XFS_DQUOT_MAGIC		0x4451		/* 'DQ' */
+#define XFS_DQUOT_VERSION	(u_int8_t)0x01	/* latest version number */
+
+/*
  * uid_t and gid_t are hard-coded to 32 bits in the inode.
  * Hence, an 'id' in a dquot is 32 bits..
  */
@@ -47,6 +53,100 @@
 typedef __uint16_t	xfs_qwarncnt_t;
 
 /*
+ * This is the main portion of the on-disk representation of quota
+ * information for a user. This is the q_core of the xfs_dquot_t that
+ * is kept in kernel memory. We pad this with some more expansion room
+ * to construct the on disk structure.
+ */
+typedef struct	xfs_disk_dquot {
+/*16*/	u_int16_t	d_magic;	/* dquot magic = XFS_DQUOT_MAGIC */
+/*8 */	u_int8_t	d_version;	/* dquot version */
+/*8 */	u_int8_t	d_flags;	/* XFS_DQ_USER/PROJ/GROUP */
+/*32*/	xfs_dqid_t	d_id;		/* user,project,group id */
+/*64*/	xfs_qcnt_t	d_blk_hardlimit;/* absolute limit on disk blks */
+/*64*/	xfs_qcnt_t	d_blk_softlimit;/* preferred limit on disk blks */
+/*64*/	xfs_qcnt_t	d_ino_hardlimit;/* maximum # allocated inodes */
+/*64*/	xfs_qcnt_t	d_ino_softlimit;/* preferred inode limit */
+/*64*/	xfs_qcnt_t	d_bcount;	/* disk blocks owned by the user */
+/*64*/	xfs_qcnt_t	d_icount;	/* inodes owned by the user */
+/*32*/	__int32_t	d_itimer;	/* zero if within inode limits if not,
+					   this is when we refuse service */
+/*32*/	__int32_t	d_btimer;	/* similar to above; for disk blocks */
+/*16*/	xfs_qwarncnt_t	d_iwarns;	/* warnings issued wrt num inodes */
+/*16*/	xfs_qwarncnt_t	d_bwarns;	/* warnings issued wrt disk blocks */
+/*32*/	__int32_t	d_pad0;		/* 64 bit align */
+/*64*/	xfs_qcnt_t	d_rtb_hardlimit;/* absolute limit on realtime blks */
+/*64*/	xfs_qcnt_t	d_rtb_softlimit;/* preferred limit on RT disk blks */
+/*64*/	xfs_qcnt_t	d_rtbcount;	/* realtime blocks owned */
+/*32*/	__int32_t	d_rtbtimer;	/* similar to above; for RT disk blocks */
+/*16*/	xfs_qwarncnt_t	d_rtbwarns;	/* warnings issued wrt RT disk blocks */
+/*16*/	__uint16_t	d_pad;
+} xfs_disk_dquot_t;
+
+/*
+ * This is what goes on disk. This is separated from the xfs_disk_dquot because
+ * carrying the unnecessary padding would be a waste of memory.
+ */
+typedef struct xfs_dqblk {
+	xfs_disk_dquot_t  dd_diskdq;	/* portion that lives incore as well */
+	char		  dd_fill[32];	/* filling for posterity */
+} xfs_dqblk_t;
+
+/*
+ * flags for q_flags field in the dquot.
+ */
+#define XFS_DQ_USER		0x0001		/* a user quota */
+/* #define XFS_DQ_PROJ		0x0002		-- project quota (IRIX) */
+#define XFS_DQ_GROUP		0x0004		/* a group quota */
+#define XFS_DQ_FLOCKED		0x0008		/* flush lock taken */
+#define XFS_DQ_DIRTY		0x0010		/* dquot is dirty */
+#define XFS_DQ_WANT		0x0020		/* for lookup/reclaim race */
+#define XFS_DQ_INACTIVE		0x0040		/* dq off mplist & hashlist */
+#define XFS_DQ_MARKER		0x0080		/* sentinel */
+
+/*
+ * In the worst case, when both user and group quotas are on,
+ * we can have a max of three dquots changing in a single transaction.
+ */
+#define XFS_DQUOT_LOGRES(mp)	(sizeof(xfs_disk_dquot_t) * 3)
+
+
+/*
+ * These are the structures used to lay out dquots and quotaoff
+ * records on the log. Quite similar to those of inodes.
+ */
+
+/*
+ * log format struct for dquots.
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ */
+typedef struct xfs_dq_logformat {
+	__uint16_t		qlf_type;      /* dquot log item type */
+	__uint16_t		qlf_size;      /* size of this item */
+	xfs_dqid_t		qlf_id;	       /* usr/grp id number : 32 bits */
+	__int64_t		qlf_blkno;     /* blkno of dquot buffer */
+	__int32_t		qlf_len;       /* len of dquot buffer */
+	__uint32_t		qlf_boffset;   /* off of dquot in buffer */
+} xfs_dq_logformat_t;
+
+/*
+ * log format struct for QUOTAOFF records.
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
+ * to the first and ensures that the first logitem is taken out of the AIL
+ * only when the last one is securely committed.
+ */
+typedef struct xfs_qoff_logformat {
+	unsigned short		qf_type;	/* quotaoff log item type */
+	unsigned short		qf_size;	/* size of this item */
+	unsigned int		qf_flags;	/* USR and/or GRP */
+	char			qf_pad[12];	/* padding for future */
+} xfs_qoff_logformat_t;
+
+
+/*
  * Disk quotas status in m_qflags, and also sb_qflags. 16 bits.
  */
 #define XFS_UQUOTA_ACCT 0x0001	/* user quota accounting ON */
@@ -134,13 +234,14 @@
 #define XFS_QMOPT_QUOTALL	(XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA)
 #define XFS_QMOPT_RESBLK_MASK	(XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
 
+#ifdef __KERNEL__
 /*
  * This check is done typically without holding the inode lock;
  * that may seem racey, but it is harmless in the context that it is used.
  * The inode cannot go inactive as long a reference is kept, and
  * therefore if dquot(s) were attached, they'll stay consistent.
  * If, for example, the ownership of the inode changes while
- * we didnt have the inode locked, the appropriate dquot(s) will be
+ * we didn't have the inode locked, the appropriate dquot(s) will be
  * attached atomically.
  */
 #define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
@@ -161,190 +262,93 @@
 #define XFS_MOUNT_QUOTA_MASK	(XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \
 				 XFS_GQUOTA_ACTIVE)
 
-#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
-
 
-#ifdef __KERNEL__
-
-#ifdef CONFIG_XFS_QUOTA
 /*
- * External Interface to the XFS disk quota subsystem.
+ * The structure kept inside the xfs_trans_t keep track of dquot changes
+ * within a transaction and apply them later.
  */
-struct	xfs_disk_dquot;
-struct	xfs_dqhash;
-struct	xfs_dquot;
-struct	xfs_inode;
-struct	xfs_mount;
-struct	xfs_trans;
-
-/*
- * Quota Manager Interface.
- */
-extern struct xfs_qm   *xfs_qm_init(void);
-extern void		xfs_qm_destroy(struct xfs_qm *);
-extern int		xfs_qm_dqflush_all(struct xfs_mount *, int);
-extern int		xfs_qm_dqattach(struct xfs_inode *, uint);
-extern int		xfs_qm_dqpurge_all(struct xfs_mount *, uint);
-extern void		xfs_qm_mount_quotainit(struct xfs_mount *, uint);
-extern void		xfs_qm_unmount_quotadestroy(struct xfs_mount *);
-extern int		xfs_qm_mount_quotas(struct xfs_mount *);
-extern int		xfs_qm_unmount_quotas(struct xfs_mount *);
-extern void		xfs_qm_dqdettach_inode(struct xfs_inode *);
-extern int		xfs_qm_sync(struct xfs_mount *, short);
-
-/*
- * Dquot interface.
- */
-extern void		xfs_dqlock(struct xfs_dquot *);
-extern void		xfs_dqunlock(struct xfs_dquot *);
-extern void		xfs_dqunlock_nonotify(struct xfs_dquot *);
-extern void		xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
-extern void		xfs_qm_dqput(struct xfs_dquot *);
-extern void		xfs_qm_dqrele(struct xfs_dquot *);
-extern xfs_dqid_t	xfs_qm_dqid(struct xfs_dquot *);
-extern int		xfs_qm_dqget(struct xfs_mount *,
-				     struct xfs_inode *, xfs_dqid_t,
-				      uint, uint, struct xfs_dquot **);
-extern int		xfs_qm_dqcheck(struct xfs_disk_dquot *,
-				       xfs_dqid_t, uint, uint, char *);
-
-/*
- * Vnodeops specific code that should actually be _in_ xfs_vnodeops.c, but
- * is here because it's nicer to keep vnodeops (therefore, XFS) lean
- * and clean.
- */
-extern struct xfs_dquot *	xfs_qm_vop_chown(struct xfs_trans *,
-						 struct xfs_inode *,
-						 struct xfs_dquot **,
-						 struct xfs_dquot *);
-extern int		xfs_qm_vop_dqalloc(struct xfs_mount *,
-					   struct xfs_inode *,
-					   uid_t, gid_t, uint,
-					   struct xfs_dquot	**,
-					   struct xfs_dquot	**);
-
-extern int		xfs_qm_vop_chown_reserve(struct xfs_trans *,
-						 struct xfs_inode *,
-						 struct xfs_dquot *,
-						 struct xfs_dquot *,
-						 uint);
-
-extern int		xfs_qm_vop_rename_dqattach(struct xfs_inode **);
-extern void		xfs_qm_vop_dqattach_and_dqmod_newinode(
-						struct xfs_trans *,
-						struct xfs_inode *,
-						struct xfs_dquot *,
-						struct xfs_dquot *);
-
-
-/*
- * Dquot Transaction interface
- */
-extern void		xfs_trans_alloc_dqinfo(struct xfs_trans *);
-extern void		xfs_trans_free_dqinfo(struct xfs_trans *);
-extern void		xfs_trans_dup_dqinfo(struct xfs_trans *,
-					     struct xfs_trans *);
-extern void		xfs_trans_mod_dquot(struct xfs_trans *,
-					    struct xfs_dquot *,
-					    uint, long);
-extern void		xfs_trans_mod_dquot_byino(struct xfs_trans *,
-						  struct xfs_inode *,
-						  uint, long);
-extern void		xfs_trans_apply_dquot_deltas(struct xfs_trans *);
-extern void		xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *);
-
-extern int		xfs_trans_reserve_quota_nblks(struct xfs_trans *,
-						      struct xfs_inode *,
-						      long, long, uint);
-
-
-extern int		xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
-							 struct xfs_dquot *,
-							 struct xfs_dquot *,
-							 long, long, uint);
-extern void		xfs_trans_log_dquot(struct xfs_trans *,
-					    struct xfs_dquot *);
-extern void		xfs_trans_dqjoin(struct xfs_trans *,
-					 struct xfs_dquot *);
-extern void		xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
-
-# define _XQM_ZONE_DESTROY(z)	((z)? kmem_cache_destroy(z) : (void)0)
-
-#else
-# define xfs_qm_init()					(NULL)
-# define xfs_qm_destroy(xqm)				do { } while (0)
-# define xfs_qm_dqflush_all(m,t)			(ENOSYS)
-# define xfs_qm_dqattach(i,t)				(ENOSYS)
-# define xfs_qm_dqpurge_all(m,t)			(ENOSYS)
-# define xfs_qm_mount_quotainit(m,t)			do { } while (0)
-# define xfs_qm_unmount_quotadestroy(m)			do { } while (0)
-# define xfs_qm_mount_quotas(m)				(ENOSYS)
-# define xfs_qm_unmount_quotas(m)			(ENOSYS)
-# define xfs_qm_dqdettach_inode(i)			do { } while (0)
-# define xfs_qm_sync(m,t)				(ENOSYS)
-# define xfs_dqlock(d)					do { } while (0)
-# define xfs_dqunlock(d)				do { } while (0)
-# define xfs_dqunlock_nonotify(d)			do { } while (0)
-# define xfs_dqlock2(d1,d2)				do { } while (0)
-# define xfs_qm_dqput(d)				do { } while (0)
-# define xfs_qm_dqrele(d)				do { } while (0)
-# define xfs_qm_dqid(d)					(-1)
-# define xfs_qm_dqget(m,i,di,t,f,d)			(ENOSYS)
-# define xfs_qm_dqcheck(dd,di,t,f,s)			(ENOSYS)
-# define xfs_trans_alloc_dqinfo(t)			do { } while (0)
-# define xfs_trans_free_dqinfo(t)			do { } while (0)
-# define xfs_trans_dup_dqinfo(t1,t2)			do { } while (0)
-# define xfs_trans_mod_dquot(t,d,f,x)			do { } while (0)
-# define xfs_trans_mod_dquot_byino(t,i,f,x)		do { } while (0)
-# define xfs_trans_apply_dquot_deltas(t)		do { } while (0)
-# define xfs_trans_unreserve_and_mod_dquots(t)		do { } while (0)
-# define xfs_trans_reserve_quota_nblks(t,i,nb,ni,f)	(ENOSYS)
-# define xfs_trans_reserve_quota_bydquots(t,x,y,b,i,f)	(ENOSYS)
-# define xfs_trans_log_dquot(t,d)			do { } while (0)
-# define xfs_trans_dqjoin(t,d)				do { } while (0)
-# define xfs_qm_dqrele_all_inodes(m,t)			do { } while (0)
-# define xfs_qm_vop_chown(t,i,d1,d2)			(NULL)
-# define xfs_qm_vop_dqalloc(m,i,u,g,f,d1,d2)		(ENOSYS)
-# define xfs_qm_vop_chown_reserve(t,i,d1,d2,f)		(ENOSYS)
-# define xfs_qm_vop_rename_dqattach(i)			(ENOSYS)
-# define xfs_qm_vop_dqattach_and_dqmod_newinode(t,i,x,y) do { } while (0)
-# define _XQM_ZONE_DESTROY(z)				do { } while (0)
-#endif	/* CONFIG_XFS_QUOTA */
-
-/*
- * Regular disk block quota reservations
- */
-#define		xfs_trans_reserve_blkquota(tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_REGBLKS)
-
-#define		xfs_trans_reserve_blkquota_force(tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, \
-		XFS_QMOPT_RES_REGBLKS|XFS_QMOPT_FORCE_RES)
-
-#define		xfs_trans_unreserve_blkquota(tp, ip, nblks) \
-(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_REGBLKS)
-
-#define		xfs_trans_reserve_quota(tp, udq, gdq, nb, ni, f) \
-xfs_trans_reserve_quota_bydquots(tp, udq, gdq, nb, ni, f|XFS_QMOPT_RES_REGBLKS)
-
-#define		xfs_trans_unreserve_quota(tp, ud, gd, b, i, f) \
-xfs_trans_reserve_quota_bydquots(tp, ud, gd, -(b), -(i), f|XFS_QMOPT_RES_REGBLKS)
-
-/*
- * Realtime disk block quota reservations
- */
-#define		xfs_trans_reserve_rtblkquota(mp, tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_RTBLKS)
-
-#define		xfs_trans_unreserve_rtblkquota(tp, ip, nblks) \
-(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_RTBLKS)
+typedef struct xfs_dqtrx {
+	struct xfs_dquot *qt_dquot;	  /* the dquot this refers to */
+	ulong		qt_blk_res;	  /* blks reserved on a dquot */
+	ulong		qt_blk_res_used;  /* blks used from the reservation */
+	ulong		qt_ino_res;	  /* inode reserved on a dquot */
+	ulong		qt_ino_res_used;  /* inodes used from the reservation */
+	long		qt_bcount_delta;  /* dquot blk count changes */
+	long		qt_delbcnt_delta; /* delayed dquot blk count changes */
+	long		qt_icount_delta;  /* dquot inode count changes */
+	ulong		qt_rtblk_res;	  /* # blks reserved on a dquot */
+	ulong		qt_rtblk_res_used;/* # blks used from reservation */
+	long		qt_rtbcount_delta;/* dquot realtime blk changes */
+	long		qt_delrtb_delta;  /* delayed RT blk count changes */
+} xfs_dqtrx_t;
+
+/*
+ * Dquot transaction functions, used if quota is enabled.
+ */
+typedef void	(*qo_dup_dqinfo_t)(struct xfs_trans *, struct xfs_trans *);
+typedef void	(*qo_mod_dquot_byino_t)(struct xfs_trans *,
+				struct xfs_inode *, uint, long);
+typedef void	(*qo_free_dqinfo_t)(struct xfs_trans *);
+typedef void	(*qo_apply_dquot_deltas_t)(struct xfs_trans *);
+typedef void	(*qo_unreserve_and_mod_dquots_t)(struct xfs_trans *);
+typedef int	(*qo_reserve_quota_nblks_t)(
+				struct xfs_trans *, struct xfs_mount *,
+				struct xfs_inode *, long, long, uint);
+typedef int	(*qo_reserve_quota_bydquots_t)(
+				struct xfs_trans *, struct xfs_mount *,
+				struct xfs_dquot *, struct xfs_dquot *,
+				long, long, uint);
+typedef struct xfs_dqtrxops {
+	qo_dup_dqinfo_t			qo_dup_dqinfo;
+	qo_free_dqinfo_t		qo_free_dqinfo;
+	qo_mod_dquot_byino_t		qo_mod_dquot_byino;
+	qo_apply_dquot_deltas_t		qo_apply_dquot_deltas;
+	qo_reserve_quota_nblks_t	qo_reserve_quota_nblks;
+	qo_reserve_quota_bydquots_t	qo_reserve_quota_bydquots;
+	qo_unreserve_and_mod_dquots_t	qo_unreserve_and_mod_dquots;
+} xfs_dqtrxops_t;
+
+#define XFS_DQTRXOP(mp, tp, op, args...) \
+			((mp)->m_qm_ops.xfs_dqtrxops ? \
+			((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : 0)
+
+#define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \
+	XFS_DQTRXOP(mp, otp, qo_dup_dqinfo, ntp)
+#define XFS_TRANS_FREE_DQINFO(mp, tp) \
+	XFS_DQTRXOP(mp, tp, qo_free_dqinfo)
+#define XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, field, delta) \
+	XFS_DQTRXOP(mp, tp, qo_mod_dquot_byino, ip, field, delta)
+#define XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp) \
+	XFS_DQTRXOP(mp, tp, qo_apply_dquot_deltas)
+#define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, fl) \
+	XFS_DQTRXOP(mp, tp, qo_reserve_quota_nblks, mp, ip, nblks, ninos, fl)
+#define XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, fl) \
+	XFS_DQTRXOP(mp, tp, qo_reserve_quota_bydquots, mp, ud, gd, nb, ni, fl)
+#define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \
+	XFS_DQTRXOP(mp, tp, qo_unreserve_and_mod_dquots)
+
+#define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \
+	XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
+				XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_RESERVE_BLKQUOTA_FORCE(mp, tp, ip, nblks) \
+	XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
+				XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES)
+#define XFS_TRANS_UNRESERVE_BLKQUOTA(mp, tp, ip, nblks) \
+	XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), 0, \
+				XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
+	XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \
+				f | XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_UNRESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
+	XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, -(nb), -(ni), \
+				f | XFS_QMOPT_RES_REGBLKS)
 
-#define		xfs_trans_reserve_rtquota(mp, tp, uq, pq, blks, f) \
-xfs_trans_reserve_quota_bydquots(mp, tp, uq, pq, blks, 0, f|XFS_QMOPT_RES_RTBLKS)
+extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
 
-#define		xfs_trans_unreserve_rtquota(tp, uq, pq, blks) \
-xfs_trans_reserve_quota_bydquots(tp, uq, pq, -(blks), XFS_QMOPT_RES_RTBLKS)
+extern struct bhv_vfsops xfs_qmops;
 
+extern void xfs_qm_init(void);
+extern void xfs_qm_exit(void);
 
 #endif	/* __KERNEL__ */
 
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_quota_priv.h linux-2.5.66-bk3/fs/xfs/xfs_quota_priv.h
--- linux-2.5.66-bk2/fs/xfs/xfs_quota_priv.h	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_quota_priv.h	Wed Dec 31 16:00:00 1969
@@ -1,192 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_QUOTA_PRIV_H__
-#define __XFS_QUOTA_PRIV_H__
-
-/*
- * Number of bmaps that we ask from bmapi when doing a quotacheck.
- * We make this restriction to keep the memory usage to a minimum.
- */
-#define XFS_DQITER_MAP_SIZE	10
-
-/* Number of dquots that fit in to a dquot block */
-#define XFS_QM_DQPERBLK(mp)	((mp)->m_quotainfo->qi_dqperchunk)
-
-#define XFS_ISLOCKED_INODE(ip)		(ismrlocked(&(ip)->i_lock, \
-					    MR_UPDATE | MR_ACCESS) != 0)
-#define XFS_ISLOCKED_INODE_EXCL(ip)	(ismrlocked(&(ip)->i_lock, \
-					    MR_UPDATE) != 0)
-
-#define XFS_DQ_IS_ADDEDTO_TRX(t, d)	((d)->q_transp == (t))
-
-#define XFS_QI_MPLRECLAIMS(mp)	((mp)->m_quotainfo->qi_dqreclaims)
-#define XFS_QI_UQIP(mp)		((mp)->m_quotainfo->qi_uquotaip)
-#define XFS_QI_GQIP(mp)		((mp)->m_quotainfo->qi_gquotaip)
-#define XFS_QI_DQCHUNKLEN(mp)	((mp)->m_quotainfo->qi_dqchunklen)
-#define XFS_QI_BTIMELIMIT(mp)	((mp)->m_quotainfo->qi_btimelimit)
-#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
-#define XFS_QI_ITIMELIMIT(mp)	((mp)->m_quotainfo->qi_itimelimit)
-#define XFS_QI_BWARNLIMIT(mp)	((mp)->m_quotainfo->qi_bwarnlimit)
-#define XFS_QI_IWARNLIMIT(mp)	((mp)->m_quotainfo->qi_iwarnlimit)
-#define XFS_QI_QOFFLOCK(mp)	((mp)->m_quotainfo->qi_quotaofflock)
-
-#define XFS_QI_MPL_LIST(mp)	((mp)->m_quotainfo->qi_dqlist)
-#define XFS_QI_MPLLOCK(mp)	((mp)->m_quotainfo->qi_dqlist.qh_lock)
-#define XFS_QI_MPLNEXT(mp)	((mp)->m_quotainfo->qi_dqlist.qh_next)
-#define XFS_QI_MPLNDQUOTS(mp)	((mp)->m_quotainfo->qi_dqlist.qh_nelems)
-
-#define XQMLCK(h)			(mutex_lock(&((h)->qh_lock), PINOD))
-#define XQMUNLCK(h)			(mutex_unlock(&((h)->qh_lock)))
-#ifdef DEBUG
-static inline int
-XQMISLCKD(xfs_dqhash_t *h)
-{
-	if (mutex_trylock(&h->qh_lock)) {
-		mutex_unlock(&h->qh_lock);
-		return 0;
-	}
-	return 1;
-}
-#endif
-
-#define XFS_DQ_HASH_LOCK(h)		XQMLCK(h)
-#define XFS_DQ_HASH_UNLOCK(h)		XQMUNLCK(h)
-#define XFS_DQ_IS_HASH_LOCKED(h)	XQMISLCKD(h)
-
-#define xfs_qm_mplist_lock(mp)		XQMLCK(&(XFS_QI_MPL_LIST(mp)))
-#define xfs_qm_mplist_unlock(mp)	XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
-#define XFS_QM_IS_MPLIST_LOCKED(mp)	XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
-
-#define xfs_qm_freelist_lock(qm)	XQMLCK(&((qm)->qm_dqfreelist))
-#define xfs_qm_freelist_unlock(qm)	XQMUNLCK(&((qm)->qm_dqfreelist))
-#define XFS_QM_IS_FREELIST_LOCKED(qm)	XQMISLCKD(&((qm)->qm_dqfreelist))
-
-/*
- * Hash into a bucket in the dquot hash table, based on <mp, id>.
- */
-#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-				 (__psunsigned_t)(id)) & \
-				(xfs_Gqm->qm_dqhashmask - 1))
-#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
-				     (xfs_Gqm->qm_usr_dqhtable + \
-				      XFS_DQ_HASHVAL(mp, id)) : \
-				     (xfs_Gqm->qm_grp_dqhtable + \
-				      XFS_DQ_HASHVAL(mp, id)))
-#define XFS_IS_DQTYPE_ON(mp, type)   (type == XFS_DQ_USER ? \
-				      XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
-#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
-	INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \
-	INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT)	      && \
-	INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT)      && \
-	INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT))
-
-#define HL_PREVP	dq_hashlist.ql_prevp
-#define HL_NEXT		dq_hashlist.ql_next
-#define MPL_PREVP	dq_mplist.ql_prevp
-#define MPL_NEXT	dq_mplist.ql_next
-
-
-#define _LIST_REMOVE(h, dqp, PVP, NXT)				\
-	{							\
-		 xfs_dquot_t *d;				\
-		 if (((d) = (dqp)->NXT))				\
-			 (d)->PVP = (dqp)->PVP;			\
-		 *((dqp)->PVP) = d;				\
-		 (dqp)->NXT = NULL;				\
-		 (dqp)->PVP = NULL;				\
-		 (h)->qh_version++;				\
-		 (h)->qh_nelems--;				\
-	}
-
-#define _LIST_INSERT(h, dqp, PVP, NXT)				\
-	{							\
-		 xfs_dquot_t *d;				\
-		 if (((d) = (h)->qh_next))			\
-			 (d)->PVP = &((dqp)->NXT);		\
-		 (dqp)->NXT = d;				\
-		 (dqp)->PVP = &((h)->qh_next);			\
-		 (h)->qh_next = dqp;				\
-		 (h)->qh_version++;				\
-		 (h)->qh_nelems++;				\
-	 }
-
-#define FOREACH_DQUOT_IN_MP(dqp, mp) \
-	for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT)
-
-#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist)	\
-for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
-     (dqp) = (dqp)->dq_flnext)
-
-#define XQM_HASHLIST_INSERT(h, dqp)	\
-	 _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT)
-
-#define XQM_FREELIST_INSERT(h, dqp)	\
-	 xfs_qm_freelist_append(h, dqp)
-
-#define XQM_MPLIST_INSERT(h, dqp)	\
-	 _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT)
-
-#define XQM_HASHLIST_REMOVE(h, dqp)	\
-	 _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT)
-#define XQM_FREELIST_REMOVE(dqp)	\
-	 xfs_qm_freelist_unlink(dqp)
-#define XQM_MPLIST_REMOVE(h, dqp)	\
-	{ _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \
-	  XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; }
-
-#define XFS_DQ_IS_LOGITEM_INITD(dqp)	((dqp)->q_logitem.qli_dquot == (dqp))
-
-#define XFS_QM_DQP_TO_DQACCT(tp, dqp)	(XFS_QM_ISUDQ(dqp) ? \
-					 (tp)->t_dqinfo->dqa_usrdquots : \
-					 (tp)->t_dqinfo->dqa_grpdquots)
-#define XFS_IS_SUSER_DQUOT(dqp)		\
-	(INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT))
-
-#define XFS_PURGE_INODE(ip)		\
-	{				\
-	  vmap_t dqvmap;		\
-	  vnode_t *dqvp;		\
-	  dqvp = XFS_ITOV(ip);		\
-	  VMAP(dqvp, dqvmap);		\
-	  VN_RELE(dqvp);		\
-	}
-
-#define DQFLAGTO_TYPESTR(d)	(((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
-				 (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
-#define DQFLAGTO_DIRTYSTR(d)	(XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
-
-#endif	/* __XFS_QUOTA_PRIV_H__ */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_rename.c linux-2.5.66-bk3/fs/xfs/xfs_rename.c
--- linux-2.5.66-bk2/fs/xfs/xfs_rename.c	Mon Mar 24 14:00:37 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_rename.c	Mon Mar 31 12:48:53 2003
@@ -261,11 +261,12 @@
 
 	src_dp = XFS_BHVTOI(src_dir_bdp);
 	target_dp = XFS_BHVTOI(target_dir_bdp);
+	mp = src_dp->i_mount;
 
 	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) ||
 	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
 				target_dp, DM_EVENT_RENAME)) {
-		error = dm_send_namesp_event(DM_EVENT_RENAME,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
 					src_dir_bdp, DM_RIGHT_NULL,
 					target_dir_bdp, DM_RIGHT_NULL,
 					src_name, target_name,
@@ -323,7 +324,6 @@
 	xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
 
 	XFS_BMAP_INIT(&free_list, &first_block);
-	mp = src_dp->i_mount;
 	tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
 	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
 	spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen);
@@ -343,12 +343,10 @@
 	/*
 	 * Attach the dquots to the inodes
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if ((error = xfs_qm_vop_rename_dqattach(inodes))) {
-			xfs_trans_cancel(tp, cancel_flags);
-			rename_which_error_return = __LINE__;
-			goto rele_return;
-		}
+	if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
+		xfs_trans_cancel(tp, cancel_flags);
+		rename_which_error_return = __LINE__;
+		goto rele_return;
 	}
 
 	/*
@@ -625,7 +623,7 @@
 	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) ||
 	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
 				target_dp, DM_EVENT_POSTRENAME)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTRENAME,
+		(void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
 					src_dir_bdp, DM_RIGHT_NULL,
 					target_dir_bdp, DM_RIGHT_NULL,
 					src_name, target_name,
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_rtalloc.h linux-2.5.66-bk3/fs/xfs/xfs_rtalloc.h
--- linux-2.5.66-bk2/fs/xfs/xfs_rtalloc.h	Mon Mar 24 14:01:11 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_rtalloc.h	Mon Mar 31 12:48:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -35,6 +35,8 @@
 struct xfs_mount;
 struct xfs_trans;
 
+#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
+
 /* Min and max rt extent sizes, specified in bytes */
 #define XFS_MAX_RTEXTSIZE	(1024 * 1024 * 1024)	/* 1GB */
 #define XFS_DFL_RTEXTSIZE	(64 * 1024)		/* 64KB */
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_trans.c linux-2.5.66-bk3/fs/xfs/xfs_trans.c
--- linux-2.5.66-bk2/fs/xfs/xfs_trans.c	Mon Mar 24 14:00:23 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_trans.c	Mon Mar 31 12:48:53 2003
@@ -173,11 +173,7 @@
 	ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
 	tp->t_rtx_res = tp->t_rtx_res_used;
 
-	/*
-	 * dup the dquot stuff too.
-	 */
-	if (tp->t_dqinfo)
-		xfs_trans_dup_dqinfo(tp, ntp);
+	XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
 
 	atomic_inc(&tp->t_mountp->m_active_trans);
 	return ntp;
@@ -703,9 +699,7 @@
 		 * means is that we have some (non-persistent) quota
 		 * reservations that need to be unreserved.
 		 */
-		if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) {
-			xfs_trans_unreserve_and_mod_dquots(tp);
-		}
+		XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
 		if (tp->t_ticket) {
 			commit_lsn = xfs_log_done(mp, tp->t_ticket,
 							NULL, log_flags);
@@ -733,9 +727,7 @@
 	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
 		xfs_trans_apply_sb_deltas(tp);
 	}
-	if (tp->t_flags & XFS_TRANS_DQ_DIRTY) {
-		xfs_trans_apply_dquot_deltas(tp);
-	}
+	XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
 
 	/*
 	 * Ask each log item how many log_vector entries it will
@@ -955,9 +947,7 @@
 	}
 
 	xfs_trans_unreserve_and_mod_sb(tp);
-	if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) {
-		xfs_trans_unreserve_and_mod_dquots(tp);
-	}
+	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
 
 	xfs_trans_free_items(tp, flags);
 	xfs_trans_free_busy(tp);
@@ -1079,9 +1069,7 @@
 	}
 #endif
 	xfs_trans_unreserve_and_mod_sb(tp);
-
-	if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY))
-		xfs_trans_unreserve_and_mod_dquots(tp);
+	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
 
 	if (tp->t_ticket) {
 		if (flags & XFS_TRANS_RELEASE_LOG_RES) {
@@ -1110,8 +1098,7 @@
 	xfs_trans_t	*tp)
 {
 	atomic_dec(&tp->t_mountp->m_active_trans);
-	if (tp->t_dqinfo)
-		xfs_trans_free_dqinfo(tp);
+	XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
 	kmem_zone_free(xfs_trans_zone, tp);
 }
 
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_trans.h linux-2.5.66-bk3/fs/xfs/xfs_trans.h
--- linux-2.5.66-bk2/fs/xfs/xfs_trans.h	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_trans.h	Mon Mar 31 12:48:53 2003
@@ -64,7 +64,6 @@
 #define XFS_LI_BUF		0x123c	/* v2 bufs, variable sized inode bufs */
 #define XFS_LI_DQUOT		0x123d
 #define XFS_LI_QUOTAOFF		0x123e
-#define XFS_LI_RPC		0x123f	/* CXFS RPC return info */
 
 /*
  * Transaction types.  Used to distinguish types of buffers.
@@ -1014,10 +1013,7 @@
 					 struct xfs_efd_log_item *,
 					 xfs_fsblock_t,
 					 xfs_extlen_t);
-void		xfs_trans_log_create_rpc(xfs_trans_t *, int, xfs_ino_t);
-void		xfs_trans_log_setattr_rpc(xfs_trans_t *, int);
 int		xfs_trans_commit(xfs_trans_t *, uint flags, xfs_lsn_t *);
-void		xfs_trans_commit_async(struct xfs_mount *);
 void		xfs_trans_cancel(xfs_trans_t *, int);
 void		xfs_trans_ail_init(struct xfs_mount *);
 xfs_lsn_t	xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t);
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_trans_dquot.c linux-2.5.66-bk3/fs/xfs/xfs_trans_dquot.c
--- linux-2.5.66-bk2/fs/xfs/xfs_trans_dquot.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_trans_dquot.c	Wed Dec 31 16:00:00 1969
@@ -1,852 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.	 Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
- * Add the locked dquot to the transaction.
- * The dquot must be locked, and it cannot be associated with any
- * transaction.
- */
-void
-xfs_trans_dqjoin(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*dqp)
-{
-	xfs_dq_logitem_t    *lp;
-
-	ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp));
-	lp = &dqp->q_logitem;
-
-	/*
-	 * Get a log_item_desc to point at the new item.
-	 */
-	(void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
-
-	/*
-	 * Initialize i_transp so we can later determine if this dquot is
-	 * associated with this transaction.
-	 */
-	dqp->q_transp = tp;
-}
-
-
-/*
- * This is called to mark the dquot as needing
- * to be logged when the transaction is committed.  The dquot must
- * already be associated with the given transaction.
- * Note that it marks the entire transaction as dirty. In the ordinary
- * case, this gets called via xfs_trans_commit, after the transaction
- * is already dirty. However, there's nothing stop this from getting
- * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY
- * flag.
- */
-void
-xfs_trans_log_dquot(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*dqp)
-{
-	xfs_log_item_desc_t	*lidp;
-
-	ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-	lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
-	ASSERT(lidp != NULL);
-
-	tp->t_flags |= XFS_TRANS_DIRTY;
-	lidp->lid_flags |= XFS_LID_DIRTY;
-}
-
-/*
- * Carry forward whatever is left of the quota blk reservation to
- * the spanky new transaction
- */
-void
-xfs_trans_dup_dqinfo(
-	xfs_trans_t	*otp,
-	xfs_trans_t	*ntp)
-{
-	xfs_dqtrx_t	*oq, *nq;
-	int		i,j;
-	xfs_dqtrx_t	*oqa, *nqa;
-
-	xfs_trans_alloc_dqinfo(ntp);
-	oqa = otp->t_dqinfo->dqa_usrdquots;
-	nqa = ntp->t_dqinfo->dqa_usrdquots;
-
-	/*
-	 * Because the quota blk reservation is carried forward,
-	 * it is also necessary to carry forward the DQ_DIRTY flag.
-	 */
-	if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
-		ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
-
-	for (j = 0; j < 2; j++) {
-		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-			if (oqa[i].qt_dquot == NULL)
-				break;
-			oq = &oqa[i];
-			nq = &nqa[i];
-
-			nq->qt_dquot = oq->qt_dquot;
-			nq->qt_bcount_delta = nq->qt_icount_delta = 0;
-			nq->qt_rtbcount_delta = 0;
-
-			/*
-			 * Transfer whatever is left of the reservations.
-			 */
-			nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used;
-			oq->qt_blk_res = oq->qt_blk_res_used;
-
-			nq->qt_rtblk_res = oq->qt_rtblk_res -
-				oq->qt_rtblk_res_used;
-			oq->qt_rtblk_res = oq->qt_rtblk_res_used;
-
-			nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used;
-			oq->qt_ino_res = oq->qt_ino_res_used;
-
-		}
-		oqa = otp->t_dqinfo->dqa_grpdquots;
-		nqa = ntp->t_dqinfo->dqa_grpdquots;
-	}
-}
-
-/*
- * Wrap around mod_dquot to account for both user and group quotas.
- */
-void
-xfs_trans_mod_dquot_byino(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	uint		field,
-	long		delta)
-{
-	ASSERT(tp);
-
-	if (tp->t_dqinfo == NULL)
-		xfs_trans_alloc_dqinfo(tp);
-
-	if (XFS_IS_UQUOTA_ON(tp->t_mountp) && ip->i_udquot) {
-		(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
-	}
-	if (XFS_IS_GQUOTA_ON(tp->t_mountp) && ip->i_gdquot) {
-		(void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
-	}
-}
-
-STATIC xfs_dqtrx_t *
-xfs_trans_get_dqtrx(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*dqp)
-{
-	int		i;
-	xfs_dqtrx_t	*qa;
-
-	for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-		qa = XFS_QM_DQP_TO_DQACCT(tp, dqp);
-
-		if (qa[i].qt_dquot == NULL ||
-		    qa[i].qt_dquot == dqp) {
-			return (&qa[i]);
-		}
-	}
-
-	return (NULL);
-}
-
-/*
- * Make the changes in the transaction structure.
- * The moral equivalent to xfs_trans_mod_sb().
- * We don't touch any fields in the dquot, so we don't care
- * if it's locked or not (most of the time it won't be).
- */
-void
-xfs_trans_mod_dquot(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*dqp,
-	uint		field,
-	long		delta)
-{
-	xfs_dqtrx_t	*qtrx;
-
-	ASSERT(tp);
-	qtrx = NULL;
-
-	if (tp->t_dqinfo == NULL)
-		xfs_trans_alloc_dqinfo(tp);
-	/*
-	 * Find either the first free slot or the slot that belongs
-	 * to this dquot.
-	 */
-	qtrx = xfs_trans_get_dqtrx(tp, dqp);
-	ASSERT(qtrx);
-	if (qtrx->qt_dquot == NULL)
-		qtrx->qt_dquot = dqp;
-
-	switch (field) {
-
-		/*
-		 * regular disk blk reservation
-		 */
-	      case XFS_TRANS_DQ_RES_BLKS:
-		qtrx->qt_blk_res += (ulong)delta;
-		break;
-
-		/*
-		 * inode reservation
-		 */
-	      case XFS_TRANS_DQ_RES_INOS:
-		qtrx->qt_ino_res += (ulong)delta;
-		break;
-
-		/*
-		 * disk blocks used.
-		 */
-	      case XFS_TRANS_DQ_BCOUNT:
-		if (qtrx->qt_blk_res && delta > 0) {
-			qtrx->qt_blk_res_used += (ulong)delta;
-			ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used);
-		}
-		qtrx->qt_bcount_delta += delta;
-		break;
-
-	      case XFS_TRANS_DQ_DELBCOUNT:
-		qtrx->qt_delbcnt_delta += delta;
-		break;
-
-		/*
-		 * Inode Count
-		 */
-	      case XFS_TRANS_DQ_ICOUNT:
-		if (qtrx->qt_ino_res && delta > 0) {
-			qtrx->qt_ino_res_used += (ulong)delta;
-			ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used);
-		}
-		qtrx->qt_icount_delta += delta;
-		break;
-
-		/*
-		 * rtblk reservation
-		 */
-	      case XFS_TRANS_DQ_RES_RTBLKS:
-		qtrx->qt_rtblk_res += (ulong)delta;
-		break;
-
-		/*
-		 * rtblk count
-		 */
-	      case XFS_TRANS_DQ_RTBCOUNT:
-		if (qtrx->qt_rtblk_res && delta > 0) {
-			qtrx->qt_rtblk_res_used += (ulong)delta;
-			ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used);
-		}
-		qtrx->qt_rtbcount_delta += delta;
-		break;
-
-	      case XFS_TRANS_DQ_DELRTBCOUNT:
-		qtrx->qt_delrtb_delta += delta;
-		break;
-
-	      default:
-		ASSERT(0);
-	}
-	tp->t_flags |= XFS_TRANS_DQ_DIRTY;
-}
-
-
-/*
- * Given an array of dqtrx structures, lock all the dquots associated
- * and join them to the transaction, provided they have been modified.
- * We know that the highest number of dquots (of one type - usr OR grp),
- * involved in a transaction is 2 and that both usr and grp combined - 3.
- * So, we don't attempt to make this very generic.
- */
-STATIC void
-xfs_trans_dqlockedjoin(
-	xfs_trans_t	*tp,
-	xfs_dqtrx_t	*q)
-{
-	ASSERT(q[0].qt_dquot != NULL);
-	if (q[1].qt_dquot == NULL) {
-		xfs_dqlock(q[0].qt_dquot);
-		xfs_trans_dqjoin(tp, q[0].qt_dquot);
-	} else {
-		ASSERT(XFS_QM_TRANS_MAXDQS == 2);
-		xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
-		xfs_trans_dqjoin(tp, q[0].qt_dquot);
-		xfs_trans_dqjoin(tp, q[1].qt_dquot);
-	}
-}
-
-
-/*
- * Called by xfs_trans_commit() and similar in spirit to
- * xfs_trans_apply_sb_deltas().
- * Go thru all the dquots belonging to this transaction and modify the
- * INCORE dquot to reflect the actual usages.
- * Unreserve just the reservations done by this transaction
- * dquot is still left locked at exit.
- */
-void
-xfs_trans_apply_dquot_deltas(
-	xfs_trans_t		*tp)
-{
-	int			i, j;
-	xfs_dquot_t		*dqp;
-	xfs_dqtrx_t		*qtrx, *qa;
-	xfs_disk_dquot_t	*d;
-	long			totalbdelta;
-	long			totalrtbdelta;
-
-	ASSERT(tp->t_dqinfo);
-	qa = tp->t_dqinfo->dqa_usrdquots;
-	for (j = 0; j < 2; j++) {
-		if (qa[0].qt_dquot == NULL) {
-			qa = tp->t_dqinfo->dqa_grpdquots;
-			continue;
-		}
-
-		/*
-		 * Lock all of the dquots and join them to the transaction.
-		 */
-		xfs_trans_dqlockedjoin(tp, qa);
-
-		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-			qtrx = &qa[i];
-			/*
-			 * The array of dquots is filled
-			 * sequentially, not sparsely.
-			 */
-			if ((dqp = qtrx->qt_dquot) == NULL)
-				break;
-
-			ASSERT(XFS_DQ_IS_LOCKED(dqp));
-			ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-
-			/*
-			 * adjust the actual number of blocks used
-			 */
-			d = &dqp->q_core;
-
-			/*
-			 * The issue here is - sometimes we don't make a blkquota
-			 * reservation intentionally to be fair to users
-			 * (when the amount is small). On the other hand,
-			 * delayed allocs do make reservations, but that's
-			 * outside of a transaction, so we have no
-			 * idea how much was really reserved.
-			 * So, here we've accumulated delayed allocation blks and
-			 * non-delay blks. The assumption is that the
-			 * delayed ones are always reserved (outside of a
-			 * transaction), and the others may or may not have
-			 * quota reservations.
-			 */
-			totalbdelta = qtrx->qt_bcount_delta +
-				qtrx->qt_delbcnt_delta;
-			totalrtbdelta = qtrx->qt_rtbcount_delta +
-				qtrx->qt_delrtb_delta;
-#ifdef QUOTADEBUG
-			if (totalbdelta < 0)
-				ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
-				       (xfs_qcnt_t) -totalbdelta);
-
-			if (totalrtbdelta < 0)
-				ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
-				       (xfs_qcnt_t) -totalrtbdelta);
-
-			if (qtrx->qt_icount_delta < 0)
-				ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
-				       (xfs_qcnt_t) -qtrx->qt_icount_delta);
-#endif
-			if (totalbdelta)
-				INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
-
-			if (qtrx->qt_icount_delta)
-				INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
-
-			if (totalrtbdelta)
-				INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
-
-			/*
-			 * Start/reset the timer(s) if needed.
-			 */
-			xfs_qm_adjust_dqtimers(tp->t_mountp, d);
-
-			dqp->dq_flags |= XFS_DQ_DIRTY;
-			/*
-			 * add this to the list of items to get logged
-			 */
-			xfs_trans_log_dquot(tp, dqp);
-			/*
-			 * Take off what's left of the original reservation.
-			 * In case of delayed allocations, there's no
-			 * reservation that a transaction structure knows of.
-			 */
-			if (qtrx->qt_blk_res != 0) {
-				if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
-					if (qtrx->qt_blk_res >
-					    qtrx->qt_blk_res_used)
-						dqp->q_res_bcount -= (xfs_qcnt_t)
-							(qtrx->qt_blk_res -
-							 qtrx->qt_blk_res_used);
-					else
-						dqp->q_res_bcount -= (xfs_qcnt_t)
-							(qtrx->qt_blk_res_used -
-							 qtrx->qt_blk_res);
-				}
-			} else {
-				/*
-				 * These blks were never reserved, either inside
-				 * a transaction or outside one (in a delayed
-				 * allocation). Also, this isn't always a
-				 * negative number since we sometimes
-				 * deliberately skip quota reservations.
-				 */
-				if (qtrx->qt_bcount_delta) {
-					dqp->q_res_bcount +=
-					      (xfs_qcnt_t)qtrx->qt_bcount_delta;
-				}
-			}
-			/*
-			 * Adjust the RT reservation.
-			 */
-			if (qtrx->qt_rtblk_res != 0) {
-				if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
-					if (qtrx->qt_rtblk_res >
-					    qtrx->qt_rtblk_res_used)
-					       dqp->q_res_rtbcount -= (xfs_qcnt_t)
-						       (qtrx->qt_rtblk_res -
-							qtrx->qt_rtblk_res_used);
-					else
-					       dqp->q_res_rtbcount -= (xfs_qcnt_t)
-						       (qtrx->qt_rtblk_res_used -
-							qtrx->qt_rtblk_res);
-				}
-			} else {
-				if (qtrx->qt_rtbcount_delta)
-					dqp->q_res_rtbcount +=
-					    (xfs_qcnt_t)qtrx->qt_rtbcount_delta;
-			}
-
-			/*
-			 * Adjust the inode reservation.
-			 */
-			if (qtrx->qt_ino_res != 0) {
-				ASSERT(qtrx->qt_ino_res >=
-				       qtrx->qt_ino_res_used);
-				if (qtrx->qt_ino_res > qtrx->qt_ino_res_used)
-					dqp->q_res_icount -= (xfs_qcnt_t)
-						(qtrx->qt_ino_res -
-						 qtrx->qt_ino_res_used);
-			} else {
-				if (qtrx->qt_icount_delta)
-					dqp->q_res_icount +=
-					    (xfs_qcnt_t)qtrx->qt_icount_delta;
-			}
-
-
-#ifdef QUOTADEBUG
-			if (qtrx->qt_rtblk_res != 0)
-				printk("RT res %d for 0x%p\n",
-				      (int) qtrx->qt_rtblk_res,
-				      dqp);
-#endif
-			ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-			ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-			ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
-		}
-		/*
-		 * Do the group quotas next
-		 */
-		qa = tp->t_dqinfo->dqa_grpdquots;
-	}
-}
-
-/*
- * Release the reservations, and adjust the dquots accordingly.
- * This is called only when the transaction is being aborted. If by
- * any chance we have done dquot modifications incore (ie. deltas) already,
- * we simply throw those away, since that's the expected behavior
- * when a transaction is curtailed without a commit.
- */
-void
-xfs_trans_unreserve_and_mod_dquots(
-	xfs_trans_t	*tp)
-{
-	int			i, j;
-	xfs_dquot_t		*dqp;
-	xfs_dqtrx_t		*qtrx, *qa;
-	boolean_t		locked;
-
-	ASSERT(tp->t_dqinfo);
-	qa = tp->t_dqinfo->dqa_usrdquots;
-
-	for (j = 0; j < 2; j++) {
-		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-			qtrx = &qa[i];
-			/*
-			 * We assume that the array of dquots is filled
-			 * sequentially, not sparsely.
-			 */
-			if ((dqp = qtrx->qt_dquot) == NULL)
-				break;
-			/*
-			 * Unreserve the original reservation. We don't care
-			 * about the number of blocks used field, or deltas.
-			 * Also we don't bother to zero the fields.
-			 */
-			locked = B_FALSE;
-			if (qtrx->qt_blk_res) {
-				xfs_dqlock(dqp);
-				locked = B_TRUE;
-				dqp->q_res_bcount -=
-					(xfs_qcnt_t)qtrx->qt_blk_res;
-			}
-			if (qtrx->qt_ino_res) {
-				if (!locked) {
-					xfs_dqlock(dqp);
-					locked = B_TRUE;
-				}
-				dqp->q_res_icount -=
-					(xfs_qcnt_t)qtrx->qt_ino_res;
-			}
-
-			if (qtrx->qt_rtblk_res) {
-				if (!locked) {
-					xfs_dqlock(dqp);
-					locked = B_TRUE;
-				}
-				dqp->q_res_rtbcount -=
-					(xfs_qcnt_t)qtrx->qt_rtblk_res;
-			}
-			if (locked)
-				xfs_dqunlock(dqp);
-
-		}
-		qa = tp->t_dqinfo->dqa_grpdquots;
-	}
-}
-
-/*
- * This reserves disk blocks and inodes against a dquot.
- * Flags indicate if the dquot is to be locked here and also
- * if the blk reservation is for RT or regular blocks.
- * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
- * Returns EDQUOT if quota is exceeded.
- */
-STATIC int
-xfs_trans_dqresv(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*dqp,
-	long		nblks,
-	long		ninos,
-	uint		flags)
-{
-	int		error;
-	xfs_qcnt_t	hardlimit;
-	xfs_qcnt_t	softlimit;
-	time_t		btimer;
-	xfs_qcnt_t	*resbcountp;
-
-	if (! (flags & XFS_QMOPT_DQLOCK)) {
-		xfs_dqlock(dqp);
-	}
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-	if (flags & XFS_TRANS_DQ_RES_BLKS) {
-		hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
-		softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
-		btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
-		resbcountp = &dqp->q_res_bcount;
-	} else {
-		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
-		hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
-		softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
-		btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
-		resbcountp = &dqp->q_res_rtbcount;
-	}
-	error = 0;
-
-	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
-	    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
-	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
-#ifdef QUOTADEBUG
-		printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n",
-			nblks, *resbcountp, hardlimit);
-#endif
-		if (nblks > 0) {
-			/*
-			 * dquot is locked already. See if we'd go over the
-			 * hardlimit or exceed the timelimit if we allocate
-			 * nblks.
-			 */
-			if (hardlimit > 0ULL &&
-			     (hardlimit <= nblks + *resbcountp)) {
-				error = EDQUOT;
-				goto error_return;
-			}
-
-			if (softlimit > 0ULL &&
-			     (softlimit <= nblks + *resbcountp)) {
-				/*
-				 * If timer or warnings has expired,
-				 * return EDQUOT
-				 */
-				if ((btimer != 0 && get_seconds() > btimer) ||
-				    (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
-				     INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
-				     XFS_QI_BWARNLIMIT(dqp->q_mount))) {
-					error = EDQUOT;
-					goto error_return;
-				}
-			}
-		}
-		if (ninos > 0) {
-			if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL &&
-			    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
-			    INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) {
-				error = EDQUOT;
-				goto error_return;
-			} else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL &&
-				   INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
-				   INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
-				/*
-				 * If timer or warnings has expired,
-				 * return EDQUOT
-				 */
-				if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
-				     get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
-				    (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
-				     INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
-				     XFS_QI_IWARNLIMIT(dqp->q_mount))) {
-					error = EDQUOT;
-					goto error_return;
-				}
-			}
-		}
-	}
-
-	/*
-	 * Change the reservation, but not the actual usage.
-	 * Note that q_res_bcount = q_core.d_bcount + resv
-	 */
-	(*resbcountp) += (xfs_qcnt_t)nblks;
-	if (ninos != 0)
-		dqp->q_res_icount += (xfs_qcnt_t)ninos;
-
-	/*
-	 * note the reservation amt in the trans struct too,
-	 * so that the transaction knows how much was reserved by
-	 * it against this particular dquot.
-	 * We don't do this when we are reserving for a delayed allocation,
-	 * because we don't have the luxury of a transaction envelope then.
-	 */
-	if (tp) {
-		ASSERT(tp->t_dqinfo);
-		ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-		if (nblks != 0)
-			xfs_trans_mod_dquot(tp, dqp,
-					    flags & XFS_QMOPT_RESBLK_MASK,
-					    nblks);
-		if (ninos != 0)
-			xfs_trans_mod_dquot(tp, dqp,
-					    XFS_TRANS_DQ_RES_INOS,
-					    ninos);
-	}
-	ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-	ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
-	ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-
-error_return:
-	if (! (flags & XFS_QMOPT_DQLOCK)) {
-		xfs_dqunlock(dqp);
-	}
-	return (error);
-}
-
-
-/*
- * Given a dquot(s), make disk block and/or inode reservations against them.
- * The fact that this does the reservation against both the usr and
- * grp quotas is important, because this follows a both-or-nothing
- * approach.
- *
- * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
- *	   XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
- *	   XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
- *	   XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
- * dquots are unlocked on return, if they were not locked by caller.
- */
-int
-xfs_trans_reserve_quota_bydquots(
-	xfs_trans_t	*tp,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp,
-	long		nblks,
-	long		ninos,
-	uint		flags)
-{
-	int		resvd;
-
-	if (tp && tp->t_dqinfo == NULL)
-		xfs_trans_alloc_dqinfo(tp);
-
-	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-	resvd = 0;
-
-	if (udqp) {
-		if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags))
-			return (EDQUOT);
-		resvd = 1;
-	}
-
-	if (gdqp) {
-		if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) {
-			/*
-			 * can't do it, so backout previous reservation
-			 */
-			if (resvd) {
-				xfs_trans_dqresv(tp, udqp,  -nblks, -ninos,
-						 flags);
-			}
-			return (EDQUOT);
-		}
-	}
-
-	/*
-	 * Didnt change anything critical, so, no need to log
-	 */
-	return (0);
-}
-
-
-/*
- * Lock the dquot and change the reservation if we can.
- * This doesn't change the actual usage, just the reservation.
- * The inode sent in is locked.
- *
- * Returns 0 on success, EDQUOT or other errors otherwise
- */
-int
-xfs_trans_reserve_quota_nblks(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	long		nblks,
-	long		ninos,
-	uint		type)
-{
-	int error;
-
-#ifdef QUOTADEBUG
-	if (ip->i_udquot)
-		ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
-	if (ip->i_gdquot)
-		ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
-#endif
-
-	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-	ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
-	       (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
-
-	/*
-	 * Reserve nblks against these dquots, with trans as the mediator.
-	 */
-	error = xfs_trans_reserve_quota_bydquots(tp,
-						 ip->i_udquot, ip->i_gdquot,
-						 nblks, ninos,
-						 type);
-	return (error);
-}
-
-/*
- * This routine is called to allocate a quotaoff log item.
- */
-xfs_qoff_logitem_t *
-xfs_trans_get_qoff_item(
-	xfs_trans_t		*tp,
-	xfs_qoff_logitem_t	*startqoff,
-	uint			flags)
-{
-	xfs_qoff_logitem_t	*q;
-
-	ASSERT(tp != NULL);
-
-	q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags);
-	ASSERT(q != NULL);
-
-	/*
-	 * Get a log_item_desc to point at the new item.
-	 */
-	(void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
-
-	return (q);
-}
-
-
-/*
- * This is called to mark the quotaoff logitem as needing
- * to be logged when the transaction is committed.  The logitem must
- * already be associated with the given transaction.
- */
-void
-xfs_trans_log_quotaoff_item(
-	xfs_trans_t		*tp,
-	xfs_qoff_logitem_t	*qlp)
-{
-	xfs_log_item_desc_t	*lidp;
-
-	lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
-	ASSERT(lidp != NULL);
-
-	tp->t_flags |= XFS_TRANS_DIRTY;
-	lidp->lid_flags |= XFS_LID_DIRTY;
-}
-
-void
-xfs_trans_alloc_dqinfo(
-	xfs_trans_t	*tp)
-{
-	(tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
-}
-
-void
-xfs_trans_free_dqinfo(
-	xfs_trans_t	*tp)
-{
-	kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
-	(tp)->t_dqinfo = NULL;
-}
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_utils.c linux-2.5.66-bk3/fs/xfs/xfs_utils.c
--- linux-2.5.66-bk2/fs/xfs/xfs_utils.c	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_utils.c	Mon Mar 31 12:48:53 2003
@@ -232,7 +232,7 @@
 			xfs_buf_relse(ialloc_context);
 			if (dqinfo) {
 				tp->t_dqinfo = dqinfo;
-				xfs_trans_free_dqinfo(tp);
+				XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
 			}
 			*tpp = ntp;
 			*ipp = NULL;
@@ -254,7 +254,7 @@
 			*ipp = NULL;
 			return code;
 		}
-		xfs_trans_bjoin (tp, ialloc_context);
+		xfs_trans_bjoin(tp, ialloc_context);
 
 		/*
 		 * Call ialloc again. Since we've locked out all
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_vfsops.c linux-2.5.66-bk3/fs/xfs/xfs_vfsops.c
--- linux-2.5.66-bk2/fs/xfs/xfs_vfsops.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_vfsops.c	Mon Mar 31 12:48:53 2003
@@ -1,7 +1,7 @@
 /*
  * XFS filesystem operations.
  *
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -68,7 +68,6 @@
 	spinlock_init(&xfs_dabuf_global_lock, "xfsda");
 #endif
 	mutex_init(&xfs_uuidtabmon, MUTEX_DEFAULT, "xfs_uuidtab");
-	mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock");
 
 	/*
 	 * Initialize all of the zone allocators we use.
@@ -175,8 +174,6 @@
 	kmem_cache_destroy(xfs_ifork_zone);
 	kmem_cache_destroy(xfs_ili_zone);
 	kmem_cache_destroy(xfs_chashlist_zone);
-	_XQM_ZONE_DESTROY(qm_dqzone);
-	_XQM_ZONE_DESTROY(qm_dqtrxzone);
 	_ACL_ZONE_DESTROY(xfs_acl_zone);
 #if  (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING))
 	ktrace_uninit();
@@ -248,9 +245,6 @@
 	if (ap->flags & XFSMNT_NOATIME)
 		mp->m_flags |= XFS_MOUNT_NOATIME;
 
-	if (ap->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
-		xfs_qm_mount_quotainit(mp, ap->flags);
-
 	if (ap->flags & XFSMNT_RETERR)
 		mp->m_flags |= XFS_MOUNT_RETERR;
 
@@ -387,11 +381,13 @@
  */
 STATIC int
 xfs_mount(
-	vfs_t			*vfsp,
+	struct bhv_desc		*bhvp,
 	struct xfs_mount_args	*args,
 	cred_t			*credp)
 {
-	xfs_mount_t		*mp;
+	struct vfs		*vfsp = bhvtovfs(bhvp);
+	struct bhv_desc		*p;
+	struct xfs_mount	*mp = XFS_BHVTOM(bhvp);
 	struct block_device	*ddev, *logdev, *rtdev;
 	int			ronly = (vfsp->vfs_flag & VFS_RDONLY);
 	int			flags = 0, error;
@@ -400,23 +396,18 @@
 	logdev = rtdev = NULL;
 
 	/*
-	 * Allocate VFS private data (xfs mount structure).
-	 */
-	mp = xfs_mount_init();
-
-	/*
 	 * Open real time and log devices - order is important.
 	 */
 	if (args->logname[0]) {
 		error = xfs_blkdev_get(mp, args->logname, &logdev);
 		if (error)
-			goto free_mp;
+			return error;
 	}
 	if (args->rtname[0]) {
 		error = xfs_blkdev_get(mp, args->rtname, &rtdev);
 		if (error) {
 			xfs_blkdev_put(logdev);
-			goto free_mp;
+			return error;
 		}
 
 		if (rtdev == ddev || rtdev == logdev) {
@@ -424,33 +415,47 @@
 	"XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
 			xfs_blkdev_put(logdev);
 			xfs_blkdev_put(rtdev);
-			error = EINVAL;
-			goto free_mp;
+			return EINVAL;
 		}
 	}
 
-	vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+	/*
+	 * Setup xfs_mount function vectors from available behaviors
+	 */
+	p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM);
+	mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_xfs;
+	p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM);
+	mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_xfs;
+	p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO);
+	mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs;
 
+	/*
+	 * Setup xfs_mount buffer target pointers
+	 */
 	mp->m_ddev_targp = xfs_alloc_buftarg(ddev);
 	if (rtdev)
 		mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev);
 	mp->m_logdev_targp = (logdev && logdev != ddev) ?
 				xfs_alloc_buftarg(logdev) : mp->m_ddev_targp;
 
+	/*
+	 * Setup flags based on mount(2) options and then the superblock
+	 */
 	error = xfs_start_flags(args, mp, ronly);
 	if (error)
 		goto error;
-
 	error = xfs_readsb(mp);
 	if (error)
 		goto error;
-
 	error = xfs_finish_flags(args, mp, ronly);
 	if (error) {
 		xfs_freesb(mp);
 		goto error;
 	}
 
+	/*
+	 * Setup xfs_mount buffer target pointers based on superblock
+	 */
 	xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,
 			    mp->m_sb.sb_sectsize);
 	if (logdev && logdev != ddev) {
@@ -465,10 +470,8 @@
 		xfs_setsize_buftarg(mp->m_rtdev_targp, mp->m_sb.sb_blocksize,
 				    mp->m_sb.sb_blocksize);
 
-	error = xfs_mountfs(vfsp, mp, ddev->bd_dev, flags);
-	if (error)
-		goto error;
-	return 0;
+	if (!(error = XFS_IOINIT(vfsp, args, flags)))
+		return 0;
 
  error:
 	xfs_binval(mp->m_ddev_targp);
@@ -479,9 +482,6 @@
 		xfs_binval(mp->m_rtdev_targp);
 	}
 	xfs_unmountfs_close(mp, NULL);
-
- free_mp:
-	xfs_mount_free(mp, 1);
 	return error;
 }
 
@@ -523,8 +523,9 @@
 				continue;
 			}
 #ifdef DEBUG
-			printk("busy vp=0x%p ip=0x%p inum %Ld count=%d\n",
-				vp, ip, ip->i_ino, vn_count(vp));
+			cmn_err(CE_WARN, "%s: busy vp=0x%p ip=0x%p "
+					 "inum %Ld count=%d",
+				__FUNCTION__, vp, ip, ip->i_ino, vn_count(vp));
 #endif
 			busy++;
 		}
@@ -543,16 +544,15 @@
 	int		flags,
 	cred_t		*credp)
 {
-	xfs_mount_t	*mp;
-	xfs_inode_t	*rip;
-	vnode_t		*rvp = 0;
 	struct vfs	*vfsp = bhvtovfs(bdp);
+	xfs_mount_t	*mp = XFS_BHVTOM(bdp);
+	xfs_inode_t	*rip;
+	vnode_t		*rvp;
 	int		unmount_event_wanted = 0;
 	int		unmount_event_flags = 0;
 	int		xfs_unmountfs_needed = 0;
 	int		error;
 
-	mp = XFS_BHVTOM(bdp);
 	rip = mp->m_rootip;
 	rvp = XFS_ITOV(rip);
 
@@ -560,7 +560,7 @@
 		bhv_desc_t	*rbdp;
 
 		rbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rvp), &xfs_vnodeops);
-		error = dm_send_namesp_event(DM_EVENT_PREUNMOUNT,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_PREUNMOUNT,
 				rbdp, DM_RIGHT_NULL, rbdp, DM_RIGHT_NULL,
 				NULL, NULL, 0, 0,
 				(mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))?
@@ -577,7 +577,8 @@
 	 */
 	if (xfs_ibusy(mp)) {
 		error = XFS_ERROR(EBUSY);
-		printk("xfs_unmount: xfs_ibusy says error/%d\n", error);
+		cmn_err(CE_ALERT, "%s: xfs_ibusy failed -- error code %d",
+			__FUNCTION__, error);
 		goto out;
 	}
 
@@ -598,7 +599,7 @@
 	 * we want to make sure we invalidate dirty pages that belong to
 	 * referenced vnodes as well.
 	 */
-	if (XFS_FORCED_SHUTDOWN(mp))  {
+	if (XFS_FORCED_SHUTDOWN(mp)) {
 		error = xfs_sync(&mp->m_bhv,
 			 (SYNC_WAIT | SYNC_CLOSE), credp);
 		ASSERT(error != EFSCORRUPTED);
@@ -612,9 +613,9 @@
 	 */
 	if (unmount_event_wanted) {
 		/* Note: mp structure must still exist for
-		 * dm_send_unmount_event() call.
+		 * XFS_SEND_UNMOUNT() call.
 		 */
-		dm_send_unmount_event(vfsp, error == 0 ? rvp : NULL,
+		XFS_SEND_UNMOUNT(mp, vfsp, error == 0 ? rvp : NULL,
 			DM_RIGHT_NULL, 0, error, unmount_event_flags);
 	}
 	if (xfs_unmountfs_needed) {
@@ -641,7 +642,7 @@
 {
 	xfs_inode_t	*rip = mp->m_rootip;
 	xfs_inode_t	*rbmip;
-	xfs_inode_t	*rsumip=NULL;
+	xfs_inode_t	*rsumip = NULL;
 	vnode_t		*rvp = XFS_ITOV(rip);
 	int		error;
 
@@ -675,23 +676,22 @@
 	}
 
 	/*
-	 * synchronously flush root inode to disk
+	 * Synchronously flush root inode to disk
 	 */
 	error = xfs_iflush(rip, XFS_IFLUSH_SYNC);
-
 	if (error == EFSCORRUPTED)
 		goto fscorrupt_out2;
 
 	if (vn_count(rvp) != 1 && !relocation) {
 		xfs_iunlock(rip, XFS_ILOCK_EXCL);
-		error = XFS_ERROR(EBUSY);
-		return (error);
+		return XFS_ERROR(EBUSY);
 	}
+
 	/*
 	 * Release dquot that rootinode, rbmino and rsumino might be holding,
 	 * flush and purge the quota inodes.
 	 */
-	error = xfs_qm_unmount_quotas(mp);
+	error = XFS_QM_UNMOUNT(mp);
 	if (error == EFSCORRUPTED)
 		goto fscorrupt_out2;
 
@@ -701,7 +701,7 @@
 	}
 
 	xfs_iunlock(rip, XFS_ILOCK_EXCL);
-	return (0);
+	return 0;
 
 fscorrupt_out:
 	xfs_ifunlock(rip);
@@ -709,8 +709,7 @@
 fscorrupt_out2:
 	xfs_iunlock(rip, XFS_ILOCK_EXCL);
 
-	error = XFS_ERROR(EFSCORRUPTED);
-	return (error);
+	return XFS_ERROR(EFSCORRUPTED);
 }
 
 /*
@@ -725,12 +724,11 @@
 	bhv_desc_t	*bdp,
 	vnode_t		**vpp)
 {
-	vnode_t *vp;
+	vnode_t		*vp;
 
 	vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip);
 	VN_HOLD(vp);
 	*vpp = vp;
-
 	return 0;
 }
 
@@ -1411,23 +1409,6 @@
 	ASSERT(ipointer_in == B_FALSE);
 
 	/*
-	 * Get the Quota Manager to flush the dquots in a similar manner.
-	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if ((error = xfs_qm_sync(mp, flags))) {
-			/*
-			 * If we got an IO error, we will be shutting down.
-			 * So, there's nothing more for us to do here.
-			 */
-			ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
-			if (XFS_FORCED_SHUTDOWN(mp)) {
-				kmem_free(ipointer, sizeof(xfs_iptr_t));
-				return XFS_ERROR(error);
-			}
-		}
-	}
-
-	/*
 	 * Flushing out dirty data above probably generated more
 	 * log activity, so if this isn't vfs_sync() then flush
 	 * the log again.  If SYNC_WAIT is set then do it synchronously.
@@ -1581,16 +1562,17 @@
 
 
 vfsops_t xfs_vfsops = {
+	BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS),
+	.vfs_parseargs		= xfs_parseargs,
+	.vfs_showargs		= xfs_showargs,
 	.vfs_mount		= xfs_mount,
 	.vfs_unmount		= xfs_unmount,
 	.vfs_root		= xfs_root,
 	.vfs_statvfs		= xfs_statvfs,
 	.vfs_sync		= xfs_sync,
 	.vfs_vget		= xfs_vget,
+	.vfs_dmapiops		= (vfs_dmapiops_t)fs_nosys,
+	.vfs_quotactl		= (vfs_quotactl_t)fs_nosys,
 	.vfs_init_vnode		= xfs_initialize_vnode,
 	.vfs_force_shutdown	= xfs_do_force_shutdown,
-#ifdef CONFIG_XFS_DMAPI
-	.vfs_dmapi_mount	= xfs_dm_mount,
-	.vfs_dmapi_fsys_vector	= xfs_dm_get_fsys_vector,
-#endif
 };
diff -urN linux-2.5.66-bk2/fs/xfs/xfs_vnodeops.c linux-2.5.66-bk3/fs/xfs/xfs_vnodeops.c
--- linux-2.5.66-bk2/fs/xfs/xfs_vnodeops.c	Mon Mar 24 14:01:53 2003
+++ linux-2.5.66-bk3/fs/xfs/xfs_vnodeops.c	Mon Mar 31 12:48:53 2003
@@ -254,28 +254,26 @@
  */
 STATIC int
 xfs_setattr(
-	bhv_desc_t	*bdp,
-	vattr_t		*vap,
-	int		flags,
-	cred_t		*credp)
+	bhv_desc_t		*bdp,
+	vattr_t			*vap,
+	int			flags,
+	cred_t			*credp)
 {
-	xfs_inode_t	*ip;
-	xfs_trans_t	*tp;
-	xfs_mount_t	*mp;
-	int		mask;
-	int		code;
-	uint		lock_flags;
-	uint		commit_flags=0;
-	uid_t		uid=0, iuid=0;
-	gid_t		gid=0, igid=0;
-	int		timeflags = 0;
-	vnode_t		*vp;
-	xfs_prid_t	projid=0, iprojid=0;
-	int		privileged;
-	int		mandlock_before, mandlock_after;
-	uint		qflags;
-	xfs_dquot_t	*udqp, *gdqp, *olddquot1, *olddquot2;
-	int		file_owner;
+	xfs_inode_t		*ip;
+	xfs_trans_t		*tp;
+	xfs_mount_t		*mp;
+	int			mask;
+	int			code;
+	uint			lock_flags;
+	uint			commit_flags=0;
+	uid_t			uid=0, iuid=0;
+	gid_t			gid=0, igid=0;
+	int			timeflags = 0;
+	vnode_t			*vp;
+	xfs_prid_t		projid=0, iprojid=0;
+	int			mandlock_before, mandlock_after;
+	struct xfs_dquot	*udqp, *gdqp, *olddquot1, *olddquot2;
+	int			file_owner;
 
 	vp = BHV_TO_VNODE(bdp);
 	vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -319,7 +317,8 @@
 	 * because the i_*dquot fields will get updated anyway.
 	 */
 	if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
-		qflags = 0;
+		uint	qflags = 0;
+
 		if (mask & XFS_AT_UID) {
 			uid = vap->va_uid;
 			qflags |= XFS_QMOPT_UQUOTA;
@@ -339,8 +338,8 @@
 		 */
 		ASSERT(udqp == NULL);
 		ASSERT(gdqp == NULL);
-		if ((code = xfs_qm_vop_dqalloc(mp, ip, uid, gid, qflags,
-						    &udqp, &gdqp)))
+		code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp);
+		if (code)
 			return (code);
 	}
 
@@ -365,7 +364,7 @@
 	} else {
 		if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) &&
 		    !(flags & ATTR_DMI)) {
-			code = xfs_dm_send_data_event (DM_EVENT_TRUNCATE, bdp,
+			code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, bdp,
 				vap->va_size, 0, AT_DELAY_FLAG(flags), NULL);
 			if (code) {
 				lock_flags = 0;
@@ -482,15 +481,10 @@
 		if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
 		    (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
 			ASSERT(tp);
-			/*
-			 * XXX:casey - This may result in unnecessary auditing.
-			 */
-			privileged = capable(CAP_FOWNER);
-			if ((code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-							  privileged ?
-							  XFS_QMOPT_FORCE_RES :
-							  0)))
-				/* out of quota */
+			code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+						capable(CAP_FOWNER) ?
+						XFS_QMOPT_FORCE_RES : 0);
+			if (code)	/* out of quota */
 				goto error_return;
 		}
 	}
@@ -520,10 +514,8 @@
 		/*
 		 * Make sure that the dquots are attached to the inode.
 		 */
-		if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-			if ((code = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED)))
-				goto error_return;
-		}
+		if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED)))
+			goto error_return;
 	}
 
 	/*
@@ -730,13 +722,8 @@
 			if (XFS_IS_UQUOTA_ON(mp)) {
 				ASSERT(mask & XFS_AT_UID);
 				ASSERT(udqp);
-				ASSERT(xfs_qm_dqid(udqp) == (xfs_dqid_t)uid);
-				olddquot1 = xfs_qm_vop_chown(tp, ip,
-							     &ip->i_udquot,
-							     udqp);
-				/*
-				 * We'll dqrele olddquot at the end.
-				 */
+				olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+							&ip->i_udquot, udqp);
 			}
 			ip->i_d.di_uid = uid;
 		}
@@ -744,10 +731,8 @@
 			if (XFS_IS_GQUOTA_ON(mp)) {
 				ASSERT(mask & XFS_AT_GID);
 				ASSERT(gdqp);
-				ASSERT(xfs_qm_dqid(gdqp) == gid);
-				olddquot2 = xfs_qm_vop_chown(tp, ip,
-							     &ip->i_gdquot,
-							     gdqp);
+				olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+							&ip->i_gdquot, gdqp);
 			}
 			ip->i_d.di_gid = gid;
 		}
@@ -802,9 +787,6 @@
 			ip->i_d.di_flags = 0;
 			if (vap->va_xflags & XFS_XFLAG_REALTIME) {
 				ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
-				/* This is replicated in the io core for
-				 * CXFS use
-				 */
 				ip->i_iocore.io_flags |= XFS_IOCORE_RT;
 			}
 			/* can't set PREALLOC this way, just ignore it */
@@ -866,16 +848,12 @@
 	xfs_iunlock(ip, lock_flags);
 
 	/*
-	 * release any dquot(s) inode had kept before chown
+	 * Release any dquot(s) the inode had kept before chown.
 	 */
-	if (olddquot1)
-		xfs_qm_dqrele(olddquot1);
-	if (olddquot2)
-		xfs_qm_dqrele(olddquot2);
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, olddquot1);
+	XFS_QM_DQRELE(mp, olddquot2);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	if (code) {
 		return code;
@@ -883,9 +861,9 @@
 
 	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_ATTRIBUTE) &&
 	    !(flags & ATTR_DMI)) {
-		(void) dm_send_namesp_event (DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL,
-				NULL, DM_RIGHT_NULL, NULL, NULL,
-			0, 0, AT_DELAY_FLAG(flags));
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL,
+					NULL, DM_RIGHT_NULL, NULL, NULL,
+					0, 0, AT_DELAY_FLAG(flags));
 	}
 	return 0;
 
@@ -893,10 +871,8 @@
 	commit_flags |= XFS_TRANS_ABORT;
 	/* FALLTHROUGH */
  error_return:
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 	if (tp) {
 		xfs_trans_cancel(tp, commit_flags);
 	}
@@ -1286,14 +1262,8 @@
 		/*
 		 * Attach the dquots to the inode up front.
 		 */
-		if (XFS_IS_QUOTA_ON(mp) &&
-		    ip->i_ino != mp->m_sb.sb_uquotino &&
-		    ip->i_ino != mp->m_sb.sb_gquotino) {
-			if (XFS_NOT_DQATTACHED(mp, ip)) {
-				if ((error = xfs_qm_dqattach(ip, 0)))
-					return (error);
-			}
-		}
+		if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+			return (error);
 
 		/*
 		 * There are blocks after the end of file.
@@ -1683,7 +1653,7 @@
 
 	if (ip->i_d.di_nlink == 0 &&
 	    DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) {
-		(void) dm_send_destroy_event(bdp, DM_RIGHT_NULL);
+		(void) XFS_SEND_DESTROY(mp, bdp, DM_RIGHT_NULL);
 	}
 
 	error = 0;
@@ -1709,14 +1679,9 @@
 
 	ASSERT(ip->i_d.di_nlink == 0);
 
-	if (XFS_IS_QUOTA_ON(mp) &&
-	    ip->i_ino != mp->m_sb.sb_uquotino &&
-	    ip->i_ino != mp->m_sb.sb_gquotino) {
-		if (XFS_NOT_DQATTACHED(mp, ip)) {
-			if ((error = xfs_qm_dqattach(ip, 0)))
-				return (VN_INACTIVE_CACHE);
-		}
-	}
+	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+		return (VN_INACTIVE_CACHE);
+
 	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 	if (truncate) {
 		/*
@@ -1826,20 +1791,18 @@
 		 * might do that, we need to make sure.	 Otherwise the
 		 * inode might be lost for a long time or forever.
 		 */
-		if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) {
+		if (!XFS_FORCED_SHUTDOWN(mp)) {
 			cmn_err(CE_NOTE,
-				"xfs_inactive:	xfs_ifree() returned an error = %d on %s",
-				error,tp->t_mountp->m_fsname);
-			xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR);
+		"xfs_inactive:	xfs_ifree() returned an error = %d on %s",
+				error, mp->m_fsname);
+			xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
 		}
 		xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT);
 	} else {
 		/*
 		 * Credit the quota account(s). The inode is gone.
 		 */
-		if (XFS_IS_QUOTA_ON(tp->t_mountp))
-			xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT,
-							 -1);
+		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
 		/*
 		 * Just ignore errors at this point.  There is
@@ -1850,8 +1813,7 @@
 	/*
 	 * Release the dquots held by inode, if any.
 	 */
-	if (ip->i_udquot || ip->i_gdquot)
-		xfs_qm_dqdettach_inode(ip);
+	XFS_QM_DQDETACH(mp, ip);
 
 	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 
@@ -1925,7 +1887,7 @@
 	uint			cancel_flags;
 	int			committed;
 	xfs_prid_t		prid;
-	xfs_dquot_t		*udqp, *gdqp;
+	struct xfs_dquot	*udqp, *gdqp;
 	uint			resblks;
 	int			dm_di_mode;
 	int			namelen;
@@ -1935,22 +1897,22 @@
 	vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
 
 	dp = XFS_BHVTOI(dir_bdp);
+	mp = dp->i_mount;
 
 	dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
 	namelen = VNAMELEN(dentry);
 
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
-		error = dm_send_namesp_event(DM_EVENT_CREATE,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
 				dir_bdp, DM_RIGHT_NULL, NULL,
 				DM_RIGHT_NULL, name, NULL,
 				dm_di_mode, 0, 0);
+
 		if (error)
 			return error;
 		dm_event_sent = 1;
 	}
 
-	mp = dp->i_mount;
-
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
@@ -1965,14 +1927,10 @@
 	/*
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		error = xfs_qm_vop_dqalloc(mp, dp,
-					   current->fsuid, current->fsgid,
-					   XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-					   &udqp, &gdqp);
-		if (error)
-			goto std_return;
-	}
+	error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+			XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
+	if (error)
+		goto std_return;
 
 	ip = NULL;
 	dp_joined_to_trans = B_FALSE;
@@ -2008,13 +1966,10 @@
 	/*
 	 * Reserve disk quota and the inode.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks,
-					    1, 0)) {
-			error = EDQUOT;
-			goto error_return;
-		}
-	}
+	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+	if (error)
+		goto error_return;
+
 	if (resblks == 0 &&
 	    (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
 		goto error_return;
@@ -2074,9 +2029,7 @@
 	 * These ids of the inode couldn't have changed since the new
 	 * inode has been locked ever since it was created.
 	 */
-	if (XFS_IS_QUOTA_ON(mp))
-		xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp,
-						       gdqp);
+	XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
 
 	/*
 	 * xfs_trans_commit normally decrements the vnode ref count
@@ -2099,10 +2052,8 @@
 		goto error_return;
 	}
 
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	/*
 	 * Propogate the fact that the vnode changed after the
@@ -2118,7 +2069,7 @@
 	if ( (*vpp || (error != 0 && dm_event_sent != 0)) &&
 			DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
 							DM_EVENT_POSTCREATE)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTCREATE,
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
 			dir_bdp, DM_RIGHT_NULL,
 			*vpp ? vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops):NULL,
 			DM_RIGHT_NULL, name, NULL,
@@ -2136,10 +2087,8 @@
 
 	if (!dp_joined_to_trans && (dp != NULL))
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	goto std_return;
 
@@ -2153,10 +2102,8 @@
 	xfs_trans_cancel(tp, cancel_flags);
 	IRELE(ip);
 
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	goto std_return;
 }
@@ -2437,8 +2384,8 @@
 	namelen = VNAMELEN(dentry);
 
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
-		error = dm_send_namesp_event(DM_EVENT_REMOVE, dir_bdp, DM_RIGHT_NULL,
-					NULL, DM_RIGHT_NULL,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_bdp,
+					DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
 					name, NULL, 0, 0, 0);
 		if (error)
 			return error;
@@ -2471,17 +2418,13 @@
 
 	ITRACE(ip);
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		ASSERT(! error);
-		if (XFS_NOT_DQATTACHED(mp, dp))
-			error = xfs_qm_dqattach(dp, 0);
-		if (!error && dp != ip && XFS_NOT_DQATTACHED(mp, ip))
-			error = xfs_qm_dqattach(ip, 0);
-		if (error) {
-			REMOVE_DEBUG_TRACE(__LINE__);
-			IRELE(ip);
-			goto std_return;
-		}
+	error = XFS_QM_DQATTACH(mp, dp, 0);
+	if (!error && dp != ip)
+		error = XFS_QM_DQATTACH(mp, ip, 0);
+	if (error) {
+		REMOVE_DEBUG_TRACE(__LINE__);
+		IRELE(ip);
+		goto std_return;
 	}
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
@@ -2606,7 +2549,7 @@
  std_return:
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp,
 						DM_EVENT_POSTREMOVE)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTREMOVE,
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
 				dir_bdp, DM_RIGHT_NULL,
 				NULL, DM_RIGHT_NULL,
 				name, NULL, dm_di_mode, error, 0);
@@ -2690,7 +2633,7 @@
 		return XFS_ERROR(EIO);
 
 	if (DM_EVENT_ENABLED(src_vp->v_vfsp, tdp, DM_EVENT_LINK)) {
-		error = dm_send_namesp_event(DM_EVENT_LINK,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
 					target_dir_bdp, DM_RIGHT_NULL,
 					src_bdp, DM_RIGHT_NULL,
 					target_name, NULL, 0, 0, 0);
@@ -2700,15 +2643,11 @@
 
 	/* Return through std_return after this point. */
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		error = 0;
-		if (XFS_NOT_DQATTACHED(mp, sip))
-			error = xfs_qm_dqattach(sip, 0);
-		if (!error && sip != tdp && XFS_NOT_DQATTACHED(mp, tdp))
-			error = xfs_qm_dqattach(tdp, 0);
-		if (error)
-			goto std_return;
-	}
+	error = XFS_QM_DQATTACH(mp, sip, 0);
+	if (!error && sip != tdp)
+		error = XFS_QM_DQATTACH(mp, tdp, 0);
+	if (error)
+		goto std_return;
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
 	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -2798,7 +2737,7 @@
 std_return:
 	if (DM_EVENT_ENABLED(src_vp->v_vfsp, sip,
 						DM_EVENT_POSTLINK)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTLINK,
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
 				target_dir_bdp, DM_RIGHT_NULL,
 				src_bdp, DM_RIGHT_NULL,
 				target_name, NULL, 0, error, 0);
@@ -2813,8 +2752,6 @@
 
 	goto std_return;
 }
-
-
 /*
  * xfs_mkdir
  *
@@ -2844,7 +2781,7 @@
 	boolean_t		created = B_FALSE;
 	int			dm_event_sent = 0;
 	xfs_prid_t		prid;
-	xfs_dquot_t		*udqp, *gdqp;
+	struct xfs_dquot	*udqp, *gdqp;
 	uint			resblks;
 	int			dm_di_mode;
 	int			dir_namelen;
@@ -2863,7 +2800,7 @@
 	dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
 
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
-		error = dm_send_namesp_event(DM_EVENT_CREATE,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
 					dir_bdp, DM_RIGHT_NULL, NULL,
 					DM_RIGHT_NULL, dir_name, NULL,
 					dm_di_mode, 0, 0);
@@ -2886,14 +2823,10 @@
 	/*
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		error = xfs_qm_vop_dqalloc(mp, dp,
-					   current->fsuid, current->fsgid,
-					   XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-					   &udqp, &gdqp);
-		if (error)
-			goto std_return;
-	}
+	error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+	if (error)
+		goto std_return;
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
 	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -2925,12 +2858,9 @@
 	/*
 	 * Reserve disk quota and the inode.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) {
-			error = XFS_ERROR(EDQUOT);
-			goto error_return;
-		}
-	}
+	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+	if (error)
+		goto error_return;
 
 	if (resblks == 0 &&
 	    (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen)))
@@ -2999,9 +2929,7 @@
 	/*
 	 * Attach the dquots to the new inode and modify the icount incore.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		xfs_qm_vop_dqattach_and_dqmod_newinode(tp, cdp, udqp, gdqp);
-	}
+	XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp);
 
 	/*
 	 * If this is a synchronous mount, make sure that the
@@ -3019,11 +2947,8 @@
 	}
 
 	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-	if (udqp)
-		 xfs_qm_dqrele(udqp);
-	if (gdqp)
-		 xfs_qm_dqrele(gdqp);
-
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 	if (error) {
 		IRELE(cdp);
 	}
@@ -3035,7 +2960,7 @@
 	if ( (created || (error != 0 && dm_event_sent != 0)) &&
 			DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
 						DM_EVENT_POSTCREATE)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTCREATE,
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
 					dir_bdp, DM_RIGHT_NULL,
 					created ? XFS_ITOBHV(cdp):NULL,
 					DM_RIGHT_NULL,
@@ -3051,11 +2976,8 @@
 	cancel_flags |= XFS_TRANS_ABORT;
  error_return:
 	xfs_trans_cancel(tp, cancel_flags);
-
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	if (!dp_joined_to_trans && (dp != NULL)) {
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -3093,6 +3015,7 @@
 
 	dir_vp = BHV_TO_VNODE(dir_bdp);
 	dp = XFS_BHVTOI(dir_bdp);
+	mp = dp->i_mount;
 
 	vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
 
@@ -3101,7 +3024,7 @@
 	namelen = VNAMELEN(dentry);
 
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
-		error = dm_send_namesp_event(DM_EVENT_REMOVE,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
 					dir_bdp, DM_RIGHT_NULL,
 					NULL, DM_RIGHT_NULL,
 					name, NULL, 0, 0, 0);
@@ -3136,17 +3059,13 @@
 	/*
 	 * Get the dquots for the inodes.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		ASSERT(! error);
-		if (XFS_NOT_DQATTACHED(mp, dp))
-			error = xfs_qm_dqattach(dp, 0);
-		if (!error && dp != cdp && XFS_NOT_DQATTACHED(mp, cdp))
-			error = xfs_qm_dqattach(cdp, 0);
-		if (error) {
-			IRELE(cdp);
-			REMOVE_DEBUG_TRACE(__LINE__);
-			goto std_return;
-		}
+	error = XFS_QM_DQATTACH(mp, dp, 0);
+	if (!error && dp != cdp)
+		error = XFS_QM_DQATTACH(mp, cdp, 0);
+	if (error) {
+		IRELE(cdp);
+		REMOVE_DEBUG_TRACE(__LINE__);
+		goto std_return;
 	}
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
@@ -3298,9 +3217,8 @@
 	/* Fall through to std_return with error = 0 or the errno
 	 * from xfs_trans_commit. */
 std_return:
-	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp,
-						DM_EVENT_POSTREMOVE)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTREMOVE,
+	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_POSTREMOVE)) {
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
 					dir_bdp, DM_RIGHT_NULL,
 					NULL, DM_RIGHT_NULL,
 					name, NULL, dm_di_mode,
@@ -3391,7 +3309,7 @@
 	int			n;
 	xfs_buf_t		*bp;
 	xfs_prid_t		prid;
-	xfs_dquot_t		*udqp, *gdqp;
+	struct xfs_dquot	*udqp, *gdqp;
 	uint			resblks;
 	char			*link_name = VNAME(dentry);
 	int			link_namelen;
@@ -3446,10 +3364,9 @@
 	}
 
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_SYMLINK)) {
-		error = dm_send_namesp_event(DM_EVENT_SYMLINK, dir_bdp, DM_RIGHT_NULL,
-						NULL, DM_RIGHT_NULL,
-						link_name, target_path,
-						0, 0, 0);
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dir_bdp,
+					DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
+					link_name, target_path, 0, 0, 0);
 		if (error)
 			return error;
 	}
@@ -3465,14 +3382,10 @@
 	/*
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		error = xfs_qm_vop_dqalloc(mp, dp,
-					   current->fsuid, current->fsgid,
-					   XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-					   &udqp, &gdqp);
-		if (error)
-			goto std_return;
-	}
+	error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+	if (error)
+		goto std_return;
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
 	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -3503,12 +3416,9 @@
 	/*
 	 * Reserve disk quota : blocks and inode.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) {
-			error = XFS_ERROR(EDQUOT);
-			goto error_return;
-		}
-	}
+	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+	if (error)
+		goto error_return;
 
 	/*
 	 * Check for ability to enter directory entry, if no space reserved.
@@ -3543,9 +3453,7 @@
 	/*
 	 * Also attach the dquot(s) to it, if applicable.
 	 */
-	if (XFS_IS_QUOTA_ON(mp)) {
-		xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, gdqp);
-	}
+	XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
 
 	if (resblks)
 		resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -3641,22 +3549,19 @@
 		goto error2;
 	}
 	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	/* Fall through to std_return with error = 0 or errno from
 	 * xfs_trans_commit	*/
 std_return:
 	if (DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
 			     DM_EVENT_POSTSYMLINK)) {
-		(void) dm_send_namesp_event(DM_EVENT_POSTSYMLINK,
-						dir_bdp, DM_RIGHT_NULL,
-						error? NULL:XFS_ITOBHV(ip),
-						DM_RIGHT_NULL,
-						link_name, target_path,
-						0, error, 0);
+		(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK,
+					dir_bdp, DM_RIGHT_NULL,
+					error ? NULL : XFS_ITOBHV(ip),
+					DM_RIGHT_NULL, link_name, target_path,
+					0, error, 0);
 	}
 
 	if (!error) {
@@ -3675,10 +3580,8 @@
 	cancel_flags |= XFS_TRANS_ABORT;
  error_return:
 	xfs_trans_cancel(tp, cancel_flags);
-	if (udqp)
-		xfs_qm_dqrele(udqp);
-	if (gdqp)
-		xfs_qm_dqrele(gdqp);
+	XFS_QM_DQRELE(mp, udqp);
+	XFS_QM_DQRELE(mp, gdqp);
 
 	if (!dp_joined_to_trans && (dp != NULL)) {
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -4165,7 +4068,7 @@
 	/*
 	 * determine if this is a realtime file
 	 */
-	if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) {
+	if ((rt = XFS_IS_REALTIME_INODE(ip)) != 0) {
 		if (ip->i_d.di_extsize)
 			rtextsize = ip->i_d.di_extsize;
 		else
@@ -4173,12 +4076,8 @@
 	} else
 		rtextsize = 0;
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (XFS_NOT_DQATTACHED(mp, ip)) {
-			if ((error = xfs_qm_dqattach(ip, 0)))
-				return error;
-		}
-	}
+	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+		return error;
 
 	if (len <= 0)
 		return XFS_ERROR(EINVAL);
@@ -4200,7 +4099,7 @@
 		end_dmi_offset = offset+len;
 		if (end_dmi_offset > ip->i_d.di_size)
 			end_dmi_offset = ip->i_d.di_size;
-		error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip),
+		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
 			offset, end_dmi_offset - offset,
 			0, NULL);
 		if (error)
@@ -4255,15 +4154,11 @@
 			break;
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		if (XFS_IS_QUOTA_ON(mp)) {
-			if (xfs_trans_reserve_quota(tp,
-						    ip->i_udquot,
-						    ip->i_gdquot,
-						    resblks, 0, 0)) {
-				error = XFS_ERROR(EDQUOT);
-				goto error1;
-			}
-		}
+		error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp,
+				ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
+				XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+		if (error)
+			goto error1;
 
 		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
@@ -4308,13 +4203,13 @@
 	if (error == ENOSPC && (attr_flags&ATTR_DMI) == 0 &&
 	    DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_NOSPACE)) {
 
-		error = dm_send_namesp_event(DM_EVENT_NOSPACE,
+		error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE,
 				XFS_ITOBHV(ip), DM_RIGHT_NULL,
 				XFS_ITOBHV(ip), DM_RIGHT_NULL,
 				NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */
 		if (error == 0)
 			goto retry;	/* Maybe DMAPI app. has made space */
-		/* else fall through with error from xfs_dm_send_data_event */
+		/* else fall through with error from XFS_SEND_DATA */
 	}
 
 	return error;
@@ -4434,38 +4329,32 @@
 	int			nimap;
 	uint			resblks;
 	int			rounding;
-	int			specrt;
+	int			rt;
 	xfs_fileoff_t		startoffset_fsb;
 	xfs_trans_t		*tp;
 
 	vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
 	mp = ip->i_mount;
 
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (XFS_NOT_DQATTACHED(mp, ip)) {
-			if ((error = xfs_qm_dqattach(ip, 0)))
-				return error;
-		}
-	}
+	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+		return error;
 
 	error = 0;
 	if (len <= 0)	/* if nothing being freed */
 		return error;
-	specrt =
-		(ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
-		!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb);
+	rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME);
 	startoffset_fsb = XFS_B_TO_FSB(mp, offset);
 	end_dmi_offset = offset + len;
 	endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
 
 	if (offset < ip->i_d.di_size &&
-	    (attr_flags&ATTR_DMI) == 0	&&
+	    (attr_flags & ATTR_DMI) == 0 &&
 	    DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
 		if (end_dmi_offset > ip->i_d.di_size)
 			end_dmi_offset = ip->i_d.di_size;
-		error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip),
-			offset, end_dmi_offset - offset,
-			AT_DELAY_FLAG(attr_flags), NULL);
+		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
+				offset, end_dmi_offset - offset,
+				AT_DELAY_FLAG(attr_flags), NULL);
 		if (error)
 			return(error);
 	}
@@ -4480,11 +4369,11 @@
 	xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0);
 	/*
 	 * Need to zero the stuff we're not freeing, on disk.
-	 * If its specrt (realtime & can't use unwritten extents) then
-	 * we actually need to zero the extent edges.  Otherwise xfs_bunmapi
+	 * If its a realtime file & can't use unwritten extents then we
+	 * actually need to zero the extent edges.  Otherwise xfs_bunmapi
 	 * will take care of it for us.
 	 */
-	if (specrt) {
+	if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
 		nimap = 1;
 		error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0,
 			&imap, &nimap, NULL);
@@ -4561,15 +4450,11 @@
 			break;
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		if (XFS_IS_QUOTA_ON(mp)) {
-			if (xfs_trans_reserve_quota(tp,
-						    ip->i_udquot,
-						    ip->i_gdquot,
-						    resblks, 0, 0)) {
-				error = XFS_ERROR(EDQUOT);
-				goto error1;
-			}
-		}
+		error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
+				ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
+				XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+		if (error)
+			goto error1;
 
 		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
diff -urN linux-2.5.66-bk2/fs/xfs/xfsidbg.c linux-2.5.66-bk3/fs/xfs/xfsidbg.c
--- linux-2.5.66-bk2/fs/xfs/xfsidbg.c	Mon Mar 24 14:01:15 2003
+++ linux-2.5.66-bk3/fs/xfs/xfsidbg.c	Mon Mar 31 12:48:53 2003
@@ -31,8 +31,8 @@
  */
 
 #include <xfs.h>
-#include <xfs_quota_priv.h>
 #include <xfs_log_recover.h>
+#include "quota/xfs_qm.h"
 #include "pagebuf/page_buf_internal.h"
 
 #include <linux/ctype.h>
@@ -1320,13 +1320,13 @@
 	"INVALID0x40000",	/*    0x40000 */
 	"INVALID0x80000",	/*    0x80000 */
 	"VROOT",		/*   0x100000 */
-	"VNOSWAP",		/*   0x200000 */
-	"VISSWAP",		/*   0x400000 */
-	"VREPLICABLE",		/*   0x800000 */
-	"VNOTREPLICABLE",	/*  0x1000000 */
-	"VDOCMP",		/*  0x2000000 */
+	"INVALID0x200000",	/*   0x200000 */
+	"INVALID00x400000",	/*   0x400000 */
+	"INVALID0x800000",	/*   0x800000 */
+	"INVALID0x1000000",	/*  0x1000000 */
+	"INVALID0x2000000",	/*  0x2000000 */
 	"VSHARE",		/*  0x4000000 */
-	"VFRLOCKS",		/*  0x8000000 */
+	"INVALID0x8000000",     /*  0x8000000 */
 	"VENF_LOCKING",		/* 0x10000000 */
 	"VOPLOCK",		/* 0x20000000 */
 	"VPURGE",		/* 0x40000000 */
@@ -1373,9 +1373,10 @@
 
 	kdb_printf("vnode: 0x%p type ", vp);
 	if ((size_t)vp->v_type >= sizeof(vnode_type)/sizeof(vnode_type[0]))
-		kdb_printf("out of range 0x%x\n", vp->v_type);
+		kdb_printf("out of range 0x%x", vp->v_type);
 	else
-		kdb_printf("%s\n", vnode_type[vp->v_type]);
+		kdb_printf("%s", vnode_type[vp->v_type]);
+	kdb_printf(" v_bh %p\n", &vp->v_bh);
 
 	if ((bh = vp->v_bh.bh_first)) {
 		kdb_printf("   v_inode 0x%p v_bh->bh_first 0x%p pobj 0x%p\n",
@@ -1397,6 +1398,9 @@
 #ifdef	CONFIG_XFS_VNODE_TRACING
 	kdb_printf("   v_trace 0x%p\n", vp->v_trace);
 #endif	/* CONFIG_XFS_VNODE_TRACING */
+        
+	kdb_printf("   v_vfsp 0x%p v_number %Lx\n",
+	        vp->v_vfsp, vp->v_number);
 }
 
 
@@ -4808,13 +4812,8 @@
 static void
 xfsidbg_xcore(xfs_iocore_t *io)
 {
-	if (IO_IS_XFS(io)) {
-		kdb_printf("io_obj 0x%p (xinode) io_mount 0x%p\n",
-			io->io_obj, io->io_mount);
-	} else {
-		kdb_printf("io_obj 0x%p (dcxvn) io_mount 0x%p\n",
-			io->io_obj, io->io_mount);
-	}
+        kdb_printf("io_obj 0x%p io_flags 0x%x io_mount 0x%p\n",
+			io->io_obj, io->io_flags, io->io_mount);
 	kdb_printf("new_size %Lx\n", io->io_new_size);
 }
 
diff -urN linux-2.5.66-bk2/include/asm-arm/div64.h linux-2.5.66-bk3/include/asm-arm/div64.h
--- linux-2.5.66-bk2/include/asm-arm/div64.h	Mon Mar 24 14:00:22 2003
+++ linux-2.5.66-bk3/include/asm-arm/div64.h	Mon Mar 31 12:48:53 2003
@@ -4,9 +4,13 @@
 /* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
-	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	register int __res asm("r2") = base;			\
+	register unsigned long long __n asm("r0") = n;		\
+	asm("bl do_div64"					\
+		: "=r" (__n), "=r" (__res)			\
+		: "0" (__n), "1" (__res)			\
+		: "r3", "ip", "lr", "cc");			\
+	n = __n;						\
 	__res;							\
 })
 
diff -urN linux-2.5.66-bk2/include/asm-arm/proc-armv/pgtable.h linux-2.5.66-bk3/include/asm-arm/proc-armv/pgtable.h
--- linux-2.5.66-bk2/include/asm-arm/proc-armv/pgtable.h	Mon Mar 24 14:00:00 2003
+++ linux-2.5.66-bk3/include/asm-arm/proc-armv/pgtable.h	Mon Mar 31 12:48:53 2003
@@ -103,6 +103,7 @@
  * entries are stored 1024 bytes below.
  */
 #define L_PTE_PRESENT		(1 << 0)
+#define L_PTE_FILE		(1 << 1)	/* only when !PRESENT */
 #define L_PTE_YOUNG		(1 << 1)
 #define L_PTE_BUFFERABLE	(1 << 2)	/* matches PTE */
 #define L_PTE_CACHEABLE		(1 << 3)	/* matches PTE */
@@ -173,6 +174,7 @@
 #define pte_exec(pte)			(pte_val(pte) & L_PTE_EXEC)
 #define pte_dirty(pte)			(pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)			(pte_val(pte) & L_PTE_YOUNG)
+#define pte_file(pte)			(pte_val(pte) & L_PTE_FILE)
 
 #define PTE_BIT_FUNC(fn,op)			\
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -196,6 +198,11 @@
 
 #define pgtable_cache_init() do { } while (0)
 
+#define pte_to_pgoff(x)	(pte_val(x) >> 2)
+#define pgoff_to_pte(x)	__pte(((x) << 2) | L_PTE_FILE)
+
+#define PTE_FILE_MAX_BITS	30
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_PROC_PGTABLE_H */
diff -urN linux-2.5.66-bk2/include/asm-arm/system.h linux-2.5.66-bk3/include/asm-arm/system.h
--- linux-2.5.66-bk2/include/asm-arm/system.h	Mon Mar 24 14:00:02 2003
+++ linux-2.5.66-bk3/include/asm-arm/system.h	Mon Mar 31 12:48:53 2003
@@ -65,12 +65,13 @@
  * The `mb' is to tell GCC not to cache `current' across this call.
  */
 struct thread_info;
-extern struct thread_info *__switch_to(struct thread_info *, struct thread_info *);
+struct task_struct;
+extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
 
-#define switch_to(prev,next,last)					\
-	do {			 					\
-		__switch_to(prev->thread_info,next->thread_info);	\
-		mb();							\
+#define switch_to(prev,next,last)						\
+	do {									\
+		last = __switch_to(prev,prev->thread_info,next->thread_info);	\
+		mb();								\
 	} while (0)
 
 #ifdef CONFIG_SMP
diff -urN linux-2.5.66-bk2/include/asm-sparc64/rwsem.h linux-2.5.66-bk3/include/asm-sparc64/rwsem.h
--- linux-2.5.66-bk2/include/asm-sparc64/rwsem.h	Mon Mar 24 14:01:11 2003
+++ linux-2.5.66-bk3/include/asm-sparc64/rwsem.h	Mon Mar 31 12:48:53 2003
@@ -18,11 +18,6 @@
 
 struct rwsem_waiter;
 
-extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
-extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *));
-
 struct rw_semaphore {
 	signed int count;
 #define RWSEM_UNLOCKED_VALUE		0x00000000
@@ -48,222 +43,13 @@
 	INIT_LIST_HEAD(&sem->wait_list);
 }
 
-static __inline__ void __down_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __down_read\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"add		%%g5, 1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" add		%%g7, 1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g1, %%l1\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l1, %%g1\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __down_read"
-		: : "r" (sem), "i" (rwsem_down_read_failed)
-		: "g5", "g7", "memory", "cc");
-}
-
-static __inline__ int __down_read_trylock(struct rw_semaphore *sem)
-{
-	int result;
-
-	__asm__ __volatile__(
-		"! beginning __down_read_trylock\n"
-		"1:\tlduw	[%1], %%g5\n\t"
-		"add		%%g5, 1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 2f\n\t"
-		" mov		0, %0\n\t"
-		"cas		[%1], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" mov		1, %0\n\t"
-		"membar		#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		"! ending __down_read_trylock"
-		: "=&r" (result)
-                : "r" (sem)
-		: "g5", "g7", "memory", "cc");
-
-	return result;
-}
-
-static __inline__ void __down_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __down_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"add		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" cmp		%%g7, 0\n\t"
-		"bne,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __down_write"
-		: : "r" (sem), "i" (rwsem_down_write_failed),
-		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-
-static __inline__ int __down_write_trylock(struct rw_semaphore *sem)
-{
-	int result;
-
-	__asm__ __volatile__(
-		"! beginning __down_write_trylock\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%1], %%g5\n\t"
-		"cmp		%%g5, 0\n\t"
-		"bne,pn		%%icc, 2f\n\t"
-		" mov		0, %0\n\t"
-		"add		%%g5, %%g1, %%g7\n\t"
-		"cas		[%1], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" mov		1, %0\n\t"
-		"membar		#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		"! ending __down_write_trylock"
-		: "=&r" (result)
-		: "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-
-	return result;
-}
-
-static __inline__ void __up_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __up_read\n\t"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, 1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection	2\n"
-		"3:\tsethi	%%hi(%2), %%g1\n\t"
-		"sub		%%g7, 1, %%g7\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n\t"
-		"andcc		%%g7, %%g1, %%g0\n\t"
-		"bne,pn		%%icc, 2b\n\t"
-		" mov		%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_read"
-		: : "r" (sem), "i" (rwsem_wake),
-		    "i" (RWSEM_ACTIVE_MASK)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-
-static __inline__ void __up_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __up_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" sub		%%g7, %%g1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection 2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_write"
-		: : "r" (sem), "i" (rwsem_wake),
-		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
-
-static __inline__ void __downgrade_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"! beginning __up_write\n\t"
-		"sethi		%%hi(%2), %%g1\n\t"
-		"or		%%g1, %%lo(%2), %%g1\n"
-		"1:\tlduw	[%0], %%g5\n\t"
-		"sub		%%g5, %%g1, %%g7\n\t"
-		"cas		[%0], %%g5, %%g7\n\t"
-		"cmp		%%g5, %%g7\n\t"
-		"bne,pn		%%icc, 1b\n\t"
-		" sub		%%g7, %%g1, %%g7\n\t"
-		"cmp		%%g7, 0\n\t"
-		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreLoad | #StoreStore\n"
-		"2:\n\t"
-		".subsection 2\n"
-		"3:\tmov	%0, %%g5\n\t"
-		"save		%%sp, -160, %%sp\n\t"
-		"mov		%%g2, %%l2\n\t"
-		"mov		%%g3, %%l3\n\t"
-		"call		%1\n\t"
-		" mov		%%g5, %%o0\n\t"
-		"mov		%%l2, %%g2\n\t"
-		"ba,pt		%%xcc, 2b\n\t"
-		" restore	%%l3, %%g0, %%g3\n\t"
-		".previous\n\t"
-		"! ending __up_write"
-		: : "r" (sem), "i" (rwsem_downgrade_wake),
-		    "i" (RWSEM_WAITING_BIAS)
-		: "g1", "g5", "g7", "memory", "cc");
-}
+extern void __down_read(struct rw_semaphore *sem);
+extern int __down_read_trylock(struct rw_semaphore *sem);
+extern void __down_write(struct rw_semaphore *sem);
+extern int __down_write_trylock(struct rw_semaphore *sem);
+extern void __up_read(struct rw_semaphore *sem);
+extern void __up_write(struct rw_semaphore *sem);
+extern void __downgrade_write(struct rw_semaphore *sem);
 
 static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
 {
diff -urN linux-2.5.66-bk2/include/asm-sparc64/timer.h linux-2.5.66-bk3/include/asm-sparc64/timer.h
--- linux-2.5.66-bk2/include/asm-sparc64/timer.h	Mon Mar 24 14:00:01 2003
+++ linux-2.5.66-bk3/include/asm-sparc64/timer.h	Mon Mar 31 12:48:53 2003
@@ -66,4 +66,10 @@
 extern void timer_tick_interrupt(struct pt_regs *);
 #endif
 
+#ifndef CONFIG_SMP
+extern unsigned long up_clock_tick;
+#endif
+
+extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
+
 #endif /* _SPARC64_TIMER_H */
diff -urN linux-2.5.66-bk2/include/linux/skbuff.h linux-2.5.66-bk3/include/linux/skbuff.h
--- linux-2.5.66-bk2/include/linux/skbuff.h	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk3/include/linux/skbuff.h	Mon Mar 31 12:48:53 2003
@@ -231,15 +231,8 @@
 				pkt_type,
 				ip_summed;
 	__u32			priority;
-	atomic_t		users;
 	unsigned short		protocol,
 				security;
-	unsigned int		truesize;
-
-	unsigned char		*head,
-				*data,
-				*tail,
-				*end;
 
 	void			(*destructor)(struct sk_buff *skb);
 #ifdef CONFIG_NETFILTER
@@ -261,6 +254,14 @@
 #ifdef CONFIG_NET_SCHED
        __u32			tc_index;               /* traffic control index */
 #endif
+
+	/* These elements must be at the end, see alloc_skb() for details.  */
+	unsigned int		truesize;
+	atomic_t		users;
+	unsigned char		*head,
+				*data,
+				*tail,
+				*end;
 };
 
 #define SK_WMEM_MAX	65535
diff -urN linux-2.5.66-bk2/include/linux/xfrm.h linux-2.5.66-bk3/include/linux/xfrm.h
--- linux-2.5.66-bk2/include/linux/xfrm.h	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk3/include/linux/xfrm.h	Mon Mar 31 12:48:53 2003
@@ -42,7 +42,6 @@
 	__u8	proto;
 	int	ifindex;
 	uid_t	user;
-	void	*owner;
 };
 
 #define XFRM_INF (~(u64)0)
@@ -164,8 +163,8 @@
 
 struct xfrm_userspi_info {
 	struct xfrm_usersa_info		info;
-	u32				min;
-	u32				max;
+	__u32				min;
+	__u32				max;
 };
 
 struct xfrm_userpolicy_info {
diff -urN linux-2.5.66-bk2/include/net/ah.h linux-2.5.66-bk3/include/net/ah.h
--- linux-2.5.66-bk2/include/net/ah.h	Mon Mar 24 14:00:09 2003
+++ linux-2.5.66-bk3/include/net/ah.h	Mon Mar 31 12:48:53 2003
@@ -17,9 +17,6 @@
 	struct crypto_tfm	*tfm;
 };
 
-extern void skb_ah_walk(const struct sk_buff *skb,
-                        struct crypto_tfm *tfm, icv_update_fn_t icv_update);
-
 static inline void
 ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
 {
@@ -27,7 +24,7 @@
 
 	memset(auth_data, 0, ahp->icv_trunc_len);
 	crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
-	skb_ah_walk(skb, tfm, crypto_hmac_update);
+	skb_icv_walk(skb, tfm, 0, skb->len, crypto_hmac_update);
 	crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv);
 	memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len);
 }
diff -urN linux-2.5.66-bk2/include/net/dst.h linux-2.5.66-bk3/include/net/dst.h
--- linux-2.5.66-bk2/include/net/dst.h	Mon Mar 24 14:01:26 2003
+++ linux-2.5.66-bk3/include/net/dst.h	Mon Mar 31 12:48:53 2003
@@ -248,11 +248,6 @@
 struct flowi;
 extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
 		       struct sock *sk, int flags);
-extern int xfrm6_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		       struct sock *sk, int flags);
-extern void xfrm_init(void);
-extern void xfrm6_init(void);
-
 #endif
 
 #endif /* _NET_DST_H */
diff -urN linux-2.5.66-bk2/include/net/esp.h linux-2.5.66-bk3/include/net/esp.h
--- linux-2.5.66-bk2/include/net/esp.h	Mon Mar 24 14:00:55 2003
+++ linux-2.5.66-bk3/include/net/esp.h	Mon Mar 31 12:48:53 2003
@@ -33,8 +33,6 @@
 	} auth;
 };
 
-extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
-			 int offset, int len, icv_update_fn_t icv_update);
 extern int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len);
 extern int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
 extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
diff -urN linux-2.5.66-bk2/include/net/xfrm.h linux-2.5.66-bk3/include/net/xfrm.h
--- linux-2.5.66-bk2/include/net/xfrm.h	Mon Mar 31 12:48:51 2003
+++ linux-2.5.66-bk3/include/net/xfrm.h	Mon Mar 31 12:48:53 2003
@@ -781,4 +781,7 @@
 struct crypto_tfm;
 typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsigned int);
 
+extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
+			 int offset, int len, icv_update_fn_t icv_update);
+
 #endif	/* _NET_XFRM_H */
diff -urN linux-2.5.66-bk2/include/pcmcia/bus_ops.h linux-2.5.66-bk3/include/pcmcia/bus_ops.h
--- linux-2.5.66-bk2/include/pcmcia/bus_ops.h	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk3/include/pcmcia/bus_ops.h	Mon Mar 31 12:48:53 2003
@@ -1,152 +1,2 @@
-/*
- * bus_ops.h 1.10 2000/06/12 21:55:41
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#ifndef _LINUX_BUS_OPS_H
-#define _LINUX_BUS_OPS_H
-
-#include <linux/config.h>
-
-#ifdef CONFIG_VIRTUAL_BUS
-
-typedef struct bus_operations {
-    void	*priv;
-    u32		(*b_in)(void *bus, u32 port, s32 sz);
-    void	(*b_ins)(void *bus, u32 port, void *buf,
-			 u32 count, s32 sz);
-    void	(*b_out)(void *bus, u32 val, u32 port, s32 sz);
-    void	(*b_outs)(void *bus, u32 port, void *buf,
-			  u32 count, s32 sz);
-    void	*(*b_ioremap)(void *bus, u_long ofs, u_long sz);
-    void	(*b_iounmap)(void *bus, void *addr);
-    u32		(*b_read)(void *bus, void *addr, s32 sz);
-    void	(*b_write)(void *bus, u32 val, void *addr, s32 sz);
-    void	(*b_copy_from)(void *bus, void *d, void *s, u32 count);
-    void	(*b_copy_to)(void *bus, void *d, void *s, u32 count);
-    int		(*b_request_irq)(void *bus, u_int irq,
-				 void (*handler)(int, void *,
-						 struct pt_regs *),
-				 u_long flags, const char *device,
-				 void *dev_id);
-    void	(*b_free_irq)(void *bus, u_int irq, void *dev_id);
-} bus_operations;
-
-#define bus_inb(b,p)		(b)->b_in((b),(p),0)
-#define bus_inw(b,p)		(b)->b_in((b),(p),1)
-#define bus_inl(b,p)		(b)->b_in((b),(p),2)
-#define bus_inw_ns(b,p)		(b)->b_in((b),(p),-1)
-#define bus_inl_ns(b,p)		(b)->b_in((b),(p),-2)
-
-#define bus_insb(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),0)
-#define bus_insw(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),1)
-#define bus_insl(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),2)
-#define bus_insw_ns(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),-1)
-#define bus_insl_ns(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),-2)
-
-#define bus_outb(b,v,p)		(b)->b_out((b),(v),(p),0)
-#define bus_outw(b,v,p)		(b)->b_out((b),(v),(p),1)
-#define bus_outl(b,v,p)		(b)->b_out((b),(v),(p),2)
-#define bus_outw_ns(b,v,p)	(b)->b_out((b),(v),(p),-1)
-#define bus_outl_ns(b,v,p)	(b)->b_out((b),(v),(p),-2)
-
-#define bus_outsb(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),0)
-#define bus_outsw(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),1)
-#define bus_outsl(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),2)
-#define bus_outsw_ns(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),-1)
-#define bus_outsl_ns(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),-2)
-
-#define bus_readb(b,a)		(b)->b_read((b),(a),0)
-#define bus_readw(b,a)		(b)->b_read((b),(a),1)
-#define bus_readl(b,a)		(b)->b_read((b),(a),2)
-#define bus_readw_ns(b,a)	(b)->b_read((b),(a),-1)
-#define bus_readl_ns(b,a)	(b)->b_read((b),(a),-2)
-
-#define bus_writeb(b,v,a)	(b)->b_write((b),(v),(a),0)
-#define bus_writew(b,v,a)	(b)->b_write((b),(v),(a),1)
-#define bus_writel(b,v,a)	(b)->b_write((b),(v),(a),2)
-#define bus_writew_ns(b,v,a)	(b)->b_write((b),(v),(a),-1)
-#define bus_writel_ns(b,v,a)	(b)->b_write((b),(v),(a),-2)
-
-#define bus_ioremap(b,s,n)	(b)->b_ioremap((b),(s),(n))
-#define bus_iounmap(b,a)	(b)->b_iounmap((b),(a))
-#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n))
-#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n))
-
-#define bus_request_irq(b,i,h,f,n,d) \
-				(b)->b_request_irq((b),(i),(h),(f),(n),(d))
-#define bus_free_irq(b,i,d)	(b)->b_free_irq((b),(i),(d))
-
-#else
-
-#define bus_inb(b,p)		inb(p)
-#define bus_inw(b,p)		inw(p)
-#define bus_inl(b,p)		inl(p)
-#define bus_inw_ns(b,p)		inw_ns(p)
-#define bus_inl_ns(b,p)		inl_ns(p)
-
-#define bus_insb(b,p,a,c)	insb(p,a,c)
-#define bus_insw(b,p,a,c)	insw(p,a,c)
-#define bus_insl(b,p,a,c)	insl(p,a,c)
-#define bus_insw_ns(b,p,a,c)	insw_ns(p,a,c)
-#define bus_insl_ns(b,p,a,c)	insl_ns(p,a,c)
-
-#define bus_outb(b,v,p)		outb(b,v,p)
-#define bus_outw(b,v,p)		outw(b,v,p)
-#define bus_outl(b,v,p)		outl(b,v,p)
-#define bus_outw_ns(b,v,p)	outw_ns(b,v,p)
-#define bus_outl_ns(b,v,p)	outl_ns(b,v,p)
-
-#define bus_outsb(b,p,a,c)	outsb(p,a,c)
-#define bus_outsw(b,p,a,c)	outsw(p,a,c)
-#define bus_outsl(b,p,a,c)	outsl(p,a,c)
-#define bus_outsw_ns(b,p,a,c)	outsw_ns(p,a,c)
-#define bus_outsl_ns(b,p,a,c)	outsl_ns(p,a,c)
-
-#define bus_readb(b,a)		readb(a)
-#define bus_readw(b,a)		readw(a)
-#define bus_readl(b,a)		readl(a)
-#define bus_readw_ns(b,a)	readw_ns(a)
-#define bus_readl_ns(b,a)	readl_ns(a)
-
-#define bus_writeb(b,v,a)	writeb(v,a)
-#define bus_writew(b,v,a)	writew(v,a)
-#define bus_writel(b,v,a)	writel(v,a)
-#define bus_writew_ns(b,v,a)	writew_ns(v,a)
-#define bus_writel_ns(b,v,a)	writel_ns(v,a)
-
-#define bus_ioremap(b,s,n)	ioremap(s,n)
-#define bus_iounmap(b,a)	iounmap(a)
-#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n)
-#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n)
-
-#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d))
-#define bus_free_irq(b,i,d)	free_irq((i),(d))
-
-#endif /* CONFIG_VIRTUAL_BUS */
-
-#endif /* _LINUX_BUS_OPS_H */
+/* now empty */
+#warning please remove the reference to this file
diff -urN linux-2.5.66-bk2/include/pcmcia/cs.h linux-2.5.66-bk3/include/pcmcia/cs.h
--- linux-2.5.66-bk2/include/pcmcia/cs.h	Mon Mar 24 13:59:53 2003
+++ linux-2.5.66-bk3/include/pcmcia/cs.h	Mon Mar 31 12:48:53 2003
@@ -98,7 +98,6 @@
     void	*buffer;
     void	*misc;
     void	*client_data;
-    struct bus_operations *bus;
 } event_callback_args_t;
 
 /* for GetConfigurationInfo */
diff -urN linux-2.5.66-bk2/include/pcmcia/driver_ops.h linux-2.5.66-bk3/include/pcmcia/driver_ops.h
--- linux-2.5.66-bk2/include/pcmcia/driver_ops.h	Mon Mar 24 14:00:45 2003
+++ linux-2.5.66-bk3/include/pcmcia/driver_ops.h	Mon Mar 31 12:48:53 2003
@@ -1,73 +1,2 @@
-/*
- * driver_ops.h 1.15 2000/06/12 21:55:40
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#ifndef _LINUX_DRIVER_OPS_H
-#define _LINUX_DRIVER_OPS_H
-
-#ifndef DEV_NAME_LEN
-#define DEV_NAME_LEN	32
-#endif
-
-#ifdef __KERNEL__
-
-typedef struct dev_node_t {
-    char		dev_name[DEV_NAME_LEN];
-    u_short		major, minor;
-    struct dev_node_t	*next;
-} dev_node_t;
-
-typedef struct dev_locator_t {
-    enum { LOC_ISA, LOC_PCI } bus;
-    union {
-	struct {
-	    u_short	io_base_1, io_base_2;
-	    u_long	mem_base;
-	    u_char	irq, dma;
-	} isa;
-	struct {
-	    u_char	bus;
-	    u_char	devfn;
-	} pci;
-    } b;
-} dev_locator_t;
-
-typedef struct driver_operations {
-    char		*name;
-    dev_node_t		*(*attach) (dev_locator_t *loc);
-    void		(*suspend) (dev_node_t *dev);
-    void		(*resume) (dev_node_t *dev);
-    void		(*detach) (dev_node_t *dev);
-} driver_operations;
-
-int register_driver(struct driver_operations *ops);
-void unregister_driver(struct driver_operations *ops);
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_DRIVER_OPS_H */
+/* now empty */
+#warning please remove the reference to this file
diff -urN linux-2.5.66-bk2/include/pcmcia/ds.h linux-2.5.66-bk3/include/pcmcia/ds.h
--- linux-2.5.66-bk2/include/pcmcia/ds.h	Mon Mar 24 13:59:46 2003
+++ linux-2.5.66-bk3/include/pcmcia/ds.h	Mon Mar 31 12:48:53 2003
@@ -30,9 +30,9 @@
 #ifndef _LINUX_DS_H
 #define _LINUX_DS_H
 
-#include <pcmcia/driver_ops.h>
 #include <pcmcia/bulkmem.h>
 #include <linux/device.h>
+#include <pcmcia/cs_types.h>
 
 typedef struct tuple_parse_t {
     tuple_t		tuple;
@@ -108,6 +108,12 @@
 
 #ifdef __KERNEL__
 
+typedef struct dev_node_t {
+    char		dev_name[DEV_NAME_LEN];
+    u_short		major, minor;
+    struct dev_node_t	*next;
+} dev_node_t;
+
 typedef struct dev_link_t {
     dev_node_t		*dev;
     u_int		state, open;
@@ -144,7 +150,7 @@
 extern struct bus_type pcmcia_bus_type;
 
 struct pcmcia_driver {
-	int			use_count, status;
+	int			use_count;
 	dev_link_t		*(*attach)(void);
 	void			(*detach)(dev_link_t *);
 	struct module		*owner;
diff -urN linux-2.5.66-bk2/include/pcmcia/ss.h linux-2.5.66-bk3/include/pcmcia/ss.h
--- linux-2.5.66-bk2/include/pcmcia/ss.h	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk3/include/pcmcia/ss.h	Mon Mar 31 12:48:53 2003
@@ -58,7 +58,6 @@
     ioaddr_t	io_offset;
     u_char	pci_irq;
     struct pci_dev *cb_dev;
-    struct bus_operations *bus;
 } socket_cap_t;
 
 /* InquireSocket capabilities */
@@ -134,9 +133,7 @@
 	int (*get_status)(unsigned int sock, u_int *value);
 	int (*get_socket)(unsigned int sock, socket_state_t *state);
 	int (*set_socket)(unsigned int sock, socket_state_t *state);
-	int (*get_io_map)(unsigned int sock, struct pccard_io_map *io);
 	int (*set_io_map)(unsigned int sock, struct pccard_io_map *io);
-	int (*get_mem_map)(unsigned int sock, struct pccard_mem_map *mem);
 	int (*set_mem_map)(unsigned int sock, struct pccard_mem_map *mem);
 	void (*proc_setup)(unsigned int sock, struct proc_dir_entry *base);
 };
diff -urN linux-2.5.66-bk2/net/core/skbuff.c linux-2.5.66-bk3/net/core/skbuff.c
--- linux-2.5.66-bk2/net/core/skbuff.c	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk3/net/core/skbuff.c	Mon Mar 31 12:48:53 2003
@@ -195,46 +195,14 @@
 	if (!data)
 		goto nodata;
 
-	/* XXX: does not include slab overhead */
-	skb->next	  = skb->prev = NULL;
-	skb->list	  = NULL;
-	skb->sk		  = NULL;
-	skb->stamp.tv_sec = 0;	/* No idea about time */
-	skb->dev	  = NULL;
-	skb->dst	  = NULL;
-	skb->sp		  = NULL;
-	memset(skb->cb, 0, sizeof(skb->cb));
-	/* Set up other state */
-	skb->len	  = 0;
-	skb->data_len	  = 0;
-	skb->csum	  = 0;
-	skb->local_df	  = 0;
-	skb->cloned	  = 0;
-	skb->pkt_type	  = PACKET_HOST;	/* Default type */
-	skb->ip_summed	  = 0;
-	skb->priority	  = 0;
-	atomic_set(&skb->users, 1);
-	skb->security	  = 0;	/* By default packets are insecure */
+	memset(skb, 0, offsetof(struct sk_buff, truesize));
 	skb->truesize = size + sizeof(struct sk_buff);
-	
-	/* Load the data pointers. */
-	skb->head = skb->data = skb->tail = data;
+	atomic_set(&skb->users, 1);
+	skb->head = data;
+	skb->data = data;
+	skb->tail = data;
 	skb->end  = data + size;
 
-	skb->destructor	  = NULL;
-#ifdef CONFIG_NETFILTER
-	skb->nfmark	= skb->nfcache = 0;
-	skb->nfct	= NULL;
-#ifdef CONFIG_NETFILTER_DEBUG
-	skb->nf_debug	= 0;
-#endif
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-	skb->nf_bridge	= NULL;
-#endif
-#endif
-#ifdef CONFIG_NET_SCHED
-	skb->tc_index	= 0;
-#endif	
 	atomic_set(&(skb_shinfo(skb)->dataref), 1);
 	skb_shinfo(skb)->nr_frags  = 0;
 	skb_shinfo(skb)->tso_size = 0;
@@ -367,10 +335,10 @@
 	C(nh);
 	C(mac);
 	C(dst);
-	dst_clone(n->dst);
+	dst_clone(skb->dst);
 	C(sp);
 #ifdef CONFIG_INET
-	secpath_get(n->sp);
+	secpath_get(skb->sp);
 #endif
 	memcpy(n->cb, skb->cb, sizeof(skb->cb));
 	C(len);
@@ -381,24 +349,20 @@
 	C(pkt_type);
 	C(ip_summed);
 	C(priority);
-	atomic_set(&n->users, 1);
 	C(protocol);
 	C(security);
-	C(truesize);
-	C(head);
-	C(data);
-	C(tail);
-	C(end);
 	n->destructor = NULL;
 #ifdef CONFIG_NETFILTER
 	C(nfmark);
 	C(nfcache);
 	C(nfct);
+	nf_conntrack_get(skb->nfct);
 #ifdef CONFIG_NETFILTER_DEBUG
 	C(nf_debug);
 #endif
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 	C(nf_bridge);
+	nf_bridge_get(skb->nf_bridge);
 #endif
 #endif /*CONFIG_NETFILTER*/
 #if defined(CONFIG_HIPPI)
@@ -407,15 +371,16 @@
 #ifdef CONFIG_NET_SCHED
 	C(tc_index);
 #endif
+	C(truesize);
+	atomic_set(&n->users, 1);
+	C(head);
+	C(data);
+	C(tail);
+	C(end);
 
 	atomic_inc(&(skb_shinfo(skb)->dataref));
 	skb->cloned = 1;
-#ifdef CONFIG_NETFILTER
-	nf_conntrack_get(skb->nfct);
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-	nf_bridge_get(skb->nf_bridge);
-#endif
-#endif
+
 	return n;
 }
 
@@ -439,7 +404,6 @@
 	new->nh.raw	= old->nh.raw + offset;
 	new->mac.raw	= old->mac.raw + offset;
 	memcpy(new->cb, old->cb, sizeof(old->cb));
-	atomic_set(&new->users, 1);
 	new->local_df	= old->local_df;
 	new->pkt_type	= old->pkt_type;
 	new->stamp	= old->stamp;
@@ -449,18 +413,19 @@
 	new->nfmark	= old->nfmark;
 	new->nfcache	= old->nfcache;
 	new->nfct	= old->nfct;
-	nf_conntrack_get(new->nfct);
+	nf_conntrack_get(old->nfct);
 #ifdef CONFIG_NETFILTER_DEBUG
 	new->nf_debug	= old->nf_debug;
 #endif
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 	new->nf_bridge	= old->nf_bridge;
-	nf_bridge_get(new->nf_bridge);
+	nf_bridge_get(old->nf_bridge);
 #endif
 #endif
 #ifdef CONFIG_NET_SCHED
 	new->tc_index	= old->tc_index;
 #endif
+	atomic_set(&new->users, 1);
 }
 
 /**
diff -urN linux-2.5.66-bk2/net/ipv4/devinet.c linux-2.5.66-bk3/net/ipv4/devinet.c
--- linux-2.5.66-bk2/net/ipv4/devinet.c	Mon Mar 24 14:00:10 2003
+++ linux-2.5.66-bk3/net/ipv4/devinet.c	Mon Mar 31 12:48:53 2003
@@ -1065,6 +1065,62 @@
 	return ret;
 }
 
+static int ipv4_doint_and_flush(ctl_table *ctl, int write,
+				struct file* filp, void *buffer,
+				size_t *lenp)
+{
+	int *valp = ctl->data;
+	int val = *valp;
+	int ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+	if (write && *valp != val)
+		rt_cache_flush(0);
+
+	return ret;
+}
+
+static int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int nlen,
+					 void *oldval, size_t *oldlenp,
+					 void *newval, size_t newlen, 
+					 void **context)
+{
+	int *valp = table->data;
+	int new;
+
+	if (!newval || !newlen)
+		return 0;
+
+	if (newlen != sizeof(int))
+		return -EINVAL;
+
+	if (get_user(new, (int *)newval))
+		return -EFAULT;
+
+	if (new == *valp)
+		return 0;
+
+	if (oldval && oldlenp) {
+		size_t len;
+
+		if (get_user(len, oldlenp))
+			return -EFAULT;
+
+		if (len) {
+			if (len > table->maxlen)
+				len = table->maxlen;
+			if (copy_to_user(oldval, valp, len))
+				return -EFAULT;
+			if (put_user(len, oldlenp))
+				return -EFAULT;
+		}
+	}
+
+	*valp = new;
+	rt_cache_flush(0);
+	return 1;
+}
+
+
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
 	ctl_table		devinet_vars[17];
@@ -1192,7 +1248,8 @@
 			.data =	&ipv4_devconf.no_xfrm,
 			.maxlen =		sizeof(int),
 			.mode =	0644,
-			.proc_handler =&proc_dointvec,
+			.proc_handler = &ipv4_doint_and_flush,
+			.strategy = &ipv4_doint_and_flush_strategy,
 		},
 		{
 			.ctl_name =	NET_IPV4_CONF_NOPOLICY,
@@ -1200,7 +1257,8 @@
 			.data =	&ipv4_devconf.no_policy,
 			.maxlen =		sizeof(int),
 			.mode =	0644,
-			.proc_handler =&proc_dointvec,
+			.proc_handler = &ipv4_doint_and_flush,
+			.strategy = &ipv4_doint_and_flush_strategy,
 		},
 	},
 	.devinet_dev = {
diff -urN linux-2.5.66-bk2/net/ipv4/sysctl_net_ipv4.c linux-2.5.66-bk3/net/ipv4/sysctl_net_ipv4.c
--- linux-2.5.66-bk2/net/ipv4/sysctl_net_ipv4.c	Mon Mar 24 14:01:13 2003
+++ linux-2.5.66-bk3/net/ipv4/sysctl_net_ipv4.c	Mon Mar 31 12:48:53 2003
@@ -77,14 +77,39 @@
 			 void *newval, size_t newlen, 
 			 void **context)
 {
+	int *valp = table->data;
 	int new;
+
+	if (!newval || !newlen)
+		return 0;
+
 	if (newlen != sizeof(int))
 		return -EINVAL;
-	if (get_user(new,(int *)newval))
-		return -EFAULT; 
-	if (new != ipv4_devconf.forwarding) 
-		inet_forward_change(); 
-	return 0; /* caller does change again and handles handles oldval */ 
+
+	if (get_user(new, (int *)newval))
+		return -EFAULT;
+
+	if (new == *valp)
+		return 0;
+
+	if (oldval && oldlenp) {
+		size_t len;
+
+		if (get_user(len, oldlenp))
+			return -EFAULT;
+
+		if (len) {
+			if (len > table->maxlen)
+				len = table->maxlen;
+			if (copy_to_user(oldval, valp, len))
+				return -EFAULT;
+			if (put_user(len, oldlenp))
+				return -EFAULT;
+		}
+	}
+
+	inet_forward_change();
+	return 1;
 }
 
 ctl_table ipv4_table[] = {
diff -urN linux-2.5.66-bk2/net/ipv4/tcp_input.c linux-2.5.66-bk3/net/ipv4/tcp_input.c
--- linux-2.5.66-bk2/net/ipv4/tcp_input.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk3/net/ipv4/tcp_input.c	Mon Mar 31 12:48:53 2003
@@ -3363,7 +3363,7 @@
 
 	/*
 	 *	Header prediction.
-	 *	The code losely follows the one in the famous 
+	 *	The code loosely follows the one in the famous 
 	 *	"30 instruction TCP receive" Van Jacobson mail.
 	 *	
 	 *	Van's trick is to deposit buffers into socket queue 
diff -urN linux-2.5.66-bk2/net/ipv6/ipv6_syms.c linux-2.5.66-bk3/net/ipv6/ipv6_syms.c
--- linux-2.5.66-bk2/net/ipv6/ipv6_syms.c	Mon Mar 24 14:01:12 2003
+++ linux-2.5.66-bk3/net/ipv6/ipv6_syms.c	Mon Mar 31 12:48:53 2003
@@ -9,6 +9,8 @@
 
 EXPORT_SYMBOL(ipv6_addr_type);
 EXPORT_SYMBOL(icmpv6_send);
+EXPORT_SYMBOL(icmpv6_statistics);
+EXPORT_SYMBOL(icmpv6_err_convert);
 EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
diff -urN linux-2.5.66-bk2/net/netsyms.c linux-2.5.66-bk3/net/netsyms.c
--- linux-2.5.66-bk2/net/netsyms.c	Mon Mar 31 12:48:51 2003
+++ linux-2.5.66-bk3/net/netsyms.c	Mon Mar 31 12:48:53 2003
@@ -356,13 +356,10 @@
 EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname);
 EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname);
 EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
-#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
-EXPORT_SYMBOL_GPL(skb_ah_walk);
-#endif
+EXPORT_SYMBOL_GPL(skb_icv_walk);
 #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
 EXPORT_SYMBOL_GPL(skb_cow_data);
 EXPORT_SYMBOL_GPL(pskb_put);
-EXPORT_SYMBOL_GPL(skb_icv_walk);
 EXPORT_SYMBOL_GPL(skb_to_sgvec);
 #endif
 
diff -urN linux-2.5.66-bk2/net/sched/sch_csz.c linux-2.5.66-bk3/net/sched/sch_csz.c
--- linux-2.5.66-bk2/net/sched/sch_csz.c	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk3/net/sched/sch_csz.c	Mon Mar 31 12:48:53 2003
@@ -56,7 +56,7 @@
 	CSZ presents a more precise but less flexible and less efficient
 	approach. As I understand it, the main idea is to create
 	WFQ flows for each guaranteed service and to allocate
-	the rest of bandwith to dummy flow-0. Flow-0 comprises
+	the rest of bandwidth to dummy flow-0. Flow-0 comprises
 	the predictive services and the best effort traffic;
 	it is handled by a priority scheduler with the highest
 	priority band allocated	for predictive services, and the rest ---
diff -urN linux-2.5.66-bk2/net/socket.c linux-2.5.66-bk3/net/socket.c
--- linux-2.5.66-bk2/net/socket.c	Mon Mar 24 14:00:16 2003
+++ linux-2.5.66-bk3/net/socket.c	Mon Mar 31 12:48:53 2003
@@ -347,17 +347,17 @@
 /*
  *	Obtains the first available file descriptor and sets it up for use.
  *
- *	This functions creates file structure and maps it to fd space
+ *	This function creates file structure and maps it to fd space
  *	of current process. On success it returns file descriptor
  *	and file struct implicitly stored in sock->file.
  *	Note that another thread may close file descriptor before we return
  *	from this function. We use the fact that now we do not refer
  *	to socket after mapping. If one day we will need it, this
- *	function will inincrement ref. count on file by 1.
+ *	function will increment ref. count on file by 1.
  *
  *	In any case returned fd MAY BE not valid!
- *	This race condition is inavoidable
- *	with shared fd spaces, we cannot solve is inside kernel,
+ *	This race condition is unavoidable
+ *	with shared fd spaces, we cannot solve it inside kernel,
  *	but we take care of internal coherence yet.
  */
 
diff -urN linux-2.5.66-bk2/net/xfrm/xfrm_algo.c linux-2.5.66-bk3/net/xfrm/xfrm_algo.c
--- linux-2.5.66-bk2/net/xfrm/xfrm_algo.c	Mon Mar 31 12:48:51 2003
+++ linux-2.5.66-bk3/net/xfrm/xfrm_algo.c	Mon Mar 31 12:48:53 2003
@@ -440,83 +440,6 @@
 	return n;
 }
 
-#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
-void skb_ah_walk(const struct sk_buff *skb,
-                        struct crypto_tfm *tfm, icv_update_fn_t icv_update)
-{
-	int offset = 0;
-	int len = skb->len;
-	int start = skb->len - skb->data_len;
-	int i, copy = start - offset;
-	struct scatterlist sg;
-
-	/* Checksum header. */
-	if (copy > 0) {
-		if (copy > len)
-			copy = len;
-		
-		sg.page = virt_to_page(skb->data + offset);
-		sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
-		sg.length = copy;
-		
-		icv_update(tfm, &sg, 1);
-		
-		if ((len -= copy) == 0)
-			return;
-		offset += copy;
-	}
-
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		int end;
-
-		BUG_TRAP(start <= offset + len);
-
-		end = start + skb_shinfo(skb)->frags[i].size;
-		if ((copy = end - offset) > 0) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-			if (copy > len)
-				copy = len;
-			
-			sg.page = frag->page;
-			sg.offset = frag->page_offset + offset-start;
-			sg.length = copy;
-			
-			icv_update(tfm, &sg, 1);
-			
-			if (!(len -= copy))
-				return;
-			offset += copy;
-		}
-		start = end;
-	}
-
-	if (skb_shinfo(skb)->frag_list) {
-		struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-		for (; list; list = list->next) {
-			int end;
-
-			BUG_TRAP(start <= offset + len);
-
-			end = start + list->len;
-			if ((copy = end - offset) > 0) {
-				if (copy > len)
-					copy = len;
-				skb_ah_walk(list, tfm, icv_update);
-				if ((len -= copy) == 0)
-					return;
-				offset += copy;
-			}
-			start = end;
-		}
-	}
-	if (len)
-		BUG();
-}
-#endif
-
-#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
 /* Move to common area: it is shared with AH. */
 
 void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
@@ -591,6 +514,7 @@
 		BUG();
 }
 
+#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
 
 /* Looking generic it is not used in another places. */
 
