Commit 1018aab0 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.59

parent f59dfe26
VERSION = 2 VERSION = 2
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 58 SUBLEVEL = 59
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
...@@ -37,6 +37,18 @@ ...@@ -37,6 +37,18 @@
# error Unable to handle more than 64 irq levels. # error Unable to handle more than 64 irq levels.
#endif #endif
/* PROBE_MASK is the bitset of irqs that we consider for autoprobing: */
#if defined(CONFIG_ALPHA_P2K)
/* always mask out unused timer irq 0 and RTC irq 8 */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL)
#elif defined(CONFIG_ALPHA_ALCOR)
/* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
#else
/* always mask out unused timer irq 0: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
#endif
/* Reserved interrupts. These must NEVER be requested by any driver! /* Reserved interrupts. These must NEVER be requested by any driver!
*/ */
#define IS_RESERVED_IRQ(irq) ((irq)==2) /* IRQ 2 used by hw cascade */ #define IS_RESERVED_IRQ(irq) ((irq)==2) /* IRQ 2 used by hw cascade */
...@@ -644,10 +656,13 @@ unsigned long probe_irq_on(void) ...@@ -644,10 +656,13 @@ unsigned long probe_irq_on(void)
unsigned int i; unsigned int i;
for (i = NR_IRQS - 1; i > 0; i--) { for (i = NR_IRQS - 1; i > 0; i--) {
if (!(PROBE_MASK & (1UL << i))) {
continue;
}
action = irq_action[i]; action = irq_action[i];
if (!action) { if (!action) {
enable_irq(i); enable_irq(i);
irqs |= (1 << i); irqs |= (1UL << i);
} }
} }
/* /*
...@@ -668,14 +683,10 @@ unsigned long probe_irq_on(void) ...@@ -668,14 +683,10 @@ unsigned long probe_irq_on(void)
*/ */
int probe_irq_off(unsigned long irqs) int probe_irq_off(unsigned long irqs)
{ {
unsigned long delay;
int i; int i;
/* as irq 0 & 8 handling don't use this function, i didn't irqs &= irq_mask;
* bother changing the following: */
irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
#ifdef CONFIG_ALPHA_P2K
irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */
#endif
if (!irqs) if (!irqs)
return 0; return 0;
i = ffz(~irqs); i = ffz(~irqs);
......
...@@ -63,6 +63,7 @@ EXPORT_SYMBOL(__global_restore_flags); ...@@ -63,6 +63,7 @@ EXPORT_SYMBOL(__global_restore_flags);
#ifdef CONFIG_MCA #ifdef CONFIG_MCA
/* Adapter probing and info methods. */ /* Adapter probing and info methods. */
EXPORT_SYMBOL(machine_id);
EXPORT_SYMBOL(mca_find_adapter); EXPORT_SYMBOL(mca_find_adapter);
EXPORT_SYMBOL(mca_write_pos); EXPORT_SYMBOL(mca_write_pos);
EXPORT_SYMBOL(mca_read_pos); EXPORT_SYMBOL(mca_read_pos);
......
...@@ -176,7 +176,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) ...@@ -176,7 +176,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
int rc; int rc;
ide_ioreg_t hd_status; ide_ioreg_t hd_status;
unsigned long timeout; unsigned long timeout;
int irqs = 0; unsigned long irqs = 0;
if (!HWIF(drive)->irq) { /* already got an IRQ? */ if (!HWIF(drive)->irq) { /* already got an IRQ? */
probe_irq_off(probe_irq_on()); /* clear dangling irqs */ probe_irq_off(probe_irq_on()); /* clear dangling irqs */
...@@ -235,7 +235,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) ...@@ -235,7 +235,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
(void) GET_STAT(); /* clear drive IRQ */ (void) GET_STAT(); /* clear drive IRQ */
} else { /* Mmmm.. multiple IRQs.. don't know which was ours */ } else { /* Mmmm.. multiple IRQs.. don't know which was ours */
printk("%s: IRQ probe failed (%d)\n", drive->name, irqs); printk("%s: IRQ probe failed (%ld)\n", drive->name, irqs);
#ifdef CONFIG_BLK_DEV_CMD640 #ifdef CONFIG_BLK_DEV_CMD640
#ifdef CMD640_DUMP_REGS #ifdef CMD640_DUMP_REGS
if (HWIF(drive)->chipset == ide_cmd640) { if (HWIF(drive)->chipset == ide_cmd640) {
......
...@@ -46,8 +46,8 @@ extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); ...@@ -46,8 +46,8 @@ extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#ifndef HAVE_AUTOIRQ #ifndef HAVE_AUTOIRQ
/* From auto_irq.c */ /* From auto_irq.c */
extern struct device *irq2dev_map[16]; extern struct device *irq2dev_map[16];
extern int autoirq_setup(int waittime); extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime); extern unsigned long autoirq_report(int waittime);
#endif #endif
/* Most of these entries should be in 'struct device' (or most of the /* Most of these entries should be in 'struct device' (or most of the
......
...@@ -39,76 +39,18 @@ static const char *version= ...@@ -39,76 +39,18 @@ static const char *version=
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */}; struct device *irq2dev_map[NR_IRQS] = {0, 0, /* ... zeroed */};
unsigned long irqs_busy = 0x2147; /* The set of fixed IRQs (keyboard, timer, etc) */ static unsigned long irqs;
unsigned long irqs_used = 0x0001; /* The set of fixed IRQs sometimes enabled. */
unsigned long irqs_reserved = 0x0000; /* An advisory "reserved" table. */
unsigned long irqs_shared = 0x0000; /* IRQ lines "shared" among conforming cards.*/
static volatile unsigned long irq_bitmap; /* The irqs we actually found. */ void autoirq_setup(int waittime)
static unsigned long irq_handled; /* The irq lines we have a handler on. */
static volatile int irq_number; /* The latest irq number we actually found. */
static void autoirq_probe(int irq, void *dev_id, struct pt_regs * regs)
{ {
irq_number = irq; irqs = probe_irq_on();
set_bit(irq, (void *)&irq_bitmap); /* irq_bitmap |= 1 << irq; */
disable_irq(irq);
return;
}
int autoirq_setup(int waittime)
{
int i, mask;
int timeout = jiffies + waittime;
int boguscount = (waittime*loops_per_sec) / 100;
irq_handled = 0;
for (i = 0; i < 16; i++) {
if (test_bit(i, &irqs_busy) == 0
&& request_irq(i, autoirq_probe, SA_INTERRUPT, "irq probe", NULL) == 0)
set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/
}
/* Update our USED lists. */
irqs_used |= ~irq_handled;
irq_number = 0;
irq_bitmap = 0;
/* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
while (timeout > jiffies && --boguscount > 0)
;
for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
if (irq_bitmap & irq_handled & mask) {
irq_handled &= ~mask;
#ifdef notdef
printk(" Spurious interrupt on IRQ %d\n", i);
#endif
free_irq(i, NULL);
}
}
return irq_handled;
} }
int autoirq_report(int waittime) int autoirq_report(int waittime)
{ {
int i; return probe_irq_off(irqs);
int timeout = jiffies+waittime;
int boguscount = (waittime*loops_per_sec) / 100;
/* Hang out at least <waittime> jiffies waiting for the IRQ. */
while (timeout > jiffies && --boguscount > 0)
if (irq_number)
break;
/* Retract the irq handlers that we installed. */
for (i = 0; i < 16; i++) {
if (test_bit(i, (void *)&irq_handled))
free_irq(i, NULL);
}
return irq_number;
} }
/* /*
......
...@@ -42,6 +42,7 @@ static const char *version = ...@@ -42,6 +42,7 @@ static const char *version =
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/bios32.h> #include <linux/bios32.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -408,6 +409,7 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr)) ...@@ -408,6 +409,7 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
outb_p(0x00, ioaddr + EN0_RCNTLO); outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI); outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
udelay(10000); /* wait 10ms for interrupt to propagate */
outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
dev->irq = autoirq_report(0); dev->irq = autoirq_report(0);
if (ei_debug > 2) if (ei_debug > 2)
......
...@@ -82,7 +82,10 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then ...@@ -82,7 +82,10 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
fi fi
fi fi
if [ "$CONFIG_MCA" = "y" ]; then if [ "$CONFIG_MCA" = "y" ]; then
dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then
bool ' reset SCSI-devices while booting' SCSI_IBMMCA_DEV_RESET
fi
fi fi
if [ "$CONFIG_PARPORT" != "n" ]; then if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
......
This diff is collapsed.
#ifndef _IBMMCA_H #ifndef _IBMMCA_H
#define _IBMMCA_H #define _IBMMCA_H
/* /*
* Low Level Driver for the IBM Microchannel SCSI Subsystem * Low Level Driver for the IBM Microchannel SCSI Subsystem
*/ */
/*services provided to the higher level of Linux SCSI driver */ /*services provided to the higher level of Linux SCSI driver */
int ibmmca_proc_info (char *, char **, off_t, int, int, int);
int ibmmca_detect (Scsi_Host_Template *); int ibmmca_detect (Scsi_Host_Template *);
int ibmmca_release (struct Scsi_Host *); int ibmmca_release (struct Scsi_Host *);
int ibmmca_command (Scsi_Cmnd *); int ibmmca_command (Scsi_Cmnd *);
...@@ -21,9 +21,9 @@ extern struct proc_dir_entry proc_scsi_ibmmca; ...@@ -21,9 +21,9 @@ extern struct proc_dir_entry proc_scsi_ibmmca;
/*initialization for Scsi_host_template type */ /*initialization for Scsi_host_template type */
#define IBMMCA { \ #define IBMMCA { \
NULL, /*next*/ \ NULL, /*next*/ \
NULL, /*module*/ \ NULL, /*usage_count*/ \
&proc_scsi_ibmmca, /*proc_dir*/ \ &proc_scsi_ibmmca, /*proc_dir*/ \
NULL, /*proc info fn*/ \ ibmmca_proc_info, /*proc info fn*/ \
"IBMMCA", /*name*/ \ "IBMMCA", /*name*/ \
ibmmca_detect, /*detect fn*/ \ ibmmca_detect, /*detect fn*/ \
ibmmca_release, /*release fn*/ \ ibmmca_release, /*release fn*/ \
......
...@@ -216,7 +216,7 @@ static int ncp_readdir(struct file *filp, ...@@ -216,7 +216,7 @@ static int ncp_readdir(struct file *filp,
int result = 0; int result = 0;
int i = 0; int i = 0;
int index = 0; int index = 0;
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = filp->f_dentry->d_inode;
struct ncp_dirent *entry = NULL; struct ncp_dirent *entry = NULL;
struct ncp_server *server = NCP_SERVER(inode); struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *dir = NCP_INOP(inode); struct ncp_inode_info *dir = NCP_INOP(inode);
......
...@@ -180,7 +180,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -180,7 +180,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto again; goto again;
} }
if (ismydir && cache->mtime != NFS_OLDMTIME(inode)) if (ismydir && cache->mtime != inode->i_mtime)
cache->valid = 0; cache->valid = 0;
if (!cache->valid || cache->age < dead) { if (!cache->valid || cache->age < dead) {
...@@ -207,7 +207,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -207,7 +207,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (j < cache->size - 1) { if (j < cache->size - 1) {
index = j + 1; index = j + 1;
entry = this_ent + 3; entry = this_ent + 3;
} else if (*(this_ent+2) >> 16) { } else if (*(this_ent+2) & (1 << 15)) {
/* eof */ /* eof */
return 0; return 0;
} }
...@@ -253,7 +253,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -253,7 +253,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
cache->valid = 1; cache->valid = 1;
entry = cache->entry + (index = 0); entry = cache->entry + (index = 0);
} }
cache->mtime = NFS_OLDMTIME(inode); cache->mtime = inode->i_mtime;
cache->age = jiffies; cache->age = jiffies;
/* /*
...@@ -929,99 +929,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -929,99 +929,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return error; return error;
} }
/*
* Many nfs protocol calls return the new file attributes after
* an operation. Here we update the inode to reflect the state
* of the server's inode.
*/
int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
int error = -EIO;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_count);
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
goto out;
}
if (inode->i_ino != fattr->fileid) {
printk("nfs_refresh_inode: inode number mismatch\n");
goto out;
}
/*
* Check whether the mode has been set, as we only want to
* do this once. (We don't allow inodes to change types.)
*/
if (inode->i_mode == 0) {
inode->i_mode = fattr->mode;
if (S_ISREG(inode->i_mode))
inode->i_op = &nfs_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &nfs_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode)) {
inode->i_op = &chrdev_inode_operations;
inode->i_rdev = to_kdev_t(fattr->rdev);
} else if (S_ISBLK(inode->i_mode)) {
inode->i_op = &blkdev_inode_operations;
inode->i_rdev = to_kdev_t(fattr->rdev);
} else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
else
inode->i_op = NULL;
} else if ((inode->i_mode & S_IFMT) == (fattr->mode & S_IFMT)) {
inode->i_mode = fattr->mode;
} else {
mode_t old_mode;
/*
* Big trouble! The inode has become a different object.
*/
#if 1
printk("nfs_refresh_inode: mode changed, %07o to %07o\n",
inode->i_mode, fattr->mode);
#endif
old_mode = inode->i_mode; /* save mode */
make_bad_inode(inode);
inode->i_mode = old_mode; /* restore mode */
inode->i_nlink = 0;
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
* (But we do want to invalidate the caches.)
*/
invalidate_inode_pages(inode);
nfs_invalidate_dircache(inode);
goto out;
}
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
/* Size changed from outside: invalidate caches on next read */
if (inode->i_size != fattr->size) {
dfprintk(PAGECACHE, "NFS: cacheinv(%x/%ld)\n",
inode->i_dev, inode->i_ino);
NFS_CACHEINV(inode);
}
if (NFS_OLDMTIME(inode) != fattr->mtime.seconds) {
dfprintk(PAGECACHE, "NFS: mtime change on %x/%ld\n",
inode->i_dev, inode->i_ino);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
inode->i_size = fattr->size;
inode->i_blocks = fattr->blocks;
inode->i_atime = fattr->atime.seconds;
inode->i_mtime = fattr->mtime.seconds;
inode->i_ctime = fattr->ctime.seconds;
error = 0;
out:
return error;
}
/* /*
* Local variables: * Local variables:
* version-control: t * version-control: t
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
extern void nfs_invalidate_dircache_sb(struct super_block *); extern void nfs_invalidate_dircache_sb(struct super_block *);
...@@ -72,6 +73,7 @@ nfs_read_inode(struct inode * inode) ...@@ -72,6 +73,7 @@ nfs_read_inode(struct inode * inode)
inode->i_rdev = 0; inode->i_rdev = 0;
inode->i_op = NULL; inode->i_op = NULL;
NFS_CACHEINV(inode); NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
} }
static void static void
...@@ -356,14 +358,48 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, ...@@ -356,14 +358,48 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
printk("nfs_fhget: iget failed\n"); printk("nfs_fhget: iget failed\n");
return NULL; return NULL;
} }
if (inode->i_dev == sb->s_dev) { #ifdef NFS_PARANOIA
if (inode->i_ino != fattr->fileid) { if (inode->i_dev != sb->s_dev)
printk("nfs_fhget: unexpected inode from iget\n"); printk("nfs_fhget: impossible\n");
return inode; #endif
}
*NFS_FH(inode) = *fhandle; if (inode->i_ino != fattr->fileid) {
nfs_refresh_inode(inode, fattr); printk("nfs_fhget: unexpected inode from iget\n");
return inode;
}
/*
* Check whether the mode has been set, as we only want to
* do this once. (We don't allow inodes to change types.)
*/
if (inode->i_mode == 0) {
inode->i_mode = fattr->mode;
if (S_ISREG(inode->i_mode))
inode->i_op = &nfs_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &nfs_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode)) {
inode->i_op = &chrdev_inode_operations;
inode->i_rdev = to_kdev_t(fattr->rdev);
} else if (S_ISBLK(inode->i_mode)) {
inode->i_op = &blkdev_inode_operations;
inode->i_rdev = to_kdev_t(fattr->rdev);
} else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
else
inode->i_op = NULL;
/*
* Preset the size and mtime, as there's no need
* to invalidate the caches.
*/
inode->i_size = fattr->size;
inode->i_mtime = fattr->mtime.seconds;
NFS_OLDMTIME(inode) = fattr->mtime.seconds;
} }
*NFS_FH(inode) = *fhandle;
nfs_refresh_inode(inode, fattr);
dprintk("NFS: fhget(%x/%ld ct=%d)\n", dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_dev, inode->i_ino,
inode->i_count); inode->i_count);
...@@ -378,6 +414,17 @@ nfs_notify_change(struct inode *inode, struct iattr *attr) ...@@ -378,6 +414,17 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
struct nfs_fattr fattr; struct nfs_fattr fattr;
int error; int error;
/*
* Make sure the inode is up-to-date.
*/
error = nfs_revalidate(inode);
if (error) {
#ifdef NFS_PARANOIA
printk("nfs_notify_change: revalidate failed, error=%d\n", error);
#endif
goto out;
}
sattr.mode = (u32) -1; sattr.mode = (u32) -1;
if (attr->ia_valid & ATTR_MODE) if (attr->ia_valid & ATTR_MODE)
sattr.mode = attr->ia_mode; sattr.mode = attr->ia_mode;
...@@ -390,7 +437,6 @@ nfs_notify_change(struct inode *inode, struct iattr *attr) ...@@ -390,7 +437,6 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
if (attr->ia_valid & ATTR_GID) if (attr->ia_valid & ATTR_GID)
sattr.gid = attr->ia_gid; sattr.gid = attr->ia_gid;
sattr.size = (u32) -1; sattr.size = (u32) -1;
if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
sattr.size = attr->ia_size; sattr.size = attr->ia_size;
...@@ -408,11 +454,25 @@ nfs_notify_change(struct inode *inode, struct iattr *attr) ...@@ -408,11 +454,25 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
} }
error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode), error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
&sattr, &fattr); &sattr, &fattr);
if (!error) { if (error)
goto out;
/*
* If we changed the size or mtime, update the inode
* now to avoid invalidating the page cache.
*/
if (sattr.size != (u32) -1) {
if (sattr.size != fattr.size)
printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
sattr.size, fattr.size);
nfs_truncate_dirty_pages(inode, sattr.size); nfs_truncate_dirty_pages(inode, sattr.size);
nfs_refresh_inode(inode, &fattr); inode->i_size = sattr.size;
inode->i_mtime = fattr.mtime.seconds;
} }
if (sattr.mtime.seconds != (u32) -1)
inode->i_mtime = fattr.mtime.seconds;
error = nfs_refresh_inode(inode, &fattr);
out:
return error; return error;
} }
...@@ -428,56 +488,154 @@ nfs_revalidate(struct inode *inode) ...@@ -428,56 +488,154 @@ nfs_revalidate(struct inode *inode)
/* /*
* This function is called whenever some part of NFS notices that * This function is called whenever some part of NFS notices that
* the cached attributes have to be refreshed. * the cached attributes have to be refreshed.
*
* This is a bit tricky because we have to make sure all dirty pages
* have been sent off to the server before calling invalidate_inode_pages.
* To make sure no other process adds more write requests while we try
* our best to flush them, we make them sleep during the attribute refresh.
*
* A very similar scenario holds for the dir cache.
*/ */
int int
_nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) _nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{ {
struct nfs_fattr fattr; struct nfs_fattr fattr;
int status; int status = 0;
if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode)) if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
return 0; goto out;
dfprintk(PAGECACHE, "NFS: revalidating %x/%ld inode\n", dfprintk(PAGECACHE, "NFS: revalidating %x/%ld inode\n",
inode->i_dev, inode->i_ino); inode->i_dev, inode->i_ino);
NFS_READTIME(inode) = jiffies; status = nfs_proc_getattr(server, NFS_FH(inode), &fattr);
if ((status = nfs_proc_getattr(server, NFS_FH(inode), &fattr)) < 0) if (status) {
#ifdef NFS_PARANOIA
printk("nfs_revalidate_inode: getattr failed, error=%d\n", status);
#endif
goto done; goto done;
}
nfs_refresh_inode(inode, &fattr); status = nfs_refresh_inode(inode, &fattr);
if (fattr.mtime.seconds != NFS_OLDMTIME(inode)) { if (status)
if (!S_ISDIR(inode->i_mode)) { goto done;
/* This sends off all dirty pages off to the server. if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) {
* Note that this function must not sleep. */
nfs_invalidate_pages(inode);
invalidate_inode_pages(inode);
} else {
nfs_invalidate_dircache(inode);
}
NFS_OLDMTIME(inode) = fattr.mtime.seconds;
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
} else {
/* Update attrtimeo value */ /* Update attrtimeo value */
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode)) if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode); NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
} }
status = 0; NFS_OLDMTIME(inode) = fattr.mtime.seconds;
done: done:
dfprintk(PAGECACHE, dfprintk(PAGECACHE,
"NFS: inode %x/%ld revalidation complete (status %d).\n", "NFS: inode %x/%ld revalidation complete (status %d).\n",
inode->i_dev, inode->i_ino, status); inode->i_dev, inode->i_ino, status);
out:
return status; return status;
} }
/*
* Many nfs protocol calls return the new file attributes after
* an operation. Here we update the inode to reflect the state
* of the server's inode.
*
* This is a bit tricky because we have to make sure all dirty pages
* have been sent off to the server before calling invalidate_inode_pages.
* To make sure no other process adds more write requests while we try
* our best to flush them, we make them sleep during the attribute refresh.
*
* A very similar scenario holds for the dir cache.
*/
int
nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
int invalid = 0;
int error = -EIO;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_count);
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
goto out;
}
if (inode->i_ino != fattr->fileid) {
printk("nfs_refresh_inode: inode number mismatch\n");
goto out;
}
/*
* Make sure the inode's type hasn't changed.
*/
if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
goto out_changed;
/*
* If the size or mtime changed from outside, we want
* to invalidate the local caches immediately.
*/
if (inode->i_size != fattr->size) {
#ifdef NFS_DEBUG_VERBOSE
printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
invalid = 1;
}
if (inode->i_mtime != fattr->mtime.seconds) {
#ifdef NFS_DEBUG_VERBOSE
printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
invalid = 1;
}
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
inode->i_size = fattr->size;
inode->i_blocks = fattr->blocks;
inode->i_atime = fattr->atime.seconds;
inode->i_mtime = fattr->mtime.seconds;
inode->i_ctime = fattr->ctime.seconds;
/*
* Update the read time so we don't revalidate too often.
*/
NFS_READTIME(inode) = jiffies;
error = 0;
if (invalid)
goto out_invalid;
out:
return error;
out_changed:
/*
* Big trouble! The inode has become a different object.
*/
#ifdef NFS_PARANOIA
printk("nfs_refresh_inode: mode changed, %07o to %07o\n",
inode->i_mode, fattr->mode);
#endif
fattr->mode = inode->i_mode; /* save mode */
make_bad_inode(inode);
inode->i_mode = fattr->mode; /* restore mode */
inode->i_nlink = 0;
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
* (But we fall through to invalidate the caches.)
*/
out_invalid:
/*
* Invalidate the local caches
*/
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
#endif
if (!S_ISDIR(inode->i_mode)) {
/* This sends off all dirty pages off to the server.
* Note that this function must not sleep. */
nfs_invalidate_pages(inode);
invalidate_inode_pages(inode);
} else
nfs_invalidate_dircache(inode);
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
goto out;
}
/* /*
* File system information * File system information
*/ */
......
...@@ -196,22 +196,44 @@ nfs_writepage_sync(struct inode *inode, struct page *page, ...@@ -196,22 +196,44 @@ nfs_writepage_sync(struct inode *inode, struct page *page,
clear_bit(PG_uptodate, &page->flags); clear_bit(PG_uptodate, &page->flags);
goto io_error; goto io_error;
} }
if (result != wsize)
printk("NFS: short write, wsize=%u, result=%d\n",
wsize, result);
refresh = 1; refresh = 1;
buffer += wsize; buffer += wsize;
offset += wsize; offset += wsize;
written += wsize; written += wsize;
count -= wsize; count -= wsize;
/*
* If we've extended the file, update the inode
* now so we don't invalidate the cache.
*/
if (offset > inode->i_size)
inode->i_size = offset;
} while (count); } while (count);
io_error: io_error:
/* N.B. do we want to refresh if there was an error?? (fattr valid?) */
if (refresh) { if (refresh) {
/* See comments in nfs_wback_result */ /* See comments in nfs_wback_result */
/* N.B. I don't think this is right -- sync writes in order */
if (fattr.size < inode->i_size) if (fattr.size < inode->i_size)
fattr.size = inode->i_size; fattr.size = inode->i_size;
if (fattr.mtime.seconds < inode->i_mtime)
printk("nfs_writepage_sync: prior time??\n");
/* Solaris 2.5 server seems to send garbled /* Solaris 2.5 server seems to send garbled
* fattrs occasionally */ * fattrs occasionally */
if (inode->i_ino == fattr.fileid) if (inode->i_ino == fattr.fileid) {
/*
* We expect the mtime value to change, and
* don't want to invalidate the caches.
*/
inode->i_mtime = fattr.mtime.seconds;
nfs_refresh_inode(inode, &fattr); nfs_refresh_inode(inode, &fattr);
}
else
printk("nfs_writepage_sync: inode %ld, got %u?\n",
inode->i_ino, fattr.fileid);
} }
nfs_unlock_page(page); nfs_unlock_page(page);
...@@ -327,7 +349,7 @@ create_write_request(struct inode *inode, struct page *page, ...@@ -327,7 +349,7 @@ create_write_request(struct inode *inode, struct page *page,
wreq = (struct nfs_wreq *) kmalloc(sizeof(*wreq), GFP_USER); wreq = (struct nfs_wreq *) kmalloc(sizeof(*wreq), GFP_USER);
if (!wreq) if (!wreq)
return NULL; goto out_fail;
memset(wreq, 0, sizeof(*wreq)); memset(wreq, 0, sizeof(*wreq));
task = &wreq->wb_task; task = &wreq->wb_task;
...@@ -336,11 +358,8 @@ create_write_request(struct inode *inode, struct page *page, ...@@ -336,11 +358,8 @@ create_write_request(struct inode *inode, struct page *page,
task->tk_action = nfs_wback_lock; task->tk_action = nfs_wback_lock;
rpcauth_lookupcred(task); /* Obtain user creds */ rpcauth_lookupcred(task); /* Obtain user creds */
if (task->tk_status < 0) { if (task->tk_status < 0)
rpc_release_task(task); goto out_req;
kfree(wreq);
return NULL;
}
/* Put the task on inode's writeback request list. */ /* Put the task on inode's writeback request list. */
wreq->wb_inode = inode; wreq->wb_inode = inode;
...@@ -357,6 +376,12 @@ create_write_request(struct inode *inode, struct page *page, ...@@ -357,6 +376,12 @@ create_write_request(struct inode *inode, struct page *page,
rpc_wake_up_next(&write_queue); rpc_wake_up_next(&write_queue);
return wreq; return wreq;
out_req:
rpc_release_task(task);
kfree(wreq);
out_fail:
return NULL;
} }
/* /*
...@@ -423,6 +448,8 @@ wait_on_write_request(struct nfs_wreq *req) ...@@ -423,6 +448,8 @@ wait_on_write_request(struct nfs_wreq *req)
} }
remove_wait_queue(&page->wait, &wait); remove_wait_queue(&page->wait, &wait);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
if (atomic_read(&page->count) == 1)
printk("NFS: lost a page\n");
atomic_dec(&page->count); atomic_dec(&page->count);
return retval; return retval;
} }
...@@ -808,15 +835,29 @@ nfs_wback_result(struct rpc_task *task) ...@@ -808,15 +835,29 @@ nfs_wback_result(struct rpc_task *task)
} }
clear_bit(PG_uptodate, &page->flags); clear_bit(PG_uptodate, &page->flags);
} else if (!WB_CANCELLED(req)) { } else if (!WB_CANCELLED(req)) {
struct nfs_fattr *fattr = req->wb_fattr;
/* Update attributes as result of writeback. /* Update attributes as result of writeback.
* Beware: when UDP replies arrive out of order, we * Beware: when UDP replies arrive out of order, we
* may end up overwriting a previous, bigger file size. * may end up overwriting a previous, bigger file size.
*/ */
if (req->wb_fattr->size < inode->i_size) if (fattr->mtime.seconds >= inode->i_mtime) {
req->wb_fattr->size = inode->i_size; if (fattr->size < inode->i_size)
/* possible Solaris 2.5 server bug workaround */ fattr->size = inode->i_size;
if (inode->i_ino == req->wb_fattr->fileid)
nfs_refresh_inode(inode, req->wb_fattr); /* possible Solaris 2.5 server bug workaround */
if (inode->i_ino == fattr->fileid) {
/*
* We expect these values to change, and
* don't want to invalidate the caches.
*/
inode->i_size = fattr->size;
inode->i_mtime = fattr->mtime.seconds;
nfs_refresh_inode(inode, fattr);
}
else
printk("nfs_wback_result: inode %ld, got %u?\n",
inode->i_ino, fattr->fileid);
}
} }
rpc_release_task(task); rpc_release_task(task);
......
...@@ -840,6 +840,13 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data) ...@@ -840,6 +840,13 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
int retval; int retval;
struct vfsmount *vfsmnt; struct vfsmount *vfsmnt;
/*
* Invalidate the inodes, as some mount options may be changed.
* N.B. If we are changing media, we should check the return
* from invalidate_inodes ... can't allow _any_ open files.
*/
invalidate_inodes(sb);
if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
return -EACCES; return -EACCES;
/*flags |= MS_RDONLY;*/ /*flags |= MS_RDONLY;*/
...@@ -870,8 +877,14 @@ static int do_remount(const char *dir,int flags,char *data) ...@@ -870,8 +877,14 @@ static int do_remount(const char *dir,int flags,char *data)
struct super_block * sb = dentry->d_inode->i_sb; struct super_block * sb = dentry->d_inode->i_sb;
retval = -EINVAL; retval = -EINVAL;
if (dentry == sb->s_root) if (dentry == sb->s_root) {
/*
* Shrink the dcache and sync the device.
*/
shrink_dcache_sb(sb);
fsync_dev(sb->s_dev);
retval = do_remount_sb(sb, flags, data); retval = do_remount_sb(sb, flags, data);
}
dput(dentry); dput(dentry);
} }
return retval; return retval;
......
...@@ -30,7 +30,7 @@ extern unsigned long occupy_region(unsigned long base, unsigned long end, ...@@ -30,7 +30,7 @@ extern unsigned long occupy_region(unsigned long base, unsigned long end,
#define HAVE_AUTOIRQ #define HAVE_AUTOIRQ
extern void *irq2dev_map[16]; /* Use only if you own the IRQ. */ extern void *irq2dev_map[16]; /* Use only if you own the IRQ. */
extern int autoirq_setup(int waittime); extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime); extern int autoirq_report(int waittime);
#endif /* _LINUX_PORTIO_H */ #endif /* _LINUX_PORTIO_H */
...@@ -33,6 +33,12 @@ ...@@ -33,6 +33,12 @@
# define ATTRIB_NORET __attribute__((noreturn)) # define ATTRIB_NORET __attribute__((noreturn))
# define NORET_AND noreturn, # define NORET_AND noreturn,
#ifdef __i386__
#define FASTCALL(x) x __attribute__((regparm(3)))
#else
#define FASTCALL(x) x
#endif
extern void math_error(void); extern void math_error(void);
NORET_TYPE void panic(const char * fmt, ...) NORET_TYPE void panic(const char * fmt, ...)
__attribute__ ((NORET_AND format (printf, 1, 2))); __attribute__ ((NORET_AND format (printf, 1, 2)));
......
...@@ -241,7 +241,7 @@ extern mem_map_t * mem_map; ...@@ -241,7 +241,7 @@ extern mem_map_t * mem_map;
*/ */
#define __get_free_page(priority) __get_free_pages((priority),0,0) #define __get_free_page(priority) __get_free_pages((priority),0,0)
#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1) #define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1)
extern unsigned long __get_free_pages(int priority, unsigned long gfporder, int dma); extern unsigned long FASTCALL(__get_free_pages(int priority, unsigned long gfporder, int dma));
extern inline unsigned long get_free_page(int priority) extern inline unsigned long get_free_page(int priority)
{ {
...@@ -256,8 +256,8 @@ extern inline unsigned long get_free_page(int priority) ...@@ -256,8 +256,8 @@ extern inline unsigned long get_free_page(int priority)
/* memory.c & swap.c*/ /* memory.c & swap.c*/
#define free_page(addr) free_pages((addr),0) #define free_page(addr) free_pages((addr),0)
extern void free_pages(unsigned long addr, unsigned long order); extern void FASTCALL(free_pages(unsigned long addr, unsigned long order));
extern void __free_page(struct page *); extern void FASTCALL(__free_page(struct page *));
extern void show_free_areas(void); extern void show_free_areas(void);
extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
......
...@@ -439,11 +439,11 @@ extern int securelevel; /* system security level */ ...@@ -439,11 +439,11 @@ extern int securelevel; /* system security level */
#define CURRENT_TIME (xtime.tv_sec) #define CURRENT_TIME (xtime.tv_sec)
extern void sleep_on(struct wait_queue ** p); extern void FASTCALL(sleep_on(struct wait_queue ** p));
extern void interruptible_sleep_on(struct wait_queue ** p); extern void FASTCALL(interruptible_sleep_on(struct wait_queue ** p));
extern void wake_up(struct wait_queue ** p); extern void FASTCALL(wake_up(struct wait_queue ** p));
extern void wake_up_interruptible(struct wait_queue ** p); extern void FASTCALL(wake_up_interruptible(struct wait_queue ** p));
extern void wake_up_process(struct task_struct * tsk); extern void FASTCALL(wake_up_process(struct task_struct * tsk));
extern void notify_parent(struct task_struct * tsk, int signal); extern void notify_parent(struct task_struct * tsk, int signal);
extern void force_sig(unsigned long sig,struct task_struct * p); extern void force_sig(unsigned long sig,struct task_struct * p);
......
...@@ -73,7 +73,7 @@ extern unsigned int nr_swapfiles; ...@@ -73,7 +73,7 @@ extern unsigned int nr_swapfiles;
extern struct swap_info_struct swap_info[]; extern struct swap_info_struct swap_info[];
void si_swapinfo(struct sysinfo *); void si_swapinfo(struct sysinfo *);
unsigned long get_swap_page(void); unsigned long get_swap_page(void);
extern void swap_free(unsigned long); extern void FASTCALL(swap_free(unsigned long));
/* /*
* vm_ops not present page codes for shared memory. * vm_ops not present page codes for shared memory.
......
...@@ -104,7 +104,7 @@ struct kernel_stat kstat = { 0 }; ...@@ -104,7 +104,7 @@ struct kernel_stat kstat = { 0 };
static inline void add_to_runqueue(struct task_struct * p) static inline void add_to_runqueue(struct task_struct * p)
{ {
if (p->counter > current->counter + 3) if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
need_resched = 1; need_resched = 1;
nr_running++; nr_running++;
(p->prev_run = init_task.prev_run)->next_run = p; (p->prev_run = init_task.prev_run)->next_run = p;
...@@ -649,14 +649,14 @@ int __down_interruptible(struct semaphore * sem) ...@@ -649,14 +649,14 @@ int __down_interruptible(struct semaphore * sem)
} }
static inline void __sleep_on(struct wait_queue **p, int state) static void FASTCALL(__sleep_on(struct wait_queue **p, int state));
static void __sleep_on(struct wait_queue **p, int state)
{ {
unsigned long flags; unsigned long flags;
struct wait_queue wait = { current, NULL }; struct wait_queue wait;
if (!p)
return;
current->state = state; current->state = state;
wait.task = current;
write_lock_irqsave(&waitqueue_lock, flags); write_lock_irqsave(&waitqueue_lock, flags);
__add_wait_queue(p, &wait); __add_wait_queue(p, &wait);
write_unlock(&waitqueue_lock); write_unlock(&waitqueue_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment