Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
7f98bfdb
Commit
7f98bfdb
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 2.1.65
parent
3e213f64
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
1396 additions
and
344 deletions
+1396
-344
CREDITS
CREDITS
+11
-0
Makefile
Makefile
+1
-1
arch/i386/kernel/entry.S
arch/i386/kernel/entry.S
+4
-0
arch/i386/kernel/traps.c
arch/i386/kernel/traps.c
+10
-0
arch/i386/mm/fault.c
arch/i386/mm/fault.c
+64
-39
drivers/block/README.fd
drivers/block/README.fd
+1
-1
drivers/block/floppy.c
drivers/block/floppy.c
+2
-2
drivers/net/eepro100.c
drivers/net/eepro100.c
+108
-42
drivers/scsi/ppa.h
drivers/scsi/ppa.h
+1
-1
drivers/sound/lowlevel/awe_config.h
drivers/sound/lowlevel/awe_config.h
+1
-1
drivers/sound/soundcard.c
drivers/sound/soundcard.c
+1
-1
fs/dcache.c
fs/dcache.c
+87
-77
fs/inode.c
fs/inode.c
+19
-22
fs/lockd/svcsubs.c
fs/lockd/svcsubs.c
+13
-4
fs/namei.c
fs/namei.c
+5
-3
fs/nfsd/export.c
fs/nfsd/export.c
+9
-13
fs/nfsd/nfsctl.c
fs/nfsd/nfsctl.c
+12
-8
fs/nfsd/nfsfh.c
fs/nfsd/nfsfh.c
+904
-36
fs/nfsd/nfsproc.c
fs/nfsd/nfsproc.c
+7
-8
fs/nfsd/nfsxdr.c
fs/nfsd/nfsxdr.c
+3
-3
fs/nfsd/vfs.c
fs/nfsd/vfs.c
+93
-49
fs/select.c
fs/select.c
+11
-0
include/asm-alpha/softirq.h
include/asm-alpha/softirq.h
+1
-1
include/linux/nfsd/nfsfh.h
include/linux/nfsd/nfsfh.h
+28
-31
net/sunrpc/svcsock.c
net/sunrpc/svcsock.c
+0
-1
No files found.
CREDITS
View file @
7f98bfdb
...
...
@@ -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
...
...
Makefile
View file @
7f98bfdb
VERSION
=
2
PATCHLEVEL
=
1
SUBLEVEL
=
6
4
SUBLEVEL
=
6
5
ARCH
:=
$(
shell
uname
-m
|
sed
-e
s/i.86/i386/
-e
s/sun4u/sparc64/
)
...
...
arch/i386/kernel/entry.S
View file @
7f98bfdb
...
...
@@ -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
)
...
...
arch/i386/kernel/traps.c
View file @
7f98bfdb
...
...
@@ -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
));
}
...
...
arch/i386/mm/fault.c
View file @
7f98bfdb
...
...
@@ -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
);
}
drivers/block/README.fd
View file @
7f98bfdb
...
...
@@ -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)
...
...
drivers/block/floppy.c
View file @
7f98bfdb
...
...
@@ -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 */
}
...
...
drivers/net/eepro100.c
View file @
7f98bfdb
...
...
@@ -19,7 +19,7 @@
*/
static
const
char
*
version
=
"eepro100.c:v0.3
4 8/3
0/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov
\n
"
;
"eepro100.c:v0.3
6 10/2
0/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov
\n
"
;
/* A few user-configurable values that apply to all boards.
First set are undocumented and spelled per Intel recommendations. */
...
...
@@ -27,13 +27,16 @@ static const char *version =
static
int
congenb
=
0
;
/* Enable congestion control in the DP83840. */
static
int
txfifo
=
8
;
/* Tx FIFO threshold in 4 byte units, 0-15 */
static
int
rxfifo
=
8
;
/* Rx FIFO threshold, default 32 bytes. */
static
int
txdmacount
=
0
;
/* Tx DMA burst length, 0-127, default 0. */
static
int
rxdmacount
=
0
;
/* Rx DMA length, 0 means no preemption. */
/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
static
int
txdmacount
=
128
;
static
int
rxdmacount
=
0
;
/* If defined use the copy-only-tiny-buffer scheme for higher performance.
The value sets the copy breakpoint. Lower uses more memory, but is
faster. */
#define SKBUFF_RX_COPYBREAK 256
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
Lower values use more memory, but are faster. */
static
int
rx_copybreak
=
200
;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static
int
max_interrupt_work
=
20
;
#include <linux/config.h>
#ifdef MODULE
...
...
@@ -161,7 +164,7 @@ also has simplified Tx and Rx buffer modes. This driver uses the "flexible"
Tx mode, but in a simplified lower-overhead manner: it associates only a
single buffer descriptor with each frame descriptor.
Despite the extra space overhead in each rec
ie
ve skbuff, the driver must use
Despite the extra space overhead in each rec
ei
ve skbuff, the driver must use
the simplified Rx buffer mode to assure that only a single data buffer is
associated with each RxFD. The driver implements this by reserving space
for the Rx descriptor at the head of each Rx skbuff
...
...
@@ -273,9 +276,6 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT ((400*HZ)/1000)
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
#define INTR_WORK 16
/* How to wait for the command unit to accept a command.
Typically this takes 0 ticks. */
static
inline
void
wait_for_cmd_done
(
int
cmd_ioaddr
)
...
...
@@ -450,6 +450,9 @@ static int speedo_rx(struct device *dev);
static
void
speedo_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
int
speedo_close
(
struct
device
*
dev
);
static
struct
enet_statistics
*
speedo_get_stats
(
struct
device
*
dev
);
#ifdef HAVE_PRIVATE_IOCTL
static
int
speedo_ioctl
(
struct
device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
#endif
static
void
set_rx_mode
(
struct
device
*
dev
);
...
...
@@ -458,24 +461,21 @@ static void set_rx_mode(struct device *dev);
/* 'options' is used to pass a transceiver override or full-duplex flag
e.g. "options=16" for FD, "options=32" for 100mbps-only. */
static
int
full_duplex
[]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
#ifdef MODULE
static
int
options
[]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
static
int
debug
=
-
1
;
/* The debug level */
#endif
/* A list of all installed Speedo devices, for removing the driver module. */
static
struct
device
*
root_speedo_dev
=
NULL
;
#endif
int
eepro100_init
(
struct
device
*
dev
)
{
int
cards_found
=
0
;
if
(
pcibios_present
())
{
int
pci_index
;
for
(
pci_index
=
0
;
pci_index
<
8
;
pci_index
++
)
{
static
int
pci_index
=
0
;
for
(;
pci_index
<
8
;
pci_index
++
)
{
unsigned
char
pci_bus
,
pci_device_fn
,
pci_irq_line
,
pci_latency
;
#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
int
pci_ioaddr
;
...
...
@@ -539,6 +539,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
{
static
int
did_version
=
0
;
/* Already printed version info. */
struct
speedo_private
*
sp
;
char
*
product
;
int
i
;
u16
eeprom
[
0x40
];
...
...
@@ -558,7 +559,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
u16
sum
=
0
;
int
j
;
for
(
j
=
0
,
i
=
0
;
i
<
0x40
;
i
++
)
{
u
nsigned
short
value
=
read_eeprom
(
ioaddr
,
i
);
u
16
value
=
read_eeprom
(
ioaddr
,
i
);
eeprom
[
i
]
=
value
;
sum
+=
value
;
if
(
i
<
3
)
{
...
...
@@ -579,8 +580,13 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
action. */
outl
(
0
,
ioaddr
+
SCBPort
);
printk
(
KERN_INFO
"%s: Intel EtherExpress Pro 10/100 at %#3x, "
,
dev
->
name
,
ioaddr
);
if
(
eeprom
[
3
]
&
0x0100
)
product
=
"OEM i82557/i82558 10/100 Ethernet"
;
else
product
=
"Intel EtherExpress Pro 10/100"
;
printk
(
KERN_INFO
"%s: %s at %#3x, "
,
dev
->
name
,
product
,
ioaddr
);
for
(
i
=
0
;
i
<
5
;
i
++
)
printk
(
"%2.2X:"
,
dev
->
dev_addr
[
i
]);
printk
(
"%2.2X, IRQ %d.
\n
"
,
dev
->
dev_addr
[
i
],
irq
);
...
...
@@ -592,7 +598,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
{
const
char
*
connectors
[]
=
{
" RJ45"
,
" BNC"
,
" AUI"
,
" MII"
};
/* The self-test results must be paragraph aligned. */
int
str
[
6
],
*
volatile
self_test_results
;
s32
str
[
6
],
*
volatile
self_test_results
;
int
boguscnt
=
16000
;
/* Timeout for set-test. */
if
(
eeprom
[
3
]
&
0x03
)
printk
(
KERN_INFO
" Receiver lock-up bug exists -- enabling"
...
...
@@ -638,7 +644,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
}
/* Perform a system self-test. */
self_test_results
=
(
int
*
)
((((
int
)
str
)
+
15
)
&
~
0xf
);
self_test_results
=
(
s32
*
)
((((
long
)
str
)
+
15
)
&
~
0xf
);
self_test_results
[
0
]
=
0
;
self_test_results
[
1
]
=
-
1
;
outl
(
virt_to_bus
(
self_test_results
)
|
1
,
ioaddr
+
SCBPort
);
...
...
@@ -669,6 +675,8 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
}
#endif
/* kernel_bloat */
outl
(
0
,
ioaddr
+
SCBPort
);
/* We do a request_region() only to register /proc/ioports info. */
request_region
(
ioaddr
,
SPEEDO3_TOTAL_SIZE
,
"Intel Speedo3 Ethernet"
);
...
...
@@ -679,10 +687,8 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
dev
->
priv
=
kmalloc
(
sizeof
(
*
sp
),
GFP_KERNEL
);
sp
=
dev
->
priv
;
memset
(
sp
,
0
,
sizeof
(
*
sp
));
#ifdef MODULE
sp
->
next_module
=
root_speedo_dev
;
root_speedo_dev
=
dev
;
#endif
if
(
card_idx
>=
0
)
{
if
(
full_duplex
[
card_idx
]
>=
0
)
...
...
@@ -695,10 +701,8 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
sp
->
phy
[
1
]
=
eeprom
[
7
];
sp
->
rx_bug
=
(
eeprom
[
3
]
&
0x03
)
==
3
?
0
:
1
;
printk
(
KERN_INFO
" Operating in %s duplex mode.
\n
"
,
sp
->
full_duplex
?
"full"
:
"half"
);
if
(
sp
->
rx_bug
)
printk
(
KERN_INFO
" Recie
ver lock-up workaround activated.
\n
"
);
printk
(
KERN_INFO
" Recei
ver lock-up workaround activated.
\n
"
);
/* The Speedo-specific entries in the device structure. */
dev
->
open
=
&
speedo_open
;
...
...
@@ -708,6 +712,9 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
#ifdef NEW_MULTICAST
dev
->
set_multicast_list
=
&
set_rx_mode
;
#endif
#ifdef HAVE_PRIVATE_IOCTL
dev
->
do_ioctl
=
&
speedo_ioctl
;
#endif
return
;
}
...
...
@@ -726,7 +733,11 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
/* Delay between EEPROM clock transitions.
This is a "nasty" timing loop, but PC compatible machines are defined
to delay an ISA compatible period for the SLOW_DOWN_IO macro. */
#ifdef _LINUX_DELAY_H
#define eeprom_delay(nanosec) udelay(1);
#else
#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
#endif
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
...
...
@@ -830,11 +841,13 @@ speedo_open(struct device *dev)
MOD_INC_USE_COUNT
;
/* Load the statistics block address. */
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outl
(
virt_to_bus
(
&
sp
->
lstats
),
ioaddr
+
SCBPointer
);
outw
(
INT_MASK
|
CU_STATSADDR
,
ioaddr
+
SCBCmd
);
sp
->
lstats
.
done_marker
=
0
;
speedo_init_rx_ring
(
dev
);
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outl
(
0
,
ioaddr
+
SCBPointer
);
outw
(
INT_MASK
|
RX_ADDR_LOAD
,
ioaddr
+
SCBCmd
);
...
...
@@ -845,8 +858,8 @@ speedo_open(struct device *dev)
/* Fill the first command with our physical address. */
{
u
nsigned
short
*
eaddrs
=
(
unsigned
short
*
)
dev
->
dev_addr
;
u
nsigned
short
*
setup_frm
=
(
short
*
)
&
(
sp
->
tx_ring
[
0
].
tx_desc_addr
);
u
16
*
eaddrs
=
(
u16
*
)
dev
->
dev_addr
;
u
16
*
setup_frm
=
(
u16
*
)
&
(
sp
->
tx_ring
[
0
].
tx_desc_addr
);
/* Avoid a bug(?!) here by marking the command already completed. */
sp
->
tx_ring
[
0
].
status
=
((
CmdSuspend
|
CmdIASetup
)
<<
16
)
|
0xa000
;
...
...
@@ -860,6 +873,7 @@ speedo_open(struct device *dev)
sp
->
dirty_tx
=
0
;
sp
->
tx_full
=
0
;
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outl
(
0
,
ioaddr
+
SCBPointer
);
outw
(
INT_MASK
|
CU_CMD_BASE
,
ioaddr
+
SCBCmd
);
...
...
@@ -896,6 +910,7 @@ speedo_open(struct device *dev)
sp
->
timer
.
function
=
&
speedo_timer
;
/* timer handler */
add_timer
(
&
sp
->
timer
);
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_DUMPSTATS
,
ioaddr
+
SCBCmd
);
return
0
;
}
...
...
@@ -1079,6 +1094,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
sp
->
last_cmd
->
command
&=
~
(
CmdSuspend
|
CmdIntr
);
sp
->
last_cmd
=
(
struct
descriptor
*
)
&
sp
->
tx_ring
[
entry
];
/* Trigger the command unit resume. */
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_RESUME
,
ioaddr
+
SCBCmd
);
restore_flags
(
flags
);
}
...
...
@@ -1100,7 +1116,7 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct
device
*
dev
=
(
struct
device
*
)
dev_instance
;
struct
speedo_private
*
sp
;
int
ioaddr
,
boguscnt
=
INTR_WORK
;
int
ioaddr
,
boguscnt
=
max_interrupt_work
;
unsigned
short
status
;
#ifndef final_version
...
...
@@ -1169,7 +1185,7 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
int
status
=
sp
->
tx_ring
[
entry
].
status
;
if
(
speedo_debug
>
5
)
printk
(
KERN_DEBUG
" scavenge canidate %d status %4.4x.
\n
"
,
printk
(
KERN_DEBUG
" scavenge can
d
idate %d status %4.4x.
\n
"
,
entry
,
status
);
if
((
status
&
0x8000
)
==
0
)
break
;
/* It still hasn't been processed. */
...
...
@@ -1256,13 +1272,13 @@ speedo_rx(struct device *dev)
dev
->
name
,
status
);
}
else
{
/* Malloc up new buffer, compatible with net-2e. */
shor
t
pkt_len
=
sp
->
rx_ringp
[
entry
]
->
count
&
0x3fff
;
in
t
pkt_len
=
sp
->
rx_ringp
[
entry
]
->
count
&
0x3fff
;
struct
sk_buff
*
skb
;
int
rx_in_place
=
0
;
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
if
(
pkt_len
>
SKBUFF_RX_COPYBREAK
)
{
if
(
pkt_len
>
rx_copybreak
)
{
struct
sk_buff
*
newskb
;
char
*
temp
;
...
...
@@ -1339,8 +1355,14 @@ speedo_rx(struct device *dev)
#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
if
(
!
rx_in_place
)
{
skb_reserve
(
skb
,
2
);
/* 16 byte align the data fields */
#if defined(__i386) && notyet
/* Packet is in one chunk -- we can copy + cksum. */
eth_io_copy_and_sum
(
skb
,
bus_to_virt
(
sp
->
rx_ringp
[
entry
]
->
rx_buf_addr
),
pkt_len
,
0
);
#else
memcpy
(
skb_put
(
skb
,
pkt_len
),
bus_to_virt
(
sp
->
rx_ringp
[
entry
]
->
rx_buf_addr
),
pkt_len
);
#endif
}
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
#else
...
...
@@ -1478,12 +1500,39 @@ speedo_get_stats(struct device *dev)
sp
->
stats
.
rx_fifo_errors
+=
sp
->
lstats
.
rx_overrun_errs
;
sp
->
stats
.
rx_length_errors
+=
sp
->
lstats
.
rx_runt_errs
;
sp
->
lstats
.
done_marker
=
0x0000
;
if
(
dev
->
start
)
if
(
dev
->
start
)
{
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_DUMPSTATS
,
ioaddr
+
SCBCmd
);
}
}
return
&
sp
->
stats
;
}
#ifdef HAVE_PRIVATE_IOCTL
static
int
speedo_ioctl
(
struct
device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
speedo_private
*
sp
=
(
struct
speedo_private
*
)
dev
->
priv
;
int
ioaddr
=
dev
->
base_addr
;
u16
*
data
=
(
u16
*
)
&
rq
->
ifr_data
;
int
phy
=
sp
->
phy
[
0
]
&
0x1f
;
switch
(
cmd
)
{
case
SIOCDEVPRIVATE
:
/* Get the address of the PHY in use. */
data
[
0
]
=
phy
;
case
SIOCDEVPRIVATE
+
1
:
/* Read the specified MII register. */
data
[
3
]
=
mdio_read
(
ioaddr
,
data
[
0
],
data
[
1
]);
return
0
;
case
SIOCDEVPRIVATE
+
2
:
/* Write the specified MII register */
if
(
!
suser
())
return
-
EPERM
;
mdio_write
(
ioaddr
,
data
[
0
],
data
[
1
],
data
[
2
]);
return
0
;
default:
return
-
EOPNOTSUPP
;
}
}
#endif
/* HAVE_PRIVATE_IOCTL */
/* Set or clear the multicast filter for this adaptor.
This is very ugly with Intel chips -- we usually have to execute an
entire configuration command, plus process a multicast command.
...
...
@@ -1542,6 +1591,7 @@ set_rx_mode(struct device *dev)
virt_to_bus
(
&
(
sp
->
tx_ring
[
sp
->
cur_tx
%
TX_RING_SIZE
]));
sp
->
last_cmd
->
command
&=
~
CmdSuspend
;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_RESUME
,
ioaddr
+
SCBCmd
);
sp
->
last_cmd
=
&
sp
->
config_cmd
;
restore_flags
(
flags
);
...
...
@@ -1557,8 +1607,7 @@ set_rx_mode(struct device *dev)
if
(
new_rx_mode
==
0
&&
dev
->
mc_count
<
3
)
{
/* The simple case of 0-2 multicast list entries occurs often, and
fits within one tx_ring[] entry. */
u16
*
setup_params
;
unsigned
short
*
eaddrs
;
u16
*
setup_params
,
*
eaddrs
;
struct
dev_mc_list
*
mclist
;
save_flags
(
flags
);
...
...
@@ -1569,12 +1618,12 @@ set_rx_mode(struct device *dev)
sp
->
tx_ring
[
entry
].
link
=
virt_to_bus
(
&
sp
->
tx_ring
[
sp
->
cur_tx
%
TX_RING_SIZE
]);
sp
->
tx_ring
[
entry
].
tx_desc_addr
=
0
;
/* Really MC list count. */
setup_params
=
(
short
*
)
&
sp
->
tx_ring
[
entry
].
tx_desc_addr
;
setup_params
=
(
u16
*
)
&
sp
->
tx_ring
[
entry
].
tx_desc_addr
;
*
setup_params
++
=
dev
->
mc_count
*
6
;
/* Fill in the multicast addresses. */
for
(
i
=
0
,
mclist
=
dev
->
mc_list
;
i
<
dev
->
mc_count
;
i
++
,
mclist
=
mclist
->
next
)
{
eaddrs
=
(
u
nsigned
short
*
)
mclist
->
dmi_addr
;
eaddrs
=
(
u
16
*
)
mclist
->
dmi_addr
;
*
setup_params
++
=
*
eaddrs
++
;
*
setup_params
++
=
*
eaddrs
++
;
*
setup_params
++
=
*
eaddrs
++
;
...
...
@@ -1582,15 +1631,16 @@ set_rx_mode(struct device *dev)
sp
->
last_cmd
->
command
&=
~
CmdSuspend
;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_RESUME
,
ioaddr
+
SCBCmd
);
sp
->
last_cmd
=
(
struct
descriptor
*
)
&
sp
->
tx_ring
[
entry
];
restore_flags
(
flags
);
}
else
if
(
new_rx_mode
==
0
)
{
/* This does not work correctly, but why not? */
struct
dev_mc_list
*
mclist
;
u
nsigned
short
*
eaddrs
;
u
16
*
eaddrs
;
struct
descriptor
*
mc_setup_frm
=
sp
->
mc_setup_frm
;
u16
*
setup_params
=
(
short
*
)
mc_setup_frm
->
params
;
u16
*
setup_params
=
(
u16
*
)
mc_setup_frm
->
params
;
int
i
;
if
(
sp
->
mc_setup_frm_len
<
10
+
dev
->
mc_count
*
6
...
...
@@ -1616,12 +1666,12 @@ set_rx_mode(struct device *dev)
mc_setup_frm
->
status
=
0
;
mc_setup_frm
->
command
=
CmdSuspend
|
CmdIntr
|
CmdMulticastList
;
/* Link set below. */
setup_params
=
(
short
*
)
mc_setup_frm
->
params
;
setup_params
=
(
u16
*
)
mc_setup_frm
->
params
;
*
setup_params
++
=
dev
->
mc_count
*
6
;
/* Fill in the multicast addresses. */
for
(
i
=
0
,
mclist
=
dev
->
mc_list
;
i
<
dev
->
mc_count
;
i
++
,
mclist
=
mclist
->
next
)
{
eaddrs
=
(
u
nsigned
short
*
)
mclist
->
dmi_addr
;
eaddrs
=
(
u
16
*
)
mclist
->
dmi_addr
;
*
setup_params
++
=
*
eaddrs
++
;
*
setup_params
++
=
*
eaddrs
++
;
*
setup_params
++
=
*
eaddrs
++
;
...
...
@@ -1647,6 +1697,7 @@ set_rx_mode(struct device *dev)
sp
->
last_cmd
->
command
&=
~
CmdSuspend
;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done
(
ioaddr
+
SCBCmd
);
outw
(
CU_RESUME
,
ioaddr
+
SCBCmd
);
sp
->
last_cmd
=
mc_setup_frm
;
restore_flags
(
flags
);
...
...
@@ -1663,6 +1714,21 @@ set_rx_mode(struct device *dev)
char
kernel_version
[]
=
UTS_RELEASE
;
#endif
#if LINUX_VERSION_CODE > 0x20118
MODULE_AUTHOR
(
"Donald Becker <becker@cesdis.gsfc.nasa.gov>"
);
MODULE_DESCRIPTION
(
"Intel i82557/i82558 EtherExpressPro driver"
);
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM
(
options
,
"1-"
__MODULE_STRING
(
8
)
"i"
);
MODULE_PARM
(
full_duplex
,
"1-"
__MODULE_STRING
(
8
)
"i"
);
MODULE_PARM
(
congenb
,
"i"
);
MODULE_PARM
(
txfifo
,
"i"
);
MODULE_PARM
(
rxfifo
,
"i"
);
MODULE_PARM
(
txdmacount
,
"i"
);
MODULE_PARM
(
rxdmacount
,
"i"
);
MODULE_PARM
(
rx_copybreak
,
"i"
);
MODULE_PARM
(
max_interrupt_work
,
"i"
);
#endif
int
init_module
(
void
)
{
...
...
drivers/scsi/ppa.h
View file @
7f98bfdb
...
...
@@ -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 */
...
...
drivers/sound/lowlevel/awe_config.h
View file @
7f98bfdb
...
...
@@ -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.
...
...
drivers/sound/soundcard.c
View file @
7f98bfdb
...
...
@@ -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
;
...
...
fs/dcache.c
View file @
7f98bfdb
...
...
@@ -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_i
t
;
goto
ou
t
;
}
}
return
0
;
found_it:
return
(
dentry
->
d_parent
==
dparent
)
&&
(
dentry
->
d_name
.
hash
==
hash
)
&&
(
dentry
->
d_name
.
len
==
len
);
valid
=
0
;
out:
return
valid
;
}
/*
...
...
fs/inode.c
View file @
7f98bfdb
...
...
@@ -358,33 +358,30 @@ static int free_inodes(int goal)
*/
static
void
try_to_free_inodes
(
int
goal
)
{
int
retr
ied
=
0
,
found
;
int
retr
y
=
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
)
{
...
...
fs/lockd/svcsubs.c
View file @
7f98bfdb
...
...
@@ -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_d
entry
==
fh
->
fh_
dentry
if
(
file
->
f_handle
.
fh_d
cookie
==
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
;
...
...
fs/namei.c
View file @
7f98bfdb
...
...
@@ -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
);
...
...
fs/nfsd/export.c
View file @
7f98bfdb
...
...
@@ -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
);
...
...
fs/nfsd/nfsctl.c
View file @
7f98bfdb
...
...
@@ -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
...
...
fs/nfsd/nfsfh.c
View file @
7f98bfdb
...
...
@@ -7,18 +7,727 @@
*/
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/dcache.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#define NFSDDBG_FACILITY NFSDDBG_FH
#define NFSD_PARANOIA 1
/* #define NFSD_DEBUG_VERBOSE 1 */
extern
unsigned
long
num_physpages
;
#define NFSD_FILE_CACHE 0
#define NFSD_DIR_CACHE 1
struct
fh_entry
{
struct
dentry
*
dentry
;
unsigned
long
reftime
;
ino_t
ino
;
dev_t
dev
;
};
#define NFSD_MAXFH PAGE_SIZE/sizeof(struct fh_entry)
static
struct
fh_entry
filetable
[
NFSD_MAXFH
];
static
struct
fh_entry
dirstable
[
NFSD_MAXFH
];
static
int
nfsd_nr_verified
=
0
;
static
int
nfsd_nr_put
=
0
;
static
unsigned
long
nfsd_next_expire
=
0
;
static
int
add_to_fhcache
(
struct
dentry
*
,
int
);
static
int
nfsd_d_validate
(
struct
dentry
*
);
static
LIST_HEAD
(
fixup_head
);
static
LIST_HEAD
(
path_inuse
);
static
int
nfsd_nr_paths
=
0
;
#define NFSD_MAX_PATHS 500
struct
nfsd_fixup
{
struct
list_head
lru
;
struct
dentry
*
dentry
;
unsigned
long
reftime
;
ino_t
ino
;
dev_t
dev
;
};
struct
nfsd_path
{
struct
list_head
lru
;
unsigned
long
reftime
;
int
users
;
ino_t
ino
;
dev_t
dev
;
char
name
[
1
];
};
/*
* Copy a dentry's path into the specified buffer.
*/
static
int
copy_path
(
char
*
buffer
,
struct
dentry
*
dentry
,
int
namelen
)
{
char
*
p
,
*
b
=
buffer
;
int
result
=
0
,
totlen
=
0
,
len
;
while
(
1
)
{
struct
dentry
*
parent
;
dentry
=
dentry
->
d_covers
;
parent
=
dentry
->
d_parent
;
len
=
dentry
->
d_name
.
len
;
p
=
(
char
*
)
dentry
->
d_name
.
name
+
len
;
totlen
+=
len
;
if
(
totlen
>
namelen
)
goto
out
;
while
(
len
--
)
*
b
++
=
*
(
--
p
);
if
(
dentry
==
parent
)
break
;
dentry
=
parent
;
totlen
++
;
if
(
totlen
>
namelen
)
goto
out
;
*
b
++
=
'/'
;
}
*
b
=
0
;
/*
* Now reverse in place ...
*/
p
=
buffer
;
while
(
p
<
b
)
{
char
c
=
*
(
--
b
);
*
b
=
*
p
;
*
p
++
=
c
;
}
result
=
1
;
out:
return
result
;
}
/*
* Add a dentry's path to the path cache.
*/
static
int
add_to_path_cache
(
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
dentry
*
this
;
struct
nfsd_path
*
new
;
int
len
,
result
=
0
;
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"add_to_path_cache: cacheing %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
/*
* Get the length of the full pathname.
*/
restart:
len
=
0
;
this
=
dentry
;
while
(
1
)
{
struct
dentry
*
parent
;
this
=
this
->
d_covers
;
parent
=
this
->
d_parent
;
len
+=
this
->
d_name
.
len
;
if
(
this
==
parent
)
break
;
this
=
parent
;
len
++
;
}
/*
* Allocate a structure to hold the path.
*/
new
=
kmalloc
(
sizeof
(
struct
nfsd_path
)
+
len
,
GFP_KERNEL
);
if
(
new
)
{
new
->
users
=
0
;
new
->
reftime
=
jiffies
;
new
->
ino
=
inode
->
i_ino
;
new
->
dev
=
inode
->
i_dev
;
result
=
copy_path
(
new
->
name
,
dentry
,
len
);
if
(
!
result
)
goto
retry
;
list_add
(
&
new
->
lru
,
&
path_inuse
);
nfsd_nr_paths
++
;
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"add_to_path_cache: added %s, paths=%d
\n
"
,
new
->
name
,
nfsd_nr_paths
);
#endif
}
return
result
;
/*
* If the dentry's path length changed, just try again ...
*/
retry:
kfree
(
new
);
printk
(
"add_to_path_cache: path length changed, retrying
\n
"
);
goto
restart
;
}
/*
* Search for a path entry for the specified (dev, inode).
*/
struct
nfsd_path
*
get_path_entry
(
dev_t
dev
,
ino_t
ino
)
{
struct
nfsd_path
*
pe
;
struct
list_head
*
tmp
;
for
(
tmp
=
path_inuse
.
next
;
tmp
!=
&
path_inuse
;
tmp
=
tmp
->
next
)
{
pe
=
list_entry
(
tmp
,
struct
nfsd_path
,
lru
);
if
(
pe
->
ino
!=
ino
)
continue
;
if
(
pe
->
dev
!=
dev
)
continue
;
list_del
(
tmp
);
list_add
(
tmp
,
&
path_inuse
);
pe
->
users
++
;
pe
->
reftime
=
jiffies
;
#ifdef NFSD_PARANOIA
printk
(
"get_path_entry: found %s for %s/%ld
\n
"
,
pe
->
name
,
kdevname
(
dev
),
ino
);
#endif
return
pe
;
}
return
NULL
;
}
static
void
put_path
(
struct
nfsd_path
*
pe
)
{
pe
->
users
--
;
}
static
void
free_path_entry
(
struct
nfsd_path
*
pe
)
{
if
(
pe
->
users
)
printk
(
"free_path_entry: %s in use, users=%d
\n
"
,
pe
->
name
,
pe
->
users
);
list_del
(
&
pe
->
lru
);
kfree
(
pe
);
nfsd_nr_paths
--
;
}
struct
nfsd_getdents_callback
{
struct
nfsd_dirent
*
dirent
;
int
found
;
int
checked
;
};
struct
nfsd_dirent
{
ino_t
ino
;
int
len
;
char
name
[
256
];
};
/*
* A custom filldir function to search for the specified inode.
*/
static
int
filldir_ino
(
void
*
__buf
,
const
char
*
name
,
int
len
,
off_t
pos
,
ino_t
ino
)
{
struct
nfsd_getdents_callback
*
buf
=
__buf
;
struct
nfsd_dirent
*
dirent
=
buf
->
dirent
;
int
result
=
0
;
buf
->
checked
++
;
if
(
ino
==
dirent
->
ino
)
{
buf
->
found
=
1
;
dirent
->
len
=
len
;
memcpy
(
dirent
->
name
,
name
,
len
);
dirent
->
name
[
len
]
=
0
;
result
=
-
1
;
}
return
result
;
}
/*
* Search a directory for the specified inode number.
*/
static
int
search_dir
(
struct
dentry
*
parent
,
ino_t
ino
,
struct
nfsd_dirent
*
dirent
)
{
struct
inode
*
inode
=
parent
->
d_inode
;
int
error
;
struct
file
file
;
struct
nfsd_getdents_callback
buffer
;
error
=
-
ENOTDIR
;
if
(
!
inode
||
!
S_ISDIR
(
inode
->
i_mode
))
goto
out
;
error
=
-
EINVAL
;
if
(
!
inode
->
i_op
||
!
inode
->
i_op
->
default_file_ops
)
goto
out
;
/*
* Open the directory ...
*/
error
=
init_private_file
(
&
file
,
parent
,
FMODE_READ
);
if
(
error
)
goto
out
;
error
=
-
EINVAL
;
if
(
!
file
.
f_op
->
readdir
)
goto
out_close
;
/*
* Initialize the callback buffer.
*/
dirent
->
ino
=
ino
;
buffer
.
dirent
=
dirent
;
buffer
.
found
=
0
;
while
(
1
)
{
buffer
.
checked
=
0
;
error
=
file
.
f_op
->
readdir
(
&
file
,
&
buffer
,
filldir_ino
);
if
(
error
<
0
)
break
;
error
=
0
;
if
(
buffer
.
found
)
{
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"search_dir: found %s
\n
"
,
dirent
->
name
);
#endif
break
;
}
error
=
-
ENOENT
;
if
(
!
buffer
.
checked
)
break
;
}
out_close:
if
(
file
.
f_op
->
release
)
file
.
f_op
->
release
(
inode
,
&
file
);
out:
return
error
;
}
/*
* Find an entry in the cache matching the given dentry pointer.
*/
static
struct
fh_entry
*
find_fhe
(
struct
dentry
*
dentry
,
int
cache
,
struct
fh_entry
**
empty
)
{
struct
fh_entry
*
fhe
;
int
i
,
found
=
(
empty
==
NULL
)
?
1
:
0
;
fhe
=
(
cache
==
NFSD_FILE_CACHE
)
?
&
filetable
[
0
]
:
&
dirstable
[
0
];
for
(
i
=
0
;
i
<
NFSD_MAXFH
;
i
++
,
fhe
++
)
{
if
(
fhe
->
dentry
==
dentry
)
{
fhe
->
reftime
=
jiffies
;
return
fhe
;
}
if
(
!
found
&&
!
fhe
->
dentry
)
{
found
=
1
;
*
empty
=
fhe
;
}
}
return
NULL
;
}
/*
* Expire a cache entry.
*/
static
void
expire_fhe
(
struct
fh_entry
*
empty
,
int
cache
)
{
struct
dentry
*
dentry
=
empty
->
dentry
;
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"expire_fhe: expiring %s/%s, d_count=%d, ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
,
empty
->
ino
);
#endif
empty
->
dentry
=
NULL
;
/* no dentry */
/*
* Add the parent to the dir cache before releasing the dentry.
*/
if
(
dentry
!=
dentry
->
d_parent
)
{
struct
dentry
*
parent
=
dget
(
dentry
->
d_parent
);
if
(
add_to_fhcache
(
parent
,
NFSD_DIR_CACHE
))
nfsd_nr_verified
++
;
else
dput
(
parent
);
}
/*
* If we're expiring a directory, copy its path.
*/
if
(
cache
==
NFSD_DIR_CACHE
)
{
add_to_path_cache
(
dentry
);
}
dput
(
dentry
);
nfsd_nr_put
++
;
}
/*
* Look for an empty slot, or select one to expire.
*/
static
void
expire_slot
(
int
cache
)
{
struct
fh_entry
*
fhe
,
*
empty
=
NULL
;
unsigned
long
oldest
=
-
1
;
int
i
;
fhe
=
(
cache
==
NFSD_FILE_CACHE
)
?
&
filetable
[
0
]
:
&
dirstable
[
0
];
for
(
i
=
0
;
i
<
NFSD_MAXFH
;
i
++
,
fhe
++
)
{
if
(
!
fhe
->
dentry
)
goto
out
;
if
(
fhe
->
reftime
<
oldest
)
{
oldest
=
fhe
->
reftime
;
empty
=
fhe
;
}
}
if
(
empty
)
expire_fhe
(
empty
,
cache
);
out:
return
;
}
/*
* Expire any cache entries older than a certain age.
*/
static
void
expire_old
(
int
cache
,
int
age
)
{
struct
fh_entry
*
fhe
;
int
i
;
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"expire_old: expiring %s older than %d
\n
"
,
(
cache
==
NFSD_FILE_CACHE
)
?
"file"
:
"dir"
,
age
);
#endif
fhe
=
(
cache
==
NFSD_FILE_CACHE
)
?
&
filetable
[
0
]
:
&
dirstable
[
0
];
for
(
i
=
0
;
i
<
NFSD_MAXFH
;
i
++
,
fhe
++
)
{
if
(
!
fhe
->
dentry
)
continue
;
if
((
jiffies
-
fhe
->
reftime
)
>
age
)
expire_fhe
(
fhe
,
cache
);
}
/*
* Trim the path cache ...
*/
while
(
nfsd_nr_paths
>
NFSD_MAX_PATHS
)
{
struct
nfsd_path
*
pe
;
pe
=
list_entry
(
path_inuse
.
prev
,
struct
nfsd_path
,
lru
);
if
(
pe
->
users
)
break
;
free_path_entry
(
pe
);
}
}
/*
* Add a dentry to the file or dir cache.
*
* Note: As NFS filehandles must have an inode, we don't accept
* negative dentries.
*/
static
int
add_to_fhcache
(
struct
dentry
*
dentry
,
int
cache
)
{
struct
fh_entry
*
fhe
,
*
empty
=
NULL
;
struct
inode
*
inode
=
dentry
->
d_inode
;
if
(
!
inode
)
{
#ifdef NFSD_PARANOIA
printk
(
"add_to_fhcache: %s/%s rejected, no inode!
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
return
0
;
}
repeat:
fhe
=
find_fhe
(
dentry
,
cache
,
&
empty
);
if
(
fhe
)
{
return
0
;
}
/*
* Not found ... make a new entry.
*/
if
(
empty
)
{
empty
->
dentry
=
dentry
;
empty
->
reftime
=
jiffies
;
empty
->
ino
=
inode
->
i_ino
;
empty
->
dev
=
inode
->
i_dev
;
return
1
;
}
expire_slot
(
cache
);
goto
repeat
;
}
/*
* Find an entry in the dir cache for the specified inode number.
*/
static
struct
fh_entry
*
find_fhe_by_ino
(
dev_t
dev
,
ino_t
ino
)
{
struct
fh_entry
*
fhe
=
&
dirstable
[
0
];
int
i
;
for
(
i
=
0
;
i
<
NFSD_MAXFH
;
i
++
,
fhe
++
)
{
if
(
fhe
->
ino
==
ino
&&
fhe
->
dev
==
dev
)
{
fhe
->
reftime
=
jiffies
;
return
fhe
;
}
}
return
NULL
;
}
/*
* Find the (directory) dentry with the specified (dev, inode) number.
* Note: this leaves the dentry in the cache.
*/
static
struct
dentry
*
find_dentry_by_ino
(
dev_t
dev
,
ino_t
ino
)
{
struct
fh_entry
*
fhe
;
struct
nfsd_path
*
pe
;
struct
dentry
*
dentry
;
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"find_dentry_by_ino: looking for inode %ld
\n
"
,
ino
);
#endif
fhe
=
find_fhe_by_ino
(
dev
,
ino
);
if
(
fhe
)
{
dentry
=
dget
(
fhe
->
dentry
);
goto
out
;
}
/*
* Search the path cache ...
*/
dentry
=
NULL
;
pe
=
get_path_entry
(
dev
,
ino
);
if
(
pe
)
{
struct
dentry
*
res
;
res
=
lookup_dentry
(
pe
->
name
,
NULL
,
0
);
if
(
!
IS_ERR
(
res
))
{
struct
inode
*
inode
=
res
->
d_inode
;
if
(
inode
&&
inode
->
i_ino
==
ino
&&
inode
->
i_dev
==
dev
)
{
dentry
=
res
;
#ifdef NFSD_PARANOIA
printk
(
"find_dentry_by_ino: found %s/%s, ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
ino
);
#endif
if
(
add_to_fhcache
(
dentry
,
NFSD_DIR_CACHE
))
{
dget
(
dentry
);
nfsd_nr_verified
++
;
}
}
else
{
dput
(
res
);
}
}
else
{
#ifdef NFSD_PARANOIA
printk
(
"find_dentry_by_ino: %s lookup failed
\n
"
,
pe
->
name
);
#endif
}
put_path
(
pe
);
}
out:
return
dentry
;
}
/*
* Look for an entry in the file cache matching the dentry pointer,
* and verify that the (dev, inode) numbers are correct. If found,
* the entry is removed from the cache.
*/
static
struct
dentry
*
find_dentry_in_fhcache
(
struct
knfs_fh
*
fh
)
{
struct
fh_entry
*
fhe
;
fhe
=
find_fhe
(
fh
->
fh_dcookie
,
NFSD_FILE_CACHE
,
NULL
);
if
(
fhe
)
{
struct
dentry
*
parent
,
*
dentry
=
fhe
->
dentry
;
struct
inode
*
inode
=
dentry
->
d_inode
;
if
(
!
inode
)
{
#ifdef NFSD_PARANOIA
printk
(
"find_dentry_in_fhcache: %s/%s has no inode!
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
goto
out
;
}
if
(
inode
->
i_ino
!=
fh
->
fh_ino
||
inode
->
i_dev
!=
fh
->
fh_dev
)
{
#ifdef NFSD_PARANOIA
printk
(
"find_dentry_in_fhcache: %s/%s mismatch, ino=%ld, fh_ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
inode
->
i_ino
,
fh
->
fh_ino
);
#endif
goto
out
;
}
fhe
->
dentry
=
NULL
;
fhe
->
ino
=
0
;
fhe
->
dev
=
0
;
nfsd_nr_put
++
;
/*
* Make sure the parent is in the dir cache ...
*/
parent
=
dget
(
dentry
->
d_parent
);
if
(
add_to_fhcache
(
parent
,
NFSD_DIR_CACHE
))
nfsd_nr_verified
++
;
else
dput
(
parent
);
return
dentry
;
}
out:
return
NULL
;
}
/*
* Look for an entry in the parent directory with the specified
* inode number.
*/
static
struct
dentry
*
lookup_by_inode
(
struct
dentry
*
parent
,
ino_t
ino
)
{
struct
dentry
*
dentry
;
int
error
;
struct
nfsd_dirent
dirent
;
/*
* Search the directory for the inode number.
*/
error
=
search_dir
(
parent
,
ino
,
&
dirent
);
if
(
error
)
{
#ifdef NFSD_PARANOIA
printk
(
"lookup_by_inode: ino %ld not found in %s
\n
"
,
ino
,
parent
->
d_name
.
name
);
#endif
goto
no_entry
;
}
dentry
=
lookup_dentry
(
dirent
.
name
,
dget
(
parent
),
0
);
if
(
!
IS_ERR
(
dentry
))
{
if
(
dentry
->
d_inode
&&
dentry
->
d_inode
->
i_ino
==
ino
)
goto
out
;
#ifdef NFSD_PARANOIA
printk
(
"lookup_by_inode: %s/%s inode mismatch??
\n
"
,
parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
dput
(
dentry
);
}
else
{
#ifdef NFSD_PARANOIA
printk
(
"lookup_by_inode: %s lookup failed, error=%ld
\n
"
,
dirent
.
name
,
PTR_ERR
(
dentry
));
#endif
}
no_entry:
dentry
=
NULL
;
out:
return
dentry
;
}
/*
* The is the basic lookup mechanism for turning an NFS filehandle
* into a dentry. There are several levels to the search:
* (1) Look for the dentry pointer the short-term fhcache,
* and verify that it has the correct inode number.
*
* (2) Try to validate the dentry pointer in the filehandle,
* and verify that it has the correct inode number.
*
* (3) Search for the parent dentry in the dir cache, and then
* look for the name matching the inode number.
*
* (4) The most general case ... search the whole volume for the inode.
*
* If successful, we return a dentry with the use count incremented.
*/
static
struct
dentry
*
find_fh_dentry
(
struct
knfs_fh
*
fh
)
{
struct
dentry
*
dentry
,
*
parent
;
/*
* Stage 1: Look for the dentry in the short-term fhcache.
*/
dentry
=
find_dentry_in_fhcache
(
fh
);
if
(
dentry
)
{
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"find_fh_dentry: found %s/%s, d_count=%d, ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
,
fh
->
fh_ino
);
#endif
goto
out
;
}
/*
* Stage 2: Attempt to validate the dentry in the filehandle.
*/
dentry
=
fh
->
fh_dcookie
;
if
(
nfsd_d_validate
(
dentry
))
{
struct
inode
*
dir
=
dentry
->
d_parent
->
d_inode
;
if
(
dir
->
i_ino
==
fh
->
fh_dirino
&&
dir
->
i_dev
==
fh
->
fh_dev
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
/*
* NFS filehandles must always have an inode,
* so we won't accept a negative dentry.
*/
if
(
!
inode
)
{
#ifdef NFSD_PARANOIA
printk
(
"find_fh_dentry: %s/%s negative, can't match %ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
fh
->
fh_ino
);
#endif
}
else
if
(
inode
->
i_ino
==
fh
->
fh_ino
&&
inode
->
i_dev
==
fh
->
fh_dev
)
{
dget
(
dentry
);
#ifdef NFSD_DEBUG_VERBOSE
printk
(
"find_fh_dentry: validated %s/%s, ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
inode
->
i_ino
);
#endif
goto
out
;
}
else
{
#ifdef NFSD_PARANOIA
printk
(
"find_fh_dentry: %s/%s mismatch, ino=%ld, fh_ino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
inode
->
i_ino
,
fh
->
fh_ino
);
#endif
}
}
else
{
#ifdef NFSD_PARANOIA
printk
(
"find_fh_dentry: %s/%s mismatch, parent ino=%ld, dirino=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dir
->
i_ino
,
fh
->
fh_dirino
);
#endif
}
}
/*
* Stage 3: Look for the parent dentry in the fhcache ...
*/
parent
=
find_dentry_by_ino
(
fh
->
fh_dev
,
fh
->
fh_dirino
);
if
(
parent
)
{
/*
* ... then search for the inode in the parent directory.
*/
dentry
=
lookup_by_inode
(
parent
,
fh
->
fh_ino
);
dput
(
parent
);
if
(
dentry
)
goto
out
;
}
/*
* Stage 4: Search the whole volume.
*/
#ifdef NFSD_PARANOIA
printk
(
"find_fh_dentry: %s, %ld/%ld not found -- need full search!
\n
"
,
kdevname
(
fh
->
fh_dev
),
fh
->
fh_dirino
,
fh
->
fh_ino
);
#endif
dentry
=
NULL
;
out:
/*
* Perform any needed housekeeping ...
* N.B. move this into one of the daemons ...
*/
if
(
jiffies
>=
nfsd_next_expire
)
{
expire_old
(
NFSD_FILE_CACHE
,
5
*
HZ
);
expire_old
(
NFSD_DIR_CACHE
,
60
*
HZ
);
nfsd_next_expire
=
jiffies
+
5
*
HZ
;
}
return
dentry
;
}
/*
* Perform sanity checks on the dentry in a client's file handle.
*
* Note that the filehandle dentry may need to be freed even after
* an error return.
*/
u32
fh_verify
(
struct
svc_rqst
*
rqstp
,
struct
svc_fh
*
fhp
,
int
type
,
int
access
)
...
...
@@ -27,50 +736,53 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
struct
dentry
*
dentry
;
struct
inode
*
inode
;
struct
knfs_fh
*
fh
=
&
fhp
->
fh_handle
;
u32
error
=
0
;
if
(
fhp
->
fh_dverified
)
return
0
;
goto
out
;
dprintk
(
"nfsd: fh_lookup(exp %x/%ld fh %p)
\n
"
,
fh
->
fh_xdev
,
fh
->
fh_xino
,
fh
->
fh_d
entry
);
fh
->
fh_xdev
,
fh
->
fh_xino
,
fh
->
fh_d
cookie
);
/* Look up the export entry. */
/*
* Look up the export entry.
* N.B. We need to lock this while in use ...
*/
error
=
nfserr_stale
;
exp
=
exp_get
(
rqstp
->
rq_client
,
fh
->
fh_xdev
,
fh
->
fh_xino
);
if
(
!
exp
)
{
/* nfsdstats.fhstale++; */
return
nfserr_stale
;
/* export entry revoked */
}
if
(
!
exp
)
/* export entry revoked */
goto
out
;
/* Check if the request originated from a secure port. */
error
=
nfserr_perm
;
if
(
!
rqstp
->
rq_secure
&&
EX_SECURE
(
exp
))
{
printk
(
KERN_WARNING
"nfsd: request from insecure port (%08lx:%d)!
\n
"
,
ntohl
(
rqstp
->
rq_addr
.
sin_addr
.
s_addr
),
ntohs
(
rqstp
->
rq_addr
.
sin_port
));
return
nfserr_perm
;
goto
out
;
}
/* Set user creds if we haven't done so already. */
nfsd_setuser
(
rqstp
,
exp
);
dentry
=
fh
->
fh_dentry
;
if
(
!
d_validate
(
dentry
,
fh
->
fh_dparent
,
fh
->
fh_dhash
,
fh
->
fh_dlen
)
||
!
(
inode
=
dentry
->
d_inode
)
||
!
inode
->
i_nlink
)
{
/* Currently we cannot tell the difference between
* a bogus pointer and a true unlink between fh
* uses. But who cares about accurate error reporting
* to buggy/malicious clients... -DaveM
*/
/* nfsdstats.fhstale++; */
return
nfserr_stale
;
}
dget
(
dentry
);
fhp
->
fh_dverified
=
1
;
/*
* Look up the dentry using the NFS fh.
*/
error
=
nfserr_stale
;
dentry
=
find_fh_dentry
(
fh
);
if
(
!
dentry
)
goto
out
;
/*
* Note: it's possible that the returned dentry won't be the
* one in the filehandle. We can correct the FH for our use,
* but unfortunately the client will keep sending the broken
* one. Hopefully the lookup will keep patching things up..
*/
fhp
->
fh_dentry
=
dentry
;
fhp
->
fh_export
=
exp
;
fhp
->
fh_dverified
=
1
;
nfsd_nr_verified
++
;
/* Type check. The correct error return for type mismatches
* does not seem to be generally agreed upon. SunOS seems to
...
...
@@ -78,33 +790,189 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
* spec says this is incorrect (implementation notes for the
* write call).
*/
if
(
type
>
0
&&
(
inode
->
i_mode
&
S_IFMT
)
!=
type
)
return
(
type
==
S_IFDIR
)
?
nfserr_notdir
:
nfserr_isdir
;
if
(
type
<
0
&&
(
inode
->
i_mode
&
S_IFMT
)
==
-
type
)
return
(
type
==
-
S_IFDIR
)
?
nfserr_notdir
:
nfserr_isdir
;
inode
=
dentry
->
d_inode
;
if
(
type
>
0
&&
(
inode
->
i_mode
&
S_IFMT
)
!=
type
)
{
error
=
(
type
==
S_IFDIR
)
?
nfserr_notdir
:
nfserr_isdir
;
goto
out
;
}
if
(
type
<
0
&&
(
inode
->
i_mode
&
S_IFMT
)
==
-
type
)
{
error
=
(
type
==
-
S_IFDIR
)
?
nfserr_notdir
:
nfserr_isdir
;
goto
out
;
}
/* Finally, check access permissions. */
return
nfsd_permission
(
fhp
->
fh_export
,
dentry
,
access
);
error
=
nfsd_permission
(
fhp
->
fh_export
,
dentry
,
access
);
out:
return
error
;
}
/*
* Compose file handle for NFS reply.
* Compose a filehandle for an NFS reply.
*
* Note that when first composed, the dentry may not yet have
* an inode. In this case a call to fh_update should be made
* before the fh goes out on the wire ...
*/
void
fh_compose
(
struct
svc_fh
*
fhp
,
struct
svc_export
*
exp
,
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
dprintk
(
"nfsd: fh_compose(exp %x/%ld dentry %p)
\n
"
,
exp
->
ex_dev
,
exp
->
ex_ino
,
dentry
);
fh_init
(
fhp
);
/* initialize empty fh */
fhp
->
fh_handle
.
fh_dentry
=
dentry
;
fhp
->
fh_handle
.
fh_dparent
=
dentry
->
d_parent
;
fhp
->
fh_handle
.
fh_dhash
=
dentry
->
d_name
.
hash
;
fhp
->
fh_handle
.
fh_dlen
=
dentry
->
d_name
.
len
;
/*
* N.B. We shouldn't need to init the fh -- the call to fh_compose
* may not be done on error paths, but the cleanup must call fh_put.
* Fix this soon!
*/
fh_init
(
fhp
);
fhp
->
fh_handle
.
fh_dcookie
=
dentry
;
if
(
inode
)
{
fhp
->
fh_handle
.
fh_ino
=
inode
->
i_ino
;
}
fhp
->
fh_handle
.
fh_dirino
=
dentry
->
d_parent
->
d_inode
->
i_ino
;
fhp
->
fh_handle
.
fh_dev
=
dentry
->
d_parent
->
d_inode
->
i_dev
;
fhp
->
fh_handle
.
fh_xdev
=
exp
->
ex_dev
;
fhp
->
fh_handle
.
fh_xino
=
exp
->
ex_ino
;
fhp
->
fh_dentry
=
dentry
;
/* our internal copy */
fhp
->
fh_export
=
exp
;
/* We stuck it there, we know it's good. */
fhp
->
fh_dverified
=
1
;
nfsd_nr_verified
++
;
}
/*
* Update filehandle information after changing a dentry.
*/
void
fh_update
(
struct
svc_fh
*
fhp
)
{
struct
dentry
*
dentry
;
struct
inode
*
inode
;
if
(
!
fhp
->
fh_dverified
)
{
printk
(
"fh_update: fh not verified!
\n
"
);
goto
out
;
}
dentry
=
fhp
->
fh_dentry
;
inode
=
dentry
->
d_inode
;
if
(
!
inode
)
{
printk
(
"fh_update: %s/%s still negative!
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
goto
out
;
}
fhp
->
fh_handle
.
fh_ino
=
inode
->
i_ino
;
out:
return
;
}
/*
* Release a filehandle. If the filehandle carries a dentry count,
* we add the dentry to the short-term cache rather than release it.
*/
void
fh_put
(
struct
svc_fh
*
fhp
)
{
if
(
fhp
->
fh_dverified
)
{
struct
dentry
*
dentry
=
fhp
->
fh_dentry
;
fh_unlock
(
fhp
);
fhp
->
fh_dverified
=
0
;
if
(
!
dentry
->
d_count
)
{
printk
(
"fh_put: %s/%s has d_count 0!
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
return
;
}
if
(
!
dentry
->
d_inode
||
!
add_to_fhcache
(
dentry
,
0
))
{
dput
(
dentry
);
nfsd_nr_put
++
;
}
}
}
/*
* Verify that the FH dentry is still a valid dentry pointer.
* After making some preliminary checks, we ask VFS to verify
* that it is indeed a dentry.
*/
static
int
nfsd_d_validate
(
struct
dentry
*
dentry
)
{
unsigned
long
dent_addr
=
(
unsigned
long
)
dentry
;
unsigned
long
min_addr
=
PAGE_OFFSET
;
unsigned
long
max_addr
=
min_addr
+
(
num_physpages
<<
PAGE_SHIFT
);
unsigned
long
align_mask
=
0x1F
;
unsigned
int
len
;
int
valid
=
0
;
if
(
dent_addr
<
min_addr
)
goto
bad_addr
;
if
(
dent_addr
>
max_addr
-
sizeof
(
struct
dentry
))
goto
bad_addr
;
if
((
dent_addr
&
~
align_mask
)
!=
dent_addr
)
goto
bad_addr
;
/*
* Looks safe enough to dereference ...
*/
len
=
dentry
->
d_name
.
len
;
if
(
len
>
NFS_MAXNAMLEN
)
goto
bad_length
;
valid
=
d_validate
(
dentry
,
dentry
->
d_parent
,
dentry
->
d_name
.
hash
,
len
);
out:
return
valid
;
bad_addr:
printk
(
"nfsd_d_validate: invalid address %lx
\n
"
,
dent_addr
);
goto
out
;
bad_length:
printk
(
"nfsd_d_validate: invalid length %d
\n
"
,
len
);
goto
out
;
}
/*
* Free the dentry and path caches.
*/
void
nfsd_fh_free
(
void
)
{
struct
fh_entry
*
fhe
;
struct
list_head
*
tmp
;
int
i
,
pass
=
2
;
fhe
=
&
filetable
[
0
];
while
(
pass
--
)
{
for
(
i
=
0
;
i
<
NFSD_MAXFH
;
i
++
,
fhe
++
)
{
struct
dentry
*
dentry
=
fhe
->
dentry
;
if
(
!
dentry
)
continue
;
fhe
->
dentry
=
NULL
;
dput
(
dentry
);
nfsd_nr_put
++
;
}
fhe
=
&
dirstable
[
0
];
}
i
=
0
;
while
((
tmp
=
path_inuse
.
next
)
!=
&
path_inuse
)
{
struct
nfsd_path
*
pe
=
list_entry
(
tmp
,
struct
nfsd_path
,
lru
);
free_path_entry
(
pe
);
i
++
;
}
printk
(
"nfsd_fh_free: %d paths freed
\n
"
,
i
);
printk
(
"nfsd_fh_free: verified %d, put %d
\n
"
,
nfsd_nr_verified
,
nfsd_nr_put
);
}
void
nfsd_fh_init
(
void
)
{
memset
(
filetable
,
0
,
NFSD_MAXFH
*
sizeof
(
struct
fh_entry
));
memset
(
dirstable
,
0
,
NFSD_MAXFH
*
sizeof
(
struct
fh_entry
));
INIT_LIST_HEAD
(
&
path_inuse
);
printk
(
"nfsd_init: initialized fhcache, entries=%lu
\n
"
,
NFSD_MAXFH
);
}
fs/nfsd/nfsproc.c
View file @
7f98bfdb
...
...
@@ -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
)
{
...
...
fs/nfsd/nfsxdr.c
View file @
7f98bfdb
...
...
@@ -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
);
...
...
fs/nfsd/vfs.c
View file @
7f98bfdb
...
...
@@ -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
;
}
/*
...
...
fs/select.c
View file @
7f98bfdb
...
...
@@ -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
;
...
...
include/asm-alpha/softirq.h
View file @
7f98bfdb
...
...
@@ -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
"
...
...
include/linux/nfsd/nfsfh.h
View file @
7f98bfdb
...
...
@@ -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 */
net/sunrpc/svcsock.c
View file @
7f98bfdb
...
...
@@ -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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment