Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d6d3f5bc
Commit
d6d3f5bc
authored
Oct 21, 2005
by
Steve French
Browse files
Options
Browse Files
Download
Plain Diff
Merge with /pub/scm/linux/kernel/git/sfrench/cifs-2.6.git/
parents
ac9b9c66
23e7dd7d
Changes
24
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
2266 additions
and
545 deletions
+2266
-545
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
+163
-11
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/readdir.c
fs/cifs/readdir.c
+65
-19
fs/cifs/transport.c
fs/cifs/transport.c
+255
-76
No files found.
fs/cifs/AUTHORS
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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
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_closes
),
atomic_read
(
&
tcon
->
num_deletes
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Opens: %d Deletes: %d
\n
Mkdirs: %d Rmdirs: %d"
,
atomic_read
(
&
tcon
->
num_opens
),
atomic_read
(
&
tcon
->
num_deletes
),
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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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,10 +940,16 @@ init_cifs(void)
if
(
!
rc
)
{
rc
=
(
int
)
kernel_thread
(
cifs_oplock_thread
,
NULL
,
CLONE_FS
|
CLONE_FILES
|
CLONE_VM
);
if
(
rc
>
0
)
return
0
;
else
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
();
}
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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
;
...
...
@@ -122,13 +123,17 @@ struct TCP_Server_Info {
struct
list_head
pending_mid_q
;
void
*
Server_NlsInfo
;
/* BB - placeholder for future NLS info */
unsigned
short
server_codepage
;
/* codepage for the server */
unsigned
long
ip_address
;
/* IP addr for the server if known
*/
unsigned
long
ip_address
;
/* IP addr for the server if known */
enum
protocolEnum
protocolType
;
char
versionMajor
;
char
versionMinor
;
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
View file @
d6d3f5bc
...
...
@@ -36,9 +36,11 @@
#define SMB_COM_CLOSE 0x04
/* triv req/rsp, timestamp ignored */
#define SMB_COM_DELETE 0x06
/* trivial response */
#define SMB_COM_RENAME 0x07
/* trivial response */
#define SMB_COM_QUERY_INFORMATION 0x08
/* aka getattr */
#define SMB_COM_SETATTR 0x09
/* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24
/* trivial response */
#define SMB_COM_COPY 0x29
/* trivial rsp, fail filename ignrd*/
#define SMB_COM_OPEN_ANDX 0x2D
/* Legacy open for old servers */
#define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32
...
...
@@ -52,6 +54,7 @@
#define SMB_COM_NT_TRANSACT 0xA0
#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
#define SMB_COM_NT_CREATE_ANDX 0xA2
#define SMB_COM_NT_CANCEL 0xA4
/* no response */
#define SMB_COM_NT_RENAME 0xA5
/* trivial response */
/* Transact2 subcommand codes */
...
...
@@ -59,6 +62,7 @@
#define TRANS2_FIND_FIRST 0x01
#define TRANS2_FIND_NEXT 0x02
#define TRANS2_QUERY_FS_INFORMATION 0x03
#define TRANS2_SET_FS_INFORMATION 0x04
#define TRANS2_QUERY_PATH_INFORMATION 0x05
#define TRANS2_SET_PATH_INFORMATION 0x06
#define TRANS2_QUERY_FILE_INFORMATION 0x07
...
...
@@ -267,10 +271,18 @@
/* CreateOptions */
#define CREATE_NOT_FILE 0x00000001
/* if set must not be file */
#define CREATE_WRITE_THROUGH 0x00000002
#define CREATE_NOT_DIR 0x00000040
/* if set must not be directory */
#define CREATE_SEQUENTIAL 0x00000004
#define CREATE_SYNC_ALERT 0x00000010
#define CREATE_ASYNC_ALERT 0x00000020
#define CREATE_NOT_DIR 0x00000040
/* if set must not be directory */
#define CREATE_NO_EA_KNOWLEDGE 0x00000200
#define CREATE_EIGHT_DOT_THREE 0x00000400
#define CREATE_RANDOM_ACCESS 0x00000800
#define CREATE_DELETE_ON_CLOSE 0x00001000
#define CREATE_OPEN_BY_ID 0x00002000
#define OPEN_REPARSE_POINT 0x00200000
#define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_SPECIAL 0x20000000
/* system. NB not sent over wire */
/* ImpersonationLevel flags */
#define SECURITY_ANONYMOUS 0
...
...
@@ -614,6 +626,7 @@ typedef struct smb_com_findclose_req {
}
FINDCLOSE_REQ
;
/* OpenFlags */
#define REQ_MORE_INFO 0x00000001
/* legacy (OPEN_AND_X) only */
#define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008
...
...
@@ -669,6 +682,62 @@ typedef struct smb_com_open_rsp {
__u16
ByteCount
;
/* bct = 0 */
}
OPEN_RSP
;
/* format of legacy open request */
typedef
struct
smb_com_openx_req
{
struct
smb_hdr
hdr
;
/* wct = 15 */
__u8
AndXCommand
;
__u8
AndXReserved
;
__le16
AndXOffset
;
__le16
OpenFlags
;
__le16
Mode
;
__le16
Sattr
;
/* search attributes */
__le16
FileAttributes
;
/* dos attrs */
__le32
CreateTime
;
/* os2 format */
__le16
OpenFunction
;
__le32
EndOfFile
;
__le32
Timeout
;
__le32
Reserved
;
__le16
ByteCount
;
/* file name follows */
char
fileName
[
1
];
}
OPENX_REQ
;
typedef
struct
smb_com_openx_rsp
{
struct
smb_hdr
hdr
;
/* wct = 15 */
__u8
AndXCommand
;
__u8
AndXReserved
;
__le16
AndXOffset
;
__u16
Fid
;
__le16
FileAttributes
;
__le32
LastWriteTime
;
/* os2 format */
__le32
EndOfFile
;
__le16
Access
;
__le16
FileType
;
__le16
IPCState
;
__le16
Action
;
__u32
FileId
;
__u16
Reserved
;
__u16
ByteCount
;
}
OPENX_RSP
;
/* Legacy write request for older servers */
typedef
struct
smb_com_writex_req
{
struct
smb_hdr
hdr
;
/* wct = 12 */
__u8
AndXCommand
;
__u8
AndXReserved
;
__le16
AndXOffset
;
__u16
Fid
;
__le32
OffsetLow
;
__u32
Reserved
;
/* Timeout */
__le16
WriteMode
;
/* 1 = write through */
__le16
Remaining
;
__le16
Reserved2
;
__le16
DataLengthLow
;
__le16
DataOffset
;
__le16
ByteCount
;
__u8
Pad
;
/* BB check for whether padded to DWORD boundary and optimum performance here */
char
Data
[
0
];
}
WRITEX_REQ
;
typedef
struct
smb_com_write_req
{
struct
smb_hdr
hdr
;
/* wct = 14 */
__u8
AndXCommand
;
...
...
@@ -700,6 +769,21 @@ typedef struct smb_com_write_rsp {
__u16
ByteCount
;
}
WRITE_RSP
;
/* legacy read request for older servers */
typedef
struct
smb_com_readx_req
{
struct
smb_hdr
hdr
;
/* wct = 10 */
__u8
AndXCommand
;
__u8
AndXReserved
;
__le16
AndXOffset
;
__u16
Fid
;
__le32
OffsetLow
;
__le16
MaxCount
;
__le16
MinCount
;
/* obsolete */
__le32
Reserved
;
__le16
Remaining
;
__le16
ByteCount
;
}
READX_REQ
;
typedef
struct
smb_com_read_req
{
struct
smb_hdr
hdr
;
/* wct = 12 */
__u8
AndXCommand
;
...
...
@@ -876,6 +960,22 @@ typedef struct smb_com_create_directory_rsp {
__u16
ByteCount
;
/* bct = 0 */
}
CREATE_DIRECTORY_RSP
;
typedef
struct
smb_com_query_information_req
{
struct
smb_hdr
hdr
;
/* wct = 0 */
__le16
ByteCount
;
/* 1 + namelen + 1 */
__u8
BufferFormat
;
/* 4 = ASCII */
unsigned
char
FileName
[
1
];
}
QUERY_INFORMATION_REQ
;
typedef
struct
smb_com_query_information_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 */
__le16
attr
;
__le32
last_write_time
;
__le32
size
;
__u16
reserved
[
5
];
__le16
ByteCount
;
/* bcc = 0 */
}
QUERY_INFORMATION_RSP
;
typedef
struct
smb_com_setattr_req
{
struct
smb_hdr
hdr
;
/* wct = 8 */
__le16
attr
;
...
...
@@ -1411,6 +1511,43 @@ typedef struct smb_com_transaction_qfsi_rsp {
__u8
Pad
;
/* may be three bytes *//* followed by data area */
}
TRANSACTION2_QFSI_RSP
;
/* SETFSInfo Levels */
#define SMB_SET_CIFS_UNIX_INFO 0x200
typedef
struct
smb_com_transaction2_setfsi_req
{
struct
smb_hdr
hdr
;
/* wct = 15 */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__le16
MaxParameterCount
;
__le16
MaxDataCount
;
__u8
MaxSetupCount
;
__u8
Reserved
;
__le16
Flags
;
__le32
Timeout
;
__u16
Reserved2
;
__le16
ParameterCount
;
/* 4 */
__le16
ParameterOffset
;
__le16
DataCount
;
/* 12 */
__le16
DataOffset
;
__u8
SetupCount
;
/* one */
__u8
Reserved3
;
__le16
SubCommand
;
/* TRANS2_SET_FS_INFORMATION */
__le16
ByteCount
;
__u8
Pad
;
__u16
FileNum
;
/* Parameters start. */
__le16
InformationLevel
;
/* Parameters end. */
__le16
ClientUnixMajor
;
/* Data start. */
__le16
ClientUnixMinor
;
__le64
ClientUnixCap
;
/* Data end */
}
TRANSACTION2_SETFSI_REQ
;
typedef
struct
smb_com_transaction2_setfsi_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 */
struct
trans2_resp
t2
;
__u16
ByteCount
;
}
TRANSACTION2_SETFSI_RSP
;
typedef
struct
smb_com_transaction2_get_dfs_refer_req
{
struct
smb_hdr
hdr
;
/* wct = 15 */
__le16
TotalParameterCount
;
...
...
@@ -1546,17 +1683,33 @@ typedef struct {
__le32
BytesPerSector
;
}
FILE_SYSTEM_INFO
;
/* size info, level 0x103 */
typedef
struct
{
__le32
fsid
;
__le32
SectorsPerAllocationUnit
;
__le32
TotalAllocationUnits
;
__le32
FreeAllocationUnits
;
__le16
BytesPerSector
;
}
FILE_SYSTEM_ALLOC_INFO
;
typedef
struct
{
__le16
MajorVersionNumber
;
__le16
MinorVersionNumber
;
__le64
Capability
;
}
FILE_SYSTEM_UNIX_INFO
;
/* Unix extensions info, level 0x200 */
/* Version numbers for CIFS UNIX major and minor. */
#define CIFS_UNIX_MAJOR_VERSION 1
#define CIFS_UNIX_MINOR_VERSION 0
/* Linux/Unix extensions capability flags */
#define CIFS_UNIX_FCNTL_CAP 0x00000001
/* support for fcntl locks */
#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002
/* support getfacl/setfacl */
#define CIFS_UNIX_XATTR_CAP 0x00000004
/* support new namespace */
#define CIFS_UNIX_EXTATTR_CAP 0x00000008
/* support chattr/chflag */
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010
/* Use POSIX pathnames on the wire. */
#define CIFS_POSIX_EXTENSIONS 0x00000010
/* support for new QFSInfo */
typedef
struct
{
/* For undefined recommended transfer size return -1 in that field */
__le32
OptimalTransferSize
;
/* bsize on some os, iosize on other os */
...
...
@@ -1907,18 +2060,17 @@ struct data_blob {
perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags
2) Close - to return the last write time to do cache across close more safely
3)
PosixQFSInfo - to return statfs info
4) FindFirst return unique inode number - what about resume key, two
forms short (matches readdir) and full (enough info to cache inodes)
5
) Mkdir - set mode
3)
FindFirst return unique inode number - what about resume key, two
forms short (matches readdir) and full (enough info to cache inodes)
4
) Mkdir - set mode
And under consideration:
6
) FindClose2 (return nanosecond timestamp ??)
7
) Use nanosecond timestamps throughout all time fields if
5
) FindClose2 (return nanosecond timestamp ??)
6
) Use nanosecond timestamps throughout all time fields if
corresponding attribute flag is set
8) sendfile - handle based copy
9) Direct i/o
10) "POSIX ACL" support
11) Misc fcntls?
7) sendfile - handle based copy
8) Direct i/o
9) Misc fcntls?
what about fixing 64 bit alignment
...
...
@@ -1974,7 +2126,7 @@ struct data_blob {
*/
/* xsymlink is a symlink format that can be used
/* xsymlink is a symlink format
(used by MacOS)
that can be used
to save symlink info in a regular file when
mounted to operating systems that do not
support the cifs Unix extensions or EAs (for xattr
...
...
fs/cifs/cifsproto.h
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
This diff is collapsed.
Click to expand it.
fs/cifs/connect.c
View file @
d6d3f5bc
This diff is collapsed.
Click to expand it.
fs/cifs/dir.c
View file @
d6d3f5bc
...
...
@@ -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,10 +233,14 @@ 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
{
direntry
->
d_op
=
&
cifs_dentry_ops
;
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_instantiate
(
direntry
,
newinode
);
}
if
((
nd
->
flags
&
LOOKUP_OPEN
)
==
FALSE
)
{
...
...
@@ -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
);
direntry
->
d_op
=
&
cifs_dentry_ops
;
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,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
parent_dir_inode
->
i_sb
,
xid
);
if
((
rc
==
0
)
&&
(
newInode
!=
NULL
))
{
direntry
->
d_op
=
&
cifs_dentry_ops
;
if
(
pTcon
->
nocase
)
direntry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
direntry
->
d_op
=
&
cifs_dentry_ops
;
d_add
(
direntry
,
newInode
);
/* since paths are not looked up by component - the parent directories are presumed to be good here */
...
...
@@ -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
View file @
d6d3f5bc
...
...
@@ -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
View file @
d6d3f5bc
This diff is collapsed.
Click to expand it.
fs/cifs/inode.c
View file @
d6d3f5bc
...
...
@@ -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
;
...
...
@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode,
pfindData
=
(
FILE_ALL_INFO
*
)
buf
;
/* could do find first instead but this returns more info */
rc
=
CIFSSMBQPathInfo
(
xid
,
pTcon
,
search_path
,
pfindData
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
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,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
rc
=
cifs_get_inode_info
(
&
newinode
,
full_path
,
NULL
,
inode
->
i_sb
,
xid
);
direntry
->
d_op
=
&
cifs_dentry_ops
;
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
)
direntry
->
d_inode
->
i_nlink
=
2
;
...
...
@@ -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 */
__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
;
}
open_file
=
find_writable_file
(
cifsInode
);
if
(
open_file
)
{
__u16
nfid
=
open_file
->
netfid
;
__u32
npid
=
open_file
->
pid
;
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
;
if
(
attrs
->
ia_valid
&
ATTR_CTIME
)
{
/* 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
(
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
View file @
d6d3f5bc
...
...
@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
(
"Create symlink worked but get_inode_info failed with rc = %d "
,
rc
));
}
else
{
direntry
->
d_op
=
&
cifs_dentry_ops
;
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
View file @
d6d3f5bc
...
...
@@ -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
))
{
return
0
;
}
else
{
cERROR
(
1
,
(
"smbCalcSize %x "
,
smbCalcSize
(
smb
)));
cERROR
(
1
,
(
"bad smb size detected. The Mid=%d"
,
smb
->
Mid
));
return
1
;
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
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
View file @
d6d3f5bc
...
...
@@ -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/readdir.c
View file @
d6d3f5bc
...
...
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
}
*
ptmp_inode
=
new_inode
(
file
->
f_dentry
->
d_sb
);
tmp_dentry
->
d_op
=
&
cifs_dentry_ops
;
if
(
pTcon
->
nocase
)
tmp_dentry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
tmp_dentry
->
d_op
=
&
cifs_dentry_ops
;
if
(
*
ptmp_inode
==
NULL
)
return
rc
;
rc
=
1
;
...
...
@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode,
tmp_inode
->
i_mode
=
cifs_sb
->
mnt_dir_mode
;
}
tmp_inode
->
i_mode
|=
S_IFDIR
;
}
else
if
((
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_UNX_EMUL
)
&&
(
attr
&
ATTR_SYSTEM
)
&&
(
end_of_file
==
0
))
{
*
pobject_type
=
DT_FIFO
;
tmp_inode
->
i_mode
|=
S_IFIFO
;
/* BB Finish for SFU style symlinks and devies */
/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(attr & ATTR_SYSTEM) && ) { */
/* we no longer mark these because we could not follow them */
/* } else if (attr & ATTR_REPARSE) {
*pobject_type = DT_LNK;
...
...
@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode,
tmp_inode
->
i_fop
=
&
cifs_file_direct_ops
;
else
tmp_inode
->
i_fop
=
&
cifs_file_ops
;
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_NO_BRL
)
tmp_inode
->
i_fop
->
lock
=
NULL
;
tmp_inode
->
i_data
.
a_ops
=
&
cifs_addr_ops
;
if
((
cifs_sb
->
tcon
)
&&
(
cifs_sb
->
tcon
->
ses
)
&&
(
cifs_sb
->
tcon
->
ses
->
server
->
maxBuf
<
4096
+
MAX_CIFS_HDR_SIZE
))
tmp_inode
->
i_data
.
a_ops
->
readpages
=
NULL
;
if
(
isNewInode
)
return
;
/* No sense invalidating pages for new inode since we
have not started caching readahead file data yet */
return
;
/* No sense invalidating pages for new inode
since have not started caching readahead file
data yet */
if
(
timespec_equal
(
&
tmp_inode
->
i_mtime
,
&
local_mtime
)
&&
(
local_size
==
tmp_inode
->
i_size
))
{
...
...
@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode
->
i_fop
=
&
cifs_file_direct_ops
;
else
tmp_inode
->
i_fop
=
&
cifs_file_ops
;
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_NO_BRL
)
tmp_inode
->
i_fop
->
lock
=
NULL
;
tmp_inode
->
i_data
.
a_ops
=
&
cifs_addr_ops
;
if
((
cifs_sb
->
tcon
)
&&
(
cifs_sb
->
tcon
->
ses
)
&&
(
cifs_sb
->
tcon
->
ses
->
server
->
maxBuf
<
4096
+
MAX_CIFS_HDR_SIZE
))
tmp_inode
->
i_data
.
a_ops
->
readpages
=
NULL
;
if
(
isNewInode
)
return
;
/* No sense invalidating pages for new inode since we
...
...
@@ -374,7 +396,8 @@ static int initiate_cifs_search(const int xid, struct file *file)
rc
=
CIFSFindFirst
(
xid
,
pTcon
,
full_path
,
cifs_sb
->
local_nls
,
&
cifsFile
->
netfid
,
&
cifsFile
->
srch_inf
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
,
CIFS_DIR_SEP
(
cifs_sb
));
if
(
rc
==
0
)
cifsFile
->
invalidHandle
=
FALSE
;
if
((
rc
==
-
EOPNOTSUPP
)
&&
...
...
@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
return
rc
;
}
/* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */
static
int
is_dir_changed
(
struct
file
*
file
)
{
struct
inode
*
inode
;
struct
cifsInodeInfo
*
cifsInfo
;
if
(
file
->
f_dentry
==
NULL
)
return
0
;
inode
=
file
->
f_dentry
->
d_inode
;
if
(
inode
==
NULL
)
return
0
;
cifsInfo
=
CIFS_I
(
inode
);
if
(
cifsInfo
->
time
==
0
)
return
1
;
/* directory was changed, perhaps due to unlink */
else
return
0
;
}
/* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not
...
...
@@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
struct
cifsFileInfo
*
cifsFile
=
file
->
private_data
;
/* check if index in the buffer */
if
((
cifsFile
==
NULL
)
||
(
ppCurrentEntry
==
NULL
)
||
(
num_to_ret
==
NULL
))
if
((
cifsFile
==
NULL
)
||
(
ppCurrentEntry
==
NULL
)
||
(
num_to_ret
==
NULL
))
return
-
ENOENT
;
*
ppCurrentEntry
=
NULL
;
...
...
@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
cifsFile
->
srch_inf
.
index_of_last_entry
-
cifsFile
->
srch_inf
.
entries_in_buffer
;
/* dump_cifs_file_struct(file, "In fce ");*/
if
(
index_to_find
<
first_entry_in_buffer
)
{
if
(((
index_to_find
<
cifsFile
->
srch_inf
.
index_of_last_entry
)
&&
is_dir_changed
(
file
))
||
(
index_to_find
<
first_entry_in_buffer
))
{
/* close and restart search */
cFYI
(
1
,(
"search backing up - close and restart search"
));
cifsFile
->
invalidHandle
=
TRUE
;
...
...
@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
while
((
index_to_find
>=
cifsFile
->
srch_inf
.
index_of_last_entry
)
&&
(
rc
==
0
)
&&
(
cifsFile
->
srch_inf
.
endOfSearch
==
FALSE
)){
cFYI
(
1
,(
"calling findnext2"
));
rc
=
CIFSFindNext
(
xid
,
pTcon
,
cifsFile
->
netfid
,
&
cifsFile
->
srch_inf
);
rc
=
CIFSFindNext
(
xid
,
pTcon
,
cifsFile
->
netfid
,
&
cifsFile
->
srch_inf
);
if
(
rc
)
return
-
ENOENT
;
}
...
...
@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
char
*
end_of_smb
=
cifsFile
->
srch_inf
.
ntwrk_buf_start
+
smbCalcSize
((
struct
smb_hdr
*
)
cifsFile
->
srch_inf
.
ntwrk_buf_start
);
/* dump_cifs_file_struct(file,"found entry in fce "); */
first_entry_in_buffer
=
cifsFile
->
srch_inf
.
index_of_last_entry
-
cifsFile
->
srch_inf
.
entries_in_buffer
;
pos_in_buf
=
index_to_find
-
first_entry_in_buffer
;
cFYI
(
1
,(
"found entry - pos_in_buf %d"
,
pos_in_buf
));
current_entry
=
cifsFile
->
srch_inf
.
srch_entries_start
;
for
(
i
=
0
;(
i
<
(
pos_in_buf
))
&&
(
current_entry
!=
NULL
);
i
++
)
{
/* go entry
to next entry figuring out which we need to start with
*/
/* go entry
by entry figuring out which is first
*/
/* if( . or ..)
skip */
rc
=
cifs_entry_is_dot
(
current_entry
,
cifsFile
);
...
...
@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
}
if
(
pos_in_buf
>=
cifsFile
->
srch_inf
.
entries_in_buffer
)
{
cFYI
(
1
,(
"can not return entries
when
pos_in_buf beyond last entry"
));
cFYI
(
1
,(
"can not return entries pos_in_buf beyond last entry"
));
*
num_to_ret
=
0
;
}
else
*
num_to_ret
=
cifsFile
->
srch_inf
.
entries_in_buffer
-
pos_in_buf
;
/* dump_cifs_file_struct(file, "end fce ");*/
return
rc
;
}
...
...
@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
(
FILE_DIRECTORY_INFO
*
)
pfindEntry
,
&
obj_type
,
rc
);
}
rc
=
filldir
(
direntry
,
qstring
.
name
,
qstring
.
len
,
file
->
f_pos
,
tmp_inode
->
i_ino
,
obj_type
);
rc
=
filldir
(
direntry
,
qstring
.
name
,
qstring
.
len
,
file
->
f_pos
,
tmp_inode
->
i_ino
,
obj_type
);
if
(
rc
)
{
cFYI
(
1
,(
"filldir rc = %d"
,
rc
));
}
...
...
@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
FreeXid
(
xid
);
return
-
EIO
;
}
/* dump_cifs_file_struct(file, "Begin rdir "); */
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
pTcon
==
NULL
)
return
-
EINVAL
;
/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
switch
((
int
)
file
->
f_pos
)
{
case
0
:
/*if (filldir(direntry, ".", 1, file->f_pos,
...
...
@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifsFile->search_resume_name = NULL; */
/* BB account for . and .. in f_pos as special case */
/* dump_cifs_file_struct(file, "rdir after default ");*/
rc
=
find_cifs_entry
(
xid
,
pTcon
,
file
,
&
current_entry
,
&
num_to_fill
);
...
...
@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifs_save_resume_key
(
current_entry
,
cifsFile
);
break
;
}
else
current_entry
=
nxt_dir_entry
(
current_entry
,
end_of_smb
);
current_entry
=
nxt_dir_entry
(
current_entry
,
end_of_smb
);
}
kfree
(
tmp_buf
);
break
;
}
/* end switch */
rddir2_exit:
/* dump_cifs_file_struct(file, "end rdir "); */
FreeXid
(
xid
);
return
rc
;
}
fs/cifs/transport.c
View file @
d6d3f5bc
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment