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
73f103e4
Commit
73f103e4
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 2.1.61
parent
be6cc637
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
937 additions
and
690 deletions
+937
-690
CREDITS
CREDITS
+1
-1
MAINTAINERS
MAINTAINERS
+2
-2
Makefile
Makefile
+1
-1
arch/i386/defconfig
arch/i386/defconfig
+8
-2
fs/Config.in
fs/Config.in
+8
-11
fs/autofs/root.c
fs/autofs/root.c
+17
-8
fs/dcache.c
fs/dcache.c
+6
-10
fs/isofs/dir.c
fs/isofs/dir.c
+5
-1
fs/isofs/inode.c
fs/isofs/inode.c
+8
-4
fs/namei.c
fs/namei.c
+26
-24
fs/nfs/dir.c
fs/nfs/dir.c
+141
-57
fs/nfs/file.c
fs/nfs/file.c
+59
-30
fs/nfs/inode.c
fs/nfs/inode.c
+9
-4
fs/nfs/write.c
fs/nfs/write.c
+44
-20
fs/nls/Config.in
fs/nls/Config.in
+33
-28
fs/nls/Makefile
fs/nls/Makefile
+4
-9
fs/nls/nls_base.c
fs/nls/nls_base.c
+3
-5
fs/smbfs/cache.c
fs/smbfs/cache.c
+5
-4
fs/smbfs/dir.c
fs/smbfs/dir.c
+46
-32
fs/smbfs/inode.c
fs/smbfs/inode.c
+50
-42
fs/smbfs/ioctl.c
fs/smbfs/ioctl.c
+13
-12
fs/smbfs/proc.c
fs/smbfs/proc.c
+126
-119
fs/smbfs/sock.c
fs/smbfs/sock.c
+164
-119
fs/vfat/namei.c
fs/vfat/namei.c
+11
-21
include/asm-alpha/socket.h
include/asm-alpha/socket.h
+0
-2
include/linux/dcache.h
include/linux/dcache.h
+11
-1
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+1
-1
include/linux/posix_types.h
include/linux/posix_types.h
+1
-1
include/linux/smb_fs.h
include/linux/smb_fs.h
+5
-9
include/linux/smb_fs_sb.h
include/linux/smb_fs_sb.h
+1
-2
mm/mmap.c
mm/mmap.c
+36
-37
mm/swap_state.c
mm/swap_state.c
+31
-18
mm/swapfile.c
mm/swapfile.c
+61
-53
No files found.
CREDITS
View file @
73f103e4
...
...
@@ -215,7 +215,7 @@ S: Fremont, California 94539
S: USA
N: Gordon Chaffee
E: chaffee@
bmrc
.berkeley.edu
E: chaffee@
cs
.berkeley.edu
W: http://bmrc.berkeley.edu/people/chaffee/
D: vfat, fat32, joliet, native language support
S: 3674 Oakwood Terrace #201
...
...
MAINTAINERS
View file @
73f103e4
...
...
@@ -368,9 +368,9 @@ S: Maintained
VFAT FILESYSTEM:
P: Gordon Chaffee
M: chaffee@
plateau.
cs.berkeley.edu
M: chaffee@cs.berkeley.edu
L: linux-kernel@vger.rutgers.edu
W: http://
www-plateau.cs
.berkeley.edu/people/chaffee
W: http://
bmrc
.berkeley.edu/people/chaffee
S: Maintained
DIGI INTL. EPCA DRIVER:
...
...
Makefile
View file @
73f103e4
VERSION
=
2
PATCHLEVEL
=
1
SUBLEVEL
=
6
0
SUBLEVEL
=
6
1
ARCH
:=
$(
shell
uname
-m
|
sed
-e
s/i.86/i386/
-e
s/sun4u/sparc64/
)
...
...
arch/i386/defconfig
View file @
73f103e4
...
...
@@ -198,10 +198,12 @@ CONFIG_EEXPRESS_PRO100=y
# CONFIG_QUOTA is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
# CONFIG_ROOT_NFS is not set
...
...
@@ -209,7 +211,6 @@ CONFIG_NFS_FS=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
...
...
@@ -218,6 +219,11 @@ CONFIG_AUTOFS_FS=y
# CONFIG_UFS_FS is not set
# CONFIG_MAC_PARTITION is not set
#
# Native Language Support
#
# CONFIG_NLS is not set
#
# Character devices
#
...
...
fs/Config.in
View file @
73f103e4
...
...
@@ -10,19 +10,16 @@ tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
tristate 'Native language support (Unicode, codepages)' CONFIG_NLS
if [ "$CONFIG_NLS" = "y" -o "$CONFIG_NLS" = "m" ]; then
if [ "$CONFIG_ISO9660_FS" = "y" -o "$CONFIG_ISO9660_FS" = "m" ]; then
bool 'Microsoft Joliet cdrom extensions' CONFIG_JOLIET
fi
# msdos filesystems
dep_tristate 'DOS FAT fs support' CONFIG_FAT_FS $CONFIG_NLS
dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
if [ "$CONFIG_ISO9660_FS" != "n" ]; then
bool 'Microsoft Joliet cdrom extensions' CONFIG_JOLIET
fi
# msdos filesystems
tristate 'DOS FAT fs support' CONFIG_FAT_FS
dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
bool '/proc filesystem support' CONFIG_PROC_FS
if [ "$CONFIG_INET" = "y" ]; then
tristate 'NFS filesystem support' CONFIG_NFS_FS
...
...
fs/autofs/root.c
View file @
73f103e4
...
...
@@ -100,7 +100,7 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
return
0
;
}
static
int
try_to_fill_dentry
(
struct
dentry
*
dentry
,
struct
super_block
*
sb
,
struct
autofs_sb_info
*
sbi
)
static
int
try_to_fill_dentry
(
struct
dentry
*
dentry
,
struct
super_block
*
sb
,
struct
autofs_sb_info
*
sbi
)
{
struct
inode
*
inode
;
struct
autofs_dir_ent
*
ent
;
...
...
@@ -132,9 +132,10 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
dentry
->
d_inode
=
inode
;
}
if
(
S_ISDIR
(
dentry
->
d_inode
->
i_mode
))
{
while
(
dentry
==
dentry
->
d_mounts
)
schedule
();
/* If this is a directory that isn't a mount point, bitch at the
daemon and fix it in user space */
if
(
S_ISDIR
(
dentry
->
d_inode
->
i_mode
)
&&
dentry
->
d_mounts
==
dentry
)
{
return
!
autofs_wait
(
sbi
,
&
dentry
->
d_name
);
}
autofs_update_usage
(
&
sbi
->
dirhash
,
ent
);
...
...
@@ -159,16 +160,24 @@ static int autofs_revalidate(struct dentry * dentry)
sbi
=
(
struct
autofs_sb_info
*
)
dir
->
i_sb
->
u
.
generic_sbp
;
/* Pending dentry */
if
(
dentry
->
d_flags
&
DCACHE_AUTOFS_PENDING
)
{
if
(
dentry
->
d_flags
&
DCACHE_AUTOFS_PENDING
)
{
if
(
autofs_oz_mode
(
sbi
))
return
1
;
return
try_to_fill_dentry
(
dentry
,
dir
->
i_sb
,
sbi
);
else
return
try_to_fill_dentry
(
dentry
,
dir
->
i_sb
,
sbi
);
}
/* Negative dentry.. invalidate if "old" */
if
(
!
dentry
->
d_inode
)
return
(
dentry
->
d_time
-
jiffies
<=
AUTOFS_NEGATIVE_TIMEOUT
);
/* Check for a non-mountpoint directory */
if
(
S_ISDIR
(
dentry
->
d_inode
->
i_mode
)
&&
dentry
->
d_mounts
==
dentry
)
{
if
(
autofs_oz_mode
(
sbi
))
return
1
;
else
return
try_to_fill_dentry
(
dentry
,
dir
->
i_sb
,
sbi
);
}
/* Update the usage list */
ent
=
(
struct
autofs_dir_ent
*
)
dentry
->
d_time
;
...
...
@@ -177,7 +186,7 @@ static int autofs_revalidate(struct dentry * dentry)
}
static
struct
dentry_operations
autofs_dentry_operations
=
{
autofs_revalidate
,
autofs_revalidate
,
/* d_revalidate */
NULL
,
/* d_hash */
NULL
,
/* d_compare */
};
...
...
fs/dcache.c
View file @
73f103e4
...
...
@@ -465,12 +465,13 @@ static inline struct list_head * d_hash(struct dentry * parent, unsigned long ha
return
dentry_hashtable
+
(
hash
&
D_HASHMASK
);
}
st
atic
inline
struct
dentry
*
__dlookup
(
struct
list_head
*
head
,
struct
dentry
*
parent
,
struct
qstr
*
name
)
st
ruct
dentry
*
d_lookup
(
struct
dentry
*
parent
,
struct
qstr
*
name
)
{
struct
list_head
*
tmp
=
head
->
next
;
int
len
=
name
->
len
;
int
hash
=
name
->
hash
;
unsigned
int
len
=
name
->
len
;
unsigned
int
hash
=
name
->
hash
;
const
unsigned
char
*
str
=
name
->
name
;
struct
list_head
*
head
=
d_hash
(
parent
,
hash
);
struct
list_head
*
tmp
=
head
->
next
;
while
(
tmp
!=
head
)
{
struct
dentry
*
dentry
=
list_entry
(
tmp
,
struct
dentry
,
d_hash
);
...
...
@@ -489,16 +490,11 @@ static inline struct dentry * __dlookup(struct list_head *head, struct dentry *
if
(
memcmp
(
dentry
->
d_name
.
name
,
str
,
len
))
continue
;
}
return
dget
(
dentry
->
d_mounts
);
return
dget
(
dentry
);
}
return
NULL
;
}
struct
dentry
*
d_lookup
(
struct
dentry
*
dir
,
struct
qstr
*
name
)
{
return
__dlookup
(
d_hash
(
dir
,
name
->
hash
),
dir
,
name
);
}
/*
* An insecure source has sent us a dentry, here we verify it.
*
...
...
fs/isofs/dir.c
View file @
73f103e4
...
...
@@ -20,6 +20,7 @@
#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/locks.h>
#include <linux/config.h>
#include <asm/uaccess.h>
...
...
@@ -206,10 +207,13 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
}
#ifdef CONFIG_JOLIET
if
(
inode
->
i_sb
->
u
.
isofs_sb
.
s_joliet_level
)
{
len
=
get_joliet_filename
(
de
,
inode
,
tmpname
);
p
=
tmpname
;
}
else
{
}
else
#endif
/* if not joliet */
{
map
=
1
;
if
(
inode
->
i_sb
->
u
.
isofs_sb
.
s_rock
)
{
len
=
get_rock_ridge_filename
(
de
,
tmpname
,
inode
);
...
...
fs/isofs/inode.c
View file @
73f103e4
...
...
@@ -89,8 +89,7 @@ struct iso9660_options{
static
int
parse_options
(
char
*
options
,
struct
iso9660_options
*
popt
)
{
char
*
this_char
,
*
value
,
*
p
;
int
len
;
char
*
this_char
,
*
value
;
popt
->
map
=
'n'
;
popt
->
rock
=
'y'
;
...
...
@@ -135,6 +134,9 @@ static int parse_options(char *options, struct iso9660_options * popt)
#ifdef CONFIG_JOLIET
if
(
!
strcmp
(
this_char
,
"iocharset"
))
{
char
*
p
;
int
len
;
p
=
value
;
while
(
*
value
&&
*
value
!=
','
)
value
++
;
len
=
value
-
p
;
...
...
@@ -275,7 +277,6 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
int
joliet_level
=
0
;
struct
iso9660_options
opt
;
int
orig_zonesize
;
char
*
p
;
struct
iso_primary_descriptor
*
pri
=
NULL
;
struct
iso_directory_record
*
rootp
;
struct
iso_supplementary_descriptor
*
sec
=
NULL
;
...
...
@@ -413,8 +414,10 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
MOD_DEC_USE_COUNT
;
return
NULL
;
}
#ifdef CONFIG_JOLIET
s
->
u
.
isofs_sb
.
s_joliet_level
=
joliet_level
;
#ifdef CONFIG_JOLIET
if
(
joliet_level
)
{
/* Note: In theory, it is possible to have Rock Ridge
* extensions mixed with Joliet. All character strings
...
...
@@ -549,6 +552,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
opt
.
iocharset
=
NULL
;
}
}
else
if
(
opt
.
utf8
==
0
)
{
char
*
p
;
p
=
opt
.
iocharset
?
opt
.
iocharset
:
"iso8859-1"
;
s
->
u
.
isofs_sb
.
s_nls_iocharset
=
load_nls
(
p
);
if
(
!
s
->
u
.
isofs_sb
.
s_nls_iocharset
)
{
...
...
fs/namei.c
View file @
73f103e4
...
...
@@ -237,8 +237,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
int
error
=
dir
->
i_op
->
lookup
(
dir
,
dentry
);
result
=
ERR_PTR
(
error
);
if
(
!
error
)
result
=
dget
(
dentry
->
d_mounts
);
dput
(
dentry
);
result
=
dentry
;
}
}
up
(
&
dir
->
i_sem
);
...
...
@@ -293,25 +292,6 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
return
dget
(
result
);
}
/* In difference to the former version, lookup() no longer eats the dir. */
static
inline
struct
dentry
*
lookup
(
struct
dentry
*
dir
,
struct
qstr
*
name
)
{
struct
dentry
*
result
;
result
=
reserved_lookup
(
dir
,
name
);
if
(
result
)
goto
done
;
result
=
cached_lookup
(
dir
,
name
);
if
(
result
)
goto
done
;
result
=
real_lookup
(
dir
,
name
);
done:
return
result
;
}
static
struct
dentry
*
do_follow_link
(
struct
dentry
*
base
,
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
...
...
@@ -334,6 +314,18 @@ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry
return
dentry
;
}
static
inline
struct
dentry
*
follow_mount
(
struct
dentry
*
dentry
)
{
struct
dentry
*
mnt
=
dentry
->
d_mounts
;
if
(
mnt
!=
dentry
)
{
dget
(
mnt
);
dput
(
dentry
);
dentry
=
mnt
;
}
return
dentry
;
}
/*
* Name resolution.
*
...
...
@@ -415,9 +407,19 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, int follo
}
}
dentry
=
lookup
(
base
,
&
this
);
if
(
IS_ERR
(
dentry
))
break
;
/* This does the actual lookups.. */
dentry
=
reserved_lookup
(
base
,
&
this
);
if
(
!
dentry
)
{
dentry
=
cached_lookup
(
base
,
&
this
);
if
(
!
dentry
)
{
dentry
=
real_lookup
(
base
,
&
this
);
if
(
IS_ERR
(
dentry
))
break
;
}
}
/* Check mountpoints.. */
dentry
=
follow_mount
(
dentry
);
if
(
!
follow
)
break
;
...
...
fs/nfs/dir.c
View file @
73f103e4
...
...
@@ -333,7 +333,6 @@ nfs_invalidate_dircache_sb(struct super_block *sb)
{
struct
nfs_dirent
*
cache
=
dircache
;
int
i
;
int
freed
=
0
;
for
(
i
=
NFS_MAX_DIRCACHE
;
i
--
;
cache
++
)
{
if
(
sb
&&
sb
->
s_dev
!=
cache
->
dev
)
...
...
@@ -347,14 +346,8 @@ nfs_invalidate_dircache_sb(struct super_block *sb)
if
(
cache
->
entry
)
{
free_page
((
unsigned
long
)
cache
->
entry
);
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
}
/*
...
...
@@ -472,9 +465,9 @@ static int nfs_instantiate(struct inode *dir, struct dentry *dentry,
struct
inode
*
inode
;
int
error
=
-
EACCES
;
nfs_invalidate_dircache
(
dir
);
inode
=
nfs_fhget
(
dir
->
i_sb
,
fhandle
,
fattr
);
if
(
inode
)
{
nfs_invalidate_dircache
(
dir
);
d_instantiate
(
dentry
,
inode
);
nfs_renew_times
(
dentry
);
error
=
0
;
...
...
@@ -638,14 +631,15 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
{
struct
qstr
sqstr
;
struct
dentry
*
sdentry
;
unsigned
long
hash
;
int
i
,
error
;
sqstr
.
name
=
silly
;
sqstr
.
len
=
slen
;
sqstr
.
hash
=
init_name_hash
();
hash
=
init_name_hash
();
for
(
i
=
0
;
i
<
slen
;
i
++
)
sqstr
.
hash
=
partial_name_hash
(
silly
[
i
],
sqstr
.
hash
);
sqstr
.
hash
=
end_name_hash
(
sqstr
.
hash
);
hash
=
partial_name_hash
(
silly
[
i
],
hash
);
sqstr
.
hash
=
end_name_hash
(
hash
);
sdentry
=
d_lookup
(
parent
,
&
sqstr
);
if
(
!
sdentry
)
{
sdentry
=
d_alloc
(
parent
,
&
sqstr
);
...
...
@@ -674,6 +668,11 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
return
-
EIO
;
/* No need to silly rename. */
}
#ifdef NFS_PARANOIA
if
(
!
dentry
->
d_inode
)
printk
(
"NFS: silly-renaming %s/%s, negative dentry??
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
if
(
dentry
->
d_flags
&
DCACHE_NFSFS_RENAMED
)
{
return
-
EBUSY
;
/* don't allow to unlink silly inode -- nope,
* think a bit: silly DENTRY, NOT inode --
...
...
@@ -729,20 +728,28 @@ static void nfs_silly_delete(struct dentry *dentry)
error
=
nfs_proc_remove
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
error
<
0
)
printk
(
"NFS "
__FUNCTION__
" failed (err = %d)
\n
"
,
-
error
);
printk
(
"NFS: can't silly-delete %s/%s, error=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
error
);
if
(
dentry
->
d_inode
)
{
if
(
dentry
->
d_inode
->
i_nlink
)
dentry
->
d_inode
->
i_nlink
--
;
}
else
}
else
{
#ifdef NFS_PARANOIA
printk
(
"nfs_silly_delete: negative dentry %s/%s
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
#endif
}
nfs_invalidate_dircache
(
dir
);
/*
* The dentry is unhashed, but we want to make it negative.
*/
d_delete
(
dentry
);
}
/*
* Check whether to expire the dentry ...
*/
else
{
unsigned
long
age
=
jiffies
-
dentry
->
d_time
;
if
(
age
>
10
*
HZ
)
d_drop
(
dentry
);
}
}
...
...
@@ -769,12 +776,22 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
return
-
ENOENT
;
}
error
=
-
ENAMETOOLONG
;
if
(
dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
goto
out
;
error
=
nfs_sillyrename
(
dir
,
dentry
);
if
(
error
&&
error
!=
-
EBUSY
)
{
#ifdef NFS_PARANOIA
if
(
dentry
->
d_count
>
1
)
printk
(
"nfs_unlink: dentry %s/%s, d_count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
);
if
(
dentry
->
d_inode
&&
dentry
->
d_inode
->
i_count
>
1
)
printk
(
"nfs_unlink: dentry %s/%s, inode i_count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_inode
->
i_count
);
#endif
/* N.B. should check for d_count > 1 and fail */
error
=
nfs_proc_remove
(
NFS_SERVER
(
dir
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
!
error
)
{
...
...
@@ -785,11 +802,12 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
d_delete
(
dentry
);
}
}
out:
return
error
;
}
static
int
nfs_symlink
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
const
char
*
symname
)
static
int
nfs_symlink
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
const
char
*
symname
)
{
struct
nfs_sattr
sattr
;
int
error
;
...
...
@@ -802,11 +820,12 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
return
-
ENOENT
;
}
error
=
-
ENAMETOOLONG
;
if
(
dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
goto
out
;
if
(
strlen
(
symname
)
>
NFS_MAXPATHLEN
)
return
-
ENAMETOOLONG
;
goto
out
;
sattr
.
mode
=
S_IFLNK
|
S_IRWXUGO
;
/* SunOS 4.1.2 crashes without this! */
sattr
.
uid
=
sattr
.
gid
=
sattr
.
size
=
(
unsigned
)
-
1
;
...
...
@@ -827,10 +846,12 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
*/
d_drop
(
dentry
);
}
out:
return
error
;
}
static
int
nfs_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
dentry
*
dentry
)
static
int
nfs_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
dentry
*
dentry
)
{
int
error
;
...
...
@@ -843,18 +864,37 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
return
-
ENOENT
;
}
error
=
-
ENAMETOOLONG
;
if
(
dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
goto
out
;
/*
* The NFS server may want to use a new fileid for the link,
* so we can't reuse the existing inode for the new dentry.
* To force a new lookup after the link operation, we can just
* drop the new dentry, as long as it's not busy. (See above.)
*/
error
=
-
EBUSY
;
if
(
dentry
->
d_count
>
1
)
{
#ifdef NFS_PARANOIA
printk
(
"nfs_link: dentry %s/%s busy, count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
);
#endif
goto
out
;
}
d_drop
(
dentry
);
error
=
nfs_proc_link
(
NFS_SERVER
(
inode
),
NFS_FH
(
inode
),
NFS_FH
(
dir
),
dentry
->
d_name
.
name
);
if
(
!
error
)
{
nfs_invalidate_dircache
(
dir
);
#if 0
inode->i_count ++;
inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
d_instantiate(dentry, inode);
error
=
0
;
#endif
}
out:
return
error
;
}
...
...
@@ -875,16 +915,31 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
* implementation that only depends on the dcache stuff instead of
* using the inode layer
*
* Unfortunately, things are a little more complicated than indicated
* above. The NFS server may decide to use a new fileid for the renamed
* file, so we can't link the new name to the old inode. Otherwise, the
* server might reuse the fileid after the old file has been removed,
* which would leave the new dentry holding an invalid fileid (possibly
* leading to file corruption). To handle this consider these cases:
* (1) within-directory:
* -- no problem, just use nfs_proc_rename
* (2) cross-directory, only one user for old and new dentry:
* -- drop both dentries to force new lookups, then use rename
* (3) cross-directory, multiple users for old, one user for new:
* -- drop new dentry, silly-rename old dentry and make a link
* (4) cross-directory, multiple users for new dentry:
* -- sorry, we're busy.
*/
static
int
nfs_rename
(
struct
inode
*
old_dir
,
struct
dentry
*
old_dentry
,
struct
inode
*
new_dir
,
struct
dentry
*
new_dentry
)
{
int
error
;
dfprintk
(
VFS
,
"NFS: rename(%x/%ld, %s -> %x/%ld, %s)
\n
"
,
old_dir
->
i_dev
,
old_dir
->
i_ino
,
old_dentry
->
d_name
.
name
,
new_dir
->
i_dev
,
new_dir
->
i_ino
,
new_dentry
->
d_name
.
name
);
int
update
=
1
,
error
;
#ifdef NFS_DEBUG_VERBOSE
printk
(
"nfs_rename: old %s/%s, count=%d, new %s/%s, count=%d
\n
"
,
old_dentry
->
d_parent
->
d_name
.
name
,
old_dentry
->
d_name
.
name
,
old_dentry
->
d_count
,
new_dentry
->
d_parent
->
d_name
.
name
,
new_dentry
->
d_name
.
name
,
new_dentry
->
d_count
);
#endif
if
(
!
old_dir
||
!
S_ISDIR
(
old_dir
->
i_mode
))
{
printk
(
"nfs_rename: old inode is NULL or not a directory
\n
"
);
return
-
ENOENT
;
...
...
@@ -895,37 +950,66 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return
-
ENOENT
;
}
if
(
old_dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
||
new_dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
return
-
ENAMETOOLONG
;
if
(
new_dir
!=
old_dir
)
{
error
=
nfs_sillyrename
(
old_dir
,
old_dentry
);
if
(
error
==
-
EBUSY
)
{
return
-
EBUSY
;
}
else
if
(
error
==
0
)
{
/* did silly rename stuff */
error
=
nfs_link
(
old_dentry
->
d_inode
,
new_dir
,
new_dentry
);
return
error
;
}
/* no need for silly rename, proceed as usual */
}
error
=
-
ENAMETOOLONG
;
if
(
old_dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
||
new_dentry
->
d_name
.
len
>
NFS_MAXNAMLEN
)
goto
out
;
/*
* Examine the cases as noted above.
*/
if
(
new_dir
==
old_dir
)
goto
simple_case
;
error
=
-
EBUSY
;
if
(
new_dentry
->
d_count
>
1
)
{
#ifdef NFS_PARANOIA
printk
(
"nfs_rename: new dentry %s/%s busy, count=%d
\n
"
,
new_dentry
->
d_parent
->
d_name
.
name
,
new_dentry
->
d_name
.
name
,
new_dentry
->
d_count
);
#endif
goto
out
;
}
d_drop
(
new_dentry
);
if
(
old_dentry
->
d_count
>
1
)
goto
complex_case
;
d_drop
(
old_dentry
);
update
=
0
;
/* no need for silly rename, proceed as usual */
simple_case:
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
)
{
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
);
if
(
error
)
goto
out
;
nfs_invalidate_dircache
(
new_dir
);
nfs_invalidate_dircache
(
old_dir
);
/* Update the dcache */
/* Update the dcache if needed */
if
(
update
)
d_move
(
old_dentry
,
new_dentry
);
}
goto
out
;
/*
* We don't need to update the dcache in this case ... the
* new dentry has been dropped, and the old one silly-renamed.
*/
complex_case:
error
=
nfs_sillyrename
(
old_dir
,
old_dentry
);
if
(
error
)
goto
out
;
nfs_invalidate_dircache
(
old_dir
);
error
=
nfs_link
(
old_dentry
->
d_inode
,
new_dir
,
new_dentry
);
if
(
error
)
goto
out
;
nfs_invalidate_dircache
(
new_dir
);
#ifdef NFS_PARANOIA
printk
(
"nfs_rename: dentry %s/%s linked to %s/%s, old count=%d
\n
"
,
new_dentry
->
d_parent
->
d_name
.
name
,
new_dentry
->
d_name
.
name
,
old_dentry
->
d_parent
->
d_name
.
name
,
old_dentry
->
d_name
.
name
,
old_dentry
->
d_count
);
#endif
out:
return
error
;
}
...
...
fs/nfs/file.c
View file @
73f103e4
...
...
@@ -83,53 +83,77 @@ struct inode_operations nfs_file_inode_operations = {
# define IS_SWAPFILE(inode) (0)
#endif
/*
* Flush all dirty pages, and check for write errors.
*
* Note that since the file close operation is called only by the
* _last_ process to close the file, we need to flush _all_ dirty
* pages. This also means that there is little sense in checking
* for errors for this specific process -- we should probably just
* clear all errors.
*/
static
int
nfs_file_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
status
;
int
status
,
error
;
dfprintk
(
VFS
,
"nfs: close(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
if
((
status
=
nfs_flush_dirty_pages
(
inode
,
0
,
0
))
<
0
)
return
status
;
return
nfs_write_error
(
inode
);
status
=
nfs_flush_dirty_pages
(
inode
,
0
,
0
,
0
);
error
=
nfs_write_error
(
inode
);
if
(
!
status
)
status
=
error
;
return
status
;
}
static
ssize_t
nfs_file_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
inode
*
inode
=
file
->
f_dentry
->
d_inode
;
int
status
;
ssize_t
result
;
dfprintk
(
VFS
,
"nfs: read(%x/%ld, %lu@%lu)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
count
,
(
unsigned
long
)
*
ppos
);
if
((
status
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
))
<
0
)
return
status
;
return
generic_file_read
(
file
,
buf
,
count
,
ppos
);
result
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
if
(
!
result
)
result
=
generic_file_read
(
file
,
buf
,
count
,
ppos
);
return
result
;
}
static
int
nfs_file_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
int
status
;
struct
inode
*
inode
=
file
->
f_dentry
->
d_inode
;
int
status
;
dfprintk
(
VFS
,
"nfs: mmap(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
if
((
status
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
))
<
0
)
return
status
;
return
generic_file_mmap
(
file
,
vma
);
status
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
if
(
!
status
)
status
=
generic_file_mmap
(
file
,
vma
);
return
status
;
}
static
int
nfs_fsync
(
struct
file
*
file
,
struct
dentry
*
dentry
)
/*
* Flush any dirty pages for this process, and check for write errors.
* The return status from this call provides a reliable indication of
* whether any write errors occurred for this process.
*/
static
int
nfs_fsync
(
struct
file
*
file
,
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
int
status
,
error
;
dfprintk
(
VFS
,
"nfs: fsync(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
return
nfs_flush_dirty_pages
(
inode
,
0
,
0
);
status
=
nfs_flush_dirty_pages
(
inode
,
current
->
pid
,
0
,
0
);
error
=
nfs_write_error
(
inode
);
if
(
!
status
)
status
=
error
;
return
status
;
}
/*
...
...
@@ -139,7 +163,7 @@ static ssize_t
nfs_file_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
inode
*
inode
=
file
->
f_dentry
->
d_inode
;
int
result
;
ssize_t
result
;
dfprintk
(
VFS
,
"nfs: write(%x/%ld (%d), %lu@%lu)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
inode
->
i_count
,
...
...
@@ -153,21 +177,26 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
printk
(
"NFS: attempt to write to active swap file!
\n
"
);
return
-
EBUSY
;
}
if
((
result
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
))
<
0
)
return
result
;
result
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
if
(
result
)
goto
out
;
/* N.B. This should be impossible now -- inodes can't change mode */
if
(
!
S_ISREG
(
inode
->
i_mode
))
{
printk
(
"nfs_file_write: write to non-file, mode %07o
\n
"
,
inode
->
i_mode
);
return
-
EINVAL
;
}
if
(
count
<=
0
)
return
0
;
/* Return error from previous async call */
if
((
result
=
nfs_write_error
(
inode
))
<
0
)
return
result
;
return
generic_file_write
(
file
,
buf
,
count
,
ppos
);
result
=
count
;
if
(
!
count
)
goto
out
;
/* Check for an error from a previous async call */
result
=
nfs_write_error
(
inode
);
if
(
!
result
)
result
=
generic_file_write
(
file
,
buf
,
count
,
ppos
);
out:
return
result
;
}
/*
...
...
@@ -176,15 +205,15 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
int
nfs_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
)
{
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
int
status
;
struct
inode
*
inode
;
dprintk
(
"NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)
\n
"
,
filp
->
f_dentry
->
d_inode
->
i_dev
,
filp
->
f_dentry
->
d_
inode
->
i_ino
,
inode
->
i_dev
,
inode
->
i_ino
,
fl
->
fl_type
,
fl
->
fl_flags
,
fl
->
fl_start
,
fl
->
fl_end
);
if
(
!
(
inode
=
filp
->
f_dentry
->
d_inode
)
)
if
(
!
inode
)
return
-
EINVAL
;
/* No mandatory locks over NFS */
...
...
@@ -209,7 +238,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* been killed by a signal, that is). */
if
(
cmd
==
F_SETLK
&&
fl
->
fl_type
==
F_UNLCK
&&
!
signal_pending
(
current
))
{
status
=
nfs_flush_dirty_pages
(
inode
,
status
=
nfs_flush_dirty_pages
(
inode
,
current
->
pid
,
fl
->
fl_start
,
fl
->
fl_end
==
NLM_OFFSET_MAX
?
0
:
fl
->
fl_end
-
fl
->
fl_start
+
1
);
if
(
status
<
0
)
...
...
fs/nfs/inode.c
View file @
73f103e4
...
...
@@ -91,16 +91,19 @@ nfs_put_inode(struct inode * inode)
static
void
nfs_delete_inode
(
struct
inode
*
inode
)
{
int
failed
;
dprintk
(
"NFS: delete_inode(%x/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
/*
* Flush out any pending write requests ...
*/
if
(
NFS_WRITEBACK
(
inode
)
!=
NULL
)
{
unsigned
long
timeout
=
jiffies
+
5
*
HZ
;
printk
(
"NFS: invalidating pending RPC requests
\n
"
);
printk
(
"NFS: inode %ld, invalidating pending RPC requests
\n
"
,
inode
->
i_ino
);
nfs_invalidate_pages
(
inode
);
while
(
NFS_WRITEBACK
(
inode
)
!=
NULL
&&
jiffies
<
timeout
)
{
current
->
state
=
TASK_
UN
INTERRUPTIBLE
;
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
HZ
/
10
;
schedule
();
}
...
...
@@ -109,8 +112,10 @@ nfs_delete_inode(struct inode * inode)
printk
(
"NFS: Arghhh, stuck RPC requests!
\n
"
);
}
if
(
check_failed_request
(
inode
))
printk
(
"NFS: inode had failed requests
\n
"
);
failed
=
check_failed_request
(
inode
);
if
(
failed
)
printk
(
"NFS: inode %ld had %d failed requests
\n
"
,
inode
->
i_ino
,
failed
);
clear_inode
(
inode
);
}
...
...
fs/nfs/write.c
View file @
73f103e4
...
...
@@ -286,16 +286,17 @@ find_write_request(struct inode *inode, struct page *page)
* Find a failed write request by pid
*/
static
struct
nfs_wreq
*
find_failed_request
(
struct
inode
*
inode
,
pid_t
pid
,
int
all
)
find_failed_request
(
struct
inode
*
inode
,
pid_t
pid
)
{
struct
nfs_wreq
*
head
,
*
req
;
if
(
!
(
req
=
head
=
nfs_failed_requests
))
return
NULL
;
do
{
if
(
req
->
wb_inode
==
inode
&&
(
all
||
req
->
wb_pid
==
pid
))
req
=
head
=
nfs_failed_requests
;
while
(
req
!=
NULL
)
{
if
(
req
->
wb_inode
==
inode
&&
(
pid
==
0
||
req
->
wb_pid
==
pid
))
return
req
;
}
while
((
req
=
WB_NEXT
(
req
))
!=
head
);
if
((
req
=
WB_NEXT
(
req
))
==
head
)
break
;
}
return
NULL
;
}
...
...
@@ -335,7 +336,7 @@ check_failed_request(struct inode * inode)
struct
nfs_wreq
*
req
;
int
found
=
0
;
while
((
req
=
find_failed_request
(
inode
,
0
,
1
))
!=
NULL
)
{
while
((
req
=
find_failed_request
(
inode
,
0
))
!=
NULL
)
{
remove_failed_request
(
req
);
found
++
;
}
...
...
@@ -561,12 +562,13 @@ nfs_updatepage(struct inode *inode, struct page *page, const char *buffer,
}
/* Create the write request. */
if
(
!
(
req
=
create_write_request
(
inode
,
page
,
offset
,
count
)))
{
status
=
-
ENOBUFS
;
status
=
-
ENOBUFS
;
req
=
create_write_request
(
inode
,
page
,
offset
,
count
);
if
(
!
req
)
goto
done
;
}
/* Copy data to page buffer. */
/* N.B. should check for fault here ... */
copy_from_user
(
page_addr
+
offset
,
buffer
,
count
);
/* Schedule request */
...
...
@@ -593,6 +595,7 @@ nfs_updatepage(struct inode *inode, struct page *page, const char *buffer,
transfer_page_lock
(
req
);
/* rpc_execute(&req->wb_task); */
if
(
sync
)
{
/* N.B. if signalled, result not ready? */
wait_on_write_request
(
req
);
if
((
count
=
nfs_write_error
(
inode
))
<
0
)
status
=
count
;
...
...
@@ -652,10 +655,20 @@ nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len,
if
(
rqoffset
<
end
&&
offset
<
rqend
&&
(
pid
==
0
||
req
->
wb_pid
==
pid
))
{
if
(
!
WB_HAVELOCK
(
req
))
if
(
!
WB_HAVELOCK
(
req
))
{
#ifdef NFS_PARANOIA
printk
(
"nfs_flush: flushing inode=%ld, %d @ %lu
\n
"
,
req
->
wb_inode
->
i_ino
,
req
->
wb_bytes
,
rqoffset
);
#endif
nfs_flush_request
(
req
);
}
last
=
req
;
}
}
else
{
#ifdef NFS_PARANOIA
printk
(
"nfs_flush_pages: in progress inode=%ld, %d @ %lu
\n
"
,
req
->
wb_inode
->
i_ino
,
req
->
wb_bytes
,
rqoffset
);
#endif
}
if
(
invalidate
)
req
->
wb_flags
|=
NFS_WRITE_INVALIDATE
;
...
...
@@ -668,6 +681,10 @@ nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len,
/*
* Cancel all writeback requests, both pending and in progress.
*
* N.B. This doesn't seem to wake up the tasks -- are we sure
* they will eventually complete? Also, this could overwrite a
* failed status code from an already-completed task.
*/
static
void
nfs_cancel_dirty
(
struct
inode
*
inode
,
pid_t
pid
)
...
...
@@ -676,7 +693,8 @@ nfs_cancel_dirty(struct inode *inode, pid_t pid)
req
=
head
=
NFS_WRITEBACK
(
inode
);
while
(
req
!=
NULL
)
{
if
(
req
->
wb_pid
==
pid
)
{
/* N.B. check for task already finished? */
if
(
pid
==
0
||
req
->
wb_pid
==
pid
)
{
req
->
wb_flags
|=
NFS_WRITE_CANCELLED
;
rpc_exit
(
&
req
->
wb_task
,
0
);
}
...
...
@@ -694,24 +712,30 @@ nfs_cancel_dirty(struct inode *inode, pid_t pid)
* this isn't used by the nlm module yet.
*/
int
nfs_flush_dirty_pages
(
struct
inode
*
inode
,
off_t
offset
,
off_t
len
)
nfs_flush_dirty_pages
(
struct
inode
*
inode
,
pid_t
pid
,
off_t
offset
,
off_t
len
)
{
struct
nfs_wreq
*
last
=
NULL
;
int
result
=
0
;
int
result
=
0
,
cancel
=
0
;
dprintk
(
"NFS: flush_dirty_pages(%x/%ld for pid %d %ld/%ld)
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
,
current
->
pid
,
offset
,
len
);
if
(
IS_SOFT
&&
signalled
())
{
nfs_cancel_dirty
(
inode
,
pid
);
cancel
=
1
;
}
for
(;;)
{
if
(
IS_SOFT
&&
signalled
())
{
nfs_cancel_dirty
(
inode
,
current
->
pid
);
if
(
!
cancel
)
nfs_cancel_dirty
(
inode
,
pid
);
result
=
-
ERESTARTSYS
;
break
;
}
/* Flush all pending writes for th
is
pid and file region */
last
=
nfs_flush_pages
(
inode
,
current
->
pid
,
offset
,
len
,
0
);
/* Flush all pending writes for th
e
pid and file region */
last
=
nfs_flush_pages
(
inode
,
pid
,
offset
,
len
,
0
);
if
(
last
==
NULL
)
break
;
wait_on_write_request
(
last
);
...
...
@@ -724,7 +748,7 @@ nfs_flush_dirty_pages(struct inode *inode, off_t offset, off_t len)
* Flush out any pending write requests and flag that they be discarded
* after the write is complete.
*
* This function is called from nfs_re
validate
_inode just before it calls
* This function is called from nfs_re
fresh
_inode just before it calls
* invalidate_inode_pages. After nfs_flush_pages returns, we can be sure
* that all dirty pages are locked, so that invalidate_inode_pages does
* not throw away any dirty pages.
...
...
@@ -780,7 +804,7 @@ nfs_check_error(struct inode *inode)
dprintk
(
"nfs: checking for write error inode %04x/%ld
\n
"
,
inode
->
i_dev
,
inode
->
i_ino
);
req
=
find_failed_request
(
inode
,
current
->
pid
,
0
);
req
=
find_failed_request
(
inode
,
current
->
pid
);
if
(
req
)
{
dprintk
(
"nfs: write error %d inode %04x/%ld
\n
"
,
req
->
wb_task
.
tk_status
,
inode
->
i_dev
,
inode
->
i_ino
);
...
...
@@ -869,7 +893,7 @@ nfs_wback_result(struct rpc_task *task)
* application by adding the request to the failed
* requests list.
*/
if
(
find_failed_request
(
inode
,
req
->
wb_pid
,
0
))
if
(
find_failed_request
(
inode
,
req
->
wb_pid
))
status
=
0
;
clear_bit
(
PG_uptodate
,
&
page
->
flags
);
}
else
if
(
!
WB_CANCELLED
(
req
))
{
...
...
fs/nls/Config.in
View file @
73f103e4
...
...
@@ -5,35 +5,40 @@
mainmenu_option next_comment
comment 'Native Language Support'
tristate 'Native language support (Unicode, codepages)' CONFIG_NLS
# msdos and Joliet want NLS
if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" ]; then
define_bool CONFIG_NLS y
else
define_bool CONFIG_NLS n
fi
if [ "$CONFIG_NLS" = "y"
-o "$CONFIG_NLS" = "m"
]; then
dep_tristate 'Codepage 437' CONFIG_NLS_CODEPAGE_437 $CONFIG_NLS
dep_tristate 'Codepage 737' CONFIG_NLS_CODEPAGE_737 $CONFIG_NLS
dep_tristate 'Codepage 775' CONFIG_NLS_CODEPAGE_775 $CONFIG_NLS
dep_tristate 'Codepage 850' CONFIG_NLS_CODEPAGE_850 $CONFIG_NLS
dep_tristate 'Codepage 852' CONFIG_NLS_CODEPAGE_852 $CONFIG_NLS
dep_tristate 'Codepage 855' CONFIG_NLS_CODEPAGE_855 $CONFIG_NLS
dep_tristate 'Codepage 857' CONFIG_NLS_CODEPAGE_857 $CONFIG_NLS
dep_tristate 'Codepage 860' CONFIG_NLS_CODEPAGE_860 $CONFIG_NLS
dep_tristate 'Codepage 861' CONFIG_NLS_CODEPAGE_861 $CONFIG_NLS
dep_tristate 'Codepage 862' CONFIG_NLS_CODEPAGE_862 $CONFIG_NLS
dep_tristate 'Codepage 863' CONFIG_NLS_CODEPAGE_863 $CONFIG_NLS
dep_tristate 'Codepage 864' CONFIG_NLS_CODEPAGE_864 $CONFIG_NLS
dep_tristate 'Codepage 865' CONFIG_NLS_CODEPAGE_865 $CONFIG_NLS
dep_tristate 'Codepage 866' CONFIG_NLS_CODEPAGE_866 $CONFIG_NLS
dep_tristate 'Codepage 869' CONFIG_NLS_CODEPAGE_869 $CONFIG_NLS
dep_tristate 'Codepage 874' CONFIG_NLS_CODEPAGE_874 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-1' CONFIG_NLS_ISO8859_1 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-2' CONFIG_NLS_ISO8859_2 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-3' CONFIG_NLS_ISO8859_3 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-4' CONFIG_NLS_ISO8859_4 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-5' CONFIG_NLS_ISO8859_5 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-6' CONFIG_NLS_ISO8859_6 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-7' CONFIG_NLS_ISO8859_7 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-8' CONFIG_NLS_ISO8859_8 $CONFIG_NLS
dep_tristate 'NLS ISO 8859-9' CONFIG_NLS_ISO8859_9 $CONFIG_NLS
dep_tristate 'NLS KOI8-R' CONFIG_NLS_KOI8_R $CONFIG_NLS
if [ "$CONFIG_NLS" = "y" ]; then
tristate 'Codepage 437' CONFIG_NLS_CODEPAGE_437
tristate 'Codepage 737' CONFIG_NLS_CODEPAGE_737
tristate 'Codepage 775' CONFIG_NLS_CODEPAGE_775
tristate 'Codepage 850' CONFIG_NLS_CODEPAGE_850
tristate 'Codepage 852' CONFIG_NLS_CODEPAGE_852
tristate 'Codepage 855' CONFIG_NLS_CODEPAGE_855
tristate 'Codepage 857' CONFIG_NLS_CODEPAGE_857
tristate 'Codepage 860' CONFIG_NLS_CODEPAGE_860
tristate 'Codepage 861' CONFIG_NLS_CODEPAGE_861
tristate 'Codepage 862' CONFIG_NLS_CODEPAGE_862
tristate 'Codepage 863' CONFIG_NLS_CODEPAGE_863
tristate 'Codepage 864' CONFIG_NLS_CODEPAGE_864
tristate 'Codepage 865' CONFIG_NLS_CODEPAGE_865
tristate 'Codepage 866' CONFIG_NLS_CODEPAGE_866
tristate 'Codepage 869' CONFIG_NLS_CODEPAGE_869
tristate 'Codepage 874' CONFIG_NLS_CODEPAGE_874
tristate 'NLS ISO 8859-1' CONFIG_NLS_ISO8859_1
tristate 'NLS ISO 8859-2' CONFIG_NLS_ISO8859_2
tristate 'NLS ISO 8859-3' CONFIG_NLS_ISO8859_3
tristate 'NLS ISO 8859-4' CONFIG_NLS_ISO8859_4
tristate 'NLS ISO 8859-5' CONFIG_NLS_ISO8859_5
tristate 'NLS ISO 8859-6' CONFIG_NLS_ISO8859_6
tristate 'NLS ISO 8859-7' CONFIG_NLS_ISO8859_7
tristate 'NLS ISO 8859-8' CONFIG_NLS_ISO8859_8
tristate 'NLS ISO 8859-9' CONFIG_NLS_ISO8859_9
tristate 'NLS KOI8-R' CONFIG_NLS_KOI8_R
fi
endmenu
fs/nls/Makefile
View file @
73f103e4
...
...
@@ -4,15 +4,7 @@
MOD_LIST_NAME
:=
NLS_MODULES
ifeq
($(CONFIG_NLS),y)
NLS
+=
nls_base.o
O_TARGET
=
nls.o
OX_OBJS
=
$(NLS)
else
ifeq
($(CONFIG_NLS),m)
MX_OBJS
+=
nls_base.o
endif
endif
NLS
=
nls_base.o
ifeq
($(CONFIG_NLS_CODEPAGE_437),y)
NLS
+=
nls_cp437.o
...
...
@@ -302,4 +294,7 @@ else
endif
endif
O_TARGET
=
nls.o
OX_OBJS
=
$(NLS)
include
$(TOPDIR)/Rules.make
fs/nls/nls_base.c
View file @
73f103e4
...
...
@@ -6,7 +6,6 @@
*
*/
#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
...
...
@@ -479,11 +478,10 @@ int init_nls(void)
#ifdef CONFIG_NLS_CODEPAGE_874
init_nls_cp874
();
#endif
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
return
0
;
#else
return
register_symtab
(
&
nls_syms
);
#ifdef CONFIG_NLS_KOI8_R
init_nls_koi8_r
();
#endif
return
0
;
}
#ifdef MODULE
...
...
fs/smbfs/cache.c
View file @
73f103e4
...
...
@@ -130,13 +130,14 @@ printk("smb_init_dircache: initializing cache, %d blocks\n", cachep->pages);
* 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
)
smb_add_to_cache
(
struct
cache_head
*
cachep
,
struct
cache_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_rec
len
;
unsigned
int
nent
,
offset
,
len
=
entry
->
len
;
unsigned
int
needed
=
len
+
sizeof
(
struct
cache_entry
);
#ifdef SMBFS_DEBUG_VERBOSE
...
...
@@ -163,10 +164,10 @@ inode, cachep->status, entry->d_name, fpos);
offset
=
index
->
space
+
index
->
num_entries
*
sizeof
(
struct
cache_entry
);
block
=
index
->
block
;
memcpy
(
&
block
->
cb_data
.
names
[
offset
],
entry
->
d_
name
,
len
);
memcpy
(
&
block
->
cb_data
.
names
[
offset
],
entry
->
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
;
block
->
cb_data
.
table
[
nent
].
ino
=
entry
->
ino
;
cachep
->
entries
++
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d
\n
"
,
...
...
fs/smbfs/dir.c
View file @
73f103e4
...
...
@@ -8,20 +8,14 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
#define SMBFS_MAX_AGE 5*HZ
static
ssize_t
smb_dir_read
(
struct
file
*
,
char
*
,
size_t
,
loff_t
*
);
static
int
smb_readdir
(
struct
file
*
,
void
*
,
filldir_t
);
...
...
@@ -94,13 +88,13 @@ hash_it(const char * name, unsigned int len)
* If a dentry already exists, we have to give the cache entry
* the correct inode number. This is needed for getcwd().
*/
static
unsigned
long
static
void
smb_find_ino
(
struct
dentry
*
dentry
,
struct
cache_dirent
*
entry
)
{
struct
dentry
*
new_dentry
;
struct
qstr
qname
;
unsigned
long
ino
=
0
;
/* N.B. Make cache_dirent name a qstr! */
qname
.
name
=
entry
->
name
;
qname
.
len
=
entry
->
len
;
qname
.
hash
=
hash_it
(
qname
.
name
,
qname
.
len
);
...
...
@@ -109,12 +103,11 @@ smb_find_ino(struct dentry *dentry, struct cache_dirent *entry)
{
struct
inode
*
inode
=
new_dentry
->
d_inode
;
if
(
inode
)
ino
=
inode
->
i_ino
;
entry
->
ino
=
inode
->
i_ino
;
dput
(
new_dentry
);
}
if
(
!
ino
)
ino
=
smb_invent_inos
(
1
);
return
ino
;
if
(
!
entry
->
ino
)
entry
->
ino
=
smb_invent_inos
(
1
);
}
static
int
...
...
@@ -125,9 +118,10 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
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
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_readdir: reading %s/%s, f_pos=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
(
int
)
filp
->
f_pos
);
#endif
/*
* Make sure our inode is up-to-date.
*/
...
...
@@ -137,6 +131,7 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
/*
* Get the cache pointer ...
*/
result
=
-
EIO
;
cachep
=
smb_get_dircache
(
dentry
);
if
(
!
cachep
)
goto
out
;
...
...
@@ -147,19 +142,20 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
result
=
smb_refill_dircache
(
cachep
,
dentry
);
if
(
result
)
goto
up_and_out
;
goto
out_free
;
}
result
=
0
;
switch
((
unsigned
int
)
filp
->
f_pos
)
{
case
0
:
if
(
filldir
(
dirent
,
"."
,
1
,
0
,
dir
->
i_ino
)
<
0
)
goto
up_and_out
;
goto
out_free
;
filp
->
f_pos
=
1
;
case
1
:
if
(
filldir
(
dirent
,
".."
,
2
,
1
,
dentry
->
d_parent
->
d_inode
->
i_ino
)
<
0
)
goto
up_and_out
;
goto
out_free
;
filp
->
f_pos
=
2
;
}
...
...
@@ -173,21 +169,18 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
* Check whether to look up the inode number.
*/
if
(
!
entry
->
ino
)
{
entry
->
ino
=
smb_find_ino
(
dentry
,
entry
);
}
smb_find_ino
(
dentry
,
entry
);
if
(
filldir
(
dirent
,
entry
->
name
,
entry
->
len
,
filp
->
f_pos
,
entry
->
ino
)
<
0
)
break
;
filp
->
f_pos
+=
1
;
}
result
=
0
;
/*
* Release the dircache.
*/
up_and_out
:
out_free
:
smb_free_dircache
(
cachep
);
out:
return
result
;
...
...
@@ -220,7 +213,8 @@ static struct dentry_operations smbfs_dentry_operations =
/*
* This is the callback when the dcache has a lookup hit.
*/
static
int
smb_lookup_validate
(
struct
dentry
*
dentry
)
static
int
smb_lookup_validate
(
struct
dentry
*
dentry
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
unsigned
long
age
=
jiffies
-
dentry
->
d_time
;
...
...
@@ -231,11 +225,11 @@ static int smb_lookup_validate(struct dentry * dentry)
* we believe in dentries for 5 seconds. (But each
* successful server lookup renews the timestamp.)
*/
valid
=
age
<
5
*
HZ
||
IS_ROOT
(
dentry
);
valid
=
(
age
<=
SMBFS_MAX_AGE
)
||
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
)
printk
(
"smb_lookup_validate: %s/%s not valid, age=%
lu
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
age
)
;
#endif
if
(
inode
)
...
...
@@ -259,10 +253,20 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
/*
* This is the callback from dput() when d_count is going to 0.
* We use this to
close files and unhash dentries with bad inod
es.
* We use this to
unhash dentries with bad inodes and close fil
es.
*/
static
void
smb_delete_dentry
(
struct
dentry
*
dentry
)
static
void
smb_delete_dentry
(
struct
dentry
*
dentry
)
{
if
((
jiffies
-
dentry
->
d_time
)
>
SMBFS_MAX_AGE
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_delete_dentry: %s/%s expired, d_time=%lu, now=%lu
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_time
,
jiffies
);
#endif
d_drop
(
dentry
);
}
if
(
dentry
->
d_inode
)
{
if
(
is_bad_inode
(
dentry
->
d_inode
))
...
...
@@ -285,9 +289,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
* are all valid, so we want to update the dentry timestamps.
* N.B. Move this to dcache?
*/
void
smb_renew_times
(
struct
dentry
*
dentry
)
void
smb_renew_times
(
struct
dentry
*
dentry
)
{
for
(;;)
{
for
(;;)
{
dentry
->
d_time
=
jiffies
;
if
(
dentry
==
dentry
->
d_parent
)
break
;
...
...
@@ -361,6 +367,10 @@ smb_instantiate(struct dentry *dentry)
error
=
0
;
}
}
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_instantiate: file %s/%s, error=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
error
);
#endif
return
error
;
}
...
...
@@ -370,6 +380,10 @@ smb_create(struct inode *dir, struct dentry *dentry, int mode)
{
int
error
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_create: creating %s/%s, mode=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
mode
);
#endif
error
=
-
ENAMETOOLONG
;
if
(
dentry
->
d_name
.
len
>
SMB_MAXNAMELEN
)
goto
out
;
...
...
fs/smbfs/inode.c
View file @
73f103e4
...
...
@@ -6,14 +6,10 @@
*
*/
#define SMBFS_DCACHE_EXT 1
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
...
...
@@ -23,6 +19,9 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/dcache.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/smb_mount.h>
#include <asm/system.h>
#include <asm/uaccess.h>
...
...
@@ -30,17 +29,11 @@
#define SMBFS_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_read_inode
(
struct
inode
*
);
static
void
smb_put_inode
(
struct
inode
*
);
static
void
smb_delete_inode
(
struct
inode
*
);
static
void
smb_read_inode
(
struct
inode
*
);
static
void
smb_put_super
(
struct
super_block
*
);
static
int
smb_statfs
(
struct
super_block
*
,
struct
statfs
*
,
int
);
static
int
smb_statfs
(
struct
super_block
*
,
struct
statfs
*
,
int
);
static
struct
super_operations
smb_sops
=
{
...
...
@@ -147,6 +140,11 @@ printk("smb_invalidate_inodes\n");
invalidate_inodes
(
SB_of
(
server
));
}
/*
* This is called when we want to check whether the inode
* has changed on the server. If it has changed, we must
* invalidate our local caches.
*/
int
smb_revalidate_inode
(
struct
inode
*
inode
)
{
...
...
@@ -167,25 +165,23 @@ jiffies, inode->u.smbfs_i.oldmtime);
}
/*
* Save the last modified time, then refresh the inode
* Save the last modified time, then refresh the inode.
* (Note: a size change should have a different mtime.)
*/
last_time
=
inode
->
i_mtime
;
error
=
smb_refresh_inode
(
inode
);
if
(
!
error
)
if
(
error
||
inode
->
i_mtime
!=
last_time
)
{
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
);
}
if
(
!
S_ISDIR
(
inode
->
i_mode
))
invalidate_inode_pages
(
inode
);
else
smb_invalid_dir_cache
(
inode
);
}
out:
return
error
;
...
...
@@ -253,10 +249,12 @@ inode->i_mode, fattr.f_mode);
/*
* 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 ...
* But we
do want
to invalidate the caches ...
*/
invalidate_inode_pages
(
inode
);
smb_invalid_dir_cache
(
inode
);
if
(
!
S_ISDIR
(
inode
->
i_mode
))
invalidate_inode_pages
(
inode
);
else
smb_invalid_dir_cache
(
inode
);
error
=
-
EIO
;
}
}
...
...
@@ -328,6 +326,7 @@ smb_put_super(struct super_block *sb)
if
(
server
->
conn_pid
)
kill_proc
(
server
->
conn_pid
,
SIGTERM
,
0
);
kfree
(
server
->
mnt
);
if
(
server
->
packet
)
smb_vfree
(
server
->
packet
);
sb
->
s_dev
=
0
;
...
...
@@ -340,7 +339,7 @@ smb_put_super(struct super_block *sb)
struct
super_block
*
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_mount_data
*
mnt
,
*
data
=
(
struct
smb_mount_data
*
)
raw_data
;
struct
smb_fattr
root
;
kdev_t
dev
=
sb
->
s_dev
;
struct
inode
*
root_inode
;
...
...
@@ -368,16 +367,25 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
sb
->
u
.
smbfs_sb
.
conn_pid
=
0
;
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
);
sb
->
u
.
smbfs_sb
.
packet_size
=
smb_round_length
(
SMB_INITIAL_PACKET_SIZE
)
;
sb
->
u
.
smbfs_sb
.
packet
=
smb_vmalloc
(
sb
->
u
.
smbfs_sb
.
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
;
mnt
=
kmalloc
(
sizeof
(
struct
smb_mount_data
),
GFP_KERNEL
);
if
(
!
mnt
)
goto
out_no_mount
;
*
mnt
=
*
data
;
mnt
->
version
=
0
;
/* dynamic flags */
#ifdef CONFIG_SMB_WIN95
mnt
->
version
|=
1
;
#endif
mnt
->
file_mode
&=
(
S_IRWXU
|
S_IRWXG
|
S_IRWXO
);
mnt
->
file_mode
|=
S_IFREG
;
mnt
->
dir_mode
&=
(
S_IRWXU
|
S_IRWXG
|
S_IRWXO
);
mnt
->
dir_mode
|=
S_IFDIR
;
sb
->
u
.
smbfs_sb
.
mnt
=
mnt
;
/*
* Keep the super block locked while we get the root inode.
*/
...
...
@@ -398,20 +406,20 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
out_no_root:
printk
(
KERN_ERR
"smb_read_super: get root inode failed
\n
"
);
iput
(
root_inode
);
kfree
(
sb
->
u
.
smbfs_sb
.
mnt
);
out_no_mount:
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_unlock:
unlock_super
(
sb
);
goto
out_fail
;
out_wrong_data:
printk
(
KERN_ERR
"smb_read_super: wrong data argument."
" Recompile smbmount.
\n
"
);
printk
(
"smb_read_super: need mount version %d
\n
"
,
SMB_MOUNT_VERSION
);
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
;
...
...
@@ -439,6 +447,7 @@ 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
;
unsigned
int
mask
=
(
S_IFREG
|
S_IFDIR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
);
int
error
,
refresh
=
0
;
error
=
-
EIO
;
...
...
@@ -459,14 +468,13 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
goto
out
;
error
=
-
EPERM
;
if
((
(
attr
->
ia_valid
&
ATTR_UID
)
&&
(
attr
->
ia_uid
!=
server
->
m
.
uid
)
))
if
((
attr
->
ia_valid
&
ATTR_UID
)
&&
(
attr
->
ia_uid
!=
server
->
mnt
->
uid
))
goto
out
;
if
((
(
attr
->
ia_valid
&
ATTR_GID
)
&&
(
attr
->
ia_uid
!=
server
->
m
.
gid
)
))
if
((
attr
->
ia_valid
&
ATTR_GID
)
&&
(
attr
->
ia_uid
!=
server
->
mnt
->
gid
))
goto
out
;
if
(((
attr
->
ia_valid
&
ATTR_MODE
)
&&
(
attr
->
ia_mode
&
~
(
S_IFREG
|
S_IFDIR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
))))
if
((
attr
->
ia_valid
&
ATTR_MODE
)
&&
(
attr
->
ia_mode
&
~
mask
))
goto
out
;
if
((
attr
->
ia_valid
&
ATTR_SIZE
)
!=
0
)
...
...
fs/smbfs/ioctl.c
View file @
73f103e4
...
...
@@ -8,10 +8,11 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/smb_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <asm/uaccess.h>
...
...
@@ -19,33 +20,33 @@ int
smb_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
result
=
-
EINVAL
;
switch
(
cmd
)
{
case
SMB_IOC_GETMOUNTUID
:
re
turn
put_user
(
SMB_SERVER
(
inode
)
->
m
.
mounted_uid
,
re
sult
=
put_user
(
SMB_SERVER
(
inode
)
->
mnt
->
mounted_uid
,
(
uid_t
*
)
arg
);
break
;
case
SMB_IOC_NEWCONN
:
{
struct
smb_conn_opt
opt
;
int
result
;
if
(
arg
==
0
)
{
/* The process offers a new connection upon SIGUSR1 */
re
turn
smb_offerconn
(
SMB_SERVER
(
inode
));
re
sult
=
smb_offerconn
(
SMB_SERVER
(
inode
));
}
if
((
result
=
verify_area
(
VERIFY_READ
,
(
uid_t
*
)
arg
,
sizeof
(
opt
)))
!=
0
)
else
{
return
result
;
result
=
-
EFAULT
;
if
(
!
copy_from_user
(
&
opt
,
(
void
*
)
arg
,
sizeof
(
opt
)))
result
=
smb_newconn
(
SMB_SERVER
(
inode
),
&
opt
);
}
copy_from_user
(
&
opt
,
(
void
*
)
arg
,
sizeof
(
opt
));
return
smb_newconn
(
SMB_SERVER
(
inode
),
&
opt
);
break
;
}
default:
return
-
EINVAL
;
}
return
result
;
}
fs/smbfs/proc.c
View file @
73f103e4
...
...
@@ -9,10 +9,7 @@
* by Riccardo Facchetti
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/smbno.h>
#include <linux/smb_fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
...
...
@@ -20,10 +17,16 @@
#include <linux/fcntl.h>
#include <linux/dcache.h>
#include <linux/dirent.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/smb_mount.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
#define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
...
...
@@ -33,12 +36,6 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
extern
void
smb_renew_times
(
struct
dentry
*
);
static
inline
int
min
(
int
a
,
int
b
)
{
...
...
@@ -46,9 +43,9 @@ min(int a, int b)
}
static
void
str_upper
(
char
*
name
)
str_upper
(
char
*
name
,
int
len
)
{
while
(
*
name
)
while
(
len
--
)
{
if
(
*
name
>=
'a'
&&
*
name
<=
'z'
)
*
name
-=
(
'a'
-
'A'
);
...
...
@@ -57,9 +54,9 @@ str_upper(char *name)
}
static
void
str_lower
(
char
*
name
)
str_lower
(
char
*
name
,
int
len
)
{
while
(
*
name
)
while
(
len
--
)
{
if
(
*
name
>=
'A'
&&
*
name
<=
'Z'
)
*
name
+=
(
'a'
-
'A'
);
...
...
@@ -158,7 +155,7 @@ static char *smb_encode_path(struct smb_sb_info *server, char *buf,
buf
+=
smb_build_path
(
dir
,
name
,
buf
);
if
(
server
->
opt
.
protocol
<=
SMB_PROTOCOL_COREPLUS
)
str_upper
(
start
);
str_upper
(
start
,
buf
-
start
);
return
buf
;
}
...
...
@@ -569,7 +566,7 @@ smb_offerconn(struct smb_sb_info *server)
int
error
;
error
=
-
EACCES
;
if
(
!
suser
()
&&
(
current
->
uid
!=
server
->
m
.
mounted_uid
))
if
(
(
current
->
uid
!=
server
->
mnt
->
mounted_uid
)
&&
!
suser
())
goto
out
;
if
(
atomic_read
(
&
server
->
sem
.
count
)
==
1
)
{
...
...
@@ -609,7 +606,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
goto
out
;
error
=
-
EACCES
;
if
(
!
suser
()
&&
(
current
->
uid
!=
server
->
m
.
mounted_uid
))
if
(
(
current
->
uid
!=
server
->
mnt
->
mounted_uid
)
&&
!
suser
(
))
goto
out
;
if
(
atomic_read
(
&
server
->
sem
.
count
)
==
1
)
{
...
...
@@ -888,12 +885,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
}
smb_unlock_server
(
server
);
}
}
/* Consider dropping negative dentries? */
#if 0
else
d_drop(dentry);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_close_dentry: closed %s/%s, count=%d
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
dentry
->
d_count
);
#endif
}
}
/* In smb_proc_read and smb_proc_write we do not retry, because the
...
...
@@ -951,11 +947,10 @@ smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
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
,
((
struct
dentry
*
)
ino
->
u
.
smbfs_i
.
dentry
)
->
d_parent
->
d_name
.
name
,
((
struct
dentry
*
)
ino
->
u
.
smbfs_i
.
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
);
...
...
@@ -967,11 +962,11 @@ count, offset, server->packet_size);
WSET
(
p
,
0
,
count
);
memcpy
(
p
+
2
,
data
,
count
);
if
((
result
=
smb_request_ok
(
server
,
SMBwrite
,
1
,
0
))
>=
0
)
result
=
smb_request_ok
(
server
,
SMBwrite
,
1
,
0
);
if
(
result
>=
0
)
result
=
WVAL
(
server
->
packet
,
smb_vwv0
);
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -997,9 +992,7 @@ smb_proc_create(struct dentry *dir, struct qstr *name,
if
((
error
=
smb_request_ok
(
server
,
SMBcreate
,
1
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
smb_proc_close
(
server
,
WVAL
(
server
->
packet
,
smb_vwv0
),
CURRENT_TIME
);
...
...
@@ -1033,10 +1026,11 @@ smb_proc_mv(struct dentry *odir, struct qstr *oname,
if
((
result
=
smb_request_ok
(
server
,
SMBmv
,
0
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1060,10 +1054,11 @@ smb_proc_mkdir(struct dentry *dir, struct qstr *name)
if
((
result
=
smb_request_ok
(
server
,
SMBmkdir
,
0
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1087,10 +1082,11 @@ smb_proc_rmdir(struct dentry *dir, struct qstr *name)
if
((
result
=
smb_request_ok
(
server
,
SMBrmdir
,
0
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1115,10 +1111,11 @@ smb_proc_unlink(struct dentry *dir, struct qstr *name)
if
((
result
=
smb_request_ok
(
server
,
SMBunlink
,
0
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1127,18 +1124,16 @@ int
smb_proc_trunc
(
struct
smb_sb_info
*
server
,
__u16
fid
,
__u32
length
)
{
char
*
p
;
char
*
buf
;
int
result
;
smb_lock_server
(
server
);
retry:
buf
=
server
->
packet
;
p
=
smb_setup_header
(
server
,
SMBwrite
,
5
,
0
);
WSET
(
buf
,
smb_vwv0
,
fid
);
WSET
(
buf
,
smb_vwv1
,
0
);
DSET
(
buf
,
smb_vwv2
,
length
);
WSET
(
buf
,
smb_vwv4
,
0
);
WSET
(
server
->
packet
,
smb_vwv0
,
fid
);
WSET
(
server
->
packet
,
smb_vwv1
,
0
);
DSET
(
server
->
packet
,
smb_vwv2
,
length
);
WSET
(
server
->
packet
,
smb_vwv4
,
0
);
*
p
++
=
4
;
*
p
++
=
0
;
smb_setup_bcc
(
server
,
p
);
...
...
@@ -1146,10 +1141,11 @@ smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
if
((
result
=
smb_request_ok
(
server
,
SMBwrite
,
1
,
0
))
<
0
)
{
if
(
smb_retry
(
server
))
{
goto
retry
;
}
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1160,18 +1156,18 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
memset
(
fattr
,
0
,
sizeof
(
*
fattr
));
fattr
->
f_nlink
=
1
;
fattr
->
f_uid
=
server
->
m
.
uid
;
fattr
->
f_gid
=
server
->
m
.
gid
;
fattr
->
f_uid
=
server
->
m
nt
->
uid
;
fattr
->
f_gid
=
server
->
m
nt
->
gid
;
fattr
->
f_blksize
=
512
;
}
static
void
smb_finish_dirent
(
struct
smb_sb_info
*
server
,
struct
smb_fattr
*
fattr
)
{
fattr
->
f_mode
=
server
->
m
.
file_mode
;
fattr
->
f_mode
=
server
->
m
nt
->
file_mode
;
if
(
fattr
->
attr
&
aDIR
)
{
fattr
->
f_mode
=
server
->
m
.
dir_mode
;
fattr
->
f_mode
=
server
->
m
nt
->
dir_mode
;
fattr
->
f_size
=
512
;
}
...
...
@@ -1194,42 +1190,47 @@ smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
smb_finish_dirent
(
server
,
fattr
);
}
/*
* Note that we are now returning the name as a reference to avoid
* an extra copy, and that the upper/lower casing is done in place.
*/
static
__u8
*
smb_decode_dirent
(
struct
smb_sb_info
*
server
,
__u8
*
p
,
struct
dirent
*
entry
)
smb_decode_dirent
(
struct
smb_sb_info
*
server
,
__u8
*
p
,
struct
cache_dirent
*
entry
)
{
int
len
;
/*
* SMB doesn't have a concept of inode numbers ...
*/
entry
->
ino
=
0
;
p
+=
SMB_STATUS_SIZE
;
/* reserved (search_status) */
len
=
strlen
(
p
+
9
);
entry
->
name
=
p
+
9
;
len
=
strlen
(
entry
->
name
);
if
(
len
>
12
)
{
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
]
==
' '
)
while
(
len
>
2
&&
entry
->
name
[
len
-
1
]
==
' '
)
len
--
;
#endif
entry
->
d_name
[
len
]
=
'\0'
;
entry
->
d_reclen
=
len
;
entry
->
d_ino
=
0
;
/* no inode number available */
entry
->
len
=
len
;
switch
(
server
->
opt
.
case_handling
)
{
case
SMB_CASE_UPPER
:
str_upper
(
entry
->
d_name
);
str_upper
(
entry
->
name
,
len
);
break
;
case
SMB_CASE_LOWER
:
str_lower
(
entry
->
d_name
);
str_lower
(
entry
->
name
,
len
);
break
;
default:
break
;
}
pr_debug
(
"smb_decode_dirent:
name = %s
\n
"
,
entry
->
name
);
pr_debug
(
"smb_decode_dirent:
len=%d, name=%s
\n
"
,
len
,
entry
->
name
);
return
p
+
22
;
}
...
...
@@ -1250,7 +1251,10 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
char
status
[
SMB_STATUS_SIZE
];
static
struct
qstr
mask
=
{
"*.*"
,
3
,
0
};
pr_debug
(
"smb_proc_readdir_short: %d @ %d
\n
"
,
cache_size
,
fpos
);
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_proc_readdir_short: %s/%s, pos=%d
\n
"
,
dir
->
d_parent
->
d_name
.
name
,
dir
->
d_name
.
name
,
fpos
);
#endif
smb_lock_server
(
server
);
...
...
@@ -1317,15 +1321,14 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
for
(
i
=
0
;
i
<
count
;
i
++
)
{
struct
dirent
this_ent
,
*
entry
=
&
this_ent
;
struct
cache_
dirent
this_ent
,
*
entry
=
&
this_ent
;
p
=
smb_decode_dirent
(
server
,
p
,
entry
);
if
(
entries_seen
==
2
&&
entry
->
d_
name
[
0
]
==
'.'
)
if
(
entries_seen
==
2
&&
entry
->
name
[
0
]
==
'.'
)
{
if
(
entry
->
d_rec
len
==
1
)
if
(
entry
->
len
==
1
)
continue
;
if
(
entry
->
d_name
[
1
]
==
'.'
&&
entry
->
d_reclen
==
2
)
if
(
entry
->
name
[
1
]
==
'.'
&&
entry
->
len
==
2
)
continue
;
}
if
(
entries_seen
>=
fpos
)
...
...
@@ -1334,12 +1337,13 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
entries_seen
);
smb_add_to_cache
(
cachep
,
entry
,
entries_seen
);
entries
++
;
}
}
else
{
#ifdef SMBFS_DEBUG_VERBOSE
else
printk
(
"smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d
\n
"
,
entries_seen
,
i
,
fpos
);
#endif
}
entries_seen
++
;
}
}
...
...
@@ -1352,58 +1356,53 @@ entries_seen, i, fpos);
/*
* Interpret a long filename structure using the specified info level:
* level 1 -- Win NT, Win 95, OS/2
* level 2 -- OS/2
* level 1 -- Win NT, Win 95, 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.
*
* We return a reference to the name string to avoid copying, and perform
* any needed upper/lower casing in place. Note!! Level 259 entries may
* not have any space beyond the name, so don't try to write a null byte!
*/
static
char
*
smb_decode_long_dirent
(
struct
smb_sb_info
*
server
,
char
*
p
,
struct
dirent
*
entry
,
int
level
)
struct
cache_
dirent
*
entry
,
int
level
)
{
char
*
result
;
unsigned
int
len
;
unsigned
int
len
=
0
;
/*
* SMB doesn't have a concept of inode numbers ...
*/
entry
->
d_
ino
=
0
;
entry
->
ino
=
0
;
switch
(
level
)
{
case
1
:
len
=
*
((
unsigned
char
*
)
p
+
26
);
entry
->
d_reclen
=
len
;
strncpy
(
entry
->
d_name
,
p
+
27
,
len
);
entry
->
d_name
[
len
]
=
'\0'
;
entry
->
len
=
len
;
entry
->
name
=
p
+
27
;
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
)
;
entry
->
name
=
p
+
12
;
/*
* 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'
)
if
(
len
&&
entry
->
name
[
len
-
1
]
==
'\0'
)
len
--
;
entry
->
d_name
[
len
]
=
'\0'
;
entry
->
d_reclen
=
len
;
entry
->
len
=
len
;
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_decode_long_dirent: info 259, len=%d, name=%s
\n
"
,
len
,
entry
->
d_
name
);
printk
(
"smb_decode_long_dirent: info 259
at %p
, len=%d, name=%s
\n
"
,
p
,
len
,
entry
->
name
);
#endif
break
;
...
...
@@ -1415,10 +1414,10 @@ len, entry->d_name);
switch
(
server
->
opt
.
case_handling
)
{
case
SMB_CASE_UPPER
:
str_upper
(
entry
->
d_name
);
str_upper
(
entry
->
name
,
len
);
break
;
case
SMB_CASE_LOWER
:
str_lower
(
entry
->
d_name
);
str_lower
(
entry
->
name
,
len
);
break
;
default:
break
;
...
...
@@ -1460,7 +1459,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
* 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?
)
* Hence we use level 259 for NT. (
And Win 95 as well ...
)
*/
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_NT1
)
info_level
=
259
;
...
...
@@ -1520,14 +1519,16 @@ ff_dir_handle, ff_resume_key, ff_lastname, mask);
WSET
(
param
,
10
,
8
+
4
+
2
);
/* resume required +
close on end +
continue */
#ifdef CONFIG_SMB_WIN95
/* Windows 95 is not able to deliver answers
to FIND_NEXT fast enough, so sleep 0.2 seconds */
current
->
timeout
=
jiffies
+
HZ
/
5
;
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
current
->
timeout
=
0
;
#endif
if
(
server
->
mnt
->
version
&
1
)
{
/* Windows 95 is not able to deliver answers
* to FIND_NEXT fast enough, so sleep 0.2 sec
*/
current
->
timeout
=
jiffies
+
HZ
/
5
;
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
current
->
timeout
=
0
;
}
}
result
=
smb_trans2_request
(
server
,
command
,
...
...
@@ -1591,7 +1592,7 @@ resp_data + resp_data_len, resp_data_len, server->packet + server->packet_size);
lastname
=
resp_data
+
ff_lastname
;
switch
(
info_level
)
{
case
2
60
:
case
2
59
:
if
(
ff_lastname
<
resp_data_len
)
mask_len
=
resp_data_len
-
ff_lastname
;
break
;
...
...
@@ -1622,7 +1623,7 @@ mask_len, ff_lastname, mask);
p
=
resp_data
;
for
(
i
=
0
;
i
<
ff_searchcount
;
i
++
)
{
struct
dirent
this_ent
,
*
entry
=
&
this_ent
;
struct
cache_
dirent
this_ent
,
*
entry
=
&
this_ent
;
p
=
smb_decode_long_dirent
(
server
,
p
,
entry
,
info_level
);
...
...
@@ -1630,12 +1631,11 @@ mask_len, ff_lastname, mask);
pr_debug
(
"smb_readdir_long: got %s
\n
"
,
entry
->
name
);
/* ignore . and .. from the server */
if
(
entries_seen
==
2
&&
entry
->
d_
name
[
0
]
==
'.'
)
if
(
entries_seen
==
2
&&
entry
->
name
[
0
]
==
'.'
)
{
if
(
entry
->
d_rec
len
==
1
)
if
(
entry
->
len
==
1
)
continue
;
if
(
entry
->
d_name
[
1
]
==
'.'
&&
entry
->
d_reclen
==
2
)
if
(
entry
->
name
[
1
]
==
'.'
&&
entry
->
len
==
2
)
continue
;
}
if
(
entries_seen
>=
fpos
)
...
...
@@ -1742,7 +1742,13 @@ printk("smb_proc_getattr_trans2: for %s: result=%d, rcls=%d, err=%d\n",
}
result
=
-
ENOENT
;
if
(
resp_data_len
<
22
)
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_proc_getattr_trans2: not enough data for %s, len=%d
\n
"
,
&
param
[
6
],
resp_data_len
);
#endif
goto
out
;
}
attr
->
f_ctime
=
date_dos2unix
(
WVAL
(
resp_data
,
2
),
WVAL
(
resp_data
,
0
));
...
...
@@ -1770,11 +1776,10 @@ smb_proc_getattr(struct dentry *dir, struct qstr *name,
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
)
* Win 95 is painfully slow at returning trans2 getattr info ...
*/
if
(
server
->
opt
.
protocol
>=
SMB_PROTOCOL_LANMAN2
&&
!
(
server
->
mnt
->
version
&
1
))
result
=
smb_proc_getattr_trans2
(
server
,
dir
,
name
,
fattr
);
else
result
=
smb_proc_getattr_core
(
server
,
dir
,
name
,
fattr
);
...
...
@@ -1784,7 +1789,6 @@ smb_proc_getattr(struct dentry *dir, struct qstr *name,
return
result
;
}
/* In core protocol, there is only 1 time to be set, we use
entry->f_mtime, to make touch work. */
static
int
...
...
@@ -1808,10 +1812,15 @@ smb_proc_setattr_core(struct smb_sb_info *server,
*
p
++
=
0
;
smb_setup_bcc
(
server
,
p
);
if
((
result
=
smb_request_ok
(
server
,
SMBsetatr
,
0
,
0
))
<
0
)
result
=
smb_request_ok
(
server
,
SMBsetatr
,
0
,
0
);
if
(
result
<
0
)
{
if
(
smb_retry
(
server
))
goto
retry
;
goto
out
;
}
result
=
0
;
out:
smb_unlock_server
(
server
);
return
result
;
}
...
...
@@ -1855,12 +1864,13 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
goto
retry
;
goto
out
;
}
result
=
0
;
if
(
server
->
rcls
!=
0
)
result
=
-
smb_errno
(
server
->
rcls
,
server
->
err
);
out:
smb_unlock_server
(
server
);
return
0
;
return
result
;
}
int
...
...
@@ -1869,9 +1879,6 @@ smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
{
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
);
else
...
...
fs/smbfs/sock.c
View file @
73f103e4
...
...
@@ -7,11 +7,9 @@
*/
#include <linux/sched.h>
#include <linux/smb_fs.h>
#include <linux/errno.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
...
...
@@ -19,6 +17,7 @@
#include <net/scm.h>
#include <net/ip.h>
#include <linux/smb_fs.h>
#include <linux/smb.h>
#include <linux/smbno.h>
...
...
@@ -97,11 +96,15 @@ smb_data_callback(struct sock *sk, int len)
while
(
1
)
{
result
=
-
EIO
;
if
(
sk
->
dead
)
{
#ifdef SMBFS_PARANOIA
printk
(
"smb_data_callback: sock dead!
\n
"
);
return
;
#endif
break
;
}
result
=
_recvfrom
(
socket
,
(
void
*
)
peek_buf
,
1
,
MSG_PEEK
|
MSG_DONTWAIT
);
if
(
result
==
-
EAGAIN
)
...
...
@@ -361,6 +364,16 @@ printk("smb_get_length: Invalid NBT packet, code=%x\n", peek_buf[0]);
return
smb_len
(
peek_buf
);
}
/*
* Since we allocate memory in increments of PAGE_SIZE,
* round up the packet length to the next multiple.
*/
int
smb_round_length
(
int
len
)
{
return
(
len
+
PAGE_SIZE
-
1
)
&
~
(
PAGE_SIZE
-
1
);
}
/*
* smb_receive
* fs points to the correct segment
...
...
@@ -369,6 +382,7 @@ static int
smb_receive
(
struct
smb_sb_info
*
server
)
{
struct
socket
*
socket
=
server_sock
(
server
);
unsigned
char
*
packet
=
server
->
packet
;
int
len
,
result
;
unsigned
char
peek_buf
[
4
];
...
...
@@ -383,19 +397,22 @@ smb_receive(struct smb_sb_info *server)
*/
if
(
len
+
4
>
server
->
packet_size
)
{
char
*
packet
;
pr_debug
(
"smb_receive: Increase packet size from %d to %d
\n
"
,
server
->
packet_size
,
len
+
4
);
int
new_len
=
smb_round_length
(
len
+
4
);
#ifdef SMBFS_PARANOIA
printk
(
"smb_receive: Increase packet size from %d to %d
\n
"
,
server
->
packet_size
,
new_len
);
#endif
result
=
-
ENOMEM
;
packet
=
smb_vmalloc
(
len
+
4
);
packet
=
smb_vmalloc
(
new_len
);
if
(
packet
==
NULL
)
goto
out
;
smb_vfree
(
server
->
packet
);
server
->
packet
=
packet
;
server
->
packet_size
=
len
+
4
;
server
->
packet_size
=
new_len
;
}
memcpy
(
server
->
packet
,
peek_buf
,
4
);
result
=
smb_receive_raw
(
socket
,
server
->
packet
+
4
,
len
);
memcpy
(
packet
,
peek_buf
,
4
);
result
=
smb_receive_raw
(
socket
,
packet
+
4
,
len
);
if
(
result
<
0
)
{
#ifdef SMBFS_DEBUG_VERBOSE
...
...
@@ -403,8 +420,8 @@ printk("smb_receive: receive error: %d\n", result);
#endif
goto
out
;
}
server
->
rcls
=
*
(
server
->
packet
+
9
);
server
->
err
=
WVAL
(
server
->
packet
,
11
);
server
->
rcls
=
*
(
packet
+
9
);
server
->
err
=
WVAL
(
packet
,
11
);
#ifdef SMBFS_DEBUG_VERBOSE
if
(
server
->
rcls
!=
0
)
...
...
@@ -415,136 +432,165 @@ printk("smb_receive: rcls=%d, err=%d\n", server->rcls, server->err);
}
/*
* 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.
* This routine checks first for "fast track" processing, as most
* packets won't need to be copied. Otherwise, it allocates a new
* packet to hold the incoming data.
*
* Note that the final server packet must be the larger of the two;
* server packets aren't allowed to shrink.
*/
static
int
smb_receive_trans2
(
struct
smb_sb_info
*
server
,
int
*
ldata
,
unsigned
char
**
data
,
int
*
lpar
am
,
unsigned
char
**
para
m
)
int
*
lpar
m
,
unsigned
char
**
par
m
)
{
int
total_data
=
0
;
int
total_param
=
0
;
unsigned
char
*
inbuf
,
*
base
,
*
rcv_buf
=
NULL
;
unsigned
int
parm_disp
,
parm_offset
,
parm_count
,
parm_tot
,
parm_len
=
0
;
unsigned
int
data_disp
,
data_offset
,
data_count
,
data_tot
,
data_len
=
0
;
unsigned
int
total_p
=
0
,
total_d
=
0
,
buf_len
=
0
;
int
result
;
unsigned
char
*
rcv_buf
;
int
buf_len
;
int
data_len
=
0
;
int
param_len
=
0
;
if
((
result
=
smb_receive
(
server
))
<
0
)
{
return
result
;
}
if
(
server
->
rcls
!=
0
)
{
*
param
=
*
data
=
server
->
packet
;
*
ldata
=
*
lparam
=
0
;
return
0
;
}
total_data
=
WVAL
(
server
->
packet
,
smb_tdrcnt
);
total_param
=
WVAL
(
server
->
packet
,
smb_tprcnt
);
pr_debug
(
"smb_receive_trans2: td=%d,tp=%d
\n
"
,
total_data
,
total_param
);
if
((
total_data
>
TRANS2_MAX_TRANSFER
)
||
(
total_param
>
TRANS2_MAX_TRANSFER
))
{
pr_debug
(
"smb_receive_trans2: data/param too long
\n
"
);
return
-
EIO
;
}
buf_len
=
total_data
+
total_param
;
if
(
server
->
packet_size
>
buf_len
)
{
buf_len
=
server
->
packet_size
;
}
if
((
rcv_buf
=
smb_vmalloc
(
buf_len
))
==
NULL
)
{
pr_debug
(
"smb_receive_trans2: could not alloc data area
\n
"
);
return
-
ENOMEM
;
}
*
param
=
rcv_buf
;
*
data
=
rcv_buf
+
total_param
;
while
(
1
)
{
unsigned
char
*
inbuf
=
server
->
packet
;
if
(
WVAL
(
inbuf
,
smb_prdisp
)
+
WVAL
(
inbuf
,
smb_prcnt
)
>
total_param
)
result
=
smb_receive
(
server
);
if
(
result
<
0
)
goto
out
;
inbuf
=
server
->
packet
;
if
(
server
->
rcls
!=
0
)
{
pr_debug
(
"smb_receive_trans2: invalid parameters
\n
"
)
;
result
=
-
EIO
;
goto
fail
;
*
parm
=
*
data
=
inbuf
;
*
ldata
=
*
lparm
=
0
;
goto
out
;
}
memcpy
(
*
param
+
WVAL
(
inbuf
,
smb_prdisp
),
smb_base
(
inbuf
)
+
WVAL
(
inbuf
,
smb_proff
),
WVAL
(
inbuf
,
smb_prcnt
));
param_len
+=
WVAL
(
inbuf
,
smb_prcnt
);
if
(
WVAL
(
inbuf
,
smb_drdisp
)
+
WVAL
(
inbuf
,
smb_drcnt
)
>
total_data
)
/*
* Extract the control data from the packet.
*/
data_tot
=
WVAL
(
inbuf
,
smb_tdrcnt
);
parm_tot
=
WVAL
(
inbuf
,
smb_tprcnt
);
parm_disp
=
WVAL
(
inbuf
,
smb_prdisp
);
parm_offset
=
WVAL
(
inbuf
,
smb_proff
);
parm_count
=
WVAL
(
inbuf
,
smb_prcnt
);
data_disp
=
WVAL
(
inbuf
,
smb_drdisp
);
data_offset
=
WVAL
(
inbuf
,
smb_droff
);
data_count
=
WVAL
(
inbuf
,
smb_drcnt
);
base
=
smb_base
(
inbuf
);
/*
* Assume success and increment lengths.
*/
parm_len
+=
parm_count
;
data_len
+=
data_count
;
if
(
!
rcv_buf
)
{
pr_debug
(
"smb_receive_trans2: invalid data block
\n
"
);
result
=
-
EIO
;
goto
fail
;
/*
* Check for fast track processing ... just this packet.
*/
if
(
parm_count
==
parm_tot
&&
data_count
==
data_tot
)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk
(
"smb_receive_trans2: fast track, parm=%u %u %u, data=%u %u %u
\n
"
,
parm_disp
,
parm_offset
,
parm_count
,
data_disp
,
data_offset
,
data_count
);
#endif
*
parm
=
base
+
parm_offset
;
*
data
=
base
+
data_offset
;
goto
success
;
}
if
(
parm_tot
>
TRANS2_MAX_TRANSFER
||
data_tot
>
TRANS2_MAX_TRANSFER
)
goto
out_too_long
;
/*
* Save the total parameter and data length.
*/
total_d
=
data_tot
;
total_p
=
parm_tot
;
buf_len
=
total_d
+
total_p
;
if
(
server
->
packet_size
>
buf_len
)
buf_len
=
server
->
packet_size
;
buf_len
=
smb_round_length
(
buf_len
);
rcv_buf
=
smb_vmalloc
(
buf_len
);
if
(
!
rcv_buf
)
goto
out_no_mem
;
*
parm
=
rcv_buf
;
*
data
=
rcv_buf
+
total_p
;
}
pr_debug
(
"disp: %d, off: %d, cnt: %d
\n
"
,
WVAL
(
inbuf
,
smb_drdisp
),
WVAL
(
inbuf
,
smb_droff
),
WVAL
(
inbuf
,
smb_drcnt
));
else
if
(
data_tot
>
total_d
||
parm_tot
>
total_p
)
goto
out_data_grew
;
memcpy
(
*
data
+
WVAL
(
inbuf
,
smb_drdisp
),
smb_base
(
inbuf
)
+
WVAL
(
inbuf
,
smb_droff
),
WVAL
(
inbuf
,
smb_drcnt
));
data_len
+=
WVAL
(
inbuf
,
smb_drcnt
);
if
((
WVAL
(
inbuf
,
smb_tdrcnt
)
>
total_data
)
||
(
WVAL
(
inbuf
,
smb_tprcnt
)
>
total_param
))
{
pr_debug
(
"smb_receive_trans2: data/params grew!
\n
"
);
result
=
-
EIO
;
goto
fail
;
}
/* the total lengths might shrink! */
total_data
=
WVAL
(
inbuf
,
smb_tdrcnt
);
total_param
=
WVAL
(
inbuf
,
smb_tprcnt
);
if
(
parm_disp
+
parm_count
>
total_p
)
goto
out_bad_parm
;
if
(
data_disp
+
data_count
>
total_d
)
goto
out_bad_data
;
memcpy
(
*
parm
+
parm_disp
,
base
+
parm_offset
,
parm_count
);
memcpy
(
*
data
+
data_disp
,
base
+
data_offset
,
data_count
);
#ifdef SMBFS_PARANOIA
if
((
data_len
>=
total_data
||
param_len
>=
total_param
)
&&
!
(
data_len
>=
total_data
&&
param_len
>=
total_param
))
printk
(
"smb_receive_trans2: dlen=%d, tdata=%d, plen=%d, tlen=%d
\n
"
,
data_len
,
total_data
,
param_len
,
total_param
);
printk
(
"smb_receive_trans2: copied, parm=%u of %u, data=%u of %u
\n
"
,
parm_len
,
parm_tot
,
data_len
,
data_tot
);
#endif
/* shouldn't this be an OR test? don't want to overrun */
if
((
data_len
>=
total_data
)
&&
(
param_len
>=
total_param
))
{
/*
* Check whether we've received all of the data. Note that
* we use the packet totals -- total lengths might shrink!
*/
if
(
data_len
>=
data_tot
&&
parm_len
>=
parm_tot
)
break
;
}
if
((
result
=
smb_receive
(
server
))
<
0
)
{
goto
fail
;
}
result
=
-
EIO
;
if
(
server
->
rcls
!=
0
)
goto
fail
;
}
*
ldata
=
data_len
;
*
lparam
=
param_len
;
/*
* Install the new packet. Note that it's possible, though
* unlikely, that the new packet could be smaller than the
* old one, in which case we just copy the data.
*/
inbuf
=
server
->
packet
;
if
(
buf_len
>=
server
->
packet_size
)
{
server
->
packet_size
=
buf_len
;
server
->
packet
=
rcv_buf
;
rcv_buf
=
inbuf
;
}
else
{
#ifdef SMBFS_PARANOIA
if
(
buf_len
<
server
->
packet_size
)
printk
(
"smb_receive_trans2: changing packet, old size=%d, new size=%d
\n
"
,
printk
(
"smb_receive_trans2: copying data, old size=%d, new size=%u
\n
"
,
server
->
packet_size
,
buf_len
);
#endif
smb_vfree
(
server
->
packet
);
server
->
packet
=
rcv_buf
;
server
->
packet_size
=
buf_len
;
return
0
;
memcpy
(
inbuf
,
rcv_buf
,
parm_len
+
data_len
);
}
fail:
smb_vfree
(
rcv_buf
);
success:
*
ldata
=
data_len
;
*
lparm
=
parm_len
;
out:
if
(
rcv_buf
)
smb_vfree
(
rcv_buf
);
return
result
;
out_no_mem:
#ifdef SMBFS_PARANOIA
printk
(
"smb_receive_trans2: couldn't allocate data area
\n
"
);
#endif
result
=
-
ENOMEM
;
goto
out
;
out_too_long:
printk
(
"smb_receive_trans2: data/param too long, data=%d, parm=%d
\n
"
,
data_tot
,
parm_tot
);
goto
out_error
;
out_data_grew:
printk
(
"smb_receive_trans2: data/params grew!
\n
"
);
goto
out_error
;
out_bad_parm:
printk
(
"smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d
\n
"
,
parm_disp
,
parm_count
,
parm_tot
);
goto
out_error
;
out_bad_data:
printk
(
"smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d
\n
"
,
data_disp
,
data_count
,
data_tot
);
out_error:
result
=
-
EIO
;
goto
out
;
}
/*
...
...
@@ -759,14 +805,13 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
}
if
(
result
<
0
)
goto
bad_conn
;
pr_debug
(
"smb_trans2_request: result = %d
\n
"
,
result
);
out:
return
result
;
bad_conn:
#ifdef SMBFS_PARANOIA
printk
(
"smb_trans2_request:
connection bad, setting invalid
\n
"
);
printk
(
"smb_trans2_request:
result=%d, setting invalid
\n
"
,
result
);
#endif
server
->
state
=
CONN_INVALID
;
smb_invalidate_inodes
(
server
);
...
...
fs/vfat/namei.c
View file @
73f103e4
...
...
@@ -1415,8 +1415,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
struct
buffer_head
*
old_bh
,
*
new_bh
,
*
dotdot_bh
;
struct
msdos_dir_entry
*
old_de
,
*
new_de
,
*
dotdot_de
;
loff_t
old_offset
,
new_offset
,
old_longname_offset
;
int
old_slots
,
old_ino
,
new_ino
,
dotdot_ino
,
ino
;
struct
inode
*
old_inode
,
*
new_inode
,
*
dotdot_inode
,
*
walk
;
int
old_slots
,
old_ino
,
new_ino
,
dotdot_ino
;
struct
inode
*
old_inode
,
*
new_inode
,
*
dotdot_inode
;
struct
dentry
*
walk
;
int
res
,
is_dir
,
i
;
int
locked
=
0
;
struct
slot_info
sinfo
;
...
...
@@ -1451,25 +1452,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
res
=
-
EINVAL
;
goto
rename_done
;
}
if
(
!
(
walk
=
iget
(
new_dir
->
i_sb
,
new_dir
->
i_ino
)))
return
-
EIO
;
walk
=
new_dentry
;
/* prevent moving directory below itself */
while
(
walk
->
i_ino
!=
MSDOS_ROOT_INO
)
{
ino
=
fat_parent_ino
(
walk
,
1
);
iput
(
walk
);
if
(
ino
<
0
)
{
res
=
ino
;
goto
rename_done
;
}
if
(
ino
==
old_ino
)
{
res
=
-
EINVAL
;
goto
rename_done
;
}
if
(
!
(
walk
=
iget
(
new_dir
->
i_sb
,
ino
)))
{
res
=
-
EIO
;
goto
rename_done
;
}
for
(;;)
{
if
(
walk
==
old_dentry
)
return
-
EINVAL
;
if
(
walk
==
walk
->
d_parent
)
break
;
walk
=
walk
->
d_parent
;
}
iput
(
walk
);
}
res
=
vfat_find
(
new_dir
,
&
new_dentry
->
d_name
,
1
,
0
,
is_dir
,
&
sinfo
);
...
...
@@ -1589,8 +1578,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
}
if
(
res
>
0
)
res
=
0
;
d_instantiate
(
new_dentry
,
new_inode
);
d_delete
(
old_dentry
);
if
(
res
==
0
)
{
d_move
(
old_dentry
,
new_dentry
);
}
rename_done:
if
(
locked
)
...
...
include/asm-alpha/socket.h
View file @
73f103e4
#ifndef _ASM_SOCKET_H
#define _ASM_SOCKET_H
#include <linux/types.h>
#include <asm/ioctl.h>
#include <asm/sockios.h>
/* For setsockoptions(2) */
...
...
include/linux/dcache.h
View file @
73f103e4
...
...
@@ -17,7 +17,8 @@
*/
struct
qstr
{
const
unsigned
char
*
name
;
unsigned
int
len
,
hash
;
unsigned
int
len
;
unsigned
int
hash
;
};
/* Name hashing routines. Initial hash value */
...
...
@@ -38,6 +39,15 @@ static inline unsigned long end_name_hash(unsigned long hash)
return
(
unsigned
int
)
hash
;
}
/* Compute the hash for a name string. */
static
inline
unsigned
int
full_name_hash
(
const
char
*
name
,
unsigned
int
len
)
{
unsigned
long
hash
=
init_name_hash
();
while
(
len
--
)
hash
=
partial_name_hash
(
*
name
++
,
hash
);
return
end_name_hash
(
hash
);
}
struct
dentry
{
int
d_count
;
unsigned
int
d_flags
;
...
...
include/linux/nfs_fs.h
View file @
73f103e4
...
...
@@ -176,7 +176,7 @@ extern int nfs_lock(struct file *file, int cmd, struct file_lock *fl);
*/
extern
int
nfs_writepage
(
struct
inode
*
,
struct
page
*
);
extern
int
nfs_check_error
(
struct
inode
*
);
extern
int
nfs_flush_dirty_pages
(
struct
inode
*
,
off_t
,
off_t
);
extern
int
nfs_flush_dirty_pages
(
struct
inode
*
,
pid_t
,
off_t
,
off_t
);
extern
int
nfs_truncate_dirty_pages
(
struct
inode
*
,
unsigned
long
);
extern
void
nfs_invalidate_pages
(
struct
inode
*
);
extern
int
nfs_updatepage
(
struct
inode
*
,
struct
page
*
,
const
char
*
,
...
...
include/linux/posix_types.h
View file @
73f103e4
...
...
@@ -41,7 +41,7 @@
#undef __FDMASK
#define __FDMASK(d) (1UL << ((d) % __NFDBITS))
typedef
struct
fd_set
{
typedef
struct
{
unsigned
long
fds_bits
[
__FDSET_LONGS
];
}
__kernel_fd_set
;
...
...
include/linux/smb_fs.h
View file @
73f103e4
...
...
@@ -65,20 +65,18 @@ smb_vfree(void *obj)
#endif
/* DEBUG_SMB_MALLOC */
struct
smb_sb_info
;
/* linux/fs/smbfs/mmap.c */
int
smb_mmap
(
struct
file
*
,
struct
vm_area_struct
*
);
/* linux/fs/smbfs/file.c */
extern
struct
inode_operations
smb_file_inode_operations
;
/* linux/fs/smbfs/dir.c */
extern
struct
inode_operations
smb_dir_inode_operations
;
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
);
int
smb_ioctl
(
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
/* linux/fs/smbfs/inode.c */
struct
super_block
*
smb_read_super
(
struct
super_block
*
,
void
*
,
int
);
...
...
@@ -126,6 +124,7 @@ 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_round_length
(
int
);
int
smb_valid_socket
(
struct
inode
*
);
void
smb_close_socket
(
struct
smb_sb_info
*
);
int
smb_release
(
struct
smb_sb_info
*
server
);
...
...
@@ -141,9 +140,6 @@ int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
int
*
lrdata
,
unsigned
char
**
rdata
,
int
*
lrparam
,
unsigned
char
**
rparam
);
/* linux/fs/smbfs/mmap.c */
int
smb_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
);
/* fs/smbfs/cache.c */
/*
...
...
@@ -206,7 +202,7 @@ 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
);
void
smb_add_to_cache
(
struct
cache_head
*
,
struct
cache_
dirent
*
,
off_t
);
int
smb_find_in_cache
(
struct
cache_head
*
,
off_t
,
struct
cache_dirent
*
);
void
smb_invalid_dir_cache
(
struct
inode
*
);
...
...
include/linux/smb_fs_sb.h
View file @
73f103e4
...
...
@@ -13,7 +13,6 @@
#include <linux/types.h>
#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
...
...
@@ -24,7 +23,7 @@ struct smb_sb_info {
enum
smb_conn_state
state
;
struct
file
*
sock_file
;
struct
smb_mount_data
m
;
struct
smb_mount_data
*
mnt
;
/* Connections are counted. Each time a new socket arrives,
* generation is incremented.
...
...
mm/mmap.c
View file @
73f103e4
...
...
@@ -92,25 +92,21 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
struct
mm_struct
*
mm
=
current
->
mm
;
lock_kernel
();
retval
=
mm
->
brk
;
if
(
brk
<
mm
->
end_code
)
goto
out
;
newbrk
=
PAGE_ALIGN
(
brk
);
oldbrk
=
PAGE_ALIGN
(
mm
->
brk
);
if
(
oldbrk
==
newbrk
)
{
retval
=
mm
->
brk
=
brk
;
goto
out
;
}
if
(
oldbrk
==
newbrk
)
goto
set_brk
;
/* Always allow shrinking brk. */
if
(
brk
<=
mm
->
brk
)
{
retval
=
mm
->
brk
=
brk
;
do_munmap
(
newbrk
,
oldbrk
-
newbrk
)
;
if
(
!
do_munmap
(
newbrk
,
oldbrk
-
newbrk
))
goto
set_brk
;
goto
out
;
}
/* Check against rlimit and stack.. */
retval
=
mm
->
brk
;
rlim
=
current
->
rlim
[
RLIMIT_DATA
].
rlim_cur
;
if
(
rlim
>=
RLIM_INFINITY
)
rlim
=
~
0
;
...
...
@@ -126,12 +122,14 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
goto
out
;
/* Ok, looks good - let it rip. */
if
(
do_mmap
(
NULL
,
oldbrk
,
newbrk
-
oldbrk
,
if
(
do_mmap
(
NULL
,
oldbrk
,
newbrk
-
oldbrk
,
PROT_READ
|
PROT_WRITE
|
PROT_EXEC
,
MAP_FIXED
|
MAP_PRIVATE
,
0
)
==
oldbrk
)
mm
->
brk
=
brk
;
retval
=
mm
->
brk
;
MAP_FIXED
|
MAP_PRIVATE
,
0
)
!=
oldbrk
)
goto
out
;
set_brk:
mm
->
brk
=
brk
;
out:
retval
=
mm
->
brk
;
unlock_kernel
();
return
retval
;
}
...
...
@@ -163,7 +161,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
{
struct
mm_struct
*
mm
=
current
->
mm
;
struct
vm_area_struct
*
vma
;
int
correct_wcount
=
0
;
int
correct_wcount
=
0
,
error
;
if
((
len
=
PAGE_ALIGN
(
len
))
==
0
)
return
addr
;
...
...
@@ -262,26 +260,24 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
vma
->
vm_dentry
=
NULL
;
vma
->
vm_pte
=
0
;
do_munmap
(
addr
,
len
);
/* Clear old maps */
/* Clear old maps */
error
=
-
ENOMEM
;
if
(
do_munmap
(
addr
,
len
))
goto
free_vma
;
/* Check against address space limit. */
if
((
mm
->
total_vm
<<
PAGE_SHIFT
)
+
len
>
current
->
rlim
[
RLIMIT_AS
].
rlim_cur
)
{
kmem_cache_free
(
vm_area_cachep
,
vma
);
return
-
ENOMEM
;
}
>
current
->
rlim
[
RLIMIT_AS
].
rlim_cur
)
goto
free_vma
;
/* Private writable mapping? Check memory availability.. */
if
((
vma
->
vm_flags
&
(
VM_SHARED
|
VM_WRITE
))
==
VM_WRITE
)
{
if
(
!
(
flags
&
MAP_NORESERVE
)
&&
!
vm_enough_memory
(
len
>>
PAGE_SHIFT
))
{
kmem_cache_free
(
vm_area_cachep
,
vma
);
return
-
ENOMEM
;
}
}
if
((
vma
->
vm_flags
&
(
VM_SHARED
|
VM_WRITE
))
==
VM_WRITE
&&
!
(
flags
&
MAP_NORESERVE
)
&&
!
vm_enough_memory
(
len
>>
PAGE_SHIFT
))
goto
free_vma
;
error
=
0
;
if
(
file
)
{
int
error
=
0
;
if
(
vma
->
vm_flags
&
VM_DENYWRITE
)
{
if
(
file
->
f_dentry
->
d_inode
->
i_writecount
>
0
)
error
=
-
ETXTBSY
;
...
...
@@ -298,23 +294,22 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
if
(
!
error
)
error
=
file
->
f_op
->
mmap
(
file
,
vma
);
if
(
error
)
{
if
(
correct_wcount
)
file
->
f_dentry
->
d_inode
->
i_writecount
++
;
kmem_cache_free
(
vm_area_cachep
,
vma
);
return
error
;
}
}
/* Fix up the count if necessary, then check for an error */
if
(
correct_wcount
)
file
->
f_dentry
->
d_inode
->
i_writecount
++
;
if
(
error
)
goto
free_vma
;
/*
* merge_segments may merge our vma, so we can't refer to it
* after the call. Save the values we need now ...
*/
flags
=
vma
->
vm_flags
;
addr
=
vma
->
vm_start
;
/* can addr have changed?? */
insert_vm_struct
(
mm
,
vma
);
if
(
correct_wcount
)
file
->
f_dentry
->
d_inode
->
i_writecount
++
;
merge_segments
(
mm
,
vma
->
vm_start
,
vma
->
vm_end
);
addr
=
vma
->
vm_start
;
/* merge_segments might have merged our vma, so we can't use it any more */
mm
->
total_vm
+=
len
>>
PAGE_SHIFT
;
if
((
flags
&
VM_LOCKED
)
&&
!
(
flags
&
VM_IO
))
{
unsigned
long
start
=
addr
;
...
...
@@ -328,6 +323,10 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
}
while
(
len
>
0
);
}
return
addr
;
free_vma:
kmem_cache_free
(
vm_area_cachep
,
vma
);
return
error
;
}
/* Get an address range which is currently unmapped.
...
...
mm/swap_state.c
View file @
73f103e4
...
...
@@ -18,9 +18,6 @@
#include <linux/swapctl.h>
#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h>
/* for cli()/sti() */
#include <asm/uaccess.h>
/* for cop_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
...
...
@@ -60,31 +57,47 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
return
0
;
}
/*
* If swap_map[] reaches 127, the entries are treated as "permanent".
*/
void
swap_duplicate
(
unsigned
long
entry
)
{
struct
swap_info_struct
*
p
;
unsigned
long
offset
,
type
;
if
(
!
entry
)
return
;
offset
=
SWP_OFFSET
(
entry
);
goto
out
;
type
=
SWP_TYPE
(
entry
);
if
(
type
&
SHM_SWP_TYPE
)
return
;
if
(
type
>=
nr_swapfiles
)
{
printk
(
"Trying to duplicate nonexistent swap-page
\n
"
);
return
;
}
goto
out
;
if
(
type
>=
nr_swapfiles
)
goto
bad_file
;
p
=
type
+
swap_info
;
if
(
offset
>=
p
->
max
)
{
printk
(
"swap_duplicate: weirdness
\n
"
);
return
;
}
if
(
!
p
->
swap_map
[
offset
])
{
printk
(
"swap_duplicate: trying to duplicate unused page
\n
"
);
return
;
offset
=
SWP_OFFSET
(
entry
);
if
(
offset
>=
p
->
max
)
goto
bad_offset
;
if
(
!
p
->
swap_map
[
offset
])
goto
bad_unused
;
if
(
p
->
swap_map
[
offset
]
<
126
)
p
->
swap_map
[
offset
]
++
;
else
{
static
int
overflow
=
0
;
if
(
overflow
++
<
5
)
printk
(
"swap_duplicate: entry %08lx map count=%d
\n
"
,
entry
,
p
->
swap_map
[
offset
]);
p
->
swap_map
[
offset
]
=
127
;
}
p
->
swap_map
[
offset
]
++
;
out:
return
;
bad_file:
printk
(
"swap_duplicate: Trying to duplicate nonexistent swap-page
\n
"
);
goto
out
;
bad_offset:
printk
(
"swap_duplicate: offset exceeds max
\n
"
);
goto
out
;
bad_unused:
printk
(
"swap_duplicate: unused page
\n
"
);
goto
out
;
}
mm/swapfile.c
View file @
73f103e4
...
...
@@ -21,11 +21,7 @@
#include <linux/malloc.h>
#include <linux/blkdev.h>
/* for blk_size */
#include <linux/vmalloc.h>
#include <linux/dcache.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>
...
...
@@ -122,52 +118,60 @@ unsigned long get_swap_page(void)
}
}
/*
* If the swap count overflows (swap_map[] == 127), the entry is considered
* "permanent" and can't be reclaimed until the swap device is closed.
*/
void
swap_free
(
unsigned
long
entry
)
{
struct
swap_info_struct
*
p
;
unsigned
long
offset
,
type
;
if
(
!
entry
)
return
;
goto
out
;
type
=
SWP_TYPE
(
entry
);
if
(
type
&
SHM_SWP_TYPE
)
return
;
if
(
type
>=
nr_swapfiles
)
{
printk
(
"Trying to free nonexistent swap-page
\n
"
);
return
;
}
goto
out
;
if
(
type
>=
nr_swapfiles
)
goto
bad_nofile
;
p
=
&
swap_info
[
type
];
if
(
!
(
p
->
flags
&
SWP_USED
))
goto
bad_device
;
if
(
p
->
prio
>
swap_info
[
swap_list
.
next
].
prio
)
swap_list
.
next
=
swap_list
.
head
;
offset
=
SWP_OFFSET
(
entry
);
if
(
offset
>=
p
->
max
)
{
printk
(
"swap_free: weirdness
\n
"
);
return
;
}
if
(
!
(
p
->
flags
&
SWP_USED
))
{
printk
(
"Trying to free swap from unused swap-device
\n
"
);
return
;
}
if
(
offset
>=
p
->
max
)
goto
bad_offset
;
if
(
offset
<
p
->
lowest_bit
)
p
->
lowest_bit
=
offset
;
if
(
offset
>
p
->
highest_bit
)
p
->
highest_bit
=
offset
;
if
(
!
p
->
swap_map
[
offset
])
printk
(
"swap_free: swap-space map bad (entry %08lx)
\n
"
,
entry
)
;
else
goto
bad_free
;
if
(
p
->
swap_map
[
offset
]
<
127
)
{
if
(
!--
p
->
swap_map
[
offset
])
nr_swap_pages
++
;
if
(
p
->
prio
>
swap_info
[
swap_list
.
next
].
prio
)
{
swap_list
.
next
=
swap_list
.
head
;
}
out:
return
;
bad_nofile:
printk
(
"swap_free: Trying to free nonexistent swap-page
\n
"
);
goto
out
;
bad_device:
printk
(
"swap_free: Trying to free swap from unused swap-device
\n
"
);
goto
out
;
bad_offset:
printk
(
"swap_free: offset exceeds max
\n
"
);
goto
out
;
bad_free:
printk
(
"swap_free: swap-space map bad (entry %08lx)
\n
"
,
entry
);
goto
out
;
}
/*
* Trying to stop swapping from a file is fraught with races, so
* we repeat quite a bit here when we have to pause. swapoff()
* isn't exactly timing-critical, so who cares (but this is /really/
* inefficient, ugh).
*
* We return 1 after having slept, which makes the process start over
* from the beginning for this process..
* The swap entry has been read in advance, and we return 1 to indicate
* that the page has been used or is no longer needed.
*/
static
inline
int
unuse_pte
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
pte_t
*
dir
,
unsigned
long
entry
,
unsigned
long
page
)
...
...
@@ -198,9 +202,8 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
if
(
pte_val
(
pte
)
!=
entry
)
return
0
;
set_pte
(
dir
,
pte_mkwrite
(
pte_mkdirty
(
mk_pte
(
page
,
vma
->
vm_page_prot
))));
flush_tlb_page
(
vma
,
address
);
++
vma
->
vm_mm
->
rss
;
swap_free
(
pte_val
(
pte
)
);
swap_free
(
entry
);
return
1
;
}
...
...
@@ -296,18 +299,6 @@ static int unuse_process(struct mm_struct * mm, unsigned long entry,
return
0
;
}
static
unsigned
long
find_swap_entry
(
int
type
)
{
struct
swap_info_struct
*
p
=
&
swap_info
[
type
];
int
i
;
for
(
i
=
1
;
i
<
p
->
max
;
i
++
)
{
if
(
p
->
swap_map
[
i
]
>
0
&&
p
->
swap_map
[
i
]
!=
0x80
)
return
SWP_ENTRY
(
type
,
i
);
}
return
0
;
}
/*
* We completely avoid races by reading each swap page in advance,
* and then search for the process using it. All the necessary
...
...
@@ -315,14 +306,13 @@ static unsigned long find_swap_entry(int type)
*/
static
int
try_to_unuse
(
unsigned
int
type
)
{
unsigned
long
page
=
0
;
struct
swap_info_struct
*
si
=
&
swap_info
[
type
]
;
struct
task_struct
*
p
;
unsigned
long
page
=
0
;
unsigned
long
entry
;
int
i
;
/*
* Find all swap entries in use ...
*/
while
((
entry
=
find_swap_entry
(
type
))
!=
0
)
{
while
(
1
)
{
if
(
!
page
)
{
page
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
page
)
...
...
@@ -330,8 +320,16 @@ static int try_to_unuse(unsigned int type)
}
/*
* Read in the page, and then free the swap page.
*/
* Find a swap page in use and read it in.
*/
for
(
i
=
1
,
entry
=
0
;
i
<
si
->
max
;
i
++
)
{
if
(
si
->
swap_map
[
i
]
>
0
&&
si
->
swap_map
[
i
]
!=
0x80
)
{
entry
=
SWP_ENTRY
(
type
,
i
);
break
;
}
}
if
(
!
entry
)
break
;
read_swap_page
(
entry
,
(
char
*
)
page
);
read_lock
(
&
tasklist_lock
);
...
...
@@ -344,9 +342,19 @@ static int try_to_unuse(unsigned int type)
unlock:
read_unlock
(
&
tasklist_lock
);
if
(
page
)
{
printk
(
"try_to_unuse: didn't find entry %8lx
\n
"
,
entry
);
swap_free
(
entry
);
/*
* If we couldn't find an entry, there are several
* possible reasons: someone else freed it first,
* we freed the last reference to an overflowed entry,
* or the system has lost track of the use counts.
*/
if
(
si
->
swap_map
[
i
]
!=
0
)
{
if
(
si
->
swap_map
[
i
]
!=
127
)
printk
(
"try_to_unuse: entry %08lx "
"not in use
\n
"
,
entry
);
si
->
swap_map
[
i
]
=
0
;
nr_swap_pages
++
;
}
}
}
...
...
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