Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
fca324e7
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fca324e7
编写于
11月 01, 2005
作者:
L
Linus Torvalds
浏览文件
操作
浏览文件
下载
差异文件
Merge master.kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6
上级
1d373741
7f285701
变更
27
展开全部
显示空白变更内容
内联
并排
Showing
27 changed file
with
2442 addition
and
722 deletion
+2442
-722
fs/cifs/AUTHORS
fs/cifs/AUTHORS
+4
-0
fs/cifs/CHANGES
fs/cifs/CHANGES
+52
-8
fs/cifs/README
fs/cifs/README
+20
-4
fs/cifs/TODO
fs/cifs/TODO
+32
-18
fs/cifs/asn1.c
fs/cifs/asn1.c
+2
-1
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.c
+87
-16
fs/cifs/cifs_debug.h
fs/cifs/cifs_debug.h
+4
-1
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_fs_sb.h
+3
-0
fs/cifs/cifsfs.c
fs/cifs/cifsfs.c
+72
-8
fs/cifs/cifsfs.h
fs/cifs/cifsfs.h
+2
-1
fs/cifs/cifsglob.h
fs/cifs/cifsglob.h
+92
-6
fs/cifs/cifspdu.h
fs/cifs/cifspdu.h
+328
-171
fs/cifs/cifsproto.h
fs/cifs/cifsproto.h
+26
-6
fs/cifs/cifssmb.c
fs/cifs/cifssmb.c
+548
-111
fs/cifs/connect.c
fs/cifs/connect.c
+182
-37
fs/cifs/dir.c
fs/cifs/dir.c
+100
-8
fs/cifs/fcntl.c
fs/cifs/fcntl.c
+9
-3
fs/cifs/file.c
fs/cifs/file.c
+333
-133
fs/cifs/inode.c
fs/cifs/inode.c
+100
-50
fs/cifs/link.c
fs/cifs/link.c
+4
-1
fs/cifs/misc.c
fs/cifs/misc.c
+101
-22
fs/cifs/netmisc.c
fs/cifs/netmisc.c
+10
-5
fs/cifs/ntlmssp.h
fs/cifs/ntlmssp.h
+4
-8
fs/cifs/readdir.c
fs/cifs/readdir.c
+65
-19
fs/cifs/rfc1002pdu.h
fs/cifs/rfc1002pdu.h
+4
-9
fs/cifs/transport.c
fs/cifs/transport.c
+255
-76
mm/swap.c
mm/swap.c
+3
-0
未找到文件。
fs/cifs/AUTHORS
浏览文件 @
fca324e7
...
...
@@ -32,6 +32,10 @@ Domen Puncer
Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
Vince Negri and Dave Stahl (for finding an important caching bug)
Adrian Bunk (kcalloc cleanups)
Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Test case and Bug Report contributors
-------------------------------------
...
...
fs/cifs/CHANGES
浏览文件 @
fca324e7
Version 1.39
------------
Defer close of a file handle slightly if pending writes depend on that file handle
(this reduces the EBADF bad file handle errors that can be logged under heavy
stress on writes).
Version 1.38
------------
Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
to be smaller at first (but increasing) so large write performance performance
over GigE is better. Do not hang thread on illegal byte range lock response
from Windows (Windows can send an RFC1001 size which does not match smb size) by
allowing an SMBs TCP length to be up to a few bytes longer than it should be.
wsize and rsize can now be larger than negotiated buffer size if server
supports large readx/writex, even when directio mount flag not specified.
Write size will in many cases now be 16K instead of 4K which greatly helps
file copy performance on lightly loaded networks. Fix oops in dnotify
when experimental config flag enabled. Make cifsFYI more granular.
Version 1.37
------------
Fix readdir caching when unlink removes file in current search buffer,
and this is followed by a rewind search to just before the deleted entry.
Do not attempt to set ctime unless atime and/or mtime change requested
(most servers throw it away anyway). Fix length check of received smbs
to be more accurate. Fix big endian problem with mapchars mount option,
and with a field returned by statfs.
Version 1.36
------------
Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
For these older servers, add option for passing netbios name of server in
on mount (servernetbiosname). Add suspend support for power management, to
avoid cifsd thread preventing software suspend from working.
Add mount option for disabling the default behavior of sending byte range lock
requests to the server (necessary for certain applications which break with
mandatory lock behavior such as Evolution), and also mount option for
requesting case insensitive matching for path based requests (requesting
case sensitive is the default).
Version 1.35
------------
Add writepage performance improvements. Fix path name conversions
for long filenames on mounts which were done with "mapchars" mount option
specified.
specified. Ensure multiplex ids do not collide. Fix case in which
rmmod can oops if done soon after last unmount. Fix truncated
search (readdir) output when resume filename was a long filename.
Fix filename conversion when mapchars mount option was specified and
filename was a long filename.
Version 1.34
------------
...
...
@@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or
kills the cifsd thread (NB: killing the cifs kernel threads is not
recommended, unmount and rmmod cifs will kill them when they are
no longer needed). Fix readdir to ASCII servers (ie older servers
which do not support Unicode) and also require asterik.
which do not support Unicode) and also require asteri
s
k.
Fix out of memory case in which data could be written one page
off in the page cache.
...
...
@@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25
------------
Fix internationlization problem in cifs readdir with filenames that map to
Fix internation
a
lization problem in cifs readdir with filenames that map to
longer UTF8 strings than the string on the wire was in Unicode. Add workaround
for readdir to netapp servers. Fix search rewind (seek into readdir to return
non-consecutive entries). Do not do readdir when server negotiates
...
...
@@ -276,7 +320,7 @@ Fix caching problem when files opened by multiple clients in which
page cache could contain stale data, and write through did
not occur often enough while file was still open when read ahead
(read oplock) not allowed. Treat "sep=" when first mount option
as an overr
r
ide of comma as the default separator between mount
as an override of comma as the default separator between mount
options.
Version 1.01
...
...
@@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string.
Version 1.00
------------
Gracefully clean up failed mounts when attempting to mount to servers such as
Windows 98 that terminate tcp sessions during proto
to
col negotiation. Handle
Windows 98 that terminate tcp sessions during protocol negotiation. Handle
embedded commas in mount parsing of passwords.
Version 0.99
...
...
@@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file
instance is closed so that the client does not continue using stale local
copy rather than later modified server copy of file. Do not reconnect
when server drops the tcp session prematurely before negotiate
protocol response. Fix oops in r
oe
pen_file when dentry freed. Allow
protocol response. Fix oops in r
eo
pen_file when dentry freed. Allow
the support for CIFS Unix Extensions to be disabled via proc interface.
Version 0.98
...
...
@@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early
Version 0.41
------------
Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked
files now return the correct
r
umber of links on fstat as they are repeatedly linked and unlinked.
files now return the correct
n
umber of links on fstat as they are repeatedly linked and unlinked.
Version 0.40
------------
...
...
@@ -704,7 +748,7 @@ session)
and cleaned them up and made them more consistent with other cifs functions.
7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways
(with or without Unix ex
ent
ions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
(with or without Unix ex
tens
ions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
nor is the symlink support using the Unix extensions
8) Started adding the readlink and follow_link code
...
...
fs/cifs/README
浏览文件 @
fca324e7
...
...
@@ -294,8 +294,10 @@ A partial list of the supported mount options follows:
during the local client kernel build will be used.
If server does not support Unicode, this parameter is
unused.
rsize default read size
wsize default write size
rsize default read size (usually 16K)
wsize default write size (usually 16K, 32K is often better over GigE)
maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
pages)
rw mount the network share read-write (note that the
server may still consider the share read-only)
ro mount network share read-only
...
...
@@ -407,6 +409,13 @@ A partial list of the supported mount options follows:
This has no effect if the server does not support
Unicode on the wire.
nomapchars Do not translate any of these seven characters (default).
nocase Request case insensitive path name matching (case
sensitive is the default if the server suports it).
nobrl Do not send byte range lock requests to the server.
This is necessary for certain applications that break
with cifs style mandatory byte range locks (and most
cifs servers do not yet support requesting advisory
byte range locks).
remount remount the share (often used to change from ro to rw mounts
or vice versa)
...
...
@@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in
kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable
tracing to the kernel message log type:
echo
1
> /proc/fs/cifs/cifsFYI
echo
7
> /proc/fs/cifs/cifsFYI
and for more extensive tracing including the start of smb requests and responses
cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
logging of various informational messages. 2 enables logging of non-zero
SMB return codes while 4 enables logging of requests that take longer
than one second to complete (except for byte range lock requests).
Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
source code (typically by setting it in the beginning of cifsglob.h),
and setting it to seven enables all three. Finally, tracing
the start of smb requests and responses can be enabled via:
echo 1 > /proc/fs/cifs/traceSMB
...
...
fs/cifs/TODO
浏览文件 @
fca324e7
version 1.3
4 April 2
9, 2005
version 1.3
7 October
9, 2005
A Partial List of Missing Features
==================================
...
...
@@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities
for visible, important contributions to this module. Here
is a partial list of the known problems and missing features:
a) Support for SecurityDescriptors
for chmod/chgrp/chown so
these can be supported for
Windows servers
a) Support for SecurityDescriptors
(Windows/CIFS ACLs) for chmod/chgrp/chown
so that these operations can be supported to
Windows servers
b)
Better pam/winbind integration (e.g. to handle uid mapping
better)
b)
Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
SecurityDescriptors
c)
multi-user mounts - multiplexed sessionsetups over single vc
(ie tcp session) - more testing needed
c)
Better pam/winbind integration (e.g. to handle uid mapping
better)
d) Kerberos/SPNEGO session setup support - (started)
...
...
@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started)
g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
style byte range lock differences
style byte range lock differences. Save byte range locks so
reconnect can replay them.
h) quota support
h) Support unlock all (unlock 0,MAX_OFFSET)
by unlocking all known byte range locks that we locked on the file.
j) finish writepages support (multi-page write behind for improved
performance) and syncpage
i) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)
j) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr
k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases.
...
...
@@ -57,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers
in the Extended Attribute format their SFU clients would recognize.
q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
will autorefresh (started)
will autorefresh (partially complete by Asser). Needs minor kernel
vfs change to support removing D_NOTIFY on a file.
r) Add GUI tool to configure /proc/fs/cifs settings and for display of
the CIFS statistics (started)
q
) implement support for security and trusted categories of xattrs
s
) implement support for security and trusted categories of xattrs
(requires minor protocol extension) to enable better support for SELINUX
r) Implement O_DIRECT flag on open (already supported on mount)
s) Allow remapping of last remaining character (\) to +0xF000 which
(this character is valid for POSIX but not for Windows)
t) Implement O_DIRECT flag on open (already supported on mount)
t
) Create UID mapping facility so server UIDs can be mapped on a per
u
) Create UID mapping facility so server UIDs can be mapped on a per
mount or a per server basis to client UIDs or nobody if no mapping
exists. This is helpful when Unix extensions are negotiated to
allow better permission checking when UIDs differ on the server
...
...
@@ -78,6 +81,17 @@ and client. Add new protocol request to the CIFS protocol
standard for asking the server for the corresponding name of a
particular uid.
v) Add support for CIFS Unix and also the newer POSIX extensions to the
server side for Samba 4.
w) Finish up the dos time conversion routines needed to return old server
time to the client (default time, of now or time 0 is used now for these
very old servers)
x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
y) Finish testing of Windows 9x/Windows ME server support (started).
KNOWN BUGS (updated April 29, 2005)
====================================
See http://bugzilla.samba.org - search on product "CifsVFS" for
...
...
fs/cifs/asn1.c
浏览文件 @
fca324e7
...
...
@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx,
unsigned
char
**
eoc
,
unsigned
int
*
cls
,
unsigned
int
*
con
,
unsigned
int
*
tag
)
{
unsigned
int
def
,
len
;
unsigned
int
def
=
0
;
unsigned
int
len
=
0
;
if
(
!
asn1_id_decode
(
ctx
,
cls
,
con
,
tag
))
return
0
;
...
...
fs/cifs/cifs_debug.c
浏览文件 @
fca324e7
...
...
@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf
+=
length
;
length
=
sprintf
(
buf
,
"CIFS Version %s
\n
"
,
CIFS_VERSION
);
buf
+=
length
;
length
=
sprintf
(
buf
,
"Active VFS Requests: %d
\n
"
,
GlobalTotalActiveXid
);
buf
+=
length
;
length
=
sprintf
(
buf
,
"Servers:"
);
buf
+=
length
;
...
...
@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
}
else
{
length
=
sprintf
(
buf
,
"
\n
%d) Name: %s Domain: %s Mounts: %d
ServerOS: %s
\n\t
ServerNOS: %s
\t
Capabilities
: 0x%x
\n\t
SMB session status: %d
\t
"
,
"
\n
%d) Name: %s Domain: %s Mounts: %d
OS: %s
\n\t
NOS: %s
\t
Capability
: 0x%x
\n\t
SMB session status: %d
\t
"
,
i
,
ses
->
serverName
,
ses
->
serverDomain
,
atomic_read
(
&
ses
->
inUse
),
ses
->
serverOS
,
ses
->
serverNOS
,
...
...
@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf
+=
length
;
}
if
(
ses
->
server
)
{
buf
+=
sprintf
(
buf
,
"TCP status: %d
\n\t
Local Users To Server: %d SecMode: 0x%x Req
Activ
e: %d"
,
buf
+=
sprintf
(
buf
,
"TCP status: %d
\n\t
Local Users To Server: %d SecMode: 0x%x Req
On Wir
e: %d"
,
ses
->
server
->
tcpStatus
,
atomic_read
(
&
ses
->
server
->
socketUseCount
),
ses
->
server
->
secMode
,
atomic_read
(
&
ses
->
server
->
inFlight
));
#ifdef CONFIG_CIFS_STATS2
buf
+=
sprintf
(
buf
,
" In Send: %d In MaxReq Wait: %d"
,
atomic_read
(
&
ses
->
server
->
inSend
),
atomic_read
(
&
ses
->
server
->
num_waiters
));
#endif
length
=
sprintf
(
buf
,
"
\n
MIDs:
\n
"
);
buf
+=
length
;
...
...
@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
dev_type
=
le32_to_cpu
(
tcon
->
fsDevInfo
.
DeviceType
);
length
=
sprintf
(
buf
,
"
\n
%d) %s Uses: %d Type: %s
Characteristics
: 0x%x Attributes: 0x%x
\n
PathComponentMax: %d Status: %d"
,
"
\n
%d) %s Uses: %d Type: %s
DevInfo
: 0x%x Attributes: 0x%x
\n
PathComponentMax: %d Status: %d"
,
i
,
tcon
->
treeName
,
atomic_read
(
&
tcon
->
useCount
),
tcon
->
nativeFileSystem
,
...
...
@@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
}
#ifdef CONFIG_CIFS_STATS
static
int
cifs_stats_write
(
struct
file
*
file
,
const
char
__user
*
buffer
,
unsigned
long
count
,
void
*
data
)
{
char
c
;
int
rc
;
struct
list_head
*
tmp
;
struct
cifsTconInfo
*
tcon
;
rc
=
get_user
(
c
,
buffer
);
if
(
rc
)
return
rc
;
if
(
c
==
'1'
||
c
==
'y'
||
c
==
'Y'
||
c
==
'0'
)
{
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
atomic_set
(
&
tcon
->
num_smbs_sent
,
0
);
atomic_set
(
&
tcon
->
num_writes
,
0
);
atomic_set
(
&
tcon
->
num_reads
,
0
);
atomic_set
(
&
tcon
->
num_oplock_brks
,
0
);
atomic_set
(
&
tcon
->
num_opens
,
0
);
atomic_set
(
&
tcon
->
num_closes
,
0
);
atomic_set
(
&
tcon
->
num_deletes
,
0
);
atomic_set
(
&
tcon
->
num_mkdirs
,
0
);
atomic_set
(
&
tcon
->
num_rmdirs
,
0
);
atomic_set
(
&
tcon
->
num_renames
,
0
);
atomic_set
(
&
tcon
->
num_t2renames
,
0
);
atomic_set
(
&
tcon
->
num_ffirst
,
0
);
atomic_set
(
&
tcon
->
num_fnext
,
0
);
atomic_set
(
&
tcon
->
num_fclose
,
0
);
atomic_set
(
&
tcon
->
num_hardlinks
,
0
);
atomic_set
(
&
tcon
->
num_symlinks
,
0
);
atomic_set
(
&
tcon
->
num_locks
,
0
);
}
read_unlock
(
&
GlobalSMBSeslock
);
}
return
count
;
}
static
int
cifs_stats_read
(
char
*
buf
,
char
**
beginBuffer
,
off_t
offset
,
int
count
,
int
*
eof
,
void
*
data
)
...
...
@@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
buf
+=
sprintf
(
buf
,
"
\t
DISCONNECTED "
);
length
+=
14
;
}
item_length
=
sprintf
(
buf
,
"
\n
SMBs: %d Oplock Breaks: %d"
,
item_length
=
sprintf
(
buf
,
"
\n
SMBs: %d Oplock Breaks: %d"
,
atomic_read
(
&
tcon
->
num_smbs_sent
),
atomic_read
(
&
tcon
->
num_oplock_brks
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Reads: %d Bytes
%lld"
,
item_length
=
sprintf
(
buf
,
"
\n
Reads: %d Bytes:
%lld"
,
atomic_read
(
&
tcon
->
num_reads
),
(
long
long
)(
tcon
->
bytes_read
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Writes: %d Bytes: %lld"
,
item_length
=
sprintf
(
buf
,
"
\n
Writes: %d Bytes: %lld"
,
atomic_read
(
&
tcon
->
num_writes
),
(
long
long
)(
tcon
->
bytes_written
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Opens: %d Deletes: %d
\n
Mkdirs: %d Rmdirs: %d"
,
"
\n
Locks: %d HardLinks: %d Symlinks: %d"
,
atomic_read
(
&
tcon
->
num_locks
),
atomic_read
(
&
tcon
->
num_hardlinks
),
atomic_read
(
&
tcon
->
num_symlinks
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Opens: %d Closes: %d Deletes: %d"
,
atomic_read
(
&
tcon
->
num_opens
),
atomic_read
(
&
tcon
->
num_deletes
),
atomic_read
(
&
tcon
->
num_closes
),
atomic_read
(
&
tcon
->
num_deletes
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Mkdirs: %d Rmdirs: %d"
,
atomic_read
(
&
tcon
->
num_mkdirs
),
atomic_read
(
&
tcon
->
num_rmdirs
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Renames: %d T2 Renames %d"
,
item_length
=
sprintf
(
buf
,
"
\n
Renames: %d T2 Renames %d"
,
atomic_read
(
&
tcon
->
num_renames
),
atomic_read
(
&
tcon
->
num_t2renames
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
FindFirst: %d FNext %d FClose %d"
,
atomic_read
(
&
tcon
->
num_ffirst
),
atomic_read
(
&
tcon
->
num_fnext
),
atomic_read
(
&
tcon
->
num_fclose
));
buf
+=
item_length
;
length
+=
item_length
;
}
read_unlock
(
&
GlobalSMBSeslock
);
...
...
@@ -341,8 +408,10 @@ cifs_proc_init(void)
cifs_debug_data_read
,
NULL
);
#ifdef CONFIG_CIFS_STATS
create_proc_read_entry
(
"Stats"
,
0
,
proc_fs_cifs
,
pde
=
create_proc_read_entry
(
"Stats"
,
0
,
proc_fs_cifs
,
cifs_stats_read
,
NULL
);
if
(
pde
)
pde
->
write_proc
=
cifs_stats_write
;
#endif
pde
=
create_proc_read_entry
(
"cifsFYI"
,
0
,
proc_fs_cifs
,
cifsFYI_read
,
NULL
);
...
...
@@ -360,7 +429,7 @@ cifs_proc_init(void)
if
(
pde
)
pde
->
write_proc
=
oplockEnabled_write
;
pde
=
create_proc_read_entry
(
"
ReenableOldCifsReaddirCode
"
,
0
,
proc_fs_cifs
,
pde
=
create_proc_read_entry
(
"
Experimental
"
,
0
,
proc_fs_cifs
,
quotaEnabled_read
,
NULL
);
if
(
pde
)
pde
->
write_proc
=
quotaEnabled_write
;
...
...
@@ -419,7 +488,7 @@ cifs_proc_clean(void)
remove_proc_entry
(
"ExtendedSecurity"
,
proc_fs_cifs
);
remove_proc_entry
(
"PacketSigningEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"LinuxExtensionsEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"
ReenableOldCifsReaddirCode
"
,
proc_fs_cifs
);
remove_proc_entry
(
"
Experimental
"
,
proc_fs_cifs
);
remove_proc_entry
(
"LookupCacheEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"cifs"
,
proc_root_fs
);
}
...
...
@@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer,
cifsFYI
=
0
;
else
if
(
c
==
'1'
||
c
==
'y'
||
c
==
'Y'
)
cifsFYI
=
1
;
else
if
((
c
>
'1'
)
&&
(
c
<=
'9'
))
cifsFYI
=
(
int
)
(
c
-
'0'
);
/* see cifs_debug.h for meanings */
return
count
;
}
...
...
fs/cifs/cifs_debug.h
浏览文件 @
fca324e7
...
...
@@ -26,6 +26,9 @@
void
cifs_dump_mem
(
char
*
label
,
void
*
data
,
int
length
);
extern
int
traceSMB
;
/* flag which enables the function below */
void
dump_smb
(
struct
smb_hdr
*
,
int
);
#define CIFS_INFO 0x01
#define CIFS_RC 0x02
#define CIFS_TIMER 0x04
/*
* debug ON
...
...
@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int);
/* information message: e.g., configuration, major event */
extern
int
cifsFYI
;
#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
#define cifsfyi(format,arg...) if (cifsFYI
& CIFS_INFO
) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
#define cFYI(button,prspec) if (button) cifsfyi prspec
...
...
fs/cifs/cifs_fs_sb.h
浏览文件 @
fca324e7
...
...
@@ -24,6 +24,9 @@
#define CIFS_MOUNT_DIRECT_IO 8
/* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10
/* if set - disable xattr support */
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20
/* remap illegal chars in filenames */
#define CIFS_MOUNT_POSIX_PATHS 0x40
/* Negotiate posix pathnames if possible. */
#define CIFS_MOUNT_UNX_EMUL 0x80
/* Network compat with SFUnix emulation */
#define CIFS_MOUNT_NO_BRL 0x100
/* No sending byte range locks to srv */
struct
cifs_sb_info
{
struct
cifsTconInfo
*
tcon
;
/* primary mount */
...
...
fs/cifs/cifsfs.c
浏览文件 @
fca324e7
...
...
@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0;
unsigned
int
sign_CIFS_PDUs
=
1
;
extern
struct
task_struct
*
oplockThread
;
/* remove sparse warning */
struct
task_struct
*
oplockThread
=
NULL
;
extern
struct
task_struct
*
dnotifyThread
;
/* remove sparse warning */
struct
task_struct
*
dnotifyThread
=
NULL
;
unsigned
int
CIFSMaxBufSize
=
CIFS_MAX_MSGSIZE
;
module_param
(
CIFSMaxBufSize
,
int
,
0
);
MODULE_PARM_DESC
(
CIFSMaxBufSize
,
"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"
);
...
...
@@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC
(
cifs_max_pending
,
"Simultaneous requests to server. Default: 50 Range: 2 to 256"
);
static
DECLARE_COMPLETION
(
cifs_oplock_exited
);
static
DECLARE_COMPLETION
(
cifs_dnotify_exited
);
extern
mempool_t
*
cifs_sm_req_poolp
;
extern
mempool_t
*
cifs_req_poolp
;
...
...
@@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
#endif
/* CIFS_EXPERIMENTAL */
rc
=
CIFSSMBQFSInfo
(
xid
,
pTcon
,
buf
);
/* Old Windows servers do not support level 103, retry with level
one if old server failed the previous call */
if
(
rc
)
rc
=
SMBOldQFSInfo
(
xid
,
pTcon
,
buf
);
/*
int f_type;
__fsid_t f_fsid;
...
...
@@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode
->
clientCanCacheAll
=
FALSE
;
cifs_inode
->
vfs_inode
.
i_blksize
=
CIFS_MAX_MSGSIZE
;
cifs_inode
->
vfs_inode
.
i_blkbits
=
14
;
/* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode
->
vfs_inode
.
i_flags
=
S_NOATIME
|
S_NOCMTIME
;
INIT_LIST_HEAD
(
&
cifs_inode
->
openFileList
);
return
&
cifs_inode
->
vfs_inode
;
}
...
...
@@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = {
};
#endif
static
void
cifs_umount_begin
(
struct
super_block
*
sblock
)
{
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
tcon
;
cifs_sb
=
CIFS_SB
(
sblock
);
if
(
cifs_sb
==
NULL
)
return
;
tcon
=
cifs_sb
->
tcon
;
if
(
tcon
==
NULL
)
return
;
down
(
&
tcon
->
tconSem
);
if
(
atomic_read
(
&
tcon
->
useCount
)
==
1
)
tcon
->
tidStatus
=
CifsExiting
;
up
(
&
tcon
->
tconSem
);
if
(
tcon
->
ses
&&
tcon
->
ses
->
server
)
{
cERROR
(
1
,(
"wake up tasks now - umount begin not complete"
));
wake_up_all
(
&
tcon
->
ses
->
server
->
request_q
);
}
/* BB FIXME - finish add checks for tidStatus BB */
return
;
}
static
int
cifs_remount
(
struct
super_block
*
sb
,
int
*
flags
,
char
*
data
)
{
*
flags
|=
MS_NODIRATIME
;
...
...
@@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = {
unless later we add lazy close of inodes or unless the kernel forgets to call
us with the same number of releases (closes) as opens */
.
show_options
=
cifs_show_options
,
/*
.umount_begin = cifs_umount_begin, *//* consider adding
in the future */
/*
.umount_begin = cifs_umount_begin, */
/* BB finish
in the future */
.
remount_fs
=
cifs_remount
,
};
...
...
@@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg)
do
{
if
(
try_to_freeze
())
continue
;
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
1
*
HZ
);
spin_lock
(
&
GlobalMid_Lock
);
if
(
list_empty
(
&
GlobalOplock_Q
))
{
spin_unlock
(
&
GlobalMid_Lock
);
...
...
@@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg)
}
}
else
spin_unlock
(
&
GlobalMid_Lock
);
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
1
);
/* yield in case q were corrupt */
}
}
while
(
!
signal_pending
(
current
));
complete_and_exit
(
&
cifs_oplock_exited
,
0
);
oplockThread
=
NULL
;
complete_and_exit
(
&
cifs_oplock_exited
,
0
);
}
static
int
cifs_dnotify_thread
(
void
*
dummyarg
)
{
daemonize
(
"cifsdnotifyd"
);
allow_signal
(
SIGTERM
);
dnotifyThread
=
current
;
do
{
if
(
try_to_freeze
())
continue
;
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
39
*
HZ
);
}
while
(
!
signal_pending
(
current
));
complete_and_exit
(
&
cifs_dnotify_exited
,
0
);
}
static
int
__init
...
...
@@ -851,6 +901,10 @@ init_cifs(void)
INIT_LIST_HEAD
(
&
GlobalSMBSessionList
);
INIT_LIST_HEAD
(
&
GlobalTreeConnectionList
);
INIT_LIST_HEAD
(
&
GlobalOplock_Q
);
#ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD
(
&
GlobalDnotifyReqList
);
INIT_LIST_HEAD
(
&
GlobalDnotifyRsp_Q
);
#endif
/*
* Initialize Global counters
*/
...
...
@@ -886,11 +940,17 @@ init_cifs(void)
if
(
!
rc
)
{
rc
=
(
int
)
kernel_thread
(
cifs_oplock_thread
,
NULL
,
CLONE_FS
|
CLONE_FILES
|
CLONE_VM
);
if
(
rc
>
0
)
{
rc
=
(
int
)
kernel_thread
(
cifs_dnotify_thread
,
NULL
,
CLONE_FS
|
CLONE_FILES
|
CLONE_VM
);
if
(
rc
>
0
)
return
0
;
else
cERROR
(
1
,(
"error %d create dnotify thread"
,
rc
));
}
else
{
cERROR
(
1
,(
"error %d create oplock thread"
,
rc
));
}
}
cifs_destroy_request_bufs
();
}
cifs_destroy_mids
();
...
...
@@ -918,6 +978,10 @@ exit_cifs(void)
send_sig
(
SIGTERM
,
oplockThread
,
1
);
wait_for_completion
(
&
cifs_oplock_exited
);
}
if
(
dnotifyThread
)
{
send_sig
(
SIGTERM
,
dnotifyThread
,
1
);
wait_for_completion
(
&
cifs_dnotify_exited
);
}
}
MODULE_AUTHOR
(
"Steve French <sfrench@us.ibm.com>"
);
...
...
fs/cifs/cifsfs.h
浏览文件 @
fca324e7
...
...
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
/* Functions related to dir entries */
extern
struct
dentry_operations
cifs_dentry_ops
;
extern
struct
dentry_operations
cifs_ci_dentry_ops
;
/* Functions related to symlinks */
extern
void
*
cifs_follow_link
(
struct
dentry
*
direntry
,
struct
nameidata
*
nd
);
...
...
@@ -96,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern
ssize_t
cifs_listxattr
(
struct
dentry
*
,
char
*
,
size_t
);
extern
int
cifs_ioctl
(
struct
inode
*
inode
,
struct
file
*
filep
,
unsigned
int
command
,
unsigned
long
arg
);
#define CIFS_VERSION "1.3
5
"
#define CIFS_VERSION "1.3
9
"
#endif
/* _CIFSFS_H */
fs/cifs/cifsglob.h
浏览文件 @
fca324e7
...
...
@@ -110,8 +110,9 @@ enum protocolEnum {
*/
struct
TCP_Server_Info
{
char
server_Name
[
SERVER_NAME_LEN_WITH_NULL
];
/* 15 chars + X'20'in 16th */
char
unicode_server_Name
[
SERVER_NAME_LEN_WITH_NULL
*
2
];
/* Unicode version of server_Name */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char
server_RFC1001_name
[
SERVER_NAME_LEN_WITH_NULL
];
char
unicode_server_Name
[
SERVER_NAME_LEN_WITH_NULL
*
2
];
struct
socket
*
ssocket
;
union
{
struct
sockaddr_in
sockAddr
;
...
...
@@ -129,6 +130,10 @@ struct TCP_Server_Info {
unsigned
svlocal
:
1
;
/* local server or remote */
atomic_t
socketUseCount
;
/* number of open cifs sessions on socket */
atomic_t
inFlight
;
/* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2
atomic_t
inSend
;
/* requests trying to send */
atomic_t
num_waiters
;
/* blocked waiting to get in sendrecv */
#endif
enum
statusEnum
tcpStatus
;
/* what we think the status is */
struct
semaphore
tcpSem
;
struct
task_struct
*
tsk
;
...
...
@@ -147,8 +152,10 @@ struct TCP_Server_Info {
/* (returned on Negotiate */
int
capabilities
;
/* allow selective disabling of caps by smb sess */
__u16
timeZone
;
__u16
CurrentMid
;
/* multiplex id - rotating counter */
char
cryptKey
[
CIFS_CRYPTO_KEY_SIZE
];
char
workstation_RFC1001_name
[
16
];
/* 16th byte is always zero */
/* 16th byte of RFC1001 workstation name is always null */
char
workstation_RFC1001_name
[
SERVER_NAME_LEN_WITH_NULL
];
__u32
sequence_number
;
/* needed for CIFS PDU signature */
char
mac_signing_key
[
CIFS_SESSION_KEY_SIZE
+
16
];
};
...
...
@@ -214,19 +221,41 @@ struct cifsTconInfo {
atomic_t
num_reads
;
atomic_t
num_oplock_brks
;
atomic_t
num_opens
;
atomic_t
num_closes
;
atomic_t
num_deletes
;
atomic_t
num_mkdirs
;
atomic_t
num_rmdirs
;
atomic_t
num_renames
;
atomic_t
num_t2renames
;
atomic_t
num_ffirst
;
atomic_t
num_fnext
;
atomic_t
num_fclose
;
atomic_t
num_hardlinks
;
atomic_t
num_symlinks
;
atomic_t
num_locks
;
#ifdef CONFIG_CIFS_STATS2
unsigned
long
long
time_writes
;
unsigned
long
long
time_reads
;
unsigned
long
long
time_opens
;
unsigned
long
long
time_deletes
;
unsigned
long
long
time_closes
;
unsigned
long
long
time_mkdirs
;
unsigned
long
long
time_rmdirs
;
unsigned
long
long
time_renames
;
unsigned
long
long
time_t2renames
;
unsigned
long
long
time_ffirst
;
unsigned
long
long
time_fnext
;
unsigned
long
long
time_fclose
;
#endif
/* CONFIG_CIFS_STATS2 */
__u64
bytes_read
;
__u64
bytes_written
;
spinlock_t
stat_lock
;
#endif
#endif
/* CONFIG_CIFS_STATS */
FILE_SYSTEM_DEVICE_INFO
fsDevInfo
;
FILE_SYSTEM_ATTRIBUTE_INFO
fsAttrInfo
;
/* ok if file system name truncated */
FILE_SYSTEM_UNIX_INFO
fsUnixInfo
;
unsigned
retry
:
1
;
unsigned
nocase
:
1
;
/* BB add field for back pointer to sb struct? */
};
...
...
@@ -270,6 +299,7 @@ struct cifsFileInfo {
struct
inode
*
pInode
;
/* needed for oplock break */
unsigned
closePend
:
1
;
/* file is marked to close */
unsigned
invalidHandle
:
1
;
/* file closed via session abend */
atomic_t
wrtPending
;
/* handle in use - defer close */
struct
semaphore
fh_sem
;
/* prevents reopen race after dead ses*/
char
*
search_resume_name
;
/* BB removeme BB */
unsigned
int
resume_name_length
;
/* BB removeme - field renamed and moved BB */
...
...
@@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb)
return
sb
->
s_fs_info
;
}
static
inline
char
CIFS_DIR_SEP
(
const
struct
cifs_sb_info
*
cifs_sb
)
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_POSIX_PATHS
)
return
'/'
;
else
return
'\\'
;
}
#ifdef CONFIG_CIFS_STATS
#define cifs_stats_inc atomic_inc
static
inline
void
cifs_stats_bytes_written
(
struct
cifsTconInfo
*
tcon
,
unsigned
int
bytes
)
{
if
(
bytes
)
{
spin_lock
(
&
tcon
->
stat_lock
);
tcon
->
bytes_written
+=
bytes
;
spin_unlock
(
&
tcon
->
stat_lock
);
}
}
static
inline
void
cifs_stats_bytes_read
(
struct
cifsTconInfo
*
tcon
,
unsigned
int
bytes
)
{
spin_lock
(
&
tcon
->
stat_lock
);
tcon
->
bytes_read
+=
bytes
;
spin_unlock
(
&
tcon
->
stat_lock
);
}
#else
#define cifs_stats_inc(field) do {} while(0)
#define cifs_stats_bytes_written(tcon, bytes) do {} while(0)
#define cifs_stats_bytes_read(tcon, bytes) do {} while(0)
#endif
/* one of these for every pending CIFS request to the server */
struct
mid_q_entry
{
...
...
@@ -313,7 +378,11 @@ struct mid_q_entry {
__u16
mid
;
/* multiplex id */
__u16
pid
;
/* process id */
__u32
sequence_number
;
/* for CIFS signing */
struct
timeval
when_sent
;
/* time when smb sent */
unsigned
long
when_alloc
;
/* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned
long
when_sent
;
/* time when smb send finished */
unsigned
long
when_received
;
/* when demux complete (taken off wire) */
#endif
struct
cifsSesInfo
*
ses
;
/* smb was sent to this server */
struct
task_struct
*
tsk
;
/* task waiting for response */
struct
smb_hdr
*
resp_buf
;
/* response buffer */
...
...
@@ -331,6 +400,20 @@ struct oplock_q_entry {
__u16
netfid
;
};
/* for pending dnotify requests */
struct
dir_notify_req
{
struct
list_head
lhead
;
__le16
Pid
;
__le16
PidHigh
;
__u16
Mid
;
__u16
Tid
;
__u16
Uid
;
__u16
netfid
;
__u32
filter
;
/* CompletionFilter (for multishot) */
int
multishot
;
struct
file
*
pfile
;
};
#define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2
...
...
@@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN
struct
list_head
GlobalOplock_Q
;
GLOBAL_EXTERN
struct
list_head
GlobalDnotifyReqList
;
/* Outstanding dir notify requests */
GLOBAL_EXTERN
struct
list_head
GlobalDnotifyRsp_Q
;
/* Dir notify response queue */
/*
* Global transaction id (XID) information
*/
...
...
fs/cifs/cifspdu.h
浏览文件 @
fca324e7
此差异已折叠。
点击以展开。
fs/cifs/cifsproto.h
浏览文件 @
fca324e7
...
...
@@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct
smb_hdr
*
/* input */
,
struct
smb_hdr
*
/* out */
,
int
*
/* bytes returned */
,
const
int
long_op
);
extern
int
SendReceive2
(
const
unsigned
int
/* xid */
,
struct
cifsSesInfo
*
,
struct
kvec
*
,
int
/* nvec */
,
int
*
/* bytes returned */
,
const
int
long_op
);
extern
int
checkSMBhdr
(
struct
smb_hdr
*
smb
,
__u16
mid
);
extern
int
checkSMB
(
struct
smb_hdr
*
smb
,
__u16
mid
,
int
length
);
extern
int
is_valid_oplock_break
(
struct
smb_hdr
*
smb
);
extern
int
is_size_safe_to_change
(
struct
cifsInodeInfo
*
);
extern
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
);
extern
unsigned
int
smbCalcSize
(
struct
smb_hdr
*
ptr
);
extern
unsigned
int
smbCalcSize_LE
(
struct
smb_hdr
*
ptr
);
extern
int
decode_negTokenInit
(
unsigned
char
*
security_blob
,
int
length
,
enum
securityEnum
*
secType
);
extern
int
cifs_inet_pton
(
int
,
char
*
source
,
void
*
dst
);
extern
int
map_smb_to_linux_error
(
struct
smb_hdr
*
smb
);
extern
void
header_assemble
(
struct
smb_hdr
*
,
char
/* command */
,
const
struct
cifsTconInfo
*
,
int
/* specifies length
of fixed section (word count) in two byte units */
);
const
struct
cifsTconInfo
*
,
int
/* length of
fixed section (word count) in two byte units */
);
extern
__u16
GetNextMid
(
struct
TCP_Server_Info
*
server
);
extern
struct
oplock_q_entry
*
AllocOplockQEntry
(
struct
inode
*
,
u16
,
struct
cifsTconInfo
*
);
extern
void
DeleteOplockQEntry
(
struct
oplock_q_entry
*
);
...
...
@@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
extern
int
CIFSFindFirst
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
searchName
,
const
struct
nls_table
*
nls_codepage
,
__u16
*
searchHandle
,
struct
cifs_search_info
*
psrch_inf
,
int
map
);
__u16
*
searchHandle
,
struct
cifs_search_info
*
psrch_inf
,
int
map
,
const
char
dirsep
);
extern
int
CIFSFindNext
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
__u16
searchHandle
,
struct
cifs_search_info
*
psrch_inf
);
...
...
@@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const
unsigned
char
*
searchName
,
FILE_ALL_INFO
*
findData
,
const
struct
nls_table
*
nls_codepage
,
int
remap
);
extern
int
SMBQueryInformation
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
FILE_ALL_INFO
*
findData
,
const
struct
nls_table
*
nls_codepage
,
int
remap
);
extern
int
CIFSSMBUnixQPathInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
...
...
@@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
int
remap
);
extern
int
CIFSSMBQFSInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
struct
kstatfs
*
FSData
);
extern
int
SMBOldQFSInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
struct
kstatfs
*
FSData
);
extern
int
CIFSSMBSetFSUnixInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
__u64
cap
);
extern
int
CIFSSMBQFSAttributeInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
);
extern
int
CIFSSMBQFSDeviceInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
);
...
...
@@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const
int
access_flags
,
const
int
omode
,
__u16
*
netfid
,
int
*
pOplock
,
FILE_ALL_INFO
*
,
const
struct
nls_table
*
nls_codepage
,
int
remap
);
extern
int
SMBLegacyOpen
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
fileName
,
const
int
disposition
,
const
int
access_flags
,
const
int
omode
,
__u16
*
netfid
,
int
*
pOplock
,
FILE_ALL_INFO
*
,
const
struct
nls_table
*
nls_codepage
,
int
remap
);
extern
int
CIFSSMBClose
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
smb_file_id
);
...
...
@@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
extern
int
CIFSSMBWrite2
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
netfid
,
const
unsigned
int
count
,
const
__u64
offset
,
unsigned
int
*
nbytes
,
const
char
__user
*
buf
,
const
int
long_op
);
struct
kvec
*
iov
,
const
int
nvec
,
const
int
long_op
);
extern
int
CIFSGetSrvInodeNumber
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
__u64
*
inode_number
,
const
struct
nls_table
*
nls_codepage
,
...
...
@@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid,
int
remap_special_chars
);
extern
int
CIFSSMBNotify
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
notify_subdirs
,
const
__u16
netfid
,
__u32
filter
,
const
struct
nls_table
*
nls_codepage
);
__u32
filter
,
struct
file
*
file
,
int
multishot
,
const
struct
nls_table
*
nls_codepage
);
extern
ssize_t
CIFSSMBQAllEAs
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
char
*
EAData
,
size_t
bufsize
,
const
struct
nls_table
*
nls_codepage
,
...
...
fs/cifs/cifssmb.c
浏览文件 @
fca324e7
此差异已折叠。
点击以展开。
fs/cifs/connect.c
浏览文件 @
fca324e7
...
...
@@ -29,6 +29,8 @@
#include <linux/utsname.h>
#include <linux/mempool.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/pagevec.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include "cifspdu.h"
...
...
@@ -44,6 +46,8 @@
#define CIFS_PORT 445
#define RFC1001_PORT 139
static
DECLARE_COMPLETION
(
cifsd_complete
);
extern
void
SMBencrypt
(
unsigned
char
*
passwd
,
unsigned
char
*
c8
,
unsigned
char
*
p24
);
extern
void
SMBNTencrypt
(
unsigned
char
*
passwd
,
unsigned
char
*
c8
,
...
...
@@ -60,6 +64,7 @@ struct smb_vol {
char
*
in6_addr
;
/* ipv6 address as human readable form of in6_addr */
char
*
iocharset
;
/* local code page for mapping to and from Unicode */
char
source_rfc1001_name
[
16
];
/* netbios name of client */
char
target_rfc1001_name
[
16
];
/* netbios name of server for Win9x/ME */
uid_t
linux_uid
;
gid_t
linux_gid
;
mode_t
file_mode
;
...
...
@@ -74,6 +79,10 @@ struct smb_vol {
unsigned
server_ino
:
1
;
/* use inode numbers from server ie UniqueId */
unsigned
direct_io
:
1
;
unsigned
remap
:
1
;
/* set to remap seven reserved chars in filenames */
unsigned
posix_paths
:
1
;
/* unset to not ask for posix pathnames. */
unsigned
sfu_emul
:
1
;
unsigned
nocase
;
/* request case insensitive filenames */
unsigned
nobrl
;
/* disable sending byte range locks to srv */
unsigned
int
rsize
;
unsigned
int
wsize
;
unsigned
int
sockopt
;
...
...
@@ -82,7 +91,8 @@ struct smb_vol {
static
int
ipv4_connect
(
struct
sockaddr_in
*
psin_server
,
struct
socket
**
csocket
,
char
*
netb_name
);
char
*
netb_name
,
char
*
server_netb_name
);
static
int
ipv6_connect
(
struct
sockaddr_in6
*
psin_server
,
struct
socket
**
csocket
);
...
...
@@ -175,9 +185,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
else
{
rc
=
ipv4_connect
(
&
server
->
addr
.
sockAddr
,
&
server
->
ssocket
,
server
->
workstation_RFC1001_name
);
server
->
workstation_RFC1001_name
,
server
->
server_RFC1001_name
);
}
if
(
rc
)
{
cFYI
(
1
,(
"reconnect error %d"
,
rc
));
msleep
(
3000
);
}
else
{
atomic_inc
(
&
tcpSesReconnectCount
);
...
...
@@ -293,12 +305,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
byte_count
+=
total_in_buf2
;
BCC_LE
(
pTargetSMB
)
=
cpu_to_le16
(
byte_count
);
byte_count
=
be32_to_cpu
(
pTargetSMB
->
smb_buf_length
)
;
byte_count
=
pTargetSMB
->
smb_buf_length
;
byte_count
+=
total_in_buf2
;
/* BB also add check that we are not beyond maximum buffer size */
pTargetSMB
->
smb_buf_length
=
cpu_to_be32
(
byte_count
)
;
pTargetSMB
->
smb_buf_length
=
byte_count
;
if
(
remaining
==
total_in_buf2
)
{
cFYI
(
1
,(
"found the last secondary response"
));
...
...
@@ -323,7 +335,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
struct
cifsSesInfo
*
ses
;
struct
task_struct
*
task_to_wake
=
NULL
;
struct
mid_q_entry
*
mid_entry
;
char
*
temp
;
char
temp
;
int
isLargeBuf
=
FALSE
;
int
isMultiRsp
;
int
reconnect
;
...
...
@@ -337,6 +349,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
atomic_inc
(
&
tcpSesAllocCount
);
length
=
tcpSesAllocCount
.
counter
;
write_unlock
(
&
GlobalSMBSeslock
);
complete
(
&
cifsd_complete
);
if
(
length
>
1
)
{
mempool_resize
(
cifs_req_poolp
,
length
+
cifs_min_rcv
,
...
...
@@ -424,22 +437,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
continue
;
}
/* the right amount was read from socket - 4 bytes */
/* The right amount was read from socket - 4 bytes */
/* so we can now interpret the length field */
/* the first byte big endian of the length field,
is actually not part of the length but the type
with the most common, zero, as regular data */
temp
=
*
((
char
*
)
smb_buffer
);
/* Note that FC 1001 length is big endian on the wire,
but we convert it here so it is always manipulated
as host byte order */
pdu_length
=
ntohl
(
smb_buffer
->
smb_buf_length
);
cFYI
(
1
,(
"rfc1002 length(big endian)0x%x)"
,
pdu_length
+
4
));
smb_buffer
->
smb_buf_length
=
pdu_length
;
cFYI
(
1
,(
"rfc1002 length 0x%x)"
,
pdu_length
+
4
));
temp
=
(
char
*
)
smb_buffer
;
if
(
temp
[
0
]
==
(
char
)
RFC1002_SESSION_KEEP_ALIVE
)
{
if
(
temp
==
(
char
)
RFC1002_SESSION_KEEP_ALIVE
)
{
continue
;
}
else
if
(
temp
[
0
]
==
(
char
)
RFC1002_POSITIVE_SESSION_RESPONSE
)
{
}
else
if
(
temp
==
(
char
)
RFC1002_POSITIVE_SESSION_RESPONSE
)
{
cFYI
(
1
,(
"Good RFC 1002 session rsp"
));
continue
;
}
else
if
(
temp
[
0
]
==
(
char
)
RFC1002_NEGATIVE_SESSION_RESPONSE
)
{
}
else
if
(
temp
==
(
char
)
RFC1002_NEGATIVE_SESSION_RESPONSE
)
{
/* we get this from Windows 98 instead of
an error on SMB negprot response */
cFYI
(
1
,(
"Negative RFC1002 Session Response Error 0x%x)"
,
temp
[
4
]
));
pdu_length
));
if
(
server
->
tcpStatus
==
CifsNew
)
{
/* if nack on negprot (rather than
ret of smb negprot error) reconnecting
...
...
@@ -461,9 +484,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
wake_up
(
&
server
->
response_q
);
continue
;
}
}
else
if
(
temp
[
0
]
!=
(
char
)
0
)
{
}
else
if
(
temp
!=
(
char
)
0
)
{
cERROR
(
1
,(
"Unknown RFC 1002 frame"
));
cifs_dump_mem
(
" Received Data: "
,
temp
,
length
);
cifs_dump_mem
(
" Received Data: "
,
(
char
*
)
smb_buffer
,
length
);
cifs_reconnect
(
server
);
csocket
=
server
->
ssocket
;
continue
;
...
...
@@ -533,7 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
dump_smb
(
smb_buffer
,
length
);
if
(
checkSMB
(
smb_buffer
,
smb_buffer
->
Mid
,
total_read
+
4
))
{
c
ERROR
(
1
,
(
"Bad SMB Received "
)
);
c
ifs_dump_mem
(
"Bad SMB: "
,
smb_buffer
,
48
);
continue
;
}
...
...
@@ -581,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
multi_t2_fnd:
task_to_wake
=
mid_entry
->
tsk
;
mid_entry
->
midState
=
MID_RESPONSE_RECEIVED
;
#ifdef CONFIG_CIFS_STATS2
mid_entry
->
when_received
=
jiffies
;
#endif
break
;
}
}
...
...
@@ -598,7 +625,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
else
if
((
is_valid_oplock_break
(
smb_buffer
)
==
FALSE
)
&&
(
isMultiRsp
==
FALSE
))
{
cERROR
(
1
,
(
"No task to wake, unknown frame rcvd!"
));
cifs_dump_mem
(
"Received Data is: "
,
temp
,
sizeof
(
struct
smb_hdr
));
cifs_dump_mem
(
"Received Data is: "
,(
char
*
)
smb_buffer
,
sizeof
(
struct
smb_hdr
));
}
}
/* end while !EXITING */
...
...
@@ -676,7 +704,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
msleep
(
125
);
}
if
(
list_empty
(
&
server
->
pending_mid_q
))
{
if
(
!
list_empty
(
&
server
->
pending_mid_q
))
{
/* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */
/* due to delays on oplock break requests, we need
...
...
@@ -713,7 +741,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
GFP_KERNEL
);
}
msleep
(
25
0
);
complete_and_exit
(
&
cifsd_complete
,
0
);
return
0
;
}
...
...
@@ -737,7 +765,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
toupper
(
system_utsname
.
nodename
[
i
]);
}
vol
->
source_rfc1001_name
[
15
]
=
0
;
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol
->
target_rfc1001_name
[
0
]
=
0
;
vol
->
linux_uid
=
current
->
uid
;
/* current->euid instead? */
vol
->
linux_gid
=
current
->
gid
;
vol
->
dir_mode
=
S_IRWXUGO
;
...
...
@@ -747,6 +777,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol
->
rw
=
TRUE
;
/* default is always to request posix paths. */
vol
->
posix_paths
=
1
;
if
(
!
options
)
return
1
;
...
...
@@ -987,7 +1020,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* The string has 16th byte zero still from
set at top of the function */
if
((
i
==
15
)
&&
(
value
[
i
]
!=
0
))
printk
(
KERN_WARNING
"CIFS: netbiosname longer than 15 and was truncated.
\n
"
);
printk
(
KERN_WARNING
"CIFS: netbiosname longer than 15 truncated.
\n
"
);
}
}
else
if
(
strnicmp
(
data
,
"servern"
,
7
)
==
0
)
{
/* servernetbiosname specified override *SMBSERVER */
if
(
!
value
||
!*
value
||
(
*
value
==
' '
))
{
cFYI
(
1
,(
"empty server netbiosname specified"
));
}
else
{
/* last byte, type, is 0x20 for servr type */
memset
(
vol
->
target_rfc1001_name
,
0x20
,
16
);
for
(
i
=
0
;
i
<
15
;
i
++
)
{
/* BB are there cases in which a comma can be
valid in this workstation netbios name (and need
special handling)? */
/* user or mount helper must uppercase netbiosname */
if
(
value
[
i
]
==
0
)
break
;
else
vol
->
target_rfc1001_name
[
i
]
=
value
[
i
];
}
/* The string has 16th byte zero still from
set at top of the function */
if
((
i
==
15
)
&&
(
value
[
i
]
!=
0
))
printk
(
KERN_WARNING
"CIFS: server netbiosname longer than 15 truncated.
\n
"
);
}
}
else
if
(
strnicmp
(
data
,
"credentials"
,
4
)
==
0
)
{
/* ignore */
...
...
@@ -1025,6 +1082,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol
->
remap
=
1
;
}
else
if
(
strnicmp
(
data
,
"nomapchars"
,
10
)
==
0
)
{
vol
->
remap
=
0
;
}
else
if
(
strnicmp
(
data
,
"sfu"
,
3
)
==
0
)
{
vol
->
sfu_emul
=
1
;
}
else
if
(
strnicmp
(
data
,
"nosfu"
,
5
)
==
0
)
{
vol
->
sfu_emul
=
0
;
}
else
if
(
strnicmp
(
data
,
"posixpaths"
,
10
)
==
0
)
{
vol
->
posix_paths
=
1
;
}
else
if
(
strnicmp
(
data
,
"noposixpaths"
,
12
)
==
0
)
{
vol
->
posix_paths
=
0
;
}
else
if
((
strnicmp
(
data
,
"nocase"
,
6
)
==
0
)
||
(
strnicmp
(
data
,
"ignorecase"
,
10
)
==
0
))
{
vol
->
nocase
=
1
;
}
else
if
(
strnicmp
(
data
,
"brl"
,
3
)
==
0
)
{
vol
->
nobrl
=
0
;
}
else
if
((
strnicmp
(
data
,
"nobrl"
,
5
)
==
0
)
||
(
strnicmp
(
data
,
"nolock"
,
6
)
==
0
))
{
vol
->
nobrl
=
1
;
/* turn off mandatory locking in mode
if remote locking is turned off since the
local vfs will do advisory */
if
(
vol
->
file_mode
==
(
S_IALLUGO
&
~
(
S_ISUID
|
S_IXGRP
)))
vol
->
file_mode
=
S_IALLUGO
;
}
else
if
(
strnicmp
(
data
,
"setuids"
,
7
)
==
0
)
{
vol
->
setuids
=
1
;
}
else
if
(
strnicmp
(
data
,
"nosetuids"
,
9
)
==
0
)
{
...
...
@@ -1244,7 +1322,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
static
int
ipv4_connect
(
struct
sockaddr_in
*
psin_server
,
struct
socket
**
csocket
,
char
*
netbios
_name
)
char
*
netbios_name
,
char
*
target
_name
)
{
int
rc
=
0
;
int
connected
=
0
;
...
...
@@ -1309,10 +1387,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
/* Eventually check for other socket options to change from
the default. sock_setsockopt not used because it expects
user space buffer */
cFYI
(
1
,(
"sndbuf %d rcvbuf %d rcvtimeo 0x%lx"
,(
*
csocket
)
->
sk
->
sk_sndbuf
,
(
*
csocket
)
->
sk
->
sk_rcvbuf
,
(
*
csocket
)
->
sk
->
sk_rcvtimeo
));
(
*
csocket
)
->
sk
->
sk_rcvtimeo
=
7
*
HZ
;
/* make the bufsizes depend on wsize/rsize and max requests */
if
((
*
csocket
)
->
sk
->
sk_sndbuf
<
(
200
*
1024
))
(
*
csocket
)
->
sk
->
sk_sndbuf
=
200
*
1024
;
if
((
*
csocket
)
->
sk
->
sk_rcvbuf
<
(
140
*
1024
))
(
*
csocket
)
->
sk
->
sk_rcvbuf
=
140
*
1024
;
/* send RFC1001 sessinit */
if
(
psin_server
->
sin_port
==
htons
(
RFC1001_PORT
))
{
/* some servers require RFC1001 sessinit before sending
negprot - BB check reconnection in case where second
...
...
@@ -1322,8 +1406,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
ses_init_buf
=
kzalloc
(
sizeof
(
struct
rfc1002_session_packet
),
GFP_KERNEL
);
if
(
ses_init_buf
)
{
ses_init_buf
->
trailer
.
session_req
.
called_len
=
32
;
if
(
target_name
&&
(
target_name
[
0
]
!=
0
))
{
rfc1002mangle
(
ses_init_buf
->
trailer
.
session_req
.
called_name
,
target_name
,
16
);
}
else
{
rfc1002mangle
(
ses_init_buf
->
trailer
.
session_req
.
called_name
,
DEFAULT_CIFS_CALLED_NAME
,
16
);
}
ses_init_buf
->
trailer
.
session_req
.
calling_len
=
32
;
/* calling name ends in null (byte 16) from old smb
convention. */
...
...
@@ -1556,7 +1646,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
sin_server
.
sin_port
=
htons
(
volume_info
.
port
);
else
sin_server
.
sin_port
=
0
;
rc
=
ipv4_connect
(
&
sin_server
,
&
csocket
,
volume_info
.
source_rfc1001_name
);
rc
=
ipv4_connect
(
&
sin_server
,
&
csocket
,
volume_info
.
source_rfc1001_name
,
volume_info
.
target_rfc1001_name
);
if
(
rc
<
0
)
{
cERROR
(
1
,
(
"Error connecting to IPv4 socket. Aborting operation"
));
...
...
@@ -1606,9 +1698,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
kfree
(
volume_info
.
password
);
FreeXid
(
xid
);
return
rc
;
}
else
}
wait_for_completion
(
&
cifsd_complete
);
rc
=
0
;
memcpy
(
srvTcp
->
workstation_RFC1001_name
,
volume_info
.
source_rfc1001_name
,
16
);
memcpy
(
srvTcp
->
server_RFC1001_name
,
volume_info
.
target_rfc1001_name
,
16
);
srvTcp
->
sequence_number
=
0
;
}
}
...
...
@@ -1653,17 +1747,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* search for existing tcon to this server share */
if
(
!
rc
)
{
if
((
volume_info
.
rsize
)
&&
(
volume_info
.
rsize
<=
CIFSMaxBufSize
))
if
(
volume_info
.
rsize
>
CIFSMaxBufSize
)
{
cERROR
(
1
,(
"rsize %d too large, using MaxBufSize"
,
volume_info
.
rsize
));
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
}
else
if
((
volume_info
.
rsize
)
&&
(
volume_info
.
rsize
<=
CIFSMaxBufSize
))
cifs_sb
->
rsize
=
volume_info
.
rsize
;
else
cifs_sb
->
rsize
=
srvTcp
->
maxBuf
-
MAX_CIFS_HDR_SIZE
;
/* default */
if
((
volume_info
.
wsize
)
&&
(
volume_info
.
wsize
<=
CIFSMaxBufSize
))
else
/* default */
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
if
(
volume_info
.
wsize
>
PAGEVEC_SIZE
*
PAGE_CACHE_SIZE
)
{
cERROR
(
1
,(
"wsize %d too large using 4096 instead"
,
volume_info
.
wsize
));
cifs_sb
->
wsize
=
4096
;
}
else
if
(
volume_info
.
wsize
)
cifs_sb
->
wsize
=
volume_info
.
wsize
;
else
cifs_sb
->
wsize
=
CIFSMaxBufSize
;
/* default */
if
(
cifs_sb
->
rsize
<
PAGE_CACHE_SIZE
)
{
cifs_sb
->
rsize
=
PAGE_CACHE_SIZE
;
cERROR
(
1
,(
"Attempt to set readsize for mount to less than one page (4096)"
));
/* Windows ME does this */
cFYI
(
1
,(
"Attempt to set readsize for mount to less than one page (4096)"
));
}
cifs_sb
->
mnt_uid
=
volume_info
.
linux_uid
;
cifs_sb
->
mnt_gid
=
volume_info
.
linux_gid
;
...
...
@@ -1681,8 +1785,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_MAP_SPECIAL_CHR
;
if
(
volume_info
.
no_xattr
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_XATTR
;
if
(
volume_info
.
sfu_emul
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_UNX_EMUL
;
if
(
volume_info
.
nobrl
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_BRL
;
if
(
volume_info
.
direct_io
)
{
c
ERROR
(
1
,(
"mounting share using direct i/o"
));
c
FYI
(
1
,(
"mounting share using direct i/o"
));
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DIRECT_IO
;
}
...
...
@@ -1696,6 +1805,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
to the same server share the last value passed in
for the retry flag is used */
tcon
->
retry
=
volume_info
.
retry
;
tcon
->
nocase
=
volume_info
.
nocase
;
}
else
{
tcon
=
tconInfoAlloc
();
if
(
tcon
==
NULL
)
...
...
@@ -1724,6 +1834,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if
(
!
rc
)
{
atomic_inc
(
&
pSesInfo
->
inUse
);
tcon
->
retry
=
volume_info
.
retry
;
tcon
->
nocase
=
volume_info
.
nocase
;
}
}
}
...
...
@@ -1745,8 +1856,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
spin_lock
(
&
GlobalMid_Lock
);
srvTcp
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
if
(
srvTcp
->
tsk
)
if
(
srvTcp
->
tsk
)
{
send_sig
(
SIGKILL
,
srvTcp
->
tsk
,
1
);
wait_for_completion
(
&
cifsd_complete
);
}
}
/* If find_unc succeeded then rc == 0 so we can not end */
if
(
tcon
)
/* up accidently freeing someone elses tcon struct */
...
...
@@ -1759,8 +1872,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
temp_rc
=
CIFSSMBLogoff
(
xid
,
pSesInfo
);
/* if the socketUseCount is now zero */
if
((
temp_rc
==
-
ESHUTDOWN
)
&&
(
pSesInfo
->
server
->
tsk
))
(
pSesInfo
->
server
->
tsk
))
{
send_sig
(
SIGKILL
,
pSesInfo
->
server
->
tsk
,
1
);
wait_for_completion
(
&
cifsd_complete
);
}
}
else
cFYI
(
1
,
(
"No session or bad tcon"
));
sesInfoFree
(
pSesInfo
);
...
...
@@ -1783,8 +1898,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cFYI
(
1
,(
"server negotiated posix acl support"
));
sb
->
s_flags
|=
MS_POSIXACL
;
}
/* Try and negotiate POSIX pathnames if we can. */
if
(
volume_info
.
posix_paths
&&
(
CIFS_UNIX_POSIX_PATHNAMES_CAP
&
le64_to_cpu
(
tcon
->
fsUnixInfo
.
Capability
)))
{
if
(
!
CIFSSMBSetFSUnixInfo
(
xid
,
tcon
,
CIFS_UNIX_POSIX_PATHNAMES_CAP
))
{
cFYI
(
1
,(
"negotiated posix pathnames support"
));
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_POSIX_PATHS
;
}
else
{
cFYI
(
1
,(
"posix pathnames support requested but not supported"
));
}
}
}
}
if
(
!
(
tcon
->
ses
->
capabilities
&
CAP_LARGE_WRITE_X
))
cifs_sb
->
wsize
=
min
(
cifs_sb
->
wsize
,
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
if
(
!
(
tcon
->
ses
->
capabilities
&
CAP_LARGE_READ_X
))
cifs_sb
->
rsize
=
min
(
cifs_sb
->
rsize
,
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
}
/* volume_info.password is freed above when existing session found
...
...
@@ -1832,6 +1966,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
header_assemble
(
smb_buffer
,
SMB_COM_SESSION_SETUP_ANDX
,
NULL
/* no tCon exists yet */
,
13
/* wct */
);
smb_buffer
->
Mid
=
GetNextMid
(
ses
->
server
);
pSMB
->
req_no_secext
.
AndXCommand
=
0xFF
;
pSMB
->
req_no_secext
.
MaxBufferSize
=
cpu_to_le16
(
ses
->
server
->
maxBuf
);
pSMB
->
req_no_secext
.
MaxMpxCount
=
cpu_to_le16
(
ses
->
server
->
maxReq
);
...
...
@@ -2107,6 +2242,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* send SMBsessionSetup here */
header_assemble
(
smb_buffer
,
SMB_COM_SESSION_SETUP_ANDX
,
NULL
/* no tCon exists yet */
,
12
/* wct */
);
smb_buffer
->
Mid
=
GetNextMid
(
ses
->
server
);
pSMB
->
req
.
hdr
.
Flags2
|=
SMBFLG2_EXT_SEC
;
pSMB
->
req
.
AndXCommand
=
0xFF
;
pSMB
->
req
.
MaxBufferSize
=
cpu_to_le16
(
ses
->
server
->
maxBuf
);
...
...
@@ -2373,6 +2510,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
/* send SMBsessionSetup here */
header_assemble
(
smb_buffer
,
SMB_COM_SESSION_SETUP_ANDX
,
NULL
/* no tCon exists yet */
,
12
/* wct */
);
smb_buffer
->
Mid
=
GetNextMid
(
ses
->
server
);
pSMB
->
req
.
hdr
.
Flags2
|=
SMBFLG2_EXT_SEC
;
pSMB
->
req
.
hdr
.
Flags
|=
(
SMBFLG_CASELESS
|
SMBFLG_CANONICAL_PATH_FORMAT
);
...
...
@@ -2715,6 +2854,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* send SMBsessionSetup here */
header_assemble
(
smb_buffer
,
SMB_COM_SESSION_SETUP_ANDX
,
NULL
/* no tCon exists yet */
,
12
/* wct */
);
smb_buffer
->
Mid
=
GetNextMid
(
ses
->
server
);
pSMB
->
req
.
hdr
.
Flags
|=
(
SMBFLG_CASELESS
|
SMBFLG_CANONICAL_PATH_FORMAT
);
pSMB
->
req
.
hdr
.
Flags2
|=
SMBFLG2_EXT_SEC
;
pSMB
->
req
.
AndXCommand
=
0xFF
;
...
...
@@ -3086,6 +3227,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
header_assemble
(
smb_buffer
,
SMB_COM_TREE_CONNECT_ANDX
,
NULL
/*no tid */
,
4
/*wct */
);
smb_buffer
->
Mid
=
GetNextMid
(
ses
->
server
);
smb_buffer
->
Uid
=
ses
->
Suid
;
pSMB
=
(
TCONX_REQ
*
)
smb_buffer
;
pSMBr
=
(
TCONX_RSP
*
)
smb_buffer_response
;
...
...
@@ -3207,8 +3350,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
return
0
;
}
else
if
(
rc
==
-
ESHUTDOWN
)
{
cFYI
(
1
,(
"Waking up socket by sending it signal"
));
if
(
cifsd_task
)
if
(
cifsd_task
)
{
send_sig
(
SIGKILL
,
cifsd_task
,
1
);
wait_for_completion
(
&
cifsd_complete
);
}
rc
=
0
;
}
/* else - we have an smb session
left on this socket do not kill cifsd */
...
...
fs/cifs/dir.c
浏览文件 @
fca324e7
...
...
@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry)
struct
dentry
*
temp
;
int
namelen
=
0
;
char
*
full_path
;
char
dirsep
=
CIFS_DIR_SEP
(
CIFS_SB
(
direntry
->
d_sb
));
if
(
direntry
==
NULL
)
return
NULL
;
/* not much we can do if dentry is freed and
...
...
@@ -74,7 +75,7 @@ build_path_from_dentry(struct dentry *direntry)
if
(
namelen
<
0
)
{
break
;
}
else
{
full_path
[
namelen
]
=
'\\'
;
full_path
[
namelen
]
=
dirsep
;
strncpy
(
full_path
+
namelen
+
1
,
temp
->
d_name
.
name
,
temp
->
d_name
.
len
);
cFYI
(
0
,
(
" name: %s "
,
full_path
+
namelen
));
...
...
@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
desiredAccess
,
CREATE_NOT_DIR
,
&
fileHandle
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
==
-
EIO
)
{
/* old server, retry the open legacy style */
rc
=
SMBLegacyOpen
(
xid
,
pTcon
,
full_path
,
disposition
,
desiredAccess
,
CREATE_NOT_DIR
,
&
fileHandle
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
}
if
(
rc
)
{
cFYI
(
1
,
(
"cifs_create returned 0x%x "
,
rc
));
}
else
{
...
...
@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
CIFS_MOUNT_MAP_SPECIAL_CHR
);
}
else
{
/* BB implement via Windows security descriptors */
/* BB implement
mode setting
via Windows security descriptors */
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
/* could set r/o dos attribute if mode & 0222 == 0 */
}
...
...
@@ -225,9 +233,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
}
if
(
rc
!=
0
)
{
cFYI
(
1
,(
"Create worked but get_inode_info failed with rc = %d"
,
cFYI
(
1
,
(
"Create worked but get_inode_info failed rc = %d"
,
rc
));
}
else
{
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_instantiate
(
direntry
,
newinode
);
}
...
...
@@ -302,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
up
(
&
direntry
->
d_sb
->
s_vfs_rename_sem
);
if
(
full_path
==
NULL
)
rc
=
-
ENOMEM
;
if
(
full_path
&&
(
pTcon
->
ses
->
capabilities
&
CAP_UNIX
))
{
else
if
(
pTcon
->
ses
->
capabilities
&
CAP_UNIX
)
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_SET_UID
)
{
rc
=
CIFSSMBUnixSetPerms
(
xid
,
pTcon
,
full_path
,
mode
,(
__u64
)
current
->
euid
,(
__u64
)
current
->
egid
,
...
...
@@ -321,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
if
(
!
rc
)
{
rc
=
cifs_get_inode_info_unix
(
&
newinode
,
full_path
,
inode
->
i_sb
,
xid
);
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
if
(
rc
==
0
)
d_instantiate
(
direntry
,
newinode
);
}
}
else
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_UNX_EMUL
)
{
int
oplock
=
0
;
u16
fileHandle
;
FILE_ALL_INFO
*
buf
;
cFYI
(
1
,(
"sfu compat create special file"
));
buf
=
kmalloc
(
sizeof
(
FILE_ALL_INFO
),
GFP_KERNEL
);
if
(
buf
==
NULL
)
{
kfree
(
full_path
);
FreeXid
(
xid
);
return
-
ENOMEM
;
}
rc
=
CIFSSMBOpen
(
xid
,
pTcon
,
full_path
,
FILE_CREATE
,
/* fail if exists */
GENERIC_WRITE
/* BB would
WRITE_OWNER | WRITE_DAC be better? */
,
/* Create a file and set the
file attribute to SYSTEM */
CREATE_NOT_DIR
|
CREATE_OPTION_SPECIAL
,
&
fileHandle
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
!
rc
)
{
/* BB Do not bother to decode buf since no
local inode yet to put timestamps in */
CIFSSMBClose
(
xid
,
pTcon
,
fileHandle
);
d_drop
(
direntry
);
}
kfree
(
buf
);
/* add code here to set EAs */
}
}
kfree
(
full_path
);
...
...
@@ -381,6 +431,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
parent_dir_inode
->
i_sb
,
xid
);
if
((
rc
==
0
)
&&
(
newInode
!=
NULL
))
{
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_add
(
direntry
,
newInode
);
...
...
@@ -440,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = {
/* d_delete: cifs_d_delete, *//* not needed except for debugging */
/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
};
static
int
cifs_ci_hash
(
struct
dentry
*
dentry
,
struct
qstr
*
q
)
{
struct
nls_table
*
codepage
=
CIFS_SB
(
dentry
->
d_inode
->
i_sb
)
->
local_nls
;
unsigned
long
hash
;
int
i
;
hash
=
init_name_hash
();
for
(
i
=
0
;
i
<
q
->
len
;
i
++
)
hash
=
partial_name_hash
(
nls_tolower
(
codepage
,
q
->
name
[
i
]),
hash
);
q
->
hash
=
end_name_hash
(
hash
);
return
0
;
}
static
int
cifs_ci_compare
(
struct
dentry
*
dentry
,
struct
qstr
*
a
,
struct
qstr
*
b
)
{
struct
nls_table
*
codepage
=
CIFS_SB
(
dentry
->
d_inode
->
i_sb
)
->
local_nls
;
if
((
a
->
len
==
b
->
len
)
&&
(
nls_strnicmp
(
codepage
,
a
->
name
,
b
->
name
,
a
->
len
)
==
0
))
{
/*
* To preserve case, don't let an existing negative dentry's
* case take precedence. If a is not a negative dentry, this
* should have no side effects
*/
memcpy
((
unsigned
char
*
)
a
->
name
,
b
->
name
,
a
->
len
);
return
0
;
}
return
1
;
}
struct
dentry_operations
cifs_ci_dentry_ops
=
{
.
d_revalidate
=
cifs_d_revalidate
,
.
d_hash
=
cifs_ci_hash
,
.
d_compare
=
cifs_ci_compare
,
};
fs/cifs/fcntl.c
浏览文件 @
fca324e7
...
...
@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
__u32
filter
=
FILE_NOTIFY_CHANGE_NAME
|
FILE_NOTIFY_CHANGE_ATTRIBUTES
;
__u16
netfid
;
if
(
experimEnabled
==
0
)
return
0
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
...
...
@@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
}
else
{
filter
=
convert_to_cifs_notify_flags
(
arg
);
if
(
filter
!=
0
)
{
rc
=
CIFSSMBNotify
(
xid
,
pTcon
,
0
/* no subdirs */
,
netfid
,
filter
,
cifs_sb
->
local_nls
);
rc
=
CIFSSMBNotify
(
xid
,
pTcon
,
0
/* no subdirs */
,
netfid
,
filter
,
file
,
arg
&
DN_MULTISHOT
,
cifs_sb
->
local_nls
);
}
else
{
rc
=
-
EINVAL
;
}
...
...
@@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
it would close automatically but may be a way
to do it easily when inode freed or when
notify info is cleared/changed */
cERROR
(
1
,(
"notify rc %d"
,
rc
));
cFYI
(
1
,(
"notify rc %d"
,
rc
));
}
}
...
...
fs/cifs/file.c
浏览文件 @
fca324e7
...
...
@@ -21,11 +21,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
#include <linux/backing-dev.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/mpage.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/smp_lock.h>
#include <linux/writeback.h>
#include <linux/delay.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
...
...
@@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private(
private_data
->
pInode
=
inode
;
private_data
->
invalidHandle
=
FALSE
;
private_data
->
closePend
=
FALSE
;
/* we have to track num writers to the inode, since writepages
does not tell us which handle the write is for so there can
be a close (overlapping with write) of the filehandle that
cifs_writepages chose to use */
atomic_set
(
&
private_data
->
wrtPending
,
0
);
return
private_data
;
}
...
...
@@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file)
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
==
-
EIO
)
{
/* Old server, try legacy style OpenX */
rc
=
SMBLegacyOpen
(
xid
,
pTcon
,
full_path
,
disposition
,
desiredAccess
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
}
if
(
rc
)
{
cFYI
(
1
,
(
"cifs_open returned 0x%x "
,
rc
));
goto
out
;
...
...
@@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file)
/* no sense reconnecting to close a file that is
already closed */
if
(
pTcon
->
tidStatus
!=
CifsNeedReconnect
)
{
int
timeout
=
2
;
while
((
atomic_read
(
&
pSMBFile
->
wrtPending
)
!=
0
)
&&
(
timeout
<
1000
)
)
{
/* Give write a better chance to get to
server ahead of the close. We do not
want to add a wait_q here as it would
increase the memory utilization as
the struct would be in each open file,
but this should give enough time to
clear the socket */
cERROR
(
1
,(
"close with pending writes"
));
msleep
(
timeout
);
timeout
*=
4
;
}
write_unlock
(
&
file
->
f_owner
.
lock
);
rc
=
CIFSSMBClose
(
xid
,
pTcon
,
pSMBFile
->
netfid
);
...
...
@@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
15 seconds is plenty */
}
#ifdef CONFIG_CIFS_STATS
if
(
total_written
>
0
)
{
atomic_inc
(
&
pTcon
->
num_writes
);
spin_lock
(
&
pTcon
->
stat_lock
);
pTcon
->
bytes_written
+=
total_written
;
spin_unlock
(
&
pTcon
->
stat_lock
);
}
#endif
cifs_stats_bytes_written
(
pTcon
,
total_written
);
/* since the write may have blocked check these pointers again */
if
(
file
->
f_dentry
)
{
...
...
@@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
pTcon
=
cifs_sb
->
tcon
;
/* cFYI(1,
(" write %d bytes to offset %lld of %s", write_size,
*poffset, file->f_dentry->d_name.name)); */
cFYI
(
1
,(
"write %zd bytes to offset %lld of %s"
,
write_size
,
*
poffset
,
file
->
f_dentry
->
d_name
.
name
));
if
(
file
->
private_data
==
NULL
)
return
-
EBADF
;
...
...
@@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
if
(
rc
!=
0
)
break
;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB FIXME We can not sign across two buffers yet */
if
((
experimEnabled
)
&&
((
pTcon
->
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
==
0
))
{
struct
kvec
iov
[
2
];
unsigned
int
len
;
len
=
min
((
size_t
)
cifs_sb
->
wsize
,
write_size
-
total_written
);
/* iov[0] is reserved for smb header */
iov
[
1
].
iov_base
=
(
char
*
)
write_data
+
total_written
;
iov
[
1
].
iov_len
=
len
;
rc
=
CIFSSMBWrite2
(
xid
,
pTcon
,
open_file
->
netfid
,
len
,
*
poffset
,
&
bytes_written
,
iov
,
1
,
long_op
);
}
else
/* BB FIXME fixup indentation of line below */
#endif
rc
=
CIFSSMBWrite
(
xid
,
pTcon
,
open_file
->
netfid
,
min_t
(
const
int
,
cifs_sb
->
wsize
,
...
...
@@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
15 seconds is plenty */
}
#ifdef CONFIG_CIFS_STATS
if
(
total_written
>
0
)
{
atomic_inc
(
&
pTcon
->
num_writes
);
spin_lock
(
&
pTcon
->
stat_lock
);
pTcon
->
bytes_written
+=
total_written
;
spin_unlock
(
&
pTcon
->
stat_lock
);
}
#endif
cifs_stats_bytes_written
(
pTcon
,
total_written
);
/* since the write may have blocked check these pointers again */
if
(
file
->
f_dentry
)
{
...
...
@@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
return
total_written
;
}
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
cifs_inode
)
{
struct
cifsFileInfo
*
open_file
;
int
rc
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each_entry
(
open_file
,
&
cifs_inode
->
openFileList
,
flist
)
{
if
(
open_file
->
closePend
)
continue
;
if
(
open_file
->
pfile
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_WRONLY
)))
{
atomic_inc
(
&
open_file
->
wrtPending
);
read_unlock
(
&
GlobalSMBSeslock
);
if
((
open_file
->
invalidHandle
)
&&
(
!
open_file
->
closePend
)
/* BB fixme -since the second clause can not be true remove it BB */
)
{
rc
=
cifs_reopen_file
(
&
cifs_inode
->
vfs_inode
,
open_file
->
pfile
,
FALSE
);
/* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */
if
(
rc
)
{
cFYI
(
1
,(
"failed on reopen file in wp"
));
read_lock
(
&
GlobalSMBSeslock
);
/* can not use this handle, no write
pending on this one after all */
atomic_dec
(
&
open_file
->
wrtPending
);
continue
;
}
}
return
open_file
;
}
}
read_unlock
(
&
GlobalSMBSeslock
);
return
NULL
;
}
static
int
cifs_partialpagewrite
(
struct
page
*
page
,
unsigned
from
,
unsigned
to
)
{
struct
address_space
*
mapping
=
page
->
mapping
;
...
...
@@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
struct
inode
*
inode
;
struct
cifsInodeInfo
*
cifsInode
;
struct
cifsFileInfo
*
open_file
=
NULL
;
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
;
struct
cifsFileInfo
*
open_file
;
if
(
!
mapping
||
!
mapping
->
host
)
return
-
EFAULT
;
...
...
@@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
if
(
mapping
->
host
->
i_size
-
offset
<
(
loff_t
)
to
)
to
=
(
unsigned
)(
mapping
->
host
->
i_size
-
offset
);
cifsInode
=
CIFS_I
(
mapping
->
host
);
read_lock
(
&
GlobalSMBSeslock
);
/* BB we should start at the end */
list_for_each_safe
(
tmp
,
tmp1
,
&
cifsInode
->
openFileList
)
{
open_file
=
list_entry
(
tmp
,
struct
cifsFileInfo
,
flist
);
if
(
open_file
->
closePend
)
continue
;
/* We check if file is open for writing first */
if
((
open_file
->
pfile
)
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_WRONLY
)))
{
read_unlock
(
&
GlobalSMBSeslock
);
bytes_written
=
cifs_write
(
open_file
->
pfile
,
write_data
,
to
-
from
,
&
offset
);
read_lock
(
&
GlobalSMBSeslock
);
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
));
if
(
open_file
)
{
bytes_written
=
cifs_write
(
open_file
->
pfile
,
write_data
,
to
-
from
,
&
offset
);
atomic_dec
(
&
open_file
->
wrtPending
);
/* Does mm or vfs already set times? */
inode
->
i_atime
=
inode
->
i_mtime
=
current_fs_time
(
inode
->
i_sb
);
inode
->
i_atime
=
inode
->
i_mtime
=
current_fs_time
(
inode
->
i_sb
);
if
((
bytes_written
>
0
)
&&
(
offset
))
{
rc
=
0
;
}
else
if
(
bytes_written
<
0
)
{
if
(
rc
==
-
EBADF
)
{
/* have seen a case in which kernel seemed to
have closed/freed a file even with writes
active so we might as well see if there are
other file structs to try for the same
inode before giving up */
continue
;
}
else
if
(
rc
!=
-
EBADF
)
rc
=
bytes_written
;
}
break
;
/* now that we found a valid file handle and
tried to write to it we are done, no sense
continuing to loop looking for another */
}
if
(
tmp
->
next
==
NULL
)
{
cFYI
(
1
,
(
"File instance %p removed"
,
tmp
));
break
;
}
}
read_unlock
(
&
GlobalSMBSeslock
);
if
(
open_file
==
NULL
)
{
}
else
{
cFYI
(
1
,
(
"No writeable filehandles for inode"
));
rc
=
-
EIO
;
}
...
...
@@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
return
rc
;
}
#if
0
#if
def CONFIG_CIFS_EXPERIMENTAL
static
int
cifs_writepages
(
struct
address_space
*
mapping
,
struct
writeback_control
*
wbc
)
{
int rc = -EFAULT;
struct
backing_dev_info
*
bdi
=
mapping
->
backing_dev_info
;
unsigned
int
bytes_to_write
;
unsigned
int
bytes_written
;
struct
cifs_sb_info
*
cifs_sb
;
int
done
=
0
;
pgoff_t
end
=
-
1
;
pgoff_t
index
;
int
is_range
=
0
;
struct
kvec
iov
[
32
];
int
len
;
int
n_iov
=
0
;
pgoff_t
next
;
int
nr_pages
;
__u64
offset
=
0
;
struct
cifsFileInfo
*
open_file
;
struct
page
*
page
;
struct
pagevec
pvec
;
int
rc
=
0
;
int
scanned
=
0
;
int
xid
;
cifs_sb
=
CIFS_SB
(
mapping
->
host
->
i_sb
);
/*
* If wsize is smaller that the page cache size, default to writing
* one page at a time via cifs_writepage
*/
if
(
cifs_sb
->
wsize
<
PAGE_CACHE_SIZE
)
return
generic_writepages
(
mapping
,
wbc
);
/* BB FIXME we do not have code to sign across multiple buffers yet,
so go to older writepage style write which we can sign if needed */
if
((
cifs_sb
->
tcon
->
ses
)
&&
(
cifs_sb
->
tcon
->
ses
->
server
))
if
(
cifs_sb
->
tcon
->
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
return
generic_writepages
(
mapping
,
wbc
);
/*
* BB: Is this meaningful for a non-block-device file system?
* If it is, we should test it again after we do I/O
*/
if
(
wbc
->
nonblocking
&&
bdi_write_congested
(
bdi
))
{
wbc
->
encountered_congestion
=
1
;
return
0
;
}
xid
=
GetXid
();
/* Find contiguous pages then iterate through repeating
call 16K write then Setpageuptodate or if LARGE_WRITE_X
support then send larger writes via kevec so as to eliminate
a memcpy */
pagevec_init
(
&
pvec
,
0
);
if
(
wbc
->
sync_mode
==
WB_SYNC_NONE
)
index
=
mapping
->
writeback_index
;
/* Start from prev offset */
else
{
index
=
0
;
scanned
=
1
;
}
if
(
wbc
->
start
||
wbc
->
end
)
{
index
=
wbc
->
start
>>
PAGE_CACHE_SHIFT
;
end
=
wbc
->
end
>>
PAGE_CACHE_SHIFT
;
is_range
=
1
;
scanned
=
1
;
}
retry:
while
(
!
done
&&
(
index
<=
end
)
&&
(
nr_pages
=
pagevec_lookup_tag
(
&
pvec
,
mapping
,
&
index
,
PAGECACHE_TAG_DIRTY
,
min
(
end
-
index
,
(
pgoff_t
)
PAGEVEC_SIZE
-
1
)
+
1
)))
{
int
first
;
unsigned
int
i
;
first
=
-
1
;
next
=
0
;
n_iov
=
0
;
bytes_to_write
=
0
;
for
(
i
=
0
;
i
<
nr_pages
;
i
++
)
{
page
=
pvec
.
pages
[
i
];
/*
* At this point we hold neither mapping->tree_lock nor
* lock on the page itself: the page may be truncated or
* invalidated (changing page->mapping to NULL), or even
* swizzled back from swapper_space to tmpfs file
* mapping
*/
if
(
first
<
0
)
lock_page
(
page
);
else
if
(
TestSetPageLocked
(
page
))
break
;
if
(
unlikely
(
page
->
mapping
!=
mapping
))
{
unlock_page
(
page
);
break
;
}
if
(
unlikely
(
is_range
)
&&
(
page
->
index
>
end
))
{
done
=
1
;
unlock_page
(
page
);
break
;
}
if
(
next
&&
(
page
->
index
!=
next
))
{
/* Not next consecutive page */
unlock_page
(
page
);
break
;
}
if
(
wbc
->
sync_mode
!=
WB_SYNC_NONE
)
wait_on_page_writeback
(
page
);
if
(
PageWriteback
(
page
)
||
!
test_clear_page_dirty
(
page
))
{
unlock_page
(
page
);
break
;
}
if
(
page_offset
(
page
)
>=
mapping
->
host
->
i_size
)
{
done
=
1
;
unlock_page
(
page
);
break
;
}
/*
* BB can we get rid of this? pages are held by pvec
*/
page_cache_get
(
page
);
len
=
min
(
mapping
->
host
->
i_size
-
page_offset
(
page
),
(
loff_t
)
PAGE_CACHE_SIZE
);
/* reserve iov[0] for the smb header */
n_iov
++
;
iov
[
n_iov
].
iov_base
=
kmap
(
page
);
iov
[
n_iov
].
iov_len
=
len
;
bytes_to_write
+=
len
;
if
(
first
<
0
)
{
first
=
i
;
offset
=
page_offset
(
page
);
}
next
=
page
->
index
+
1
;
if
(
bytes_to_write
+
PAGE_CACHE_SIZE
>
cifs_sb
->
wsize
)
break
;
}
if
(
n_iov
)
{
/* Search for a writable handle every time we call
* CIFSSMBWrite2. We can't rely on the last handle
* we used to still be valid
*/
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
));
if
(
!
open_file
)
{
cERROR
(
1
,
(
"No writable handles for inode"
));
rc
=
-
EBADF
;
}
else
{
rc
=
CIFSSMBWrite2
(
xid
,
cifs_sb
->
tcon
,
open_file
->
netfid
,
bytes_to_write
,
offset
,
&
bytes_written
,
iov
,
n_iov
,
1
);
atomic_dec
(
&
open_file
->
wrtPending
);
if
(
rc
||
bytes_written
<
bytes_to_write
)
{
cERROR
(
1
,(
"Write2 ret %d, written = %d"
,
rc
,
bytes_written
));
/* BB what if continued retry is
requested via mount flags? */
set_bit
(
AS_EIO
,
&
mapping
->
flags
);
SetPageError
(
page
);
}
else
{
cifs_stats_bytes_written
(
cifs_sb
->
tcon
,
bytes_written
);
}
}
for
(
i
=
0
;
i
<
n_iov
;
i
++
)
{
page
=
pvec
.
pages
[
first
+
i
];
kunmap
(
page
);
unlock_page
(
page
);
page_cache_release
(
page
);
}
if
((
wbc
->
nr_to_write
-=
n_iov
)
<=
0
)
done
=
1
;
index
=
next
;
}
pagevec_release
(
&
pvec
);
}
if
(
!
scanned
&&
!
done
)
{
/*
* We hit the last page and there is more work to be done: wrap
* back to the start of the file
*/
scanned
=
1
;
index
=
0
;
goto
retry
;
}
if
(
!
is_range
)
mapping
->
writeback_index
=
index
;
FreeXid
(
xid
);
return
rc
;
}
#endif
...
...
@@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
if
(
rc
!=
0
)
break
;
}
rc
=
CIFSSMBRead
(
xid
,
pTcon
,
open_file
->
netfid
,
current_read_size
,
*
poffset
,
&
bytes_read
,
&
smb_read_data
);
pSMBr
=
(
struct
smb_com_read_rsp
*
)
smb_read_data
;
if
(
copy_to_user
(
current_offset
,
smb_read_data
+
4
/* RFC1001 hdr */
...
...
@@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
return
rc
;
}
}
else
{
#ifdef CONFIG_CIFS_STATS
atomic_inc
(
&
pTcon
->
num_reads
);
spin_lock
(
&
pTcon
->
stat_lock
);
pTcon
->
bytes_read
+=
total_read
;
spin_unlock
(
&
pTcon
->
stat_lock
);
#endif
cifs_stats_bytes_read
(
pTcon
,
bytes_read
);
*
poffset
+=
bytes_read
;
}
}
...
...
@@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
total_read
+=
bytes_read
,
current_offset
+=
bytes_read
)
{
current_read_size
=
min_t
(
const
int
,
read_size
-
total_read
,
cifs_sb
->
rsize
);
/* For windows me and 9x we do not want to request more
than it negotiated since it will refuse the read then */
if
((
pTcon
->
ses
)
&&
!
(
pTcon
->
ses
->
capabilities
&
CAP_LARGE_FILES
))
{
current_read_size
=
min_t
(
const
int
,
current_read_size
,
pTcon
->
ses
->
server
->
maxBuf
-
128
);
}
rc
=
-
EAGAIN
;
while
(
rc
==
-
EAGAIN
)
{
if
((
open_file
->
invalidHandle
)
&&
...
...
@@ -1289,7 +1515,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if
(
rc
!=
0
)
break
;
}
rc
=
CIFSSMBRead
(
xid
,
pTcon
,
open_file
->
netfid
,
current_read_size
,
*
poffset
,
...
...
@@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return
rc
;
}
}
else
{
#ifdef CONFIG_CIFS_STATS
atomic_inc
(
&
pTcon
->
num_reads
);
spin_lock
(
&
pTcon
->
stat_lock
);
pTcon
->
bytes_read
+=
total_read
;
spin_unlock
(
&
pTcon
->
stat_lock
);
#endif
cifs_stats_bytes_read
(
pTcon
,
total_read
);
*
poffset
+=
bytes_read
;
}
}
...
...
@@ -1455,7 +1675,8 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
open_file
->
netfid
,
read_size
,
offset
,
&
bytes_read
,
&
smb_read_data
);
/* BB need to check return code here */
/* BB more RC checks ? */
if
(
rc
==
-
EAGAIN
)
{
if
(
smb_read_data
)
{
cifs_buf_release
(
smb_read_data
);
...
...
@@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
le16_to_cpu
(
pSMBr
->
DataOffset
),
&
lru_pvec
);
i
+=
bytes_read
>>
PAGE_CACHE_SHIFT
;
#ifdef CONFIG_CIFS_STATS
atomic_inc
(
&
pTcon
->
num_reads
);
spin_lock
(
&
pTcon
->
stat_lock
);
pTcon
->
bytes_read
+=
bytes_read
;
spin_unlock
(
&
pTcon
->
stat_lock
);
#endif
cifs_stats_bytes_read
(
pTcon
,
bytes_read
);
if
((
int
)(
bytes_read
&
PAGE_CACHE_MASK
)
!=
bytes_read
)
{
i
++
;
/* account for partial page */
...
...
@@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page)
page caching in the current Linux kernel design */
int
is_size_safe_to_change
(
struct
cifsInodeInfo
*
cifsInode
)
{
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
;
struct
cifsFileInfo
*
open_file
=
NULL
;
int
rc
=
TRUE
;
if
(
cifsInode
==
NULL
)
return
rc
;
if
(
cifsInode
)
open_file
=
find_writable_file
(
cifsInode
)
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each_safe
(
tmp
,
tmp1
,
&
cifsInode
->
openFileList
)
{
open_file
=
list_entry
(
tmp
,
struct
cifsFileInfo
,
flist
);
if
(
open_file
==
NULL
)
break
;
if
(
open_file
->
closePend
)
continue
;
/* We check if file is open for writing,
BB we could supplement this with a check to see if file size
changes have been flushed to server - ie inode metadata dirty */
if
((
open_file
->
pfile
)
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_WRONLY
)))
{
rc
=
FALSE
;
break
;
}
if
(
tmp
->
next
==
NULL
)
{
cFYI
(
1
,
(
"File instance %p removed"
,
tmp
));
break
;
}
}
read_unlock
(
&
GlobalSMBSeslock
);
return
rc
;
if
(
open_file
)
{
/* there is not actually a write pending so let
this handle go free and allow it to
be closable if needed */
atomic_dec
(
&
open_file
->
wrtPending
);
return
0
;
}
else
return
1
;
}
static
int
cifs_prepare_write
(
struct
file
*
file
,
struct
page
*
page
,
unsigned
from
,
unsigned
to
)
{
...
...
@@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = {
.
readpage
=
cifs_readpage
,
.
readpages
=
cifs_readpages
,
.
writepage
=
cifs_writepage
,
#ifdef CONFIG_CIFS_EXPERIMENTAL
.
writepages
=
cifs_writepages
,
#endif
.
prepare_write
=
cifs_prepare_write
,
.
commit_write
=
cifs_commit_write
,
.
set_page_dirty
=
__set_page_dirty_nobuffers
,
...
...
fs/cifs/inode.c
浏览文件 @
fca324e7
...
...
@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode
->
i_fop
=
&
cifs_file_direct_ops
;
else
inode
->
i_fop
=
&
cifs_file_ops
;
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_NO_BRL
)
inode
->
i_fop
->
lock
=
NULL
;
inode
->
i_data
.
a_ops
=
&
cifs_addr_ops
;
/* check if server can support readpages */
if
(
pTcon
->
ses
->
server
->
maxBuf
<
4096
+
MAX_CIFS_HDR_SIZE
)
inode
->
i_data
.
a_ops
->
readpages
=
NULL
;
}
else
if
(
S_ISDIR
(
inode
->
i_mode
))
{
cFYI
(
1
,
(
" Directory inode"
));
inode
->
i_op
=
&
cifs_dir_inode_ops
;
...
...
@@ -215,6 +221,16 @@ int cifs_get_inode_info(struct inode **pinode,
rc
=
CIFSSMBQPathInfo
(
xid
,
pTcon
,
search_path
,
pfindData
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
/* BB optimize code so we do not make the above call
when server claims no NT SMB support and the above call
failed at least once - set flag in tcon or mount */
if
((
rc
==
-
EOPNOTSUPP
)
||
(
rc
==
-
EINVAL
))
{
rc
=
SMBQueryInformation
(
xid
,
pTcon
,
search_path
,
pfindData
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
}
}
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if
(
rc
)
{
...
...
@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode,
on dirs */
inode
->
i_mode
=
cifs_sb
->
mnt_dir_mode
;
inode
->
i_mode
|=
S_IFDIR
;
}
else
if
((
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_UNX_EMUL
)
&&
(
cifsInfo
->
cifsAttrs
&
ATTR_SYSTEM
)
&&
/* No need to le64 convert size of zero */
(
pfindData
->
EndOfFile
==
0
))
{
inode
->
i_mode
=
cifs_sb
->
mnt_file_mode
;
inode
->
i_mode
|=
S_IFIFO
;
/* BB Finish for SFU style symlinks and devies */
/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
}
else
{
inode
->
i_mode
|=
S_IFREG
;
/* treat the dos attribute of read-only as read-only
...
...
@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode,
inode
->
i_fop
=
&
cifs_file_direct_ops
;
else
inode
->
i_fop
=
&
cifs_file_ops
;
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_NO_BRL
)
inode
->
i_fop
->
lock
=
NULL
;
inode
->
i_data
.
a_ops
=
&
cifs_addr_ops
;
if
(
pTcon
->
ses
->
server
->
maxBuf
<
4096
+
MAX_CIFS_HDR_SIZE
)
inode
->
i_data
.
a_ops
->
readpages
=
NULL
;
}
else
if
(
S_ISDIR
(
inode
->
i_mode
))
{
cFYI
(
1
,
(
" Directory inode "
));
inode
->
i_op
=
&
cifs_dir_inode_ops
;
...
...
@@ -577,6 +608,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
rc
=
cifs_get_inode_info
(
&
newinode
,
full_path
,
NULL
,
inode
->
i_sb
,
xid
);
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_instantiate
(
direntry
,
newinode
);
if
(
direntry
->
d_inode
)
...
...
@@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
int
rc
=
-
EACCES
;
int
found
=
FALSE
;
struct
cifsFileInfo
*
open_file
=
NULL
;
FILE_BASIC_INFO
time_buf
;
int
set_time
=
FALSE
;
...
...
@@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
__u64
uid
=
0xFFFFFFFFFFFFFFFFULL
;
__u64
gid
=
0xFFFFFFFFFFFFFFFFULL
;
struct
cifsInodeInfo
*
cifsInode
;
struct
list_head
*
tmp
;
xid
=
GetXid
();
...
...
@@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
filemap_fdatawait
(
direntry
->
d_inode
->
i_mapping
);
if
(
attrs
->
ia_valid
&
ATTR_SIZE
)
{
read_lock
(
&
GlobalSMBSeslock
);
/* To avoid spurious oplock breaks from server, in the case of
inodes that we already have open, avoid doing path based
setting of file size if we can do it by handle.
...
...
@@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
when the local oplock break takes longer to flush
writebehind data than the SMB timeout for the SetPathInfo
request would allow */
list_for_each
(
tmp
,
&
cifsInode
->
openFileList
)
{
open_file
=
list_entry
(
tmp
,
struct
cifsFileInfo
,
flist
);
/* We check if file is open for writing first */
if
((
open_file
->
pfile
)
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_WRONLY
)))
{
if
(
open_file
->
invalidHandle
==
FALSE
)
{
/* we found a valid, writeable network
file handle to use to try to set the
file size */
open_file
=
find_writable_file
(
cifsInode
);
if
(
open_file
)
{
__u16
nfid
=
open_file
->
netfid
;
__u32
npid
=
open_file
->
pid
;
read_unlock
(
&
GlobalSMBSeslock
);
found
=
TRUE
;
rc
=
CIFSSMBSetFileSize
(
xid
,
pTcon
,
attrs
->
ia_size
,
nfid
,
npid
,
FALSE
);
cFYI
(
1
,
(
"SetFileSize by handle "
"(setattrs) rc = %d"
,
rc
));
/* Do not need reopen and retry on
EAGAIN since we will retry by
pathname below */
/* now that we found one valid file
handle no sense continuing to loop
trying others, so break here */
break
;
}
rc
=
CIFSSMBSetFileSize
(
xid
,
pTcon
,
attrs
->
ia_size
,
nfid
,
npid
,
FALSE
);
atomic_dec
(
&
open_file
->
wrtPending
);
cFYI
(
1
,(
"SetFSize for attrs rc = %d"
,
rc
));
if
(
rc
==
-
EINVAL
)
{
int
bytes_written
;
rc
=
CIFSSMBWrite
(
xid
,
pTcon
,
nfid
,
0
,
attrs
->
ia_size
,
&
bytes_written
,
NULL
,
NULL
,
1
/* 45 seconds */
);
cFYI
(
1
,(
"Wrt seteof rc %d"
,
rc
));
}
}
if
(
found
==
FALSE
)
read_unlock
(
&
GlobalSMBSeslock
);
if
(
rc
!=
0
)
{
/* Set file size by pathname rather than by handle
either because no valid, writeable file handle for
...
...
@@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cFYI
(
1
,
(
" SetEOF by path (setattrs) rc = %d"
,
rc
));
cFYI
(
1
,
(
"SetEOF by path (setattrs) rc = %d"
,
rc
));
if
(
rc
==
-
EINVAL
)
{
__u16
netfid
;
int
oplock
=
FALSE
;
rc
=
SMBLegacyOpen
(
xid
,
pTcon
,
full_path
,
FILE_OPEN
,
SYNCHRONIZE
|
FILE_WRITE_ATTRIBUTES
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
==
0
)
{
int
bytes_written
;
rc
=
CIFSSMBWrite
(
xid
,
pTcon
,
netfid
,
0
,
attrs
->
ia_size
,
&
bytes_written
,
NULL
,
NULL
,
1
/* 45 sec */
);
cFYI
(
1
,(
"wrt seteof rc %d"
,
rc
));
CIFSSMBClose
(
xid
,
pTcon
,
netfid
);
}
}
}
/* Server is ok setting allocation size implicitly - no need
...
...
@@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc
=
vmtruncate
(
direntry
->
d_inode
,
attrs
->
ia_size
);
cifs_truncate_page
(
direntry
->
d_inode
->
i_mapping
,
direntry
->
d_inode
->
i_size
);
}
}
else
goto
cifs_setattr_exit
;
}
if
(
attrs
->
ia_valid
&
ATTR_UID
)
{
cFYI
(
1
,
(
"
CIFS -
UID changed to %d"
,
attrs
->
ia_uid
));
cFYI
(
1
,
(
"UID changed to %d"
,
attrs
->
ia_uid
));
uid
=
attrs
->
ia_uid
;
/* entry->uid = cpu_to_le16(attr->ia_uid); */
}
if
(
attrs
->
ia_valid
&
ATTR_GID
)
{
cFYI
(
1
,
(
"
CIFS -
GID changed to %d"
,
attrs
->
ia_gid
));
cFYI
(
1
,
(
"GID changed to %d"
,
attrs
->
ia_gid
));
gid
=
attrs
->
ia_gid
;
/* entry->gid = cpu_to_le16(attr->ia_gid); */
}
time_buf
.
Attributes
=
0
;
if
(
attrs
->
ia_valid
&
ATTR_MODE
)
{
cFYI
(
1
,
(
"
CIFS -
Mode changed to 0x%x"
,
attrs
->
ia_mode
));
cFYI
(
1
,
(
"Mode changed to 0x%x"
,
attrs
->
ia_mode
));
mode
=
attrs
->
ia_mode
;
/* entry->mode = cpu_to_le16(attr->ia_mode); */
}
if
((
cifs_sb
->
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
...
...
@@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cpu_to_le64
(
cifs_UnixTimeToNT
(
attrs
->
ia_mtime
));
}
else
time_buf
.
LastWriteTime
=
0
;
/* Do not set ctime explicitly unless other time
stamps are changed explicitly (i.e. by utime()
since we would then have a mix of client and
server times */
if
(
attrs
->
ia_valid
&
ATTR_CTIME
)
{
if
(
set_time
&&
(
attrs
->
ia_valid
&
ATTR_CTIME
)
)
{
set_time
=
TRUE
;
cFYI
(
1
,
(
" CIFS - CTIME changed "
));
/* BB probably no need */
/* Although Samba throws this field away
it may be useful to Windows - but we do
not want to set ctime unless some other
timestamp is changing */
cFYI
(
1
,
(
"CIFS - CTIME changed "
));
time_buf
.
ChangeTime
=
cpu_to_le64
(
cifs_UnixTimeToNT
(
attrs
->
ia_ctime
));
}
else
time_buf
.
ChangeTime
=
0
;
if
(
set_time
||
time_buf
.
Attributes
)
{
/* BB what if setting one attribute fails (such as size) but
time setting works? */
time_buf
.
CreationTime
=
0
;
/* do not change */
/* In the future we should experiment - try setting timestamps
via Handle (SetFileInfo) instead of by path */
...
...
@@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
&time_buf, cifs_sb->local_nls); */
}
}
/* Even if error on time set, no sense failing the call if
the server would set the time to a reasonable value anyway,
and this check ensures that we are not being called from
sys_utimes in which case we ought to fail the call back to
the user when the server rejects the call */
if
((
rc
)
&&
(
attrs
->
ia_valid
&&
(
ATTR_MODE
|
ATTR_GID
|
ATTR_UID
|
ATTR_SIZE
)))
rc
=
0
;
}
/* do not need local check to inode_check_ok since the server does
that */
if
(
!
rc
)
rc
=
inode_setattr
(
direntry
->
d_inode
,
attrs
);
cifs_setattr_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
return
rc
;
...
...
fs/cifs/link.c
浏览文件 @
fca324e7
...
...
@@ -198,6 +198,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
(
"Create symlink worked but get_inode_info failed with rc = %d "
,
rc
));
}
else
{
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_instantiate
(
direntry
,
newinode
);
}
...
...
fs/cifs/misc.c
浏览文件 @
fca324e7
...
...
@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp;
extern
mempool_t
*
cifs_req_poolp
;
extern
struct
task_struct
*
oplockThread
;
static
__u16
GlobalMid
;
/* multiplex id - rotating counter */
/* The xid serves as a useful identifier for each incoming vfs request,
in a similar way to the mid which is useful to track each sent smb,
and CurrentXid can also provide a running counter (although it
...
...
@@ -51,6 +49,8 @@ _GetXid(void)
GlobalTotalActiveXid
++
;
if
(
GlobalTotalActiveXid
>
GlobalMaxActiveXid
)
GlobalMaxActiveXid
=
GlobalTotalActiveXid
;
/* keep high water mark for number of simultaneous vfs ops in our filesystem */
if
(
GlobalTotalActiveXid
>
65000
)
cFYI
(
1
,(
"warning: more than 65000 requests active"
));
xid
=
GlobalCurrentXid
++
;
spin_unlock
(
&
GlobalMid_Lock
);
return
xid
;
...
...
@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free)
return
;
}
/*
Find a free multiplex id (SMB mid). Otherwise there could be
mid collisions which might cause problems, demultiplexing the
wrong response to this request. Multiplex ids could collide if
one of a series requests takes much longer than the others, or
if a very large number of long lived requests (byte range
locks or FindNotify requests) are pending. No more than
64K-1 requests can be outstanding at one time. If no
mids are available, return zero. A future optimization
could make the combination of mids and uid the key we use
to demultiplex on (rather than mid alone).
In addition to the above check, the cifs demultiplex
code already used the command code as a secondary
check of the frame and if signing is negotiated the
response would be discarded if the mid were the same
but the signature was wrong. Since the mid is not put in the
pending queue until later (when it is about to be dispatched)
we do have to limit the number of outstanding requests
to somewhat less than 64K-1 although it is hard to imagine
so many threads being in the vfs at one time.
*/
__u16
GetNextMid
(
struct
TCP_Server_Info
*
server
)
{
__u16
mid
=
0
;
__u16
last_mid
;
int
collision
;
if
(
server
==
NULL
)
return
mid
;
spin_lock
(
&
GlobalMid_Lock
);
last_mid
=
server
->
CurrentMid
;
/* we do not want to loop forever */
server
->
CurrentMid
++
;
/* This nested loop looks more expensive than it is.
In practice the list of pending requests is short,
fewer than 50, and the mids are likely to be unique
on the first pass through the loop unless some request
takes longer than the 64 thousand requests before it
(and it would also have to have been a request that
did not time out) */
while
(
server
->
CurrentMid
!=
last_mid
)
{
struct
list_head
*
tmp
;
struct
mid_q_entry
*
mid_entry
;
collision
=
0
;
if
(
server
->
CurrentMid
==
0
)
server
->
CurrentMid
++
;
list_for_each
(
tmp
,
&
server
->
pending_mid_q
)
{
mid_entry
=
list_entry
(
tmp
,
struct
mid_q_entry
,
qhead
);
if
((
mid_entry
->
mid
==
server
->
CurrentMid
)
&&
(
mid_entry
->
midState
==
MID_REQUEST_SUBMITTED
))
{
/* This mid is in use, try a different one */
collision
=
1
;
break
;
}
}
if
(
collision
==
0
)
{
mid
=
server
->
CurrentMid
;
break
;
}
server
->
CurrentMid
++
;
}
spin_unlock
(
&
GlobalMid_Lock
);
return
mid
;
}
/* NB: MID can not be set if treeCon not passed in, in that
case it is responsbility of caller to set the mid */
void
header_assemble
(
struct
smb_hdr
*
buffer
,
char
smb_command
/* command */
,
const
struct
cifsTconInfo
*
treeCon
,
int
word_count
...
...
@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
(
2
*
word_count
)
+
sizeof
(
struct
smb_hdr
)
-
4
/* RFC 1001 length field does not count */
+
2
/* for bcc field itself */
;
/* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
/* Note that this is the only network field that has to be converted
to big endian and it is done just before we send it */
buffer
->
Protocol
[
0
]
=
0xFF
;
buffer
->
Protocol
[
1
]
=
'S'
;
...
...
@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer
->
Pid
=
cpu_to_le16
((
__u16
)
current
->
tgid
);
buffer
->
PidHigh
=
cpu_to_le16
((
__u16
)(
current
->
tgid
>>
16
));
spin_lock
(
&
GlobalMid_Lock
);
GlobalMid
++
;
buffer
->
Mid
=
GlobalMid
;
spin_unlock
(
&
GlobalMid_Lock
);
if
(
treeCon
)
{
buffer
->
Tid
=
treeCon
->
tid
;
...
...
@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
if
(
treeCon
->
ses
->
capabilities
&
CAP_STATUS32
)
{
buffer
->
Flags2
|=
SMBFLG2_ERR_STATUS
;
}
buffer
->
Uid
=
treeCon
->
ses
->
Suid
;
/* always in LE format */
/* Uid is not converted */
buffer
->
Uid
=
treeCon
->
ses
->
Suid
;
buffer
->
Mid
=
GetNextMid
(
treeCon
->
ses
->
server
);
if
(
multiuser_mount
!=
0
)
{
/* For the multiuser case, there are few obvious technically */
/* possible mechanisms to match the local linux user (uid) */
...
...
@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
}
if
(
treeCon
->
Flags
&
SMB_SHARE_IS_IN_DFS
)
buffer
->
Flags2
|=
SMBFLG2_DFS
;
if
(
treeCon
->
nocase
)
buffer
->
Flags
|=
SMBFLG_CASELESS
;
if
((
treeCon
->
ses
)
&&
(
treeCon
->
ses
->
server
))
if
(
treeCon
->
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
...
...
@@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
int
checkSMB
(
struct
smb_hdr
*
smb
,
__u16
mid
,
int
length
)
{
__u32
len
=
be32_to_cpu
(
smb
->
smb_buf_length
);
__u32
len
=
smb
->
smb_buf_length
;
__u32
clc_len
;
/* calculated length */
cFYI
(
0
,
(
"Entering checkSMB with Length: %x, smb_buf_length: %x "
,
length
,
len
));
...
...
@@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
cERROR
(
1
,
(
"smb_buf_length greater than MaxBufSize"
));
cERROR
(
1
,
(
"bad smb detected. Illegal length.
The
mid=%d"
,
(
"bad smb detected. Illegal length. mid=%d"
,
smb
->
Mid
));
return
1
;
}
if
(
checkSMBhdr
(
smb
,
mid
))
return
1
;
if
((
4
+
len
!=
smbCalcSize
(
smb
)
)
clc_len
=
smbCalcSize_LE
(
smb
);
if
((
4
+
len
!=
clc_len
)
||
(
4
+
len
!=
(
unsigned
int
)
length
))
{
cERROR
(
1
,
(
"Calculated size 0x%x vs actual length 0x%x"
,
clc_len
,
4
+
len
));
cERROR
(
1
,
(
"bad smb size detected for Mid=%d"
,
smb
->
Mid
));
/* Windows XP can return a few bytes too much, presumably
an illegal pad, at the end of byte range lock responses
so we allow for up to eight byte pad, as long as actual
received length is as long or longer than calculated length */
if
((
4
+
len
>
clc_len
)
&&
(
len
<=
clc_len
+
3
))
return
0
;
}
else
{
cERROR
(
1
,
(
"smbCalcSize %x "
,
smbCalcSize
(
smb
)));
cERROR
(
1
,
(
"bad smb size detected. The Mid=%d"
,
smb
->
Mid
));
else
return
1
;
}
return
0
;
}
int
is_valid_oplock_break
(
struct
smb_hdr
*
buf
)
...
...
@@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
if
(
tcon
->
tid
==
buf
->
Tid
)
{
#ifdef CONFIG_CIFS_STATS
atomic_inc
(
&
tcon
->
num_oplock_brks
);
#endif
cifs_stats_inc
(
&
tcon
->
num_oplock_brks
);
list_for_each
(
tmp1
,
&
tcon
->
openFileList
){
netfile
=
list_entry
(
tmp1
,
struct
cifsFileInfo
,
tlist
);
...
...
@@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
int
i
,
j
,
charlen
;
int
len_remaining
=
maxlen
;
char
src_char
;
__u16
temp
;
if
(
!
mapChars
)
return
cifs_strtoUCS
((
wchar_t
*
)
target
,
source
,
PATH_MAX
,
cp
);
...
...
@@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
break;*/
default:
charlen
=
cp
->
char2uni
(
source
+
i
,
len_remaining
,
target
+
j
);
len_remaining
,
&
temp
);
/* if no match, use question mark, which
at least in some cases servers as wild card */
if
(
charlen
<
1
)
{
target
[
j
]
=
cpu_to_le16
(
0x003f
);
charlen
=
1
;
}
}
else
target
[
j
]
=
cpu_to_le16
(
temp
);
len_remaining
-=
charlen
;
/* character may take more than one byte in the
the source string, but will take exactly two
...
...
fs/cifs/netmisc.c
浏览文件 @
fca324e7
...
...
@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
int
cifs_inet_pton
(
int
address_family
,
char
*
cp
,
void
*
dst
)
{
struct
in_addr
address
;
int
value
;
int
digit
;
int
i
;
...
...
@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
if
(
value
>
addr_class_max
[
end
-
bytes
])
return
0
;
address
.
s_addr
=
*
((
__be32
*
)
bytes
)
|
htonl
(
value
);
*
((
__be32
*
)
dst
)
=
address
.
s_addr
;
*
((
__be32
*
)
dst
)
=
*
((
__be32
*
)
bytes
)
|
htonl
(
value
);
return
1
;
/* success */
}
...
...
@@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb)
if
(
smb
->
Flags2
&
SMBFLG2_ERR_STATUS
)
{
/* translate the newer STATUS codes to old style errors and then to POSIX errors */
__u32
err
=
le32_to_cpu
(
smb
->
Status
.
CifsError
);
if
(
cifsFYI
)
if
(
cifsFYI
&
CIFS_RC
)
cifs_print_status
(
err
);
ntstatus_to_dos
(
err
,
&
smberrclass
,
&
smberrcode
);
}
else
{
...
...
@@ -870,7 +868,14 @@ unsigned int
smbCalcSize
(
struct
smb_hdr
*
ptr
)
{
return
(
sizeof
(
struct
smb_hdr
)
+
(
2
*
ptr
->
WordCount
)
+
BCC
(
ptr
));
2
/* size of the bcc field */
+
BCC
(
ptr
));
}
unsigned
int
smbCalcSize_LE
(
struct
smb_hdr
*
ptr
)
{
return
(
sizeof
(
struct
smb_hdr
)
+
(
2
*
ptr
->
WordCount
)
+
2
/* size of the bcc field */
+
le16_to_cpu
(
BCC_LE
(
ptr
)));
}
/* The following are taken from fs/ntfs/util.c */
...
...
fs/cifs/ntlmssp.h
浏览文件 @
fca324e7
...
...
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma pack(1)
#define NTLMSSP_SIGNATURE "NTLMSSP"
/* Message Types */
#define NtLmNegotiate cpu_to_le32(1)
...
...
@@ -63,7 +61,7 @@ typedef struct _SECURITY_BUFFER {
__le16
Length
;
__le16
MaximumLength
;
__le32
Buffer
;
/* offset to buffer */
}
SECURITY_BUFFER
;
}
__attribute__
((
packed
))
SECURITY_BUFFER
;
typedef
struct
_NEGOTIATE_MESSAGE
{
__u8
Signature
[
sizeof
(
NTLMSSP_SIGNATURE
)];
...
...
@@ -73,7 +71,7 @@ typedef struct _NEGOTIATE_MESSAGE {
SECURITY_BUFFER
WorkstationName
;
/* RFC 1001 and ASCII */
char
DomainString
[
0
];
/* followed by WorkstationString */
}
NEGOTIATE_MESSAGE
,
*
PNEGOTIATE_MESSAGE
;
}
__attribute__
((
packed
))
NEGOTIATE_MESSAGE
,
*
PNEGOTIATE_MESSAGE
;
typedef
struct
_CHALLENGE_MESSAGE
{
__u8
Signature
[
sizeof
(
NTLMSSP_SIGNATURE
)];
...
...
@@ -83,7 +81,7 @@ typedef struct _CHALLENGE_MESSAGE {
__u8
Challenge
[
CIFS_CRYPTO_KEY_SIZE
];
__u8
Reserved
[
8
];
SECURITY_BUFFER
TargetInfoArray
;
}
CHALLENGE_MESSAGE
,
*
PCHALLENGE_MESSAGE
;
}
__attribute__
((
packed
))
CHALLENGE_MESSAGE
,
*
PCHALLENGE_MESSAGE
;
typedef
struct
_AUTHENTICATE_MESSAGE
{
__u8
Signature
[
sizeof
(
NTLMSSP_SIGNATURE
)];
...
...
@@ -96,6 +94,4 @@ typedef struct _AUTHENTICATE_MESSAGE {
SECURITY_BUFFER
SessionKey
;
__le32
NegotiateFlags
;
char
UserString
[
0
];
}
AUTHENTICATE_MESSAGE
,
*
PAUTHENTICATE_MESSAGE
;
#pragma pack()
/* resume default structure packing */
}
__attribute__
((
packed
))
AUTHENTICATE_MESSAGE
,
*
PAUTHENTICATE_MESSAGE
;
fs/cifs/readdir.c
浏览文件 @
fca324e7
此差异已折叠。
点击以展开。
fs/cifs/rfc1002pdu.h
浏览文件 @
fca324e7
...
...
@@ -21,8 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma pack(1)
/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
/* RFC 1002 session packet types */
...
...
@@ -48,17 +46,17 @@ struct rfc1002_session_packet {
__u8
calling_len
;
__u8
calling_name
[
32
];
__u8
scope2
;
/* null */
}
session_req
;
}
__attribute__
((
packed
))
session_req
;
struct
{
__u32
retarget_ip_addr
;
__u16
port
;
}
retarget_resp
;
}
__attribute__
((
packed
))
retarget_resp
;
__u8
neg_ses_resp_error_code
;
/* POSITIVE_SESSION_RESPONSE packet does not include trailer.
SESSION_KEEP_ALIVE packet also does not include a trailer.
Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
}
trailer
;
};
}
__attribute__
((
packed
))
trailer
;
}
__attribute__
((
packed
))
;
/* Negative Session Response error codes */
#define RFC1002_NOT_LISTENING_CALLED 0x80
/* not listening on called name */
...
...
@@ -74,6 +72,3 @@ server netbios name). Currently server names are resolved only via DNS
(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER "
#pragma pack()
/* resume default structure packing */
fs/cifs/transport.c
浏览文件 @
fca324e7
此差异已折叠。
点击以展开。
mm/swap.c
浏览文件 @
fca324e7
...
...
@@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec)
pagevec_reinit
(
pvec
);
}
EXPORT_SYMBOL
(
__pagevec_release
);
/*
* pagevec_release() for pages which are known to not be on the LRU
*
...
...
@@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
return
pagevec_count
(
pvec
);
}
EXPORT_SYMBOL
(
pagevec_lookup_tag
);
#ifdef CONFIG_SMP
/*
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录