Commit 7f98bfdb authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.65

parent 3e213f64
......@@ -451,6 +451,17 @@ S: 1123 North Oak Park Avenue
S: Oak Park, Illinois 60302
S: USA
N: Jim Freeman
E: jfree@caldera.com
W: http://www.sovereign.org/
D: Initial GPL'd Frame Relay driver
D: Dynamic PPP devices
D: Sundry modularizations (PPP, IPX, ...) and fixes
S: Caldera, Inc.
S: 240 West Center St.
S: Orem, Utah 84059-1920
S: USA
N: Bob Frey
E: bobf@advansys.com
D: AdvanSys SCSI driver
......
VERSION = 2
PATCHLEVEL = 1
SUBLEVEL = 64
SUBLEVEL = 65
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
......@@ -349,6 +349,10 @@ ENTRY(page_fault)
pushl $ SYMBOL_NAME(do_page_fault)
jmp error_code
ENTRY(page_fault_f00f)
pushl $ SYMBOL_NAME(do_page_fault_f00f)
jmp error_code
ENTRY(spurious_interrupt_bug)
pushl $0
pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
......
......@@ -103,6 +103,7 @@ asmlinkage void segment_not_present(void);
asmlinkage void stack_segment(void);
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void page_fault_f00f(void);
asmlinkage void coprocessor_error(void);
asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
......@@ -417,6 +418,14 @@ __initfunc(void trap_init_f00f_bug(void))
{
unsigned long page;
/*
* We use a special page fault handler, to actually detect
* 'bounced' traps/exceptions #0-6. This new page fault
* handler is a few tens of cycles slower than the 'normal'
* one.
*/
set_trap_gate(14,&page_fault_f00f);
/*
* Allocate a new page in virtual address space,
* and move the IDT to have entry #7 starting at
......@@ -433,6 +442,7 @@ __initfunc(void trap_init_f00f_bug(void))
*/
idt = (struct desc_struct *)(page - 7*8);
__asm__ __volatile__("lidt %0": "=m" (idt_descr));
}
......
......@@ -74,15 +74,6 @@ int __verify_write(const void * addr, unsigned long size)
return 0;
}
asmlinkage void do_divide_error (struct pt_regs *, unsigned long);
asmlinkage void do_debug (struct pt_regs *, unsigned long);
asmlinkage void do_nmi (struct pt_regs *, unsigned long);
asmlinkage void do_int3 (struct pt_regs *, unsigned long);
asmlinkage void do_overflow (struct pt_regs *, unsigned long);
asmlinkage void do_bounds (struct pt_regs *, unsigned long);
asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
extern int pentium_f00f_bug;
/*
* This routine handles page faults. It determines the address,
......@@ -94,45 +85,17 @@ extern int pentium_f00f_bug;
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
static void __do_page_fault(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
unsigned long address;
unsigned long page;
unsigned long fixup;
int write;
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
/*
* Pentium F0 0F C7 C8 bug workaround. Do this first,
* to make sure we don't have locking problems with
* asynchronous traps (ie NMI).
*/
if ( !(error_code & 7) && pentium_f00f_bug ) {
unsigned long nr;
nr = (address - (unsigned long) idt) >> 3;
if (nr < 7) {
static void (*handler[])(struct pt_regs *, unsigned long) = {
do_divide_error, /* 0 - divide overflow */
do_debug, /* 1 - debug trap */
do_nmi, /* 2 - NMI */
do_int3, /* 3 - int 3 */
do_overflow, /* 4 - overflow */
do_bounds, /* 5 - bound range */
do_invalid_op }; /* 6 - invalid opcode */
handler[nr](regs, 0);
return;
}
}
lock_kernel();
tsk = current;
mm = tsk->mm;
......@@ -253,3 +216,65 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
out:
unlock_kernel();
}
/*
* One of these two functions is the real page fault handler, which one depends
* on wether the CPU has the F00F bug:
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
unsigned long address;
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
__do_page_fault(regs, error_code, address);
}
asmlinkage void do_divide_error (struct pt_regs *, unsigned long);
asmlinkage void do_debug (struct pt_regs *, unsigned long);
asmlinkage void do_nmi (struct pt_regs *, unsigned long);
asmlinkage void do_int3 (struct pt_regs *, unsigned long);
asmlinkage void do_overflow (struct pt_regs *, unsigned long);
asmlinkage void do_bounds (struct pt_regs *, unsigned long);
asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
extern int pentium_f00f_bug;
asmlinkage void do_page_fault_f00f(struct pt_regs *regs, unsigned long error_code)
{
unsigned long address;
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
/*
* Pentium F0 0F C7 C8 bug workaround. Do this first,
* to make sure we don't have locking problems with
* asynchronous traps (ie NMI).
*/
if ( !(error_code & 5) && pentium_f00f_bug ) {
unsigned long nr;
nr = (address - (unsigned long) idt) >> 3;
if (nr < 7) {
static void (*handler[])(struct pt_regs *, unsigned long) = {
do_divide_error, /* 0 - divide overflow */
do_debug, /* 1 - debug trap */
do_nmi, /* 2 - NMI */
do_int3, /* 3 - int 3 */
do_overflow, /* 4 - overflow */
do_bounds, /* 5 - bound range */
do_invalid_op }; /* 6 - invalid opcode */
if (nr == 3 || nr == 4) regs->eip++;
handler[nr](regs, 0);
return;
}
}
__do_page_fault(regs, error_code, address);
}
......@@ -4,7 +4,7 @@ FAQ list:
=========
A FAQ list may be found in the fdutils package (see below), and also
at http://www.club.innet.lu/~year3160/floppy/FAQ.html
at http://poboxes.com/Alain.Knaff/floppy/FAQ.html
Lilo config options (Thinkpad users, read this)
......
......@@ -3274,7 +3274,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
case BLKRAGET:
return put_user(read_ahead[MAJOR(inode->i_rdev)],
(int *) param);
(long *) param);
case BLKFLSBUF:
if(!suser()) return -EACCES;
fsync_dev(inode->i_rdev);
......@@ -3283,7 +3283,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case BLKGETSIZE:
ECALL(get_floppy_geometry(drive, type, &g));
return put_user(g->size, (int *) param);
return put_user(g->size, (long *) param);
/* BLKRRPART is not defined as floppies don't have
* partition tables */
}
......
This diff is collapsed.
......@@ -100,7 +100,7 @@ static char *PPA_MODE_STRING[] =
int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */
/* other options */
#define PPA_CAN_QUEUE 0 /* use "queueing" interface */
#define PPA_CAN_QUEUE 1 /* use "queueing" interface */
#define PPA_BURST_SIZE 512 /* data burst size */
#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */
#define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */
......
......@@ -37,7 +37,7 @@
/* if you have lowlevel.h in the lowlevel directory (OSS-Lite), define
* the following line.
*/
#undef HAS_LOWLEVEL_H
#define HAS_LOWLEVEL_H
/* if your system doesn't support patch manager (OSS 3.7 or newer),
* define the following line.
......
......@@ -327,7 +327,7 @@ sound_mmap (struct file *file, struct vm_area_struct *vma)
vma->vm_page_prot))
return -EAGAIN;
vma->vm_dentry = file->f_dentry;
vma->vm_dentry = dget(file->f_dentry);
dmap->mapping_flags |= DMA_MAP_MAPPED;
......
......@@ -118,6 +118,11 @@ void dput(struct dentry *dentry)
}
list_add(&dentry->d_lru, &dentry_unused);
dentry_stat.nr_unused++;
/*
* Update the timestamp
*/
dentry->d_reftime = jiffies;
out:
if (count >= 0) {
dentry->d_count = count;
......@@ -135,15 +140,12 @@ void dput(struct dentry *dentry)
* Try to invalidate the dentry if it turns out to be
* possible. If there are other users of the dentry we
* can't invalidate it.
*
* We should probably try to see if we can invalidate
* any unused children - right now we refuse to invalidate
* too much. That would require a better child list
* data structure, though.
*/
int d_invalidate(struct dentry * dentry)
{
/* We might want to do a partial shrink_dcache here */
/* Check whether to do a partial shrink_dcache */
if (dentry->d_count > 1 && !list_empty(&dentry->d_subdirs))
shrink_dcache_parent(dentry);
if (dentry->d_count != 1)
return -EBUSY;
......@@ -152,27 +154,31 @@ int d_invalidate(struct dentry * dentry)
}
/*
* Selects less valuable dentries to be pruned when
* we need inodes or memory. The selected dentries
* are moved to the old end of the list where
* prune_dcache() can find them.
* Select less valuable dentries to be pruned when we need
* inodes or memory. The selected dentries are moved to the
* old end of the list where prune_dcache() can find them.
*
* Negative dentries are included in the selection so that
* they don't accumulate at the end of the list. The count
* returned is the total number of dentries selected, which
* may be much larger than the requested number of inodes.
*/
int select_dcache(int count, int page_count)
int select_dcache(int inode_count, int page_count)
{
struct list_head *tail = &dentry_unused;
struct list_head *next = dentry_unused.prev;
int forward = 0, young = 0, depth = dentry_stat.nr_unused >> 1;
int found = 0, pages = 0;
struct list_head *next, *tail = &dentry_unused;
int found = 0, forward = 0, young = 8;
int depth = dentry_stat.nr_unused >> 1;
unsigned long min_value = 0, max_value = 4;
#ifdef DCACHE_DEBUG
printk("select_dcache: %d unused, count=%d, pages=%d\n",
dentry_stat.nr_unused, count, page_count);
#endif
if (page_count)
max_value = -1;
next = tail->prev;
while (next != &dentry_unused && depth--) {
struct list_head *tmp = next;
struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
struct inode *inode = dentry->d_inode;
unsigned long value = 0;
unsigned long value = 0;
next = tmp->prev;
if (forward)
......@@ -184,56 +190,57 @@ dentry_stat.nr_unused, count, page_count);
continue;
}
/*
* Select dentries based on the page cache count ...
* should factor in number of uses as well.
*/
if (inode) {
if (inode->i_state)
continue;
value = inode->i_nrpages;
}
/*
* Consider various exemptions ...
* Check the dentry's age to see whether to change direction.
*/
if (!page_count) {
if (!inode)
continue;
if (value >= 3)
continue;
} else if (!forward) {
if (inode) {
int age = CURRENT_TIME - inode->i_atime;
if (age < dentry_stat.age_limit) {
if (++young > 8) {
forward = 1;
next = dentry_unused.next;
if (!forward) {
int age = (jiffies - dentry->d_reftime) / HZ;
if (age < dentry_stat.age_limit) {
if (!--young) {
forward = 1;
next = dentry_unused.next;
/*
* Update the limits -- we don't want
* files with too few or too many pages.
*/
if (page_count) {
min_value = 3;
max_value = 15;
}
#ifdef DCACHE_DEBUG
printk("select_dcache: age=%d, pages=%d, scanning forward\n", age, pages);
printk("select_dcache: %s/%s age=%d, scanning forward\n",
dentry->d_parent->d_name.name, dentry->d_name.name, age);
#endif
}
continue;
}
continue;
}
} else {
/*
* If we're scanning from the front, don't take
* files with only a trivial amount of memory.
*/
if (value < 3 || value > 15)
}
/*
* Select dentries based on the page cache count ...
* should factor in number of uses as well. We take
* all negative dentries so that they don't accumulate.
* (We skip inodes that aren't immediately available.)
*/
if (inode) {
value = inode->i_nrpages;
if (value >= max_value || value < min_value)
continue;
if (inode->i_state || inode->i_count > 1)
continue;
}
/*
* Move the dentry behind the tail
* Move the selected dentries behind the tail.
*/
if (tmp != tail->prev) {
list_del(tmp);
list_add(tmp, tail->prev);
}
tail = tmp;
pages += value;
if (++found >= count)
found++;
if (inode && --inode_count <= 0)
break;
if (page_count && pages >= page_count)
if (page_count && (page_count -= value) <= 0)
break;
}
return found;
......@@ -430,7 +437,7 @@ void check_dcache_memory()
if (goal) {
if (goal > 50)
goal = 50;
count = select_dcache(128, goal);
count = select_dcache(32, goal);
#ifdef DCACHE_DEBUG
printk("check_dcache_memory: goal=%d, count=%d\n", goal, count);
#endif
......@@ -453,7 +460,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
* Prune the dcache if there are too many unused dentries.
*/
if (dentry_stat.nr_unused > 3*(nr_inodes >> 1)) {
#ifdef DCACHE_PARANOIA
#ifdef DCACHE_DEBUG
printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused);
#endif
prune_dcache(8);
......@@ -579,30 +586,33 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
int d_validate(struct dentry *dentry, struct dentry *dparent,
unsigned int hash, unsigned int len)
{
struct list_head *base = d_hash(dparent, hash);
struct list_head *lhp = base;
while ((lhp = lhp->next) != base) {
if (dentry == list_entry(lhp, struct dentry, d_hash))
goto found_it;
}
/* Special case, local mount points don't live in the hashes.
* So if we exhausted the chain, search the super blocks.
*/
if (dentry && dentry == dparent) {
struct super_block *sb;
struct list_head *base, *lhp;
int valid = 1;
if (dentry != dparent) {
base = d_hash(dparent, hash);
lhp = base;
while ((lhp = lhp->next) != base) {
if (dentry == list_entry(lhp, struct dentry, d_hash))
goto out;
}
} else {
/*
* Special case: local mount points don't live in
* the hashes, so we search the super blocks.
*/
struct super_block *sb = super_blocks + 0;
for (sb = super_blocks + 0; sb < super_blocks + NR_SUPER; sb++) {
for (; sb < super_blocks + NR_SUPER; sb++) {
if (!sb->s_dev)
continue;
if (sb->s_root == dentry)
goto found_it;
goto out;
}
}
return 0;
found_it:
return (dentry->d_parent == dparent) &&
(dentry->d_name.hash == hash) &&
(dentry->d_name.len == len);
valid = 0;
out:
return valid;
}
/*
......
......@@ -358,33 +358,30 @@ static int free_inodes(int goal)
*/
static void try_to_free_inodes(int goal)
{
int retried = 0, found;
int retry = 1, found;
/*
* Check whether to preshrink the dcache ...
*/
if (inodes_stat.preshrink) {
spin_unlock(&inode_lock);
select_dcache(goal, 0);
prune_dcache(goal);
spin_lock(&inode_lock);
}
if (inodes_stat.preshrink)
goto preshrink;
repeat:
found = free_inodes(goal);
/*
* If we didn't free any inodes, do a limited
* pruning of the dcache to help the next time.
*/
if (!found) {
retry = 0;
do {
if (free_inodes(goal))
break;
/*
* If we didn't free any inodes, do a limited
* pruning of the dcache to help the next time.
*/
preshrink:
spin_unlock(&inode_lock);
select_dcache(goal, 0);
prune_dcache(goal);
found = select_dcache(goal, 0);
if (found < goal)
found = goal;
prune_dcache(found);
spin_lock(&inode_lock);
if (inodes_stat.preshrink && !retried++)
goto repeat;
}
} while (retry--);
}
/*
......@@ -440,11 +437,11 @@ static struct inode * grow_inodes(void)
* If the allocation failed, do an extensive pruning of
* the dcache and then try again to free some inodes.
*/
prune_dcache(128);
prune_dcache(inodes_stat.nr_inodes >> 2);
inodes_stat.preshrink = 1;
spin_lock(&inode_lock);
free_inodes(128);
free_inodes(inodes_stat.nr_inodes >> 2);
{
struct list_head *tmp = inode_unused.next;
if (tmp != &inode_unused) {
......
......@@ -32,10 +32,16 @@ static struct semaphore nlm_file_sema = MUTEX;
* Lookup file info. If it doesn't exist, create a file info struct
* and open a (VFS) file for the given inode.
*
* The NFS filehandle must have been validated prior to this call,
* as we assume that the dentry pointer is valid.
*
* FIXME:
* Note that we open the file O_RDONLY even when creating write locks.
* This is not quite right, but for now, we assume the client performs
* the proper R/W checking.
*
* The dentry in the FH may not be validated .. can we call this with
* the full svc_fh?
*/
u32
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
......@@ -43,21 +49,24 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
{
struct nlm_file *file;
struct knfs_fh *fh = (struct knfs_fh *) f;
unsigned int hash = FILE_HASH(fh->fh_dhash);
struct dentry *dentry = fh->fh_dcookie;
unsigned int hash = FILE_HASH(dentry->d_name.hash);
u32 nfserr;
dprintk("lockd: nlm_file_lookup(%p)\n", fh->fh_dentry);
dprintk("lockd: nlm_file_lookup(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
/* Lock file table */
down(&nlm_file_sema);
for (file = nlm_files[hash]; file; file = file->f_next) {
if (file->f_handle.fh_dentry == fh->fh_dentry
if (file->f_handle.fh_dcookie == dentry
&& !memcmp(&file->f_handle, fh, sizeof(*fh)))
goto found;
}
dprintk("lockd: creating file for %p\n", fh->fh_dentry);
dprintk("lockd: creating file for %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
if (!(file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL))) {
up(&nlm_file_sema);
return nlm_lck_denied_nolocks;
......
......@@ -235,9 +235,11 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
result = ERR_PTR(-ENOMEM);
if (dentry) {
int error = dir->i_op->lookup(dir, dentry);
result = ERR_PTR(error);
if (!error)
result = dentry;
result = dentry;
if (error) {
dput(dentry);
result = ERR_PTR(error);
}
}
}
up(&dir->i_sem);
......
......@@ -179,27 +179,24 @@ exp_export(struct nfsctl_export *nxp)
}
/* Look up the dentry */
err = -EINVAL;
dentry = lookup_dentry(nxp->ex_path, NULL, 0);
if (IS_ERR(dentry)) {
err = -EINVAL;
if (IS_ERR(dentry))
goto finish;
}
err = -ENOENT;
inode = dentry->d_inode;
if(!inode) {
err = -ENOENT;
if(!inode)
goto finish;
}
err = -EINVAL;
if(inode->i_dev != nxp->ex_dev || inode->i_ino != nxp->ex_ino) {
/* I'm just being paranoid... */
err = -EINVAL;
goto finish;
}
/* We currently export only dirs. */
if (!S_ISDIR(inode->i_mode)) {
err = -ENOTDIR;
err = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
goto finish;
}
/* If this is a sub-export, must be root of FS */
if ((parent = exp_parent(clp, dev)) != NULL) {
......@@ -211,10 +208,9 @@ exp_export(struct nfsctl_export *nxp)
}
}
if (!(exp = kmalloc(sizeof(*exp), GFP_USER))) {
err = -ENOMEM;
err = -ENOMEM;
if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
goto finish;
}
dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
strcpy(exp->ex_path, nxp->ex_path);
......
......@@ -17,11 +17,11 @@
#include <linux/fcntl.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/nfs.h>
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/malloc.h>
#include <linux/nfs.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
......@@ -38,6 +38,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
extern void nfsd_fh_init(void);
extern long sys_call_table[];
static int nfsctl_svc(struct nfsctl_svc *data);
......@@ -64,6 +65,7 @@ nfsd_init(void)
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
nfsd_racache_init(); /* Readahead param cache */
nfsd_fh_init(); /* FH table */
initialized = 1;
}
......@@ -141,31 +143,33 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
union nfsctl_res * res = NULL;
int err;
MOD_INC_USE_COUNT;
lock_kernel ();
if (!initialized)
nfsd_init();
err = -EPERM;
if (!suser()) {
err = -EPERM;
goto done;
}
err = -EFAULT;
if (!access_ok(VERIFY_READ, argp, sizeof(*argp))
|| (resp && !access_ok(VERIFY_WRITE, resp, sizeof(*resp)))) {
err = -EFAULT;
goto done;
}
err = -ENOMEM; /* ??? */
if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
(resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
err = -ENOMEM; /* ??? */
goto done;
}
err = -EINVAL;
copy_from_user(arg, argp, sizeof(*argp));
if (arg->ca_version != NFSCTL_VERSION) {
printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
err = -EINVAL;
goto done;
}
MOD_INC_USE_COUNT;
switch(cmd) {
case NFSCTL_SVC:
err = nfsctl_svc(&arg->ca_svc);
......@@ -193,7 +197,6 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
default:
err = -EINVAL;
}
MOD_DEC_USE_COUNT;
if (!err && resp)
copy_to_user(resp, res, sizeof(*resp));
......@@ -205,6 +208,7 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
kfree(res);
unlock_kernel ();
MOD_DEC_USE_COUNT;
return err;
}
......@@ -224,7 +228,6 @@ int
init_module(void)
{
printk("Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
nfsd_init();
do_nfsservctl = handle_sys_nfsservctl;
return 0;
}
......@@ -242,6 +245,7 @@ cleanup_module(void)
do_nfsservctl = NULL;
nfsd_export_shutdown();
nfsd_cache_shutdown();
nfsd_fh_free();
#ifdef CONFIG_PROC_FS
nfsd_stat_shutdown();
#endif
......
This diff is collapsed.
......@@ -78,6 +78,8 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
/*
* Look up a path name component
* Note: the dentry in the resp->fh may be negative if the file
* doesn't exist yet.
* N.B. After this call resp->fh needs an fh_put
*/
static int
......@@ -88,10 +90,8 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
dprintk("nfsd: LOOKUP %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
nfserr = nfsd_lookup(rqstp, &argp->fh,
argp->name,
argp->len,
&resp->fh);
nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
&resp->fh);
fh_put(&argp->fh);
RETURN(nfserr);
......@@ -209,11 +209,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
if (nfserr)
goto done; /* must fh_put dirfhp even on error */
dirp = dirfhp->fh_handle.fh_dentry->d_inode;
dirp = dirfhp->fh_dentry->d_inode;
/* Check for MAY_WRITE separately. */
nfserr = nfsd_permission(dirfhp->fh_export,
dirfhp->fh_handle.fh_dentry,
nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry,
MAY_WRITE);
if (nfserr == nfserr_rofs) {
rdonly = 1; /* Non-fatal error for echo > /dev/null */
......@@ -224,7 +223,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
if (newfhp->fh_dverified)
inode = newfhp->fh_handle.fh_dentry->d_inode;
inode = newfhp->fh_dentry->d_inode;
/* Get rid of this soon... */
if (exists && !inode) {
......
......@@ -363,7 +363,7 @@ int
nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
struct nfsd_attrstat *resp)
{
if (!(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
if (!(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
return xdr_ressize_check(rqstp, p);
}
......@@ -373,7 +373,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_diropres *resp)
{
if (!(p = encode_fh(p, &resp->fh))
|| !(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
|| !(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
return xdr_ressize_check(rqstp, p);
}
......@@ -391,7 +391,7 @@ int
nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_readres *resp)
{
if (!(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
if (!(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
*p++ = htonl(resp->count);
p += XDR_QUADLEN(resp->count);
......
......@@ -36,6 +36,8 @@
#include <asm/uaccess.h>
#endif
extern void fh_update(struct svc_fh*);
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
/* Open mode for nfsd_open */
......@@ -108,10 +110,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dprintk("nfsd: nfsd_lookup(fh %p, %s)\n", SVCFH_DENTRY(fhp), name);
/* Obtain dentry and export. */
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP)) != 0)
return err;
err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP);
if (err)
goto out;
dparent = fhp->fh_handle.fh_dentry;
dparent = fhp->fh_dentry;
exp = fhp->fh_export;
/* Fast path... */
......@@ -121,11 +124,16 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
!nfsd_iscovered(dparent, exp)) {
struct dentry *dchild;
dchild = lookup_dentry(name, dget(dparent), 1);
/* Lookup the name, but don't follow links */
dchild = lookup_dentry(name, dget(dparent), 0);
err = PTR_ERR(dchild);
if (IS_ERR(dchild))
return nfserrno(-err);
/*
* Note: we compose the filehandle now, but as the
* dentry may be negative, it may need to be updated.
*/
fh_compose(resfh, exp, dchild);
return (dchild->d_inode ? 0 : nfserr_noent);
}
......@@ -135,6 +143,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
return nfserr_noent;
if (nfsd_iscovered(dparent, exp))
return nfserr_acces;
out:
return err;
}
......@@ -158,10 +167,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
ftype = S_IFREG;
/* Get inode */
if ((err = fh_verify(rqstp, fhp, ftype, accmode)) != 0)
return err;
err = fh_verify(rqstp, fhp, ftype, accmode);
if (err)
goto out;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
/* The size case is special... */
......@@ -169,7 +179,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
if (err != 0)
return err;
goto out;
}
if ((err = get_write_access(inode)) != 0)
return nfserrno(-err);
......@@ -211,8 +221,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(inode);
}
return 0;
err = 0;
out:
return err;
}
/*
......@@ -230,20 +241,23 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
access = wflag? MAY_WRITE : MAY_READ;
if ((err = fh_verify(rqstp, fhp, type, access)) != 0)
return err;
goto out;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
/* Disallow access to files with the append-only bit set or
* with mandatory locking enabled */
err = nfserr_perm;
if (IS_APPEND(inode) || IS_ISMNDLK(inode))
return nfserr_perm;
goto out;
if (!inode->i_op || !inode->i_op->default_file_ops)
return nfserr_perm;
goto out;
if (wflag && (err = get_write_access(inode)) != 0)
return nfserrno(-err);
if (wflag && (err = get_write_access(inode)) != 0) {
err = nfserrno(-err);
goto out;
}
memset(filp, 0, sizeof(*filp));
filp->f_op = inode->i_op->default_file_ops;
......@@ -252,6 +266,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
filp->f_mode = wflag? FMODE_WRITE : FMODE_READ;
filp->f_dentry = dentry;
err = 0;
if (filp->f_op->open) {
err = filp->f_op->open(inode, filp);
if (err) {
......@@ -262,11 +277,11 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
* is really on callers stack frame. -DaveM
*/
filp->f_count--;
return nfserrno(-err);
err = nfserrno(-err);
}
}
return 0;
out:
return err;
}
/*
......@@ -281,7 +296,8 @@ nfsd_close(struct file *filp)
if (!inode->i_count)
printk(KERN_WARNING "nfsd: inode count == 0!\n");
if (!dentry->d_count)
printk(KERN_WARNING "nfsd: wheee, dentry count == 0!\n");
printk(KERN_WARNING "nfsd: wheee, %s/%s d_count == 0!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
if (filp->f_mode & FMODE_WRITE)
......@@ -299,6 +315,9 @@ nfsd_sync(struct inode *inode, struct file *filp)
/*
* Obtain the readahead parameters for the given file
*
* N.B. is raparm cache for a file cleared when the file closes??
* (dentry might be reused later.)
*/
static inline struct raparms *
nfsd_get_raparms(struct dentry *dentry)
......@@ -506,39 +525,53 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct inode *dirp;
int err;
err = nfserr_perm;
if (!flen)
return nfserr_perm;
goto out;
if (!(iap->ia_valid & ATTR_MODE))
iap->ia_mode = 0;
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0)
return err;
err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
if (err)
goto out;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
/* Get all the sanity checks out of the way before we lock the parent. */
if(!dirp->i_op || !dirp->i_op->lookup) {
return nfserrno(-ENOTDIR);
} else if(type == S_IFREG) {
err = nfserr_notdir;
if(!dirp->i_op || !dirp->i_op->lookup)
goto out;
err = nfserr_perm;
if (type == S_IFREG) {
if(!dirp->i_op->create)
return nfserr_perm;
goto out;
} else if(type == S_IFDIR) {
if(!dirp->i_op->mkdir)
return nfserr_perm;
goto out;
} else if((type == S_IFCHR) || (type == S_IFBLK) || (type == S_IFIFO)) {
if(!dirp->i_op->mknod)
return nfserr_perm;
goto out;
} else {
return nfserr_perm;
goto out;
}
if(!resfhp->fh_dverified) {
/*
* The response filehandle may have been setup already ...
*/
if (!resfhp->fh_dverified) {
dchild = lookup_dentry(fname, dget(dentry), 0);
err = PTR_ERR(dchild);
if(IS_ERR(dchild))
return nfserrno(-err);
} else
dchild = resfhp->fh_handle.fh_dentry;
dchild = resfhp->fh_dentry;
/*
* Make sure the child dentry is still negative ...
*/
if (dchild->d_inode) {
printk("nfsd_create: dentry %s/%s not negative!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}
/* Looks good, lock the directory. */
fh_lock(fhp);
......@@ -562,9 +595,15 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
/* If needed, assemble the file handle for the newly created file. */
if(!resfhp->fh_dverified)
/*
* Assemble the file handle for the newly created file,
* or update the filehandle to get the new inode info.
*/
if (!resfhp->fh_dverified) {
fh_compose(resfhp, fhp->fh_export, dchild);
} else {
fh_update(resfhp);
}
/* Set file attributes. Mode has already been set and
* setting uid/gid works only for root. Irix appears to
......@@ -574,7 +613,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = 0;
if ((iap->ia_valid &= (ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
out:
return err;
}
......@@ -597,7 +636,7 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
if ((err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE|MAY_TRUNC)) != 0)
return err;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
if ((err = get_write_access(inode)) != 0)
......@@ -635,7 +674,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
if ((err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ)) != 0)
return err;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
if (!inode->i_op || !inode->i_op->readlink)
......@@ -673,7 +712,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0)
return err;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
if (nfsd_iscovered(dentry, fhp->fh_export) ||
......@@ -720,7 +759,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
(err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP)) != 0)
return err;
ddir = ffhp->fh_handle.fh_dentry;
ddir = ffhp->fh_dentry;
dirp = ddir->d_inode;
dnew = lookup_dentry(fname, dget(ddir), 1);
......@@ -731,7 +770,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = -EEXIST;
if (dnew->d_inode)
goto dput_and_out;
dest = tfhp->fh_handle.fh_dentry->d_inode;
dest = tfhp->fh_dentry->d_inode;
err = -EPERM;
if (!len)
......@@ -794,10 +833,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|| (err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE)) != 0)
return err;
fdentry = ffhp->fh_handle.fh_dentry;
fdentry = ffhp->fh_dentry;
fdir = fdentry->d_inode;
tdentry = tfhp->fh_handle.fh_dentry;
tdentry = tfhp->fh_dentry;
tdir = tdentry->d_inode;
if (!flen || (fname[0] == '.' &&
......@@ -816,6 +855,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (IS_ERR(ndentry))
goto out_dput_old;
/* N.B. check this ... problems in locking?? */
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
err = -EXDEV;
if (fdir->i_dev != tdir->i_dev)
......@@ -856,7 +896,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE)) != 0)
return err;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
rdentry = lookup_dentry(fname, dget(dentry), 0);
......@@ -975,20 +1015,24 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
unsigned long oldfs;
int err;
if ((err = fh_verify(rqstp, fhp, 0, MAY_NOP)) != 0)
return err;
dentry = fhp->fh_handle.fh_dentry;
err = fh_verify(rqstp, fhp, 0, MAY_NOP);
if (err)
goto out;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
err = nfserr_io;
if (!(sb = inode->i_sb) || !sb->s_op->statfs)
return nfserr_io;
goto out;
oldfs = get_fs();
set_fs (KERNEL_DS);
sb->s_op->statfs(sb, stat, sizeof(*stat));
set_fs (oldfs);
err = 0;
return 0;
out:
return err;
}
/*
......
......@@ -328,6 +328,17 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
zero_fd_set(n, &fds->res_out);
zero_fd_set(n, &fds->res_ex);
error = do_select(n, fds, wait);
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
unsigned long timeout = current->timeout - jiffies - 1;
unsigned long sec = 0, usec = 0;
if ((long) timeout > 0) {
sec = timeout / HZ;
usec = timeout % HZ;
usec *= (1000000/HZ);
}
put_user(sec, &tvp->tv_sec);
put_user(usec, &tvp->tv_usec);
}
current->timeout = 0;
if (error < 0)
goto out;
......
......@@ -14,7 +14,7 @@ static inline void clear_active_bhs(unsigned long x)
unsigned long temp;
__asm__ __volatile__(
"1: ldq_l %0,%1\n"
" and %0,%2,%0\n"
" bic %0,%2,%0\n"
" stq_c %0,%1\n"
" beq %0,2f\n"
".section .text2,\"ax\"\n"
......
......@@ -27,12 +27,12 @@
* ino/dev of the exported inode.
*/
struct nfs_fhbase {
struct dentry *fb_dentry;
struct dentry *fb_dparent;
unsigned int fb_dhash;
unsigned int fb_dlen;
ino_t fb_xino;
struct dentry * fb_dentry; /* dentry cookie */
ino_t fb_ino; /* our inode number */
ino_t fb_dirino; /* dir inode number */
dev_t fb_dev; /* our device */
dev_t fb_xdev;
ino_t fb_xino;
};
#define NFS_FH_PADDING (NFS_FHSIZE - sizeof(struct nfs_fhbase))
......@@ -41,13 +41,12 @@ struct knfs_fh {
__u8 fh_cookie[NFS_FH_PADDING];
};
#define fh_dentry fh_base.fb_dentry
#define fh_dparent fh_base.fb_dparent
#define fh_dhash fh_base.fb_dhash
#define fh_dlen fh_base.fb_dlen
#define fh_xino fh_base.fb_xino
#define fh_dcookie fh_base.fb_dentry
#define fh_ino fh_base.fb_ino
#define fh_dirino fh_base.fb_dirino
#define fh_dev fh_base.fb_dev
#define fh_xdev fh_base.fb_xdev
#define fh_xino fh_base.fb_xino
#ifdef __KERNEL__
......@@ -57,6 +56,7 @@ struct knfs_fh {
*/
typedef struct svc_fh {
struct knfs_fh fh_handle; /* FH data */
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
size_t fh_pre_size; /* size before operation */
time_t fh_pre_mtime; /* mtime before oper */
......@@ -69,17 +69,26 @@ typedef struct svc_fh {
/*
* Shorthand for dprintk()'s
*/
#define SVCFH_DENTRY(f) ((f)->fh_handle.fh_dentry)
#define SVCFH_DENTRY(f) ((f)->fh_dentry)
/*
* Function prototypes
*/
u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
void fh_compose(struct svc_fh *, struct svc_export *, struct dentry *);
u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
void fh_compose(struct svc_fh *, struct svc_export *, struct dentry *);
void fh_put(struct svc_fh *);
void nfsd_fh_init(void);
void nfsd_fh_free(void);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
if (src->fh_dverified) {
struct dentry *dentry = src->fh_dentry;
printk("fh_copy: copying %s/%s, already verified!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}
*dst = *src;
return dst;
}
......@@ -97,7 +106,7 @@ fh_init(struct svc_fh *fhp)
static inline void
fh_lock(struct svc_fh *fhp)
{
struct inode *inode = fhp->fh_handle.fh_dentry->d_inode;
struct inode *inode = fhp->fh_dentry->d_inode;
/*
dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
......@@ -117,7 +126,7 @@ fh_lock(struct svc_fh *fhp)
static inline void
fh_unlock(struct svc_fh *fhp)
{
struct inode *inode = fhp->fh_handle.fh_dentry->d_inode;
struct inode *inode = fhp->fh_dentry->d_inode;
if (fhp->fh_locked) {
if (!fhp->fh_post_version)
......@@ -130,17 +139,7 @@ fh_unlock(struct svc_fh *fhp)
/*
* Release an inode
*/
#ifndef NFSD_DEBUG
static inline void
fh_put(struct svc_fh *fhp)
{
if (fhp->fh_dverified) {
fh_unlock(fhp);
dput(fhp->fh_handle.fh_dentry);
fhp->fh_dverified = 0;
}
}
#else
#if 0
#define fh_put(fhp) __fh_put(fhp, __FILE__, __LINE__)
static inline void
......@@ -151,7 +150,7 @@ __fh_put(struct svc_fh *fhp, char *file, int line)
if (!fhp->fh_dverified)
return;
dentry = fhp->fh_handle.fh_dentry;
dentry = fhp->fh_dentry;
if (!dentry->d_count) {
printk("nfsd: trying to free free dentry in %s:%d\n"
" file %s/%s\n",
......@@ -159,14 +158,12 @@ __fh_put(struct svc_fh *fhp, char *file, int line)
dentry->d_parent->d_name.name, dentry->d_name.name);
} else {
fh_unlock(fhp);
dput(dentry);
fhp->fh_dverified = 0;
dput(dentry);
}
}
#endif
#endif /* __KERNEL__ */
#endif /* NFSD_FH_H */
......@@ -766,7 +766,6 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp)
}
}
printk("svc_recv: svsk=%p, use count=%d\n", svsk, svsk->sk_inuse);
dprintk("svc: server %p servicing socket %p\n", rqstp, svsk);
len = svsk->sk_recvfrom(rqstp);
......
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