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
f59dfe26
Commit
f59dfe26
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 2.1.58
parent
b23c7003
Changes
50
Hide whitespace changes
Inline
Side-by-side
Showing
50 changed files
with
3020 additions
and
1475 deletions
+3020
-1475
CREDITS
CREDITS
+3
-2
Makefile
Makefile
+1
-1
arch/i386/mm/fault.c
arch/i386/mm/fault.c
+2
-1
fs/bad_inode.c
fs/bad_inode.c
+10
-1
fs/binfmt_misc.c
fs/binfmt_misc.c
+53
-32
fs/dcache.c
fs/dcache.c
+124
-44
fs/file_table.c
fs/file_table.c
+32
-17
fs/lockd/clntproc.c
fs/lockd/clntproc.c
+6
-2
fs/lockd/svc.c
fs/lockd/svc.c
+114
-27
fs/locks.c
fs/locks.c
+3
-3
fs/namei.c
fs/namei.c
+10
-6
fs/nfs/dir.c
fs/nfs/dir.c
+288
-184
fs/nfs/inode.c
fs/nfs/inode.c
+83
-39
fs/nfs/nfs2xdr.c
fs/nfs/nfs2xdr.c
+30
-18
fs/nfs/nfs3xdr.c
fs/nfs/nfs3xdr.c
+34
-14
fs/nfs/proc.c
fs/nfs/proc.c
+27
-8
fs/proc/array.c
fs/proc/array.c
+44
-22
fs/proc/base.c
fs/proc/base.c
+6
-2
fs/proc/generic.c
fs/proc/generic.c
+58
-39
fs/proc/inode.c
fs/proc/inode.c
+110
-32
fs/proc/root.c
fs/proc/root.c
+80
-19
fs/smbfs/Makefile
fs/smbfs/Makefile
+1
-1
fs/smbfs/cache.c
fs/smbfs/cache.c
+314
-0
fs/smbfs/dir.c
fs/smbfs/dir.c
+187
-239
fs/smbfs/file.c
fs/smbfs/file.c
+105
-61
fs/smbfs/inode.c
fs/smbfs/inode.c
+192
-87
fs/smbfs/proc.c
fs/smbfs/proc.c
+580
-362
fs/smbfs/sock.c
fs/smbfs/sock.c
+69
-47
fs/super.c
fs/super.c
+26
-29
include/linux/dcache.h
include/linux/dcache.h
+1
-0
include/linux/fs.h
include/linux/fs.h
+6
-1
include/linux/list.h
include/linux/list.h
+39
-8
include/linux/mm.h
include/linux/mm.h
+2
-0
include/linux/nfs.h
include/linux/nfs.h
+0
-8
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+2
-2
include/linux/proc_fs.h
include/linux/proc_fs.h
+3
-1
include/linux/smb_fs.h
include/linux/smb_fs.h
+92
-33
include/linux/smb_fs_i.h
include/linux/smb_fs_i.h
+3
-1
include/linux/smb_fs_sb.h
include/linux/smb_fs_sb.h
+6
-0
include/linux/sunrpc/sched.h
include/linux/sunrpc/sched.h
+1
-1
kernel/fork.c
kernel/fork.c
+18
-10
kernel/ksyms.c
kernel/ksyms.c
+4
-0
kernel/sysctl.c
kernel/sysctl.c
+1
-1
mm/filemap.c
mm/filemap.c
+57
-0
mm/vmscan.c
mm/vmscan.c
+23
-9
net/sunrpc/clnt.c
net/sunrpc/clnt.c
+28
-17
net/sunrpc/pmap_clnt.c
net/sunrpc/pmap_clnt.c
+8
-7
net/sunrpc/sched.c
net/sunrpc/sched.c
+104
-18
net/sunrpc/svc.c
net/sunrpc/svc.c
+23
-17
net/sunrpc/svcsock.c
net/sunrpc/svcsock.c
+7
-2
No files found.
CREDITS
View file @
f59dfe26
...
...
@@ -632,8 +632,9 @@ S: USA
N: Nick Holloway
E: Nick.Holloway@alfie.demon.co.uk
E: Nick.Holloway@parallax.co.uk
D: Small patches for kernel, libc
D: MAKEDEV
W: http://www.alfie.demon.co.uk/
P: 1024/75C49395 3A F0 E3 4E B7 9F E0 7E 47 A3 B0 D5 68 6A C2 FB
D: Occasional Linux hacker...
S: 15 Duke Street
S: Chapelfields
S: Coventry
...
...
Makefile
View file @
f59dfe26
VERSION
=
2
PATCHLEVEL
=
1
SUBLEVEL
=
5
7
SUBLEVEL
=
5
8
ARCH
:=
$(
shell
uname
-m
|
sed
-e
s/i.86/i386/
-e
s/sun4u/sparc64/
)
...
...
arch/i386/mm/fault.c
View file @
f59dfe26
...
...
@@ -172,9 +172,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* Are we prepared to handle this kernel fault? */
if
((
fixup
=
search_exception_table
(
regs
->
eip
))
!=
0
)
{
printk
(
KERN_DEBUG
"%s: Exception at [<%lx>]
(
%lx)
\n
"
,
printk
(
KERN_DEBUG
"%s: Exception at [<%lx>]
cr2=%lx (fixup:
%lx)
\n
"
,
tsk
->
comm
,
regs
->
eip
,
address
,
fixup
);
regs
->
eip
=
fixup
;
goto
out
;
...
...
fs/bad_inode.c
View file @
f59dfe26
...
...
@@ -19,7 +19,7 @@ static struct dentry * bad_follow_link(struct inode * ino, struct dentry *base)
return
ERR_PTR
(
-
EIO
);
}
static
int
return_EIO
()
static
int
return_EIO
(
void
)
{
return
-
EIO
;
}
...
...
@@ -81,3 +81,12 @@ void make_bad_inode(struct inode * inode)
inode
->
i_op
=
&
bad_inode_ops
;
}
/*
* This tests whether an inode has been flagged as bad. The test uses
* &bad_inode_ops to cover the case of invalidated inodes as well as
* those created by make_bad_inode() above.
*/
int
is_bad_inode
(
struct
inode
*
inode
)
{
return
(
inode
->
i_op
==
&
bad_inode_ops
);
}
fs/binfmt_misc.c
View file @
f59dfe26
...
...
@@ -281,21 +281,19 @@ static int proc_write_register(struct file *file, const char *buffer,
const
char
*
sp
;
char
del
,
*
dp
;
struct
binfmt_entry
*
e
;
int
memsize
,
cnt
=
count
-
1
,
err
=
0
;
int
memsize
,
cnt
=
count
-
1
,
err
;
MOD_INC_USE_COUNT
;
/* some sanity checks */
if
((
count
<
11
)
||
(
count
>
256
))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
if
((
count
<
11
)
||
(
count
>
256
))
goto
_err
;
}
err
=
-
ENOMEM
;
memsize
=
sizeof
(
struct
binfmt_entry
)
+
count
;
if
(
!
(
e
=
(
struct
binfmt_entry
*
)
kmalloc
(
memsize
,
GFP_USER
)))
{
err
=
-
ENOMEM
;
if
(
!
(
e
=
(
struct
binfmt_entry
*
)
kmalloc
(
memsize
,
GFP_USER
)))
goto
_err
;
}
err
=
0
;
sp
=
buffer
+
1
;
del
=
buffer
[
0
];
dp
=
(
char
*
)
e
+
sizeof
(
struct
binfmt_entry
);
...
...
@@ -327,12 +325,8 @@ static int proc_write_register(struct file *file, const char *buffer,
/* more sanity checks */
if
(
err
||
!
(
!
cnt
||
(
!
(
--
cnt
)
&&
(
*
sp
==
'\n'
)))
||
(
e
->
size
<
1
)
||
((
e
->
size
+
e
->
offset
)
>
127
)
||
!
(
e
->
proc_name
)
||
!
(
e
->
interpreter
)
||
entry_proc_setup
(
e
))
{
kfree
(
e
);
err
=
-
EINVAL
;
goto
_err
;
}
!
(
e
->
proc_name
)
||
!
(
e
->
interpreter
)
||
entry_proc_setup
(
e
))
goto
free_err
;
write_lock
(
&
entries_lock
);
e
->
next
=
entries
;
...
...
@@ -341,8 +335,11 @@ static int proc_write_register(struct file *file, const char *buffer,
err
=
count
;
_err:
MOD_DEC_USE_COUNT
;
return
err
;
free_err:
kfree
(
e
);
err
=
-
EINVAL
;
goto
_err
;
}
/*
...
...
@@ -357,7 +354,6 @@ static int proc_read_status(char *page, char **start, off_t off,
char
*
dp
;
int
elen
,
i
,
err
;
MOD_INC_USE_COUNT
;
#ifndef VERBOSE_STATUS
if
(
data
)
{
if
(
!
(
e
=
get_entry
((
int
)
data
)))
{
...
...
@@ -415,7 +411,6 @@ static int proc_read_status(char *page, char **start, off_t off,
err
=
elen
;
_err:
MOD_DEC_USE_COUNT
;
return
err
;
}
...
...
@@ -429,7 +424,6 @@ static int proc_write_status(struct file *file, const char *buffer,
struct
binfmt_entry
*
e
;
int
res
=
count
;
MOD_INC_USE_COUNT
;
if
(
buffer
[
count
-
1
]
==
'\n'
)
count
--
;
if
((
count
==
1
)
&&
!
(
buffer
[
0
]
&
~
(
'0'
|
'1'
)))
{
...
...
@@ -449,7 +443,6 @@ static int proc_write_status(struct file *file, const char *buffer,
}
else
{
res
=
-
EINVAL
;
}
MOD_DEC_USE_COUNT
;
return
res
;
}
...
...
@@ -477,29 +470,57 @@ static int entry_proc_setup(struct binfmt_entry *e)
return
0
;
}
#ifdef MODULE
/*
* This is called as the fill_inode function when an inode
* is going into (fill = 1) or out of service (fill = 0).
* We use it here to manage the module use counts.
*
* Note: only the top-level directory needs to do this; if
* a lower level is referenced, the parent will be as well.
*/
static
void
bm_modcount
(
struct
inode
*
inode
,
int
fill
)
{
if
(
fill
)
MOD_INC_USE_COUNT
;
else
MOD_DEC_USE_COUNT
;
}
#endif
__initfunc
(
int
init_misc_binfmt
(
void
))
{
struct
proc_dir_entry
*
status
=
NULL
,
*
reg
;
int
error
=
-
ENOMEM
;
if
(
!
(
bm_dir
=
create_proc_entry
(
"sys/fs/binfmt_misc"
,
S_IFDIR
,
NULL
))
||
!
(
status
=
create_proc_entry
(
"status"
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
bm_dir
))
||
!
(
reg
=
create_proc_entry
(
"register"
,
S_IFREG
|
S_IWUSR
,
bm_dir
)))
{
if
(
status
)
remove_proc_entry
(
"status"
,
bm_dir
);
if
(
bm_dir
)
remove_proc_entry
(
"sys/fs/binfmt_misc"
,
NULL
);
return
-
ENOMEM
;
}
bm_dir
=
create_proc_entry
(
"sys/fs/binfmt_misc"
,
S_IFDIR
,
NULL
);
if
(
!
bm_dir
)
goto
out
;
#ifdef MODULE
bm_dir
->
fill_inode
=
bm_modcount
;
#endif
status
=
create_proc_entry
(
"status"
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
bm_dir
);
if
(
!
status
)
goto
cleanup_bm
;
status
->
read_proc
=
proc_read_status
;
status
->
write_proc
=
proc_write_status
;
reg
=
create_proc_entry
(
"register"
,
S_IFREG
|
S_IWUSR
,
bm_dir
);
if
(
!
reg
)
goto
cleanup_status
;
reg
->
write_proc
=
proc_write_register
;
return
register_binfmt
(
&
misc_format
);
error
=
register_binfmt
(
&
misc_format
);
out:
return
error
;
cleanup_status:
remove_proc_entry
(
"status"
,
bm_dir
);
cleanup_bm:
remove_proc_entry
(
"sys/fs/binfmt_misc"
,
NULL
);
goto
out
;
}
#ifdef MODULE
...
...
fs/dcache.c
View file @
f59dfe26
...
...
@@ -61,37 +61,54 @@ static inline void d_free(struct dentry *dentry)
*/
void
dput
(
struct
dentry
*
dentry
)
{
if
(
dentry
)
{
int
count
;
int
count
;
if
(
!
dentry
)
return
;
repeat:
count
=
dentry
->
d_count
-
1
;
if
(
count
<
0
)
{
printk
(
"Negative d_count (%d) for %s/%s
\n
"
,
count
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
*
(
int
*
)
0
=
0
;
}
count
=
dentry
->
d_count
-
1
;
if
(
count
!=
0
)
goto
out
;
/*
* Note that if d_op->d_delete blocks,
* the dentry could go back in use.
* Each fs will have to watch for this.
*/
if
(
dentry
->
d_op
&&
dentry
->
d_op
->
d_delete
)
{
dentry
->
d_op
->
d_delete
(
dentry
);
count
=
dentry
->
d_count
-
1
;
if
(
count
!=
0
)
goto
out
;
}
list_del
(
&
dentry
->
d_lru
);
if
(
list_empty
(
&
dentry
->
d_hash
))
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
dentry
*
parent
;
if
(
inode
)
iput
(
inode
);
parent
=
dentry
->
d_parent
;
d_free
(
dentry
);
if
(
dentry
==
parent
)
return
;
dentry
=
parent
;
goto
repeat
;
}
list_add
(
&
dentry
->
d_lru
,
&
dentry_unused
);
out:
if
(
count
>=
0
)
{
dentry
->
d_count
=
count
;
if
(
!
count
)
{
list_del
(
&
dentry
->
d_lru
);
if
(
dentry
->
d_op
&&
dentry
->
d_op
->
d_delete
)
dentry
->
d_op
->
d_delete
(
dentry
);
if
(
list_empty
(
&
dentry
->
d_hash
))
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
dentry
*
parent
;
if
(
inode
)
iput
(
inode
);
parent
=
dentry
->
d_parent
;
d_free
(
dentry
);
if
(
dentry
==
parent
)
return
;
dentry
=
parent
;
goto
repeat
;
}
list_add
(
&
dentry
->
d_lru
,
&
dentry_unused
);
}
return
;
}
printk
(
"Negative d_count (%d) for %s/%s
\n
"
,
count
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
*
(
int
*
)
0
=
0
;
}
/*
...
...
@@ -99,13 +116,14 @@ void dput(struct dentry *dentry)
* possible. If there are other users of the dentry we
* can't invalidate it.
*
* This is currently incorrect. We should try to see if
* we can invalidate any unused children - right now we
* refuse to invalidate way too much.
* 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
should
do a partial shrink_dcache here */
/* We
might want to
do a partial shrink_dcache here */
if
(
dentry
->
d_count
!=
1
)
return
-
EBUSY
;
...
...
@@ -113,6 +131,27 @@ int d_invalidate(struct dentry * dentry)
return
0
;
}
/*
* Throw away a dentry - free the inode, dput the parent.
* This requires that the LRU list has already been
* removed.
*/
static
inline
void
prune_one_dentry
(
struct
dentry
*
dentry
)
{
struct
dentry
*
parent
;
list_del
(
&
dentry
->
d_hash
);
if
(
dentry
->
d_inode
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
dentry
->
d_inode
=
NULL
;
iput
(
inode
);
}
parent
=
dentry
->
d_parent
;
d_free
(
dentry
);
dput
(
parent
);
}
/*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
...
...
@@ -131,24 +170,65 @@ void prune_dcache(int count)
INIT_LIST_HEAD
(
tmp
);
dentry
=
list_entry
(
tmp
,
struct
dentry
,
d_lru
);
if
(
!
dentry
->
d_count
)
{
struct
dentry
*
parent
;
list_del
(
&
dentry
->
d_hash
);
if
(
dentry
->
d_inode
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
dentry
->
d_inode
=
NULL
;
iput
(
inode
);
}
parent
=
dentry
->
d_parent
;
d_free
(
dentry
);
dput
(
parent
);
prune_one_dentry
(
dentry
);
if
(
!--
count
)
break
;
}
}
}
/*
* Shrink the dcache for the specified super block.
* This allows us to unmount a device without disturbing
* the dcache for the other devices.
*
* This implementation makes just two traversals of the
* unused list. On the first pass we move the selected
* dentries to the most recent end, and on the second
* pass we free them. The second pass must restart after
* each dput(), but since the target dentries are all at
* the end, it's really just a single traversal.
*/
void
shrink_dcache_sb
(
struct
super_block
*
sb
)
{
struct
list_head
*
tmp
,
*
next
;
struct
dentry
*
dentry
;
/*
* Pass one ... move the dentries for the specified
* superblock to the most recent end of the unused list.
*/
next
=
dentry_unused
.
next
;
while
(
next
!=
&
dentry_unused
)
{
tmp
=
next
;
next
=
tmp
->
next
;
dentry
=
list_entry
(
tmp
,
struct
dentry
,
d_lru
);
if
(
dentry
->
d_sb
!=
sb
)
continue
;
list_del
(
tmp
);
list_add
(
tmp
,
&
dentry_unused
);
}
/*
* Pass two ... free the dentries for this superblock.
*/
repeat:
next
=
dentry_unused
.
next
;
while
(
next
!=
&
dentry_unused
)
{
tmp
=
next
;
next
=
tmp
->
next
;
dentry
=
list_entry
(
tmp
,
struct
dentry
,
d_lru
);
if
(
dentry
->
d_sb
!=
sb
)
continue
;
if
(
dentry
->
d_count
)
continue
;
list_del
(
tmp
);
INIT_LIST_HEAD
(
tmp
);
prune_one_dentry
(
dentry
);
goto
repeat
;
}
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
struct
dentry
*
d_alloc
(
struct
dentry
*
parent
,
const
struct
qstr
*
name
)
...
...
fs/file_table.c
View file @
f59dfe26
...
...
@@ -18,8 +18,9 @@
static
kmem_cache_t
*
filp_cache
;
/* sysctl tunables... */
int
nr_files
=
0
;
int
max_files
=
NR_FILE
;
int
nr_files
=
0
;
/* read only */
int
nr_free_files
=
0
;
/* read only */
int
max_files
=
NR_FILE
;
/* tunable */
/* Free list management, if you are here you must have f_count == 0 */
static
struct
file
*
free_filps
=
NULL
;
...
...
@@ -30,6 +31,7 @@ void insert_file_free(struct file *file)
free_filps
->
f_pprev
=
&
file
->
f_next
;
free_filps
=
file
;
file
->
f_pprev
=
&
free_filps
;
nr_free_files
++
;
}
/* The list of in-use filp's must be exported (ugh...) */
...
...
@@ -43,6 +45,7 @@ static inline void put_inuse(struct file *file)
file
->
f_pprev
=
&
inuse_filps
;
}
/* N.B. This should be an __initfunc ... */
void
file_table_init
(
void
)
{
filp_cache
=
kmem_cache_create
(
"filp"
,
sizeof
(
struct
file
),
...
...
@@ -50,6 +53,11 @@ void file_table_init(void)
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
if
(
!
filp_cache
)
panic
(
"VFS: Cannot alloc filp SLAB cache."
);
/*
* We could allocate the reserved files here, but really
* shouldn't need to: the normal boot process will create
* plenty of free files.
*/
}
/* Find an unused file structure and return a pointer to it.
...
...
@@ -61,24 +69,31 @@ struct file * get_empty_filp(void)
static
int
old_max
=
0
;
struct
file
*
f
;
f
=
free_filps
;
if
(
!
f
)
goto
get_more
;
remove_filp
(
f
);
got_one:
memset
(
f
,
0
,
sizeof
(
*
f
));
f
->
f_count
=
1
;
f
->
f_version
=
++
event
;
put_inuse
(
f
);
return
f
;
get_more:
/* Reserve a few files for the super-user.. */
if
(
nr_files
<
(
current
->
euid
?
max_files
-
10
:
max_files
))
{
if
(
nr_free_files
>
NR_RESERVED_FILES
)
{
used_one:
f
=
free_filps
;
remove_filp
(
f
);
nr_free_files
--
;
new_one:
memset
(
f
,
0
,
sizeof
(
*
f
));
f
->
f_count
=
1
;
f
->
f_version
=
++
event
;
put_inuse
(
f
);
return
f
;
}
/*
* Use a reserved one if we're the superuser
*/
if
(
nr_free_files
&&
!
current
->
euid
)
goto
used_one
;
/*
* Allocate a new one if we're below the limit.
*/
if
(
nr_files
<
max_files
)
{
f
=
kmem_cache_alloc
(
filp_cache
,
SLAB_KERNEL
);
if
(
f
)
{
nr_files
++
;
goto
got
_one
;
goto
new
_one
;
}
/* Big problems... */
printk
(
"VFS: filp allocation failed
\n
"
);
...
...
fs/lockd/clntproc.c
View file @
f59dfe26
...
...
@@ -160,8 +160,9 @@ static inline int
nlmclnt_grace_wait
(
struct
nlm_host
*
host
)
{
if
(
!
host
->
h_reclaiming
)
current
->
timeout
=
10
*
HZ
;
current
->
timeout
=
jiffies
+
10
*
HZ
;
interruptible_sleep_on
(
&
host
->
h_gracewait
);
current
->
timeout
=
0
;
return
signalled
()
?
-
ERESTARTSYS
:
0
;
}
...
...
@@ -178,9 +179,11 @@ nlmclnt_alloc_call(void)
sizeof
(
struct
nlm_rqst
));
if
(
call
)
return
call
;
current
->
timeout
=
5
*
HZ
;
printk
(
"nlmclnt_alloc_call: failed, waiting for memory
\n
"
);
current
->
timeout
=
jiffies
+
5
*
HZ
;
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
current
->
timeout
=
0
;
}
return
NULL
;
}
...
...
@@ -232,6 +235,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* Back off a little and try again */
current
->
timeout
=
jiffies
+
15
*
HZ
;
interruptible_sleep_on
(
&
host
->
h_gracewait
);
current
->
timeout
=
0
;
}
while
(
!
signalled
());
return
-
ERESTARTSYS
;
...
...
fs/lockd/svc.c
View file @
f59dfe26
...
...
@@ -42,11 +42,15 @@
extern
struct
svc_program
nlmsvc_program
;
struct
nlmsvc_binding
*
nlmsvc_ops
=
NULL
;
static
int
nlmsvc_sema
=
0
;
static
int
nlmsvc_pid
=
0
;
static
struct
semaphore
nlmsvc_sema
=
MUTEX
;
static
unsigned
int
nlmsvc_users
=
0
;
static
pid_t
nlmsvc_pid
=
0
;
unsigned
long
nlmsvc_grace_period
=
0
;
unsigned
long
nlmsvc_timeout
=
0
;
static
struct
wait_queue
*
lockd_start
=
NULL
;
static
struct
wait_queue
*
lockd_exit
=
NULL
;
/*
* Currently the following can be set only at insmod time.
* Ideally, they would be accessible through the sysctl interface.
...
...
@@ -64,10 +68,16 @@ lockd(struct svc_rqst *rqstp)
sigset_t
oldsigmask
;
int
err
=
0
;
lock_kernel
();
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT
;
/* exit_files(current); */
lock_kernel
();
/*
* Let our maker know we're running.
*/
nlmsvc_pid
=
current
->
pid
;
wake_up
(
&
lockd_start
);
exit_mm
(
current
);
current
->
session
=
1
;
current
->
pgrp
=
1
;
...
...
@@ -76,6 +86,12 @@ lockd(struct svc_rqst *rqstp)
/* kick rpciod */
rpciod_up
();
/*
* N.B. current do_fork() doesn't like NULL task->files,
* so we defer closing files until forking rpciod.
*/
exit_files
(
current
);
dprintk
(
"NFS locking service started (ver "
LOCKD_VERSION
").
\n
"
);
if
(
!
nlm_timeout
)
...
...
@@ -94,14 +110,14 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_grace_period
+=
jiffies
;
nlmsvc_timeout
=
nlm_timeout
*
HZ
;
nlmsvc_pid
=
current
->
pid
;
/*
* The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away, and we've been sent a
* signal.
* signal
, or else another process has taken over our job
.
*/
while
(
nlmsvc_sema
||
!
signalled
())
{
while
((
nlmsvc_users
||
!
signalled
())
&&
nlmsvc_pid
==
current
->
pid
)
{
if
(
signalled
())
current
->
signal
=
0
;
...
...
@@ -156,8 +172,17 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_ops
->
exp_unlock
();
}
nlm_shutdown_hosts
();
/*
* Check whether there's a new lockd process before
* shutting down the hosts and clearing the slot.
*/
if
(
!
nlmsvc_pid
||
current
->
pid
==
nlmsvc_pid
)
{
nlm_shutdown_hosts
();
nlmsvc_pid
=
0
;
}
else
printk
(
"lockd: new process, skipping host shutdown
\n
"
);
wake_up
(
&
lockd_exit
);
/* Exit the RPC thread */
svc_exit_thread
(
rqstp
);
...
...
@@ -166,7 +191,6 @@ lockd(struct svc_rqst *rqstp)
/* Release module */
MOD_DEC_USE_COUNT
;
nlmsvc_pid
=
0
;
}
/*
...
...
@@ -185,42 +209,100 @@ lockd_makesock(struct svc_serv *serv, int protocol, unsigned short port)
return
svc_create_socket
(
serv
,
protocol
,
&
sin
);
}
/*
* Bring up the lockd process if it's not already up.
*/
int
lockd_up
(
void
)
{
struct
svc_serv
*
serv
;
int
error
;
int
error
=
0
;
if
(
nlmsvc_pid
||
nlmsvc_sema
++
)
return
0
;
down
(
&
nlmsvc_sema
);
/*
* Unconditionally increment the user count ... this is
* the number of clients who _want_ a lockd process.
*/
nlmsvc_users
++
;
/*
* Check whether we're already up and running.
*/
if
(
nlmsvc_pid
)
goto
out
;
dprintk
(
"lockd: creating service
\n
"
);
if
((
serv
=
svc_create
(
&
nlmsvc_program
,
0
,
NLMSVC_XDRSIZE
))
==
NULL
)
return
-
ENOMEM
;
/*
* Sanity check: if there's no pid,
* we should be the first user ...
*/
if
(
nlmsvc_users
>
1
)
printk
(
"lockd_up: no pid, %d users??
\n
"
,
nlmsvc_users
);
error
=
-
ENOMEM
;
serv
=
svc_create
(
&
nlmsvc_program
,
0
,
NLMSVC_XDRSIZE
);
if
(
!
serv
)
{
printk
(
"lockd_up: create service failed
\n
"
);
goto
out
;
}
if
((
error
=
lockd_makesock
(
serv
,
IPPROTO_UDP
,
0
))
<
0
if
((
error
=
lockd_makesock
(
serv
,
IPPROTO_UDP
,
0
))
<
0
||
(
error
=
lockd_makesock
(
serv
,
IPPROTO_TCP
,
0
))
<
0
)
{
svc_destroy
(
serv
);
return
error
;
printk
(
"lockd_up: makesock failed, error=%d
\n
"
,
error
);
goto
destroy_and_out
;
}
if
((
error
=
svc_create_thread
(
lockd
,
serv
))
<
0
)
nlmsvc_sema
--
;
/*
* Create the kernel thread and wait for it to start.
*/
error
=
svc_create_thread
(
lockd
,
serv
);
if
(
error
)
{
printk
(
"lockd_up: create thread failed, error=%d
\n
"
,
error
);
goto
destroy_and_out
;
}
sleep_on
(
&
lockd_start
);
/* Release server */
/*
* Note: svc_serv structures have an initial use count of 1,
* so we exit through here on both success and failure.
*/
destroy_and_out:
svc_destroy
(
serv
);
return
0
;
out:
up
(
&
nlmsvc_sema
);
return
error
;
}
/*
* Decrement the user count and bring down lockd if we're the last.
*/
void
lockd_down
(
void
)
{
if
(
!
nlmsvc_pid
||
--
nlmsvc_sema
>
0
)
return
;
down
(
&
nlmsvc_sema
);
if
(
nlmsvc_users
)
{
if
(
--
nlmsvc_users
)
goto
out
;
}
else
printk
(
"lockd_down: no users! pid=%d
\n
"
,
nlmsvc_pid
);
if
(
!
nlmsvc_pid
)
{
printk
(
"lockd_down: nothing to do!
\n
"
);
goto
out
;
}
kill_proc
(
nlmsvc_pid
,
SIGKILL
,
1
);
nlmsvc_sema
=
0
;
nlmsvc_pid
=
0
;
/*
* Wait for the lockd process to exit, but since we're holding
* the lockd semaphore, we can't wait around forever ...
*/
current
->
timeout
=
jiffies
+
5
*
HZ
;
interruptible_sleep_on
(
&
lockd_exit
);
current
->
timeout
=
0
;
if
(
nlmsvc_pid
)
{
printk
(
"lockd_down: lockd failed to exit, clearing pid
\n
"
);
nlmsvc_pid
=
0
;
}
out:
up
(
&
nlmsvc_sema
);
}
#ifdef MODULE
...
...
@@ -235,6 +317,11 @@ lockd_down(void)
int
init_module
(
void
)
{
/* Init the static variables */
nlmsvc_sema
=
MUTEX
;
nlmsvc_users
=
0
;
nlmsvc_pid
=
0
;
lockd_exit
=
NULL
;
nlmxdr_init
();
return
0
;
}
...
...
fs/locks.c
View file @
f59dfe26
...
...
@@ -881,9 +881,6 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if
(
caller
->
fl_type
!=
F_UNLCK
)
{
repeat:
error
=
-
ERESTARTSYS
;
if
(
signal_pending
(
current
))
goto
out
;
for
(
fl
=
inode
->
i_flock
;
fl
!=
NULL
;
fl
=
fl
->
fl_next
)
{
if
(
!
(
fl
->
fl_flags
&
FL_POSIX
))
continue
;
...
...
@@ -895,6 +892,9 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
error
=
-
EDEADLK
;
if
(
posix_locks_deadlock
(
caller
,
fl
))
goto
out
;
error
=
-
ERESTARTSYS
;
if
(
signal_pending
(
current
))
goto
out
;
locks_insert_block
(
fl
,
caller
);
interruptible_sleep_on
(
&
caller
->
fl_wait
);
locks_delete_block
(
fl
,
caller
);
...
...
fs/namei.c
View file @
f59dfe26
...
...
@@ -232,11 +232,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
result
=
d_lookup
(
parent
,
name
);
if
(
!
result
)
{
struct
dentry
*
dentry
=
d_alloc
(
parent
,
name
);
int
error
=
dir
->
i_op
->
lookup
(
dir
,
dentry
);
result
=
ERR_PTR
(
error
);
if
(
!
error
)
result
=
dget
(
dentry
->
d_mounts
);
dput
(
dentry
);
result
=
ERR_PTR
(
-
ENOMEM
);
if
(
dentry
)
{
int
error
=
dir
->
i_op
->
lookup
(
dir
,
dentry
);
result
=
ERR_PTR
(
error
);
if
(
!
error
)
result
=
dget
(
dentry
->
d_mounts
);
dput
(
dentry
);
}
}
up
(
&
dir
->
i_sem
);
return
result
;
...
...
@@ -1170,7 +1173,8 @@ static inline int do_rename(const char * oldname, const char * newname)
if
(
new_dir
->
d_inode
->
i_sb
&&
new_dir
->
d_inode
->
i_sb
->
dq_op
)
new_dir
->
d_inode
->
i_sb
->
dq_op
->
initialize
(
new_dir
->
d_inode
,
-
1
);
error
=
old_dir
->
d_inode
->
i_op
->
rename
(
old_dir
->
d_inode
,
old_dentry
,
new_dir
->
d_inode
,
new_dentry
);
error
=
old_dir
->
d_inode
->
i_op
->
rename
(
old_dir
->
d_inode
,
old_dentry
,
new_dir
->
d_inode
,
new_dentry
);
exit_lock:
double_unlock
(
new_dir
,
old_dir
);
...
...
fs/nfs/dir.c
View file @
f59dfe26
...
...
@@ -29,6 +29,11 @@
#include <asm/segment.h>
/* for fs functions */
/* needed by smbfs as well ... move to dcache? */
extern
void
nfs_renew_times
(
struct
dentry
*
);
extern
void
nfs_invalidate_dircache_sb
(
struct
super_block
*
);
#define NFS_PARANOIA 1
/*
* Head for a dircache entry. Currently still very simple; when
* the cache grows larger, we will need a LRU list.
...
...
@@ -36,14 +41,14 @@
struct
nfs_dirent
{
dev_t
dev
;
/* device number */
ino_t
ino
;
/* inode number */
u32
cookie
;
/* cooke of first entry */
u32
cookie
;
/* cook
i
e of first entry */
unsigned
short
valid
:
1
,
/* data is valid */
locked
:
1
;
/* entry locked */
unsigned
int
size
;
/* # of entries */
unsigned
long
age
;
/* last used */
unsigned
long
mtime
;
/* last attr stamp */
struct
wait_queue
*
wait
;
struct
nfs_entry
*
entry
;
__u32
*
entry
;
/* three __u32's per entry */
};
static
int
nfs_dir_open
(
struct
inode
*
inode
,
struct
file
*
file
);
...
...
@@ -123,15 +128,16 @@ static struct nfs_dirent dircache[NFS_MAX_DIRCACHE];
static
int
nfs_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
)
{
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
static
struct
wait_queue
*
readdir_wait
=
NULL
;
struct
wait_queue
**
waitp
=
NULL
;
struct
nfs_dirent
*
cache
,
*
free
;
struct
nfs_entry
*
entry
;
unsigned
long
age
,
dead
;
u32
cookie
;
int
ismydir
,
result
;
int
i
,
j
,
index
=
0
;
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
__u32
*
entry
;
char
*
name
,
*
start
;
dfprintk
(
VFS
,
"NFS: nfs_readdir(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
if
(
!
inode
||
!
S_ISDIR
(
inode
->
i_mode
))
{
...
...
@@ -194,17 +200,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break
;
}
for
(
j
=
0
;
j
<
cache
->
size
;
j
++
)
{
/*
dprintk("NFS: examing entry %.*s @%d\n",
(int) cache->entry[j].length,
cache->entry[j].name,
cache->entry[j].cookie);
*/
if
(
cache
->
entry
[
j
].
cookie
!=
cookie
)
__u32
*
this_ent
=
cache
->
entry
+
j
*
3
;
if
(
*
(
this_ent
+
1
)
!=
cookie
)
continue
;
if
(
j
<
cache
->
size
-
1
)
{
entry
=
cache
->
entry
+
(
index
=
j
+
1
);
}
else
if
(
cache
->
entry
[
j
].
eof
)
{
index
=
j
+
1
;
entry
=
this_ent
+
3
;
}
else
if
(
*
(
this_ent
+
2
)
>>
16
)
{
/* eof */
return
0
;
}
break
;
...
...
@@ -235,12 +239,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
cache
->
dev
=
inode
->
i_dev
;
cache
->
ino
=
inode
->
i_ino
;
if
(
!
cache
->
entry
)
{
cache
->
entry
=
(
struct
nfs_entry
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
cache
->
entry
)
{
result
=
-
ENOMEM
;
result
=
-
ENOMEM
;
cache
->
entry
=
(
__u32
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
cache
->
entry
)
goto
done
;
}
}
result
=
nfs_proc_readdir
(
NFS_SERVER
(
inode
),
NFS_FH
(
inode
),
...
...
@@ -257,25 +259,29 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/*
* Yowza! We have a cache entry...
*/
start
=
(
char
*
)
cache
->
entry
;
while
(
index
<
cache
->
size
)
{
int
nextpos
=
entry
->
cookie
;
__u32
fileid
=
*
entry
++
;
__u32
nextpos
=
*
entry
++
;
/* cookie */
__u32
length
=
*
entry
++
;
/*
* Unpack the eof flag, offset, and length
*/
result
=
length
&
(
1
<<
15
);
/* eof flag */
name
=
start
+
((
length
>>
16
)
&
0xFFFF
);
length
&=
0x7FFF
;
/*
dprintk("NFS: filldir(%p, %.*s, %d, %d, %x, eof %x)\n", entry,
(int)
entry->length, entry->name, entry->
length,
(int)
length, name,
length,
(unsigned int) filp->f_pos,
entry->fileid, entry->eof
);
fileid, result
);
*/
if
(
filldir
(
dirent
,
entry
->
name
,
entry
->
length
,
cookie
,
entry
->
fileid
)
<
0
)
if
(
filldir
(
dirent
,
name
,
length
,
cookie
,
fileid
)
<
0
)
break
;
cookie
=
nextpos
;
if
(
nextpos
!=
entry
->
cookie
)
{
printk
(
"nfs_readdir: shouldn't happen!
\n
"
);
break
;
}
index
++
;
entry
++
;
}
filp
->
f_pos
=
cookie
;
result
=
0
;
...
...
@@ -293,44 +299,73 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
/*
* Invalidate dircache entries for
inode
* Invalidate dircache entries for
an inode.
*/
void
nfs_invalidate_dircache
(
struct
inode
*
inode
)
{
struct
nfs_dirent
*
cache
;
struct
nfs_dirent
*
cache
=
dircache
;
dev_t
dev
=
inode
->
i_dev
;
ino_t
ino
=
inode
->
i_ino
;
int
i
;
dfprintk
(
DIRCACHE
,
"NFS: invalidate dircache for %x/%ld
\n
"
,
dev
,
(
long
)
ino
);
for
(
i
=
0
,
cache
=
dircache
;
i
<
NFS_MAX_DIRCACHE
;
i
++
,
cache
++
)
{
if
(
!
cache
->
locked
&&
cache
->
dev
==
dev
&&
cache
->
ino
==
ino
)
cache
->
valid
=
0
;
/* brute force */
for
(
i
=
NFS_MAX_DIRCACHE
;
i
--
;
cache
++
)
{
if
(
cache
->
ino
!=
ino
)
continue
;
if
(
cache
->
dev
!=
dev
)
continue
;
if
(
cache
->
locked
)
{
printk
(
"NFS: cache locked for %s/%ld
\n
"
,
kdevname
(
dev
),
ino
);
continue
;
}
cache
->
valid
=
0
;
/* brute force */
}
}
/*
*
Free directory cache memory
*
Called from cleanup_module
*
Invalidate the dircache for a super block (or all caches),
*
and release the cache memory.
*/
void
nfs_
free_dircache
(
void
)
nfs_
invalidate_dircache_sb
(
struct
super_block
*
sb
)
{
struct
nfs_dirent
*
cache
;
struct
nfs_dirent
*
cache
=
dircache
;
int
i
;
int
freed
=
0
;
dfprintk
(
DIRCACHE
,
"NFS: freeing dircache
\n
"
);
for
(
i
=
0
,
cache
=
dircache
;
i
<
NFS_MAX_DIRCACHE
;
i
++
,
cache
++
)
{
cache
->
valid
=
0
;
for
(
i
=
NFS_MAX_DIRCACHE
;
i
--
;
cache
++
)
{
if
(
sb
&&
sb
->
s_dev
!=
cache
->
dev
)
continue
;
if
(
cache
->
locked
)
{
printk
(
"nfs_kfree_cache: locked entry in dircache!
\n
"
);
printk
(
"NFS: cache locked at umount %s
\n
"
,
(
cache
->
entry
?
"(lost a page!)"
:
""
));
continue
;
}
if
(
cache
->
entry
)
cache
->
valid
=
0
;
/* brute force */
if
(
cache
->
entry
)
{
free_page
((
unsigned
long
)
cache
->
entry
);
cache
->
entry
=
NULL
;
cache
->
entry
=
NULL
;
freed
++
;
}
}
#ifdef NFS_PARANOIA
if
(
freed
)
printk
(
"nfs_invalidate_dircache_sb: freed %d pages from %s
\n
"
,
freed
,
kdevname
(
sb
->
s_dev
));
#endif
}
/*
* Free directory cache memory
* Called from cleanup_module
*/
void
nfs_free_dircache
(
void
)
{
dfprintk
(
DIRCACHE
,
"NFS: freeing dircache
\n
"
);
nfs_invalidate_dircache_sb
(
NULL
);
}
/*
...
...
@@ -350,20 +385,46 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
unsigned
long
time
=
jiffies
-
dentry
->
d_time
;
unsigned
long
max
=
5
*
HZ
;
if
(
dentry
->
d_inode
&&
S_ISDIR
(
dentry
->
d_inode
->
i_mode
))
max
=
10
*
HZ
;
return
time
<
max
;
if
(
dentry
->
d_inode
)
{
if
(
is_bad_inode
(
dentry
->
d_inode
))
{
#ifdef NFS_PARANOIA
printk
(
"nfs_lookup_validate: %s/%s has dud inode
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
goto
bad
;
}
if
(
S_ISDIR
(
dentry
->
d_inode
->
i_mode
))
max
=
10
*
HZ
;
}
return
(
time
<
max
)
||
IS_ROOT
(
dentry
);
bad:
return
0
;
}
static
void
nfs_silly_delete
(
struct
dentry
*
);
static
struct
dentry_operations
nfs_dentry_operations
=
{
nfs_lookup_revalidate
,
nfs_lookup_revalidate
,
/* d_validate(struct dentry *) */
0
,
/* d_hash */
0
,
/* d_compare */
nfs_silly_delete
,
nfs_silly_delete
,
/* d_delete(struct dentry *) */
};
/*
* Whenever a lookup succeeds, we know the parent directories
* are all valid, so we want to update the dentry timestamps.
*/
void
nfs_renew_times
(
struct
dentry
*
dentry
)
{
for
(;;)
{
dentry
->
d_time
=
jiffies
;
if
(
dentry
==
dentry
->
d_parent
)
break
;
dentry
=
dentry
->
d_parent
;
}
}
static
int
nfs_lookup
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
struct
inode
*
inode
;
...
...
@@ -383,20 +444,42 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
if
(
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
error
=
nfs_proc_lookup
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
&
fhandle
,
&
fattr
);
error
=
nfs_proc_lookup
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
&
fhandle
,
&
fattr
);
inode
=
NULL
;
if
(
error
==
-
ENOENT
)
goto
no_entry
;
if
(
!
error
)
{
error
=
-
EACCES
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
&
fhandle
,
&
fattr
);
if
(
!
inode
)
return
-
EACCES
;
}
else
if
(
error
!=
-
ENOENT
)
return
error
;
dentry
->
d_time
=
jiffies
;
dentry
->
d_op
=
&
nfs_dentry_operations
;
d_add
(
dentry
,
inode
);
return
0
;
if
(
inode
)
{
no_entry:
dentry
->
d_op
=
&
nfs_dentry_operations
;
d_add
(
dentry
,
inode
);
nfs_renew_times
(
dentry
);
error
=
0
;
}
}
return
error
;
}
/*
* Code common to create, mkdir, and mknod.
*/
static
int
nfs_instantiate
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
struct
nfs_fattr
*
fattr
,
struct
nfs_fh
*
fhandle
)
{
struct
inode
*
inode
;
int
error
=
-
EACCES
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
fhandle
,
fattr
);
if
(
inode
)
{
nfs_invalidate_dircache
(
dir
);
d_instantiate
(
dentry
,
inode
);
nfs_renew_times
(
dentry
);
error
=
0
;
}
return
error
;
}
static
int
nfs_create
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
int
mode
)
...
...
@@ -404,7 +487,6 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
struct
nfs_sattr
sattr
;
struct
nfs_fattr
fattr
;
struct
nfs_fh
fhandle
;
struct
inode
*
inode
;
int
error
;
dfprintk
(
VFS
,
"NFS: create(%x/%ld, %s
\n
"
,
...
...
@@ -422,18 +504,10 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
sattr
.
uid
=
sattr
.
gid
=
sattr
.
size
=
(
unsigned
)
-
1
;
sattr
.
atime
.
seconds
=
sattr
.
mtime
.
seconds
=
(
unsigned
)
-
1
;
error
=
nfs_proc_create
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
error
)
return
error
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
&
fhandle
,
&
fattr
);
if
(
!
inode
)
return
-
EACCES
;
nfs_invalidate_dircache
(
dir
);
d_instantiate
(
dentry
,
inode
);
return
0
;
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
!
error
)
error
=
nfs_instantiate
(
dir
,
dentry
,
&
fattr
,
&
fhandle
);
return
error
;
}
static
int
nfs_mknod
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
int
mode
,
int
rdev
)
...
...
@@ -441,7 +515,6 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
struct
nfs_sattr
sattr
;
struct
nfs_fattr
fattr
;
struct
nfs_fh
fhandle
;
struct
inode
*
inode
;
int
error
;
dfprintk
(
VFS
,
"NFS: mknod(%x/%ld, %s
\n
"
,
...
...
@@ -462,18 +535,10 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
sattr
.
atime
.
seconds
=
sattr
.
mtime
.
seconds
=
(
unsigned
)
-
1
;
error
=
nfs_proc_create
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
error
)
return
error
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
&
fhandle
,
&
fattr
);
if
(
!
inode
)
return
-
EACCES
;
nfs_invalidate_dircache
(
dir
);
d_instantiate
(
dentry
,
inode
);
return
0
;
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
!
error
)
error
=
nfs_instantiate
(
dir
,
dentry
,
&
fattr
,
&
fhandle
);
return
error
;
}
static
int
nfs_mkdir
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
int
mode
)
...
...
@@ -481,7 +546,6 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct
nfs_sattr
sattr
;
struct
nfs_fattr
fattr
;
struct
nfs_fh
fhandle
;
struct
inode
*
inode
;
int
error
;
dfprintk
(
VFS
,
"NFS: mkdir(%x/%ld, %s
\n
"
,
...
...
@@ -500,20 +564,16 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
sattr
.
atime
.
seconds
=
sattr
.
mtime
.
seconds
=
(
unsigned
)
-
1
;
error
=
nfs_proc_mkdir
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
error
)
return
error
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
&
fhandle
,
&
fattr
);
if
(
!
inode
)
return
-
EACCES
;
nfs_invalidate_dircache
(
dir
);
d_instantiate
(
dentry
,
inode
);
return
0
;
dentry
->
d_name
.
name
,
&
sattr
,
&
fhandle
,
&
fattr
);
if
(
!
error
)
error
=
nfs_instantiate
(
dir
,
dentry
,
&
fattr
,
&
fhandle
);
return
error
;
}
/*
* Update inode->i_nlink immediately after a successful operation.
* (See comments for nfs_unlink.)
*/
static
int
nfs_rmdir
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
int
error
;
...
...
@@ -530,12 +590,14 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return
-
ENAMETOOLONG
;
error
=
nfs_proc_rmdir
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
error
)
return
error
;
nfs_invalidate_dircache
(
dir
);
d_delete
(
dentry
);
return
0
;
if
(
!
error
)
{
if
(
dentry
->
d_inode
->
i_nlink
)
dentry
->
d_inode
->
i_nlink
--
;
nfs_invalidate_dircache
(
dir
);
nfs_renew_times
(
dentry
);
d_delete
(
dentry
);
}
return
error
;
}
...
...
@@ -642,16 +704,15 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
error
=
nfs_proc_rename
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
NFS_FH
(
dir
),
silly
);
if
(
error
)
{
dput
(
sdentry
);
return
error
;
if
(
!
error
)
{
nfs_invalidate_dircache
(
dir
);
nfs_renew_times
(
dentry
);
d_move
(
dentry
,
sdentry
);
dentry
->
d_flags
|=
DCACHE_NFSFS_RENAMED
;
/* If we return 0 we don't unlink */
}
nfs_invalidate_dircache
(
dir
);
d_move
(
dentry
,
sdentry
);
dput
(
sdentry
);
dentry
->
d_flags
|=
DCACHE_NFSFS_RENAMED
;
return
0
;
/* don't unlink */
return
error
;
}
static
void
nfs_silly_delete
(
struct
dentry
*
dentry
)
...
...
@@ -670,8 +731,18 @@ static void nfs_silly_delete(struct dentry *dentry)
if
(
error
<
0
)
printk
(
"NFS "
__FUNCTION__
" failed (err = %d)
\n
"
,
-
error
);
dentry
->
d_inode
->
i_nlink
--
;
if
(
dentry
->
d_inode
)
{
if
(
dentry
->
d_inode
->
i_nlink
)
dentry
->
d_inode
->
i_nlink
--
;
}
else
printk
(
"nfs_silly_delete: negative dentry %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
nfs_invalidate_dircache
(
dir
);
/*
* The dentry is unhashed, but we want to make it negative.
*/
d_delete
(
dentry
);
}
}
...
...
@@ -680,8 +751,11 @@ static void nfs_silly_delete(struct dentry *dentry)
*
* If sillyrename() returns 0, we do nothing, otherwise we unlink.
*
* inode->i_nlink is updated here rather than waiting for the next
* nfs_refresh_inode() for cosmetic reasons only.
* Updating inode->i_nlink here rather than waiting for the next
* nfs_refresh_inode() is not merely cosmetic; once an object has
* been deleted, we want to get rid of the inode locally. The NFS
* server may reuse the fileid for a new inode, and we don't want
* that to be confused with this inode.
*/
static
int
nfs_unlink
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
...
...
@@ -700,20 +774,19 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
error
=
nfs_sillyrename
(
dir
,
dentry
);
if
(
error
==
-
EBUSY
)
{
return
-
EBUSY
;
}
else
if
(
error
<
0
)
{
if
(
error
&&
error
!=
-
EBUSY
)
{
error
=
nfs_proc_remove
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
error
<
0
)
return
error
;
dentry
->
d_inode
->
i_nlink
--
;
nfs_invalidate_dircache
(
dir
);
d_delete
(
dentry
);
if
(
!
error
)
{
if
(
dentry
->
d_inode
->
i_nlink
)
dentry
->
d_inode
->
i_nlink
--
;
nfs_invalidate_dircache
(
dir
);
nfs_renew_times
(
dentry
);
d_delete
(
dentry
);
}
}
return
0
;
return
error
;
}
static
int
nfs_symlink
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
const
char
*
symname
)
...
...
@@ -740,22 +813,21 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
sattr
.
atime
.
seconds
=
sattr
.
mtime
.
seconds
=
(
unsigned
)
-
1
;
error
=
nfs_proc_symlink
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
,
symname
,
&
sattr
);
if
(
error
)
return
error
;
nfs_invalidate_dircache
(
dir
);
/* this looks _funny_ doesn't it? But: nfs_proc_symlink()
* only fills in sattr, not fattr. Thus nfs_fhget() cannot be
* called, it would be pointless, without a valid fattr
* argument. Other possibility: call nfs_proc_lookup()
* HERE. But why? If somebody wants to reference this
* symlink, the cached_lookup() will fail, and
* nfs_proc_symlink() will be called anyway.
*/
d_drop
(
dentry
);
return
0
;
dentry
->
d_name
.
name
,
symname
,
&
sattr
);
if
(
!
error
)
{
nfs_invalidate_dircache
(
dir
);
nfs_renew_times
(
dentry
->
d_parent
);
/* this looks _funny_ doesn't it? But: nfs_proc_symlink()
* only fills in sattr, not fattr. Thus nfs_fhget() cannot be
* called, it would be pointless, without a valid fattr
* argument. Other possibility: call nfs_proc_lookup()
* HERE. But why? If somebody wants to reference this
* symlink, the cached_lookup() will fail, and
* nfs_proc_symlink() will be called anyway.
*/
d_drop
(
dentry
);
}
return
error
;
}
static
int
nfs_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
dentry
*
dentry
)
...
...
@@ -774,17 +846,16 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
if
(
dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
error
=
nfs_proc_link
(
NFS_SERVER
(
inode
),
NFS_FH
(
inode
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
error
)
return
error
;
nfs_invalidate_dircache
(
dir
);
inode
->
i_count
++
;
inode
->
i_nlink
++
;
/* no need to wait for nfs_refresh_inode() */
d_instantiate
(
dentry
,
inode
);
return
0
;
error
=
nfs_proc_link
(
NFS_SERVER
(
inode
),
NFS_FH
(
inode
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
!
error
)
{
nfs_invalidate_dircache
(
dir
);
inode
->
i_count
++
;
inode
->
i_nlink
++
;
/* no need to wait for nfs_refresh_inode() */
d_instantiate
(
dentry
,
inode
);
error
=
0
;
}
return
error
;
}
/*
...
...
@@ -843,15 +914,19 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
error
=
nfs_proc_rename
(
NFS_SERVER
(
old_dir
),
NFS_FH
(
old_dir
),
old_dentry
->
d_name
.
name
,
NFS_FH
(
new_dir
),
new_dentry
->
d_name
.
name
);
if
(
error
)
return
error
;
nfs_invalidate_dircache
(
old_dir
);
nfs_invalidate_dircache
(
new_dir
);
if
(
!
error
)
{
nfs_invalidate_dircache
(
old_dir
);
nfs_invalidate_dircache
(
new_dir
);
/*
* We know these paths are still valid ...
*/
nfs_renew_times
(
old_dentry
);
nfs_renew_times
(
new_dentry
->
d_parent
);
/* Update the dcache */
d_move
(
old_dentry
,
new_dentry
);
return
0
;
/* Update the dcache */
d_move
(
old_dentry
,
new_dentry
);
}
return
error
;
}
/*
...
...
@@ -860,23 +935,68 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* of the server's inode.
*/
void
nfs_refresh_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
int
nfs_refresh_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
{
int
was_empty
;
int
error
=
-
EIO
;
dfprintk
(
VFS
,
"NFS: refresh_inode(%x/%ld ct=%d)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
inode
->
i_count
);
if
(
!
inode
||
!
fattr
)
{
printk
(
"nfs_refresh_inode: inode or fattr is NULL
\n
"
);
return
;
goto
out
;
}
if
(
inode
->
i_ino
!=
fattr
->
fileid
)
{
printk
(
"nfs_refresh_inode: inode number mismatch
\n
"
);
return
;
goto
out
;
}
was_empty
=
(
inode
->
i_mode
==
0
);
inode
->
i_mode
=
fattr
->
mode
;
/*
* Check whether the mode has been set, as we only want to
* do this once. (We don't allow inodes to change types.)
*/
if
(
inode
->
i_mode
==
0
)
{
inode
->
i_mode
=
fattr
->
mode
;
if
(
S_ISREG
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_file_inode_operations
;
else
if
(
S_ISDIR
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_dir_inode_operations
;
else
if
(
S_ISLNK
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_symlink_inode_operations
;
else
if
(
S_ISCHR
(
inode
->
i_mode
))
{
inode
->
i_op
=
&
chrdev_inode_operations
;
inode
->
i_rdev
=
to_kdev_t
(
fattr
->
rdev
);
}
else
if
(
S_ISBLK
(
inode
->
i_mode
))
{
inode
->
i_op
=
&
blkdev_inode_operations
;
inode
->
i_rdev
=
to_kdev_t
(
fattr
->
rdev
);
}
else
if
(
S_ISFIFO
(
inode
->
i_mode
))
init_fifo
(
inode
);
else
inode
->
i_op
=
NULL
;
}
else
if
((
inode
->
i_mode
&
S_IFMT
)
==
(
fattr
->
mode
&
S_IFMT
))
{
inode
->
i_mode
=
fattr
->
mode
;
}
else
{
mode_t
old_mode
;
/*
* Big trouble! The inode has become a different object.
*/
#if 1
printk
(
"nfs_refresh_inode: mode changed, %07o to %07o
\n
"
,
inode
->
i_mode
,
fattr
->
mode
);
#endif
old_mode
=
inode
->
i_mode
;
/* save mode */
make_bad_inode
(
inode
);
inode
->
i_mode
=
old_mode
;
/* restore mode */
inode
->
i_nlink
=
0
;
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
* (But we do want to invalidate the caches.)
*/
invalidate_inode_pages
(
inode
);
nfs_invalidate_dircache
(
inode
);
goto
out
;
}
inode
->
i_nlink
=
fattr
->
nlink
;
inode
->
i_uid
=
fattr
->
uid
;
inode
->
i_gid
=
fattr
->
gid
;
...
...
@@ -893,29 +1013,13 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
NFS_ATTRTIMEO
(
inode
)
=
NFS_MINATTRTIMEO
(
inode
);
}
inode
->
i_size
=
fattr
->
size
;
if
(
S_ISCHR
(
inode
->
i_mode
)
||
S_ISBLK
(
inode
->
i_mode
))
inode
->
i_rdev
=
to_kdev_t
(
fattr
->
rdev
);
else
inode
->
i_rdev
=
0
;
inode
->
i_blocks
=
fattr
->
blocks
;
inode
->
i_atime
=
fattr
->
atime
.
seconds
;
inode
->
i_mtime
=
fattr
->
mtime
.
seconds
;
inode
->
i_ctime
=
fattr
->
ctime
.
seconds
;
if
(
S_ISREG
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_file_inode_operations
;
else
if
(
S_ISDIR
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_dir_inode_operations
;
else
if
(
S_ISLNK
(
inode
->
i_mode
))
inode
->
i_op
=
&
nfs_symlink_inode_operations
;
else
if
(
S_ISCHR
(
inode
->
i_mode
))
inode
->
i_op
=
&
chrdev_inode_operations
;
else
if
(
S_ISBLK
(
inode
->
i_mode
))
inode
->
i_op
=
&
blkdev_inode_operations
;
else
if
(
S_ISFIFO
(
inode
->
i_mode
))
{
if
(
was_empty
)
init_fifo
(
inode
);
}
else
inode
->
i_op
=
NULL
;
error
=
0
;
out:
return
error
;
}
/*
...
...
fs/nfs/inode.c
View file @
f59dfe26
...
...
@@ -34,6 +34,8 @@
#define NFSDBG_FACILITY NFSDBG_VFS
extern
void
nfs_invalidate_dircache_sb
(
struct
super_block
*
);
static
int
nfs_notify_change
(
struct
inode
*
,
struct
iattr
*
);
static
void
nfs_put_inode
(
struct
inode
*
);
static
void
nfs_delete_inode
(
struct
inode
*
);
...
...
@@ -67,6 +69,7 @@ nfs_read_inode(struct inode * inode)
{
inode
->
i_blksize
=
inode
->
i_sb
->
s_blocksize
;
inode
->
i_mode
=
0
;
inode
->
i_rdev
=
0
;
inode
->
i_op
=
NULL
;
NFS_CACHEINV
(
inode
);
}
...
...
@@ -75,6 +78,11 @@ static void
nfs_put_inode
(
struct
inode
*
inode
)
{
dprintk
(
"NFS: put_inode(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
/*
* We want to get rid of unused inodes ...
*/
if
(
inode
->
i_count
==
1
)
inode
->
i_nlink
=
0
;
}
static
void
...
...
@@ -90,13 +98,21 @@ nfs_put_super(struct super_block *sb)
struct
nfs_server
*
server
=
&
sb
->
u
.
nfs_sb
.
s_server
;
struct
rpc_clnt
*
rpc
;
/*
* Lock the super block while we bring down the daemons.
*/
lock_super
(
sb
);
if
((
rpc
=
server
->
client
)
!=
NULL
)
rpc_shutdown_client
(
rpc
);
if
(
!
(
server
->
flags
&
NFS_MOUNT_NONLM
))
lockd_down
();
/* release rpc.lockd */
rpciod_down
();
/* release rpciod */
lock_super
(
sb
);
/*
* Invalidate the dircache for this superblock.
*/
nfs_invalidate_dircache_sb
(
sb
);
sb
->
s_dev
=
0
;
unlock_super
(
sb
);
MOD_DEC_USE_COUNT
;
...
...
@@ -147,14 +163,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
unsigned
int
authflavor
;
int
tcp
;
kdev_t
dev
=
sb
->
s_dev
;
struct
inode
*
root_inode
;
MOD_INC_USE_COUNT
;
if
(
!
data
)
{
printk
(
"nfs_read_super: missing data argument
\n
"
);
sb
->
s_dev
=
0
;
MOD_DEC_USE_COUNT
;
return
NULL
;
}
if
(
!
data
)
goto
out_miss_args
;
if
(
data
->
version
!=
NFS_MOUNT_VERSION
)
{
printk
(
"nfs warning: mount version %s than kernel
\n
"
,
data
->
version
<
NFS_MOUNT_VERSION
?
"older"
:
"newer"
);
...
...
@@ -164,13 +178,19 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
data
->
bsize
=
0
;
}
/* We now require that the mount process passes the remote address */
memcpy
(
&
srvaddr
,
&
data
->
addr
,
sizeof
(
srvaddr
));
if
(
srvaddr
.
sin_addr
.
s_addr
==
INADDR_ANY
)
goto
out_no_remote
;
lock_super
(
sb
);
server
=
&
sb
->
u
.
nfs_sb
.
s_server
;
sb
->
s_magic
=
NFS_SUPER_MAGIC
;
sb
->
s_dev
=
dev
;
sb
->
s_op
=
&
nfs_sops
;
sb
->
s_blocksize
=
nfs_block_size
(
data
->
bsize
,
&
sb
->
s_blocksize_bits
);
sb
->
u
.
nfs_sb
.
s_root
=
data
->
root
;
server
=
&
sb
->
u
.
nfs_sb
.
s_server
;
server
->
rsize
=
nfs_block_size
(
data
->
rsize
,
NULL
);
server
->
wsize
=
nfs_block_size
(
data
->
wsize
,
NULL
);
server
->
flags
=
data
->
flags
;
...
...
@@ -179,15 +199,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server
->
acdirmin
=
data
->
acdirmin
*
HZ
;
server
->
acdirmax
=
data
->
acdirmax
*
HZ
;
strcpy
(
server
->
hostname
,
data
->
hostname
);
sb
->
u
.
nfs_sb
.
s_root
=
data
->
root
;
/* We now require that the mount process passes the remote address */
memcpy
(
&
srvaddr
,
&
data
->
addr
,
sizeof
(
srvaddr
));
if
(
srvaddr
.
sin_addr
.
s_addr
==
INADDR_ANY
)
{
printk
(
"NFS: mount program didn't pass remote address!
\n
"
);
MOD_DEC_USE_COUNT
;
return
NULL
;
}
/* Which protocol do we use? */
tcp
=
(
data
->
flags
&
NFS_MOUNT_TCP
);
...
...
@@ -210,18 +221,13 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
/* Now create transport and client */
xprt
=
xprt_create_proto
(
tcp
?
IPPROTO_TCP
:
IPPROTO_UDP
,
&
srvaddr
,
&
timeparms
);
if
(
xprt
==
NULL
)
{
printk
(
"NFS: cannot create RPC transport.
\n
"
);
goto
failure
;
}
if
(
xprt
==
NULL
)
goto
out_no_xprt
;
clnt
=
rpc_create_client
(
xprt
,
server
->
hostname
,
&
nfs_program
,
NFS_VERSION
,
authflavor
);
if
(
clnt
==
NULL
)
{
printk
(
"NFS: cannot create RPC client.
\n
"
);
xprt_destroy
(
xprt
);
goto
failure
;
}
if
(
clnt
==
NULL
)
goto
out_no_client
;
clnt
->
cl_intr
=
(
data
->
flags
&
NFS_MOUNT_INTR
)
?
1
:
0
;
clnt
->
cl_softrtry
=
(
data
->
flags
&
NFS_MOUNT_SOFT
)
?
1
:
0
;
...
...
@@ -229,29 +235,67 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server
->
client
=
clnt
;
/* Fire up rpciod if not yet running */
#ifdef RPCIOD_RESULT
if
(
rpciod_up
())
goto
out_no_iod
;
#else
rpciod_up
();
#endif
/* Unlock super block and try to get root fh attributes */
/*
* Keep the super block locked while we try to get
* the root fh attributes.
*/
root_inode
=
nfs_fhget
(
sb
,
&
data
->
root
,
NULL
);
if
(
!
root_inode
)
goto
out_no_root
;
sb
->
s_root
=
d_alloc_root
(
root_inode
,
NULL
);
if
(
!
sb
->
s_root
)
goto
out_no_root
;
/* We're airborne */
unlock_super
(
sb
);
sb
->
s_root
=
d_alloc_root
(
nfs_fhget
(
sb
,
&
data
->
root
,
NULL
),
NULL
);
if
(
sb
->
s_root
!=
NULL
)
{
/* We're airborne */
if
(
!
(
server
->
flags
&
NFS_MOUNT_NONLM
))
lockd_up
();
return
sb
;
}
/* Check whether to start the lockd process */
if
(
!
(
server
->
flags
&
NFS_MOUNT_NONLM
))
lockd_up
();
return
sb
;
/* Yargs. It didn't work out. */
out_no_root:
printk
(
"nfs_read_super: get root inode failed
\n
"
);
rpc_shutdown_client
(
server
->
client
);
iput
(
root_inode
);
rpciod_down
();
#ifdef RPCIOD_RESULT
goto
out_shutdown
;
failure:
MOD_DEC_USE_COUNT
;
if
(
sb
->
s_lock
)
unlock_super
(
sb
);
out_no_iod:
printk
(
"nfs_read_super: couldn't start rpciod!
\n
"
);
out_shutdown:
#endif
rpc_shutdown_client
(
server
->
client
);
goto
out_unlock
;
out_no_client:
printk
(
"NFS: cannot create RPC client.
\n
"
);
xprt_destroy
(
xprt
);
goto
out_unlock
;
out_no_xprt:
printk
(
"NFS: cannot create RPC transport.
\n
"
);
out_unlock:
unlock_super
(
sb
);
goto
out_fail
;
out_no_remote:
printk
(
"NFS: mount program didn't pass remote address!
\n
"
);
goto
out_fail
;
out_miss_args:
printk
(
"nfs_read_super: missing data argument
\n
"
);
out_fail:
sb
->
s_dev
=
0
;
MOD_DEC_USE_COUNT
;
return
NULL
;
}
...
...
fs/nfs/nfs2xdr.c
View file @
f59dfe26
...
...
@@ -23,6 +23,7 @@
#include <linux/nfs_fs.h>
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
#define QUADLEN(len) (((len) + 3) >> 2)
static
int
nfs_stat_to_errno
(
int
stat
);
...
...
@@ -371,17 +372,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
* Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static
int
nfs_xdr_readdirres
(
struct
rpc_rqst
*
req
,
u32
*
p
,
struct
nfs_readdirres
*
res
)
{
struct
nfs_entry
*
entry
;
struct
iovec
*
iov
=
req
->
rq_rvec
;
int
status
,
nr
,
len
;
char
*
string
;
char
*
string
,
*
start
;
u32
*
end
;
__u32
fileid
,
cookie
,
*
entry
;
if
((
status
=
ntohl
(
*
p
++
)))
return
-
nfs_stat_to_errno
(
status
);
...
...
@@ -396,10 +398,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
end
=
(
u32
*
)
((
u8
*
)
p
+
iov
[
1
].
iov_len
);
/* Get start and end of dirent buffer */
entry
=
(
struct
nfs_entry
*
)
res
->
buffer
;
entry
=
(
__u32
*
)
res
->
buffer
;
start
=
(
char
*
)
res
->
buffer
;
string
=
(
char
*
)
res
->
buffer
+
res
->
bufsiz
;
for
(
nr
=
0
;
*
p
++
;
nr
++
,
entry
++
)
{
entry
->
fileid
=
ntohl
(
*
p
++
);
for
(
nr
=
0
;
*
p
++
;
nr
++
)
{
fileid
=
ntohl
(
*
p
++
);
len
=
ntohl
(
*
p
++
);
if
((
p
+
QUADLEN
(
len
)
+
3
)
>
end
)
{
...
...
@@ -413,27 +416,36 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return
-
errno_NFSERR_IO
;
}
string
-=
len
;
if
((
void
*
)
(
entry
+
1
)
>
(
void
*
)
string
)
{
/* This may actually happen because an nfs_entry
* will take up more space than the XDR data. On
* 32bit machines that's due to 8byte alignment,
* on 64bit machines that's because the char * takes
* up 2 longs.
*
* THIS IS BAD!
if
((
void
*
)
(
entry
+
3
)
>
(
void
*
)
string
)
{
/*
* This error is impossible as long as the temp
* buffer is no larger than the user buffer. The
* current packing algorithm uses the same amount
* of space in the user buffer as in the XDR data,
* so it's guaranteed to fit.
*/
printk
(
KERN_NOTICE
"NFS: should not happen
in %s!
\n
"
,
printk
(
"NFS: incorrect buffer size
in %s!
\n
"
,
__FUNCTION__
);
break
;
}
entry
->
name
=
string
;
entry
->
length
=
len
;
memmove
(
string
,
p
,
len
);
p
+=
QUADLEN
(
len
);
entry
->
cookie
=
ntohl
(
*
p
++
);
entry
->
eof
=
!
p
[
0
]
&&
p
[
1
];
cookie
=
ntohl
(
*
p
++
);
/*
* To make everything fit, we encode the length, offset,
* and eof flag into 32 bits. This works for filenames
* up to 32K and PAGE_SIZE up to 64K.
*/
status
=
!
p
[
0
]
&&
p
[
1
]
?
(
1
<<
15
)
:
0
;
/* eof flag */
*
entry
++
=
fileid
;
*
entry
++
=
cookie
;
*
entry
++
=
((
string
-
start
)
<<
16
)
|
status
|
(
len
&
0x7FFF
);
}
#ifdef NFS_PARANOIA
printk
(
"nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d
\n
"
,
nr
,
((
char
*
)
entry
-
start
),
(
start
+
res
->
bufsiz
-
string
));
#endif
return
nr
;
}
...
...
fs/nfs/nfs3xdr.c
View file @
f59dfe26
...
...
@@ -384,17 +384,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
* Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static
int
nfs_xdr_readdirres
(
struct
rpc_rqst
*
req
,
u32
*
p
,
struct
nfs_readdirres
*
res
)
{
struct
nfs_entry
*
entry
;
struct
iovec
*
iov
=
req
->
rq_rvec
;
int
status
,
nr
,
len
;
char
*
string
;
char
*
string
,
*
start
;
u32
*
end
;
__u32
fileid
,
cookie
,
*
entry
;
if
((
status
=
ntohl
(
*
p
++
)))
return
-
nfs_stat_to_errno
(
status
);
...
...
@@ -413,10 +414,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return
-
errno_NFSERR_IO
;
}
string
=
(
char
*
)
res
->
buffer
+
res
->
bufsiz
;
entry
=
(
struct
nfs_entry
*
)
res
->
buffer
;
for
(
nr
=
0
;
*
p
++
;
nr
++
,
entry
++
)
{
entry
->
fileid
=
ntohl
(
*
p
++
);
entry
=
(
__u32
*
)
res
->
buffer
;
start
=
(
char
*
)
res
->
buffer
;
string
=
start
+
res
->
bufsiz
;
for
(
nr
=
0
;
*
p
++
;
nr
++
)
{
fileid
=
ntohl
(
*
p
++
);
len
=
ntohl
(
*
p
++
);
if
((
p
+
QUADLEN
(
len
)
+
3
)
>
end
)
{
...
...
@@ -430,22 +432,40 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return
-
errno_NFSERR_IO
;
}
string
-=
len
;
if
((
void
*
)
(
entry
+
1
)
>
(
void
*
)
string
)
{
dprintk
(
"NFS: shouldnothappen in readdirres_decode!
\n
"
);
break
;
/* should not happen */
if
((
void
*
)
(
entry
+
3
)
>
(
void
*
)
string
)
{
/*
* This error is impossible as long as the temp
* buffer is no larger than the user buffer. The
* current packing algorithm uses the same amount
* of space in the user buffer as in the XDR data,
* so it's guaranteed to fit.
*/
printk
(
"NFS: incorrect buffer size in %s!
\n
"
,
__FUNCTION__
);
break
;
}
entry
->
name
=
string
;
entry
->
length
=
len
;
memmove
(
string
,
p
,
len
);
p
+=
QUADLEN
(
len
);
entry
->
cookie
=
ntohl
(
*
p
++
);
entry
->
eof
=
!
p
[
0
]
&&
p
[
1
];
cookie
=
ntohl
(
*
p
++
);
/*
* To make everything fit, we encode the length, offset,
* and eof flag into 32 bits. This works for filenames
* up to 32K and PAGE_SIZE up to 64K.
*/
status
=
!
p
[
0
]
&&
p
[
1
]
?
(
1
<<
15
)
:
0
;
/* eof flag */
*
entry
++
=
fileid
;
*
entry
++
=
cookie
;
*
entry
++
=
((
string
-
start
)
<<
16
)
|
status
|
(
len
&
0x7FFF
);
/*
dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
len, string,
entry->cookie, entry->eof
);
len, string,
cookie, status
);
*/
}
#ifdef NFS_PARANOIA
printk
(
"nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d
\n
"
,
nr
,
((
char
*
)
entry
-
start
),
(
start
+
res
->
bufsiz
-
string
));
#endif
return
nr
;
}
...
...
fs/nfs/proc.c
View file @
f59dfe26
...
...
@@ -250,25 +250,43 @@ nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
*/
int
nfs_proc_readdir
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
u32
cookie
,
unsigned
int
size
,
struct
nfs_entry
*
entry
)
u32
cookie
,
unsigned
int
size
,
__u32
*
entry
)
{
struct
nfs_readdirargs
arg
;
struct
nfs_readdirres
res
;
void
*
buffer
;
unsigned
int
buf_size
=
PAGE_SIZE
;
int
status
;
/* First get a temp buffer for the readdir reply */
while
(
!
(
buffer
=
(
void
*
)
get_free_page
(
GFP_USER
)))
{
need_resched
=
1
;
schedule
();
if
(
signalled
())
return
-
ERESTARTSYS
;
}
/* N.B. does this really need to be cleared? */
status
=
-
ENOMEM
;
buffer
=
(
void
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
buffer
)
goto
out
;
/*
* Calculate the effective size the buffer. To make sure
* that the returned data will fit into the user's buffer,
* we decrease the buffer size as necessary.
*
* Note: NFS returns three __u32 values for each entry,
* and we assume that the data is packed into the user
* buffer with the same efficiency.
*/
if
(
size
<
buf_size
)
buf_size
=
size
;
if
(
server
->
rsize
<
buf_size
)
buf_size
=
server
->
rsize
;
#if 0
printk("nfs_proc_readdir: user size=%d, rsize=%d, buf_size=%d\n",
size, server->rsize, buf_size);
#endif
arg
.
fh
=
fhandle
;
arg
.
cookie
=
cookie
;
arg
.
buffer
=
buffer
;
arg
.
bufsiz
=
server
->
rsize
<
PAGE_SIZE
?
server
->
rsize
:
PAGE_SIZE
;
arg
.
bufsiz
=
buf_size
;
res
.
buffer
=
entry
;
res
.
bufsiz
=
size
;
...
...
@@ -276,6 +294,7 @@ nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
status
=
rpc_call
(
server
->
client
,
NFSPROC_READDIR
,
&
arg
,
&
res
,
0
);
dprintk
(
"NFS reply readdir: %d
\n
"
,
status
);
free_page
((
unsigned
long
)
buffer
);
out:
return
status
;
}
...
...
fs/proc/array.c
View file @
f59dfe26
...
...
@@ -348,6 +348,12 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
if
(
!
p
||
!
p
->
mm
||
ptr
>=
TASK_SIZE
)
return
0
;
/* Check for NULL pgd .. shouldn't happen! */
if
(
!
p
->
mm
->
pgd
)
{
printk
(
"get_phys_addr: pid %d has NULL pgd!
\n
"
,
p
->
pid
);
return
0
;
}
page_dir
=
pgd_offset
(
p
->
mm
,
ptr
);
if
(
pgd_none
(
*
page_dir
))
return
0
;
...
...
@@ -917,24 +923,34 @@ static int get_statm(int pid, char * buffer)
#define MAPS_LINE_MAX MAPS_LINE_MAX8
static
long
read_maps
(
int
pid
,
struct
file
*
file
,
char
*
buf
,
unsigned
long
count
)
static
long
read_maps
(
int
pid
,
struct
file
*
file
,
char
*
buf
,
unsigned
long
count
)
{
struct
task_struct
*
p
=
find_task_by_pid
(
pid
);
char
*
destptr
;
struct
task_struct
*
p
;
struct
vm_area_struct
*
map
,
*
next
;
char
*
destptr
=
buf
,
*
buffer
;
loff_t
lineno
;
int
column
;
struct
vm_area_struct
*
map
;
int
i
;
char
*
buffer
;
int
column
,
i
,
volatile_task
;
long
retval
;
/*
* We might sleep getting the page, so get it first.
*/
retval
=
-
ENOMEM
;
buffer
=
(
char
*
)
__get_free_page
(
GFP_KERNEL
);
if
(
!
buffer
)
goto
out
;
retval
=
-
EINVAL
;
p
=
find_task_by_pid
(
pid
);
if
(
!
p
)
return
-
EINVAL
;
goto
freepage_out
;
if
(
!
p
->
mm
||
p
->
mm
==
&
init_mm
||
count
==
0
)
return
0
;
goto
getlen_out
;
buffer
=
(
char
*
)
__get_free_page
(
GFP_KERNEL
);
/* Check whether the mmaps could change if we sleep */
volatile_task
=
(
p
!=
current
||
p
->
mm
->
count
>
1
);
/* decode f_pos */
lineno
=
file
->
f_pos
>>
MAPS_LINE_SHIFT
;
...
...
@@ -944,9 +960,7 @@ static long read_maps (int pid, struct file * file,
for
(
map
=
p
->
mm
->
mmap
,
i
=
0
;
map
&&
(
i
<
lineno
);
map
=
map
->
vm_next
,
i
++
)
continue
;
destptr
=
buf
;
for
(
;
map
;
)
{
for
(
;
map
;
map
=
next
)
{
/* produce the next line */
char
*
line
;
char
str
[
5
],
*
cp
=
str
;
...
...
@@ -957,6 +971,10 @@ static long read_maps (int pid, struct file * file,
MAPS_LINE_MAX4
:
MAPS_LINE_MAX8
;
int
len
;
/*
* Get the next vma now (but it won't be used if we sleep).
*/
next
=
map
->
vm_next
;
flags
=
map
->
vm_flags
;
*
cp
++
=
flags
&
VM_READ
?
'r'
:
'-'
;
...
...
@@ -993,20 +1011,19 @@ static long read_maps (int pid, struct file * file,
if
(
column
>=
len
)
{
column
=
0
;
/* continue with next line at column 0 */
lineno
++
;
map
=
map
->
vm_next
;
continue
;
continue
;
/* we haven't slept */
}
i
=
len
-
column
;
if
(
i
>
count
)
i
=
count
;
copy_to_user
(
destptr
,
line
+
column
,
i
);
destptr
+=
i
;
count
-=
i
;
column
+=
i
;
copy_to_user
(
destptr
,
line
+
column
,
i
);
/* may have slept */
destptr
+=
i
;
count
-=
i
;
column
+=
i
;
if
(
column
>=
len
)
{
column
=
0
;
/* next time: next line at column 0 */
lineno
++
;
map
=
map
->
vm_next
;
}
/* done? */
...
...
@@ -1016,15 +1033,20 @@ static long read_maps (int pid, struct file * file,
/* By writing to user space, we might have slept.
* Stop the loop, to avoid a race condition.
*/
if
(
p
!=
current
)
if
(
volatile_task
)
break
;
}
/* encode f_pos */
file
->
f_pos
=
(
lineno
<<
MAPS_LINE_SHIFT
)
+
column
;
getlen_out:
retval
=
destptr
-
buf
;
freepage_out:
free_page
((
unsigned
long
)
buffer
);
return
destptr
-
buf
;
out:
return
retval
;
}
#ifdef CONFIG_MODULES
...
...
fs/proc/base.c
View file @
f59dfe26
...
...
@@ -50,13 +50,17 @@ static struct inode_operations proc_base_inode_operations = {
NULL
/* permission */
};
static
void
proc_pid_fill_inode
(
struct
inode
*
inode
)
/*
* The fill argument is non-zero when the inode is being filled ...
* we don't need to do anything when it's being deleted.
*/
static
void
proc_pid_fill_inode
(
struct
inode
*
inode
,
int
fill
)
{
struct
task_struct
*
p
;
int
pid
=
inode
->
i_ino
>>
16
;
int
ino
=
inode
->
i_ino
&
0xffff
;
if
((
p
=
find_task_by_pid
(
pid
))
!=
NULL
)
{
if
(
fill
&&
(
p
=
find_task_by_pid
(
pid
))
!=
NULL
)
{
if
(
p
->
dumpable
||
ino
==
PROC_PID_INO
)
{
inode
->
i_uid
=
p
->
euid
;
inode
->
i_gid
=
p
->
gid
;
...
...
fs/proc/generic.c
View file @
f59dfe26
...
...
@@ -16,11 +16,13 @@
#include <linux/stat.h>
#include <asm/bitops.h>
extern
struct
inode_operations
proc_dyna_dir_inode_operations
;
static
long
proc_file_read
(
struct
inode
*
inode
,
struct
file
*
file
,
char
*
buf
,
unsigned
long
nbytes
);
static
long
proc_file_write
(
struct
inode
*
inode
,
struct
file
*
file
,
const
char
*
buffer
,
unsigned
long
count
);
static
long
long
proc_file_lseek
(
struct
file
*
file
,
long
long
offset
,
int
orig
);
static
long
long
proc_file_lseek
(
struct
file
*
,
long
long
,
int
);
int
proc_match
(
int
len
,
const
char
*
name
,
struct
proc_dir_entry
*
de
)
{
...
...
@@ -44,17 +46,14 @@ static struct file_operations proc_file_operations = {
NULL
/* can't fsync */
};
/*
* proc files can do almost nothing..
*/
struct
inode_operations
proc_file_inode_operations
=
{
&
proc_file_operations
,
/* default proc file-ops */
NULL
,
/* create
*/
NULL
,
/* lookup
*/
NULL
,
/* link
*/
NULL
,
/* unlink
*/
NULL
,
/* symlink
*/
NULL
,
/* mkdir
*/
&
proc_file_operations
,
/* default proc file-ops */
NULL
,
/* create
*/
NULL
,
/* lookup
*/
NULL
,
/* link
*/
NULL
,
/* unlink
*/
NULL
,
/* symlink
*/
NULL
,
/* mkdir
*/
NULL
,
/* rmdir */
NULL
,
/* mknod */
NULL
,
/* rename */
...
...
@@ -240,57 +239,77 @@ static int xlate_proc_name(const char *name,
struct
proc_dir_entry
*
create_proc_entry
(
const
char
*
name
,
mode_t
mode
,
struct
proc_dir_entry
*
parent
)
{
struct
proc_dir_entry
*
ent
;
const
char
*
fn
;
if
(
parent
)
fn
=
name
;
else
{
if
(
xlate_proc_name
(
name
,
&
parent
,
&
fn
))
return
NULL
;
}
struct
proc_dir_entry
*
ent
=
NULL
;
const
char
*
fn
=
name
;
int
len
;
if
(
!
parent
&&
xlate_proc_name
(
name
,
&
parent
,
&
fn
)
!=
0
)
goto
out
;
len
=
strlen
(
fn
);
ent
=
kmalloc
(
sizeof
(
struct
proc_dir_entry
),
GFP_KERNEL
);
ent
=
kmalloc
(
sizeof
(
struct
proc_dir_entry
)
+
len
+
1
,
GFP_KERNEL
);
if
(
!
ent
)
return
NULL
;
goto
out
;
memset
(
ent
,
0
,
sizeof
(
struct
proc_dir_entry
));
memcpy
(((
char
*
)
ent
)
+
sizeof
(
*
ent
),
fn
,
len
+
1
);
ent
->
name
=
((
char
*
)
ent
)
+
sizeof
(
*
ent
);
ent
->
namelen
=
len
;
if
(
mode
==
S_IFDIR
)
if
(
mode
==
S_IFDIR
)
{
mode
|=
S_IRUGO
|
S_IXUGO
;
else
if
(
mode
==
0
)
mode
=
S_IFREG
|
S_IRUGO
;
ent
->
name
=
fn
;
ent
->
namelen
=
strlen
(
fn
);
ent
->
mode
=
mode
;
if
(
S_ISDIR
(
mode
))
ent
->
ops
=
&
proc_dyna_dir_inode_operations
;
ent
->
nlink
=
2
;
else
}
else
if
(
mode
==
0
)
{
mode
=
S_IFREG
|
S_IRUGO
;
ent
->
nlink
=
1
;
}
ent
->
mode
=
mode
;
proc_register
(
parent
,
ent
);
out:
return
ent
;
}
extern
void
free_proc_entry
(
struct
proc_dir_entry
*
);
void
free_proc_entry
(
struct
proc_dir_entry
*
de
)
{
kfree
(
de
);
}
/*
* Remove a /proc entry and free it if it's not currently in use.
* If it is in use, we set the 'deleted' flag.
*/
void
remove_proc_entry
(
const
char
*
name
,
struct
proc_dir_entry
*
parent
)
{
struct
proc_dir_entry
*
de
;
const
char
*
fn
;
const
char
*
fn
=
name
;
int
len
;
if
(
parent
)
fn
=
name
;
else
if
(
xlate_proc_name
(
name
,
&
parent
,
&
fn
))
return
;
if
(
!
parent
&&
xlate_proc_name
(
name
,
&
parent
,
&
fn
)
!=
0
)
goto
out
;
len
=
strlen
(
fn
);
for
(
de
=
parent
->
subdir
;
de
;
de
=
de
->
next
)
{
if
(
proc_match
(
len
,
fn
,
de
))
break
;
}
if
(
de
)
if
(
de
)
{
printk
(
"remove_proc_entry: parent nlink=%d, file nlink=%d
\n
"
,
parent
->
nlink
,
de
->
nlink
);
proc_unregister
(
parent
,
de
->
low_ino
);
kfree
(
de
);
de
->
nlink
=
0
;
de
->
deleted
=
1
;
if
(
!
de
->
count
)
free_proc_entry
(
de
);
else
{
printk
(
"remove_proc_entry: %s/%s busy, count=%d
\n
"
,
parent
->
name
,
de
->
name
,
de
->
count
);
}
}
out:
return
;
}
fs/proc/inode.c
View file @
f59dfe26
...
...
@@ -17,23 +17,66 @@
#include <asm/system.h>
#include <asm/uaccess.h>
extern
void
free_proc_entry
(
struct
proc_dir_entry
*
);
struct
proc_dir_entry
*
de_get
(
struct
proc_dir_entry
*
de
)
{
if
(
de
)
de
->
count
++
;
return
de
;
}
/*
* Decrements the use count and checks for deferred deletion.
*/
void
de_put
(
struct
proc_dir_entry
*
de
)
{
if
(
de
)
{
if
(
!
de
->
count
)
{
printk
(
"de_put: entry %s already free!
\n
"
,
de
->
name
);
return
;
}
if
(
!--
de
->
count
)
{
if
(
de
->
deleted
)
{
printk
(
"de_put: deferred delete of %s
\n
"
,
de
->
name
);
free_proc_entry
(
de
);
}
}
}
}
static
void
proc_put_inode
(
struct
inode
*
inode
)
{
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if
((
inode
->
i_ino
>=
PROC_OPENPROM_FIRST
)
&&
(
inode
->
i_ino
<
PROC_OPENPROM_FIRST
+
PROC_NOPENPROM
)
&&
proc_openprom_use
)
if
((
inode
->
i_ino
>=
PROC_OPENPROM_FIRST
)
&&
(
inode
->
i_ino
<
PROC_OPENPROM_FIRST
+
PROC_NOPENPROM
)
&&
proc_openprom_use
)
(
*
proc_openprom_use
)(
inode
,
0
);
#endif
/*
* Kill off unused inodes ... VFS will unhash and
* delete the inode if we set i_nlink to zero.
*/
if
(
inode
->
i_count
==
1
)
inode
->
i_nlink
=
0
;
}
/*
* D
oes this ever happen?
* D
ecrement the use count of the proc_dir_entry.
*/
static
void
proc_delete_inode
(
struct
inode
*
inode
)
{
printk
(
"proc_delete_inode()?
\n
"
);
inode
->
i_size
=
0
;
struct
proc_dir_entry
*
de
=
inode
->
u
.
generic_ip
;
if
(
de
)
{
/*
* Call the fill_inode hook to release module counts.
*/
if
(
de
->
fill_inode
)
de
->
fill_inode
(
inode
,
0
);
de_put
(
de
);
}
}
static
void
proc_put_super
(
struct
super_block
*
sb
)
...
...
@@ -47,7 +90,7 @@ static struct super_operations proc_sops = {
proc_read_inode
,
proc_write_inode
,
proc_put_inode
,
proc_delete_inode
,
proc_delete_inode
,
/* delete_inode(struct inode *) */
NULL
,
proc_put_super
,
NULL
,
...
...
@@ -85,9 +128,24 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return
1
;
}
struct
inode
*
proc_get_inode
(
struct
super_block
*
s
,
int
ino
,
struct
proc_dir_entry
*
de
)
struct
inode
*
proc_get_inode
(
struct
super_block
*
sb
,
int
ino
,
struct
proc_dir_entry
*
de
)
{
struct
inode
*
inode
=
iget
(
s
,
ino
);
struct
inode
*
inode
;
/*
* Increment the use count so the dir entry can't disappear.
*/
de_get
(
de
);
#if 1
/* shouldn't ever happen */
if
(
de
&&
de
->
deleted
)
printk
(
"proc_iget: using deleted entry %s, count=%d
\n
"
,
de
->
name
,
de
->
count
);
#endif
inode
=
iget
(
sb
,
ino
);
if
(
!
inode
)
goto
out_fail
;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if
((
inode
->
i_ino
>=
PROC_OPENPROM_FIRST
)
...
...
@@ -95,23 +153,29 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
&&
proc_openprom_use
)
(
*
proc_openprom_use
)(
inode
,
1
);
#endif
if
(
inode
&&
inode
->
i_sb
==
s
)
{
inode
->
u
.
generic_ip
=
(
void
*
)
de
;
if
(
de
)
{
if
(
de
->
mode
)
{
inode
->
i_mode
=
de
->
mode
;
inode
->
i_uid
=
de
->
uid
;
inode
->
i_gid
=
de
->
gid
;
}
if
(
de
->
size
)
inode
->
i_size
=
de
->
size
;
if
(
de
->
ops
)
inode
->
i_op
=
de
->
ops
;
if
(
de
->
nlink
)
inode
->
i_nlink
=
de
->
nlink
;
if
(
de
->
fill_inode
)
de
->
fill_inode
(
inode
);
/* N.B. How can this test ever fail?? */
if
(
inode
->
i_sb
!=
sb
)
printk
(
"proc_get_inode: inode fubar
\n
"
);
inode
->
u
.
generic_ip
=
(
void
*
)
de
;
if
(
de
)
{
if
(
de
->
mode
)
{
inode
->
i_mode
=
de
->
mode
;
inode
->
i_uid
=
de
->
uid
;
inode
->
i_gid
=
de
->
gid
;
}
if
(
de
->
size
)
inode
->
i_size
=
de
->
size
;
if
(
de
->
ops
)
inode
->
i_op
=
de
->
ops
;
if
(
de
->
nlink
)
inode
->
i_nlink
=
de
->
nlink
;
/*
* The fill_inode routine should use this call
* to increment module counts, if necessary.
*/
if
(
de
->
fill_inode
)
de
->
fill_inode
(
inode
,
1
);
}
/*
* Fixup the root inode's nlink value
...
...
@@ -126,26 +190,40 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
}
read_unlock
(
&
tasklist_lock
);
}
out:
return
inode
;
out_fail:
de_put
(
de
);
goto
out
;
}
struct
super_block
*
proc_read_super
(
struct
super_block
*
s
,
void
*
data
,
int
silent
)
{
struct
inode
*
root_inode
;
lock_super
(
s
);
s
->
s_blocksize
=
1024
;
s
->
s_blocksize_bits
=
10
;
s
->
s_magic
=
PROC_SUPER_MAGIC
;
s
->
s_op
=
&
proc_sops
;
root_inode
=
proc_get_inode
(
s
,
PROC_ROOT_INO
,
&
proc_root
);
if
(
!
root_inode
)
goto
out_no_root
;
s
->
s_root
=
d_alloc_root
(
root_inode
,
NULL
);
if
(
!
s
->
s_root
)
goto
out_no_root
;
parse_options
(
data
,
&
root_inode
->
i_uid
,
&
root_inode
->
i_gid
);
unlock_super
(
s
);
s
->
s_root
=
d_alloc_root
(
proc_get_inode
(
s
,
PROC_ROOT_INO
,
&
proc_root
),
NULL
);
if
(
!
s
->
s_root
)
{
s
->
s_dev
=
0
;
printk
(
"get root inode failed
\n
"
);
return
NULL
;
}
parse_options
(
data
,
&
s
->
s_root
->
d_inode
->
i_uid
,
&
s
->
s_root
->
d_inode
->
i_gid
);
return
s
;
out_no_root:
printk
(
"proc_read_super: get root inode failed
\n
"
);
iput
(
root_inode
);
s
->
s_dev
=
0
;
unlock_super
(
s
);
return
NULL
;
}
int
proc_statfs
(
struct
super_block
*
sb
,
struct
statfs
*
buf
,
int
bufsiz
)
...
...
fs/proc/root.c
View file @
f59dfe26
...
...
@@ -25,6 +25,7 @@
static
int
proc_root_readdir
(
struct
file
*
,
void
*
,
filldir_t
);
static
int
proc_root_lookup
(
struct
inode
*
,
struct
dentry
*
);
static
int
proc_unlink
(
struct
inode
*
,
struct
dentry
*
);
static
unsigned
char
proc_alloc_map
[
PROC_NDYNAMIC
/
8
]
=
{
0
};
...
...
@@ -72,6 +73,29 @@ struct inode_operations proc_dir_inode_operations = {
NULL
/* permission */
};
/*
* /proc dynamic directories now support unlinking
*/
struct
inode_operations
proc_dyna_dir_inode_operations
=
{
&
proc_dir_operations
,
/* default proc dir ops */
NULL
,
/* create */
proc_lookup
,
/* lookup */
NULL
,
/* link */
proc_unlink
,
/* unlink(struct inode *, struct dentry *) */
NULL
,
/* symlink */
NULL
,
/* mkdir */
NULL
,
/* rmdir */
NULL
,
/* mknod */
NULL
,
/* rename */
NULL
,
/* readlink */
NULL
,
/* follow_link */
NULL
,
/* readpage */
NULL
,
/* writepage */
NULL
,
/* bmap */
NULL
,
/* truncate */
NULL
/* permission */
};
/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
...
...
@@ -173,7 +197,8 @@ proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, fil
int
proc_openprom_regdev
(
struct
openpromfs_dev
*
d
)
{
if
(
proc_openpromdev_ino
==
PROC_OPENPROMD_FIRST
+
PROC_NOPENPROMD
)
return
-
1
;
if
(
proc_openpromdev_ino
==
PROC_OPENPROMD_FIRST
+
PROC_NOPENPROMD
)
return
-
1
;
d
->
next
=
proc_openprom_devices
;
d
->
inode
=
proc_openpromdev_ino
++
;
proc_openprom_devices
=
d
;
...
...
@@ -218,6 +243,7 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
(
inode
,
filp
,
dirent
,
filldir
);
return
-
EINVAL
;
}
#define OPENPROM_DEFREADDIR proc_openprom_defreaddir
static
int
proc_openprom_deflookup
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
...
...
@@ -229,17 +255,17 @@ proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
(
dir
,
dentry
);
return
-
ENOENT
;
}
#define OPENPROM_DEFLOOKUP proc_openprom_deflookup
#else
#define OPENPROM_DEFREADDIR NULL
#define OPENPROM_DEFLOOKUP NULL
#endif
static
struct
file_operations
proc_openprom_operations
=
{
NULL
,
/* lseek - default */
NULL
,
/* read - bad */
NULL
,
/* write - bad */
#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
proc_openprom_defreaddir
,
/* readdir */
#else
NULL
,
/* readdir */
#endif
OPENPROM_DEFREADDIR
,
/* readdir */
NULL
,
/* poll - default */
NULL
,
/* ioctl - default */
NULL
,
/* mmap */
...
...
@@ -251,11 +277,7 @@ static struct file_operations proc_openprom_operations = {
struct
inode_operations
proc_openprom_inode_operations
=
{
&
proc_openprom_operations
,
/* default net directory file-ops */
NULL
,
/* create */
#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
proc_openprom_deflookup
,
/* lookup */
#else
NULL
,
/* lookup */
#endif
OPENPROM_DEFLOOKUP
,
/* lookup */
NULL
,
/* link */
NULL
,
/* unlink */
NULL
,
/* symlink */
...
...
@@ -638,6 +660,26 @@ void proc_root_init(void)
#endif
}
/*
* As some entries in /proc are volatile, we want to
* get rid of unused dentries. This could be made
* smarter: we could keep a "volatile" flag in the
* inode to indicate which ones to keep.
*/
static
void
proc_delete_dentry
(
struct
dentry
*
dentry
)
{
d_drop
(
dentry
);
}
static
struct
dentry_operations
proc_dentry_operations
=
{
NULL
,
/* revalidate */
NULL
,
/* d_hash */
NULL
,
/* d_compare */
proc_delete_dentry
/* d_delete(struct dentry *) */
};
/*
* Don't create negative dentries here, return -ENOENT by hand
* instead.
...
...
@@ -646,12 +688,15 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
{
struct
inode
*
inode
;
struct
proc_dir_entry
*
de
;
int
error
;
error
=
-
ENOTDIR
;
if
(
!
dir
||
!
S_ISDIR
(
dir
->
i_mode
))
return
-
ENOTDIR
;
goto
out
;
de
=
(
struct
proc_dir_entry
*
)
dir
->
u
.
generic_ip
;
error
=
-
ENOENT
;
inode
=
NULL
;
de
=
(
struct
proc_dir_entry
*
)
dir
->
u
.
generic_ip
;
if
(
de
)
{
for
(
de
=
de
->
subdir
;
de
;
de
=
de
->
next
)
{
if
(
!
de
||
!
de
->
low_ino
)
...
...
@@ -660,18 +705,20 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
continue
;
if
(
!
memcmp
(
dentry
->
d_name
.
name
,
de
->
name
,
de
->
namelen
))
{
int
ino
=
de
->
low_ino
|
(
dir
->
i_ino
&
~
(
0xffff
));
error
=
-
EINVAL
;
inode
=
proc_get_inode
(
dir
->
i_sb
,
ino
,
de
);
if
(
!
inode
)
return
-
EINVAL
;
break
;
}
}
}
if
(
!
inode
)
return
-
ENOENT
;
d_add
(
dentry
,
inode
);
return
0
;
if
(
inode
)
{
dentry
->
d_op
=
&
proc_dentry_operations
;
d_add
(
dentry
,
inode
);
error
=
0
;
}
out:
return
error
;
}
static
int
proc_root_lookup
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
...
...
@@ -721,6 +768,8 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
if
(
!
inode
)
return
-
EINVAL
;
}
dentry
->
d_op
=
&
proc_dentry_operations
;
d_add
(
dentry
,
inode
);
return
0
;
}
...
...
@@ -827,3 +876,15 @@ static int proc_root_readdir(struct file * filp,
read_unlock
(
&
tasklist_lock
);
return
0
;
}
static
int
proc_unlink
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
struct
proc_dir_entry
*
dp
=
dir
->
u
.
generic_ip
;
printk
(
"proc_file_unlink: deleting %s/%s
\n
"
,
dp
->
name
,
dentry
->
d_name
.
name
);
remove_proc_entry
(
dentry
->
d_name
.
name
,
dp
);
dentry
->
d_inode
->
i_nlink
=
0
;
d_delete
(
dentry
);
return
0
;
}
fs/smbfs/Makefile
View file @
f59dfe26
...
...
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET
:=
smbfs.o
O_OBJS
:=
proc.o dir.o sock.o inode.o file.o ioctl.o
O_OBJS
:=
proc.o dir.o
cache.o
sock.o inode.o file.o ioctl.o
M_OBJS
:=
$(O_TARGET)
# If you want debugging output, please uncomment the following line
...
...
fs/smbfs/cache.c
0 → 100644
View file @
f59dfe26
/*
* cache.c
*
* Copyright (C) 1997 by Bill Hawes
*
* Routines to support directory cacheing using the page cache.
* Right now this only works for smbfs, but will be generalized
* for use with other filesystems.
*/
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/dirent.h>
#include <linux/smb_fs.h>
#include <asm/page.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
static
inline
struct
inode
*
get_cache_inode
(
struct
cache_head
*
cachep
)
{
return
(
mem_map
+
MAP_NR
((
unsigned
long
)
cachep
))
->
inode
;
}
/*
* Get a pointer to the cache_head structure,
* mapped as the page at offset 0. The page is
* kept locked while we're using the cache.
*/
struct
cache_head
*
smb_get_dircache
(
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
cache_head
*
cachep
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_get_dircache: finding cache for %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
cachep
=
(
struct
cache_head
*
)
get_cached_page
(
inode
,
0
,
1
);
if
(
!
cachep
)
goto
out
;
if
(
cachep
->
valid
)
{
struct
cache_index
*
index
=
cachep
->
index
;
struct
cache_block
*
block
;
unsigned
long
offset
;
int
i
;
cachep
->
valid
=
0
;
/*
* Here we only want to find existing cache blocks,
* not add new ones.
*/
for
(
i
=
0
;
i
<
cachep
->
pages
;
i
++
,
index
++
)
{
#ifdef SMBFS_PARANOIA
if
(
index
->
block
)
printk
(
"smb_get_dircache: cache %s/%s has existing block!
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
offset
=
PAGE_SIZE
+
(
i
<<
PAGE_SHIFT
);
block
=
(
struct
cache_block
*
)
get_cached_page
(
inode
,
offset
,
0
);
if
(
!
block
)
goto
out
;
index
->
block
=
block
;
}
cachep
->
valid
=
1
;
}
out:
return
cachep
;
}
/*
* Unlock and release the data blocks.
*/
static
void
smb_free_cache_blocks
(
struct
cache_head
*
cachep
)
{
struct
cache_index
*
index
=
cachep
->
index
;
int
i
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_free_cache_blocks: freeing %d blocks
\n
"
,
cachep
->
pages
);
#endif
for
(
i
=
0
;
i
<
cachep
->
pages
;
i
++
,
index
++
)
{
if
(
index
->
block
)
{
put_cached_page
((
unsigned
long
)
index
->
block
);
index
->
block
=
NULL
;
}
}
}
/*
* Unlocks and releases the dircache.
*/
void
smb_free_dircache
(
struct
cache_head
*
cachep
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_free_dircache: freeing cache
\n
"
);
#endif
smb_free_cache_blocks
(
cachep
);
put_cached_page
((
unsigned
long
)
cachep
);
}
/*
* Initializes the dircache. We release any existing data blocks,
* and then clear the cache_head structure.
*/
void
smb_init_dircache
(
struct
cache_head
*
cachep
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_init_dircache: initializing cache, %d blocks
\n
"
,
cachep
->
pages
);
#endif
smb_free_cache_blocks
(
cachep
);
memset
(
cachep
,
0
,
sizeof
(
struct
cache_head
));
}
/*
* Add a new entry to the cache. This assumes that the
* entries are coming in order and are added to the end.
*/
void
smb_add_to_cache
(
struct
cache_head
*
cachep
,
struct
dirent
*
entry
,
off_t
fpos
)
{
struct
inode
*
inode
=
get_cache_inode
(
cachep
);
struct
cache_index
*
index
;
struct
cache_block
*
block
;
unsigned
long
page_off
;
unsigned
int
nent
,
offset
,
len
=
entry
->
d_reclen
;
unsigned
int
needed
=
len
+
sizeof
(
struct
cache_entry
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_add_to_cache: cache inode %p, status %d, adding %s at %ld
\n
"
,
inode
,
cachep
->
status
,
entry
->
d_name
,
fpos
);
#endif
/*
* Don't do anything if we've had an error ...
*/
if
(
cachep
->
status
)
goto
out
;
index
=
&
cachep
->
index
[
cachep
->
idx
];
if
(
!
index
->
block
)
goto
get_block
;
/* space available? */
if
(
needed
<
index
->
space
)
{
add_entry:
nent
=
index
->
num_entries
;
index
->
num_entries
++
;
index
->
space
-=
needed
;
offset
=
index
->
space
+
index
->
num_entries
*
sizeof
(
struct
cache_entry
);
block
=
index
->
block
;
memcpy
(
&
block
->
cb_data
.
names
[
offset
],
entry
->
d_name
,
len
);
block
->
cb_data
.
table
[
nent
].
namelen
=
len
;
block
->
cb_data
.
table
[
nent
].
offset
=
offset
;
block
->
cb_data
.
table
[
nent
].
ino
=
entry
->
d_ino
;
cachep
->
entries
++
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d
\n
"
,
entry
->
d_name
,
len
,
fpos
,
cachep
->
entries
);
#endif
return
;
}
/*
* This block is full ... advance the index.
*/
cachep
->
idx
++
;
if
(
cachep
->
idx
>
NINDEX
)
/* not likely */
goto
out_full
;
index
++
;
#ifdef SMBFS_PARANOIA
if
(
index
->
block
)
printk
(
"smb_add_to_cache: new index already has block!
\n
"
);
#endif
/*
* Get the next cache block
*/
get_block:
cachep
->
pages
++
;
page_off
=
PAGE_SIZE
+
(
cachep
->
idx
<<
PAGE_SHIFT
);
block
=
(
struct
cache_block
*
)
get_cached_page
(
inode
,
page_off
,
1
);
if
(
block
)
{
index
->
block
=
block
;
index
->
space
=
PAGE_SIZE
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_add_to_cache: inode=%p, pages=%d, block at %ld
\n
"
,
inode
,
cachep
->
pages
,
page_off
);
#endif
goto
add_entry
;
}
/*
* On failure, just set the return status ...
*/
out_full:
cachep
->
status
=
-
ENOMEM
;
out:
return
;
}
int
smb_find_in_cache
(
struct
cache_head
*
cachep
,
off_t
pos
,
struct
cache_dirent
*
entry
)
{
struct
cache_index
*
index
=
cachep
->
index
;
struct
cache_block
*
block
;
unsigned
int
i
,
nent
,
offset
=
0
;
off_t
next_pos
=
2
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_find_in_cache: cache %p, looking for pos=%ld
\n
"
,
cachep
,
pos
);
#endif
for
(
i
=
0
;
i
<
cachep
->
pages
;
i
++
,
index
++
)
{
if
(
pos
<
next_pos
)
break
;
nent
=
pos
-
next_pos
;
next_pos
+=
index
->
num_entries
;
if
(
pos
>=
next_pos
)
continue
;
/*
* The entry is in this block. Note: we return
* then name as a reference with _no_ null byte.
*/
block
=
index
->
block
;
entry
->
ino
=
block
->
cb_data
.
table
[
nent
].
ino
;
entry
->
len
=
block
->
cb_data
.
table
[
nent
].
namelen
;
offset
=
block
->
cb_data
.
table
[
nent
].
offset
;
entry
->
name
=
&
block
->
cb_data
.
names
[
offset
];
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_find_in_cache: found %s, len=%d, pos=%ld
\n
"
,
entry
->
name
,
entry
->
len
,
pos
);
#endif
break
;
}
return
offset
;
}
int
smb_refill_dircache
(
struct
cache_head
*
cachep
,
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
int
result
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_refill_dircache: cache %s/%s, blocks=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
cachep
->
pages
);
#endif
/*
* Fill the cache, starting at position 2.
*/
retry:
inode
->
u
.
smbfs_i
.
cache_valid
=
1
;
result
=
smb_proc_readdir
(
dentry
,
2
,
cachep
);
if
(
result
<
0
)
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_refill_dircache: readdir failed, result=%d
\n
"
,
result
);
#endif
goto
out
;
}
/*
* Check whether the cache was invalidated while
* we were doing the scan ...
*/
if
(
!
inode
->
u
.
smbfs_i
.
cache_valid
)
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_refill_dircache: cache invalidated, retrying
\n
"
);
#endif
goto
retry
;
}
result
=
cachep
->
status
;
if
(
!
result
)
{
cachep
->
valid
=
1
;
}
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_refill_cache: cache %s/%s status=%d, entries=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
cachep
->
status
,
cachep
->
entries
);
#endif
out:
return
result
;
}
void
smb_invalid_dir_cache
(
struct
inode
*
dir
)
{
/*
* Get rid of any unlocked pages, and clear the
* 'valid' flag in case a scan is in progress.
*/
invalidate_inode_pages
(
dir
);
dir
->
u
.
smbfs_i
.
cache_valid
=
0
;
}
fs/smbfs/dir.c
View file @
f59dfe26
...
...
@@ -23,21 +23,17 @@
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
#define this_dir_cached(dir) ((dir->i_sb == c_sb) && (dir->i_ino == c_ino))
static
long
smb_dir_read
(
struct
inode
*
inode
,
struct
file
*
filp
,
char
*
buf
,
unsigned
long
count
);
static
int
smb_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
);
static
long
smb_dir_read
(
struct
inode
*
,
struct
file
*
,
char
*
,
unsigned
long
);
static
int
smb_readdir
(
struct
file
*
,
void
*
,
filldir_t
);
static
int
smb_dir_open
(
struct
inode
*
,
struct
file
*
);
static
int
smb_lookup
(
struct
inode
*
,
struct
dentry
*
);
static
int
smb_create
(
struct
inode
*
,
struct
dentry
*
,
int
);
static
int
smb_mkdir
(
struct
inode
*
,
struct
dentry
*
,
int
);
static
int
smb_rmdir
(
struct
inode
*
,
struct
dentry
*
);
static
int
smb_unlink
(
struct
inode
*
,
struct
dentry
*
);
static
int
smb_rename
(
struct
inode
*
,
struct
dentry
*
,
struct
inode
*
,
struct
dentry
*
);
static
int
smb_rename
(
struct
inode
*
,
struct
dentry
*
,
struct
inode
*
,
struct
dentry
*
);
static
struct
file_operations
smb_dir_operations
=
{
...
...
@@ -48,7 +44,7 @@ static struct file_operations smb_dir_operations =
NULL
,
/* poll - default */
smb_ioctl
,
/* ioctl */
NULL
,
/* mmap */
NULL
,
/* no special open code
*/
smb_dir_open
,
/* open(struct inode *, struct file *)
*/
NULL
,
/* no special release code */
NULL
/* fsync */
};
...
...
@@ -75,15 +71,6 @@ struct inode_operations smb_dir_inode_operations =
NULL
/* smap */
};
static
void
smb_put_dentry
(
struct
dentry
*
);
static
struct
dentry_operations
smbfs_dentry_operations
=
{
NULL
,
/* revalidate */
NULL
,
/* d_hash */
NULL
,
/* d_compare */
smb_put_dentry
/* d_delete */
};
static
long
smb_dir_read
(
struct
inode
*
inode
,
struct
file
*
filp
,
char
*
buf
,
unsigned
long
count
)
...
...
@@ -92,120 +79,43 @@ smb_dir_read(struct inode *inode, struct file *filp, char *buf,
}
/*
* This is the callback from dput(). We close the file so that
* cached dentries don't keep the file open.
*/
void
smb_put_dentry
(
struct
dentry
*
dentry
)
{
struct
inode
*
ino
=
dentry
->
d_inode
;
if
(
ino
)
smb_close
(
ino
);
}
/* Static variables for the dir cache */
static
struct
smb_dirent
*
c_entry
=
NULL
;
static
struct
super_block
*
c_sb
=
NULL
;
static
unsigned
long
c_ino
=
0
;
static
int
c_seen_eof
;
static
int
c_size
;
static
int
c_last_returned_index
;
static
struct
smb_dirent
*
smb_search_in_cache
(
struct
inode
*
dir
,
unsigned
long
f_pos
)
{
int
i
;
if
(
this_dir_cached
(
dir
))
for
(
i
=
0
;
i
<
c_size
;
i
++
)
{
if
(
c_entry
[
i
].
f_pos
<
f_pos
)
continue
;
if
(
c_entry
[
i
].
f_pos
==
f_pos
)
{
c_last_returned_index
=
i
;
return
&
(
c_entry
[
i
]);
}
break
;
}
return
NULL
;
}
/*
* Compute the hash for a qstr ... move to include/linux/dcache.h?
* Compute the hash for a qstr.
* N.B. Move to include/linux/dcache.h?
*/
static
unsigned
int
hash_it
(
const
char
*
name
,
unsigned
int
len
)
static
unsigned
int
hash_it
(
const
char
*
name
,
unsigned
int
len
)
{
unsigned
long
hash
;
hash
=
init_name_hash
();
unsigned
long
hash
=
init_name_hash
();
while
(
len
--
)
hash
=
partial_name_hash
(
*
name
++
,
hash
);
return
end_name_hash
(
hash
);
}
static
struct
semaphore
refill_cache_sem
=
MUTEX
;
/*
* Called with the refill semaphore held.
* If a dentry already exists, we have to give the cache entry
* the correct inode number. This is needed for getcwd().
*/
static
int
smb_
refill_dir_cache
(
struct
dentry
*
dentry
,
unsigned
long
f_pos
)
static
unsigned
long
smb_
find_ino
(
struct
dentry
*
dentry
,
struct
cache_dirent
*
entry
)
{
struct
inode
*
dir
=
dentry
->
d_inode
;
ino_t
ino_start
;
int
i
,
result
;
result
=
smb_proc_readdir
(
dentry
,
f_pos
,
SMB_READDIR_CACHE_SIZE
,
c_entry
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_refill_dir_cache: dir=%s/%s, pos=%lu, result=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
f_pos
,
result
);
#endif
if
(
result
<=
0
)
{
/*
* If an error occurred, the cache may have been partially
* filled prior to failing, so we must invalidate.
* N.B. Might not need to for 0 return ... save cache?
*/
c_sb
=
NULL
;
c_ino
=
0
;
c_seen_eof
=
0
;
goto
out
;
}
/* Suppose there are a multiple of cache entries? */
c_seen_eof
=
(
result
<
SMB_READDIR_CACHE_SIZE
);
c_sb
=
dir
->
i_sb
;
c_ino
=
dir
->
i_ino
;
c_size
=
result
;
c_last_returned_index
=
0
;
/* is this used? */
ino_start
=
smb_invent_inos
(
c_size
);
/*
* If a dentry already exists, we have to give the cache entry
* the correct inode number. This is needed for getcwd().
*/
for
(
i
=
0
;
i
<
c_size
;
i
++
)
struct
dentry
*
new_dentry
;
struct
qstr
qname
;
unsigned
long
ino
=
0
;
qname
.
name
=
entry
->
name
;
qname
.
len
=
entry
->
len
;
qname
.
hash
=
hash_it
(
qname
.
name
,
qname
.
len
);
new_dentry
=
d_lookup
(
dentry
,
&
qname
);
if
(
new_dentry
)
{
struct
dentry
*
new_dentry
;
struct
qstr
qname
;
c_entry
[
i
].
attr
.
f_ino
=
ino_start
++
;
qname
.
name
=
c_entry
[
i
].
name
;
qname
.
len
=
c_entry
[
i
].
len
;
qname
.
hash
=
hash_it
(
qname
.
name
,
qname
.
len
);
new_dentry
=
d_lookup
(
dentry
,
&
qname
);
if
(
new_dentry
)
{
struct
inode
*
inode
=
new_dentry
->
d_inode
;
if
(
inode
)
c_entry
[
i
].
attr
.
f_ino
=
inode
->
i_ino
;
dput
(
new_dentry
);
}
struct
inode
*
inode
=
new_dentry
->
d_inode
;
if
(
inode
)
ino
=
inode
->
i_ino
;
dput
(
new_dentry
);
}
out:
return
result
;
if
(
!
ino
)
ino
=
smb_invent_inos
(
1
);
return
ino
;
}
static
int
...
...
@@ -213,150 +123,195 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct
dentry
*
dentry
=
filp
->
f_dentry
;
struct
inode
*
dir
=
dentry
->
d_inode
;
struct
smb_dirent
*
entry
;
struct
cache_head
*
cachep
;
int
result
;
pr_debug
(
"smb_readdir: filp->f_pos = %d
\n
"
,
(
int
)
filp
->
f_pos
);
pr_debug
(
"smb_readdir: dir->i_ino = %ld, c_ino = %ld
\n
"
,
dir
->
i_ino
,
c_ino
);
result
=
-
EBADF
;
if
((
dir
==
NULL
)
||
!
S_ISDIR
(
dir
->
i_mode
))
/*
* Make sure our inode is up-to-date.
*/
result
=
smb_revalidate_inode
(
dir
);
if
(
result
)
goto
out
;
/*
* Get the cache pointer ...
*/
cachep
=
smb_get_dircache
(
dentry
);
if
(
!
cachep
)
goto
out
;
/*
*
Check whether the directory cache exists yet
*
Make sure the cache is up-to-date.
*/
if
(
c_entry
==
NULL
)
if
(
!
cachep
->
valid
)
{
int
size
=
sizeof
(
struct
smb_dirent
)
*
SMB_READDIR_CACHE_SIZE
;
result
=
-
ENOMEM
;
entry
=
(
struct
smb_dirent
*
)
smb_vmalloc
(
size
);
/*
* Somebody else may have allocated the cache,
* so we check again to avoid a memory leak.
*/
if
(
!
c_entry
)
{
if
(
!
entry
)
goto
out
;
c_entry
=
entry
;
}
else
if
(
entry
)
{
printk
(
"smb_readdir: cache already alloced!
\n
"
);
smb_vfree
(
entry
);
}
result
=
smb_refill_dircache
(
cachep
,
dentry
);
if
(
result
)
goto
up_and_out
;
}
result
=
0
;
switch
((
unsigned
int
)
filp
->
f_pos
)
{
case
0
:
if
(
filldir
(
dirent
,
"."
,
1
,
0
,
dir
->
i_ino
)
<
0
)
goto
out
;
goto
up_and_
out
;
filp
->
f_pos
=
1
;
case
1
:
if
(
filldir
(
dirent
,
".."
,
2
,
1
,
dentry
->
d_parent
->
d_inode
->
i_ino
)
<
0
)
goto
out
;
goto
up_and_
out
;
filp
->
f_pos
=
2
;
}
/*
* Since filldir() could block if dirent is paged out,
* we hold the refill semaphore while using the cache.
* N.B. It's possible that the directory could change
* between calls to readdir ... what to do??
*/
down
(
&
refill_cache_sem
);
entry
=
smb_search_in_cache
(
dir
,
filp
->
f_pos
);
if
(
entry
==
NULL
)
while
(
1
)
{
/* Past the end of _this_ directory? */
if
(
this_dir_cached
(
dir
)
&&
c_seen_eof
&&
filp
->
f_pos
==
c_entry
[
c_size
-
1
].
f_pos
+
1
)
struct
cache_dirent
this_dirent
,
*
entry
=
&
this_dirent
;
if
(
!
smb_find_in_cache
(
cachep
,
filp
->
f_pos
,
entry
))
break
;
/*
* Check whether to look up the inode number.
*/
if
(
!
entry
->
ino
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_readdir: eof reached for %s/%s, c_size=%d, pos=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
c_size
,
(
int
)
filp
->
f_pos
);
#endif
goto
up_and_out
;
entry
->
ino
=
smb_find_ino
(
dentry
,
entry
);
}
result
=
smb_refill_dir_cache
(
dentry
,
filp
->
f_pos
);
if
(
result
<=
0
)
goto
up_and_out
;
entry
=
c_entry
;
}
while
(
entry
<
&
(
c_entry
[
c_size
]))
{
pr_debug
(
"smb_readdir: entry->name = %s
\n
"
,
entry
->
name
);
if
(
filldir
(
dirent
,
entry
->
name
,
entry
->
len
,
entry
->
f_pos
,
entry
->
attr
.
f_
ino
)
<
0
)
filp
->
f_pos
,
entry
->
ino
)
<
0
)
break
;
#if SMBFS_PARANOIA
/* should never happen */
if
(
!
this_dir_cached
(
dir
)
||
(
entry
->
f_pos
!=
filp
->
f_pos
))
printk
(
"smb_readdir: cache changed!
\n
"
);
#endif
filp
->
f_pos
+=
1
;
entry
+=
1
;
}
result
=
0
;
/*
* Release the dircache.
*/
up_and_out:
up
(
&
refill_cache_sem
);
smb_free_dircache
(
cachep
);
out:
return
result
;
}
void
smb_
init_dir_cache
(
void
)
static
int
smb_
dir_open
(
struct
inode
*
dir
,
struct
file
*
file
)
{
c_entry
=
NULL
;
c_sb
=
NULL
;
c_ino
=
0
;
c_seen_eof
=
0
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_dir_open: (%s/%s)
\n
"
,
file
->
f_dentry
->
d_parent
->
d_name
.
name
,
file
->
f_dentry
->
d_name
.
name
);
#endif
return
smb_revalidate_inode
(
dir
);
}
void
smb_invalid_dir_cache
(
struct
inode
*
dir
)
/*
* Dentry operations routines
*/
static
int
smb_lookup_validate
(
struct
dentry
*
);
static
void
smb_delete_dentry
(
struct
dentry
*
);
static
struct
dentry_operations
smbfs_dentry_operations
=
{
smb_lookup_validate
,
/* d_validate(struct dentry *) */
NULL
,
/* d_hash */
NULL
,
/* d_compare */
smb_delete_dentry
/* d_delete(struct dentry *) */
};
/*
* This is the callback when the dcache has a lookup hit.
*/
static
int
smb_lookup_validate
(
struct
dentry
*
dentry
)
{
if
(
this_dir_cached
(
dir
))
struct
inode
*
inode
=
dentry
->
d_inode
;
unsigned
long
age
=
jiffies
-
dentry
->
d_time
;
int
valid
;
/*
* The default validation is based on dentry age:
* we believe in dentries for 5 seconds. (But each
* successful server lookup renews the timestamp.)
*/
valid
=
age
<
5
*
HZ
||
IS_ROOT
(
dentry
);
#ifdef SMBFS_DEBUG_VERBOSE
if
(
!
valid
)
printk
(
"smb_lookup_validate: %s/%s not valid, age=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
age
)
#endif
if
(
inode
)
{
if
(
is_bad_inode
(
inode
))
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_lookup_validate: %s/%s has dud inode
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
valid
=
0
;
}
}
else
{
c_sb
=
NULL
;
c_ino
=
0
;
c_seen_eof
=
0
;
/*
* What should we do for negative dentries?
*/
}
return
valid
;
}
void
smb_free_dir_cache
(
void
)
/*
* This is the callback from dput() when d_count is going to 0.
* We use this to close files and unhash dentries with bad inodes.
*/
static
void
smb_delete_dentry
(
struct
dentry
*
dentry
)
{
if
(
c_entry
!=
NULL
)
if
(
dentry
->
d_inode
)
{
if
(
is_bad_inode
(
dentry
->
d_inode
))
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_delete_dentry: bad inode, unhashing %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
d_drop
(
dentry
);
}
smb_close_dentry
(
dentry
);
}
else
{
/* N.B. can this block?? */
smb_vfree
(
c_entry
);
/* N.B. Unhash negative dentries? */
}
}
/*
* Whenever a lookup succeeds, we know the parent directories
* are all valid, so we want to update the dentry timestamps.
* N.B. Move this to dcache?
*/
void
smb_renew_times
(
struct
dentry
*
dentry
)
{
for
(;;)
{
dentry
->
d_time
=
jiffies
;
if
(
dentry
==
dentry
->
d_parent
)
break
;
dentry
=
dentry
->
d_parent
;
}
c_entry
=
NULL
;
}
static
int
smb_lookup
(
struct
inode
*
dir
,
struct
dentry
*
d
_
entry
)
smb_lookup
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
struct
smb_fattr
finfo
;
struct
inode
*
inode
;
int
error
;
error
=
-
ENAMETOOLONG
;
if
(
d
_
entry
->
d_name
.
len
>
SMB_MAXNAMELEN
)
if
(
dentry
->
d_name
.
len
>
SMB_MAXNAMELEN
)
goto
out
;
error
=
smb_proc_getattr
(
d
_entry
->
d_parent
,
&
(
d_
entry
->
d_name
),
&
finfo
);
#if SMBFS_PARANOIA
error
=
smb_proc_getattr
(
d
entry
->
d_parent
,
&
(
d
entry
->
d_name
),
&
finfo
);
#if
def
SMBFS_PARANOIA
if
(
error
&&
error
!=
-
ENOENT
)
printk
(
"smb_lookup: find %s/%s failed, error=%d
\n
"
,
d
_entry
->
d_parent
->
d_name
.
name
,
d_
entry
->
d_name
.
name
,
error
);
d
entry
->
d_parent
->
d_name
.
name
,
d
entry
->
d_name
.
name
,
error
);
#endif
inode
=
NULL
;
...
...
@@ -370,10 +325,11 @@ d_entry->d_parent->d_name.name, d_entry->d_name.name, error);
if
(
inode
)
{
/* cache the dentry pointer */
inode
->
u
.
smbfs_i
.
dentry
=
d
_
entry
;
inode
->
u
.
smbfs_i
.
dentry
=
dentry
;
add_entry:
d_entry
->
d_op
=
&
smbfs_dentry_operations
;
d_add
(
d_entry
,
inode
);
dentry
->
d_op
=
&
smbfs_dentry_operations
;
d_add
(
dentry
,
inode
);
smb_renew_times
(
dentry
);
error
=
0
;
}
}
...
...
@@ -385,25 +341,24 @@ d_entry->d_parent->d_name.name, d_entry->d_name.name, error);
* This code is common to all routines creating a new inode.
*/
static
int
smb_instantiate
(
struct
inode
*
dir
,
struct
dentry
*
dentry
)
smb_instantiate
(
struct
dentry
*
dentry
)
{
struct
smb_fattr
fattr
;
int
error
;
smb_invalid_dir_cache
(
dir
);
error
=
smb_proc_getattr
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
),
&
fattr
);
if
(
!
error
)
{
struct
inode
*
inode
;
error
=
-
EACCES
;
fattr
.
f_ino
=
smb_invent_inos
(
1
);
inode
=
smb_iget
(
d
ir
->
i
_sb
,
&
fattr
);
inode
=
smb_iget
(
d
entry
->
d
_sb
,
&
fattr
);
if
(
inode
)
{
/* cache the dentry pointer */
inode
->
u
.
smbfs_i
.
dentry
=
dentry
;
d_instantiate
(
dentry
,
inode
);
smb_renew_times
(
dentry
);
error
=
0
;
}
}
...
...
@@ -424,11 +379,12 @@ smb_create(struct inode *dir, struct dentry *dentry, int mode)
* state. Currently we close it directly again, although this
* is not necessary anymore. */
smb_invalid_dir_cache
(
dir
);
error
=
smb_proc_create
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
),
0
,
CURRENT_TIME
);
if
(
!
error
)
{
error
=
smb_instantiate
(
d
ir
,
d
entry
);
error
=
smb_instantiate
(
dentry
);
}
out:
return
error
;
...
...
@@ -444,10 +400,11 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if
(
dentry
->
d_name
.
len
>
SMB_MAXNAMELEN
)
goto
out
;
smb_invalid_dir_cache
(
dir
);
error
=
smb_proc_mkdir
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
));
if
(
!
error
)
{
error
=
smb_instantiate
(
d
ir
,
d
entry
);
error
=
smb_instantiate
(
dentry
);
}
out:
return
error
;
...
...
@@ -459,7 +416,7 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
int
error
;
error
=
-
ENAMETOOLONG
;
if
(
dentry
->
d_name
.
len
>
NFS_MAXNAM
LEN
)
if
(
dentry
->
d_name
.
len
>
SMB_MAXNAME
LEN
)
goto
out
;
/*
...
...
@@ -468,11 +425,12 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
*/
if
(
dentry
->
d_inode
)
smb_close
(
dentry
->
d_inode
);
smb_invalid_dir_cache
(
dir
);
smb_invalid_dir_cache
(
dir
);
error
=
smb_proc_rmdir
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
));
if
(
!
error
)
{
smb_renew_times
(
dentry
);
d_delete
(
dentry
);
}
out:
...
...
@@ -494,11 +452,12 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
*/
if
(
dentry
->
d_inode
)
smb_close
(
dentry
->
d_inode
);
smb_invalid_dir_cache
(
dir
);
smb_invalid_dir_cache
(
dir
);
error
=
smb_proc_unlink
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
));
if
(
!
error
)
{
smb_renew_times
(
dentry
);
d_delete
(
dentry
);
}
out:
...
...
@@ -511,19 +470,6 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int
error
;
error
=
-
ENOTDIR
;
if
(
!
old_dir
||
!
S_ISDIR
(
old_dir
->
i_mode
))
{
printk
(
"smb_rename: old inode is NULL or not a directory
\n
"
);
goto
out
;
}
if
(
!
new_dir
||
!
S_ISDIR
(
new_dir
->
i_mode
))
{
printk
(
"smb_rename: new inode is NULL or not a directory
\n
"
);
goto
out
;
}
error
=
-
ENAMETOOLONG
;
if
(
old_dentry
->
d_name
.
len
>
SMB_MAXNAMELEN
||
new_dentry
->
d_name
.
len
>
SMB_MAXNAMELEN
)
...
...
@@ -538,10 +484,8 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
if
(
new_dentry
->
d_inode
)
smb_close
(
new_dentry
->
d_inode
);
/* Assume success and invalidate now */
smb_invalid_dir_cache
(
old_dir
);
smb_invalid_dir_cache
(
new_dir
);
error
=
smb_proc_mv
(
old_dentry
->
d_parent
,
&
(
old_dentry
->
d_name
),
new_dentry
->
d_parent
,
&
(
new_dentry
->
d_name
));
/*
...
...
@@ -549,22 +493,24 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
if
(
error
==
-
EEXIST
)
{
#ifdef SMBFS_
PARANOIA
#ifdef SMBFS_
DEBUG_VERBOSE
printk
(
"smb_rename: existing file %s/%s, d_count=%d
\n
"
,
new_dentry
->
d_parent
->
d_name
.
name
,
new_dentry
->
d_name
.
name
,
new_dentry
->
d_count
);
#endif
error
=
smb_proc_unlink
(
new_dentry
->
d_parent
,
&
(
new_dentry
->
d_name
));
#ifdef SMBFS_
PARANOIA
#ifdef SMBFS_
DEBUG_VERBOSE
printk
(
"smb_rename: after unlink error=%d
\n
"
,
error
);
#endif
if
(
error
)
goto
out
;
d_delete
(
new_dentry
);
error
=
smb_proc_mv
(
old_dentry
->
d_parent
,
&
(
old_dentry
->
d_name
),
new_dentry
->
d_parent
,
&
(
new_dentry
->
d_name
));
if
(
!
error
)
{
d_delete
(
new_dentry
);
error
=
smb_proc_mv
(
old_dentry
->
d_parent
,
&
(
old_dentry
->
d_name
),
new_dentry
->
d_parent
,
&
(
new_dentry
->
d_name
));
}
}
/*
...
...
@@ -572,6 +518,8 @@ printk("smb_rename: after unlink error=%d\n", error);
*/
if
(
!
error
)
{
smb_renew_times
(
old_dentry
);
smb_renew_times
(
new_dentry
->
d_parent
);
d_move
(
old_dentry
,
new_dentry
);
}
out:
...
...
fs/smbfs/file.c
View file @
f59dfe26
...
...
@@ -23,17 +23,29 @@
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
extern
int
smb_get_rsize
(
struct
smb_sb_info
*
);
extern
int
smb_get_wsize
(
struct
smb_sb_info
*
);
static
inline
int
min
(
int
a
,
int
b
)
{
return
a
<
b
?
a
:
b
;
}
static
inline
void
smb_unlock_page
(
struct
page
*
page
)
{
clear_bit
(
PG_locked
,
&
page
->
flags
);
wake_up
(
&
page
->
wait
);
}
static
int
smb_fsync
(
struct
file
*
file
,
struct
dentry
*
dentry
)
{
printk
(
"smb_fsync: sync file %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_fsync: sync file %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
return
0
;
}
...
...
@@ -43,14 +55,13 @@ smb_fsync(struct file *file, struct dentry * dentry)
static
int
smb_readpage_sync
(
struct
inode
*
inode
,
struct
page
*
page
)
{
unsigned
long
offset
=
page
->
offset
;
char
*
buffer
=
(
char
*
)
page_address
(
page
);
unsigned
long
offset
=
page
->
offset
;
struct
dentry
*
dentry
=
inode
->
u
.
smbfs_i
.
dentry
;
int
rsize
=
SMB_SERVER
(
inode
)
->
opt
.
max_xmit
-
(
SMB_HEADER_LEN
+
15
);
int
result
,
refresh
=
0
;
int
rsize
=
smb_get_rsize
(
SMB_SERVER
(
inode
));
int
count
=
PAGE_SIZE
;
int
result
;
pr_debug
(
"SMB: smb_readpage_sync(%p)
\n
"
,
page
);
clear_bit
(
PG_error
,
&
page
->
flags
);
result
=
-
EIO
;
...
...
@@ -60,24 +71,22 @@ smb_readpage_sync(struct inode *inode, struct page *page)
goto
io_error
;
}
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
count
,
offset
,
rsize
);
#endif
result
=
smb_open
(
dentry
,
O_RDONLY
);
if
(
result
<
0
)
goto
io_error
;
/* Should revalidate inode ... */
do
{
if
(
count
<
rsize
)
rsize
=
count
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_readpage: reading %s/%s, offset=%ld, buffer=%p, size=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
offset
,
buffer
,
rsize
);
#endif
result
=
smb_proc_read
(
inode
,
offset
,
rsize
,
buffer
);
if
(
result
<
0
)
goto
io_error
;
refresh
=
1
;
count
-=
result
;
offset
+=
result
;
buffer
+=
result
;
...
...
@@ -90,10 +99,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
result
=
0
;
io_error:
if
(
refresh
)
smb_refresh_inode
(
inode
);
clear_bit
(
PG_locked
,
&
page
->
flags
);
wake_up
(
&
page
->
wait
);
smb_unlock_page
(
page
);
return
result
;
}
...
...
@@ -110,7 +116,7 @@ smb_readpage(struct inode *inode, struct page *page)
set_bit
(
PG_locked
,
&
page
->
flags
);
atomic_inc
(
&
page
->
count
);
error
=
smb_readpage_sync
(
inode
,
page
);
__free_page
(
page
);
free_page
(
page_address
(
page
)
);
return
error
;
}
...
...
@@ -122,24 +128,24 @@ static int
smb_writepage_sync
(
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
long
offset
,
unsigned
int
count
)
{
int
wsize
=
SMB_SERVER
(
inode
)
->
opt
.
max_xmit
-
(
SMB_HEADER_LEN
+
15
);
u8
*
buffer
=
(
u8
*
)
page_address
(
page
)
+
offset
;
int
wsize
=
smb_get_wsize
(
SMB_SERVER
(
inode
));
int
result
,
refresh
=
0
,
written
=
0
;
u8
*
buffer
;
pr_debug
(
"SMB: smb_writepage_sync(%x/%ld %d@%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
count
,
page
->
offset
+
offset
);
buffer
=
(
u8
*
)
page_address
(
page
)
+
offset
;
offset
+=
page
->
offset
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d
\n
"
,
((
struct
dentry
*
)
inode
->
u
.
smbfs_i
.
dentry
)
->
d_parent
->
d_name
.
name
,
((
struct
dentry
*
)
inode
->
u
.
smbfs_i
.
dentry
)
->
d_name
.
name
,
count
,
offset
,
wsize
);
#endif
do
{
if
(
count
<
wsize
)
wsize
=
count
;
result
=
smb_proc_write
(
inode
,
offset
,
wsize
,
buffer
);
if
(
result
<
0
)
{
if
(
result
<
0
)
{
/* Must mark the page invalid after I/O error */
clear_bit
(
PG_uptodate
,
&
page
->
flags
);
goto
io_error
;
...
...
@@ -157,11 +163,11 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
}
while
(
count
);
io_error:
#if 0
if (refresh)
smb_refresh_inode(inode);
clear_bit
(
PG_locked
,
&
page
->
flags
);
wake_up
(
&
page
->
wait
);
#endif
smb_unlock_page
(
page
);
return
written
?
written
:
result
;
}
...
...
@@ -181,7 +187,7 @@ smb_writepage(struct inode *inode, struct page *page)
set_bit
(
PG_locked
,
&
page
->
flags
);
atomic_inc
(
&
page
->
count
);
result
=
smb_writepage_sync
(
inode
,
page
,
0
,
PAGE_SIZE
);
__free_page
(
page
);
free_page
(
page_address
(
page
)
);
return
result
;
}
...
...
@@ -189,8 +195,8 @@ static int
smb_updatepage
(
struct
inode
*
inode
,
struct
page
*
page
,
const
char
*
buffer
,
unsigned
long
offset
,
unsigned
int
count
,
int
sync
)
{
u
8
*
page_addr
;
int
result
;
u
nsigned
long
page_addr
=
page_address
(
page
)
;
int
result
;
pr_debug
(
"SMB: smb_updatepage(%x/%ld %d@%ld, sync=%d)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
...
...
@@ -203,21 +209,21 @@ smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
set_bit
(
PG_locked
,
&
page
->
flags
);
atomic_inc
(
&
page
->
count
);
page_addr
=
(
u8
*
)
page_address
(
page
);
if
(
copy_from_user
(
page_addr
+
offset
,
buffer
,
count
))
if
(
copy_from_user
((
char
*
)
page_addr
+
offset
,
buffer
,
count
))
goto
bad_fault
;
result
=
smb_writepage_sync
(
inode
,
page
,
offset
,
count
);
out:
__free_page
(
page
);
free_page
(
page_addr
);
return
result
;
bad_fault:
printk
(
"smb_updatepage: fault at page=%p buffer=%p
\n
"
,
page
,
buffer
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_updatepage: fault at addr=%lu, offset=%lu, buffer=%p
\n
"
,
page_addr
,
offset
,
buffer
);
#endif
result
=
-
EFAULT
;
clear_bit
(
PG_uptodate
,
&
page
->
flags
);
clear_bit
(
PG_locked
,
&
page
->
flags
);
wake_up
(
&
page
->
wait
);
smb_unlock_page
(
page
);
goto
out
;
}
...
...
@@ -227,9 +233,11 @@ smb_file_read(struct inode * inode, struct file * file,
{
int
status
;
pr_debug
(
"SMB: read(%x/%ld (%d), %lu@%lu)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
inode
->
i_count
,
count
,
(
unsigned
long
)
file
->
f_pos
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_file_read: file %s/%s, count=%lu@%lu
\n
"
,
file
->
f_dentry
->
d_parent
->
d_name
.
name
,
file
->
f_dentry
->
d_name
.
name
,
count
,
(
unsigned
long
)
file
->
f_pos
);
#endif
status
=
smb_revalidate_inode
(
inode
);
if
(
status
>=
0
)
...
...
@@ -246,6 +254,11 @@ smb_file_mmap(struct file * file, struct vm_area_struct * vma)
struct
inode
*
inode
=
dentry
->
d_inode
;
int
status
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_file_mmap: file %s/%s, address %lu - %lu
\n
"
,
file
->
f_dentry
->
d_parent
->
d_name
.
name
,
file
->
f_dentry
->
d_name
.
name
,
vma
->
vm_start
,
vma
->
vm_end
);
#endif
status
=
smb_revalidate_inode
(
inode
);
if
(
status
>=
0
)
{
...
...
@@ -263,40 +276,67 @@ smb_file_write(struct inode *inode, struct file *file,
{
int
result
;
pr_debug
(
"SMB: write(%x/%ld (%d), %lu@%lu)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
inode
->
i_count
,
count
,
(
unsigned
long
)
file
->
f_pos
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_file_write: file %s/%s, count=%lu@%lu
\n
"
,
file
->
f_dentry
->
d_parent
->
d_name
.
name
,
file
->
f_dentry
->
d_name
.
name
,
count
,
(
unsigned
long
)
file
->
f_pos
);
#endif
#ifdef SMBFS_PARANOIA
/* Should be impossible now that inodes can't change mode */
result
=
-
EINVAL
;
if
(
!
inode
)
{
printk
(
"smb_file_write: inode = NULL
\n
"
);
if
(
!
S_ISREG
(
inode
->
i_mode
))
{
printk
(
"smb_file_write: write to non-file, mode %07o
\n
"
,
inode
->
i_mode
);
goto
out
;
}
#endif
result
=
smb_revalidate_inode
(
inode
);
if
(
result
<
0
)
if
(
result
)
goto
out
;
result
=
smb_open
(
file
->
f_dentry
,
O_WRONLY
);
if
(
result
<
0
)
if
(
result
)
goto
out
;
result
=
-
EINVAL
;
if
(
!
S_ISREG
(
inode
->
i_mode
))
{
printk
(
"smb_file_write: write to non-file, mode %07o
\n
"
,
inode
->
i_mode
);
goto
out
;
}
result
=
0
;
if
(
count
>
0
)
{
result
=
generic_file_write
(
inode
,
file
,
buf
,
count
);
if
(
result
>
0
)
smb_refresh_inode
(
inode
);
}
out:
return
result
;
}
static
int
smb_file_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_file_open: inode=%p, file=%p
\n
"
,
inode
,
file
);
#endif
return
0
;
}
static
int
smb_file_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
dentry
*
dentry
=
file
->
f_dentry
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_file_release: closing file %s/%s, d_count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
);
#endif
if
(
dentry
->
d_count
==
1
)
{
smb_close
(
inode
);
}
return
0
;
}
static
struct
file_operations
smb_file_operations
=
{
NULL
,
/* lseek - default */
...
...
@@ -305,10 +345,14 @@ static struct file_operations smb_file_operations =
NULL
,
/* readdir - bad */
NULL
,
/* poll - default */
smb_ioctl
,
/* ioctl */
smb_file_mmap
,
/* mmap */
NULL
,
/* open */
NULL
,
/* release */
smb_fsync
,
/* fsync */
smb_file_mmap
,
/* mmap(struct file*, struct vm_area_struct*) */
smb_file_open
,
/* open(struct inode*, struct file*) */
smb_file_release
,
/* release(struct inode*, struct file*) */
smb_fsync
,
/* fsync(struct file*, struct dentry*) */
NULL
,
/* fasync(struct file*, int) */
NULL
,
/* check_media_change(kdev_t dev) */
NULL
,
/* revalidate(kdev_t dev) */
NULL
/* lock(struct file*, int, struct file_lock*) */
};
struct
inode_operations
smb_file_inode_operations
=
...
...
fs/smbfs/inode.c
View file @
f59dfe26
...
...
@@ -6,6 +6,8 @@
*
*/
#define SMBFS_DCACHE_EXT 1
#include <linux/config.h>
#include <linux/module.h>
...
...
@@ -18,17 +20,20 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/dcache.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define S
B_of(server) ((struct super_block *) ((char *)(server) - \
(unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
#define S
MBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
#ifndef SMBFS_DCACHE_EXT
#define shrink_dcache_sb(sb) shrink_dcache()
#endif
extern
void
smb_renew_times
(
struct
dentry
*
);
extern
int
close_fp
(
struct
file
*
filp
);
static
void
smb_put_inode
(
struct
inode
*
);
...
...
@@ -67,7 +72,7 @@ smb_invent_inos(unsigned long n)
return
ino
;
}
static
struct
smb_fattr
*
read_fattr
;
static
struct
smb_fattr
*
read_fattr
=
NULL
;
static
struct
semaphore
read_semaphore
=
MUTEX
;
struct
inode
*
...
...
@@ -80,6 +85,7 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
down
(
&
read_semaphore
);
read_fattr
=
fattr
;
result
=
iget
(
sb
,
fattr
->
f_ino
);
read_fattr
=
NULL
;
up
(
&
read_semaphore
);
return
result
;
}
...
...
@@ -87,7 +93,6 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
static
void
smb_set_inode_attr
(
struct
inode
*
inode
,
struct
smb_fattr
*
fattr
)
{
inode
->
i_dev
=
inode
->
i_sb
->
s_dev
;
inode
->
i_mode
=
fattr
->
f_mode
;
inode
->
i_nlink
=
fattr
->
f_nlink
;
inode
->
i_uid
=
fattr
->
f_uid
;
...
...
@@ -99,6 +104,10 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode
->
i_atime
=
fattr
->
f_atime
;
inode
->
i_blksize
=
fattr
->
f_blksize
;
inode
->
i_blocks
=
fattr
->
f_blocks
;
/*
* Update the "last time refreshed" field for revalidation.
*/
inode
->
u
.
smbfs_i
.
oldmtime
=
jiffies
;
}
static
void
...
...
@@ -106,15 +115,15 @@ smb_read_inode(struct inode *inode)
{
pr_debug
(
"smb_iget: %p
\n
"
,
read_fattr
);
if
((
atomic_read
(
&
read_semaphore
.
count
)
==
1
)
||
(
inode
->
i_ino
!=
read_fattr
->
f_ino
))
if
(
!
read_fattr
||
inode
->
i_ino
!=
read_fattr
->
f_ino
)
{
printk
(
"smb_read_inode called from invalid point
\n
"
);
return
;
}
smb_set_inode_attr
(
inode
,
read_fattr
)
;
inode
->
i_dev
=
inode
->
i_sb
->
s_dev
;
memset
(
&
(
inode
->
u
.
smbfs_i
),
0
,
sizeof
(
inode
->
u
.
smbfs_i
));
smb_set_inode_attr
(
inode
,
read_fattr
);
if
(
S_ISREG
(
inode
->
i_mode
))
inode
->
i_op
=
&
smb_file_inode_operations
;
...
...
@@ -131,59 +140,129 @@ smb_read_inode(struct inode *inode)
void
smb_invalidate_inodes
(
struct
smb_sb_info
*
server
)
{
printk
(
"smb_invalidate_inodes
\n
"
);
shrink_dcache
();
/* should shrink only this sb */
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_invalidate_inodes
\n
"
);
#endif
shrink_dcache_sb
(
SB_of
(
server
));
invalidate_inodes
(
SB_of
(
server
));
}
int
smb_revalidate_inode
(
struct
inode
*
ino
)
smb_revalidate_inode
(
struct
inode
*
ino
de
)
{
struct
dentry
*
dentry
=
ino
->
u
.
smbfs_i
.
dentry
;
time_t
last_time
;
int
error
=
0
;
pr_debug
(
"smb_revalidate_inode
\n
"
);
if
(
!
ino
)
goto
bad_no_inode
;
dentry
=
ino
->
u
.
smbfs_i
.
dentry
;
#if 0
if (dentry)
/*
* Check whether we've recently refreshed the inode.
*/
if
(
jiffies
<
inode
->
u
.
smbfs_i
.
oldmtime
+
HZ
/
10
)
{
printk("smb_revalidate: checking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_revalidate_inode: up-to-date, jiffies=%lu, oldtime=%lu
\n
"
,
jiffies
,
inode
->
u
.
smbfs_i
.
oldmtime
);
#endif
goto
out
;
}
/*
* Save the last modified time, then refresh the inode
*/
last_time
=
inode
->
i_mtime
;
error
=
smb_refresh_inode
(
inode
);
if
(
!
error
)
{
if
(
inode
->
i_mtime
!=
last_time
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_revalidate: %s/%s changed, old=%ld, new=%ld
\n
"
,
((
struct
dentry
*
)
inode
->
u
.
smbfs_i
.
dentry
)
->
d_parent
->
d_name
.
name
,
((
struct
dentry
*
)
inode
->
u
.
smbfs_i
.
dentry
)
->
d_name
.
name
,
(
long
)
last_time
,
(
long
)
inode
->
i_mtime
);
#endif
if
(
!
S_ISDIR
(
inode
->
i_mode
))
invalidate_inode_pages
(
inode
);
else
smb_invalid_dir_cache
(
inode
);
}
}
out:
return
error
;
bad_no_inode:
printk
(
"smb_revalidate: no inode!
\n
"
);
error
=
-
EINVAL
;
goto
out
;
}
/*
* This is called to update the inode attributes after
* we've made changes to a file or directory.
*/
int
smb_refresh_inode
(
struct
inode
*
ino
)
smb_refresh_inode
(
struct
inode
*
ino
de
)
{
struct
dentry
*
dentry
=
ino
->
u
.
smbfs_i
.
dentry
;
struct
dentry
*
dentry
=
ino
de
->
u
.
smbfs_i
.
dentry
;
struct
smb_fattr
fattr
;
int
error
;
pr_debug
(
"smb_refresh_inode
\n
"
);
error
=
-
EIO
;
if
(
!
dentry
)
{
if
(
!
dentry
)
{
printk
(
"smb_refresh_inode: no dentry, can't refresh
\n
"
);
error
=
-
EIO
;
goto
out
;
}
/* N.B. Should check for changes of important fields! cf. NFS */
/*
* Kludge alert ... for some reason we can't get attributes
* for the root directory, so just return success.
*/
error
=
0
;
if
(
IS_ROOT
(
dentry
))
goto
out
;
error
=
smb_proc_getattr
(
dentry
->
d_parent
,
&
(
dentry
->
d_name
),
&
fattr
);
if
(
!
error
)
{
smb_set_inode_attr
(
ino
,
&
fattr
);
smb_renew_times
(
dentry
);
/*
* Check whether the type part of the mode changed,
* and don't update the attributes if it did.
*/
if
((
inode
->
i_mode
&
S_IFMT
)
==
(
fattr
.
f_mode
&
S_IFMT
))
smb_set_inode_attr
(
inode
,
&
fattr
);
else
{
/*
* Big trouble! The inode has become a new object,
* so any operations attempted on it are invalid.
*
* Take a couple of steps to limit damage:
* (1) Mark the inode as bad so that subsequent
* lookup validations will fail.
* (2) Clear i_nlink so the inode will be released
* at iput() time. (Unhash it as well?)
* We also invalidate the caches for good measure.
*/
#ifdef SMBFS_PARANOIA
printk
(
"smb_refresh_inode: %s/%s changed mode, %07o to %07o
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
inode
->
i_mode
,
fattr
.
f_mode
);
#endif
fattr
.
f_mode
=
inode
->
i_mode
;
/* save mode */
make_bad_inode
(
inode
);
inode
->
i_mode
=
fattr
.
f_mode
;
/* restore mode */
inode
->
i_nlink
=
0
;
/*
* No need to worry about unhashing the dentry: the
* lookup validation will see that the inode is bad.
* But we may need to invalidate the caches ...
*/
invalidate_inode_pages
(
inode
);
smb_invalid_dir_cache
(
inode
);
error
=
-
EIO
;
}
}
out:
return
error
;
}
/*
...
...
@@ -192,19 +271,20 @@ smb_refresh_inode(struct inode *ino)
static
void
smb_put_inode
(
struct
inode
*
ino
)
{
struct
dentry
*
dentry
;
pr_debug
(
"smb_put_inode: count = %d
\n
"
,
ino
->
i_count
);
if
(
ino
->
i_count
>
1
)
{
struct
dentry
*
dentry
;
/*
* Check whether the dentry still holds this inode.
* This looks scary, but should work ...
d_inode is
*
cleared before iput() in the dcache
.
* This looks scary, but should work ...
if this is
*
the last use, d_inode == NULL or d_count == 0
.
*/
dentry
=
(
struct
dentry
*
)
ino
->
u
.
smbfs_i
.
dentry
;
if
(
dentry
&&
dentry
->
d_inode
!=
ino
)
{
if
(
dentry
&&
(
dentry
->
d_inode
!=
ino
||
dentry
->
d_count
==
0
))
{
ino
->
u
.
smbfs_i
.
dentry
=
NULL
;
#if
1
#if
def SMBFS_DEBUG_VERBOSE
printk
(
"smb_put_inode: cleared dentry for %s/%s (%ld), count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
ino
->
i_ino
,
ino
->
i_count
);
#endif
...
...
@@ -263,7 +343,6 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
struct
smb_mount_data
*
data
=
(
struct
smb_mount_data
*
)
raw_data
;
struct
smb_fattr
root
;
kdev_t
dev
=
sb
->
s_dev
;
unsigned
char
*
packet
;
struct
inode
*
root_inode
;
struct
dentry
*
dentry
;
...
...
@@ -275,62 +354,65 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
if
(
data
->
version
!=
SMB_MOUNT_VERSION
)
goto
out_wrong_data
;
packet
=
smb_vmalloc
(
SMB_INITIAL_PACKET_SIZE
);
if
(
!
packet
)
goto
out_no_mem
;
lock_super
(
sb
);
sb
->
s_blocksize
=
1024
;
/* Eh... Is this correct? */
sb
->
s_blocksize_bits
=
10
;
sb
->
s_magic
=
SMB_SUPER_MAGIC
;
sb
->
s_dev
=
dev
;
sb
->
s_dev
=
dev
;
/* shouldn't need this ... */
sb
->
s_op
=
&
smb_sops
;
sb
->
u
.
smbfs_sb
.
sock_file
=
NULL
;
sb
->
u
.
smbfs_sb
.
sem
=
MUTEX
;
sb
->
u
.
smbfs_sb
.
wait
=
NULL
;
sb
->
u
.
smbfs_sb
.
conn_pid
=
0
;
sb
->
u
.
smbfs_sb
.
packet
=
packet
;
sb
->
u
.
smbfs_sb
.
packet_size
=
SMB_INITIAL_PACKET_SIZE
;
sb
->
u
.
smbfs_sb
.
state
=
CONN_INVALID
;
/* no connection yet */
sb
->
u
.
smbfs_sb
.
generation
=
0
;
sb
->
u
.
smbfs_sb
.
packet_size
=
SMB_INITIAL_PACKET_SIZE
;
sb
->
u
.
smbfs_sb
.
packet
=
smb_vmalloc
(
SMB_INITIAL_PACKET_SIZE
);
if
(
!
sb
->
u
.
smbfs_sb
.
packet
)
goto
out_no_mem
;
sb
->
u
.
smbfs_sb
.
m
=
*
data
;
sb
->
u
.
smbfs_sb
.
m
.
file_mode
=
(
sb
->
u
.
smbfs_sb
.
m
.
file_mode
&
(
S_IRWXU
|
S_IRWXG
|
S_IRWXO
))
|
S_IFREG
;
sb
->
u
.
smbfs_sb
.
m
.
dir_mode
=
(
sb
->
u
.
smbfs_sb
.
m
.
dir_mode
&
(
S_IRWXU
|
S_IRWXG
|
S_IRWXO
))
|
S_IFDIR
;
/*
* Keep the super block locked while we get the root inode.
*/
smb_init_root_dirent
(
&
(
sb
->
u
.
smbfs_sb
),
&
root
);
sb
->
s_root
=
NULL
;
unlock_super
(
sb
);
root_inode
=
smb_iget
(
sb
,
&
root
);
if
(
!
root_inode
)
goto
out_no_root
;
dentry
=
d_alloc_root
(
root_inode
,
NULL
);
if
(
!
dentry
)
goto
out_no_root
;
root_inode
->
u
.
smbfs_i
.
dentry
=
dentry
;
sb
->
s_root
=
dentry
;
unlock_super
(
sb
);
return
sb
;
out_no_data:
printk
(
"smb_read_super: missing data argument
\n
"
);
goto
out
;
out_wrong_data:
printk
(
KERN_ERR
"smb_read_super: wrong data argument."
" Recompile smbmount.
\n
"
);
goto
out
;
out_no_mem:
pr_debug
(
"smb_read_super: could not alloc packet
\n
"
);
goto
out
;
out_no_root:
sb
->
s_dev
=
0
;
/* iput() might block */
printk
(
KERN_ERR
"smb_read_super: get root inode failed
\n
"
);
iput
(
root_inode
);
smb_vfree
(
packet
);
out:
smb_vfree
(
sb
->
u
.
smbfs_sb
.
packet
);
goto
out_unlock
;
out_no_mem:
printk
(
"smb_read_super: could not alloc packet
\n
"
);
goto
out_unlock
;
out_wrong_data:
printk
(
KERN_ERR
"smb_read_super: wrong data argument."
" Recompile smbmount.
\n
"
);
goto
out_fail
;
out_no_data:
printk
(
"smb_read_super: missing data argument
\n
"
);
goto
out_fail
;
out_unlock:
unlock_super
(
sb
);
out_fail:
sb
->
s_dev
=
0
;
MOD_DEC_USE_COUNT
;
return
NULL
;
...
...
@@ -355,8 +437,9 @@ smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
int
smb_notify_change
(
struct
inode
*
inode
,
struct
iattr
*
attr
)
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
inode
);
struct
dentry
*
dentry
=
inode
->
u
.
smbfs_i
.
dentry
;
int
error
;
int
error
,
refresh
=
0
;
error
=
-
EIO
;
if
(
!
dentry
)
...
...
@@ -365,40 +448,54 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
goto
out
;
}
/*
* Make sure our inode is up-to-date ...
*/
error
=
smb_revalidate_inode
(
inode
);
if
(
error
)
goto
out
;
if
((
error
=
inode_change_ok
(
inode
,
attr
))
<
0
)
goto
out
;
error
=
-
EPERM
;
if
(((
attr
->
ia_valid
&
ATTR_UID
)
&&
(
attr
->
ia_uid
!=
SMB_SERVER
(
inode
)
->
m
.
uid
)))
if
(((
attr
->
ia_valid
&
ATTR_UID
)
&&
(
attr
->
ia_uid
!=
server
->
m
.
uid
)))
goto
out
;
if
(((
attr
->
ia_valid
&
ATTR_GID
)
&&
(
attr
->
ia_uid
!=
SMB_SERVER
(
inode
)
->
m
.
gid
)))
if
(((
attr
->
ia_valid
&
ATTR_GID
)
&&
(
attr
->
ia_uid
!=
server
->
m
.
gid
)))
goto
out
;
if
(((
attr
->
ia_valid
&
ATTR_MODE
)
&&
(
attr
->
ia_mode
&
~
(
S_IFREG
|
S_IFDIR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
))))
goto
out
;
/*
* Assume success and invalidate the parent's dir cache
*/
smb_invalid_dir_cache
(
dentry
->
d_parent
->
d_inode
);
if
((
attr
->
ia_valid
&
ATTR_SIZE
)
!=
0
)
{
if
((
error
=
smb_open
(
dentry
,
O_WRONLY
))
<
0
)
error
=
smb_open
(
dentry
,
O_WRONLY
);
if
(
error
)
goto
out
;
if
((
error
=
smb_proc_trunc
(
SMB_SERVER
(
inode
),
inode
->
u
.
smbfs_i
.
fileid
,
attr
->
ia_size
))
<
0
)
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_notify_change: changing %s/%s, old size=%ld, new size=%ld
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
(
long
)
inode
->
i_size
,
(
long
)
attr
->
ia_size
);
#endif
error
=
smb_proc_trunc
(
server
,
inode
->
u
.
smbfs_i
.
fileid
,
attr
->
ia_size
);
if
(
error
)
goto
out
;
/*
* We don't implement an i_op->truncate operation,
* so we have to update the page cache here.
*/
if
(
attr
->
ia_size
<
inode
->
i_size
)
{
truncate_inode_pages
(
inode
,
attr
->
ia_size
);
inode
->
i_size
=
attr
->
ia_size
;
}
refresh
=
1
;
}
if
((
attr
->
ia_valid
&
(
ATTR_CTIME
|
ATTR_MTIME
|
ATTR_ATIME
))
!=
0
)
{
struct
smb_fattr
fattr
;
fattr
.
attr
=
0
;
...
...
@@ -417,15 +514,25 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
if
((
attr
->
ia_valid
&
ATTR_ATIME
)
!=
0
)
fattr
.
f_atime
=
attr
->
ia_atime
;
error
=
smb_proc_setattr
(
SMB_SERVER
(
inode
),
dentry
,
&
fattr
);
if
(
error
>=
0
)
{
inode
->
i_ctime
=
fattr
.
f_ctime
;
inode
->
i_mtime
=
fattr
.
f_mtime
;
inode
->
i_atime
=
fattr
.
f_atime
;
}
error
=
smb_proc_setattr
(
server
,
dentry
,
&
fattr
);
if
(
error
)
goto
out
;
refresh
=
1
;
}
error
=
0
;
out:
if
(
refresh
)
{
/*
* N.B. Currently we're only using the dir cache for
* file names, so we don't need to invalidate here.
*/
#if 0
smb_invalid_dir_cache(dentry->d_parent->d_inode);
#endif
smb_refresh_inode
(
inode
);
}
return
error
;
}
...
...
@@ -461,7 +568,6 @@ init_module(void)
smb_current_vmalloced
=
0
;
#endif
smb_init_dir_cache
();
read_semaphore
=
MUTEX
;
return
init_smb_fs
();
...
...
@@ -471,7 +577,6 @@ void
cleanup_module
(
void
)
{
pr_debug
(
"smbfs: cleanup_module called
\n
"
);
smb_free_dir_cache
();
unregister_filesystem
(
&
smb_fs_type
);
#ifdef DEBUG_SMB_MALLOC
printk
(
KERN_DEBUG
"smb_malloced: %d
\n
"
,
smb_malloced
);
...
...
fs/smbfs/proc.c
View file @
f59dfe26
...
...
@@ -5,6 +5,8 @@
* Copyright (C) 1997 by Volker Lendecke
*
* 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
* 28/09/97 - Fixed smb_d_path [now smb_build_path()] to be non-recursive
* by Riccardo Facchetti
*/
#include <linux/config.h>
...
...
@@ -16,6 +18,8 @@
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/dcache.h>
#include <linux/dirent.h>
#include <asm/uaccess.h>
#include <asm/string.h>
...
...
@@ -33,8 +37,7 @@
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
static
int
smb_request_ok
(
struct
smb_sb_info
*
s
,
int
command
,
int
wct
,
int
bcc
);
void
smb_close_socket
(
struct
smb_sb_info
*
);
extern
void
smb_renew_times
(
struct
dentry
*
);
static
inline
int
min
(
int
a
,
int
b
)
...
...
@@ -64,6 +67,17 @@ str_lower(char *name)
}
}
static
void
reverse_string
(
char
*
buf
,
int
len
)
{
char
c
;
char
*
end
=
buf
+
len
-
1
;
while
(
buf
<
end
)
{
c
=
*
buf
;
*
(
buf
++
)
=
*
end
;
*
(
end
--
)
=
c
;
}
}
/*****************************************************************************/
/* */
/* Encoding/Decoding section */
...
...
@@ -85,30 +99,55 @@ smb_encode_smb_length(__u8 * p, __u32 len)
}
/*
*
Return the server for the specified dentry
*
N.B. Make this a #define in the smb header
*
smb_build_path: build the path to entry and name storing it in buf.
*
The path returned will have the trailing '\0'.
*/
static
struct
smb_sb_info
*
server_from_dentry
(
struct
dentry
*
dentry
)
static
int
smb_build_path
(
struct
dentry
*
entry
,
struct
qstr
*
name
,
char
*
buf
)
{
return
&
dentry
->
d_sb
->
u
.
smbfs_sb
;
}
char
*
path
=
buf
;
static
int
smb_d_path
(
struct
dentry
*
entry
,
char
*
buf
)
{
if
(
entry
==
NULL
)
goto
test_name_and_out
;
/*
* If IS_ROOT, we have to do no walking at all.
*/
if
(
IS_ROOT
(
entry
))
{
*
buf
=
'\\'
;
return
1
;
}
else
{
int
len
=
smb_d_path
(
entry
->
d_parent
,
buf
);
buf
+=
len
;
if
(
len
>
1
)
{
*
buf
++
=
'\\'
;
len
++
;
}
memcpy
(
buf
,
entry
->
d_name
.
name
,
entry
->
d_name
.
len
);
return
len
+
entry
->
d_name
.
len
;
*
(
path
++
)
=
'\\'
;
if
(
name
!=
NULL
)
goto
name_and_out
;
goto
out
;
}
/*
* Build the path string walking the tree backward from end to ROOT
* and store it in reversed order [see reverse_string()]
*/
for
(;;)
{
memcpy
(
path
,
entry
->
d_name
.
name
,
entry
->
d_name
.
len
);
reverse_string
(
path
,
entry
->
d_name
.
len
);
path
+=
entry
->
d_name
.
len
;
*
(
path
++
)
=
'\\'
;
entry
=
entry
->
d_parent
;
if
(
IS_ROOT
(
entry
))
break
;
}
reverse_string
(
buf
,
path
-
buf
);
test_name_and_out:
if
(
name
!=
NULL
)
{
*
(
path
++
)
=
'\\'
;
name_and_out:
memcpy
(
path
,
name
->
name
,
name
->
len
);
path
+=
name
->
len
;
}
out:
*
(
path
++
)
=
'\0'
;
return
(
path
-
buf
);
}
static
char
*
smb_encode_path
(
struct
smb_sb_info
*
server
,
char
*
buf
,
...
...
@@ -116,15 +155,7 @@ static char *smb_encode_path(struct smb_sb_info *server, char *buf,
{
char
*
start
=
buf
;
if
(
dir
!=
NULL
)
buf
+=
smb_d_path
(
dir
,
buf
);
if
(
name
!=
NULL
)
{
*
buf
++
=
'\\'
;
memcpy
(
buf
,
name
->
name
,
name
->
len
);
buf
+=
name
->
len
;
*
buf
++
=
0
;
}
buf
+=
smb_build_path
(
dir
,
name
,
buf
);
if
(
server
->
opt
.
protocol
<=
SMB_PROTOCOL_COREPLUS
)
str_upper
(
start
);
...
...
@@ -249,6 +280,55 @@ smb_verify(__u8 * packet, int command, int wct, int bcc)
(
bcc
==
-
1
||
SMB_BCC
(
packet
)
>=
bcc
))
?
0
:
-
EIO
;
}
/*
* Returns the maximum read or write size for the current packet size
* and max_xmit value.
* N.B. Since this value is usually computed before locking the server,
* the server's packet size must never be decreased!
*/
static
int
smb_get_xmitsize
(
struct
smb_sb_info
*
server
,
int
overhead
)
{
int
size
=
server
->
packet_size
;
/*
* Start with the smaller of packet size and max_xmit ...
*/
if
(
size
>
server
->
opt
.
max_xmit
)
size
=
server
->
opt
.
max_xmit
;
return
size
-
overhead
;
}
/*
* Calculate the maximum read size
*/
int
smb_get_rsize
(
struct
smb_sb_info
*
server
)
{
int
overhead
=
SMB_HEADER_LEN
+
5
*
sizeof
(
__u16
)
+
2
+
1
+
2
;
int
size
=
smb_get_xmitsize
(
server
,
overhead
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_get_rsize: packet=%d, xmit=%d, size=%d
\n
"
,
server
->
packet_size
,
server
->
opt
.
max_xmit
,
size
);
#endif
return
size
;
}
/*
* Calculate the maximum write size
*/
int
smb_get_wsize
(
struct
smb_sb_info
*
server
)
{
int
overhead
=
SMB_HEADER_LEN
+
5
*
sizeof
(
__u16
)
+
2
+
1
+
2
;
int
size
=
smb_get_xmitsize
(
server
,
overhead
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_get_wsize: packet=%d, xmit=%d, size=%d
\n
"
,
server
->
packet_size
,
server
->
opt
.
max_xmit
,
size
);
#endif
return
size
;
}
static
int
smb_errno
(
int
errcls
,
int
error
)
{
...
...
@@ -365,38 +445,6 @@ smb_unlock_server(struct smb_sb_info *server)
up
(
&
(
server
->
sem
));
}
/* smb_request_ok: We expect the server to be locked. Then we do the
request and check the answer completely. When smb_request_ok
returns 0, you can be quite sure that everything went well. When
the answer is <=0, the returned number is a valid unix errno. */
static
int
smb_request_ok
(
struct
smb_sb_info
*
s
,
int
command
,
int
wct
,
int
bcc
)
{
int
result
=
0
;
s
->
rcls
=
0
;
s
->
err
=
0
;
if
(
smb_request
(
s
)
<
0
)
{
pr_debug
(
"smb_request failed
\n
"
);
result
=
-
EIO
;
}
else
if
(
smb_valid_packet
(
s
->
packet
)
!=
0
)
{
pr_debug
(
"not a valid packet!
\n
"
);
result
=
-
EIO
;
}
else
if
(
s
->
rcls
!=
0
)
{
result
=
-
smb_errno
(
s
->
rcls
,
s
->
err
);
}
else
if
(
smb_verify
(
s
->
packet
,
command
,
wct
,
bcc
)
!=
0
)
{
pr_debug
(
"smb_verify failed
\n
"
);
result
=
-
EIO
;
}
return
result
;
}
/*
* smb_retry: This function should be called when smb_request_ok has
indicated an error. If the error was indicated because the
...
...
@@ -409,6 +457,8 @@ smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
static
int
smb_retry
(
struct
smb_sb_info
*
server
)
{
struct
wait_queue
wait
=
{
current
,
NULL
};
unsigned
long
timeout
;
int
result
=
0
;
if
(
server
->
state
!=
CONN_INVALID
)
...
...
@@ -423,31 +473,94 @@ smb_retry(struct smb_sb_info *server)
goto
out
;
}
printk
(
"smb_retry: signalling process %d
\n
"
,
server
->
conn_pid
);
kill_proc
(
server
->
conn_pid
,
SIGUSR1
,
0
);
#if 0
server->conn_pid = 0;
#endif
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_retry: signalled pid %d, waiting for new connection
\n
"
,
server
->
conn_pid
);
#endif
/*
* Block here until we get a new connection.
* N.B. This needs to be fixed ... we should wait in an
* interruptible sleep for CONN_VALID.
* Wait here for a new connection.
*/
printk
(
"smb_retry: blocking for new connection
\n
"
);
smb_lock_server
(
server
);
timeout
=
jiffies
+
10
*
HZ
;
add_wait_queue
(
&
server
->
wait
,
&
wait
);
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
HZ
;
if
(
server
->
state
!=
CONN_INVALID
)
break
;
if
(
jiffies
>
timeout
)
{
printk
(
"smb_retry: timed out, try again later
\n
"
);
break
;
}
if
(
signal_pending
(
current
))
{
printk
(
"smb_retry: caught signal
\n
"
);
break
;
}
schedule
();
}
remove_wait_queue
(
&
server
->
wait
,
&
wait
);
current
->
timeout
=
0
;
current
->
state
=
TASK_RUNNING
;
if
(
server
->
state
==
CONN_VALID
)
{
printk
(
"smb_retry: new connection pid=%d
\n
"
,
server
->
conn_pid
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_retry: new connection pid=%d
\n
"
,
server
->
conn_pid
);
#endif
result
=
1
;
}
out:
return
result
;
}
/* smb_request_ok: We expect the server to be locked. Then we do the
request and check the answer completely. When smb_request_ok
returns 0, you can be quite sure that everything went well. When
the answer is <=0, the returned number is a valid unix errno. */
static
int
smb_request_ok
(
struct
smb_sb_info
*
s
,
int
command
,
int
wct
,
int
bcc
)
{
int
result
=
0
;
s
->
rcls
=
0
;
s
->
err
=
0
;
/* Make sure we have a connection */
if
(
s
->
state
!=
CONN_VALID
&&
!
smb_retry
(
s
))
{
result
=
-
EIO
;
}
else
if
(
smb_request
(
s
)
<
0
)
{
pr_debug
(
"smb_request failed
\n
"
);
result
=
-
EIO
;
}
else
if
(
smb_valid_packet
(
s
->
packet
)
!=
0
)
{
pr_debug
(
"not a valid packet!
\n
"
);
result
=
-
EIO
;
}
else
if
(
s
->
rcls
!=
0
)
{
result
=
-
smb_errno
(
s
->
rcls
,
s
->
err
);
}
else
if
(
smb_verify
(
s
->
packet
,
command
,
wct
,
bcc
)
!=
0
)
{
pr_debug
(
"smb_verify failed
\n
"
);
result
=
-
EIO
;
}
return
result
;
}
/*
* This is called with the server locked after a successful smb_newconn().
* It installs the new connection pid, sets server->state to CONN_VALID,
* and
unlocks the server
.
* and
wakes up the process waiting for the new connection
.
* N.B. The first call is made without locking the server -- need to fix!
*/
int
...
...
@@ -458,21 +571,24 @@ smb_offerconn(struct smb_sb_info *server)
error
=
-
EACCES
;
if
(
!
suser
()
&&
(
current
->
uid
!=
server
->
m
.
mounted_uid
))
goto
out
;
if
(
atomic_read
(
&
server
->
sem
.
count
)
==
1
)
{
printk
(
"smb_offerconn: server not locked, count=%d
\n
"
,
atomic_read
(
&
server
->
sem
.
count
));
#if 0
goto out;
#endif
}
server
->
conn_pid
=
current
->
pid
;
server
->
state
=
CONN_VALID
;
printk
(
"smb_offerconn: state valid, pid=%d
\n
"
,
server
->
conn_pid
);
wake_up_interruptible
(
&
server
->
wait
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_offerconn: state valid, pid=%d
\n
"
,
server
->
conn_pid
);
#endif
error
=
0
;
/*
* The initial call may be made without the server locked?
*/
out:
if
(
atomic_read
(
&
server
->
sem
.
count
)
!=
1
)
smb_unlock_server
(
server
);
else
printk
(
"smb_offerconn: server not locked, count=%d
\n
"
,
atomic_read
(
&
server
->
sem
.
count
));
return
error
;
}
...
...
@@ -488,15 +604,21 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
error
=
-
EBADF
;
if
(
opt
->
fd
>=
NR_OPEN
||
!
(
filp
=
current
->
files
->
fd
[
opt
->
fd
]))
goto
out_unlock
;
if
(
!
S_ISSOCK
(
filp
->
f_dentry
->
d_inode
->
i_mode
))
goto
out_unlock
;
if
(
!
S_ISSOCK
(
filp
->
f_dentry
->
d_inode
->
i_mode
))
goto
out_unlock
;
goto
out
;
if
(
!
smb_valid_socket
(
filp
->
f_dentry
->
d_inode
))
goto
out
;
error
=
-
EACCES
;
if
(
!
suser
()
&&
(
current
->
uid
!=
server
->
m
.
mounted_uid
))
goto
out_unlock
;
goto
out
;
if
(
atomic_read
(
&
server
->
sem
.
count
)
==
1
)
{
printk
(
"smb_newconn: server not locked, count=%d
\n
"
,
atomic_read
(
&
server
->
sem
.
count
));
#if 0
goto out;
#endif
}
/*
* Make sure the old socket is closed
...
...
@@ -507,23 +629,15 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
server
->
sock_file
=
filp
;
smb_catch_keepalive
(
server
);
server
->
opt
=
*
opt
;
pr_debug
(
"smb_newconn: protocol = %d
\n
"
,
server
->
opt
.
protocol
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_newconn: protocol=%d, max_xmit=%d
\n
"
,
server
->
opt
.
protocol
,
server
->
opt
.
max_xmit
);
#endif
server
->
generation
+=
1
;
error
=
0
;
out:
return
error
;
/*
* Unlock now if an error occurred.
*/
out_unlock:
if
(
atomic_read
(
&
server
->
sem
.
count
)
!=
1
)
smb_unlock_server
(
server
);
else
printk
(
"smb_newconn: server not locked, count=%d
\n
"
,
atomic_read
(
&
server
->
sem
.
count
));
goto
out
;
}
/* smb_setup_header: We completely set up the packet. You only have to
...
...
@@ -536,6 +650,10 @@ smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc
__u8
*
p
=
server
->
packet
;
__u8
*
buf
=
server
->
packet
;
if
(
xmit_len
>
server
->
packet_size
)
printk
(
"smb_setup_header: Aieee, xmit len > packet! len=%d, size=%d
\n
"
,
xmit_len
,
server
->
packet_size
);
p
=
smb_encode_smb_length
(
p
,
xmit_len
-
4
);
*
p
++
=
0xff
;
...
...
@@ -577,92 +695,106 @@ smb_setup_bcc(struct smb_sb_info *server, __u8 * p)
}
/*
* We're called with the server locked, and we leave it that way.
We
*
try maximum permission
s.
* We're called with the server locked, and we leave it that way.
*
Set the permissions to be consistent with the desired acces
s.
*/
static
int
smb_proc_open
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
)
smb_proc_open
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
int
wish
)
{
struct
inode
*
ino
=
dir
->
d_inode
;
int
mode
,
read_write
=
0x42
,
read_only
=
0x40
;
int
error
;
char
*
p
;
mode
=
read_write
;
#if 0
if (!(wish & (O_WRONLY | O_RDWR)))
mode = read_only;
#endif
retry:
p
=
smb_setup_header
(
server
,
SMBopen
,
2
,
0
);
WSET
(
server
->
packet
,
smb_vwv0
,
0x42
);
/* read/write */
WSET
(
server
->
packet
,
smb_vwv0
,
mode
);
WSET
(
server
->
packet
,
smb_vwv1
,
aSYSTEM
|
aHIDDEN
|
aDIR
);
*
p
++
=
4
;
p
=
smb_encode_path
(
server
,
p
,
dir
,
NULL
);
smb_setup_bcc
(
server
,
p
);
if
((
error
=
smb_request_ok
(
server
,
SMBopen
,
7
,
0
))
!=
0
)
error
=
smb_request_ok
(
server
,
SMBopen
,
7
,
0
);
if
(
error
!=
0
)
{
if
(
smb_retry
(
server
))
goto
retry
;
if
((
error
!=
-
EACCES
)
&&
(
error
!=
-
ETXTBSY
)
&&
(
error
!=
-
EROFS
))
goto
out
;
p
=
smb_setup_header
(
server
,
SMBopen
,
2
,
0
);
WSET
(
server
->
packet
,
smb_vwv0
,
0x40
);
/* read only */
WSET
(
server
->
packet
,
smb_vwv1
,
aSYSTEM
|
aHIDDEN
|
aDIR
);
*
p
++
=
4
;
p
=
smb_encode_path
(
server
,
p
,
dir
,
NULL
);
smb_setup_bcc
(
server
,
p
);
if
((
error
=
smb_request_ok
(
server
,
SMBopen
,
7
,
0
))
!=
0
)
if
(
mode
==
read_write
&&
(
error
==
-
EACCES
||
error
==
-
ETXTBSY
||
error
==
-
EROFS
))
{
if
(
smb_retry
(
server
))
goto
retry
;
goto
out
;
#ifdef SMBFS_PARANOIA
printk
(
"smb_proc_open: %s/%s open failed, error=%d, retrying R/O
\n
"
,
dir
->
d_parent
->
d_name
.
name
,
dir
->
d_name
.
name
,
error
);
#endif
mode
=
read_only
;
goto
retry
;
}
}
/* We should now have data in vwv[0..6]. */
ino
->
u
.
smbfs_i
.
fileid
=
WVAL
(
server
->
packet
,
smb_vwv0
);
ino
->
u
.
smbfs_i
.
attr
=
WVAL
(
server
->
packet
,
smb_vwv1
);
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
ino
->
u
.
smbfs_i
.
access
=
WVAL
(
server
->
packet
,
smb_vwv6
);
ino
->
u
.
smbfs_i
.
access
&=
3
;
/* N.B. Suppose the open failed?? */
ino
->
u
.
smbfs_i
.
open
=
server
->
generation
;
pr_debug
(
"smb_proc_open: entry->access = %d
\n
"
,
ino
->
u
.
smbfs_i
.
access
);
out:
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_open: error=%d, access=%d
\n
"
,
error
,
ino
->
u
.
smbfs_i
.
access
);
#endif
return
error
;
}
int
smb_open
(
struct
dentry
*
d
ir
,
int
wish
)
smb_open
(
struct
dentry
*
d
entry
,
int
wish
)
{
struct
inode
*
i
=
d
ir
->
d_inode
;
struct
inode
*
i
=
d
entry
->
d_inode
;
int
result
;
result
=
-
E
IO
;
result
=
-
E
NOENT
;
if
(
!
i
)
{
printk
(
"smb_open: no inode for dentry %s/%s
\n
"
,
d
ir
->
d_parent
->
d_name
.
name
,
dir
->
d_name
.
name
);
d
entry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
goto
out
;
}
/*
* If the inode is already open, we don't need to lock the server.
* Note: If the caller holds an active dentry and the file is
* currently open, we can be sure that the file isn't about
* to be closed. (See smb_close_dentry() below.)
*/
if
(
!
smb_is_open
(
i
))
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
i
);
smb_lock_server
(
server
);
result
=
smb_proc_open
(
server
,
dir
);
result
=
0
;
if
(
!
smb_is_open
(
i
))
result
=
smb_proc_open
(
server
,
dentry
,
wish
);
smb_unlock_server
(
server
);
if
(
result
)
{
printk
(
"smb_open: %s/%s open failed, result=%d
\n
"
,
dir
->
d_parent
->
d_name
.
name
,
dir
->
d_name
.
name
,
result
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_open: %s/%s open failed, result=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
result
);
#endif
goto
out
;
}
/*
* A successful open means the path is still valid ...
*/
smb_renew_times
(
dentry
);
}
result
=
-
EACCES
;
...
...
@@ -679,15 +811,35 @@ smb_open(struct dentry *dir, int wish)
/* We're called with the server locked */
static
int
smb_proc_close
(
struct
smb_sb_info
*
server
,
__u16
fileid
,
__u32
mtime
)
static
int
smb_proc_close
(
struct
smb_sb_info
*
server
,
__u16
fileid
,
__u32
mtime
)
{
smb_setup_header
(
server
,
SMBclose
,
3
,
0
);
WSET
(
server
->
packet
,
smb_vwv0
,
fileid
);
DSET
(
server
->
packet
,
smb_vwv1
,
mtime
);
DSET
(
server
->
packet
,
smb_vwv1
,
utc2local
(
mtime
)
);
return
smb_request_ok
(
server
,
SMBclose
,
0
,
0
);
}
/*
* Called with the server locked
*/
static
int
smb_proc_close_inode
(
struct
smb_sb_info
*
server
,
struct
inode
*
ino
)
{
int
result
=
0
;
if
(
smb_is_open
(
ino
))
{
/*
* We clear the open flag in advance, in case another
* process observes the value while we block below.
*/
ino
->
u
.
smbfs_i
.
open
=
0
;
result
=
smb_proc_close
(
server
,
ino
->
u
.
smbfs_i
.
fileid
,
ino
->
i_mtime
);
}
return
result
;
}
int
smb_close
(
struct
inode
*
ino
)
{
...
...
@@ -697,39 +849,66 @@ smb_close(struct inode *ino)
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
ino
);
smb_lock_server
(
server
);
result
=
smb_proc_close
(
server
,
ino
->
u
.
smbfs_i
.
fileid
,
ino
->
i_mtime
);
result
=
smb_proc_close_inode
(
server
,
ino
);
smb_unlock_server
(
server
);
ino
->
u
.
smbfs_i
.
open
=
0
;
}
return
result
;
}
/*
* This routine is called from dput() when d_count is going to 0.
* We use this to close the file so that cached dentries don't
* keep too many files open.
*
* There are some tricky race conditions here: the dentry may go
* back into use while we're closing the file, and we don't want
* the new user to be confused as to the open status.
*/
void
smb_close_dentry
(
struct
dentry
*
dentry
)
{
struct
inode
*
ino
=
dentry
->
d_inode
;
if
(
ino
)
{
if
(
smb_is_open
(
ino
))
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
ino
);
smb_lock_server
(
server
);
/*
* Check whether the dentry is back in use.
*/
if
(
dentry
->
d_count
<=
1
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_close_dentry: closing %s/%s, count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
);
#endif
smb_proc_close_inode
(
server
,
ino
);
}
smb_unlock_server
(
server
);
}
}
/* Consider dropping negative dentries? */
#if 0
else
d_drop(dentry);
#endif
}
/* In smb_proc_read and smb_proc_write we do not retry, because the
file-id would not be valid after a reconnection. */
/* smb_proc_read: fs indicates if it should be copied with
copy_to_user. */
int
smb_proc_read
(
struct
inode
*
ino
,
off_t
offset
,
long
count
,
char
*
data
)
smb_proc_read
(
struct
inode
*
ino
,
off_t
offset
,
int
count
,
char
*
data
)
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
ino
);
__u16
returned_count
,
data_len
;
char
*
buf
;
int
result
;
struct
dentry
*
dentry
;
if
(
!
ino
||
!
(
dentry
=
ino
->
u
.
smbfs_i
.
dentry
))
{
printk
(
"smb_proc_read: no inode!
\n
"
);
return
-
EIO
;
}
smb_lock_server
(
server
);
smb_setup_header
(
server
,
SMBread
,
5
,
0
);
/* Achtung! Do not refer to the cached packet after the request! */
buf
=
server
->
packet
;
WSET
(
buf
,
smb_vwv0
,
ino
->
u
.
smbfs_i
.
fileid
);
WSET
(
buf
,
smb_vwv1
,
count
);
...
...
@@ -739,10 +918,6 @@ smb_proc_read(struct inode *ino, off_t offset, long count, char *data)
result
=
smb_request_ok
(
server
,
SMBread
,
5
,
-
1
);
if
(
result
<
0
)
goto
out
;
#if 0
printk("smb_proc_read: file %s/%s, result=%d, packet=%p\n",
dentry->d_parent->d_name.name, dentry->d_name.name, result, server->packet);
#endif
returned_count
=
WVAL
(
server
->
packet
,
smb_vwv0
);
buf
=
SMB_BUF
(
server
->
packet
);
...
...
@@ -758,6 +933,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result, server->packet);
result
=
data_len
;
out:
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_read: file %s/%s, count=%d, result=%d
\n
"
,
((
struct
dentry
*
)
ino
->
u
.
smbfs_i
.
dentry
)
->
d_parent
->
d_name
.
name
,
((
struct
dentry
*
)
ino
->
u
.
smbfs_i
.
dentry
)
->
d_name
.
name
,
count
,
result
);
#endif
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -766,10 +946,17 @@ int
smb_proc_write
(
struct
inode
*
ino
,
off_t
offset
,
int
count
,
const
char
*
data
)
{
struct
smb_sb_info
*
server
=
SMB_SERVER
(
ino
);
int
res
=
0
;
int
res
ult
;
__u8
*
p
;
smb_lock_server
(
server
);
#if SMBFS_DEBUG_VERBOSE
{
struct
dentry
*
dentry
=
ino
->
u
.
smbfs_i
.
dentry
;
printk
(
"smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
count
,
offset
,
server
->
packet_size
);
}
#endif
p
=
smb_setup_header
(
server
,
SMBwrite
,
5
,
count
+
3
);
WSET
(
server
->
packet
,
smb_vwv0
,
ino
->
u
.
smbfs_i
.
fileid
);
WSET
(
server
->
packet
,
smb_vwv1
,
count
);
...
...
@@ -780,12 +967,12 @@ smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
WSET
(
p
,
0
,
count
);
memcpy
(
p
+
2
,
data
,
count
);
if
((
res
=
smb_request_ok
(
server
,
SMBwrite
,
1
,
0
))
>=
0
)
res
=
WVAL
(
server
->
packet
,
smb_vwv0
);
if
((
res
ult
=
smb_request_ok
(
server
,
SMBwrite
,
1
,
0
))
>=
0
)
res
ult
=
WVAL
(
server
->
packet
,
smb_vwv0
);
smb_unlock_server
(
server
);
return
res
;
return
res
ult
;
}
int
...
...
@@ -1003,50 +1190,46 @@ smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
smb_init_dirent
(
server
,
fattr
);
fattr
->
attr
=
aDIR
;
fattr
->
f_ino
=
1
;
fattr
->
f_mtime
=
CURRENT_TIME
;
smb_finish_dirent
(
server
,
fattr
);
}
static
__u8
*
smb_decode_dirent
(
struct
smb_sb_info
*
server
,
__u8
*
p
,
struct
smb_dirent
*
entry
)
smb_decode_dirent
(
struct
smb_sb_info
*
server
,
__u8
*
p
,
struct
dirent
*
entry
)
{
smb_init_dirent
(
server
,
&
(
entry
->
attr
))
;
int
len
;
p
+=
SMB_STATUS_SIZE
;
/* reserved (search_status) */
entry
->
attr
.
attr
=
*
p
;
entry
->
attr
.
f_mtime
=
entry
->
attr
.
f_atime
=
entry
->
attr
.
f_ctime
=
date_dos2unix
(
WVAL
(
p
,
1
),
WVAL
(
p
,
3
));
entry
->
attr
.
f_size
=
DVAL
(
p
,
5
);
entry
->
len
=
strlen
(
p
+
9
);
if
(
entry
->
len
>
12
)
{
entry
->
len
=
12
;
}
memcpy
(
entry
->
name
,
p
+
9
,
entry
->
len
);
entry
->
name
[
entry
->
len
]
=
'\0'
;
while
(
entry
->
len
>
2
)
len
=
strlen
(
p
+
9
);
if
(
len
>
12
)
{
/* Pathworks fills names with spaces */
entry
->
len
-=
1
;
if
(
entry
->
name
[
entry
->
len
]
==
' '
)
{
entry
->
name
[
entry
->
len
]
=
'\0'
;
}
len
=
12
;
}
memcpy
(
entry
->
d_name
,
p
+
9
,
len
);
#ifdef SMBFS_TRIM_BLANKS
/*
* Trim trailing blanks for Pathworks servers
*/
while
(
len
>
2
&&
entry
->
d_name
[
len
-
1
]
==
' '
)
len
--
;
#endif
entry
->
d_name
[
len
]
=
'\0'
;
entry
->
d_reclen
=
len
;
entry
->
d_ino
=
0
;
/* no inode number available */
switch
(
server
->
opt
.
case_handling
)
{
case
SMB_CASE_UPPER
:
str_upper
(
entry
->
name
);
str_upper
(
entry
->
d_
name
);
break
;
case
SMB_CASE_LOWER
:
str_lower
(
entry
->
name
);
str_lower
(
entry
->
d_
name
);
break
;
default:
break
;
}
pr_debug
(
"smb_decode_dirent: name = %s
\n
"
,
entry
->
name
);
smb_finish_dirent
(
server
,
&
(
entry
->
attr
));
return
p
+
22
;
}
...
...
@@ -1056,50 +1239,43 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
static
int
smb_proc_readdir_short
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
int
fpos
,
int
cache_size
,
struct
smb_dirent
*
entry
)
void
*
cachep
)
{
char
*
p
;
char
*
buf
;
int
error
;
int
result
;
int
i
;
int
first
,
total_count
;
struct
smb_dirent
*
current_entry
;
int
i
,
first
,
entries_seen
,
entries
;
int
entries_asked
=
(
server
->
opt
.
max_xmit
-
100
)
/
SMB_DIRINFO_SIZE
;
__u16
bcc
;
__u16
count
;
char
status
[
SMB_STATUS_SIZE
];
int
entries_asked
=
(
server
->
opt
.
max_xmit
-
100
)
/
SMB_DIRINFO_SIZE
;
static
struct
qstr
mask
=
{
"*.*"
,
3
,
0
};
pr_debug
(
"
SMB call readdir
%d @ %d
\n
"
,
cache_size
,
fpos
);
pr_debug
(
"
smb_proc_readdir_short:
%d @ %d
\n
"
,
cache_size
,
fpos
);
smb_lock_server
(
server
);
/* N.B. We need to reinitialize the cache to restart */
retry:
smb_init_dircache
(
cachep
);
first
=
1
;
total_count
=
0
;
current_entry
=
entry
;
entries
=
0
;
entries_seen
=
2
;
/* implicit . and .. */
while
(
1
)
{
buf
=
server
->
packet
;
p
=
smb_setup_header
(
server
,
SMBsearch
,
2
,
0
);
WSET
(
server
->
packet
,
smb_vwv0
,
entries_asked
);
WSET
(
server
->
packet
,
smb_vwv1
,
aDIR
);
*
p
++
=
4
;
if
(
first
==
1
)
{
p
=
smb_setup_header
(
server
,
SMBsearch
,
2
,
0
);
WSET
(
buf
,
smb_vwv0
,
entries_asked
);
WSET
(
buf
,
smb_vwv1
,
aDIR
);
*
p
++
=
4
;
p
=
smb_encode_path
(
server
,
p
,
dir
,
&
mask
);
*
p
++
=
5
;
WSET
(
p
,
0
,
0
);
p
+=
2
;
first
=
0
;
}
else
{
p
=
smb_setup_header
(
server
,
SMBsearch
,
2
,
0
);
WSET
(
buf
,
smb_vwv0
,
entries_asked
);
WSET
(
buf
,
smb_vwv1
,
aDIR
);
*
p
++
=
4
;
*
p
++
=
0
;
*
p
++
=
5
;
WSET
(
p
,
0
,
SMB_STATUS_SIZE
);
...
...
@@ -1110,39 +1286,25 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
smb_setup_bcc
(
server
,
p
);
if
((
error
=
smb_request_ok
(
server
,
SMBsearch
,
1
,
-
1
))
<
0
)
result
=
smb_request_ok
(
server
,
SMBsearch
,
1
,
-
1
);
if
(
result
<
0
)
{
if
((
server
->
rcls
==
ERRDOS
)
&&
(
server
->
err
==
ERRnofiles
))
{
result
=
total_count
-
fpos
;
goto
unlock_return
;
}
else
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
result
=
error
;
goto
unlock_return
;
}
if
((
server
->
rcls
==
ERRDOS
)
&&
(
server
->
err
==
ERRnofiles
))
break
;
if
(
smb_retry
(
server
))
goto
retry
;
goto
unlock_return
;
}
p
=
SMB_VWV
(
server
->
packet
);
count
=
WVAL
(
p
,
0
);
bcc
=
WVAL
(
p
,
2
);
first
=
0
;
if
(
count
<=
0
)
{
result
=
total_count
-
fpos
;
goto
unlock_return
;
}
break
;
result
=
-
EIO
;
bcc
=
WVAL
(
p
,
2
);
if
(
bcc
!=
count
*
SMB_DIRINFO_SIZE
+
3
)
{
result
=
-
EIO
;
goto
unlock_return
;
}
p
+=
7
;
/* Read the last entry into the status field. */
...
...
@@ -1155,102 +1317,125 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
(
total_count
<
fpos
)
{
p
+=
SMB_DIRINFO_SIZE
;
pr_debug
(
"smb_proc_readdir: skipped entry.
\n
"
);
pr_debug
(
" total_count = %d
\n
"
" i = %d, fpos = %d
\n
"
,
total_count
,
i
,
fpos
);
}
else
if
(
total_count
>=
fpos
+
cache_size
)
struct
dirent
this_ent
,
*
entry
=
&
this_ent
;
p
=
smb_decode_dirent
(
server
,
p
,
entry
);
if
(
entries_seen
==
2
&&
entry
->
d_name
[
0
]
==
'.'
)
{
result
=
total_count
-
fpos
;
goto
unlock_return
;
}
else
if
(
entry
->
d_reclen
==
1
)
continue
;
if
(
entry
->
d_name
[
1
]
==
'.'
&&
entry
->
d_reclen
==
2
)
continue
;
}
if
(
entries_seen
>=
fpos
)
{
p
=
smb_decode_dirent
(
server
,
p
,
current_entry
);
current_entry
->
f_pos
=
total_count
;
pr_debug
(
"smb_proc_readdir: entry->f_pos = "
"%u
\n
"
,
entry
->
f_pos
);
current_entry
+=
1
;
pr_debug
(
"smb_proc_readdir: fpos=%u
\n
"
,
entries_seen
);
smb_add_to_cache
(
cachep
,
entry
,
entries_seen
);
entries
++
;
}
total_count
+=
1
;
#ifdef SMBFS_DEBUG_VERBOSE
else
printk
(
"smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d
\n
"
,
entries_seen
,
i
,
fpos
);
#endif
entries_seen
++
;
}
}
unlock_return:
result
=
entries
;
unlock_return:
smb_unlock_server
(
server
);
return
result
;
}
/* interpret a long filename structure - this is mostly guesses at the
moment. The length of the structure is returned. The structure of
a long filename depends on the info level. 260 is used by NT and 2
is used by OS/2. */
/*
* Interpret a long filename structure using the specified info level:
* level 1 -- Win NT, Win 95, OS/2
* level 2 -- OS/2
* level 259 -- File name and length only, Win NT, Win 95
* level 260 -- Win NT, Win 95
* There seem to be numerous inconsistencies and bugs in implementation.
*/
static
char
*
smb_decode_long_dirent
(
struct
smb_sb_info
*
server
,
char
*
p
,
struct
smb_
dirent
*
entry
,
int
level
)
struct
dirent
*
entry
,
int
level
)
{
char
*
result
;
unsigned
int
len
;
smb_init_dirent
(
server
,
&
(
entry
->
attr
));
/*
* SMB doesn't have a concept of inode numbers ...
*/
entry
->
d_ino
=
0
;
switch
(
level
)
{
/* We might add more levels later... */
case
1
:
entry
->
attr
.
f_ctime
=
date_dos2unix
(
WVAL
(
p
,
6
),
WVAL
(
p
,
4
));
entry
->
attr
.
f_atime
=
date_dos2unix
(
WVAL
(
p
,
10
),
WVAL
(
p
,
8
));
entry
->
attr
.
f_mtime
=
date_dos2unix
(
WVAL
(
p
,
14
),
WVAL
(
p
,
12
));
entry
->
attr
.
f_size
=
DVAL
(
p
,
16
);
entry
->
attr
.
attr
=
*
(
p
+
24
);
/*
* Achtung, lengths can go up to 255
*/
len
=
*
((
unsigned
char
*
)
p
+
26
);
entry
->
len
=
len
;
strncpy
(
entry
->
name
,
p
+
27
,
len
);
entry
->
name
[
len
]
=
'\0'
;
entry
->
d_rec
len
=
len
;
strncpy
(
entry
->
d_
name
,
p
+
27
,
len
);
entry
->
d_
name
[
len
]
=
'\0'
;
result
=
p
+
28
+
len
;
break
;
case
259
:
/* SMB_FIND_FILE_NAMES_INFO = 0x103 */
/*
* This info level returns just the file name and length,
* which is all we need right now.
*/
result
=
p
+
DVAL
(
p
,
0
);
/* DVAL(p, 4) should be resume key? Seems to be 0 .. */
len
=
DVAL
(
p
,
8
);
if
(
len
>
255
)
len
=
255
;
strncpy
(
entry
->
d_name
,
p
+
12
,
len
);
/*
* Kludge alert: Win NT 4.0 adds a trailing null byte and
* counts it in the name length, but Win 95 doesn't. Hence
* we test for a trailing null and decrement the length ...
*/
if
(
len
&&
entry
->
d_name
[
len
-
1
]
==
'\0'
)
len
--
;
entry
->
d_name
[
len
]
=
'\0'
;
entry
->
d_reclen
=
len
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_decode_long_dirent: info 259, len=%d, name=%s
\n
"
,
len
,
entry
->
d_name
);
#endif
break
;
default:
printk
(
"smb_decode
: Unknown long filename format
%d
\n
"
,
level
);
printk
(
"smb_decode
_long_dirent: Unknown level
%d
\n
"
,
level
);
result
=
p
+
WVAL
(
p
,
0
);
}
switch
(
server
->
opt
.
case_handling
)
{
case
SMB_CASE_UPPER
:
str_upper
(
entry
->
name
);
str_upper
(
entry
->
d_
name
);
break
;
case
SMB_CASE_LOWER
:
str_lower
(
entry
->
name
);
str_lower
(
entry
->
d_
name
);
break
;
default:
break
;
}
smb_finish_dirent
(
server
,
&
(
entry
->
attr
));
return
result
;
}
static
int
smb_proc_readdir_long
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
int
fpos
,
int
cache_size
,
struct
smb_dirent
*
cache
)
void
*
cachep
)
{
/*
NT uses 260, OS/2 uses 2. Both accept 1
. */
const
int
info_level
=
1
;
/*
Both NT and OS/2 accept info level 1 (but see note below)
. */
int
info_level
=
1
;
const
int
max_matches
=
512
;
char
*
p
;
char
*
lastname
;
unsigned
lastname_len
;
int
i
;
char
*
p
,
*
mask
,
*
lastname
;
int
first
,
entries
,
entries_seen
;
unsigned
char
*
resp_data
=
NULL
;
...
...
@@ -1260,36 +1445,45 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
__u16
command
;
int
result
;
int
ff_resume_key
=
0
;
int
ff_resume_key
=
0
;
/* this isn't being used */
int
ff_searchcount
=
0
;
int
ff_eos
=
0
;
int
ff_lastname
=
0
;
int
ff_dir_handle
=
0
;
int
loop_count
=
0
;
int
mask_len
,
i
,
result
;
char
param
[
SMB_MAXPATHLEN
+
2
+
12
];
/* too long for the stack! */
int
mask_len
;
char
*
mask
=
&
(
param
[
12
]);
char
param
[
12
+
SMB_MAXPATHLEN
+
2
];
/* too long for the stack! */
static
struct
qstr
star
=
{
"*"
,
1
,
0
};
mask_len
=
smb_encode_path
(
server
,
mask
,
dir
,
&
star
)
-
mask
;
mask
[
mask_len
]
=
0
;
mask
[
mask_len
+
1
]
=
0
;
pr_debug
(
"smb_readdir_long cache=%d, fpos=%d, mask=%s
\n
"
,
cache_size
,
fpos
,
mask
);
/*
* Check whether to change the info level. There appears to be
* a bug in Win NT 4.0's handling of info level 1, whereby it
* truncates the directory scan for certain patterns of files.
* Hence we use level 259 for NT. (Win 95 uses this too?)
*/
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_NT1
)
info_level
=
259
;
smb_lock_server
(
server
);
retry:
/*
* Encode the initial path
*/
mask
=
&
(
param
[
12
]);
mask_len
=
smb_encode_path
(
server
,
mask
,
dir
,
&
star
)
-
mask
;
first
=
1
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_readdir_long: starting fpos=%d, mask=%s
\n
"
,
fpos
,
mask
);
#endif
/*
* We must reinitialize the dircache when retrying.
*/
smb_init_dircache
(
cachep
);
entries
=
0
;
entries_seen
=
2
;
ff_eos
=
0
;
while
(
ff_eos
==
0
)
{
...
...
@@ -1301,6 +1495,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
entries
=
-
EIO
;
break
;
}
if
(
first
!=
0
)
{
command
=
TRANSACT2_FINDFIRST
;
...
...
@@ -1314,10 +1509,11 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
}
else
{
command
=
TRANSACT2_FINDNEXT
;
pr_debug
(
"hand=0x%X resume=%d ff_lastnm=%d mask=%s
\n
"
,
ff_dir_handle
,
ff_resume_key
,
ff_lastname
,
mask
);
WSET
(
param
,
0
,
ff_dir_handle
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_readdir_long: handle=0x%X, resume=%d, lastname=%d, mask=%s
\n
"
,
ff_dir_handle
,
ff_resume_key
,
ff_lastname
,
mask
);
#endif
WSET
(
param
,
0
,
ff_dir_handle
);
/* search handle */
WSET
(
param
,
2
,
max_matches
);
/* max count */
WSET
(
param
,
4
,
info_level
);
DSET
(
param
,
6
,
ff_resume_key
);
/* ff_resume_key */
...
...
@@ -1335,7 +1531,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
}
result
=
smb_trans2_request
(
server
,
command
,
0
,
NULL
,
12
+
mask_len
+
2
,
param
,
0
,
NULL
,
12
+
mask_len
+
1
,
param
,
&
resp_data_len
,
&
resp_data
,
&
resp_param_len
,
&
resp_param
);
...
...
@@ -1343,10 +1539,13 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
{
if
(
smb_retry
(
server
))
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_proc_readdir_long: error=%d, retrying
\n
"
,
result
);
#endif
goto
retry
;
}
#ifdef SMBFS_PARANOIA
printk
(
"smb_proc_readdir_long:
trans2_request error=%d
\n
"
,
result
);
printk
(
"smb_proc_readdir_long:
error=%d, breaking
\n
"
,
result
);
#endif
entries
=
result
;
break
;
...
...
@@ -1354,13 +1553,17 @@ printk("smb_proc_readdir_long: trans2_request error=%d\n", result);
if
(
server
->
rcls
!=
0
)
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_proc_readdir_long:
error, rcls=%d, err=%d
\n
"
,
printk
(
"smb_proc_readdir_long:
rcls=%d, err=%d, breaking
\n
"
,
server
->
rcls
,
server
->
err
);
#endif
/* Why isn't this considered an error? */
/* entries = -EIO; */
entries
=
-
smb_errno
(
server
->
rcls
,
server
->
err
);
break
;
}
#ifdef SMBFS_PARANOIA
if
(
resp_data
+
resp_data_len
>
server
->
packet
+
server
->
packet_size
)
printk
(
"s_p_r_l: data past packet end! data=%p, len=%d, packet=%p
\n
"
,
resp_data
+
resp_data_len
,
resp_data_len
,
server
->
packet
+
server
->
packet_size
);
#endif
/* parse out some important return info */
if
(
first
!=
0
)
...
...
@@ -1380,86 +1583,90 @@ server->rcls, server->err);
{
break
;
}
/* point to the data bytes */
p
=
resp_data
;
/* we might need the lastname for continuations */
lastname
=
""
;
lastname_len
=
0
;
mask_len
=
0
;
if
(
ff_lastname
>
0
)
{
ff_resume_key
=
0
;
lastname
=
p
+
ff_lastname
;
lastname
=
resp_data
+
ff_lastname
;
switch
(
info_level
)
{
case
260
:
lastname_len
=
resp_data_len
-
ff_lastname
;
if
(
ff_lastname
<
resp_data_len
)
mask_len
=
resp_data_len
-
ff_lastname
;
break
;
case
1
:
lastname_len
=
*
((
unsigned
char
*
)
lastname
++
);
/* Win NT 4.0 doesn't set the length byte */
lastname
++
;
if
(
ff_lastname
+
2
<
resp_data_len
)
mask_len
=
strlen
(
lastname
);
break
;
}
/*
* Update the mask string for the next message.
*/
if
(
mask_len
>
255
)
mask_len
=
255
;
if
(
mask_len
)
strncpy
(
mask
,
lastname
,
mask_len
);
ff_resume_key
=
0
;
}
lastname_len
=
min
(
lastname_len
,
256
);
strncpy
(
mask
,
lastname
,
lastname_len
);
mask
[
lastname_len
]
=
'\0'
;
mask
[
mask_len
]
=
0
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_readdir_long: new mask, len=%d@%d, mask=%s
\n
"
,
mask_len
,
ff_lastname
,
mask
);
#endif
/* Now we are ready to parse smb directory entries. */
/* point to the data bytes */
p
=
resp_data
;
for
(
i
=
0
;
i
<
ff_searchcount
;
i
++
)
{
struct
smb_dirent
*
entry
=
&
(
cache
[
entries
])
;
struct
dirent
this_ent
,
*
entry
=
&
this_ent
;
p
=
smb_decode_long_dirent
(
server
,
p
,
entry
,
info_level
);
p
=
smb_decode_long_dirent
(
server
,
p
,
entry
,
info_level
);
pr_debug
(
"smb_readdir_long: got %s
\n
"
,
entry
->
name
);
if
((
entry
->
name
[
0
]
==
'.'
)
&&
((
entry
->
name
[
1
]
==
'\0'
)
||
((
entry
->
name
[
1
]
==
'.'
)
&&
(
entry
->
name
[
2
]
==
'\0'
))))
/* ignore . and .. from the server */
if
(
entries_seen
==
2
&&
entry
->
d_name
[
0
]
==
'.'
)
{
/* ignore . and .. from the server */
continue
;
if
(
entry
->
d_reclen
==
1
)
continue
;
if
(
entry
->
d_name
[
1
]
==
'.'
&&
entry
->
d_reclen
==
2
)
continue
;
}
if
(
entries_seen
>=
fpos
)
{
entry
->
f_pos
=
entries_seen
;
smb_add_to_cache
(
cachep
,
entry
,
entries_seen
)
;
entries
+=
1
;
}
entries_seen
+=
1
;
if
(
entries
<
cache_size
)
continue
;
/* cache is full */
goto
finished
;
entries_seen
++
;
}
pr_debug
(
"received %d entries (eos=%d resume=%d)
\n
"
,
ff_searchcount
,
ff_eos
,
ff_resume_key
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_readdir_long: received %d entries, eos=%d, resume=%d
\n
"
,
ff_searchcount
,
ff_eos
,
ff_resume_key
);
#endif
first
=
0
;
}
finished:
smb_unlock_server
(
server
);
return
entries
;
}
int
smb_proc_readdir
(
struct
dentry
*
dir
,
int
fpos
,
int
cache_size
,
struct
smb_dirent
*
entry
)
smb_proc_readdir
(
struct
dentry
*
dir
,
int
fpos
,
void
*
cachep
)
{
struct
smb_sb_info
*
server
;
server
=
server_from_dentry
(
dir
);
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_LANMAN2
)
return
smb_proc_readdir_long
(
server
,
dir
,
fpos
,
cache_size
,
entry
);
return
smb_proc_readdir_long
(
server
,
dir
,
fpos
,
cachep
);
else
return
smb_proc_readdir_short
(
server
,
dir
,
fpos
,
cache_size
,
entry
);
return
smb_proc_readdir_short
(
server
,
dir
,
fpos
,
cachep
);
}
static
int
...
...
@@ -1498,7 +1705,6 @@ static int
smb_proc_getattr_trans2
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
struct
qstr
*
name
,
struct
smb_fattr
*
attr
)
{
char
param
[
SMB_MAXPATHLEN
+
20
];
char
*
p
;
int
result
;
...
...
@@ -1506,29 +1712,34 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
unsigned
char
*
resp_param
=
NULL
;
int
resp_data_len
=
0
;
int
resp_param_len
=
0
;
char
param
[
SMB_MAXPATHLEN
+
20
];
/* too big for the stack! */
smb_lock_server
(
server
);
retry:
WSET
(
param
,
0
,
1
);
/* Info level SMB_INFO_STANDARD */
DSET
(
param
,
2
,
0
);
p
=
smb_encode_path
(
server
,
param
+
6
,
dir
,
name
);
smb_lock_server
(
server
);
retry:
result
=
smb_trans2_request
(
server
,
TRANSACT2_QPATHINFO
,
0
,
NULL
,
p
-
param
,
param
,
&
resp_data_len
,
&
resp_data
,
&
resp_param_len
,
&
resp_param
);
if
(
server
->
rcls
!=
0
)
{
result
=
-
smb_errno
(
server
->
rcls
,
server
->
err
);
goto
out
;
}
if
(
result
<
0
)
{
if
(
smb_retry
(
server
))
goto
retry
;
goto
out
;
}
if
(
server
->
rcls
!=
0
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_getattr_trans2: for %s: result=%d, rcls=%d, err=%d
\n
"
,
&
param
[
6
],
result
,
server
->
rcls
,
server
->
err
);
#endif
result
=
-
smb_errno
(
server
->
rcls
,
server
->
err
);
goto
out
;
}
result
=
-
ENOENT
;
if
(
resp_data_len
<
22
)
goto
out
;
...
...
@@ -1553,15 +1764,19 @@ smb_proc_getattr(struct dentry *dir, struct qstr *name,
struct
smb_fattr
*
fattr
)
{
struct
smb_sb_info
*
server
;
int
result
=
-
1
;
int
result
;
server
=
server_from_dentry
(
dir
);
smb_init_dirent
(
server
,
fattr
);
/*
* N.B. Why would we want to fall back to xxx_core on error?
* If the file doesn't exist (a very common case), the core
* protocol won't find it either.
*/
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_LANMAN2
)
result
=
smb_proc_getattr_trans2
(
server
,
dir
,
name
,
fattr
);
if
(
result
<
0
)
else
result
=
smb_proc_getattr_core
(
server
,
dir
,
name
,
fattr
);
smb_finish_dirent
(
server
,
fattr
);
...
...
@@ -1605,8 +1820,6 @@ static int
smb_proc_setattr_trans2
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
struct
smb_fattr
*
fattr
)
{
char
param
[
SMB_MAXPATHLEN
+
20
];
char
data
[
26
];
char
*
p
;
int
result
;
...
...
@@ -1614,7 +1827,12 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
unsigned
char
*
resp_param
=
NULL
;
int
resp_data_len
=
0
;
int
resp_param_len
=
0
;
char
param
[
SMB_MAXPATHLEN
+
20
];
/* too long for the stack! */
char
data
[
26
];
smb_lock_server
(
server
);
retry:
WSET
(
param
,
0
,
1
);
/* Info level SMB_INFO_STANDARD */
DSET
(
param
,
2
,
0
);
p
=
smb_encode_path
(
server
,
param
+
6
,
dir
,
NULL
);
...
...
@@ -1627,22 +1845,20 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
WSET
(
data
,
20
,
fattr
->
attr
);
WSET
(
data
,
22
,
0
);
smb_lock_server
(
server
);
retry:
result
=
smb_trans2_request
(
server
,
TRANSACT2_SETPATHINFO
,
26
,
data
,
p
-
param
,
param
,
&
resp_data_len
,
&
resp_data
,
&
resp_param_len
,
&
resp_param
);
if
(
server
->
rcls
!=
0
)
{
smb_unlock_server
(
server
);
return
-
smb_errno
(
server
->
rcls
,
server
->
err
);
}
if
(
result
<
0
)
{
if
(
smb_retry
(
server
))
goto
retry
;
goto
out
;
}
if
(
server
->
rcls
!=
0
)
result
=
-
smb_errno
(
server
->
rcls
,
server
->
err
);
out:
smb_unlock_server
(
server
);
return
0
;
}
...
...
@@ -1651,12 +1867,14 @@ int
smb_proc_setattr
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
struct
smb_fattr
*
fattr
)
{
int
result
=
-
1
;
int
result
;
/*
* N.B. Why would we want to fall back to xxx_core on error?
*/
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_LANMAN2
)
result
=
smb_proc_setattr_trans2
(
server
,
dir
,
fattr
);
if
(
result
<
0
)
else
result
=
smb_proc_setattr_core
(
server
,
dir
,
fattr
);
return
result
;
...
...
fs/smbfs/sock.c
View file @
f59dfe26
...
...
@@ -126,18 +126,26 @@ smb_data_callback(struct sock *sk, int len)
}
}
int
smb_valid_socket
(
struct
inode
*
inode
)
{
return
(
inode
&&
S_ISSOCK
(
inode
->
i_mode
)
&&
inode
->
u
.
socket_i
.
type
==
SOCK_STREAM
);
}
static
struct
socket
*
server_sock
(
struct
smb_sb_info
*
server
)
{
struct
file
*
file
;
struct
inode
*
inode
;
if
(
server
&&
(
file
=
server
->
sock_file
)
&&
(
inode
=
file
->
f_dentry
->
d_inode
)
&&
S_ISSOCK
(
inode
->
i_mode
)
&&
inode
->
u
.
socket_i
.
type
==
SOCK_STREAM
)
return
&
(
inode
->
u
.
socket_i
);
if
(
server
&&
(
file
=
server
->
sock_file
))
{
#ifdef SMBFS_PARANOIA
if
(
!
smb_valid_socket
(
file
->
f_dentry
->
d_inode
))
printk
(
"smb_server_sock: bad socket!
\n
"
);
#endif
return
&
file
->
f_dentry
->
d_inode
->
u
.
socket_i
;
}
return
NULL
;
}
...
...
@@ -242,15 +250,13 @@ smb_close_socket(struct smb_sb_info *server)
if
(
file
)
{
struct
socket
*
socket
=
server_sock
(
server
);
printk
(
"smb_close_socket: closing socket %p
\n
"
,
socket
);
/*
* We need a way to check for tasks running the callback!
*/
if
(
socket
->
sk
->
data_ready
==
smb_data_callback
)
printk
(
"smb_close_socket: still catching keepalives!
\n
"
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_close_socket: closing socket %p
\n
"
,
server_sock
(
server
));
#endif
#ifdef SMBFS_PARANOIA
if
(
server_sock
(
server
)
->
sk
->
data_ready
==
smb_data_callback
)
printk
(
"smb_close_socket: still catching keepalives!
\n
"
);
#endif
server
->
sock_file
=
NULL
;
close_fp
(
file
);
}
...
...
@@ -325,7 +331,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
if
(
result
<
0
)
{
pr_debug
(
"smb_get_length: recv error = %d
\n
"
,
-
result
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_get_length: recv error = %d
\n
"
,
-
result
);
#endif
return
result
;
}
switch
(
peek_buf
[
0
])
...
...
@@ -339,7 +347,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
goto
re_recv
;
default:
pr_debug
(
"smb_get_length: Invalid NBT packet
\n
"
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_get_length: Invalid NBT packet, code=%x
\n
"
,
peek_buf
[
0
]);
#endif
return
-
EIO
;
}
...
...
@@ -359,39 +369,39 @@ static int
smb_receive
(
struct
smb_sb_info
*
server
)
{
struct
socket
*
socket
=
server_sock
(
server
);
int
len
;
int
result
;
int
len
,
result
;
unsigned
char
peek_buf
[
4
];
len
=
smb_get_length
(
socket
,
peek_buf
);
if
(
len
<
0
)
{
return
len
;
}
result
=
smb_get_length
(
socket
,
peek_buf
);
if
(
result
<
0
)
goto
out
;
len
=
result
;
/*
* Some servers do not respect our max_xmit and send
* larger packets. Try to allocate a new packet,
* but don't free the old one unless we succeed.
*/
if
(
len
+
4
>
server
->
packet_size
)
{
/* Some servers do not care about our max_xmit. They
send larger packets */
char
*
packet
;
pr_debug
(
"smb_receive: Increase packet size from %d to %d
\n
"
,
server
->
packet_size
,
len
+
4
);
result
=
-
ENOMEM
;
packet
=
smb_vmalloc
(
len
+
4
);
if
(
packet
==
NULL
)
goto
out
;
smb_vfree
(
server
->
packet
);
server
->
packet
=
0
;
server
->
packet_size
=
0
;
server
->
packet
=
smb_vmalloc
(
len
+
4
);
if
(
server
->
packet
==
NULL
)
{
return
-
ENOMEM
;
}
server
->
packet
=
packet
;
server
->
packet_size
=
len
+
4
;
}
memcpy
(
server
->
packet
,
peek_buf
,
4
);
result
=
smb_receive_raw
(
socket
,
server
->
packet
+
4
,
len
);
if
(
result
<
0
)
{
pr_debug
(
"smb_receive: receive error: %d
\n
"
,
result
);
return
result
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_receive: receive error: %d
\n
"
,
result
);
#endif
goto
out
;
}
server
->
rcls
=
*
(
server
->
packet
+
9
);
server
->
err
=
WVAL
(
server
->
packet
,
11
);
...
...
@@ -400,9 +410,16 @@ smb_receive(struct smb_sb_info *server)
if
(
server
->
rcls
!=
0
)
printk
(
"smb_receive: rcls=%d, err=%d
\n
"
,
server
->
rcls
,
server
->
err
);
#endif
out:
return
result
;
}
/*
* This routine needs a lot of work. We should check whether the packet
* is all one part before allocating a new one, and should try first to
* copy to a temp buffer before allocating.
* The final server->packet should be the larger of the two.
*/
static
int
smb_receive_trans2
(
struct
smb_sb_info
*
server
,
int
*
ldata
,
unsigned
char
**
data
,
...
...
@@ -515,6 +532,11 @@ data_len, total_data, param_len, total_param);
*
ldata
=
data_len
;
*
lparam
=
param_len
;
#ifdef SMBFS_PARANOIA
if
(
buf_len
<
server
->
packet_size
)
printk
(
"smb_receive_trans2: changing packet, old size=%d, new size=%d
\n
"
,
server
->
packet_size
,
buf_len
);
#endif
smb_vfree
(
server
->
packet
);
server
->
packet
=
rcv_buf
;
server
->
packet_size
=
buf_len
;
...
...
@@ -537,9 +559,6 @@ smb_request(struct smb_sb_info *server)
unsigned
char
*
buffer
;
result
=
-
EBADF
;
if
(
!
server
)
/* this can't happen */
goto
bad_no_server
;
buffer
=
server
->
packet
;
if
(
!
buffer
)
goto
bad_no_packet
;
...
...
@@ -586,13 +605,12 @@ smb_request(struct smb_sb_info *server)
return
result
;
bad_conn:
printk
(
"smb_request: result %d, setting invalid
\n
"
,
result
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_request: result %d, setting invalid
\n
"
,
result
);
#endif
server
->
state
=
CONN_INVALID
;
smb_invalidate_inodes
(
server
);
goto
out
;
bad_no_server:
printk
(
"smb_request: no server!
\n
"
);
goto
out
;
bad_no_packet:
printk
(
"smb_request: no packet!
\n
"
);
goto
out
;
...
...
@@ -631,6 +649,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
struct
iovec
iov
[
4
];
struct
msghdr
msg
;
/* N.B. This test isn't valid! packet_size may be < max_xmit */
if
((
bcc
+
oparam
)
>
server
->
opt
.
max_xmit
)
{
return
-
ENOMEM
;
...
...
@@ -639,6 +658,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
WSET
(
server
->
packet
,
smb_tpscnt
,
lparam
);
WSET
(
server
->
packet
,
smb_tdscnt
,
ldata
);
/* N.B. these values should reflect out current packet size */
WSET
(
server
->
packet
,
smb_mprcnt
,
TRANS2_MAX_TRANSFER
);
WSET
(
server
->
packet
,
smb_mdrcnt
,
TRANS2_MAX_TRANSFER
);
WSET
(
server
->
packet
,
smb_msrcnt
,
0
);
...
...
@@ -745,7 +765,9 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
return
result
;
bad_conn:
printk
(
"smb_trans2_request: connection bad, setting invalid
\n
"
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_trans2_request: connection bad, setting invalid
\n
"
);
#endif
server
->
state
=
CONN_INVALID
;
smb_invalidate_inodes
(
server
);
goto
out
;
...
...
fs/super.c
View file @
f59dfe26
...
...
@@ -17,8 +17,6 @@
* Added change_root: Werner Almesberger & Hans Lermen, Feb '96
*/
#include <stdarg.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
...
...
@@ -252,29 +250,24 @@ static int fs_maxindex(void)
/*
* Whee.. Weird sysv syscall.
*/
asmlinkage
int
sys_sysfs
(
int
option
,
...
)
asmlinkage
int
sys_sysfs
(
int
option
,
unsigned
long
arg1
,
unsigned
long
arg2
)
{
va_list
args
;
int
retval
=
-
EINVAL
;
unsigned
int
index
;
lock_kernel
();
va_start
(
args
,
option
);
switch
(
option
)
{
case
1
:
retval
=
fs_index
(
va_arg
(
args
,
const
char
*
)
);
retval
=
fs_index
(
(
const
char
*
)
arg1
);
break
;
case
2
:
index
=
va_arg
(
args
,
unsigned
int
);
retval
=
fs_name
(
index
,
va_arg
(
args
,
char
*
));
retval
=
fs_name
(
arg1
,
(
char
*
)
arg2
);
break
;
case
3
:
retval
=
fs_maxindex
();
break
;
}
va_end
(
args
);
unlock_kernel
();
return
retval
;
}
...
...
@@ -933,12 +926,11 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
struct
file_system_type
*
fstype
;
struct
dentry
*
dentry
=
NULL
;
struct
inode
*
inode
=
NULL
;
struct
file_operations
*
fops
;
kdev_t
dev
;
int
retval
=
-
EPERM
;
const
char
*
t
;
unsigned
long
flags
=
0
;
unsigned
long
page
=
0
;
struct
file
dummy
;
/* allows read-write or read-only flag */
lock_kernel
();
if
(
!
suser
())
...
...
@@ -954,6 +946,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
free_page
(
page
);
goto
out
;
}
retval
=
copy_mount_options
(
type
,
&
page
);
if
(
retval
<
0
)
goto
out
;
...
...
@@ -962,8 +955,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
retval
=
-
ENODEV
;
if
(
!
fstype
)
goto
out
;
t
=
fstype
->
name
;
fops
=
NULL
;
memset
(
&
dummy
,
0
,
sizeof
(
dummy
))
;
if
(
fstype
->
fs_flags
&
FS_REQUIRES_DEV
)
{
dentry
=
namei
(
dev_name
);
retval
=
PTR_ERR
(
dentry
);
...
...
@@ -984,17 +977,15 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if
(
MAJOR
(
dev
)
>=
MAX_BLKDEV
)
goto
dput_and_out
;
fops
=
get_blkfops
(
MAJOR
(
dev
));
retval
=
-
ENOTBLK
;
if
(
!
fops
)
dummy
.
f_op
=
get_blkfops
(
MAJOR
(
dev
));
if
(
!
dummy
.
f_op
)
goto
dput_and_out
;
if
(
fops
->
open
)
{
struct
file
dummy
;
/* allows read-write or read-only flag */
memset
(
&
dummy
,
0
,
sizeof
(
dummy
));
if
(
dummy
.
f_op
->
open
)
{
dummy
.
f_dentry
=
dentry
;
dummy
.
f_mode
=
(
new_flags
&
MS_RDONLY
)
?
1
:
3
;
retval
=
fops
->
open
(
inode
,
&
dummy
);
retval
=
dummy
.
f_op
->
open
(
inode
,
&
dummy
);
if
(
retval
)
goto
dput_and_out
;
}
...
...
@@ -1009,22 +1000,28 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if
((
new_flags
&
MS_MGC_MSK
)
==
MS_MGC_VAL
)
{
flags
=
new_flags
&
~
MS_MGC_MSK
;
retval
=
copy_mount_options
(
data
,
&
page
);
if
(
retval
<
0
)
{
put_unnamed_dev
(
dev
);
goto
dput_and_out
;
}
if
(
retval
<
0
)
goto
clean_up
;
}
retval
=
do_mount
(
dev
,
dev_name
,
dir_name
,
t
,
flags
,(
void
*
)
page
);
retval
=
do_mount
(
dev
,
dev_name
,
dir_name
,
fstype
->
name
,
flags
,
(
void
*
)
page
);
free_page
(
page
);
if
(
retval
&&
fops
&&
fops
->
release
)
{
fops
->
release
(
inode
,
NULL
);
put_unnamed_dev
(
dev
);
}
if
(
retval
)
goto
clean_up
;
dput_and_out:
dput
(
dentry
);
out:
unlock_kernel
();
return
retval
;
clean_up:
if
(
dummy
.
f_op
)
{
if
(
dummy
.
f_op
->
release
)
dummy
.
f_op
->
release
(
inode
,
NULL
);
}
else
put_unnamed_dev
(
dev
);
goto
dput_and_out
;
}
__initfunc
(
static
void
do_mount_root
(
void
))
...
...
include/linux/dcache.h
View file @
f59dfe26
...
...
@@ -104,6 +104,7 @@ extern void d_delete(struct dentry *);
/* allocate/de-allocate */
extern
struct
dentry
*
d_alloc
(
struct
dentry
*
parent
,
const
struct
qstr
*
name
);
extern
void
prune_dcache
(
int
);
extern
void
shrink_dcache_sb
(
struct
super_block
*
);
extern
int
d_invalidate
(
struct
dentry
*
);
#define shrink_dcache() prune_dcache(0)
...
...
include/linux/fs.h
View file @
f59dfe26
...
...
@@ -42,9 +42,10 @@
/* And dynamically-tunable limits and defaults: */
extern
int
max_inodes
;
extern
int
max_files
,
nr_files
;
extern
int
max_files
,
nr_files
,
nr_free_files
;
#define NR_INODE 4096
/* this should be bigger than NR_FILE */
#define NR_FILE 1024
/* this can well be larger on a larger system */
#define NR_RESERVED_FILES 10
/* reserved for root */
#define MAY_EXEC 1
#define MAY_WRITE 2
...
...
@@ -628,6 +629,10 @@ extern struct inode_operations chrdev_inode_operations;
extern
void
init_fifo
(
struct
inode
*
inode
);
extern
struct
inode_operations
fifo_inode_operations
;
/* Invalid inode operations -- fs/bad_inode.c */
extern
void
make_bad_inode
(
struct
inode
*
inode
);
extern
int
is_bad_inode
(
struct
inode
*
inode
);
extern
struct
file_operations
connecting_fifo_fops
;
extern
struct
file_operations
read_fifo_fops
;
extern
struct
file_operations
write_fifo_fops
;
...
...
include/linux/list.h
View file @
f59dfe26
...
...
@@ -3,7 +3,14 @@
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct
list_head
{
struct
list_head
*
next
,
*
prev
;
};
...
...
@@ -15,24 +22,48 @@ struct list_head {
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
static
inline
void
list_add
(
struct
list_head
*
new
,
struct
list_head
*
head
)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static
inline
void
__list_add
(
struct
list_head
*
new
,
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
struct
list_head
*
next
=
head
->
next
;
next
->
prev
=
new
;
new
->
next
=
next
;
new
->
prev
=
head
;
head
->
next
=
new
;
new
->
prev
=
prev
;
prev
->
next
=
new
;
}
static
inline
void
list_del
(
struct
list_head
*
entry
)
/*
* Insert a new entry after the specified head..
*/
static
inline
void
list_add
(
struct
list_head
*
new
,
struct
list_head
*
head
)
{
__list_add
(
new
,
head
,
head
->
next
);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static
inline
void
__list_del
(
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
struct
list_head
*
next
,
*
prev
;
next
=
entry
->
next
;
prev
=
entry
->
prev
;
next
->
prev
=
prev
;
prev
->
next
=
next
;
}
static
inline
void
list_del
(
struct
list_head
*
entry
)
{
__list_del
(
entry
->
prev
,
entry
->
next
);
}
static
inline
int
list_empty
(
struct
list_head
*
head
)
{
return
head
->
next
==
head
;
...
...
include/linux/mm.h
View file @
f59dfe26
...
...
@@ -296,6 +296,8 @@ extern unsigned long get_unmapped_area(unsigned long, unsigned long);
extern
unsigned
long
page_unuse
(
unsigned
long
);
extern
int
shrink_mmap
(
int
,
int
);
extern
void
truncate_inode_pages
(
struct
inode
*
,
unsigned
long
);
extern
unsigned
long
get_cached_page
(
struct
inode
*
,
unsigned
long
,
int
);
extern
void
put_cached_page
(
unsigned
long
);
#define GFP_BUFFER 0x00
#define GFP_ATOMIC 0x01
...
...
include/linux/nfs.h
View file @
f59dfe26
...
...
@@ -129,14 +129,6 @@ struct nfs_sattr {
struct
nfs_time
mtime
;
};
struct
nfs_entry
{
__u32
fileid
;
char
*
name
;
unsigned
int
length
:
31
,
eof:
1
;
__u32
cookie
;
};
struct
nfs_fsinfo
{
__u32
tsize
;
__u32
bsize
;
...
...
include/linux/nfs_fs.h
View file @
f59dfe26
...
...
@@ -125,7 +125,7 @@ extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
extern
int
nfs_proc_rmdir
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
dir
,
const
char
*
name
);
extern
int
nfs_proc_readdir
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
u32
cookie
,
unsigned
int
size
,
struct
nfs_entry
*
entry
);
u32
cookie
,
unsigned
int
size
,
__u32
*
entry
);
extern
int
nfs_proc_statfs
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
res
);
...
...
@@ -138,7 +138,7 @@ extern struct super_block *nfs_read_super(struct super_block *sb,
extern
int
init_nfs_fs
(
void
);
extern
struct
inode
*
nfs_fhget
(
struct
super_block
*
sb
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
);
extern
void
nfs_refresh_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
);
extern
int
nfs_refresh_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
);
extern
int
nfs_revalidate
(
struct
inode
*
);
extern
int
_nfs_revalidate_inode
(
struct
nfs_server
*
,
struct
inode
*
);
...
...
include/linux/proc_fs.h
View file @
f59dfe26
...
...
@@ -237,13 +237,15 @@ struct proc_dir_entry {
unsigned
long
size
;
struct
inode_operations
*
ops
;
int
(
*
get_info
)(
char
*
,
char
**
,
off_t
,
int
,
int
);
void
(
*
fill_inode
)(
struct
inode
*
);
void
(
*
fill_inode
)(
struct
inode
*
,
int
);
struct
proc_dir_entry
*
next
,
*
parent
,
*
subdir
;
void
*
data
;
int
(
*
read_proc
)(
char
*
page
,
char
**
start
,
off_t
off
,
int
count
,
int
*
eof
,
void
*
data
);
int
(
*
write_proc
)(
struct
file
*
file
,
const
char
*
buffer
,
unsigned
long
count
,
void
*
data
);
unsigned
int
count
;
/* use count */
int
deleted
;
/* delete flag */
};
extern
int
(
*
dispatch_scsi_info_ptr
)
(
int
ino
,
char
*
buffer
,
char
**
start
,
...
...
include/linux/smb_fs.h
View file @
f59dfe26
...
...
@@ -9,6 +9,7 @@
#ifndef _LINUX_SMB_FS_H
#define _LINUX_SMB_FS_H
#include <linux/dirent.h>
#include <linux/smb.h>
/*
...
...
@@ -71,30 +72,24 @@ extern struct inode_operations smb_file_inode_operations;
/* linux/fs/smbfs/dir.c */
extern
struct
inode_operations
smb_dir_inode_operations
;
struct
smb_inode_info
*
smb_find_inode
(
struct
smb_sb_info
*
server
,
ino_t
ino
);
void
smb_free_inode_info
(
struct
smb_inode_info
*
i
);
void
smb_free_all_inodes
(
struct
smb_sb_info
*
server
);
void
smb_init_root
(
struct
smb_sb_info
*
server
);
int
smb_stat_root
(
struct
smb_sb_info
*
server
);
void
smb_init_dir_cache
(
void
);
void
smb_invalid_dir_cache
(
struct
inode
*
);
void
smb_free_dir_cache
(
void
);
void
smb_init_root
(
struct
smb_sb_info
*
);
int
smb_stat_root
(
struct
smb_sb_info
*
);
void
smb_renew_times
(
struct
dentry
*
);
/* linux/fs/smbfs/ioctl.c */
int
smb_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
);
/* linux/fs/smbfs/inode.c */
struct
super_block
*
smb_read_super
(
struct
super_block
*
sb
,
void
*
raw_data
,
int
silent
);
struct
super_block
*
smb_read_super
(
struct
super_block
*
,
void
*
,
int
);
extern
int
init_smb_fs
(
void
);
void
smb_invalidate_inodes
(
struct
smb_sb_info
*
server
);
int
smb_revalidate_inode
(
struct
inode
*
i
);
int
smb_refresh_inode
(
struct
inode
*
i
);
int
smb_notify_change
(
struct
inode
*
inode
,
struct
iattr
*
attr
);
void
smb_invalidate_connection
(
struct
smb_sb_info
*
server
);
int
smb_conn_is_valid
(
struct
smb_sb_info
*
server
);
unsigned
long
smb_invent_inos
(
unsigned
long
n
);
void
smb_invalidate_inodes
(
struct
smb_sb_info
*
);
int
smb_revalidate_inode
(
struct
inode
*
);
int
smb_refresh_inode
(
struct
inode
*
);
int
smb_notify_change
(
struct
inode
*
,
struct
iattr
*
);
void
smb_invalidate_connection
(
struct
smb_sb_info
*
);
int
smb_conn_is_valid
(
struct
smb_sb_info
*
);
unsigned
long
smb_invent_inos
(
unsigned
long
);
struct
inode
*
smb_iget
(
struct
super_block
*
,
struct
smb_fattr
*
);
/* linux/fs/smbfs/proc.c */
...
...
@@ -105,6 +100,7 @@ __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command,
int
smb_offerconn
(
struct
smb_sb_info
*
server
);
int
smb_newconn
(
struct
smb_sb_info
*
server
,
struct
smb_conn_opt
*
opt
);
int
smb_close
(
struct
inode
*
);
void
smb_close_dentry
(
struct
dentry
*
);
int
smb_open
(
struct
dentry
*
,
int
);
static
inline
int
smb_is_open
(
struct
inode
*
i
)
...
...
@@ -112,34 +108,31 @@ smb_is_open(struct inode *i)
return
(
i
->
u
.
smbfs_i
.
open
==
SMB_SERVER
(
i
)
->
generation
);
}
int
smb_proc_read
(
struct
inode
*
,
off_t
,
long
,
char
*
);
int
smb_proc_read
(
struct
inode
*
,
off_t
,
int
,
char
*
);
int
smb_proc_write
(
struct
inode
*
,
off_t
,
int
,
const
char
*
);
int
smb_proc_create
(
struct
dentry
*
,
struct
qstr
*
,
__u16
,
time_t
);
int
smb_proc_mv
(
struct
dentry
*
,
struct
qstr
*
,
struct
dentry
*
,
struct
qstr
*
);
int
smb_proc_mkdir
(
struct
dentry
*
,
struct
qstr
*
);
int
smb_proc_rmdir
(
struct
dentry
*
,
struct
qstr
*
);
int
smb_proc_unlink
(
struct
dentry
*
dir
,
struct
qstr
*
);
int
smb_proc_readdir
(
struct
dentry
*
dir
,
int
fpos
,
int
cache_size
,
struct
smb_dirent
*
entry
);
int
smb_proc_getattr
(
struct
dentry
*
dir
,
struct
qstr
*
name
,
struct
smb_fattr
*
entry
);
int
smb_proc_setattr
(
struct
smb_sb_info
*
server
,
struct
dentry
*
dir
,
struct
smb_fattr
*
new_finfo
);
int
smb_proc_dskattr
(
struct
super_block
*
sb
,
struct
statfs
*
attr
);
int
smb_proc_reconnect
(
struct
smb_sb_info
*
server
);
int
smb_proc_connect
(
struct
smb_sb_info
*
server
);
int
smb_proc_disconnect
(
struct
smb_sb_info
*
server
);
int
smb_proc_trunc
(
struct
smb_sb_info
*
server
,
__u16
fid
,
__u32
length
);
int
smb_proc_readdir
(
struct
dentry
*
,
int
,
void
*
);
int
smb_proc_getattr
(
struct
dentry
*
,
struct
qstr
*
,
struct
smb_fattr
*
);
int
smb_proc_setattr
(
struct
smb_sb_info
*
,
struct
dentry
*
,
struct
smb_fattr
*
);
int
smb_proc_dskattr
(
struct
super_block
*
,
struct
statfs
*
);
int
smb_proc_reconnect
(
struct
smb_sb_info
*
);
int
smb_proc_connect
(
struct
smb_sb_info
*
);
int
smb_proc_disconnect
(
struct
smb_sb_info
*
);
int
smb_proc_trunc
(
struct
smb_sb_info
*
,
__u16
,
__u32
);
void
smb_init_root_dirent
(
struct
smb_sb_info
*
server
,
struct
smb_fattr
*
);
/* linux/fs/smbfs/sock.c */
int
smb_valid_socket
(
struct
inode
*
);
void
smb_close_socket
(
struct
smb_sb_info
*
);
int
smb_release
(
struct
smb_sb_info
*
server
);
int
smb_connect
(
struct
smb_sb_info
*
server
);
int
smb_request
(
struct
smb_sb_info
*
server
);
int
smb_request_read_raw
(
struct
smb_sb_info
*
server
,
unsigned
char
*
target
,
int
max_len
);
int
smb_request_write_raw
(
struct
smb_sb_info
*
server
,
unsigned
const
char
*
source
,
int
length
);
int
smb_request_read_raw
(
struct
smb_sb_info
*
,
unsigned
char
*
,
int
);
int
smb_request_write_raw
(
struct
smb_sb_info
*
,
unsigned
const
char
*
,
int
);
int
smb_catch_keepalive
(
struct
smb_sb_info
*
server
);
int
smb_dont_catch_keepalive
(
struct
smb_sb_info
*
server
);
int
smb_trans2_request
(
struct
smb_sb_info
*
server
,
__u16
trans2_command
,
...
...
@@ -151,6 +144,72 @@ int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
/* linux/fs/smbfs/mmap.c */
int
smb_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
);
/* fs/smbfs/cache.c */
/*
* The cache index describes the pages mapped starting
* at offset PAGE_SIZE. We keep only a minimal amount
* of information here.
*/
struct
cache_index
{
unsigned
short
num_entries
;
unsigned
short
space
;
struct
cache_block
*
block
;
};
#define NINDEX (PAGE_SIZE-64)/sizeof(struct cache_index)
/*
* The cache head is mapped as the page at offset 0.
*/
struct
cache_head
{
int
valid
;
int
status
;
/* error code or 0 */
int
entries
;
/* total entries */
int
pages
;
/* number of data pages */
int
idx
;
/* index of current data page */
struct
cache_index
index
[
NINDEX
];
};
/*
* An array of cache_entry structures holds information
* for each object in the cache_block.
*/
struct
cache_entry
{
ino_t
ino
;
unsigned
short
namelen
;
unsigned
short
offset
;
};
/*
* The cache blocks hold the actual data. The entry table grows up
* while the names grow down, and we have space until they meet.
*/
struct
cache_block
{
union
{
struct
cache_entry
table
[
1
];
char
names
[
PAGE_SIZE
];
}
cb_data
;
};
/*
* To return an entry, we can pass a reference to the
* name instead of having to copy it.
*/
struct
cache_dirent
{
ino_t
ino
;
unsigned
long
pos
;
int
len
;
char
*
name
;
};
struct
cache_head
*
smb_get_dircache
(
struct
dentry
*
);
void
smb_init_dircache
(
struct
cache_head
*
);
void
smb_free_dircache
(
struct
cache_head
*
);
int
smb_refill_dircache
(
struct
cache_head
*
,
struct
dentry
*
);
void
smb_add_to_cache
(
struct
cache_head
*
,
struct
dirent
*
,
off_t
);
int
smb_find_in_cache
(
struct
cache_head
*
,
off_t
,
struct
cache_dirent
*
);
void
smb_invalid_dir_cache
(
struct
inode
*
);
#endif
/* __KERNEL__ */
#endif
/* _LINUX_SMB_FS_H */
include/linux/smb_fs_i.h
View file @
f59dfe26
...
...
@@ -22,11 +22,13 @@ struct smb_inode_info {
* (open == generation).
*/
unsigned
int
open
;
void
*
dentry
;
/* The dentry we were opened with */
__u16
fileid
;
/* What id to handle a file with? */
__u16
attr
;
/* Attribute fields, DOS value */
__u16
access
;
/* Access bits. */
__u16
cache_valid
;
/* dircache valid? */
unsigned
long
oldmtime
;
/* last time refreshed */
void
*
dentry
;
/* The dentry we were opened with */
};
#endif
...
...
include/linux/smb_fs_sb.h
View file @
f59dfe26
...
...
@@ -15,6 +15,11 @@
#include <linux/smb.h>
#include <linux/smb_mount.h>
/* Get the server for the specified dentry */
#define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
#define SB_of(server) ((struct super_block *) ((char *)(server) - \
(unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
struct
smb_sb_info
{
enum
smb_conn_state
state
;
struct
file
*
sock_file
;
...
...
@@ -29,6 +34,7 @@ struct smb_sb_info {
struct
smb_conn_opt
opt
;
struct
semaphore
sem
;
struct
wait_queue
*
wait
;
__u32
packet_size
;
unsigned
char
*
packet
;
...
...
include/linux/sunrpc/sched.h
View file @
f59dfe26
...
...
@@ -143,7 +143,7 @@ void rpc_del_timer(struct rpc_task *);
void
rpc_delay
(
struct
rpc_task
*
,
unsigned
long
);
void
*
rpc_allocate
(
unsigned
int
flags
,
unsigned
int
);
void
rpc_free
(
void
*
);
void
rpciod_up
(
void
);
int
rpciod_up
(
void
);
void
rpciod_down
(
void
);
extern
__inline__
void
*
...
...
kernel/fork.c
View file @
f59dfe26
...
...
@@ -208,7 +208,6 @@ static inline int dup_mmap(struct mm_struct * mm)
struct
vm_area_struct
*
mpnt
,
*
tmp
,
**
pprev
;
int
retval
;
mm
->
mmap
=
mm
->
mmap_cache
=
NULL
;
flush_cache_mm
(
current
->
mm
);
pprev
=
&
mm
->
mmap
;
for
(
mpnt
=
current
->
mm
->
mmap
;
mpnt
;
mpnt
=
mpnt
->
vm_next
)
{
...
...
@@ -254,8 +253,7 @@ static inline int dup_mmap(struct mm_struct * mm)
if
(
retval
)
goto
fail_nomem
;
}
flush_tlb_mm
(
current
->
mm
);
return
0
;
retval
=
0
;
fail_nomem:
flush_tlb_mm
(
current
->
mm
);
...
...
@@ -276,7 +274,10 @@ struct mm_struct * mm_alloc(void)
mm
->
count
=
1
;
mm
->
def_flags
=
0
;
mm
->
mmap_sem
=
MUTEX
;
mm
->
pgd
=
NULL
;
/*
* Leave mm->pgd set to the parent's pgd
* so that pgd_offset() is always valid.
*/
mm
->
mmap
=
mm
->
mmap_cache
=
NULL
;
/* It has not run yet, so cannot be present in anyone's
...
...
@@ -324,10 +325,12 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
goto
free_mm
;
retval
=
dup_mmap
(
mm
);
if
(
retval
)
goto
free_
mm
;
goto
free_
pt
;
return
0
;
free_mm:
mm
->
pgd
=
NULL
;
free_pt:
tsk
->
mm
=
NULL
;
mmput
(
mm
);
fail_nomem:
...
...
@@ -376,7 +379,13 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk
struct
files_struct
*
oldf
,
*
newf
;
struct
file
**
old_fds
,
**
new_fds
;
/*
* A background process may not have any files ...
*/
oldf
=
current
->
files
;
if
(
!
oldf
)
return
0
;
if
(
clone_flags
&
CLONE_FILES
)
{
oldf
->
count
++
;
return
0
;
...
...
@@ -516,7 +525,9 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
}
++
total_forks
;
error
=
p
->
pid
;
goto
fork_out
;
bad_fork:
unlock_kernel
();
return
error
;
bad_fork_cleanup_sighand:
exit_sighand
(
p
);
...
...
@@ -536,10 +547,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
nr_tasks
--
;
bad_fork_free:
free_task_struct
(
p
);
bad_fork:
fork_out:
unlock_kernel
();
return
error
;
goto
bad_fork
;
}
static
void
files_ctor
(
void
*
fp
,
kmem_cache_t
*
cachep
,
unsigned
long
flags
)
...
...
kernel/ksyms.c
View file @
f59dfe26
...
...
@@ -192,6 +192,8 @@ EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL
(
posix_block_lock
);
EXPORT_SYMBOL
(
posix_unblock_lock
);
EXPORT_SYMBOL
(
dput
);
EXPORT_SYMBOL
(
get_cached_page
);
EXPORT_SYMBOL
(
put_cached_page
);
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL
(
do_nfsservctl
);
...
...
@@ -369,6 +371,8 @@ EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL
(
get_hash_table
);
EXPORT_SYMBOL
(
get_empty_inode
);
EXPORT_SYMBOL
(
insert_inode_hash
);
EXPORT_SYMBOL
(
make_bad_inode
);
EXPORT_SYMBOL
(
is_bad_inode
);
EXPORT_SYMBOL
(
event
);
EXPORT_SYMBOL
(
__down
);
EXPORT_SYMBOL
(
__up
);
...
...
kernel/sysctl.c
View file @
f59dfe26
...
...
@@ -147,7 +147,7 @@ static ctl_table kern_table[] = {
0444
,
NULL
,
&
proc_dointvec
},
{
KERN_MAXINODE
,
"inode-max"
,
&
max_inodes
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
KERN_NRFILE
,
"file-nr"
,
&
nr_files
,
sizeof
(
int
),
{
KERN_NRFILE
,
"file-nr"
,
&
nr_files
,
3
*
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
KERN_MAXFILE
,
"file-max"
,
&
max_files
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
...
...
mm/filemap.c
View file @
f59dfe26
...
...
@@ -1398,3 +1398,60 @@ generic_file_write(struct inode *inode, struct file *file, const char *buf, unsi
return
written
;
return
status
;
}
/*
* Support routines for directory cacheing using the page cache.
*/
/*
* Finds the page at the specified offset, installing a new page
* if requested. The count is incremented and the page is locked.
*
* Note: we don't have to worry about races here, as the caller
* is holding the inode semaphore.
*/
unsigned
long
get_cached_page
(
struct
inode
*
inode
,
unsigned
long
offset
,
int
new
)
{
struct
page
*
page
;
struct
page
**
hash
;
unsigned
long
page_cache
;
hash
=
page_hash
(
inode
,
offset
);
page
=
__find_page
(
inode
,
offset
,
*
hash
);
if
(
!
page
)
{
if
(
!
new
)
goto
out
;
page_cache
=
get_free_page
(
GFP_KERNEL
);
if
(
!
page_cache
)
goto
out
;
page
=
mem_map
+
MAP_NR
(
page_cache
);
add_to_page_cache
(
page
,
inode
,
offset
,
hash
);
}
if
(
atomic_read
(
&
page
->
count
)
!=
2
)
printk
(
"get_cached_page: page count=%d
\n
"
,
atomic_read
(
&
page
->
count
));
if
(
test_bit
(
PG_locked
,
&
page
->
flags
))
printk
(
"get_cached_page: page already locked!
\n
"
);
set_bit
(
PG_locked
,
&
page
->
flags
);
out:
return
page_address
(
page
);
}
/*
* Unlock and free a page.
*/
void
put_cached_page
(
unsigned
long
addr
)
{
struct
page
*
page
=
mem_map
+
MAP_NR
(
addr
);
if
(
!
test_bit
(
PG_locked
,
&
page
->
flags
))
printk
(
"put_cached_page: page not locked!
\n
"
);
if
(
atomic_read
(
&
page
->
count
)
!=
2
)
printk
(
"put_cached_page: page count=%d
\n
"
,
atomic_read
(
&
page
->
count
));
clear_bit
(
PG_locked
,
&
page
->
flags
);
wake_up
(
&
page
->
wait
);
__free_page
(
page
);
}
mm/vmscan.c
View file @
f59dfe26
...
...
@@ -24,9 +24,6 @@
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <asm/dma.h>
#include <asm/system.h>
/* for cli()/sti() */
#include <asm/uaccess.h>
/* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
...
...
@@ -418,6 +415,7 @@ void kswapd_setup(void)
printk
(
"Starting kswapd v%.*s
\n
"
,
i
,
s
);
}
#define MAX_SWAP_FAIL 3
/*
* The background pageout daemon.
* Started as a kernel thread from the init process.
...
...
@@ -445,6 +443,8 @@ int kswapd(void *unused)
init_swap_timer
();
while
(
1
)
{
int
fail
;
kswapd_awake
=
0
;
current
->
signal
=
0
;
run_task_queue
(
&
tq_disk
);
...
...
@@ -455,13 +455,27 @@ int kswapd(void *unused)
* We now only swap out as many pages as needed.
* When we are truly low on memory, we swap out
* synchronously (WAIT == 1). -- Rik.
* If we've had too many consecutive failures,
* go back to sleep to let other tasks run.
*/
for
(
fail
=
0
;
fail
++
<
MAX_SWAP_FAIL
;)
{
int
pages
,
wait
;
pages
=
nr_free_pages
;
if
(
nr_free_pages
>=
min_free_pages
)
pages
+=
atomic_read
(
&
nr_async_pages
);
if
(
pages
>=
free_pages_high
)
break
;
wait
=
(
pages
<
free_pages_low
);
if
(
try_to_free_page
(
GFP_KERNEL
,
0
,
wait
))
fail
=
0
;
}
/*
* Report failure if we couldn't reach the minimum goal.
*/
while
(
nr_free_pages
<
min_free_pages
)
try_to_free_page
(
GFP_KERNEL
,
0
,
1
);
while
((
nr_free_pages
+
atomic_read
(
&
nr_async_pages
))
<
free_pages_low
)
try_to_free_page
(
GFP_KERNEL
,
0
,
1
);
while
((
nr_free_pages
+
atomic_read
(
&
nr_async_pages
))
<
free_pages_high
)
try_to_free_page
(
GFP_KERNEL
,
0
,
0
);
if
(
nr_free_pages
<
min_free_pages
)
printk
(
"kswapd: failed, got %d of %d
\n
"
,
nr_free_pages
,
min_free_pages
);
}
}
...
...
net/sunrpc/clnt.c
View file @
f59dfe26
...
...
@@ -116,17 +116,23 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
/*
* Properly shut down an RPC client, terminating all outstanding
* requests.
* requests. Note that we must be certain that cl_oneshot and
* cl_dead are cleared, or else the client would be destroyed
* when the last task releases it.
*/
int
rpc_shutdown_client
(
struct
rpc_clnt
*
clnt
)
{
dprintk
(
"RPC: shutting down %s client for %s
\n
"
,
clnt
->
cl_protname
,
clnt
->
cl_server
);
clnt
->
cl_protname
,
clnt
->
cl_server
);
while
(
clnt
->
cl_users
)
{
dprintk
(
"sigmask %08lx
\n
"
,
current
->
signal
);
dprintk
(
"users %d
\n
"
,
clnt
->
cl_users
);
clnt
->
cl_dead
=
1
;
#ifdef RPC_DEBUG
printk
(
"rpc_shutdown_client: client %s, tasks=%d
\n
"
,
clnt
->
cl_protname
,
clnt
->
cl_users
);
#endif
/* Don't let rpc_release_client destroy us */
clnt
->
cl_oneshot
=
0
;
clnt
->
cl_dead
=
0
;
rpc_killall_tasks
(
clnt
);
sleep_on
(
&
destroy_wait
);
}
...
...
@@ -162,12 +168,16 @@ rpc_release_client(struct rpc_clnt *clnt)
{
dprintk
(
"RPC: rpc_release_client(%p, %d)
\n
"
,
clnt
,
clnt
->
cl_users
);
if
(
--
(
clnt
->
cl_users
)
==
0
)
{
wake_up
(
&
destroy_wait
);
if
(
clnt
->
cl_oneshot
||
clnt
->
cl_dead
)
rpc_destroy_client
(
clnt
);
}
dprintk
(
"RPC: rpc_release_client done
\n
"
);
if
(
clnt
->
cl_users
)
{
if
(
--
(
clnt
->
cl_users
)
>
0
)
return
;
}
else
printk
(
"rpc_release_client: %s client already free??
\n
"
,
clnt
->
cl_protname
);
wake_up
(
&
destroy_wait
);
if
(
clnt
->
cl_oneshot
||
clnt
->
cl_dead
)
rpc_destroy_client
(
clnt
);
}
/*
...
...
@@ -205,10 +215,9 @@ rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
if
((
async
=
(
flags
&
RPC_TASK_ASYNC
))
!=
0
)
{
if
(
!
func
)
func
=
rpc_default_callback
;
if
(
!
(
task
=
rpc_new_task
(
clnt
,
func
,
flags
)))
{
current
->
blocked
=
oldmask
;
return
-
ENOMEM
;
}
status
=
-
ENOMEM
;
if
(
!
(
task
=
rpc_new_task
(
clnt
,
func
,
flags
)))
goto
out
;
task
->
tk_calldata
=
data
;
}
else
{
rpc_init_task
(
task
,
clnt
,
NULL
,
flags
);
...
...
@@ -222,12 +231,13 @@ rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
}
else
async
=
0
;
status
=
0
;
if
(
!
async
)
{
status
=
task
->
tk_status
;
rpc_release_task
(
task
);
}
else
status
=
0
;
}
out:
current
->
blocked
=
oldmask
;
return
status
;
}
...
...
@@ -354,6 +364,7 @@ call_allocate(struct rpc_task *task)
if
((
task
->
tk_buffer
=
rpc_malloc
(
task
,
bufsiz
))
!=
NULL
)
return
;
printk
(
"RPC: buffer allocation failed for task %p
\n
"
,
task
);
if
(
1
||
!
signalled
())
{
xprt_release
(
task
);
...
...
net/sunrpc/pmap_clnt.c
View file @
f59dfe26
...
...
@@ -54,15 +54,16 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
}
clnt
->
cl_binding
=
1
;
task
->
tk_status
=
0
;
if
(
!
(
pmap_clnt
=
pmap_create
(
clnt
->
cl_server
,
sap
,
map
->
pm_prot
)))
{
task
->
tk_status
=
-
EACCES
;
task
->
tk_status
=
-
EACCES
;
/* why set this? returns -EIO below */
if
(
!
(
pmap_clnt
=
pmap_create
(
clnt
->
cl_server
,
sap
,
map
->
pm_prot
)))
goto
bailout
;
}
if
(
!
(
child
=
rpc_new_child
(
pmap_clnt
,
task
)))
{
rpc_destroy_client
(
pmap_clnt
);
task
->
tk_status
=
0
;
/*
* Note: rpc_new_child will release client after a failure.
*/
if
(
!
(
child
=
rpc_new_child
(
pmap_clnt
,
task
)))
goto
bailout
;
}
/* Setup the call info struct */
rpc_call_setup
(
child
,
PMAP_GETPORT
,
map
,
&
clnt
->
cl_port
,
0
);
...
...
net/sunrpc/sched.c
View file @
f59dfe26
...
...
@@ -56,7 +56,8 @@ static struct rpc_task * all_tasks = NULL;
*/
static
struct
wait_queue
*
rpciod_idle
=
NULL
;
static
struct
wait_queue
*
rpciod_killer
=
NULL
;
static
int
rpciod_sema
=
0
;
static
struct
semaphore
rpciod_sema
=
MUTEX
;
static
unsigned
int
rpciod_users
=
0
;
static
pid_t
rpciod_pid
=
0
;
static
int
rpc_inhibit
=
0
;
...
...
@@ -575,19 +576,36 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
current
->
pid
);
}
/*
* Create a new task for the specified client. We have to
* clean up after an allocation failure, as the client may
* have specified "oneshot".
*/
struct
rpc_task
*
rpc_new_task
(
struct
rpc_clnt
*
clnt
,
rpc_action
callback
,
int
flags
)
{
struct
rpc_task
*
task
;
if
(
!
(
task
=
(
struct
rpc_task
*
)
rpc_allocate
(
flags
,
sizeof
(
*
task
))))
return
NULL
;
task
=
(
struct
rpc_task
*
)
rpc_allocate
(
flags
,
sizeof
(
*
task
));
if
(
!
task
)
goto
cleanup
;
rpc_init_task
(
task
,
clnt
,
callback
,
flags
);
dprintk
(
"RPC: %4d allocated task
\n
"
,
task
->
tk_pid
);
task
->
tk_flags
|=
RPC_TASK_DYNAMIC
;
out:
return
task
;
cleanup:
/* Check whether to release the client */
if
(
clnt
)
{
printk
(
"rpc_new_task: failed, users=%d, oneshot=%d
\n
"
,
clnt
->
cl_users
,
clnt
->
cl_oneshot
);
clnt
->
cl_users
++
;
/* pretend we were used ... */
rpc_release_client
(
clnt
);
}
goto
out
;
}
void
...
...
@@ -662,6 +680,9 @@ rpc_child_exit(struct rpc_task *child)
rpc_release_task
(
child
);
}
/*
* Note: rpc_new_task releases the client after a failure.
*/
struct
rpc_task
*
rpc_new_child
(
struct
rpc_clnt
*
clnt
,
struct
rpc_task
*
parent
)
{
...
...
@@ -715,11 +736,15 @@ rpciod(void *ptr)
unsigned
long
oldflags
;
int
rounds
=
0
;
MOD_INC_USE_COUNT
;
lock_kernel
();
/*
* Let our maker know we're running ...
*/
rpciod_pid
=
current
->
pid
;
wake_up
(
&
rpciod_idle
);
MOD_INC_USE_COUNT
;
/* exit_files(current); */
exit_files
(
current
);
exit_mm
(
current
);
current
->
blocked
|=
~
_S
(
SIGKILL
);
current
->
session
=
1
;
...
...
@@ -727,25 +752,28 @@ rpciod(void *ptr)
sprintf
(
current
->
comm
,
"rpciod"
);
dprintk
(
"RPC: rpciod starting (pid %d)
\n
"
,
rpciod_pid
);
while
(
rpciod_
sema
)
{
while
(
rpciod_
users
)
{
if
(
signalled
())
{
if
(
current
->
signal
&
_S
(
SIGKILL
))
{
rpciod_killall
();
}
else
{
printk
(
"rpciod: ignoring signal (%d users)
\n
"
,
rpciod_
sema
);
rpciod_
users
);
}
current
->
signal
&=
current
->
blocked
;
}
__rpc_schedule
();
if
(
++
rounds
>=
64
)
/* safeguard */
if
(
++
rounds
>=
64
)
{
/* safeguard */
schedule
();
rounds
=
0
;
}
save_flags
(
oldflags
);
cli
();
if
(
!
schedq
.
task
)
{
dprintk
(
"RPC: rpciod back to sleep
\n
"
);
interruptible_sleep_on
(
&
rpciod_idle
);
dprintk
(
"RPC: switch to rpciod
\n
"
);
rounds
=
0
;
}
restore_flags
(
oldflags
);
}
...
...
@@ -780,26 +808,84 @@ rpciod_killall(void)
}
}
void
/*
* Start up the rpciod process if it's not already running.
*/
int
rpciod_up
(
void
)
{
dprintk
(
"rpciod_up pid %d sema %d
\n
"
,
rpciod_pid
,
rpciod_sema
);
if
(
!
(
rpciod_sema
++
)
||
!
rpciod_pid
)
kernel_thread
(
rpciod
,
&
rpciod_killer
,
0
);
int
error
=
0
;
MOD_INC_USE_COUNT
;
down
(
&
rpciod_sema
);
dprintk
(
"rpciod_up: pid %d, users %d
\n
"
,
rpciod_pid
,
rpciod_users
);
rpciod_users
++
;
if
(
rpciod_pid
)
goto
out
;
/*
* If there's no pid, we should be the first user.
*/
if
(
rpciod_users
>
1
)
printk
(
"rpciod_up: no pid, %d users??
\n
"
,
rpciod_users
);
/*
* Create the rpciod thread and wait for it to start.
*/
error
=
kernel_thread
(
rpciod
,
&
rpciod_killer
,
0
);
if
(
error
<
0
)
{
printk
(
"rpciod_up: create thread failed, error=%d
\n
"
,
error
);
goto
out
;
}
sleep_on
(
&
rpciod_idle
);
error
=
0
;
out:
up
(
&
rpciod_sema
);
MOD_DEC_USE_COUNT
;
return
error
;
}
void
rpciod_down
(
void
)
{
dprintk
(
"rpciod_down pid %d sema %d
\n
"
,
rpciod_pid
,
rpciod_sema
);
if
(
--
rpciod_sema
>
0
)
return
;
unsigned
long
oldflags
;
MOD_INC_USE_COUNT
;
down
(
&
rpciod_sema
);
dprintk
(
"rpciod_down pid %d sema %d
\n
"
,
rpciod_pid
,
rpciod_users
);
if
(
rpciod_users
)
{
if
(
--
rpciod_users
)
goto
out
;
}
else
printk
(
"rpciod_down: pid=%d, no users??
\n
"
,
rpciod_pid
);
if
(
!
rpciod_pid
)
{
printk
(
"rpciod_down: Nothing to do!
\n
"
);
goto
out
;
}
rpciod_sema
=
0
;
kill_proc
(
rpciod_pid
,
SIGKILL
,
1
);
/*
* Usually rpciod will exit very quickly, so we
* wait briefly before checking the process id.
*/
oldflags
=
current
->
signal
;
current
->
signal
=
0
;
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
1
;
schedule
();
current
->
timeout
=
0
;
/*
* Display a message if we're going to wait longer.
*/
while
(
rpciod_pid
)
{
if
(
signalled
())
return
;
printk
(
"rpciod_down: waiting for pid %d to exit
\n
"
,
rpciod_pid
);
if
(
signalled
())
{
printk
(
"rpciod_down: caught signal
\n
"
);
break
;
}
interruptible_sleep_on
(
&
rpciod_killer
);
}
current
->
signal
=
oldflags
;
out:
up
(
&
rpciod_sema
);
MOD_DEC_USE_COUNT
;
}
net/sunrpc/svc.c
View file @
f59dfe26
...
...
@@ -62,8 +62,12 @@ svc_destroy(struct svc_serv *serv)
serv
->
sv_program
->
pg_name
,
serv
->
sv_nrthreads
);
if
(
--
(
serv
->
sv_nrthreads
)
!=
0
)
return
;
if
(
serv
->
sv_nrthreads
)
{
if
(
--
(
serv
->
sv_nrthreads
)
!=
0
)
return
;
}
else
printk
(
"svc_destroy: no threads for serv=%p!
\n
"
,
serv
);
while
((
svsk
=
serv
->
sv_allsocks
)
!=
NULL
)
svc_delete_socket
(
svsk
);
...
...
@@ -110,30 +114,31 @@ svc_release_buffer(struct svc_buf *bufp)
int
svc_create_thread
(
svc_thread_fn
func
,
struct
svc_serv
*
serv
)
{
struct
svc_rqst
*
rqstp
=
0
;
int
error
;
struct
svc_rqst
*
rqstp
;
int
error
=
-
ENOMEM
;
if
(
!
(
rqstp
=
kmalloc
(
sizeof
(
*
rqstp
),
GFP_KERNEL
)))
return
-
ENOMEM
;
rqstp
=
kmalloc
(
sizeof
(
*
rqstp
),
GFP_KERNEL
);
if
(
!
rqstp
)
goto
out
;
memset
(
rqstp
,
0
,
sizeof
(
*
rqstp
));
if
(
!
(
rqstp
->
rq_argp
=
(
u32
*
)
kmalloc
(
serv
->
sv_xdrsize
,
GFP_KERNEL
))
||
!
(
rqstp
->
rq_resp
=
(
u32
*
)
kmalloc
(
serv
->
sv_xdrsize
,
GFP_KERNEL
))
||
!
svc_init_buffer
(
&
rqstp
->
rq_defbuf
,
serv
->
sv_bufsz
))
{
error
=
-
ENOMEM
;
goto
failure
;
}
||
!
svc_init_buffer
(
&
rqstp
->
rq_defbuf
,
serv
->
sv_bufsz
))
goto
out_thread
;
serv
->
sv_nrthreads
++
;
if
((
error
=
kernel_thread
((
int
(
*
)(
void
*
))
func
,
rqstp
,
0
))
<
0
)
goto
failure
;
rqstp
->
rq_server
=
serv
;
return
0
;
error
=
kernel_thread
((
int
(
*
)(
void
*
))
func
,
rqstp
,
0
);
if
(
error
<
0
)
goto
out_thread
;
error
=
0
;
out:
return
error
;
failure
:
out_thread
:
svc_exit_thread
(
rqstp
);
return
error
;
goto
out
;
}
/*
...
...
@@ -152,7 +157,8 @@ svc_exit_thread(struct svc_rqst *rqstp)
kfree
(
rqstp
);
/* Release the server */
svc_destroy
(
serv
);
if
(
serv
)
svc_destroy
(
serv
);
}
/*
...
...
net/sunrpc/svcsock.c
View file @
f59dfe26
...
...
@@ -743,14 +743,18 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp)
if
((
svsk
=
svc_sock_dequeue
(
serv
))
!=
NULL
)
{
enable_bh
(
NET_BH
);
rqstp
->
rq_sock
=
svsk
;
svsk
->
sk_inuse
++
;
svsk
->
sk_inuse
++
;
/* N.B. where is this decremented? */
}
else
{
/* No data pending. Go to sleep */
rqstp
->
rq_sock
=
NULL
;
rqstp
->
rq_wait
=
NULL
;
svc_serv_enqueue
(
serv
,
rqstp
);
current
->
state
=
TASK_UNINTERRUPTIBLE
;
/*
* We have to be able to interrupt this wait
* to bring down the daemons ...
*/
current
->
state
=
TASK_INTERRUPTIBLE
;
add_wait_queue
(
&
rqstp
->
rq_wait
,
&
wait
);
enable_bh
(
NET_BH
);
schedule
();
...
...
@@ -762,6 +766,7 @@ 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