summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/i386/Kconfig19
-rw-r--r--arch/i386/mm/hugetlbpage.c4
-rw-r--r--arch/ia64/Kconfig10
-rw-r--r--arch/ia64/ia32/ia32_signal.c4
-rw-r--r--arch/ia64/mm/hugetlbpage.c1
-rw-r--r--arch/mips/kernel/signal32.c4
-rw-r--r--arch/ppc64/mm/hugetlbpage.c20
-rw-r--r--arch/s390/kernel/compat_signal.c4
-rw-r--r--arch/sparc64/kernel/signal32.c4
-rw-r--r--arch/x86_64/Kconfig20
-rw-r--r--arch/x86_64/ia32/ia32_signal.c4
-rw-r--r--drivers/block/floppy98.c49
-rw-r--r--drivers/block/ll_rw_blk.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c1
-rw-r--r--drivers/md/dm-ioctl.c8
-rw-r--r--drivers/md/dm-stripe.c14
-rw-r--r--drivers/md/dm-table.c4
-rw-r--r--drivers/md/dm.c15
-rw-r--r--drivers/pci/Kconfig19
-rw-r--r--drivers/pcmcia/cistpl.c3
-rw-r--r--drivers/pcmcia/cs.c2
-rw-r--r--drivers/pcmcia/i82365.c49
-rw-r--r--drivers/pcmcia/rsrc_mgr.c3
-rw-r--r--drivers/pcmcia/tcic.c26
-rw-r--r--drivers/serial/8250.c28
-rw-r--r--drivers/serial/serial_cs.c16
-rw-r--r--drivers/video/aty/aty128fb.c4
-rw-r--r--fs/buffer.c104
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/mpage.c3
-rw-r--r--fs/nfsd/nfs4proc.c149
-rw-r--r--fs/nfsd/nfs4state.c235
-rw-r--r--fs/nfsd/nfs4xdr.c35
-rw-r--r--fs/ntfs/aops.c2
-rw-r--r--fs/reiserfs/inode.c5
-rw-r--r--fs/reiserfs/journal.c39
-rw-r--r--fs/reiserfs/super.c16
-rw-r--r--include/asm-arm/pgtable.h63
-rw-r--r--include/asm-generic/rmap.h3
-rw-r--r--include/asm-mips/siginfo.h2
-rw-r--r--include/linux/buffer_head.h9
-rw-r--r--include/linux/compat_ioctl.h13
-rw-r--r--include/linux/dm-ioctl.h38
-rw-r--r--include/linux/fs.h3
-rw-r--r--include/linux/mm.h3
-rw-r--r--include/linux/nfsd/nfsd.h3
-rw-r--r--include/linux/nfsd/state.h8
-rw-r--r--include/linux/reiserfs_fs_sb.h2
-rw-r--r--ipc/mqueue.c6
-rw-r--r--kernel/signal.c1
-rw-r--r--mm/mmap.c34
-rw-r--r--mm/mremap.c22
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c1
54 files changed, 667 insertions, 474 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 0c93ec368a38..954887332846 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1095,25 +1095,6 @@ config PCI_MMCONFIG
select ACPI_BOOT
default y
-config PCI_USE_VECTOR
- bool "Vector-based interrupt indexing (MSI)"
- depends on X86_LOCAL_APIC && X86_IO_APIC
- default n
- help
- This replaces the current existing IRQ-based index interrupt scheme
- with the vector-base index scheme. The advantages of vector base
- over IRQ base are listed below:
- 1) Support MSI implementation.
- 2) Support future IOxAPIC hotplug
-
- Note that this allows the device drivers to enable MSI, Message
- Signaled Interrupt, on all MSI capable device functions detected.
- Message Signal Interrupt enables an MSI-capable hardware device to
- send an inbound Memory Write on its PCI bus instead of asserting
- IRQ signal on device IRQ pin.
-
- If you don't know what to do here, say N.
-
source "drivers/pci/Kconfig"
config ISA
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
index a702f96373af..6f27153316c4 100644
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -206,10 +206,8 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
struct page *page;
page = pte_page(*(pte_t *)pmd);
- if (page) {
+ if (page)
page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT);
- get_page(page);
- }
return page;
}
#endif
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 8472f3d894bd..781f24985a05 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -361,16 +361,6 @@ config PCI
information about which PCI hardware does work under Linux and which
doesn't.
-config PCI_USE_VECTOR
- bool
- default y if IA64
- help
- This enables MSI, Message Signaled Interrupt, on specific
- MSI capable device functions detected upon requests from the
- device drivers. Message Signal Interrupt enables an MSI-capable
- hardware device to send an inbound Memory Write on its PCI bus
- instead of asserting IRQ signal on device IRQ pin.
-
config PCI_DOMAINS
bool
default PCI
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index bb1e836fb227..f64a9be95e10 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -114,8 +114,8 @@ copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from)
err |= __get_user(to->si_band, &from->si_band);
err |= __get_user(to->si_fd, &from->si_fd);
break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ:
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid);
err |= __get_user(to->si_int, &from->si_int);
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index f487a5649dca..1c0310bb4f2c 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -170,7 +170,6 @@ struct page *follow_huge_addr(struct mm_struct *mm, struct vm_area_struct *vma,
ptep = huge_pte_offset(mm, addr);
page = pte_page(*ptep);
page += ((addr & ~HPAGE_MASK) >> PAGE_SHIFT);
- get_page(page);
return page;
}
int pmd_huge(pmd_t pmd)
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index c52074f84300..44a30542626d 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -358,8 +358,8 @@ static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd);
break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ:
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int);
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
index e81eeec9b009..ad8763c35de7 100644
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -360,10 +360,8 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
BUG_ON(! pmd_hugepage(*pmd));
page = hugepte_page(*(hugepte_t *)pmd);
- if (page) {
+ if (page)
page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT);
- get_page(page);
- }
return page;
}
@@ -609,15 +607,6 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
}
}
-static inline unsigned long computeHugeHptePP(unsigned int hugepte)
-{
- unsigned long flags = 0x2;
-
- if (! (hugepte & _HUGEPAGE_RW))
- flags |= 0x1;
- return flags;
-}
-
int hash_huge_page(struct mm_struct *mm, unsigned long access,
unsigned long ea, unsigned long vsid, int local)
{
@@ -671,7 +660,7 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access,
old_pte = *ptep;
new_pte = old_pte;
- hpteflags = computeHugeHptePP(hugepte_val(new_pte));
+ hpteflags = 0x2 | (! (hugepte_val(new_pte) & _HUGEPAGE_RW));
/* Check if pte already has an hpte (case 2) */
if (unlikely(hugepte_val(old_pte) & _HUGEPAGE_HASHPTE)) {
@@ -747,7 +736,7 @@ repeat:
static void flush_hash_hugepage(mm_context_t context, unsigned long ea,
hugepte_t pte, int local)
{
- unsigned long vsid, vpn, va, hash, secondary, slot;
+ unsigned long vsid, vpn, va, hash, slot;
BUG_ON(hugepte_bad(pte));
BUG_ON(!in_hugepage_area(context, ea));
@@ -757,8 +746,7 @@ static void flush_hash_hugepage(mm_context_t context, unsigned long ea,
va = (vsid << 28) | (ea & 0x0fffffff);
vpn = va >> LARGE_PAGE_SHIFT;
hash = hpt_hash(vpn, 1);
- secondary = !!(hugepte_val(pte) & _HUGEPAGE_SECONDARY);
- if (secondary)
+ if (hugepte_val(pte) & _HUGEPAGE_SECONDARY)
hash = ~hash;
slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
slot += (hugepte_val(pte) & _HUGEPAGE_GROUP_IX) >> 5;
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 373040404a5a..3886a27b8e4d 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -74,8 +74,8 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else {
switch (from->si_code >> 16) {
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ:
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
err |= __put_user(from->si_int, &to->si_int);
/* fallthrough */
case __SI_KILL >> 16:
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index e2f62a666d8c..544ce9dfc2dd 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -129,8 +129,8 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from)
err |= __put_user(from->si_trapno, &to->si_trapno);
err |= __put_user((long)from->si_addr, &to->si_addr);
break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ:
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int);
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 26c6908d9cd9..cfe5b0f8d04a 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -338,26 +338,6 @@ config PCI_MMCONFIG
depends on PCI
select ACPI_BOOT
-# the drivers/pci/msi.c code needs to be fixed first before enabling
-config PCI_USE_VECTOR
- bool "Vector-based interrupt indexing"
- depends on X86_LOCAL_APIC && NOTWORKING
- default n
- help
- This replaces the current existing IRQ-based index interrupt scheme
- with the vector-base index scheme. The advantages of vector base
- over IRQ base are listed below:
- 1) Support MSI implementation.
- 2) Support future IOxAPIC hotplug
-
- Note that this enables MSI, Message Signaled Interrupt, on all
- MSI capable device functions detected if users also install the
- MSI patch. Message Signal Interrupt enables an MSI-capable
- hardware device to send an inbound Memory Write on its PCI bus
- instead of asserting IRQ signal on device IRQ pin.
-
- If you don't know what to do here, say N.
-
source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 1a828de6a55d..7e56a4bc372a 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -85,8 +85,8 @@ int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from)
err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user((u32)(u64)from->si_ptr, &to->si_ptr);
break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ:
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int);
break;
diff --git a/drivers/block/floppy98.c b/drivers/block/floppy98.c
index 450cf5a58895..81b28c1b77c6 100644
--- a/drivers/block/floppy98.c
+++ b/drivers/block/floppy98.c
@@ -168,8 +168,11 @@ static int print_unex=1;
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/version.h>
-#define FDPATCHES
#include <linux/fdreg.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/cdrom.h> /* for the compatibility eject ioctl */
+#include <linux/completion.h>
/*
* 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
@@ -179,7 +182,6 @@ static int print_unex=1;
#include <linux/fd.h>
#define FLOPPY98_MOTOR_MASK 0x08
-#define FDPATCHES
#include <linux/hdreg.h>
#define FD98_STATUS (0 + FD_IOPORT )
#define FD98_DATA (2 + FD_IOPORT )
@@ -250,9 +252,10 @@ static int use_virtual_dma;
*/
static spinlock_t floppy_lock = SPIN_LOCK_UNLOCKED;
+static struct completion device_release;
static unsigned short virtual_dma_port=0x3f0;
-void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int set_mode(char mask, char data);
static void register_devfs_entries (int drive) __init;
@@ -987,9 +990,9 @@ static void empty(void)
static DECLARE_WORK(floppy_work, NULL, NULL);
-static void schedule_bh( void (*handler)(void*) )
+static void schedule_bh(void (*handler) (void))
{
- PREPARE_WORK(&floppy_work, handler, NULL);
+ PREPARE_WORK(&floppy_work, (void (*)(void *))handler, NULL);
schedule_work(&floppy_work);
}
@@ -1627,7 +1630,7 @@ static void print_result(char *message, int inr)
}
/* interrupt handler. Note that this can be called externally on the Sparc */
-void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
void (*handler)(void) = do_floppy;
int do_print;
@@ -1648,7 +1651,7 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
printk("floppy interrupt on bizarre fdc %d\n",fdc);
printk("handler=%p\n", handler);
is_alive("bizarre fdc");
- return;
+ return IRQ_NONE;
}
FDCS->reset = 0;
@@ -1661,7 +1664,7 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* activity.
*/
- do_print = !handler && !initialising;
+ do_print = !handler && print_unex && !initialising;
inr = result();
if (inr && do_print)
@@ -1701,13 +1704,16 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2);
}
if (handler) {
- schedule_bh( (void *)(void *) handler);
+ schedule_bh(handler);
} else {
#if 0
FDCS->reset = 1;
#endif
}
is_alive("normal interrupt end");
+
+ /* FIXME! Was it really for us? */
+ return IRQ_HANDLED;
}
static void recalibrate_floppy(void)
@@ -4231,11 +4237,16 @@ static int __init floppy_setup(char *str)
static int have_no_fdc= -ENODEV;
+static void floppy_device_release(struct device *dev)
+{
+ complete(&device_release);
+}
+
static struct platform_device floppy_device = {
.name = "floppy",
.id = 0,
.dev = {
- .name = "Floppy Drive",
+ .release = floppy_device_release,
},
};
@@ -4267,10 +4278,8 @@ int __init floppy_init(void)
}
devfs_mk_dir (NULL, "floppy", NULL);
- if (register_blkdev(FLOPPY_MAJOR,"fd")) {
- err = -EBUSY;
+ if ((err = register_blkdev(FLOPPY_MAJOR,"fd")))
goto out;
- }
for (i=0; i<N_DRIVE; i++) {
disks[i]->major = FLOPPY_MAJOR;
@@ -4288,7 +4297,7 @@ int __init floppy_init(void)
else
floppy_sizes[i] = MAX_DISK_SIZE << 1;
- floppy_queue = blk_init_queue(do_fd_request, &floppy_lock)
+ floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
if (!floppy_queue)
goto out_queue;
@@ -4628,10 +4637,14 @@ void cleanup_module(void)
{
int drive;
+ init_completion(&device_release);
platform_device_unregister(&floppy_device);
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
unregister_blkdev(FLOPPY_MAJOR, "fd");
+
for (drive = 0; drive < N_DRIVE; drive++) {
+ del_timer_sync(&motor_off_timer[drive]);
+
if ((allowed_drive_mask & (1 << drive)) &&
fdc_state[FDC(drive)].version != FDC_NONE) {
del_gendisk(disks[drive]);
@@ -4641,9 +4654,17 @@ void cleanup_module(void)
}
devfs_remove("floppy");
+ del_timer_sync(&fd_timeout);
+ del_timer_sync(&fd_timer);
blk_cleanup_queue(floppy_queue);
+
+ if (usage_count)
+ floppy_release_irq_and_dma();
+
/* eject disk, if any */
fd_eject(0);
+
+ wait_for_completion(&device_release);
}
MODULE_PARM(floppy,"s");
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 5ee752d64f4a..85dac0809fb2 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -2429,7 +2429,7 @@ EXPORT_SYMBOL(generic_make_request);
* interfaces, @bio must be presetup and ready for I/O.
*
*/
-int submit_bio(int rw, struct bio *bio)
+void submit_bio(int rw, struct bio *bio)
{
int count = bio_sectors(bio);
@@ -2451,7 +2451,6 @@ int submit_bio(int rw, struct bio *bio)
}
generic_make_request(bio);
- return 1;
}
EXPORT_SYMBOL(submit_bio);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 42b7e5d22de9..34ceaeed6890 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -51,6 +51,7 @@
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#ifdef CONFIG_HIGH_RES_TIMERS
#include <linux/hrtime.h>
# if defined(schedule_next_int)
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 72915e2ae07c..26e07286e21f 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -800,7 +800,7 @@ static void retrieve_status(struct dm_table *table,
struct dm_target *ti = dm_table_get_target(table, i);
remaining = len - (outptr - outbuf);
- if (remaining < sizeof(struct dm_target_spec)) {
+ if (remaining <= sizeof(struct dm_target_spec)) {
param->flags |= DM_BUFFER_FULL_FLAG;
break;
}
@@ -815,6 +815,10 @@ static void retrieve_status(struct dm_table *table,
outptr += sizeof(struct dm_target_spec);
remaining = len - (outptr - outbuf);
+ if (remaining <= 0) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
/* Get the status/table string from the target driver */
if (ti->type->status) {
@@ -828,7 +832,7 @@ static void retrieve_status(struct dm_table *table,
outptr += strlen(outptr) + 1;
used = param->data_start + (outptr - outbuf);
- align_ptr(outptr);
+ outptr = align_ptr(outptr);
spec->next = outptr - outbuf;
}
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index ce6da00c82a0..b5bacd717760 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -187,24 +187,24 @@ static int stripe_status(struct dm_target *ti,
status_type_t type, char *result, unsigned int maxlen)
{
struct stripe_c *sc = (struct stripe_c *) ti->private;
- int offset;
+ unsigned int sz = 0;
unsigned int i;
char buffer[32];
+#define EMIT(x...) sz += ((sz >= maxlen) ? \
+ 0 : scnprintf(result + sz, maxlen - sz, x))
+
switch (type) {
case STATUSTYPE_INFO:
result[0] = '\0';
break;
case STATUSTYPE_TABLE:
- offset = scnprintf(result, maxlen, "%d " SECTOR_FORMAT,
- sc->stripes, sc->chunk_mask + 1);
+ EMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1);
for (i = 0; i < sc->stripes; i++) {
format_dev_t(buffer, sc->stripe[i].dev->bdev->bd_dev);
- offset +=
- scnprintf(result + offset, maxlen - offset,
- " %s " SECTOR_FORMAT, buffer,
- sc->stripe[i].physical_start);
+ EMIT(" %s " SECTOR_FORMAT, buffer,
+ sc->stripe[i].physical_start);
}
break;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 93dc0e6361c0..87df3e90fc4f 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -663,12 +663,14 @@ int dm_table_add_target(struct dm_table *t, const char *type,
if (!len) {
tgt->error = "zero-length target";
+ DMERR(": %s\n", tgt->error);
return -EINVAL;
}
tgt->type = dm_get_target_type(type);
if (!tgt->type) {
tgt->error = "unknown target type";
+ DMERR(": %s\n", tgt->error);
return -EINVAL;
}
@@ -705,7 +707,7 @@ int dm_table_add_target(struct dm_table *t, const char *type,
return 0;
bad:
- printk(KERN_ERR DM_NAME ": %s\n", tgt->error);
+ DMERR(": %s\n", tgt->error);
dm_put_target_type(tgt->type);
return r;
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 542f9cd0acc0..0270a5659727 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -294,6 +294,9 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
if (bio->bi_size)
return 1;
+ if (!bio_flagged(bio, BIO_UPTODATE) && !error)
+ error = -EIO;
+
if (endio) {
r = endio(tio->ti, bio, error, &tio->info);
if (r < 0)
@@ -745,7 +748,7 @@ static void event_callback(void *context)
down_write(&md->lock);
md->event_nr++;
- wake_up_interruptible(&md->eventq);
+ wake_up(&md->eventq);
up_write(&md->lock);
}
@@ -922,7 +925,7 @@ int dm_suspend(struct mapped_device *md)
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!atomic_read(&md->pending))
+ if (!atomic_read(&md->pending) || signal_pending(current))
break;
io_schedule();
@@ -931,6 +934,14 @@ int dm_suspend(struct mapped_device *md)
down_write(&md->lock);
remove_wait_queue(&md->wait, &wait);
+
+ /* were we interrupted ? */
+ if (atomic_read(&md->pending)) {
+ clear_bit(DMF_BLOCK_IO, &md->flags);
+ up_write(&md->lock);
+ return -EINTR;
+ }
+
set_bit(DMF_SUSPENDED, &md->flags);
map = dm_get_table(md);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 268e5084f7a0..b8f764fd210f 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -1,6 +1,25 @@
#
# PCI configuration
#
+config PCI_USE_VECTOR
+ bool "Vector-based interrupt indexing (MSI)"
+ depends on (X86_LOCAL_APIC && X86_IO_APIC && !X86_64) || IA64
+ default n
+ help
+ This replaces the current existing IRQ-based index interrupt scheme
+ with the vector-base index scheme. The advantages of vector base
+ over IRQ base are listed below:
+ 1) Support MSI implementation.
+ 2) Support future IOxAPIC hotplug
+
+ Note that this allows the device drivers to enable MSI, Message
+ Signaled Interrupt, on all MSI capable device functions detected.
+ Message Signal Interrupt enables an MSI-capable hardware device to
+ send an inbound Memory Write on its PCI bus instead of asserting
+ IRQ signal on device IRQ pin.
+
+ If you don't know what to do here, say N.
+
config PCI_LEGACY_PROC
bool "Legacy /proc/pci interface"
depends on PCI
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 693a10f91cec..d975ad35aa52 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -33,6 +33,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/major.h>
@@ -78,7 +79,7 @@ static const u_int exponent[] = {
/* Parameters that can be set with 'insmod' */
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 881561fd7fa9..c92a8b6eb176 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -94,7 +94,7 @@ MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS);
MODULE_LICENSE("Dual MPL/GPL");
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
INT_MODULE_PARM(setup_delay, 10); /* centiseconds */
INT_MODULE_PARM(resume_delay, 20); /* centiseconds */
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 5afbc805113d..ec5ff85cde4a 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -104,7 +104,8 @@ static int extra_sockets = 0;
static int ignore = -1;
/* Bit map or list of interrupts to choose from */
static u_int irq_mask = 0xffff;
-static int irq_list[16] = { -1 };
+static int irq_list[16];
+static int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq = 0;
@@ -130,27 +131,27 @@ static int async_clock = -1;
static int cable_mode = -1;
static int wakeup = 0;
-MODULE_PARM(i365_base, "i");
-MODULE_PARM(ignore, "i");
-MODULE_PARM(extra_sockets, "i");
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-16i");
-MODULE_PARM(cs_irq, "i");
-MODULE_PARM(async_clock, "i");
-MODULE_PARM(cable_mode, "i");
-MODULE_PARM(wakeup, "i");
-
-MODULE_PARM(do_scan, "i");
-MODULE_PARM(poll_interval, "i");
-MODULE_PARM(cycle_time, "i");
-MODULE_PARM(has_dma, "i");
-MODULE_PARM(has_led, "i");
-MODULE_PARM(has_ring, "i");
-MODULE_PARM(dynamic_mode, "i");
-MODULE_PARM(freq_bypass, "i");
-MODULE_PARM(setup_time, "i");
-MODULE_PARM(cmd_time, "i");
-MODULE_PARM(recov_time, "i");
+module_param(i365_base, int, 0444);
+module_param(ignore, int, 0444);
+module_param(extra_sockets, int, 0444);
+module_param(irq_mask, int, 0444);
+module_param_array(irq_list, int, irq_list_count, 0444);
+module_param(cs_irq, int, 0444);
+module_param(async_clock, int, 0444);
+module_param(cable_mode, int, 0444);
+module_param(wakeup, int, 0444);
+
+module_param(do_scan, int, 0444);
+module_param(poll_interval, int, 0444);
+module_param(cycle_time, int, 0444);
+module_param(has_dma, int, 0444);
+module_param(has_led, int, 0444);
+module_param(has_ring, int, 0444);
+module_param(dynamic_mode, int, 0444);
+module_param(freq_bypass, int, 0444);
+module_param(setup_time, int, 0444);
+module_param(cmd_time, int, 0444);
+module_param(recov_time, int, 0444);
/*====================================================================*/
@@ -705,10 +706,10 @@ static void __init add_pcic(int ns, int type)
printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
/* Set host options, build basic interrupt mask */
- if (irq_list[0] == -1)
+ if (irq_list_count == 0)
mask = irq_mask;
else
- for (i = mask = 0; i < 16; i++)
+ for (i = mask = 0; i < irq_list_count; i++)
mask |= (1<<irq_list[i]);
mask &= I365_MASK & set_bridge_opts(base, ns);
/* Scan for ISA interrupts */
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index bd110ae66916..8aeb21af08e2 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -33,6 +33,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -56,7 +57,7 @@
/* Parameters that can be set with 'insmod' */
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
#ifdef CONFIG_PCMCIA_PROBE
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 82ba1aff2290..5f9b4be82276 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -60,7 +60,6 @@
static int pc_debug;
module_param(pc_debug, int, 0644);
-MODULE_PARM(pc_debug, "i");
static const char *version =
"tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)";
@@ -91,7 +90,8 @@ static int do_scan = 1;
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xffff;
-static int irq_list[16] = { -1 };
+static int irq_list[16];
+static int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq;
@@ -105,15 +105,15 @@ static int poll_quick = HZ/20;
/* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */
static int cycle_time = 70;
-MODULE_PARM(tcic_base, "i");
-MODULE_PARM(ignore, "i");
-MODULE_PARM(do_scan, "i");
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-16i");
-MODULE_PARM(cs_irq, "i");
-MODULE_PARM(poll_interval, "i");
-MODULE_PARM(poll_quick, "i");
-MODULE_PARM(cycle_time, "i");
+module_param(tcic_base, int, 0444);
+module_param(ignore, int, 0444);
+module_param(do_scan, int, 0444);
+module_param(irq_mask, int, 0444);
+module_param_array(irq_list, int, irq_list_count, 0444);
+module_param(cs_irq, int, 0444);
+module_param(poll_interval, int, 0444);
+module_param(poll_quick, int, 0444);
+module_param(cycle_time, int, 0444);
/*====================================================================*/
@@ -481,10 +481,10 @@ static int __init init_tcic(void)
/* Build interrupt mask */
printk(", %d sockets\n" KERN_INFO " irq list (", sockets);
- if (irq_list[0] == -1)
+ if (irq_list_count == 0)
mask = irq_mask;
else
- for (i = mask = 0; i < 16; i++)
+ for (i = mask = 0; i < irq_list_count; i++)
mask |= (1<<irq_list[i]);
/* irq 14, 11, 10, 7, 6, 5, 4, 3 */
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 589a4134af8a..d61f7a24f98e 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -21,6 +21,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
@@ -117,11 +118,11 @@ static struct old_serial_port old_serial_port[] = {
#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS)
-#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
+#ifdef CONFIG_SERIAL_8250_RSA
#define PORT_RSA_MAX 4
-static int probe_rsa[PORT_RSA_MAX];
-static int force_rsa[PORT_RSA_MAX];
+static unsigned long probe_rsa[PORT_RSA_MAX];
+static unsigned int probe_rsa_count;
#endif /* CONFIG_SERIAL_8250_RSA */
struct uart_8250_port {
@@ -678,21 +679,16 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
break;
}
-#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
+#ifdef CONFIG_SERIAL_8250_RSA
/*
* Only probe for RSA ports if we got the region.
*/
if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
int i;
- for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
- if (!probe_rsa[i] && !force_rsa[i])
- break;
- if (((probe_rsa[i] != up->port.iobase) ||
- check_region(up->port.iobase + UART_RSA_BASE, 16)) &&
- (force_rsa[i] != up->port.iobase))
- continue;
- if (__enable_rsa(up)) {
+ for (i = 0 ; i < probe_rsa_count; ++i) {
+ if (probe_rsa[i] == up->port.iobase &&
+ __enable_rsa(up)) {
up->port.type = PORT_RSA;
break;
}
@@ -2215,14 +2211,12 @@ EXPORT_SYMBOL(serial8250_resume_port);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $");
-MODULE_PARM(share_irqs, "i");
+module_param(share_irqs, uint, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
" (unsafe)");
-#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
-MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+#ifdef CONFIG_SERIAL_8250_RSA
+module_param_array(probe_rsa, ulong, probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
-MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
-MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
#endif
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index e4bece38efed..c3e6eb244e9f 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -32,6 +32,7 @@
======================================================================*/
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
@@ -71,17 +72,18 @@ static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
+static int irq_list[4];
+static unsigned int irq_list_count;
/* Enable the speaker? */
static int do_sound = 1;
/* Skip strict UART tests? */
static int buggy_uart;
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(do_sound, "i");
-MODULE_PARM(buggy_uart, "i");
+module_param(irq_mask, uint, 0444);
+module_param_array(irq_list, int, irq_list_count, 0444);
+module_param(do_sound, int, 0444);
+module_param(buggy_uart, int, 0444);
/*====================================================================*/
@@ -221,10 +223,10 @@ static dev_link_t *serial_attach(void)
link->io.NumPorts1 = 8;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
+ if (irq_list_count == 0)
link->irq.IRQInfo2 = irq_mask;
else
- for (i = 0; i < 4; i++)
+ for (i = 0; i < irq_list_count; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index a0a7dbd97915..b19eded6cb8b 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1998,11 +1998,13 @@ err_free_fb:
static void __devexit aty128_remove(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
- struct aty128fb_par *par = info->par;
+ struct aty128fb_par *par;
if (!info)
return;
+ par = info->par;
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
diff --git a/fs/buffer.c b/fs/buffer.c
index 99f1ce112ea9..21b8ae31e827 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -51,25 +51,6 @@ static struct bh_wait_queue_head {
wait_queue_head_t wqh;
} ____cacheline_aligned_in_smp bh_wait_queue_heads[1<<BH_WAIT_TABLE_ORDER];
-/*
- * Debug/devel support stuff
- */
-
-void __buffer_error(char *file, int line)
-{
- static int enough;
-
- if (enough > 10)
- return;
- enough++;
- printk("buffer layer error at %s:%d\n", file, line);
-#ifndef CONFIG_KALLSYMS
- printk("Pass this trace through ksymoops for reporting\n");
-#endif
- dump_stack();
-}
-EXPORT_SYMBOL(__buffer_error);
-
inline void
init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
{
@@ -99,17 +80,6 @@ EXPORT_SYMBOL(wake_up_buffer);
void fastcall unlock_buffer(struct buffer_head *bh)
{
- /*
- * unlock_buffer against a zero-count bh is a bug, if the page
- * is not locked. Because then nothing protects the buffer's
- * waitqueue, which is used here. (Well. Other locked buffers
- * against the page will pin it. But complain anyway).
- */
- if (atomic_read(&bh->b_count) == 0 &&
- !PageLocked(bh->b_page) &&
- !PageWriteback(bh->b_page))
- buffer_error();
-
clear_buffer_locked(bh);
smp_mb__after_clear_bit();
wake_up_buffer(bh);
@@ -125,10 +95,6 @@ void __wait_on_buffer(struct buffer_head * bh)
wait_queue_head_t *wqh = bh_waitq_head(bh);
DEFINE_WAIT(wait);
- if (atomic_read(&bh->b_count) == 0 &&
- (!bh->b_page || !PageLocked(bh->b_page)))
- buffer_error();
-
do {
prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
if (buffer_locked(bh)) {
@@ -146,8 +112,6 @@ void __wait_on_buffer(struct buffer_head * bh)
static void
__set_page_buffers(struct page *page, struct buffer_head *head)
{
- if (page_has_buffers(page))
- buffer_error();
page_cache_get(page);
SetPagePrivate(page);
page->private = (unsigned long)head;
@@ -433,10 +397,12 @@ __find_get_block_slow(struct block_device *bdev, sector_t block, int unused)
}
bh = bh->b_this_page;
} while (bh != head);
- buffer_error();
- printk("block=%llu, b_blocknr=%llu\n",
+
+ printk("__find_get_block_slow() failed. "
+ "block=%llu, b_blocknr=%llu\n",
(unsigned long long)block, (unsigned long long)bh->b_blocknr);
printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size);
+ printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
out_unlock:
spin_unlock(&bd_mapping->private_lock);
page_cache_release(page);
@@ -847,10 +813,7 @@ int __set_page_dirty_buffers(struct page *page)
struct buffer_head *bh = head;
do {
- if (buffer_uptodate(bh))
- set_buffer_dirty(bh);
- else
- buffer_error();
+ set_buffer_dirty(bh);
bh = bh->b_this_page;
} while (bh != head);
}
@@ -1151,7 +1114,7 @@ grow_dev_page(struct block_device *bdev, sector_t block,
return page;
failed:
- buffer_error();
+ BUG();
unlock_page(page);
page_cache_release(page);
return NULL;
@@ -1247,8 +1210,6 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
*/
void fastcall mark_buffer_dirty(struct buffer_head *bh)
{
- if (!buffer_uptodate(bh))
- buffer_error();
if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh))
__set_page_dirty_nobuffers(bh->b_page);
}
@@ -1267,7 +1228,7 @@ void __brelse(struct buffer_head * buf)
return;
}
printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n");
- buffer_error(); /* For the stack backtrace */
+ WARN_ON(1);
}
/*
@@ -1294,8 +1255,6 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
unlock_buffer(bh);
return bh;
} else {
- if (buffer_dirty(bh))
- buffer_error();
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
submit_bh(READ, bh);
@@ -1686,10 +1645,6 @@ void unmap_underlying_metadata(struct block_device *bdev, sector_t block)
old_bh = __find_get_block_slow(bdev, block, 0);
if (old_bh) {
-#if 0 /* This happens. Later. */
- if (buffer_dirty(old_bh))
- buffer_error();
-#endif
clear_buffer_dirty(old_bh);
wait_on_buffer(old_bh);
clear_buffer_req(old_bh);
@@ -1737,8 +1692,6 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
if (!page_has_buffers(page)) {
- if (!PageUptodate(page))
- buffer_error();
create_empty_buffers(page, 1 << inode->i_blkbits,
(1 << BH_Dirty)|(1 << BH_Uptodate));
}
@@ -1767,9 +1720,6 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
* mapped buffers outside i_size will occur, because
* this page can be outside i_size when there is a
* truncate in progress.
- *
- * if (buffer_mapped(bh))
- * buffer_error();
*/
/*
* The buffer was zeroed by block_write_full_page()
@@ -1777,8 +1727,6 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
clear_buffer_dirty(bh);
set_buffer_uptodate(bh);
} else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
- if (buffer_new(bh))
- buffer_error();
err = get_block(inode, block, bh, 1);
if (err)
goto recover;
@@ -1811,8 +1759,6 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
continue;
}
if (test_clear_buffer_dirty(bh)) {
- if (!buffer_uptodate(bh))
- buffer_error();
mark_buffer_async_write(bh);
} else {
unlock_buffer(bh);
@@ -1942,8 +1888,6 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
unmap_underlying_metadata(bh->b_bdev,
bh->b_blocknr);
if (PageUptodate(page)) {
- if (!buffer_mapped(bh))
- buffer_error();
set_buffer_uptodate(bh);
continue;
}
@@ -2001,8 +1945,6 @@ out:
void *kaddr;
clear_buffer_new(bh);
- if (buffer_uptodate(bh))
- buffer_error();
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr+block_start, 0, bh->b_size);
kunmap_atomic(kaddr, KM_USER0);
@@ -2068,8 +2010,6 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (!PageLocked(page))
PAGE_BUG(page);
- if (PageUptodate(page))
- buffer_error();
blocksize = 1 << inode->i_blkbits;
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
@@ -2684,7 +2624,7 @@ static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err)
return 0;
}
-int submit_bh(int rw, struct buffer_head * bh)
+void submit_bh(int rw, struct buffer_head * bh)
{
struct bio *bio;
@@ -2692,13 +2632,6 @@ int submit_bh(int rw, struct buffer_head * bh)
BUG_ON(!buffer_mapped(bh));
BUG_ON(!bh->b_end_io);
- if ((rw == READ || rw == READA) && buffer_uptodate(bh))
- buffer_error();
- if (rw == WRITE && !buffer_uptodate(bh))
- buffer_error();
- if (rw == READ && buffer_dirty(bh))
- buffer_error();
-
/* Only clear out a write error when rewriting */
if (test_set_buffer_req(bh) && rw == WRITE)
clear_buffer_write_io_error(bh);
@@ -2722,7 +2655,7 @@ int submit_bh(int rw, struct buffer_head * bh)
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
- return submit_bio(rw, bio);
+ submit_bio(rw, bio);
}
/**
@@ -2798,21 +2731,6 @@ void sync_dirty_buffer(struct buffer_head *bh)
}
/*
- * Sanity checks for try_to_free_buffers.
- */
-static void check_ttfb_buffer(struct page *page, struct buffer_head *bh)
-{
- if (!buffer_uptodate(bh) && !buffer_req(bh)) {
- if (PageUptodate(page) && page->mapping
- && buffer_mapped(bh) /* discard_buffer */
- && S_ISBLK(page->mapping->host->i_mode))
- {
- buffer_error();
- }
- }
-}
-
-/*
* try_to_free_buffers() checks if all the buffers on this particular page
* are unused, and releases them if so.
*
@@ -2847,7 +2765,6 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = head;
do {
- check_ttfb_buffer(page, bh);
if (buffer_write_io_error(bh))
set_bit(AS_EIO, &page->mapping->flags);
if (buffer_busy(bh))
@@ -2857,9 +2774,6 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = bh->b_this_page;
} while (bh != head);
- if (!was_uptodate && PageUptodate(page) && !PageError(page))
- buffer_error();
-
do {
struct buffer_head *next = bh->b_this_page;
diff --git a/fs/exec.c b/fs/exec.c
index 1ea7c8d6c898..c37b1478fdac 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -609,7 +609,9 @@ static inline int de_thread(struct task_struct *tsk)
newsig->group_stop_count = 0;
newsig->curr_target = NULL;
init_sigpending(&newsig->shared_pending);
+ INIT_LIST_HEAD(&newsig->posix_timers);
+ newsig->tty = oldsig->tty;
newsig->pgrp = oldsig->pgrp;
newsig->session = oldsig->session;
newsig->leader = oldsig->leader;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index f5333b88376b..929b643115b8 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1358,8 +1358,6 @@ static int ext3_ordered_writepage(struct page *page,
}
if (!page_has_buffers(page)) {
- if (!PageUptodate(page))
- buffer_error();
create_empty_buffers(page, inode->i_sb->s_blocksize,
(1 << BH_Dirty)|(1 << BH_Uptodate));
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 1f7d045fa905..a22fc8f0ba9b 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -485,8 +485,7 @@ mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
break;
block_in_file++;
}
- if (page_block == 0)
- buffer_error();
+ BUG_ON(page_block == 0);
first_unmapped = page_block;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 439157bbab45..d8765a09327f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -66,10 +66,31 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src)
}
static int
+do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+ int accmode, status;
+
+ if (open->op_truncate &&
+ !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+ return nfserr_inval;
+
+ accmode = MAY_NOP;
+ if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
+ accmode = MAY_READ;
+ if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
+ accmode |= (MAY_WRITE | MAY_TRUNC);
+ accmode |= MAY_OWNER_OVERRIDE;
+
+ status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+
+ return status;
+}
+
+static int
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct svc_fh resfh;
- int accmode, status;
+ int status;
fh_init(&resfh, NFS4_FHSIZE);
open->op_truncate = 0;
@@ -92,6 +113,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
if (!status) {
set_change_info(&open->op_cinfo, current_fh);
+
+ /* set reply cache */
fh_dup2(current_fh, &resfh);
/* XXXJBF: keep a saved svc_fh struct instead?? */
open->op_stateowner->so_replay.rp_openfh_len =
@@ -100,30 +123,66 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
&resfh.fh_handle.fh_base,
resfh.fh_handle.fh_size);
- accmode = MAY_NOP;
- if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
- accmode = MAY_READ;
- if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
- accmode |= (MAY_WRITE | MAY_TRUNC);
- accmode |= MAY_OWNER_OVERRIDE;
- status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+ status = do_open_permission(rqstp, current_fh, open);
}
fh_put(&resfh);
return status;
}
+static int
+do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+ int status;
+
+ dprintk("NFSD: do_open_fhandle\n");
+
+ /* we don't know the target directory, and therefore can not
+ * set the change info
+ */
+
+ memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
+
+ /* set replay cache */
+ open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size;
+ memcpy(open->op_stateowner->so_replay.rp_openfh,
+ &current_fh->fh_handle.fh_base,
+ current_fh->fh_handle.fh_size);
+
+ open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
+ !open->op_iattr.ia_size;
+
+ status = do_open_permission(rqstp, current_fh, open);
+
+ return status;
+}
+
+
+/*
+ * nfs4_unlock_state() called in encode
+ */
static inline int
nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
int status;
- dprintk("NFSD: nfsd4_open filename %.*s\n",
- (int)open->op_fname.len, open->op_fname.data);
+ dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
+ (int)open->op_fname.len, open->op_fname.data,
+ open->op_stateowner);
+
+ if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_grace;
+
+ if (nfs4_in_no_grace() &&
+ open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_no_grace;
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
+ open->op_stateowner = NULL;
+ nfs4_lock_state();
+
/* check seqid for replay. set nfs4_owner */
status = nfsd4_process_open1(open);
if (status == NFSERR_REPLAY_ME) {
@@ -141,16 +200,30 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
}
if (status)
return status;
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) {
/*
* This block of code will (1) set CURRENT_FH to the file being opened,
* creating it if necessary, (2) set open->op_cinfo,
* (3) set open->op_truncate if the file is to be truncated
* after opening, (4) do permission checking.
*/
- status = do_open_lookup(rqstp, current_fh, open);
- if (status)
- return status;
-
+ status = do_open_lookup(rqstp, current_fh, open);
+ if (status)
+ return status;
+ } else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
+ /*
+ * The CURRENT_FH is already set to the file being opened. This
+ * block of code will (1) set open->op_cinfo, (2) set
+ * open->op_truncate if the file is to be truncated after opening,
+ * (3) do permission checking.
+ */
+ status = do_open_fhandle(rqstp, current_fh, open);
+ if (status)
+ return status;
+ } else {
+ printk("NFSD: unsupported OPEN claim type\n");
+ return nfserr_inval;
+ }
/*
* nfsd4_process_open2() does the actual opening of the file. If
* successful, it (1) truncates the file if open->op_truncate was
@@ -187,9 +260,14 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putf
static inline int
nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
{
+ int status;
+
fh_put(current_fh);
- return exp_pseudoroot(rqstp->rq_client, current_fh,
+ status = exp_pseudoroot(rqstp->rq_client, current_fh,
&rqstp->rq_chandle);
+ if (!status)
+ status = nfsd_setuser(rqstp, current_fh->fh_export);
+ return status;
}
static inline int
@@ -402,6 +480,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read
int status;
/* no need to check permission - this will be done in nfsd_read() */
+ if (nfs4_in_grace())
+ return nfserr_grace;
if (read->rd_offset >= OFFSET_MAX)
return nfserr_inval;
@@ -448,6 +528,9 @@ out:
static inline int
nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
{
+ u64 cookie = readdir->rd_cookie;
+ static const nfs4_verifier zeroverf;
+
/* no need to check permission - this will be done in nfsd_readdir() */
if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
@@ -456,7 +539,8 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re
readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
- if (readdir->rd_cookie > ~(u32)0)
+ if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
+ (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
return nfserr_bad_cookie;
readdir->rd_rqstp = rqstp;
@@ -521,10 +605,13 @@ static inline int
nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
{
struct nfs4_stateid *stp;
- int status = nfserr_nofilehandle;
+ int status = nfs_ok;
+
+ if (nfs4_in_grace())
+ return nfserr_grace;
if (!current_fh->fh_dentry)
- goto out;
+ return nfserr_nofilehandle;
status = nfs_ok;
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
@@ -563,6 +650,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
u32 *p;
int status = nfs_ok;
+ if (nfs4_in_grace())
+ return nfserr_grace;
+
/* no need to check permission - this will be done in nfsd_write() */
if (write->wr_offset >= OFFSET_MAX)
@@ -757,7 +847,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
break;
case OP_CLOSE:
op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
- op->replay = &op->u.close.cl_stateowner->so_replay;
+ if (op->u.close.cl_stateowner)
+ op->replay =
+ &op->u.close.cl_stateowner->so_replay;
break;
case OP_COMMIT:
op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
@@ -776,13 +868,18 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
break;
case OP_LOCK:
op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
- op->replay = &op->u.lock.lk_stateowner->so_replay;
+ if (op->u.lock.lk_stateowner)
+ op->replay =
+ &op->u.lock.lk_stateowner->so_replay;
break;
case OP_LOCKT:
op->status = nfsd4_lockt(rqstp, &current_fh, &op->u.lockt);
break;
case OP_LOCKU:
op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku);
+ if (op->u.locku.lu_stateowner)
+ op->replay =
+ &op->u.locku.lu_stateowner->so_replay;
break;
case OP_LOOKUP:
op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
@@ -797,15 +894,21 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
break;
case OP_OPEN:
op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
- op->replay = &op->u.open.op_stateowner->so_replay;
+ if (op->u.open.op_stateowner)
+ op->replay =
+ &op->u.open.op_stateowner->so_replay;
break;
case OP_OPEN_CONFIRM:
op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
- op->replay = &op->u.open_confirm.oc_stateowner->so_replay;
+ if (op->u.open_confirm.oc_stateowner)
+ op->replay =
+ &op->u.open_confirm.oc_stateowner->so_replay;
break;
case OP_OPEN_DOWNGRADE:
op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
- op->replay = &op->u.open_downgrade.od_stateowner->so_replay;
+ if (op->u.open_downgrade.od_stateowner)
+ op->replay =
+ &op->u.open_downgrade.od_stateowner->so_replay;
break;
case OP_PUTFH:
op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 13ca74de2a21..73a8944ad96e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -52,6 +52,7 @@
/* Globals */
time_t boot_time;
+static time_t grace_end = 0;
static u32 current_clientid = 1;
static u32 current_ownerid;
static u32 current_fileid;
@@ -89,6 +90,9 @@ nfs4_lock_state(void)
down(&client_sema);
}
+/*
+ * nfs4_unlock_state(); called in encode
+ */
void
nfs4_unlock_state(void)
{
@@ -136,12 +140,16 @@ static void release_file(struct nfs4_file *fp);
*
* client_lru holds client queue ordered by nfs4_client.cl_time
* for lease renewal.
+ *
+ * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
+ * for last close replay.
*/
static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE];
static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE];
static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE];
static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
static struct list_head client_lru;
+static struct list_head close_lru;
static inline void
renew_client(struct nfs4_client *clp)
@@ -376,7 +384,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
unsigned int strhashval;
struct nfs4_client * conf, * unconf, * new, * clp;
int status;
- struct list_head *pos, *next;
status = nfserr_inval;
if (!check_name(clname))
@@ -391,8 +398,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
conf = NULL;
nfs4_lock_state();
- list_for_each_safe(pos, next, &conf_str_hashtbl[strhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_strhash);
+ list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {
if (!cmp_name(&clp->cl_name, &clname))
continue;
/*
@@ -422,8 +428,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
break;
}
unconf = NULL;
- list_for_each_safe(pos, next, &unconf_str_hashtbl[strhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_strhash);
+ list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {
if (!cmp_name(&clp->cl_name, &clname))
continue;
/* cl_name match from a previous SETCLIENTID operation */
@@ -549,7 +554,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
clientid_t * clid = &setclientid_confirm->sc_clientid;
- struct list_head *pos, *next;
int status;
status = nfserr_stale_clientid;
@@ -562,8 +566,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
idhashval = clientid_hashval(clid->cl_id);
nfs4_lock_state();
- list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_idhash);
+ list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
if (!cmp_clid(&clp->cl_clientid, clid))
continue;
@@ -582,8 +585,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
conf = clp;
break;
}
- list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_idhash);
+ list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
if (!cmp_clid(&clp->cl_clientid, clid))
continue;
status = nfserr_inval;
@@ -774,6 +776,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_perfilestate);
INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */
+ INIT_LIST_HEAD(&sop->so_close_lru);
+ sop->so_time = 0;
list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
list_add(&sop->so_perclient, &clp->cl_perclient);
@@ -814,6 +818,7 @@ release_stateowner(struct nfs4_stateowner *sop)
list_del(&sop->so_strhash);
list_del(&sop->so_perclient);
list_del(&sop->so_perlockowner);
+ list_del(&sop->so_close_lru);
del_perclient++;
while (!list_empty(&sop->so_perfilestate)) {
stp = list_entry(sop->so_perfilestate.next,
@@ -882,6 +887,19 @@ release_file(struct nfs4_file *fp)
}
void
+move_to_close_lru(struct nfs4_stateowner *sop)
+{
+ dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
+ /* remove stateowner from all other hash lists except perclient */
+ list_del_init(&sop->so_idhash);
+ list_del_init(&sop->so_strhash);
+ list_del_init(&sop->so_perlockowner);
+
+ list_add_tail(&sop->so_close_lru, &close_lru);
+ sop->so_time = get_seconds();
+}
+
+void
release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
int flag)
{
@@ -890,16 +908,13 @@ release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
dprintk("NFSD: release_state_owner\n");
release_stateid(stp, flag);
- /*
- * release unused nfs4_stateowners.
- * XXX will need to be placed on an open_stateid_lru list to be
+
+ /* place unused nfs4_stateowners on so_close_lru list to be
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) {
- release_stateowner(sop);
- *sopp = NULL;
- }
+ if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
+ move_to_close_lru(sop);
/* unused nfs4_file's are releseed. XXX slab cache? */
if (list_empty(&fp->fi_perfile)) {
release_file(fp);
@@ -916,11 +931,9 @@ cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t
/* search ownerstr_hashtbl[] for owner */
static int
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {
- struct list_head *pos, *next;
struct nfs4_stateowner *local = NULL;
- list_for_each_safe(pos, next, &ownerstr_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateowner, so_strhash);
+ list_for_each_entry(local, &ownerstr_hashtbl[hashval], so_strhash) {
if(!cmp_owner_str(local, &open->op_owner, &open->op_clientid))
continue;
*op = local;
@@ -933,12 +946,10 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nf
static int
verify_clientid(struct nfs4_client **client, clientid_t *clid) {
- struct list_head *pos, *next;
struct nfs4_client *clp;
unsigned int idhashval = clientid_hashval(clid->cl_id);
- list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_idhash);
+ list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
if (!cmp_clid(&clp->cl_clientid, clid))
continue;
*client = clp;
@@ -951,11 +962,9 @@ verify_clientid(struct nfs4_client **client, clientid_t *clid) {
/* search file_hashtbl[] for file */
static int
find_file(unsigned int hashval, struct inode *ino, struct nfs4_file **fp) {
- struct list_head *pos, *next;
struct nfs4_file *local = NULL;
- list_for_each_safe(pos, next, &file_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_file, fi_hash);
+ list_for_each_entry(local, &file_hashtbl[hashval], fi_hash) {
if (local->fi_inode == ino) {
*fp = local;
return(1);
@@ -1011,15 +1020,13 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
unsigned int fi_hashval;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
- struct list_head *pos, *next;
dprintk("NFSD: nfs4_share_conflict\n");
fi_hashval = file_hashval(ino);
if (find_file(fi_hashval, ino, &fp)) {
/* Search for conflicting share reservations */
- list_for_each_safe(pos, next, &fp->fi_perfile) {
- stp = list_entry(pos, struct nfs4_stateid, st_perfile);
+ list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
if (test_bit(deny_type, &stp->st_deny_bmap) ||
test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
return nfserr_share_denied;
@@ -1066,6 +1073,8 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access)
* notfound:
* verify clientid
* create new owner
+ *
+ * called with nfs4_lock_state() held.
*/
int
nfsd4_process_open1(struct nfsd4_open *open)
@@ -1082,9 +1091,8 @@ nfsd4_process_open1(struct nfsd4_open *open)
status = nfserr_stale_clientid;
if (STALE_CLIENTID(&open->op_clientid))
- goto out;
+ return status;
- nfs4_lock_state();
strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
if (find_openstateowner_str(strhashval, open, &sop)) {
open->op_stateowner = sop;
@@ -1104,7 +1112,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
}
/* replay: indicate to calling function */
status = NFSERR_REPLAY_ME;
- goto out;
+ return status;
}
if (sop->so_confirmed) {
if (open->op_seqid == sop->so_seqid + 1) {
@@ -1142,25 +1150,27 @@ instantiate_new_owner:
renew:
renew_client(sop->so_client);
out:
- nfs4_unlock_state();
+ if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ status = nfserr_reclaim_bad;
return status;
}
-
+/*
+ * called with nfs4_lock_state() held.
+ */
int
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct iattr iattr;
struct nfs4_stateowner *sop = open->op_stateowner;
- struct nfs4_file *fp;
+ struct nfs4_file *fp = NULL;
struct inode *ino;
unsigned int fi_hashval;
- struct list_head *pos, *next;
struct nfs4_stateid *stq, *stp = NULL;
int status;
status = nfserr_resource;
if (!sop)
- goto out;
+ return status;
ino = current_fh->fh_dentry->d_inode;
@@ -1168,13 +1178,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
goto out;
- nfs4_lock_state();
fi_hashval = file_hashval(ino);
if (find_file(fi_hashval, ino, &fp)) {
/* Search for conflicting share reservations */
status = nfserr_share_denied;
- list_for_each_safe(pos, next, &fp->fi_perfile) {
- stq = list_entry(pos, struct nfs4_stateid, st_perfile);
+ list_for_each_entry(stq, &fp->fi_perfile, st_perfile) {
if(stq->st_stateowner == sop) {
stp = stq;
continue;
@@ -1253,6 +1261,17 @@ out:
if (fp && list_empty(&fp->fi_perfile))
release_file(fp);
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
+ if (status)
+ status = nfserr_reclaim_bad;
+ else {
+ /* successful reclaim. so_seqid is decremented because
+ * it will be bumped in encode_open
+ */
+ open->op_stateowner->so_confirmed = 1;
+ open->op_stateowner->so_seqid--;
+ }
+ }
/*
* To finish the open response, we just need to set the rflags.
*/
@@ -1260,12 +1279,12 @@ out:
if (!open->op_stateowner->so_confirmed)
open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
- nfs4_unlock_state();
return status;
out_free:
kfree(stp);
goto out;
}
+
static struct work_struct laundromat_work;
static void laundromat_main(void *);
static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
@@ -1274,7 +1293,6 @@ int
nfsd4_renew(clientid_t *clid)
{
struct nfs4_client *clp;
- struct list_head *pos, *next;
unsigned int idhashval;
int status;
@@ -1286,15 +1304,13 @@ nfsd4_renew(clientid_t *clid)
goto out;
status = nfs_ok;
idhashval = clientid_hashval(clid->cl_id);
- list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_idhash);
+ list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
if (!cmp_clid(&clp->cl_clientid, clid))
continue;
renew_client(clp);
goto out;
}
- list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
- clp = list_entry(pos, struct nfs4_client, cl_idhash);
+ list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
if (!cmp_clid(&clp->cl_clientid, clid))
continue;
renew_client(clp);
@@ -1316,9 +1332,11 @@ time_t
nfs4_laundromat(void)
{
struct nfs4_client *clp;
+ struct nfs4_stateowner *sop;
struct list_head *pos, *next;
time_t cutoff = get_seconds() - NFSD_LEASE_TIME;
- time_t t, return_val = NFSD_LEASE_TIME;
+ time_t t, clientid_val = NFSD_LEASE_TIME;
+ time_t u, close_val = NFSD_LEASE_TIME;
nfs4_lock_state();
@@ -1327,18 +1345,30 @@ nfs4_laundromat(void)
clp = list_entry(pos, struct nfs4_client, cl_lru);
if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
t = clp->cl_time - cutoff;
- if (return_val > t)
- return_val = t;
+ if (clientid_val > t)
+ clientid_val = t;
break;
}
dprintk("NFSD: purging unused client (clientid %08x)\n",
clp->cl_clientid.cl_id);
expire_client(clp);
}
- if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
- return_val = NFSD_LAUNDROMAT_MINTIMEOUT;
+ list_for_each_safe(pos, next, &close_lru) {
+ sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
+ if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {
+ u = sop->so_time - cutoff;
+ if (close_val > u)
+ close_val = u;
+ break;
+ }
+ dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
+ sop->so_id);
+ release_stateowner(sop);
+ }
+ if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
+ clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
nfs4_unlock_state();
- return return_val;
+ return clientid_val;
}
void
@@ -1351,17 +1381,19 @@ laundromat_main(void *not_used)
schedule_delayed_work(&laundromat_work, t*HZ);
}
-/* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
+/* search ownerid_hashtbl[] and close_lru for stateid owner
+ * (stateid->si_stateownerid)
+ */
struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id) {
- struct list_head *pos, *next;
+find_openstateowner_id(u32 st_id, int flags) {
struct nfs4_stateowner *local = NULL;
- unsigned int hashval = ownerid_hashval(st_id);
- list_for_each_safe(pos, next, &ownerid_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateowner, so_idhash);
- if(local->so_id == st_id)
- return local;
+ dprintk("NFSD: find_openstateowner_id %d\n", st_id);
+ if (flags & CLOSE_STATE) {
+ list_for_each_entry(local, &close_lru, so_close_lru) {
+ if(local->so_id == st_id)
+ return local;
+ }
}
return NULL;
}
@@ -1547,11 +1579,12 @@ no_nfs4_stateid:
* starting by trying to look up the stateowner.
* If stateowner is not found - stateid is bad.
*/
- if (!(sop = find_openstateowner_id(stateid->si_stateownerid))) {
+ if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
status = nfserr_bad_stateid;
goto out;
}
+ *sopp = sop;
check_replay:
if (seqid == sop->so_seqid) {
@@ -1561,11 +1594,15 @@ check_replay:
} else {
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
+ *sopp = NULL;
status = nfserr_bad_seqid;
}
goto out;
}
+/*
+ * nfs4_unlock_state(); called in encode
+ */
int
nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
{
@@ -1601,7 +1638,6 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
stp->st_stateid.si_generation);
status = nfs_ok;
out:
- nfs4_unlock_state();
return status;
}
@@ -1630,6 +1666,9 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
}
}
+/*
+ * nfs4_unlock_state(); called in encode
+ */
int
nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
@@ -1642,6 +1681,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
(int)current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
+ od->od_stateowner = NULL;
status = nfserr_inval;
if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))
goto out;
@@ -1675,10 +1715,12 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
- nfs4_unlock_state();
return status;
}
+/*
+ * nfs4_unlock_state() called after encode
+ */
int
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
{
@@ -1689,10 +1731,12 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
(int)current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
+ close->cl_stateowner = NULL;
nfs4_lock_state();
+ /* check close_lru for replay */
if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid,
&close->cl_stateid,
- CHECK_FH | OPEN_STATE,
+ CHECK_FH | OPEN_STATE | CLOSE_STATE,
&close->cl_stateowner, &stp, NULL)))
goto out;
/*
@@ -1705,7 +1749,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
/* release_state_owner() calls nfsd_close() if needed */
release_state_owner(stp, &close->cl_stateowner, OPEN_STATE);
out:
- nfs4_unlock_state();
return status;
}
@@ -1729,7 +1772,6 @@ static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
struct nfs4_stateid *
find_stateid(stateid_t *stid, int flags)
{
- struct list_head *pos, *next;
struct nfs4_stateid *local = NULL;
u32 st_id = stid->si_stateownerid;
u32 f_id = stid->si_fileid;
@@ -1738,8 +1780,7 @@ find_stateid(stateid_t *stid, int flags)
dprintk("NFSD: find_stateid flags 0x%x\n",flags);
if ((flags & LOCK_STATE) || (flags & RDWR_STATE)) {
hashval = stateid_hashval(st_id, f_id);
- list_for_each_safe(pos, next, &lockstateid_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateid, st_hash);
+ list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
if((local->st_stateid.si_stateownerid == st_id) &&
(local->st_stateid.si_fileid == f_id))
return local;
@@ -1747,8 +1788,7 @@ find_stateid(stateid_t *stid, int flags)
}
if ((flags & OPEN_STATE) || (flags & RDWR_STATE)) {
hashval = stateid_hashval(st_id, f_id);
- list_for_each_safe(pos, next, &stateid_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateid, st_hash);
+ list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
if((local->st_stateid.si_stateownerid == st_id) &&
(local->st_stateid.si_fileid == f_id))
return local;
@@ -1779,14 +1819,12 @@ nfs4_transform_lock_offset(struct file_lock *lock)
int
nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval)
{
- struct list_head *pos, *next;
struct nfs4_stateowner *local = NULL;
int status = 0;
if (hashval >= LOCK_HASH_SIZE)
goto out;
- list_for_each_safe(pos, next, &lock_ownerid_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateowner, so_idhash);
+ list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {
if (local == sop) {
status = 1;
goto out;
@@ -1817,11 +1855,9 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
static int
find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid_t *clid, struct nfs4_stateowner **op) {
- struct list_head *pos, *next;
struct nfs4_stateowner *local = NULL;
- list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[hashval]) {
- local = list_entry(pos, struct nfs4_stateowner, so_strhash);
+ list_for_each_entry(local, &lock_ownerstr_hashtbl[hashval], so_strhash) {
if(!cmp_owner_str(local, owner, clid))
continue;
*op = local;
@@ -1854,6 +1890,8 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_perfilestate);
INIT_LIST_HEAD(&sop->so_perlockowner);
+ INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
+ sop->so_time = 0;
list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
list_add(&sop->so_perclient, &clp->cl_perclient);
@@ -1913,6 +1951,8 @@ check_lock_length(u64 offset, u64 length)
/*
* LOCK operation
+ *
+ * nfs4_unlock_state(); called in encode
*/
int
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
@@ -1929,6 +1969,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
(long long) lock->lk_offset,
(long long) lock->lk_length);
+ if (nfs4_in_grace() && !lock->lk_reclaim)
+ return nfserr_grace;
+ if (nfs4_in_no_grace() && lock->lk_reclaim)
+ return nfserr_no_grace;
+
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
@@ -1958,8 +2003,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
CHECK_FH | OPEN_STATE,
&open_sop, &open_stp,
&lock->v.new.clientid);
- if (status)
+ if (status) {
+ if (lock->lk_reclaim)
+ status = nfserr_reclaim_bad;
goto out;
+ }
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
@@ -2077,7 +2125,6 @@ out_destroy_new_stateid:
release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);
}
out:
- nfs4_unlock_state();
return status;
}
@@ -2095,6 +2142,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
unsigned int strhashval;
int status;
+ if (nfs4_in_grace())
+ return nfserr_grace;
+
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
return nfserr_inval;
@@ -2188,6 +2238,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (check_lock_length(locku->lu_offset, locku->lu_length))
return nfserr_inval;
+ locku->lu_stateowner = NULL;
nfs4_lock_state();
if ((status = nfs4_preprocess_seqid_op(current_fh,
@@ -2230,7 +2281,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
out:
- nfs4_unlock_state();
return status;
out_nfserr:
@@ -2265,7 +2315,6 @@ int
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
- struct list_head *pos, *next;
struct nfs4_stateowner *local = NULL;
struct xdr_netobj *owner = &rlockowner->rl_owner;
int status, i;
@@ -2286,9 +2335,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
/* find the lockowner */
status = nfs_ok;
for (i=0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[i]) {
- local = list_entry(pos, struct nfs4_stateowner,
- so_strhash);
+ list_for_each_entry(local, &lock_ownerstr_hashtbl[i], so_strhash) {
if(cmp_owner_str(local, owner, clid))
break;
}
@@ -2299,9 +2346,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
/* check for any locks held by any stateid associated with the
* (lock) stateowner */
status = nfserr_locks_held;
- list_for_each_safe(pos, next, &local->so_perfilestate) {
- stp = list_entry(pos, struct nfs4_stateid,
- st_perfilestate);
+ list_for_each_entry(stp, &local->so_perfilestate, st_perfilestate) {
if(stp->st_vfs_set) {
if (check_for_locks(&stp->st_vfs_file, local))
goto out;
@@ -2324,6 +2369,7 @@ void
nfs4_state_init(void)
{
int i;
+ time_t start = get_seconds();
if (nfs4_init)
return;
@@ -2351,15 +2397,30 @@ nfs4_state_init(void)
memset(&zerostateid, 0, sizeof(stateid_t));
memset(&onestateid, ~0, sizeof(stateid_t));
+ INIT_LIST_HEAD(&close_lru);
INIT_LIST_HEAD(&client_lru);
init_MUTEX(&client_sema);
- boot_time = get_seconds();
+ boot_time = start;
+ grace_end = start + NFSD_LEASE_TIME;
INIT_WORK(&laundromat_work,laundromat_main, NULL);
schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
nfs4_init = 1;
}
+int
+nfs4_in_grace(void)
+{
+ return time_before(get_seconds(), (unsigned long)grace_end);
+}
+
+int
+nfs4_in_no_grace(void)
+{
+ return (grace_end < get_seconds());
+}
+
+
static void
__nfs4_state_shutdown(void)
{
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index e5e6445bc565..b98b5fe49efc 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -484,11 +484,14 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
DECODE_TAIL;
}
+#define NFS4_STATE_NOT_LOCKED ((void *)-1)
+
static int
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
DECODE_HEAD;
+ close->cl_stateowner = NFS4_STATE_NOT_LOCKED;
READ_BUF(4 + sizeof(stateid_t));
READ32(close->cl_seqid);
READ32(close->cl_stateid.si_generation);
@@ -579,6 +582,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;
+ lock->lk_stateowner = NFS4_STATE_NOT_LOCKED;
/*
* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
*/
@@ -636,6 +640,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
{
DECODE_HEAD;
+ locku->lu_stateowner = NFS4_STATE_NOT_LOCKED;
READ_BUF(24 + sizeof(stateid_t));
READ32(locku->lu_type);
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
@@ -671,6 +676,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
memset(open->op_bmval, 0, sizeof(open->op_bmval));
open->op_iattr.ia_valid = 0;
+ open->op_stateowner = NFS4_STATE_NOT_LOCKED;
/* seqid, share_access, share_deny, clientid, ownerlen */
READ_BUF(16 + sizeof(clientid_t));
@@ -746,6 +752,7 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
{
DECODE_HEAD;
+ open_conf->oc_stateowner = NFS4_STATE_NOT_LOCKED;
READ_BUF(4 + sizeof(stateid_t));
READ32(open_conf->oc_req_stateid.si_generation);
COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
@@ -759,6 +766,7 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
{
DECODE_HEAD;
+ open_down->od_stateowner = NFS4_STATE_NOT_LOCKED;
READ_BUF(4 + sizeof(stateid_t));
READ32(open_down->od_stateid.si_generation);
COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
@@ -1259,7 +1267,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
*/
#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
- if (seqid_mutating_err(nfserr) && stateowner) { \
+ if (seqid_mutating_err(nfserr) && stateowner \
+ && (stateowner != NFS4_STATE_NOT_LOCKED)) { \
if (stateowner->so_confirmed) \
stateowner->so_seqid++; \
stateowner->so_replay.rp_status = nfserr; \
@@ -1267,7 +1276,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
(((char *)(resp)->p - (char *)save)); \
memcpy(stateowner->so_replay.rp_buf, save, \
stateowner->so_replay.rp_buflen); \
- } } while(0)
+ } \
+ if (stateowner != NFS4_STATE_NOT_LOCKED) \
+ nfs4_unlock_state(); \
+ } while (0);
static u32 nfs4_ftypes[16] = {
@@ -1917,7 +1929,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open
ENCODE_SEQID_OP_HEAD;
if (nfserr)
- return;
+ goto out;
RESERVE_SPACE(36 + sizeof(stateid_t));
WRITE32(open->op_stateid.si_generation);
@@ -1972,7 +1984,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open
BUG();
}
/* XXX save filehandle here */
-
+out:
ENCODE_SEQID_OP_TAIL(open->op_stateowner);
}
@@ -2179,6 +2191,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
readdir->common.err == nfserr_toosmall &&
readdir->buffer == page)
nfserr = nfserr_toosmall;
+ if (nfserr == nfserr_symlink)
+ nfserr = nfserr_notdir;
if (nfserr)
goto err_no_verf;
@@ -2295,14 +2309,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
RESERVE_SPACE(8);
WRITE32(op->opnum);
- if ((op->opnum != OP_SETATTR) && (op->opnum != OP_LOCK) && (op->opnum != OP_LOCKT) && (op->opnum != OP_SETCLIENTID) && (op->status)) {
- *p++ = op->status;
- ADJUST_ARGS();
- return;
- } else {
- statp = p++; /* to be backfilled at the end */
- ADJUST_ARGS();
- }
+ statp = p++; /* to be backfilled at the end */
+ ADJUST_ARGS();
switch (op->opnum) {
case OP_ACCESS:
@@ -2406,6 +2414,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
*
* XDR note: do not encode rp->rp_buflen: the buffer contains the
* previously sent already encoded operation.
+ *
+ * called with nfs4_lock_state() held
*/
void
nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
@@ -2423,6 +2433,7 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
RESERVE_SPACE(rp->rp_buflen);
WRITEMEM(rp->rp_buf, rp->rp_buflen);
ADJUST_ARGS();
+ nfs4_unlock_state();
}
/*
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index bb048a75318d..3f4df6ddbe1c 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -1340,8 +1340,6 @@ err_out:
void *kaddr;
clear_buffer_new(bh);
- if (buffer_uptodate(bh))
- buffer_error();
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr + block_start, 0, bh->b_size);
kunmap_atomic(kaddr, KM_USER0);
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 6df304c6b1cc..308ecf13cc0c 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1925,7 +1925,6 @@ static int map_block_for_writepage(struct inode *inode,
th.t_trans_id = 0;
if (!buffer_uptodate(bh_result)) {
- buffer_error();
return -EIO;
}
@@ -2057,8 +2056,6 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control
* in the BH_Uptodate is just a sanity check.
*/
if (!page_has_buffers(page)) {
- if (!PageUptodate(page))
- buffer_error();
create_empty_buffers(page, inode->i_sb->s_blocksize,
(1 << BH_Dirty) | (1 << BH_Uptodate));
}
@@ -2120,8 +2117,6 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control
}
}
if (test_clear_buffer_dirty(bh)) {
- if (!buffer_uptodate(bh))
- buffer_error();
mark_buffer_async_write(bh);
} else {
unlock_buffer(bh);
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 96398695fa10..78b95f54eb2f 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -86,6 +86,7 @@ static struct workqueue_struct *commit_wq;
/* journal list state bits */
#define LIST_TOUCHED 1
#define LIST_DIRTY 2
+#define LIST_COMMIT_PENDING 4 /* someone will commit this list */
/* flags for do_journal_end */
#define FLUSH_ALL 1 /* flush commit and real blocks */
@@ -2308,6 +2309,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = commit_max_age;
} else {
SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age);
+ SB_JOURNAL_DEFAULT_MAX_COMMIT_AGE(p_s_sb) = SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb);
SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = JOURNAL_MAX_TRANS_AGE;
}
@@ -2462,8 +2464,20 @@ void reiserfs_wait_on_write_block(struct super_block *s) {
}
static void queue_log_writer(struct super_block *s) {
+ wait_queue_t wait;
set_bit(WRITERS_QUEUED, &SB_JOURNAL(s)->j_state);
- sleep_on(&SB_JOURNAL(s)->j_join_wait);
+
+ /*
+ * we don't want to use wait_event here because
+ * we only want to wait once.
+ */
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&SB_JOURNAL(s)->j_join_wait, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (test_bit(WRITERS_QUEUED, &SB_JOURNAL(s)->j_state))
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&SB_JOURNAL(s)->j_join_wait, &wait);
}
static void wake_queued_writers(struct super_block *s) {
@@ -2476,7 +2490,9 @@ static void let_transaction_grow(struct super_block *sb,
{
unsigned long bcount = SB_JOURNAL(sb)->j_bcount;
while(1) {
- yield();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ SB_JOURNAL(sb)->j_current_jl->j_state |= LIST_COMMIT_PENDING;
while ((atomic_read(&SB_JOURNAL(sb)->j_wcount) > 0 ||
atomic_read(&SB_JOURNAL(sb)->j_jlock)) &&
SB_JOURNAL(sb)->j_trans_id == trans_id) {
@@ -2909,9 +2925,15 @@ static void flush_async_commits(void *p) {
flush_commit_list(p_s_sb, jl, 1);
}
unlock_kernel();
- atomic_inc(&SB_JOURNAL(p_s_sb)->j_async_throttle);
- filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
- atomic_dec(&SB_JOURNAL(p_s_sb)->j_async_throttle);
+ /*
+ * this is a little racey, but there's no harm in missing
+ * the filemap_fdata_write
+ */
+ if (!atomic_read(&SB_JOURNAL(p_s_sb)->j_async_throttle)) {
+ atomic_inc(&SB_JOURNAL(p_s_sb)->j_async_throttle);
+ filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
+ atomic_dec(&SB_JOURNAL(p_s_sb)->j_async_throttle);
+ }
}
/*
@@ -3000,7 +3022,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, struct supe
jl = SB_JOURNAL(p_s_sb)->j_current_jl;
trans_id = jl->j_trans_id;
-
+ if (wait_on_commit)
+ jl->j_state |= LIST_COMMIT_PENDING;
atomic_set(&(SB_JOURNAL(p_s_sb)->j_jlock), 1) ;
if (flush) {
SB_JOURNAL(p_s_sb)->j_next_full_flush = 1 ;
@@ -3522,8 +3545,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
if (flush) {
flush_commit_list(p_s_sb, jl, 1) ;
flush_journal_list(p_s_sb, jl, 1) ;
- } else
- queue_work(commit_wq, &SB_JOURNAL(p_s_sb)->j_work);
+ } else if (!(jl->j_state & LIST_COMMIT_PENDING))
+ queue_delayed_work(commit_wq, &SB_JOURNAL(p_s_sb)->j_work, HZ/10);
/* if the next transaction has any chance of wrapping, flush
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index fbd4d224b69b..f2233df104a6 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -709,13 +709,11 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
char *p = 0;
int val = simple_strtoul (arg, &p, 0);
/* commit=NNN (time in seconds) */
- if ( *p != '\0' || val == 0) {
+ if ( *p != '\0' || val < 0) {
printk ("reiserfs_parse_options: bad value %s\n", arg);
return 0;
}
- if ( val > 0 ) {
- *commit_max_age = val;
- }
+ *commit_max_age = val;
}
if ( c == 'w' ) {
@@ -821,8 +819,14 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask);
if(commit_max_age != 0) {
- SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age;
- SB_JOURNAL_MAX_TRANS_AGE(s) = commit_max_age;
+ SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age;
+ SB_JOURNAL_MAX_TRANS_AGE(s) = commit_max_age;
+ }
+ else
+ {
+ /* 0 means restore defaults. */
+ SB_JOURNAL_MAX_COMMIT_AGE(s) = SB_JOURNAL_DEFAULT_MAX_COMMIT_AGE(s);
+ SB_JOURNAL_MAX_TRANS_AGE(s) = JOURNAL_MAX_TRANS_AGE;
}
if(blocks) {
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 94522584d6f6..a0d71213c8dc 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -15,13 +15,62 @@
#include <asm/arch/vmalloc.h>
/*
- * We pull a couple of tricks here:
- * 1. We wrap the PMD into the PGD.
- * 2. We lie about the size of the PTE and PGD.
- * Even though we have 256 PTE entries and 4096 PGD entries, we tell
- * Linux that we actually have 512 PTE entries and 2048 PGD entries.
- * Each "Linux" PGD entry is made up of two hardware PGD entries, and
- * each PTE table is actually two hardware PTE tables.
+ * Hardware-wise, we have a two level page table structure, where the first
+ * level has 4096 entries, and the second level has 256 entries. Each entry
+ * is one 32-bit word. Most of the bits in the second level entry are used
+ * by hardware, and there aren't any "accessed" and "dirty" bits.
+ *
+ * Linux on the other hand has a three level page table structure, which can
+ * be wrapped to fit a two level page table structure easily - using the PGD
+ * and PTE only. However, Linux also expects one "PTE" table per page, and
+ * at least a "dirty" bit.
+ *
+ * Therefore, we tweak the implementation slightly - we tell Linux that we
+ * have 2048 entries in the first level, each of which is 8 bytes (iow, two
+ * hardware pointers to the second level.) The second level contains two
+ * hardware PTE tables arranged contiguously, followed by Linux versions
+ * which contain the state information Linux needs. We, therefore, end up
+ * with 512 entries in the "PTE" level.
+ *
+ * This leads to the page tables having the following layout:
+ *
+ * pgd pte
+ * | |
+ * +--------+ +0
+ * | |-----> +------------+ +0
+ * +- - - - + +4 | h/w pt 0 |
+ * | |-----> +------------+ +1024
+ * +--------+ +8 | h/w pt 1 |
+ * | | +------------+ +2048
+ * +- - - - + | Linux pt 0 |
+ * | | +------------+ +3072
+ * +--------+ | Linux pt 1 |
+ * | | +------------+ +4096
+ *
+ * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
+ * PTE_xxx for definitions of bits appearing in the "h/w pt".
+ *
+ * PMD_xxx definitions refer to bits in the first level page table.
+ *
+ * The "dirty" bit is emulated by only granting hardware write permission
+ * iff the page is marked "writable" and "dirty" in the Linux PTE. This
+ * means that a write to a clean page will cause a permission fault, and
+ * the Linux MM layer will mark the page dirty via handle_pte_fault().
+ * For the hardware to notice the permission change, the TLB entry must
+ * be flushed, and ptep_establish() does that for us.
+ *
+ * The "accessed" or "young" bit is emulated by a similar method; we only
+ * allow accesses to the page if the "young" bit is set. Accesses to the
+ * page will cause a fault, and handle_pte_fault() will set the young bit
+ * for us as long as the page is marked present in the corresponding Linux
+ * PTE entry. Again, ptep_establish() will ensure that the TLB is up to
+ * date.
+ *
+ * However, when the "young" bit is cleared, we deny access to the page
+ * by clearing the hardware PTE. Currently Linux does not flush the TLB
+ * for us in this case, which means the TLB will retain the transation
+ * until either the TLB entry is evicted under pressure, or a context
+ * switch which changes the user space mapping occurs.
*/
#define PTRS_PER_PTE 512
#define PTRS_PER_PMD 1
diff --git a/include/asm-generic/rmap.h b/include/asm-generic/rmap.h
index 7de7730e9cc3..f743d9f80b0f 100644
--- a/include/asm-generic/rmap.h
+++ b/include/asm-generic/rmap.h
@@ -57,7 +57,8 @@ static inline unsigned long ptep_to_address(pte_t * ptep)
{
struct page * page = kmap_atomic_to_page(ptep);
unsigned long low_bits;
- low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE;
+ low_bits = ((unsigned long)ptep & (PTRS_PER_PTE*sizeof(pte_t) - 1))
+ * (PAGE_SIZE/sizeof(pte_t));
return page->index + low_bits;
}
diff --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h
index 39d9ca204104..c980cb9a982a 100644
--- a/include/asm-mips/siginfo.h
+++ b/include/asm-mips/siginfo.h
@@ -175,7 +175,7 @@ typedef struct siginfo32 {
#undef SI_MESGQ
#define SI_ASYNCIO -2 /* sent by AIO completion */
#define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
-#define SI_MESGQ -4 /* sent by real time mesq state change */
+#define SI_MESGQ __SI_CODE(__SI_MESGQ,-4) /* sent by real time mesq state change */
#ifdef __KERNEL__
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 110584f07883..ebe0b1221579 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -62,13 +62,6 @@ struct buffer_head {
};
/*
- * Debug
- */
-
-void __buffer_error(char *file, int line);
-#define buffer_error() __buffer_error(__FILE__, __LINE__)
-
-/*
* macro tricks to expand the set_buffer_foo(), clear_buffer_foo()
* and buffer_foo() functions.
*/
@@ -177,7 +170,7 @@ void free_buffer_head(struct buffer_head * bh);
void FASTCALL(unlock_buffer(struct buffer_head *bh));
void ll_rw_block(int, int, struct buffer_head * bh[]);
void sync_dirty_buffer(struct buffer_head *bh);
-int submit_bh(int, struct buffer_head *);
+void submit_bh(int, struct buffer_head *);
void write_boundary_block(struct block_device *bdev,
sector_t bblock, unsigned blocksize);
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index be4c3e031f1e..278c533b6994 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -123,6 +123,19 @@ COMPATIBLE_IOCTL(STOP_ARRAY)
COMPATIBLE_IOCTL(STOP_ARRAY_RO)
COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
/* DM */
+COMPATIBLE_IOCTL(DM_VERSION_32)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES_32)
+COMPATIBLE_IOCTL(DM_DEV_CREATE_32)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE_32)
+COMPATIBLE_IOCTL(DM_DEV_RENAME_32)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND_32)
+COMPATIBLE_IOCTL(DM_DEV_STATUS_32)
+COMPATIBLE_IOCTL(DM_DEV_WAIT_32)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD_32)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR_32)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS_32)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
COMPATIBLE_IOCTL(DM_VERSION)
COMPATIBLE_IOCTL(DM_LIST_DEVICES)
COMPATIBLE_IOCTL(DM_DEV_CREATE)
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index cd781d795f8d..03f99db7ad7b 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -129,8 +129,14 @@ struct dm_target_spec {
int32_t status; /* used when reading from kernel only */
/*
- * Offset in bytes (from the start of this struct) to
- * next target_spec.
+ * Location of the next dm_target_spec.
+ * - When specifying targets on a DM_TABLE_LOAD command, this value is
+ * the number of bytes from the start of the "current" dm_target_spec
+ * to the start of the "next" dm_target_spec.
+ * - When retrieving targets on a DM_TABLE_STATUS command, this value
+ * is the number of bytes from the start of the first dm_target_spec
+ * (that follows the dm_ioctl struct) to the start of the "next"
+ * dm_target_spec.
*/
uint32_t next;
@@ -200,6 +206,34 @@ enum {
DM_LIST_VERSIONS_CMD,
};
+/*
+ * The dm_ioctl struct passed into the ioctl is just the header
+ * on a larger chunk of memory. On x86-64 and other
+ * architectures the dm-ioctl struct will be padded to an 8 byte
+ * boundary so the size will be different, which would change the
+ * ioctl code - yes I really messed up. This hack forces these
+ * architectures to have the correct ioctl code.
+ */
+#ifdef CONFIG_COMPAT
+typedef char ioctl_struct[308];
+#define DM_VERSION_32 _IOWR(DM_IOCTL, DM_VERSION_CMD, ioctl_struct)
+#define DM_REMOVE_ALL_32 _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, ioctl_struct)
+#define DM_LIST_DEVICES_32 _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, ioctl_struct)
+
+#define DM_DEV_CREATE_32 _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, ioctl_struct)
+#define DM_DEV_REMOVE_32 _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, ioctl_struct)
+#define DM_DEV_RENAME_32 _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, ioctl_struct)
+#define DM_DEV_SUSPEND_32 _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, ioctl_struct)
+#define DM_DEV_STATUS_32 _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, ioctl_struct)
+#define DM_DEV_WAIT_32 _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, ioctl_struct)
+
+#define DM_TABLE_LOAD_32 _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, ioctl_struct)
+#define DM_TABLE_CLEAR_32 _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, ioctl_struct)
+#define DM_TABLE_DEPS_32 _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, ioctl_struct)
+#define DM_TABLE_STATUS_32 _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct)
+#define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct)
+#endif
+
#define DM_IOCTL 0xfd
#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c9fb9bbe154a..edaaaf6ce341 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -751,7 +751,6 @@ struct super_block {
char s_id[32]; /* Informational name */
- struct kobject kobj; /* anchor for sysfs */
void *s_fs_info; /* Filesystem private info */
/*
@@ -1359,7 +1358,7 @@ extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list);
extern void file_kill(struct file *f);
struct bio;
-extern int submit_bio(int, struct bio *);
+extern void submit_bio(int, struct bio *);
extern int bdev_read_only(struct block_device *);
extern int set_blocksize(struct block_device *, int);
extern int sb_set_blocksize(struct super_block *, int);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 14dba1b26016..4fd3c76ac05f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -526,9 +526,8 @@ extern void si_meminfo_node(struct sysinfo *val, int nid);
extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *,
struct rb_node **, struct rb_node *);
-extern struct vm_area_struct *copy_vma(struct vm_area_struct *,
+extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
unsigned long addr, unsigned long len, unsigned long pgoff);
-extern void vma_relink_file(struct vm_area_struct *, struct vm_area_struct *);
extern void exit_mmap(struct mm_struct *);
extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 418356558209..cd9c59cf93fd 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -196,6 +196,9 @@ void nfsd_lockd_shutdown(void);
#define nfserr_openmode __constant_htonl(NFSERR_OPENMODE)
#define nfserr_locks_held __constant_htonl(NFSERR_LOCKS_HELD)
#define nfserr_op_illegal __constant_htonl(NFSERR_OP_ILLEGAL)
+#define nfserr_grace __constant_htonl(NFSERR_GRACE)
+#define nfserr_no_grace __constant_htonl(NFSERR_NO_GRACE)
+#define nfserr_reclaim_bad __constant_htonl(NFSERR_RECLAIM_BAD)
/* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 4598b9756668..06da18506122 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -132,6 +132,9 @@ struct nfs4_replay {
* release a stateowner.
* so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
* close is called to reap associated byte-range locks
+* so_close_lru: (open) stateowner is placed on this list instead of being
+* reaped (when so_perfilestate is empty) to hold the last close replay.
+* reaped by laundramat thread after lease period.
*/
struct nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */
@@ -139,6 +142,8 @@ struct nfs4_stateowner {
struct list_head so_perclient; /* nfs4_client->cl_perclient */
struct list_head so_perfilestate; /* list: nfs4_stateid */
struct list_head so_perlockowner; /* nfs4_stateid->st_perlockowner */
+ struct list_head so_close_lru; /* tail queue */
+ time_t so_time; /* time of placement on so_close_lru */
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id;
struct nfs4_client * so_client;
@@ -194,6 +199,7 @@ struct nfs4_stateid {
#define OPEN_STATE 0x00000004
#define LOCK_STATE 0x00000008
#define RDWR_STATE 0x00000010
+#define CLOSE_STATE 0x00000020
#define seqid_mutating_err(err) \
(((err) != nfserr_stale_clientid) && \
@@ -209,4 +215,6 @@ extern int nfs4_share_conflict(struct svc_fh *current_fh,
unsigned int deny_type);
extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
+extern int nfs4_in_grace(void);
+extern int nfs4_in_no_grace(void);
#endif /* NFSD4_STATE_H */
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 3248dcf369f2..9fa2813c2e69 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -208,6 +208,7 @@ struct reiserfs_journal {
unsigned int s_journal_trans_max ; /* max number of blocks in a transaction. */
unsigned int s_journal_max_batch ; /* max number of blocks to batch into a trans */
unsigned int s_journal_max_commit_age ; /* in seconds, how old can an async commit be */
+ unsigned int s_journal_default_max_commit_age ; /* the default for the max commit age */
unsigned int s_journal_max_trans_age ; /* in seconds, how old can a transaction be */
struct reiserfs_journal_cnode *j_cnode_free_list ;
@@ -481,6 +482,7 @@ int reiserfs_resize(struct super_block *, unsigned long) ;
#define SB_JOURNAL_TRANS_MAX(s) (SB_JOURNAL(s)->s_journal_trans_max)
#define SB_JOURNAL_MAX_BATCH(s) (SB_JOURNAL(s)->s_journal_max_batch)
#define SB_JOURNAL_MAX_COMMIT_AGE(s) (SB_JOURNAL(s)->s_journal_max_commit_age)
+#define SB_JOURNAL_DEFAULT_MAX_COMMIT_AGE(s) (SB_JOURNAL(s)->s_journal_default_max_commit_age)
#define SB_JOURNAL_MAX_TRANS_AGE(s) (SB_JOURNAL(s)->s_journal_max_trans_age)
/* A safe version of the "bdevname", which returns the "s_id" field of
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 72f74d564f9b..8c54e3e81d22 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -153,7 +153,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = MQUEUE_MAGIC;
sb->s_op = &mqueue_super_ops;
- inode = mqueue_get_inode(sb, S_IFDIR | S_IRWXUGO);
+ inode = mqueue_get_inode(sb, S_IFDIR | S_ISVTX | S_IRWXUGO);
if (!inode)
return -ENOMEM;
@@ -685,10 +685,6 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
goto out_err;
}
- if (permission(dentry->d_inode, MAY_WRITE, NULL)) {
- err = -EACCES;
- goto out_err;
- }
inode = dentry->d_inode;
if (inode)
atomic_inc(&inode->i_count);
diff --git a/kernel/signal.c b/kernel/signal.c
index c69671600bef..0232084c1f65 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2052,7 +2052,6 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
case __SI_MESGQ: /* But this is */
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
err |= __put_user(from->si_ptr, &to->si_ptr);
break;
default: /* this is just in case for now ... */
diff --git a/mm/mmap.c b/mm/mmap.c
index eed4e083bca1..94ad97fb2b04 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1498,9 +1498,11 @@ void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
* Copy the vma structure to a new location in the same mm,
* prior to moving page table entries, to effect an mremap move.
*/
-struct vm_area_struct *copy_vma(struct vm_area_struct *vma,
+struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
unsigned long addr, unsigned long len, unsigned long pgoff)
{
+ struct vm_area_struct *vma = *vmap;
+ unsigned long vma_start = vma->vm_start;
struct mm_struct *mm = vma->vm_mm;
struct vm_area_struct *new_vma, *prev;
struct rb_node **rb_link, *rb_parent;
@@ -1508,7 +1510,14 @@ struct vm_area_struct *copy_vma(struct vm_area_struct *vma,
find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
new_vma = vma_merge(mm, prev, rb_parent, addr, addr + len,
vma->vm_flags, vma->vm_file, pgoff);
- if (!new_vma) {
+ if (new_vma) {
+ /*
+ * Source vma may have been merged into new_vma
+ */
+ if (vma_start >= new_vma->vm_start &&
+ vma_start < new_vma->vm_end)
+ *vmap = new_vma;
+ } else {
new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (new_vma) {
*new_vma = *vma;
@@ -1525,24 +1534,3 @@ struct vm_area_struct *copy_vma(struct vm_area_struct *vma,
}
return new_vma;
}
-
-/*
- * Position vma after prev in shared file list:
- * for mremap move error recovery racing against vmtruncate.
- */
-void vma_relink_file(struct vm_area_struct *vma, struct vm_area_struct *prev)
-{
- struct mm_struct *mm = vma->vm_mm;
- struct address_space *mapping;
-
- if (vma->vm_file) {
- mapping = vma->vm_file->f_mapping;
- if (mapping) {
- down(&mapping->i_shared_sem);
- spin_lock(&mm->page_table_lock);
- list_move(&vma->shared, &prev->shared);
- spin_unlock(&mm->page_table_lock);
- up(&mapping->i_shared_sem);
- }
- }
-}
diff --git a/mm/mremap.c b/mm/mremap.c
index c355d4da4afe..4dc19b415000 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -169,6 +169,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
unsigned long new_len, unsigned long new_addr)
{
struct mm_struct *mm = vma->vm_mm;
+ struct address_space *mapping = NULL;
struct vm_area_struct *new_vma;
unsigned long vm_flags = vma->vm_flags;
unsigned long new_pgoff;
@@ -184,30 +185,35 @@ static unsigned long move_vma(struct vm_area_struct *vma,
return -ENOMEM;
new_pgoff = vma->vm_pgoff + ((old_addr - vma->vm_start) >> PAGE_SHIFT);
- new_vma = copy_vma(vma, new_addr, new_len, new_pgoff);
+ new_vma = copy_vma(&vma, new_addr, new_len, new_pgoff);
if (!new_vma)
return -ENOMEM;
+ if (vma->vm_file) {
+ /*
+ * Subtle point from Rajesh Venkatasubramanian: before
+ * moving file-based ptes, we must lock vmtruncate out,
+ * since it might clean the dst vma before the src vma,
+ * and we propagate stale pages into the dst afterward.
+ */
+ mapping = vma->vm_file->f_mapping;
+ down(&mapping->i_shared_sem);
+ }
moved_len = move_page_tables(vma, new_addr, old_addr, old_len);
if (moved_len < old_len) {
/*
* On error, move entries back from new area to old,
* which will succeed since page tables still there,
* and then proceed to unmap new area instead of old.
- *
- * Subtle point from Rajesh Venkatasubramanian: before
- * moving file-based ptes, move new_vma before old vma
- * in the i_mmap or i_mmap_shared list, so when racing
- * against vmtruncate we cannot propagate pages to be
- * truncated back from new_vma into just cleaned old.
*/
- vma_relink_file(vma, new_vma);
move_page_tables(new_vma, old_addr, new_addr, moved_len);
vma = new_vma;
old_len = new_len;
old_addr = new_addr;
new_addr = -ENOMEM;
}
+ if (mapping)
+ up(&mapping->i_shared_sem);
/* Conceal VM_ACCOUNT so old reservation is not undone */
if (vm_flags & VM_ACCOUNT) {
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 2277667d3397..a60a541e9f5e 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -895,6 +895,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
svc_putu32(resv, rpc_success);
goto complete;
case RPC_GSS_PROC_DATA:
+ *authp = rpc_autherr_badcred;
rqstp->rq_client =
find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
if (rqstp->rq_client == NULL)