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