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
nexedi
linux
Commits
6ea75952
Commit
6ea75952
authored
Oct 08, 2010
by
Steve French
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-next'
parents
6b0cd00b
d2445556
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
1614 additions
and
434 deletions
+1614
-434
fs/cifs/README
fs/cifs/README
+5
-0
fs/cifs/cifs_debug.h
fs/cifs/cifs_debug.h
+1
-1
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_dfs_ref.c
+12
-9
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_fs_sb.h
+9
-3
fs/cifs/cifsacl.c
fs/cifs/cifsacl.c
+35
-11
fs/cifs/cifsencrypt.c
fs/cifs/cifsencrypt.c
+129
-17
fs/cifs/cifsfs.c
fs/cifs/cifsfs.c
+41
-20
fs/cifs/cifsfs.h
fs/cifs/cifsfs.h
+1
-1
fs/cifs/cifsglob.h
fs/cifs/cifsglob.h
+55
-12
fs/cifs/cifspdu.h
fs/cifs/cifspdu.h
+0
-1
fs/cifs/cifsproto.h
fs/cifs/cifsproto.h
+11
-6
fs/cifs/cifssmb.c
fs/cifs/cifssmb.c
+9
-7
fs/cifs/cn_cifs.h
fs/cifs/cn_cifs.h
+0
-37
fs/cifs/connect.c
fs/cifs/connect.c
+431
-19
fs/cifs/dir.c
fs/cifs/dir.c
+68
-35
fs/cifs/file.c
fs/cifs/file.c
+91
-67
fs/cifs/fscache.c
fs/cifs/fscache.c
+7
-6
fs/cifs/inode.c
fs/cifs/inode.c
+177
-52
fs/cifs/ioctl.c
fs/cifs/ioctl.c
+3
-14
fs/cifs/link.c
fs/cifs/link.c
+348
-24
fs/cifs/misc.c
fs/cifs/misc.c
+1
-1
fs/cifs/ntlmssp.h
fs/cifs/ntlmssp.h
+15
-0
fs/cifs/readdir.c
fs/cifs/readdir.c
+32
-22
fs/cifs/sess.c
fs/cifs/sess.c
+91
-45
fs/cifs/transport.c
fs/cifs/transport.c
+3
-3
fs/cifs/xattr.c
fs/cifs/xattr.c
+39
-21
No files found.
fs/cifs/README
View file @
6ea75952
...
...
@@ -527,6 +527,11 @@ A partial list of the supported mount options follows:
SFU does). In the future the bottom 9 bits of the
mode also will be emulated using queries of the security
descriptor (ACL).
mfsymlinks Enable support for Minshall+French symlinks
(see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks)
This option is ignored when specified together with the
'sfu' option. Minshall+French symlinks are used even if
the server supports the CIFS Unix Extensions.
sign Must use packet signing (helps avoid unwanted data modification
by intermediate systems in the route). Note that signing
does not work with lanman or plaintext authentication.
...
...
fs/cifs/cifs_debug.h
View file @
6ea75952
...
...
@@ -34,7 +34,7 @@ void cifs_dump_mids(struct TCP_Server_Info *);
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_RC
0x02
#define CIFS_TIMER 0x04
/*
...
...
fs/cifs/cifs_dfs_ref.c
View file @
6ea75952
...
...
@@ -306,6 +306,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
int
xid
,
i
;
int
rc
=
0
;
struct
vfsmount
*
mnt
=
ERR_PTR
(
-
ENOENT
);
struct
tcon_link
*
tlink
;
cFYI
(
1
,
"in %s"
,
__func__
);
BUG_ON
(
IS_ROOT
(
dentry
));
...
...
@@ -315,14 +316,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
dput
(
nd
->
path
.
dentry
);
nd
->
path
.
dentry
=
dget
(
dentry
);
cifs_sb
=
CIFS_SB
(
dentry
->
d_inode
->
i_sb
);
ses
=
cifs_sb
->
tcon
->
ses
;
if
(
!
ses
)
{
rc
=
-
EINVAL
;
goto
out_err
;
}
/*
* The MSDFS spec states that paths in DFS referral requests and
* responses must be prefixed by a single '\' character instead of
...
...
@@ -335,10 +328,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto
out_err
;
}
rc
=
get_dfs_path
(
xid
,
ses
,
full_path
+
1
,
cifs_sb
->
local_nls
,
cifs_sb
=
CIFS_SB
(
dentry
->
d_inode
->
i_sb
);
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
goto
out_err
;
}
ses
=
tlink_tcon
(
tlink
)
->
ses
;
rc
=
get_dfs_path
(
xid
,
ses
,
full_path
+
1
,
cifs_sb
->
local_nls
,
&
num_referrals
,
&
referrals
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
for
(
i
=
0
;
i
<
num_referrals
;
i
++
)
{
int
len
;
dump_referral
(
referrals
+
i
);
...
...
fs/cifs/cifs_fs_sb.h
View file @
6ea75952
...
...
@@ -15,6 +15,8 @@
* the GNU Lesser General Public License for more details.
*
*/
#include <linux/radix-tree.h>
#ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H
...
...
@@ -36,10 +38,13 @@
#define CIFS_MOUNT_NOPOSIXBRL 0x2000
/* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC 0x4000
/* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE 0x8000
/* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS 0x10000
/* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER 0x20000
/* multiuser mount */
struct
cifs_sb_info
{
struct
cifsTconInfo
*
tcon
;
/* primary mount */
struct
list_head
nested_tcon_q
;
struct
radix_tree_root
tlink_tree
;
#define CIFS_TLINK_MASTER_TAG 0
/* is "master" (mount) tcon */
spinlock_t
tlink_tree_lock
;
struct
nls_table
*
local_nls
;
unsigned
int
rsize
;
unsigned
int
wsize
;
...
...
@@ -47,12 +52,13 @@ struct cifs_sb_info {
gid_t
mnt_gid
;
mode_t
mnt_file_mode
;
mode_t
mnt_dir_mode
;
int
mnt_cifs_flags
;
unsigned
int
mnt_cifs_flags
;
int
prepathlen
;
char
*
prepath
;
/* relative path under the share to mount to */
#ifdef CONFIG_CIFS_DFS_UPCALL
char
*
mountdata
;
/* mount options received at mount time */
#endif
struct
backing_dev_info
bdi
;
struct
delayed_work
prune_tlinks
;
};
#endif
/* _CIFS_FS_SB_H */
fs/cifs/cifsacl.c
View file @
6ea75952
...
...
@@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
{
struct
cifs_ntsd
*
pntsd
=
NULL
;
int
xid
,
rc
;
struct
tcon_link
*
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
NULL
;
xid
=
GetXid
();
rc
=
CIFSSMBGetCIFSACL
(
xid
,
cifs_sb
->
tcon
,
fid
,
&
pntsd
,
pacllen
);
rc
=
CIFSSMBGetCIFSACL
(
xid
,
tlink_tcon
(
tlink
)
,
fid
,
&
pntsd
,
pacllen
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
cFYI
(
1
,
"GetCIFSACL rc = %d ACL len %d"
,
rc
,
*
pacllen
);
return
pntsd
;
...
...
@@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
int
oplock
=
0
;
int
xid
,
rc
;
__u16
fid
;
struct
cifsTconInfo
*
tcon
;
struct
tcon_link
*
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
NULL
;
tcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
rc
=
CIFSSMBOpen
(
xid
,
cifs_sb
->
tcon
,
path
,
FILE_OPEN
,
READ_CONTROL
,
0
,
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
path
,
FILE_OPEN
,
READ_CONTROL
,
0
,
&
fid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
)
{
...
...
@@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
goto
out
;
}
rc
=
CIFSSMBGetCIFSACL
(
xid
,
cifs_sb
->
tcon
,
fid
,
&
pntsd
,
pacllen
);
rc
=
CIFSSMBGetCIFSACL
(
xid
,
tcon
,
fid
,
&
pntsd
,
pacllen
);
cFYI
(
1
,
"GetCIFSACL rc = %d ACL len %d"
,
rc
,
*
pacllen
);
CIFSSMBClose
(
xid
,
cifs_sb
->
tcon
,
fid
);
CIFSSMBClose
(
xid
,
tcon
,
fid
);
out:
cifs_put_tlink
(
tlink
);
FreeXid
(
xid
);
return
pntsd
;
}
...
...
@@ -603,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct
cifsFileInfo
*
open_file
=
NULL
;
if
(
inode
)
open_file
=
find_readable_file
(
CIFS_I
(
inode
));
open_file
=
find_readable_file
(
CIFS_I
(
inode
)
,
true
);
if
(
!
open_file
)
return
get_cifs_acl_by_path
(
cifs_sb
,
path
,
pacllen
);
...
...
@@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
struct
cifs_ntsd
*
pnntsd
,
u32
acllen
)
{
int
xid
,
rc
;
struct
tcon_link
*
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
xid
=
GetXid
();
rc
=
CIFSSMBSetCIFSACL
(
xid
,
cifs_sb
->
tcon
,
fid
,
pnntsd
,
acllen
);
rc
=
CIFSSMBSetCIFSACL
(
xid
,
tlink_tcon
(
tlink
)
,
fid
,
pnntsd
,
acllen
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
cFYI
(
DBG2
,
"SetCIFSACL rc = %d"
,
rc
);
return
rc
;
...
...
@@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
int
oplock
=
0
;
int
xid
,
rc
;
__u16
fid
;
struct
cifsTconInfo
*
tcon
;
struct
tcon_link
*
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
rc
=
CIFSSMBOpen
(
xid
,
cifs_sb
->
tcon
,
path
,
FILE_OPEN
,
WRITE_DAC
,
0
,
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
path
,
FILE_OPEN
,
WRITE_DAC
,
0
,
&
fid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
)
{
...
...
@@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
goto
out
;
}
rc
=
CIFSSMBSetCIFSACL
(
xid
,
cifs_sb
->
tcon
,
fid
,
pnntsd
,
acllen
);
rc
=
CIFSSMBSetCIFSACL
(
xid
,
tcon
,
fid
,
pnntsd
,
acllen
);
cFYI
(
DBG2
,
"SetCIFSACL rc = %d"
,
rc
);
CIFSSMBClose
(
xid
,
cifs_sb
->
tcon
,
fid
);
out:
CIFSSMBClose
(
xid
,
tcon
,
fid
);
out:
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -661,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
cFYI
(
DBG2
,
"set ACL for %s from mode 0x%x"
,
path
,
inode
->
i_mode
);
open_file
=
find_readable_file
(
CIFS_I
(
inode
));
open_file
=
find_readable_file
(
CIFS_I
(
inode
)
,
true
);
if
(
!
open_file
)
return
set_cifs_acl_by_path
(
cifs_sb
,
path
,
pnntsd
,
acllen
);
...
...
fs/cifs/cifsencrypt.c
View file @
6ea75952
...
...
@@ -27,6 +27,7 @@
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
#include "ntlmssp.h"
#include <linux/ctype.h>
#include <linux/random.h>
...
...
@@ -42,7 +43,7 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned
char
*
p24
);
static
int
cifs_calculate_signature
(
const
struct
smb_hdr
*
cifs_pdu
,
const
struct
mac
_key
*
key
,
char
*
signature
)
const
struct
session
_key
*
key
,
char
*
signature
)
{
struct
MD5Context
context
;
...
...
@@ -78,7 +79,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
server
->
sequence_number
++
;
spin_unlock
(
&
GlobalMid_Lock
);
rc
=
cifs_calculate_signature
(
cifs_pdu
,
&
server
->
mac_signing
_key
,
rc
=
cifs_calculate_signature
(
cifs_pdu
,
&
server
->
session
_key
,
smb_signature
);
if
(
rc
)
memset
(
cifs_pdu
->
Signature
.
SecuritySignature
,
0
,
8
);
...
...
@@ -89,7 +90,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
}
static
int
cifs_calc_signature2
(
const
struct
kvec
*
iov
,
int
n_vec
,
const
struct
mac
_key
*
key
,
char
*
signature
)
const
struct
session
_key
*
key
,
char
*
signature
)
{
struct
MD5Context
context
;
int
i
;
...
...
@@ -145,7 +146,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
server
->
sequence_number
++
;
spin_unlock
(
&
GlobalMid_Lock
);
rc
=
cifs_calc_signature2
(
iov
,
n_vec
,
&
server
->
mac_signing
_key
,
rc
=
cifs_calc_signature2
(
iov
,
n_vec
,
&
server
->
session
_key
,
smb_signature
);
if
(
rc
)
memset
(
cifs_pdu
->
Signature
.
SecuritySignature
,
0
,
8
);
...
...
@@ -156,14 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
}
int
cifs_verify_signature
(
struct
smb_hdr
*
cifs_pdu
,
const
struct
mac_key
*
mac
_key
,
const
struct
session_key
*
session
_key
,
__u32
expected_sequence_number
)
{
unsigned
int
rc
;
char
server_response_sig
[
8
];
char
what_we_think_sig_should_be
[
20
];
if
(
(
cifs_pdu
==
NULL
)
||
(
mac_key
==
NULL
)
)
if
(
cifs_pdu
==
NULL
||
session_key
==
NULL
)
return
-
EINVAL
;
if
(
cifs_pdu
->
Command
==
SMB_COM_NEGOTIATE
)
...
...
@@ -192,7 +193,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
cpu_to_le32
(
expected_sequence_number
);
cifs_pdu
->
Signature
.
Sequence
.
Reserved
=
0
;
rc
=
cifs_calculate_signature
(
cifs_pdu
,
mac
_key
,
rc
=
cifs_calculate_signature
(
cifs_pdu
,
session
_key
,
what_we_think_sig_should_be
);
if
(
rc
)
...
...
@@ -209,7 +210,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
}
/* We fill in key by putting in 40 byte array which was allocated by caller */
int
cifs_calculate_
mac_key
(
struct
mac
_key
*
key
,
const
char
*
rn
,
int
cifs_calculate_
session_key
(
struct
session
_key
*
key
,
const
char
*
rn
,
const
char
*
password
)
{
char
temp_key
[
16
];
...
...
@@ -262,6 +263,90 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
}
#endif
/* CIFS_WEAK_PW_HASH */
/* This is just a filler for ntlmv2 type of security mechanisms.
* Older servers are not very particular about the contents of av pairs
* in the blob and for sec mechs like ntlmv2, there is no negotiation
* as in ntlmssp, so unless domain and server netbios and dns names
* are specified, there is no way to obtain name. In case of ntlmssp,
* server provides that info in type 2 challenge packet
*/
static
int
build_avpair_blob
(
struct
cifsSesInfo
*
ses
)
{
struct
ntlmssp2_name
*
attrptr
;
ses
->
tilen
=
2
*
sizeof
(
struct
ntlmssp2_name
);
ses
->
tiblob
=
kzalloc
(
ses
->
tilen
,
GFP_KERNEL
);
if
(
!
ses
->
tiblob
)
{
ses
->
tilen
=
0
;
cERROR
(
1
,
"Challenge target info allocation failure"
);
return
-
ENOMEM
;
}
attrptr
=
(
struct
ntlmssp2_name
*
)
ses
->
tiblob
;
attrptr
->
type
=
cpu_to_le16
(
NTLMSSP_DOMAIN_TYPE
);
return
0
;
}
/* Server has provided av pairs/target info in the type 2 challenge
* packet and we have plucked it and stored within smb session.
* We parse that blob here to find netbios domain name to be used
* as part of ntlmv2 authentication (in Target String), if not already
* specified on the command line.
* If this function returns without any error but without fetching
* domain name, authentication may fail against some server but
* may not fail against other (those who are not very particular
* about target string i.e. for some, just user name might suffice.
*/
static
int
find_domain_name
(
struct
cifsSesInfo
*
ses
)
{
unsigned
int
attrsize
;
unsigned
int
type
;
unsigned
int
onesize
=
sizeof
(
struct
ntlmssp2_name
);
unsigned
char
*
blobptr
;
unsigned
char
*
blobend
;
struct
ntlmssp2_name
*
attrptr
;
if
(
!
ses
->
tilen
||
!
ses
->
tiblob
)
return
0
;
blobptr
=
ses
->
tiblob
;
blobend
=
ses
->
tiblob
+
ses
->
tilen
;
while
(
blobptr
+
onesize
<
blobend
)
{
attrptr
=
(
struct
ntlmssp2_name
*
)
blobptr
;
type
=
le16_to_cpu
(
attrptr
->
type
);
if
(
type
==
NTLMSSP_AV_EOL
)
break
;
blobptr
+=
2
;
/* advance attr type */
attrsize
=
le16_to_cpu
(
attrptr
->
length
);
blobptr
+=
2
;
/* advance attr size */
if
(
blobptr
+
attrsize
>
blobend
)
break
;
if
(
type
==
NTLMSSP_AV_NB_DOMAIN_NAME
)
{
if
(
!
attrsize
)
break
;
if
(
!
ses
->
domainName
)
{
struct
nls_table
*
default_nls
;
ses
->
domainName
=
kmalloc
(
attrsize
+
1
,
GFP_KERNEL
);
if
(
!
ses
->
domainName
)
return
-
ENOMEM
;
default_nls
=
load_nls_default
();
cifs_from_ucs2
(
ses
->
domainName
,
(
__le16
*
)
blobptr
,
attrsize
,
attrsize
,
default_nls
,
false
);
unload_nls
(
default_nls
);
break
;
}
}
blobptr
+=
attrsize
;
/* advance attr value */
}
return
0
;
}
static
int
calc_ntlmv2_hash
(
struct
cifsSesInfo
*
ses
,
const
struct
nls_table
*
nls_cp
)
{
...
...
@@ -321,7 +406,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
return
rc
;
}
void
setup_ntlmv2_rsp
(
struct
cifsSesInfo
*
ses
,
char
*
resp_buf
,
int
setup_ntlmv2_rsp
(
struct
cifsSesInfo
*
ses
,
char
*
resp_buf
,
const
struct
nls_table
*
nls_cp
)
{
int
rc
;
...
...
@@ -333,25 +419,48 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
buf
->
time
=
cpu_to_le64
(
cifs_UnixTimeToNT
(
CURRENT_TIME
));
get_random_bytes
(
&
buf
->
client_chal
,
sizeof
(
buf
->
client_chal
));
buf
->
reserved2
=
0
;
buf
->
names
[
0
].
type
=
cpu_to_le16
(
NTLMSSP_DOMAIN_TYPE
);
buf
->
names
[
0
].
length
=
0
;
buf
->
names
[
1
].
type
=
0
;
buf
->
names
[
1
].
length
=
0
;
if
(
ses
->
server
->
secType
==
RawNTLMSSP
)
{
if
(
!
ses
->
domainName
)
{
rc
=
find_domain_name
(
ses
);
if
(
rc
)
{
cERROR
(
1
,
"error %d finding domain name"
,
rc
);
goto
setup_ntlmv2_rsp_ret
;
}
}
}
else
{
rc
=
build_avpair_blob
(
ses
);
if
(
rc
)
{
cERROR
(
1
,
"error %d building av pair blob"
,
rc
);
return
rc
;
}
}
/* calculate buf->ntlmv2_hash */
rc
=
calc_ntlmv2_hash
(
ses
,
nls_cp
);
if
(
rc
)
if
(
rc
)
{
cERROR
(
1
,
"could not get v2 hash rc %d"
,
rc
);
goto
setup_ntlmv2_rsp_ret
;
}
CalcNTLMv2_response
(
ses
,
resp_buf
);
/* now calculate the MAC key for NTLMv2 */
hmac_md5_init_limK_to_64
(
ses
->
server
->
ntlmv2_hash
,
16
,
&
context
);
hmac_md5_update
(
resp_buf
,
16
,
&
context
);
hmac_md5_final
(
ses
->
server
->
mac_signing
_key
.
data
.
ntlmv2
.
key
,
&
context
);
hmac_md5_final
(
ses
->
server
->
session
_key
.
data
.
ntlmv2
.
key
,
&
context
);
memcpy
(
&
ses
->
server
->
mac_signing
_key
.
data
.
ntlmv2
.
resp
,
resp_buf
,
memcpy
(
&
ses
->
server
->
session
_key
.
data
.
ntlmv2
.
resp
,
resp_buf
,
sizeof
(
struct
ntlmv2_resp
));
ses
->
server
->
mac_signing_key
.
len
=
16
+
sizeof
(
struct
ntlmv2_resp
);
ses
->
server
->
session_key
.
len
=
16
+
sizeof
(
struct
ntlmv2_resp
);
return
0
;
setup_ntlmv2_rsp_ret:
kfree
(
ses
->
tiblob
);
ses
->
tiblob
=
NULL
;
ses
->
tilen
=
0
;
return
rc
;
}
void
CalcNTLMv2_response
(
const
struct
cifsSesInfo
*
ses
,
...
...
@@ -365,6 +474,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
hmac_md5_update
(
v2_session_response
+
8
,
sizeof
(
struct
ntlmv2_resp
)
-
8
,
&
context
);
if
(
ses
->
tilen
)
hmac_md5_update
(
ses
->
tiblob
,
ses
->
tilen
,
&
context
);
hmac_md5_final
(
v2_session_response
,
&
context
);
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
fs/cifs/cifsfs.c
View file @
6ea75952
...
...
@@ -36,6 +36,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/smp_lock.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
#define DECLARE_GLOBALS_HERE
...
...
@@ -136,9 +137,6 @@ cifs_read_super(struct super_block *sb, void *data,
sb
->
s_magic
=
CIFS_MAGIC_NUMBER
;
sb
->
s_op
=
&
cifs_super_ops
;
sb
->
s_bdi
=
&
cifs_sb
->
bdi
;
/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize =
cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
sb
->
s_blocksize
=
CIFS_MAX_MSGSIZE
;
sb
->
s_blocksize_bits
=
14
;
/* default 2**14 = CIFS_MAX_MSGSIZE */
inode
=
cifs_root_iget
(
sb
,
ROOT_I
);
...
...
@@ -224,7 +222,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct
super_block
*
sb
=
dentry
->
d_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
cifsTconInfo
*
tcon
=
cifs_sb
_master_tcon
(
cifs_sb
)
;
int
rc
=
-
EOPNOTSUPP
;
int
xid
;
...
...
@@ -366,14 +364,36 @@ static int
cifs_show_options
(
struct
seq_file
*
s
,
struct
vfsmount
*
m
)
{
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
m
->
mnt_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
struct
sockaddr
*
srcaddr
;
srcaddr
=
(
struct
sockaddr
*
)
&
tcon
->
ses
->
server
->
srcaddr
;
seq_printf
(
s
,
",unc=%s"
,
tcon
->
treeName
);
if
(
tcon
->
ses
->
userName
)
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MULTIUSER
)
seq_printf
(
s
,
",multiuser"
);
else
if
(
tcon
->
ses
->
userName
)
seq_printf
(
s
,
",username=%s"
,
tcon
->
ses
->
userName
);
if
(
tcon
->
ses
->
domainName
)
seq_printf
(
s
,
",domain=%s"
,
tcon
->
ses
->
domainName
);
if
(
srcaddr
->
sa_family
!=
AF_UNSPEC
)
{
struct
sockaddr_in
*
saddr4
;
struct
sockaddr_in6
*
saddr6
;
saddr4
=
(
struct
sockaddr_in
*
)
srcaddr
;
saddr6
=
(
struct
sockaddr_in6
*
)
srcaddr
;
if
(
srcaddr
->
sa_family
==
AF_INET6
)
seq_printf
(
s
,
",srcaddr=%pI6c"
,
&
saddr6
->
sin6_addr
);
else
if
(
srcaddr
->
sa_family
==
AF_INET
)
seq_printf
(
s
,
",srcaddr=%pI4"
,
&
saddr4
->
sin_addr
.
s_addr
);
else
seq_printf
(
s
,
",srcaddr=BAD-AF:%i"
,
(
int
)(
srcaddr
->
sa_family
));
}
seq_printf
(
s
,
",uid=%d"
,
cifs_sb
->
mnt_uid
);
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_OVERR_UID
)
seq_printf
(
s
,
",forceuid"
);
...
...
@@ -422,6 +442,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
seq_printf
(
s
,
",dynperm"
);
if
(
m
->
mnt_sb
->
s_flags
&
MS_POSIXACL
)
seq_printf
(
s
,
",acl"
);
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
seq_printf
(
s
,
",mfsymlinks"
);
seq_printf
(
s
,
",rsize=%d"
,
cifs_sb
->
rsize
);
seq_printf
(
s
,
",wsize=%d"
,
cifs_sb
->
wsize
);
...
...
@@ -437,9 +459,7 @@ static void cifs_umount_begin(struct super_block *sb)
if
(
cifs_sb
==
NULL
)
return
;
tcon
=
cifs_sb
->
tcon
;
if
(
tcon
==
NULL
)
return
;
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
read_lock
(
&
cifs_tcp_ses_lock
);
if
((
tcon
->
tc_count
>
1
)
||
(
tcon
->
tidStatus
==
CifsExiting
))
{
...
...
@@ -568,6 +588,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
/* note that this is called by vfs setlease with the BKL held
although I doubt that BKL is needed here in cifs */
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
struct
cifsFileInfo
*
cfile
=
file
->
private_data
;
if
(
!
(
S_ISREG
(
inode
->
i_mode
)))
return
-
EINVAL
;
...
...
@@ -578,8 +599,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
((
arg
==
F_WRLCK
)
&&
(
CIFS_I
(
inode
)
->
clientCanCacheAll
)))
return
generic_setlease
(
file
,
arg
,
lease
);
else
if
(
CIFS_SB
(
inode
->
i_sb
)
->
tcon
->
local_lease
&&
!
CIFS_I
(
inode
)
->
clientCanCacheRead
)
else
if
(
tlink_tcon
(
cfile
->
tlink
)
->
local_lease
&&
!
CIFS_I
(
inode
)
->
clientCanCacheRead
)
/* If the server claims to support oplock on this
file, then we still need to check oplock even
if the local_lease mount option is set, but there
...
...
@@ -912,11 +933,11 @@ init_cifs(void)
rc
=
cifs_fscache_register
();
if
(
rc
)
goto
out
;
goto
out
_clean_proc
;
rc
=
cifs_init_inodecache
();
if
(
rc
)
goto
out_
clean_proc
;
goto
out_
unreg_fscache
;
rc
=
cifs_init_mids
();
if
(
rc
)
...
...
@@ -938,19 +959,19 @@ init_cifs(void)
return
0
;
#ifdef CONFIG_CIFS_UPCALL
out_unregister_filesystem:
out_unregister_filesystem:
unregister_filesystem
(
&
cifs_fs_type
);
#endif
out_destroy_request_bufs:
out_destroy_request_bufs:
cifs_destroy_request_bufs
();
out_destroy_mids:
out_destroy_mids:
cifs_destroy_mids
();
out_destroy_inodecache:
out_destroy_inodecache:
cifs_destroy_inodecache
();
out_clean_proc:
cifs_proc_clean
();
out_unreg_fscache:
cifs_fscache_unregister
();
out:
out_clean_proc:
cifs_proc_clean
();
return
rc
;
}
...
...
fs/cifs/cifsfs.h
View file @
6ea75952
...
...
@@ -104,7 +104,7 @@ extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
extern
int
cifs_symlink
(
struct
inode
*
inode
,
struct
dentry
*
direntry
,
const
char
*
symname
);
extern
int
cifs_removexattr
(
struct
dentry
*
,
const
char
*
);
extern
int
cifs_setxattr
(
struct
dentry
*
,
const
char
*
,
const
void
*
,
extern
int
cifs_setxattr
(
struct
dentry
*
,
const
char
*
,
const
void
*
,
size_t
,
int
);
extern
ssize_t
cifs_getxattr
(
struct
dentry
*
,
const
char
*
,
void
*
,
size_t
);
extern
ssize_t
cifs_listxattr
(
struct
dentry
*
,
char
*
,
size_t
);
...
...
fs/cifs/cifsglob.h
View file @
6ea75952
...
...
@@ -97,7 +97,7 @@ enum protocolEnum {
/* Netbios frames protocol not supported at this time */
};
struct
mac
_key
{
struct
session
_key
{
unsigned
int
len
;
union
{
char
ntlm
[
CIFS_SESS_KEY_SIZE
+
16
];
...
...
@@ -139,6 +139,7 @@ struct TCP_Server_Info {
struct
sockaddr_in
sockAddr
;
struct
sockaddr_in6
sockAddr6
;
}
addr
;
struct
sockaddr_storage
srcaddr
;
/* locally bind to this IP */
wait_queue_head_t
response_q
;
wait_queue_head_t
request_q
;
/* if more than maxmpx to srvr must block*/
struct
list_head
pending_mid_q
;
...
...
@@ -182,7 +183,7 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */
char
workstation_RFC1001_name
[
RFC1001_NAME_LEN_WITH_NULL
];
__u32
sequence_number
;
/* needed for CIFS PDU signature */
struct
mac_key
mac_signing
_key
;
struct
session_key
session
_key
;
char
ntlmv2_hash
[
16
];
unsigned
long
lstrp
;
/* when we got last response from this server */
u16
dialect
;
/* dialect index that server chose */
...
...
@@ -222,6 +223,8 @@ struct cifsSesInfo {
char
userName
[
MAX_USERNAME_SIZE
+
1
];
char
*
domainName
;
char
*
password
;
unsigned
int
tilen
;
/* length of the target info blob */
unsigned
char
*
tiblob
;
/* target info blob in challenge response */
bool
need_reconnect
:
1
;
/* connection reset, uid now invalid */
};
/* no more than one of the following three session flags may be set */
...
...
@@ -307,6 +310,44 @@ struct cifsTconInfo {
/* BB add field for back pointer to sb struct(s)? */
};
/*
* This is a refcounted and timestamped container for a tcon pointer. The
* container holds a tcon reference. It is considered safe to free one of
* these when the tl_count goes to 0. The tl_time is the time of the last
* "get" on the container.
*/
struct
tcon_link
{
unsigned
long
tl_index
;
unsigned
long
tl_flags
;
#define TCON_LINK_MASTER 0
#define TCON_LINK_PENDING 1
#define TCON_LINK_IN_TREE 2
unsigned
long
tl_time
;
atomic_t
tl_count
;
struct
cifsTconInfo
*
tl_tcon
;
};
extern
struct
tcon_link
*
cifs_sb_tlink
(
struct
cifs_sb_info
*
cifs_sb
);
static
inline
struct
cifsTconInfo
*
tlink_tcon
(
struct
tcon_link
*
tlink
)
{
return
tlink
->
tl_tcon
;
}
extern
void
cifs_put_tlink
(
struct
tcon_link
*
tlink
);
static
inline
struct
tcon_link
*
cifs_get_tlink
(
struct
tcon_link
*
tlink
)
{
if
(
tlink
&&
!
IS_ERR
(
tlink
))
atomic_inc
(
&
tlink
->
tl_count
);
return
tlink
;
}
/* This function is always expected to succeed */
extern
struct
cifsTconInfo
*
cifs_sb_master_tcon
(
struct
cifs_sb_info
*
cifs_sb
);
/*
* This info hangs off the cifsFileInfo structure, pointed to by llist.
* This is used to track byte stream locks on the file
...
...
@@ -348,6 +389,7 @@ struct cifsFileInfo {
struct
file
*
pfile
;
/* needed for writepage */
struct
inode
*
pInode
;
/* needed for oplock break */
struct
vfsmount
*
mnt
;
struct
tcon_link
*
tlink
;
struct
mutex
lock_mutex
;
struct
list_head
llist
;
/* list of byte range locks we have. */
bool
closePend
:
1
;
/* file is marked to close */
...
...
@@ -369,6 +411,7 @@ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
static
inline
void
cifsFileInfo_put
(
struct
cifsFileInfo
*
cifs_file
)
{
if
(
atomic_dec_and_test
(
&
cifs_file
->
count
))
{
cifs_put_tlink
(
cifs_file
->
tlink
);
iput
(
cifs_file
->
pInode
);
kfree
(
cifs_file
);
}
...
...
@@ -474,16 +517,16 @@ struct oplock_q_entry {
/* 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
;
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
;
};
struct
dfs_info3_param
{
...
...
fs/cifs/cifspdu.h
View file @
6ea75952
...
...
@@ -663,7 +663,6 @@ struct ntlmv2_resp {
__le64
time
;
__u64
client_chal
;
/* random */
__u32
reserved2
;
struct
ntlmssp2_name
names
[
2
];
/* array of name entries could follow ending in minimum 4 byte struct */
}
__attribute__
((
packed
));
...
...
fs/cifs/cifsproto.h
View file @
6ea75952
...
...
@@ -78,9 +78,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern
bool
is_valid_oplock_break
(
struct
smb_hdr
*
smb
,
struct
TCP_Server_Info
*
);
extern
bool
is_size_safe_to_change
(
struct
cifsInodeInfo
*
,
__u64
eof
);
extern
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
);
extern
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
,
bool
);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern
struct
cifsFileInfo
*
find_readable_file
(
struct
cifsInodeInfo
*
);
extern
struct
cifsFileInfo
*
find_readable_file
(
struct
cifsInodeInfo
*
,
bool
);
#endif
extern
unsigned
int
smbCalcSize
(
struct
smb_hdr
*
ptr
);
extern
unsigned
int
smbCalcSize_LE
(
struct
smb_hdr
*
ptr
);
...
...
@@ -107,7 +107,8 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
extern
struct
cifsFileInfo
*
cifs_new_fileinfo
(
struct
inode
*
newinode
,
__u16
fileHandle
,
struct
file
*
file
,
struct
vfsmount
*
mnt
,
unsigned
int
oflags
);
struct
vfsmount
*
mnt
,
struct
tcon_link
*
tlink
,
unsigned
int
oflags
,
__u32
oplock
);
extern
int
cifs_posix_open
(
char
*
full_path
,
struct
inode
**
pinode
,
struct
super_block
*
sb
,
int
mode
,
int
oflags
,
...
...
@@ -362,12 +363,12 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
extern
int
cifs_sign_smb2
(
struct
kvec
*
iov
,
int
n_vec
,
struct
TCP_Server_Info
*
,
__u32
*
);
extern
int
cifs_verify_signature
(
struct
smb_hdr
*
,
const
struct
mac_key
*
mac
_key
,
const
struct
session_key
*
session
_key
,
__u32
expected_sequence_number
);
extern
int
cifs_calculate_
mac_key
(
struct
mac
_key
*
key
,
const
char
*
rn
,
extern
int
cifs_calculate_
session_key
(
struct
session
_key
*
key
,
const
char
*
rn
,
const
char
*
pass
);
extern
void
CalcNTLMv2_response
(
const
struct
cifsSesInfo
*
,
char
*
);
extern
void
setup_ntlmv2_rsp
(
struct
cifsSesInfo
*
,
char
*
,
extern
int
setup_ntlmv2_rsp
(
struct
cifsSesInfo
*
,
char
*
,
const
struct
nls_table
*
);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern
void
calc_lanman_hash
(
const
char
*
password
,
const
char
*
cryptkey
,
...
...
@@ -408,4 +409,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
extern
int
CIFSGetExtAttr
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
netfid
,
__u64
*
pExtAttrBits
,
__u64
*
pMask
);
extern
void
cifs_autodisable_serverino
(
struct
cifs_sb_info
*
cifs_sb
);
extern
bool
CIFSCouldBeMFSymlink
(
const
struct
cifs_fattr
*
fattr
);
extern
int
CIFSCheckMFSymlink
(
struct
cifs_fattr
*
fattr
,
const
unsigned
char
*
path
,
struct
cifs_sb_info
*
cifs_sb
,
int
xid
);
#endif
/* _CIFSPROTO_H */
fs/cifs/cifssmb.c
View file @
6ea75952
...
...
@@ -620,13 +620,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc
=
0
;
else
rc
=
-
EINVAL
;
if
(
server
->
sec_kerberos
||
server
->
sec_mskerberos
)
server
->
secType
=
Kerberos
;
else
if
(
server
->
sec_ntlmssp
)
server
->
secType
=
RawNTLMSSP
;
else
rc
=
-
EOPNOTSUPP
;
if
(
server
->
secType
==
Kerberos
)
{
if
(
!
server
->
sec_kerberos
&&
!
server
->
sec_mskerberos
)
rc
=
-
EOPNOTSUPP
;
}
else
if
(
server
->
secType
==
RawNTLMSSP
)
{
if
(
!
server
->
sec_ntlmssp
)
rc
=
-
EOPNOTSUPP
;
}
else
rc
=
-
EOPNOTSUPP
;
}
}
else
server
->
capabilities
&=
~
CAP_EXTENDED_SECURITY
;
...
...
fs/cifs/cn_cifs.h
deleted
100644 → 0
View file @
6b0cd00b
/*
* fs/cifs/cn_cifs.h
*
* Copyright (c) International Business Machines Corp., 2002
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CN_CIFS_H
#define _CN_CIFS_H
#ifdef CONFIG_CIFS_UPCALL
#include <linux/types.h>
#include <linux/connector.h>
struct
cifs_upcall
{
char
signature
[
4
];
/* CIFS */
enum
command
{
CIFS_GET_IP
=
0x00000001
,
/* get ip address for hostname */
CIFS_GET_SECBLOB
=
0x00000002
,
/* get SPNEGO wrapped blob */
}
command
;
/* union cifs upcall data follows */
};
#endif
/* CIFS_UPCALL */
#endif
/* _CN_CIFS_H */
fs/cifs/connect.c
View file @
6ea75952
...
...
@@ -47,7 +47,6 @@
#include "ntlmssp.h"
#include "nterr.h"
#include "rfc1002pdu.h"
#include "cn_cifs.h"
#include "fscache.h"
#define CIFS_PORT 445
...
...
@@ -100,16 +99,24 @@ struct smb_vol {
bool
noautotune
:
1
;
bool
nostrictsync
:
1
;
/* do not force expensive SMBflush on every sync */
bool
fsc
:
1
;
/* enable fscache */
bool
mfsymlinks
:
1
;
/* use Minshall+French Symlinks */
bool
multiuser
:
1
;
unsigned
int
rsize
;
unsigned
int
wsize
;
bool
sockopt_tcp_nodelay
:
1
;
unsigned
short
int
port
;
char
*
prepath
;
struct
sockaddr_storage
srcaddr
;
/* allow binding to a local IP */
struct
nls_table
*
local_nls
;
};
/* FIXME: should these be tunable? */
#define TLINK_ERROR_EXPIRE (1 * HZ)
#define TLINK_IDLE_EXPIRE (600 * HZ)
static
int
ipv4_connect
(
struct
TCP_Server_Info
*
server
);
static
int
ipv6_connect
(
struct
TCP_Server_Info
*
server
);
static
void
cifs_prune_tlinks
(
struct
work_struct
*
work
);
/*
* cifs tcp session reconnection
...
...
@@ -1046,6 +1053,22 @@ cifs_parse_mount_options(char *options, const char *devname,
"long
\n
"
);
return
1
;
}
}
else
if
(
strnicmp
(
data
,
"srcaddr"
,
7
)
==
0
)
{
vol
->
srcaddr
.
ss_family
=
AF_UNSPEC
;
if
(
!
value
||
!*
value
)
{
printk
(
KERN_WARNING
"CIFS: srcaddr value"
" not specified.
\n
"
);
return
1
;
/* needs_arg; */
}
i
=
cifs_convert_address
((
struct
sockaddr
*
)
&
vol
->
srcaddr
,
value
,
strlen
(
value
));
if
(
i
<
0
)
{
printk
(
KERN_WARNING
"CIFS: Could not parse"
" srcaddr: %s
\n
"
,
value
);
return
1
;
}
}
else
if
(
strnicmp
(
data
,
"prefixpath"
,
10
)
==
0
)
{
if
(
!
value
||
!*
value
)
{
printk
(
KERN_WARNING
...
...
@@ -1325,6 +1348,10 @@ cifs_parse_mount_options(char *options, const char *devname,
"/proc/fs/cifs/LookupCacheEnabled to 0
\n
"
);
}
else
if
(
strnicmp
(
data
,
"fsc"
,
3
)
==
0
)
{
vol
->
fsc
=
true
;
}
else
if
(
strnicmp
(
data
,
"mfsymlinks"
,
10
)
==
0
)
{
vol
->
mfsymlinks
=
true
;
}
else
if
(
strnicmp
(
data
,
"multiuser"
,
8
)
==
0
)
{
vol
->
multiuser
=
true
;
}
else
printk
(
KERN_WARNING
"CIFS: Unknown mount option %s
\n
"
,
data
);
...
...
@@ -1356,6 +1383,13 @@ cifs_parse_mount_options(char *options, const char *devname,
return
1
;
}
}
if
(
vol
->
multiuser
&&
!
(
vol
->
secFlg
&
CIFSSEC_MAY_KRB5
))
{
cERROR
(
1
,
"Multiuser mounts currently require krb5 "
"authentication!"
);
return
1
;
}
if
(
vol
->
UNCip
==
NULL
)
vol
->
UNCip
=
&
vol
->
UNC
[
2
];
...
...
@@ -1374,8 +1408,36 @@ cifs_parse_mount_options(char *options, const char *devname,
return
0
;
}
/** Returns true if srcaddr isn't specified and rhs isn't
* specified, or if srcaddr is specified and
* matches the IP address of the rhs argument.
*/
static
bool
match_address
(
struct
TCP_Server_Info
*
server
,
struct
sockaddr
*
addr
)
srcip_matches
(
struct
sockaddr
*
srcaddr
,
struct
sockaddr
*
rhs
)
{
switch
(
srcaddr
->
sa_family
)
{
case
AF_UNSPEC
:
return
(
rhs
->
sa_family
==
AF_UNSPEC
);
case
AF_INET
:
{
struct
sockaddr_in
*
saddr4
=
(
struct
sockaddr_in
*
)
srcaddr
;
struct
sockaddr_in
*
vaddr4
=
(
struct
sockaddr_in
*
)
rhs
;
return
(
saddr4
->
sin_addr
.
s_addr
==
vaddr4
->
sin_addr
.
s_addr
);
}
case
AF_INET6
:
{
struct
sockaddr_in6
*
saddr6
=
(
struct
sockaddr_in6
*
)
srcaddr
;
struct
sockaddr_in6
*
vaddr6
=
(
struct
sockaddr_in6
*
)
&
rhs
;
return
ipv6_addr_equal
(
&
saddr6
->
sin6_addr
,
&
vaddr6
->
sin6_addr
);
}
default:
WARN_ON
(
1
);
return
false
;
/* don't expect to be here */
}
}
static
bool
match_address
(
struct
TCP_Server_Info
*
server
,
struct
sockaddr
*
addr
,
struct
sockaddr
*
srcaddr
)
{
struct
sockaddr_in
*
addr4
=
(
struct
sockaddr_in
*
)
addr
;
struct
sockaddr_in6
*
addr6
=
(
struct
sockaddr_in6
*
)
addr
;
...
...
@@ -1402,6 +1464,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
break
;
}
if
(
!
srcip_matches
(
srcaddr
,
(
struct
sockaddr
*
)
&
server
->
srcaddr
))
return
false
;
return
true
;
}
...
...
@@ -1460,16 +1525,8 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
write_lock
(
&
cifs_tcp_ses_lock
);
list_for_each_entry
(
server
,
&
cifs_tcp_ses_list
,
tcp_ses_list
)
{
/*
* the demux thread can exit on its own while still in CifsNew
* so don't accept any sockets in that state. Since the
* tcpStatus never changes back to CifsNew it's safe to check
* for this without a lock.
*/
if
(
server
->
tcpStatus
==
CifsNew
)
continue
;
if
(
!
match_address
(
server
,
addr
))
if
(
!
match_address
(
server
,
addr
,
(
struct
sockaddr
*
)
&
vol
->
srcaddr
))
continue
;
if
(
!
match_security
(
server
,
vol
))
...
...
@@ -1584,6 +1641,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
* no need to spinlock this init of tcpStatus or srv_count
*/
tcp_ses
->
tcpStatus
=
CifsNew
;
memcpy
(
&
tcp_ses
->
srcaddr
,
&
volume_info
->
srcaddr
,
sizeof
(
tcp_ses
->
srcaddr
));
++
tcp_ses
->
srv_count
;
if
(
addr
.
ss_family
==
AF_INET6
)
{
...
...
@@ -1740,6 +1799,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
if
(
ses
==
NULL
)
goto
get_ses_fail
;
ses
->
tilen
=
0
;
ses
->
tiblob
=
NULL
;
/* new SMB session uses our server ref */
ses
->
server
=
server
;
if
(
server
->
addr
.
sockAddr6
.
sin6_family
==
AF_INET6
)
...
...
@@ -1913,6 +1974,23 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
return
ERR_PTR
(
rc
);
}
void
cifs_put_tlink
(
struct
tcon_link
*
tlink
)
{
if
(
!
tlink
||
IS_ERR
(
tlink
))
return
;
if
(
!
atomic_dec_and_test
(
&
tlink
->
tl_count
)
||
test_bit
(
TCON_LINK_IN_TREE
,
&
tlink
->
tl_flags
))
{
tlink
->
tl_time
=
jiffies
;
return
;
}
if
(
!
IS_ERR
(
tlink_tcon
(
tlink
)))
cifs_put_tcon
(
tlink_tcon
(
tlink
));
kfree
(
tlink
);
return
;
}
int
get_dfs_path
(
int
xid
,
struct
cifsSesInfo
*
pSesInfo
,
const
char
*
old_path
,
...
...
@@ -1997,6 +2075,33 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
}
static
int
bind_socket
(
struct
TCP_Server_Info
*
server
)
{
int
rc
=
0
;
if
(
server
->
srcaddr
.
ss_family
!=
AF_UNSPEC
)
{
/* Bind to the specified local IP address */
struct
socket
*
socket
=
server
->
ssocket
;
rc
=
socket
->
ops
->
bind
(
socket
,
(
struct
sockaddr
*
)
&
server
->
srcaddr
,
sizeof
(
server
->
srcaddr
));
if
(
rc
<
0
)
{
struct
sockaddr_in
*
saddr4
;
struct
sockaddr_in6
*
saddr6
;
saddr4
=
(
struct
sockaddr_in
*
)
&
server
->
srcaddr
;
saddr6
=
(
struct
sockaddr_in6
*
)
&
server
->
srcaddr
;
if
(
saddr6
->
sin6_family
==
AF_INET6
)
cERROR
(
1
,
"cifs: "
"Failed to bind to: %pI6c, error: %d
\n
"
,
&
saddr6
->
sin6_addr
,
rc
);
else
cERROR
(
1
,
"cifs: "
"Failed to bind to: %pI4, error: %d
\n
"
,
&
saddr4
->
sin_addr
.
s_addr
,
rc
);
}
}
return
rc
;
}
static
int
ipv4_connect
(
struct
TCP_Server_Info
*
server
)
...
...
@@ -2022,6 +2127,10 @@ ipv4_connect(struct TCP_Server_Info *server)
cifs_reclassify_socket4
(
socket
);
}
rc
=
bind_socket
(
server
);
if
(
rc
<
0
)
return
rc
;
/* user overrode default port */
if
(
server
->
addr
.
sockAddr
.
sin_port
)
{
rc
=
socket
->
ops
->
connect
(
socket
,
(
struct
sockaddr
*
)
...
...
@@ -2184,6 +2293,10 @@ ipv6_connect(struct TCP_Server_Info *server)
cifs_reclassify_socket6
(
socket
);
}
rc
=
bind_socket
(
server
);
if
(
rc
<
0
)
return
rc
;
/* user overrode default port */
if
(
server
->
addr
.
sockAddr6
.
sin6_port
)
{
rc
=
socket
->
ops
->
connect
(
socket
,
...
...
@@ -2383,6 +2496,8 @@ convert_delimiter(char *path, char delim)
static
void
setup_cifs_sb
(
struct
smb_vol
*
pvolume_info
,
struct
cifs_sb_info
*
cifs_sb
)
{
INIT_DELAYED_WORK
(
&
cifs_sb
->
prune_tlinks
,
cifs_prune_tlinks
);
if
(
pvolume_info
->
rsize
>
CIFSMaxBufSize
)
{
cERROR
(
1
,
"rsize %d too large, using MaxBufSize"
,
pvolume_info
->
rsize
);
...
...
@@ -2462,10 +2577,21 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DYNPERM
;
if
(
pvolume_info
->
fsc
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_FSCACHE
;
if
(
pvolume_info
->
multiuser
)
cifs_sb
->
mnt_cifs_flags
|=
(
CIFS_MOUNT_MULTIUSER
|
CIFS_MOUNT_NO_PERM
);
if
(
pvolume_info
->
direct_io
)
{
cFYI
(
1
,
"mounting share using direct i/o"
);
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DIRECT_IO
;
}
if
(
pvolume_info
->
mfsymlinks
)
{
if
(
pvolume_info
->
sfu_emul
)
{
cERROR
(
1
,
"mount option mfsymlinks ignored if sfu "
"mount option is used"
);
}
else
{
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_MF_SYMLINKS
;
}
}
if
((
pvolume_info
->
cifs_acl
)
&&
(
pvolume_info
->
dynperm
))
cERROR
(
1
,
"mount option dynperm ignored if cifsacl "
...
...
@@ -2552,6 +2678,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
struct
TCP_Server_Info
*
srvTcp
;
char
*
full_path
;
char
*
mount_data
=
mount_data_global
;
struct
tcon_link
*
tlink
;
#ifdef CONFIG_CIFS_DFS_UPCALL
struct
dfs_info3_param
*
referrals
=
NULL
;
unsigned
int
num_referrals
=
0
;
...
...
@@ -2563,6 +2690,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo
=
NULL
;
srvTcp
=
NULL
;
full_path
=
NULL
;
tlink
=
NULL
;
xid
=
GetXid
();
...
...
@@ -2638,8 +2766,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
goto
remote_path_check
;
}
cifs_sb
->
tcon
=
tcon
;
/* do not care if following two calls succeed - informational */
if
(
!
tcon
->
ipc
)
{
CIFSSMBQFSDeviceInfo
(
xid
,
tcon
);
...
...
@@ -2748,6 +2874,38 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
#endif
}
if
(
rc
)
goto
mount_fail_check
;
/* now, hang the tcon off of the superblock */
tlink
=
kzalloc
(
sizeof
*
tlink
,
GFP_KERNEL
);
if
(
tlink
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
mount_fail_check
;
}
tlink
->
tl_index
=
pSesInfo
->
linux_uid
;
tlink
->
tl_tcon
=
tcon
;
tlink
->
tl_time
=
jiffies
;
set_bit
(
TCON_LINK_MASTER
,
&
tlink
->
tl_flags
);
set_bit
(
TCON_LINK_IN_TREE
,
&
tlink
->
tl_flags
);
rc
=
radix_tree_preload
(
GFP_KERNEL
);
if
(
rc
==
-
ENOMEM
)
{
kfree
(
tlink
);
goto
mount_fail_check
;
}
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
radix_tree_insert
(
&
cifs_sb
->
tlink_tree
,
pSesInfo
->
linux_uid
,
tlink
);
radix_tree_tag_set
(
&
cifs_sb
->
tlink_tree
,
pSesInfo
->
linux_uid
,
CIFS_TLINK_MASTER_TAG
);
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
radix_tree_preload_end
();
queue_delayed_work
(
system_nrt_wq
,
&
cifs_sb
->
prune_tlinks
,
TLINK_IDLE_EXPIRE
);
mount_fail_check:
/* on error free sesinfo and tcon struct if needed */
if
(
rc
)
{
...
...
@@ -2934,19 +3092,39 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
int
cifs_umount
(
struct
super_block
*
sb
,
struct
cifs_sb_info
*
cifs_sb
)
{
int
rc
=
0
;
int
i
,
ret
;
char
*
tmp
;
struct
tcon_link
*
tlink
[
8
];
unsigned
long
index
=
0
;
cancel_delayed_work_sync
(
&
cifs_sb
->
prune_tlinks
);
do
{
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
ret
=
radix_tree_gang_lookup
(
&
cifs_sb
->
tlink_tree
,
(
void
**
)
tlink
,
index
,
ARRAY_SIZE
(
tlink
));
/* increment index for next pass */
if
(
ret
>
0
)
index
=
tlink
[
ret
-
1
]
->
tl_index
+
1
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
cifs_get_tlink
(
tlink
[
i
]);
clear_bit
(
TCON_LINK_IN_TREE
,
&
tlink
[
i
]
->
tl_flags
);
radix_tree_delete
(
&
cifs_sb
->
tlink_tree
,
tlink
[
i
]
->
tl_index
);
}
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
if
(
cifs_sb
->
tcon
)
cifs_put_tcon
(
cifs_sb
->
tcon
);
for
(
i
=
0
;
i
<
ret
;
i
++
)
cifs_put_tlink
(
tlink
[
i
]);
}
while
(
ret
!=
0
);
cifs_sb
->
tcon
=
NULL
;
tmp
=
cifs_sb
->
prepath
;
cifs_sb
->
prepathlen
=
0
;
cifs_sb
->
prepath
=
NULL
;
kfree
(
tmp
);
return
rc
;
return
0
;
}
int
cifs_negotiate_protocol
(
unsigned
int
xid
,
struct
cifsSesInfo
*
ses
)
...
...
@@ -3007,3 +3185,237 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
return
rc
;
}
static
struct
cifsTconInfo
*
cifs_construct_tcon
(
struct
cifs_sb_info
*
cifs_sb
,
uid_t
fsuid
)
{
struct
cifsTconInfo
*
master_tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
=
NULL
;
struct
smb_vol
*
vol_info
;
char
username
[
MAX_USERNAME_SIZE
+
1
];
vol_info
=
kzalloc
(
sizeof
(
*
vol_info
),
GFP_KERNEL
);
if
(
vol_info
==
NULL
)
{
tcon
=
ERR_PTR
(
-
ENOMEM
);
goto
out
;
}
snprintf
(
username
,
MAX_USERNAME_SIZE
,
"krb50x%x"
,
fsuid
);
vol_info
->
username
=
username
;
vol_info
->
local_nls
=
cifs_sb
->
local_nls
;
vol_info
->
linux_uid
=
fsuid
;
vol_info
->
cred_uid
=
fsuid
;
vol_info
->
UNC
=
master_tcon
->
treeName
;
vol_info
->
retry
=
master_tcon
->
retry
;
vol_info
->
nocase
=
master_tcon
->
nocase
;
vol_info
->
local_lease
=
master_tcon
->
local_lease
;
vol_info
->
no_linux_ext
=
!
master_tcon
->
unix_ext
;
/* FIXME: allow for other secFlg settings */
vol_info
->
secFlg
=
CIFSSEC_MUST_KRB5
;
/* get a reference for the same TCP session */
write_lock
(
&
cifs_tcp_ses_lock
);
++
master_tcon
->
ses
->
server
->
srv_count
;
write_unlock
(
&
cifs_tcp_ses_lock
);
ses
=
cifs_get_smb_ses
(
master_tcon
->
ses
->
server
,
vol_info
);
if
(
IS_ERR
(
ses
))
{
tcon
=
(
struct
cifsTconInfo
*
)
ses
;
cifs_put_tcp_session
(
master_tcon
->
ses
->
server
);
goto
out
;
}
tcon
=
cifs_get_tcon
(
ses
,
vol_info
);
if
(
IS_ERR
(
tcon
))
{
cifs_put_smb_ses
(
ses
);
goto
out
;
}
if
(
ses
->
capabilities
&
CAP_UNIX
)
reset_cifs_unix_caps
(
0
,
tcon
,
NULL
,
vol_info
);
out:
kfree
(
vol_info
);
return
tcon
;
}
static
struct
tcon_link
*
cifs_sb_master_tlink
(
struct
cifs_sb_info
*
cifs_sb
)
{
struct
tcon_link
*
tlink
;
unsigned
int
ret
;
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
ret
=
radix_tree_gang_lookup_tag
(
&
cifs_sb
->
tlink_tree
,
(
void
**
)
&
tlink
,
0
,
1
,
CIFS_TLINK_MASTER_TAG
);
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
/* the master tcon should always be present */
if
(
ret
==
0
)
BUG
();
return
tlink
;
}
struct
cifsTconInfo
*
cifs_sb_master_tcon
(
struct
cifs_sb_info
*
cifs_sb
)
{
return
tlink_tcon
(
cifs_sb_master_tlink
(
cifs_sb
));
}
static
int
cifs_sb_tcon_pending_wait
(
void
*
unused
)
{
schedule
();
return
signal_pending
(
current
)
?
-
ERESTARTSYS
:
0
;
}
/*
* Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
* current task.
*
* If the superblock doesn't refer to a multiuser mount, then just return
* the master tcon for the mount.
*
* First, search the radix tree for an existing tcon for this fsuid. If one
* exists, then check to see if it's pending construction. If it is then wait
* for construction to complete. Once it's no longer pending, check to see if
* it failed and either return an error or retry construction, depending on
* the timeout.
*
* If one doesn't exist then insert a new tcon_link struct into the tree and
* try to construct a new one.
*/
struct
tcon_link
*
cifs_sb_tlink
(
struct
cifs_sb_info
*
cifs_sb
)
{
int
ret
;
unsigned
long
fsuid
=
(
unsigned
long
)
current_fsuid
();
struct
tcon_link
*
tlink
,
*
newtlink
;
if
(
!
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MULTIUSER
))
return
cifs_get_tlink
(
cifs_sb_master_tlink
(
cifs_sb
));
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
tlink
=
radix_tree_lookup
(
&
cifs_sb
->
tlink_tree
,
fsuid
);
if
(
tlink
)
cifs_get_tlink
(
tlink
);
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
if
(
tlink
==
NULL
)
{
newtlink
=
kzalloc
(
sizeof
(
*
tlink
),
GFP_KERNEL
);
if
(
newtlink
==
NULL
)
return
ERR_PTR
(
-
ENOMEM
);
newtlink
->
tl_index
=
fsuid
;
newtlink
->
tl_tcon
=
ERR_PTR
(
-
EACCES
);
set_bit
(
TCON_LINK_PENDING
,
&
newtlink
->
tl_flags
);
set_bit
(
TCON_LINK_IN_TREE
,
&
newtlink
->
tl_flags
);
cifs_get_tlink
(
newtlink
);
ret
=
radix_tree_preload
(
GFP_KERNEL
);
if
(
ret
!=
0
)
{
kfree
(
newtlink
);
return
ERR_PTR
(
ret
);
}
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
/* was one inserted after previous search? */
tlink
=
radix_tree_lookup
(
&
cifs_sb
->
tlink_tree
,
fsuid
);
if
(
tlink
)
{
cifs_get_tlink
(
tlink
);
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
radix_tree_preload_end
();
kfree
(
newtlink
);
goto
wait_for_construction
;
}
ret
=
radix_tree_insert
(
&
cifs_sb
->
tlink_tree
,
fsuid
,
newtlink
);
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
radix_tree_preload_end
();
if
(
ret
)
{
kfree
(
newtlink
);
return
ERR_PTR
(
ret
);
}
tlink
=
newtlink
;
}
else
{
wait_for_construction:
ret
=
wait_on_bit
(
&
tlink
->
tl_flags
,
TCON_LINK_PENDING
,
cifs_sb_tcon_pending_wait
,
TASK_INTERRUPTIBLE
);
if
(
ret
)
{
cifs_put_tlink
(
tlink
);
return
ERR_PTR
(
ret
);
}
/* if it's good, return it */
if
(
!
IS_ERR
(
tlink
->
tl_tcon
))
return
tlink
;
/* return error if we tried this already recently */
if
(
time_before
(
jiffies
,
tlink
->
tl_time
+
TLINK_ERROR_EXPIRE
))
{
cifs_put_tlink
(
tlink
);
return
ERR_PTR
(
-
EACCES
);
}
if
(
test_and_set_bit
(
TCON_LINK_PENDING
,
&
tlink
->
tl_flags
))
goto
wait_for_construction
;
}
tlink
->
tl_tcon
=
cifs_construct_tcon
(
cifs_sb
,
fsuid
);
clear_bit
(
TCON_LINK_PENDING
,
&
tlink
->
tl_flags
);
wake_up_bit
(
&
tlink
->
tl_flags
,
TCON_LINK_PENDING
);
if
(
IS_ERR
(
tlink
->
tl_tcon
))
{
cifs_put_tlink
(
tlink
);
return
ERR_PTR
(
-
EACCES
);
}
return
tlink
;
}
/*
* periodic workqueue job that scans tcon_tree for a superblock and closes
* out tcons.
*/
static
void
cifs_prune_tlinks
(
struct
work_struct
*
work
)
{
struct
cifs_sb_info
*
cifs_sb
=
container_of
(
work
,
struct
cifs_sb_info
,
prune_tlinks
.
work
);
struct
tcon_link
*
tlink
[
8
];
unsigned
long
now
=
jiffies
;
unsigned
long
index
=
0
;
int
i
,
ret
;
do
{
spin_lock
(
&
cifs_sb
->
tlink_tree_lock
);
ret
=
radix_tree_gang_lookup
(
&
cifs_sb
->
tlink_tree
,
(
void
**
)
tlink
,
index
,
ARRAY_SIZE
(
tlink
));
/* increment index for next pass */
if
(
ret
>
0
)
index
=
tlink
[
ret
-
1
]
->
tl_index
+
1
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
if
(
test_bit
(
TCON_LINK_MASTER
,
&
tlink
[
i
]
->
tl_flags
)
||
atomic_read
(
&
tlink
[
i
]
->
tl_count
)
!=
0
||
time_after
(
tlink
[
i
]
->
tl_time
+
TLINK_IDLE_EXPIRE
,
now
))
{
tlink
[
i
]
=
NULL
;
continue
;
}
cifs_get_tlink
(
tlink
[
i
]);
clear_bit
(
TCON_LINK_IN_TREE
,
&
tlink
[
i
]
->
tl_flags
);
radix_tree_delete
(
&
cifs_sb
->
tlink_tree
,
tlink
[
i
]
->
tl_index
);
}
spin_unlock
(
&
cifs_sb
->
tlink_tree_lock
);
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
if
(
tlink
[
i
]
!=
NULL
)
cifs_put_tlink
(
tlink
[
i
]);
}
}
while
(
ret
!=
0
);
queue_delayed_work
(
system_nrt_wq
,
&
cifs_sb
->
prune_tlinks
,
TLINK_IDLE_EXPIRE
);
}
fs/cifs/dir.c
View file @
6ea75952
...
...
@@ -54,18 +54,18 @@ build_path_from_dentry(struct dentry *direntry)
int
dfsplen
;
char
*
full_path
;
char
dirsep
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
direntry
->
d_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
if
(
direntry
==
NULL
)
return
NULL
;
/* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly
when the server crashed */
cifs_sb
=
CIFS_SB
(
direntry
->
d_sb
);
dirsep
=
CIFS_DIR_SEP
(
cifs_sb
);
pplen
=
cifs_sb
->
prepathlen
;
if
(
cifs_sb
->
tcon
&&
(
cifs_sb
->
tcon
->
Flags
&
SMB_SHARE_IS_IN_DFS
)
)
dfsplen
=
strnlen
(
cifs_sb
->
tcon
->
treeName
,
MAX_TREE_SIZE
+
1
);
if
(
tcon
->
Flags
&
SMB_SHARE_IS_IN_DFS
)
dfsplen
=
strnlen
(
tcon
->
treeName
,
MAX_TREE_SIZE
+
1
);
else
dfsplen
=
0
;
cifs_bp_rename_retry:
...
...
@@ -117,7 +117,7 @@ build_path_from_dentry(struct dentry *direntry)
/* BB test paths to Windows with '/' in the midst of prepath */
if
(
dfsplen
)
{
strncpy
(
full_path
,
cifs_sb
->
tcon
->
treeName
,
dfsplen
);
strncpy
(
full_path
,
tcon
->
treeName
,
dfsplen
);
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_POSIX_PATHS
)
{
int
i
;
for
(
i
=
0
;
i
<
dfsplen
;
i
++
)
{
...
...
@@ -131,28 +131,26 @@ build_path_from_dentry(struct dentry *direntry)
}
struct
cifsFileInfo
*
cifs_new_fileinfo
(
struct
inode
*
newinode
,
__u16
fileHandle
,
struct
file
*
file
,
struct
vfsmount
*
mnt
,
unsigned
int
oflags
)
cifs_new_fileinfo
(
struct
inode
*
newinode
,
__u16
fileHandle
,
struct
file
*
file
,
struct
vfsmount
*
mnt
,
struct
tcon_link
*
tlink
,
unsigned
int
oflags
,
__u32
oplock
)
{
int
oplock
=
0
;
struct
cifsFileInfo
*
pCifsFile
;
struct
cifsInodeInfo
*
pCifsInode
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
mnt
->
mnt_sb
);
pCifsFile
=
kzalloc
(
sizeof
(
struct
cifsFileInfo
),
GFP_KERNEL
);
if
(
pCifsFile
==
NULL
)
return
pCifsFile
;
if
(
oplockEnabled
)
oplock
=
REQ_OPLOCK
;
pCifsFile
->
netfid
=
fileHandle
;
pCifsFile
->
pid
=
current
->
tgid
;
pCifsFile
->
uid
=
current_fsuid
();
pCifsFile
->
pInode
=
igrab
(
newinode
);
pCifsFile
->
mnt
=
mnt
;
pCifsFile
->
pfile
=
file
;
pCifsFile
->
invalidHandle
=
false
;
pCifsFile
->
closePend
=
false
;
pCifsFile
->
tlink
=
cifs_get_tlink
(
tlink
);
mutex_init
(
&
pCifsFile
->
fh_mutex
);
mutex_init
(
&
pCifsFile
->
lock_mutex
);
INIT_LIST_HEAD
(
&
pCifsFile
->
llist
);
...
...
@@ -160,7 +158,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
INIT_WORK
(
&
pCifsFile
->
oplock_break
,
cifs_oplock_break
);
write_lock
(
&
GlobalSMBSeslock
);
list_add
(
&
pCifsFile
->
tlist
,
&
cifs_sb
->
tcon
->
openFileList
);
list_add
(
&
pCifsFile
->
tlist
,
&
(
tlink_tcon
(
tlink
)
->
openFileList
)
);
pCifsInode
=
CIFS_I
(
newinode
);
if
(
pCifsInode
)
{
/* if readable file instance put first in list*/
...
...
@@ -193,6 +191,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
__u32
posix_flags
=
0
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
);
struct
cifs_fattr
fattr
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
cFYI
(
1
,
"posix open %s"
,
full_path
);
...
...
@@ -227,10 +227,20 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
posix_flags
|=
SMB_O_DIRECT
;
mode
&=
~
current_umask
();
rc
=
CIFSPOSIXCreate
(
xid
,
cifs_sb
->
tcon
,
posix_flags
,
mode
,
pnetfid
,
presp_data
,
poplock
,
full_path
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
goto
posix_open_ret
;
}
tcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSPOSIXCreate
(
xid
,
tcon
,
posix_flags
,
mode
,
pnetfid
,
presp_data
,
poplock
,
full_path
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
if
(
rc
)
goto
posix_open_ret
;
...
...
@@ -291,6 +301,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
int
desiredAccess
=
GENERIC_READ
|
GENERIC_WRITE
;
__u16
fileHandle
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
char
*
full_path
=
NULL
;
FILE_ALL_INFO
*
buf
=
NULL
;
...
...
@@ -300,13 +311,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
tcon
=
cifs_sb
->
tcon
;
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
cifs_create_out
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
FreeXid
(
xid
);
return
PTR_ERR
(
tlink
);
}
tcon
=
tlink_tcon
(
tlink
);
if
(
oplockEnabled
)
oplock
=
REQ_OPLOCK
;
...
...
@@ -316,6 +326,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
else
oflags
=
FMODE_READ
|
SMB_O_CREAT
;
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
cifs_create_out
;
}
if
(
tcon
->
unix_ext
&&
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
&&
(
CIFS_UNIX_POSIX_PATH_OPS_CAP
&
le64_to_cpu
(
tcon
->
fsUnixInfo
.
Capability
)))
{
...
...
@@ -375,7 +391,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if
(
!
tcon
->
unix_ext
&&
(
mode
&
S_IWUGO
)
==
0
)
create_options
|=
CREATE_OPTION_READONLY
;
if
(
cifs_sb
->
tcon
->
ses
->
capabilities
&
CAP_NT_SMBS
)
if
(
tcon
->
ses
->
capabilities
&
CAP_NT_SMBS
)
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
full_path
,
disposition
,
desiredAccess
,
create_options
,
&
fileHandle
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
...
...
@@ -468,7 +484,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
}
pfile_info
=
cifs_new_fileinfo
(
newinode
,
fileHandle
,
filp
,
nd
->
path
.
mnt
,
oflags
);
nd
->
path
.
mnt
,
tlink
,
oflags
,
oplock
);
if
(
pfile_info
==
NULL
)
{
fput
(
filp
);
CIFSSMBClose
(
xid
,
tcon
,
fileHandle
);
...
...
@@ -481,6 +498,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
cifs_create_out:
kfree
(
buf
);
kfree
(
full_path
);
cifs_put_tlink
(
tlink
);
FreeXid
(
xid
);
return
rc
;
}
...
...
@@ -491,6 +509,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
int
rc
=
-
EPERM
;
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
struct
inode
*
newinode
=
NULL
;
...
...
@@ -503,10 +522,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
if
(
!
old_valid_dev
(
device_number
))
return
-
EINVAL
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
...
...
@@ -606,6 +629,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
kfree
(
full_path
);
kfree
(
buf
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -619,6 +643,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
__u16
fileHandle
=
0
;
bool
posix_open
=
false
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
cifsFileInfo
*
cfile
;
struct
inode
*
newInode
=
NULL
;
...
...
@@ -633,7 +658,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
/* check whether path exists */
cifs_sb
=
CIFS_SB
(
parent_dir_inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
FreeXid
(
xid
);
return
(
struct
dentry
*
)
tlink
;
}
pTcon
=
tlink_tcon
(
tlink
);
/*
* Don't allow the separator character in a path component.
...
...
@@ -644,8 +674,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
for
(
i
=
0
;
i
<
direntry
->
d_name
.
len
;
i
++
)
if
(
direntry
->
d_name
.
name
[
i
]
==
'\\'
)
{
cFYI
(
1
,
"Invalid file name"
);
FreeXid
(
xid
)
;
return
ERR_PTR
(
-
EINVAL
)
;
rc
=
-
EINVAL
;
goto
lookup_out
;
}
}
...
...
@@ -655,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
*/
if
(
nd
&&
(
nd
->
flags
&
LOOKUP_EXCL
))
{
d_instantiate
(
direntry
,
NULL
);
return
NULL
;
rc
=
0
;
goto
lookup_out
;
}
/* can not grab the rename sem here since it would
...
...
@@ -663,8 +694,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
in which we already have the sb rename sem */
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
FreeXid
(
xid
)
;
return
ERR_PTR
(
-
ENOMEM
)
;
rc
=
-
ENOMEM
;
goto
lookup_out
;
}
if
(
direntry
->
d_inode
!=
NULL
)
{
...
...
@@ -728,8 +759,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
}
cfile
=
cifs_new_fileinfo
(
newInode
,
fileHandle
,
filp
,
nd
->
path
.
mnt
,
nd
->
intent
.
open
.
flags
);
nd
->
path
.
mnt
,
tlink
,
nd
->
intent
.
open
.
flags
,
oplock
);
if
(
cfile
==
NULL
)
{
fput
(
filp
);
CIFSSMBClose
(
xid
,
pTcon
,
fileHandle
);
...
...
@@ -759,6 +791,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
lookup_out:
kfree
(
full_path
);
cifs_put_tlink
(
tlink
);
FreeXid
(
xid
);
return
ERR_PTR
(
rc
);
}
...
...
fs/cifs/file.c
View file @
6ea75952
...
...
@@ -165,7 +165,7 @@ cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
/* all arguments to this function must be checked for validity in caller */
static
inline
int
cifs_open_inode_helper
(
struct
inode
*
inode
,
struct
cifsTconInfo
*
pTcon
,
int
*
oplock
,
FILE_ALL_INFO
*
buf
,
struct
cifsTconInfo
*
pTcon
,
__u32
oplock
,
FILE_ALL_INFO
*
buf
,
char
*
full_path
,
int
xid
)
{
struct
cifsInodeInfo
*
pCifsInode
=
CIFS_I
(
inode
);
...
...
@@ -207,11 +207,11 @@ static inline int cifs_open_inode_helper(struct inode *inode,
rc
=
cifs_get_inode_info
(
&
inode
,
full_path
,
buf
,
inode
->
i_sb
,
xid
,
NULL
);
if
((
*
oplock
&
0xF
)
==
OPLOCK_EXCLUSIVE
)
{
if
((
oplock
&
0xF
)
==
OPLOCK_EXCLUSIVE
)
{
pCifsInode
->
clientCanCacheAll
=
true
;
pCifsInode
->
clientCanCacheRead
=
true
;
cFYI
(
1
,
"Exclusive Oplock granted on inode %p"
,
inode
);
}
else
if
((
*
oplock
&
0xF
)
==
OPLOCK_READ
)
}
else
if
((
oplock
&
0xF
)
==
OPLOCK_READ
)
pCifsInode
->
clientCanCacheRead
=
true
;
return
rc
;
...
...
@@ -224,6 +224,7 @@ int cifs_open(struct inode *inode, struct file *file)
__u32
oplock
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsFileInfo
*
pCifsFile
=
NULL
;
struct
cifsInodeInfo
*
pCifsInode
;
char
*
full_path
=
NULL
;
...
...
@@ -235,7 +236,12 @@ int cifs_open(struct inode *inode, struct file *file)
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
tcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
FreeXid
(
xid
);
return
PTR_ERR
(
tlink
);
}
tcon
=
tlink_tcon
(
tlink
);
pCifsInode
=
CIFS_I
(
file
->
f_path
.
dentry
->
d_inode
);
...
...
@@ -277,7 +283,7 @@ int cifs_open(struct inode *inode, struct file *file)
pCifsFile
=
cifs_new_fileinfo
(
inode
,
netfid
,
file
,
file
->
f_path
.
mnt
,
oflags
);
tlink
,
oflags
,
oplock
);
if
(
pCifsFile
==
NULL
)
{
CIFSSMBClose
(
xid
,
tcon
,
netfid
);
rc
=
-
ENOMEM
;
...
...
@@ -345,7 +351,7 @@ int cifs_open(struct inode *inode, struct file *file)
goto
out
;
}
if
(
cifs_sb
->
tcon
->
ses
->
capabilities
&
CAP_NT_SMBS
)
if
(
tcon
->
ses
->
capabilities
&
CAP_NT_SMBS
)
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
full_path
,
disposition
,
desiredAccess
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
buf
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
...
...
@@ -365,12 +371,12 @@ int cifs_open(struct inode *inode, struct file *file)
goto
out
;
}
rc
=
cifs_open_inode_helper
(
inode
,
tcon
,
&
oplock
,
buf
,
full_path
,
xid
);
rc
=
cifs_open_inode_helper
(
inode
,
tcon
,
oplock
,
buf
,
full_path
,
xid
);
if
(
rc
!=
0
)
goto
out
;
pCifsFile
=
cifs_new_fileinfo
(
inode
,
netfid
,
file
,
file
->
f_path
.
mnt
,
file
->
f_flags
);
tlink
,
file
->
f_flags
,
oplock
);
if
(
pCifsFile
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
out
;
...
...
@@ -402,6 +408,7 @@ int cifs_open(struct inode *inode, struct file *file)
kfree
(
buf
);
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -461,7 +468,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
}
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
tcon
=
cifs_sb
->
tcon
;
tcon
=
tlink_tcon
(
pCifsFile
->
tlink
)
;
/* can not grab rename sem here because various ops, including
those that already have the rename sem can end up causing writepage
...
...
@@ -575,7 +582,7 @@ int cifs_close(struct inode *inode, struct file *file)
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
pTcon
=
tlink_tcon
(
pSMBFile
->
tlink
)
;
if
(
pSMBFile
)
{
struct
cifsLockInfo
*
li
,
*
tmp
;
write_lock
(
&
GlobalSMBSeslock
);
...
...
@@ -653,11 +660,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
xid
=
GetXid
();
if
(
pCFileStruct
)
{
struct
cifsTconInfo
*
pTcon
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
struct
cifsTconInfo
*
pTcon
=
tlink_tcon
(
pCFileStruct
->
tlink
);
cFYI
(
1
,
"Freeing private data in close dir"
);
write_lock
(
&
GlobalSMBSeslock
);
...
...
@@ -681,6 +684,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
else
cifs_buf_release
(
ptmp
);
}
cifs_put_tlink
(
pCFileStruct
->
tlink
);
kfree
(
file
->
private_data
);
file
->
private_data
=
NULL
;
}
...
...
@@ -767,7 +771,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
cFYI
(
1
,
"Unknown type of lock"
);
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
tcon
=
cifs_sb
->
tcon
;
tcon
=
tlink_tcon
(((
struct
cifsFileInfo
*
)
file
->
private_data
)
->
tlink
)
;
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EBADF
;
...
...
@@ -960,14 +964,14 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
/* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
*poffset, file->f_path.dentry->d_name.name); */
if
(
file
->
private_data
==
NULL
)
return
-
EBADF
;
open_file
=
file
->
private_data
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
rc
=
generic_write_checks
(
file
,
poffset
,
&
write_size
,
0
);
if
(
rc
)
...
...
@@ -1062,14 +1066,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
cFYI
(
1
,
"write %zd bytes to offset %lld of %s"
,
write_size
,
*
poffset
,
file
->
f_path
.
dentry
->
d_name
.
name
);
if
(
file
->
private_data
==
NULL
)
return
-
EBADF
;
open_file
=
file
->
private_data
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
xid
=
GetXid
();
...
...
@@ -1165,9 +1168,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
struct
cifsFileInfo
*
find_readable_file
(
struct
cifsInodeInfo
*
cifs_inode
)
struct
cifsFileInfo
*
find_readable_file
(
struct
cifsInodeInfo
*
cifs_inode
,
bool
fsuid_only
)
{
struct
cifsFileInfo
*
open_file
=
NULL
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
cifs_inode
->
vfs_inode
.
i_sb
);
/* only filter by fsuid on multiuser mounts */
if
(
!
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MULTIUSER
))
fsuid_only
=
false
;
read_lock
(
&
GlobalSMBSeslock
);
/* we could simply get the first_list_entry since write-only entries
...
...
@@ -1176,6 +1185,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
list_for_each_entry
(
open_file
,
&
cifs_inode
->
openFileList
,
flist
)
{
if
(
open_file
->
closePend
)
continue
;
if
(
fsuid_only
&&
open_file
->
uid
!=
current_fsuid
())
continue
;
if
(
open_file
->
pfile
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_RDONLY
)))
{
if
(
!
open_file
->
invalidHandle
)
{
...
...
@@ -1195,9 +1206,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
}
#endif
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
cifs_inode
)
struct
cifsFileInfo
*
find_writable_file
(
struct
cifsInodeInfo
*
cifs_inode
,
bool
fsuid_only
)
{
struct
cifsFileInfo
*
open_file
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
cifs_inode
->
vfs_inode
.
i_sb
);
bool
any_available
=
false
;
int
rc
;
...
...
@@ -1211,13 +1224,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
return
NULL
;
}
/* only filter by fsuid on multiuser mounts */
if
(
!
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MULTIUSER
))
fsuid_only
=
false
;
read_lock
(
&
GlobalSMBSeslock
);
refind_writable:
list_for_each_entry
(
open_file
,
&
cifs_inode
->
openFileList
,
flist
)
{
if
(
open_file
->
closePend
||
(
!
any_available
&&
open_file
->
pid
!=
current
->
tgid
))
if
(
open_file
->
closePend
)
continue
;
if
(
!
any_available
&&
open_file
->
pid
!=
current
->
tgid
)
continue
;
if
(
fsuid_only
&&
open_file
->
uid
!=
current_fsuid
())
continue
;
if
(
open_file
->
pfile
&&
((
open_file
->
pfile
->
f_flags
&
O_RDWR
)
||
(
open_file
->
pfile
->
f_flags
&
O_WRONLY
)))
{
...
...
@@ -1284,7 +1303,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
int
rc
=
-
EFAULT
;
int
bytes_written
=
0
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
struct
inode
*
inode
;
struct
cifsFileInfo
*
open_file
;
...
...
@@ -1293,7 +1311,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
inode
=
page
->
mapping
->
host
;
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
offset
+=
(
loff_t
)
from
;
write_data
=
kmap
(
page
);
...
...
@@ -1314,7 +1331,7 @@ 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
);
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
));
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
)
,
false
);
if
(
open_file
)
{
bytes_written
=
cifs_write
(
open_file
->
pfile
,
write_data
,
to
-
from
,
&
offset
);
...
...
@@ -1352,6 +1369,7 @@ static int cifs_writepages(struct address_space *mapping,
int
nr_pages
;
__u64
offset
=
0
;
struct
cifsFileInfo
*
open_file
;
struct
cifsTconInfo
*
tcon
;
struct
cifsInodeInfo
*
cifsi
=
CIFS_I
(
mapping
->
host
);
struct
page
*
page
;
struct
pagevec
pvec
;
...
...
@@ -1359,6 +1377,15 @@ static int cifs_writepages(struct address_space *mapping,
int
scanned
=
0
;
int
xid
,
long_op
;
/*
* 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
;
}
cifs_sb
=
CIFS_SB
(
mapping
->
host
->
i_sb
);
/*
...
...
@@ -1368,27 +1395,29 @@ static int cifs_writepages(struct address_space *mapping,
if
(
cifs_sb
->
wsize
<
PAGE_CACHE_SIZE
)
return
generic_writepages
(
mapping
,
wbc
);
if
((
cifs_sb
->
tcon
->
ses
)
&&
(
cifs_sb
->
tcon
->
ses
->
server
))
if
(
cifs_sb
->
tcon
->
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
if
(
!
experimEnabled
)
return
generic_writepages
(
mapping
,
wbc
);
iov
=
kmalloc
(
32
*
sizeof
(
struct
kvec
),
GFP_KERNEL
);
if
(
iov
==
NULL
)
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 there's no open file, then this is likely to fail too,
* but it'll at least handle the return. Maybe it should be
* a BUG() instead?
*/
if
(
wbc
->
nonblocking
&&
bdi_write_congested
(
bdi
))
{
wbc
->
encountered_congestion
=
1
;
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
),
false
);
if
(
!
open_file
)
{
kfree
(
iov
);
return
0
;
return
generic_writepages
(
mapping
,
wbc
)
;
}
tcon
=
tlink_tcon
(
open_file
->
tlink
);
if
(
!
experimEnabled
&&
tcon
->
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
{
cifsFileInfo_put
(
open_file
);
return
generic_writepages
(
mapping
,
wbc
);
}
cifsFileInfo_put
(
open_file
);
xid
=
GetXid
();
pagevec_init
(
&
pvec
,
0
);
...
...
@@ -1492,38 +1521,34 @@ static int cifs_writepages(struct address_space *mapping,
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
));
open_file
=
find_writable_file
(
CIFS_I
(
mapping
->
host
),
false
);
if
(
!
open_file
)
{
cERROR
(
1
,
"No writable handles for inode"
);
rc
=
-
EBADF
;
}
else
{
long_op
=
cifs_write_timeout
(
cifsi
,
offset
);
rc
=
CIFSSMBWrite2
(
xid
,
cifs_sb
->
tcon
,
open_file
->
netfid
,
rc
=
CIFSSMBWrite2
(
xid
,
tcon
,
open_file
->
netfid
,
bytes_to_write
,
offset
,
&
bytes_written
,
iov
,
n_iov
,
long_op
);
cifsFileInfo_put
(
open_file
);
cifs_update_eof
(
cifsi
,
offset
,
bytes_written
);
}
if
(
rc
||
bytes_written
<
bytes_to_write
)
{
cERROR
(
1
,
"Write2 ret %d, wrote %d"
,
rc
,
bytes_written
);
/* BB what if continued retry is
requested via mount flags? */
if
(
rc
==
-
ENOSPC
)
set_bit
(
AS_ENOSPC
,
&
mapping
->
flags
);
else
set_bit
(
AS_EIO
,
&
mapping
->
flags
);
}
else
{
cifs_stats_bytes_written
(
cifs_sb
->
tcon
,
bytes_written
);
}
if
(
rc
||
bytes_written
<
bytes_to_write
)
{
cERROR
(
1
,
"Write2 ret %d, wrote %d"
,
rc
,
bytes_written
);
/* BB what if continued retry is
requested via mount flags? */
if
(
rc
==
-
ENOSPC
)
set_bit
(
AS_ENOSPC
,
&
mapping
->
flags
);
else
set_bit
(
AS_EIO
,
&
mapping
->
flags
);
}
else
{
cifs_stats_bytes_written
(
tcon
,
bytes_written
);
}
for
(
i
=
0
;
i
<
n_iov
;
i
++
)
{
page
=
pvec
.
pages
[
first
+
i
];
/* Should we also set page error on
...
...
@@ -1665,7 +1690,7 @@ int cifs_fsync(struct file *file, int datasync)
if
(
rc
==
0
)
{
rc
=
CIFS_I
(
inode
)
->
write_behind_rc
;
CIFS_I
(
inode
)
->
write_behind_rc
=
0
;
tcon
=
CIFS_SB
(
inode
->
i_sb
)
->
tcon
;
tcon
=
tlink_tcon
(
smbfile
->
tlink
)
;
if
(
!
rc
&&
tcon
&&
smbfile
&&
!
(
CIFS_SB
(
inode
->
i_sb
)
->
mnt_cifs_flags
&
CIFS_MOUNT_NOSSYNC
))
rc
=
CIFSSMBFlush
(
xid
,
tcon
,
smbfile
->
netfid
);
...
...
@@ -1750,7 +1775,6 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EBADF
;
...
...
@@ -1758,6 +1782,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
return
rc
;
}
open_file
=
file
->
private_data
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
if
((
file
->
f_flags
&
O_ACCMODE
)
==
O_WRONLY
)
cFYI
(
1
,
"attempting read on write only file instance"
);
...
...
@@ -1831,7 +1856,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EBADF
;
...
...
@@ -1839,6 +1863,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return
rc
;
}
open_file
=
file
->
private_data
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
if
((
file
->
f_flags
&
O_ACCMODE
)
==
O_WRONLY
)
cFYI
(
1
,
"attempting read on write only file instance"
);
...
...
@@ -1974,7 +1999,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
}
open_file
=
file
->
private_data
;
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
)
;
/*
* Reads as many pages as possible from fscache. Returns -ENOBUFS
...
...
@@ -2312,7 +2337,6 @@ void cifs_oplock_break(struct work_struct *work)
oplock_break
);
struct
inode
*
inode
=
cfile
->
pInode
;
struct
cifsInodeInfo
*
cinode
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
cfile
->
mnt
->
mnt_sb
);
int
rc
,
waitrc
=
0
;
if
(
inode
&&
S_ISREG
(
inode
->
i_mode
))
{
...
...
@@ -2339,8 +2363,8 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if
(
!
cfile
->
closePend
&&
!
cfile
->
oplock_break_cancelled
)
{
rc
=
CIFSSMBLock
(
0
,
cifs_sb
->
tcon
,
cfile
->
netfid
,
0
,
0
,
0
,
0
,
LOCKING_ANDX_OPLOCK_RELEASE
,
false
);
rc
=
CIFSSMBLock
(
0
,
tlink_tcon
(
cfile
->
tlink
),
cfile
->
netfid
,
0
,
0
,
0
,
0
,
LOCKING_ANDX_OPLOCK_RELEASE
,
false
);
cFYI
(
1
,
"Oplock release rc = %d"
,
rc
);
}
...
...
fs/cifs/fscache.c
View file @
6ea75952
...
...
@@ -62,15 +62,15 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
{
struct
cifsInodeInfo
*
cifsi
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
if
(
cifsi
->
fscache
)
return
;
cifsi
->
fscache
=
fscache_acquire_cookie
(
cifs_sb
->
tcon
->
fscache
,
&
cifs_fscache_inode_object_def
,
cifsi
);
cFYI
(
1
,
"CIFS: got FH cookie (0x%p/0x%p)"
,
cifs_sb
->
tcon
->
fscache
,
cifsi
->
fscache
);
cifsi
->
fscache
=
fscache_acquire_cookie
(
tcon
->
fscache
,
&
cifs_fscache_inode_object_def
,
cifsi
);
cFYI
(
1
,
"CIFS: got FH cookie (0x%p/0x%p)"
,
tcon
->
fscache
,
cifsi
->
fscache
);
}
void
cifs_fscache_release_inode_cookie
(
struct
inode
*
inode
)
...
...
@@ -117,7 +117,8 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode)
/* retire the current fscache cache and get a new one */
fscache_relinquish_cookie
(
cifsi
->
fscache
,
1
);
cifsi
->
fscache
=
fscache_acquire_cookie
(
cifs_sb
->
tcon
->
fscache
,
cifsi
->
fscache
=
fscache_acquire_cookie
(
cifs_sb_master_tcon
(
cifs_sb
)
->
fscache
,
&
cifs_fscache_inode_object_def
,
cifsi
);
cFYI
(
1
,
"CIFS: new cookie 0x%p oldcookie 0x%p"
,
...
...
fs/cifs/inode.c
View file @
6ea75952
...
...
@@ -52,7 +52,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
/* check if server can support readpages */
if
(
cifs_sb
->
tcon
->
ses
->
server
->
maxBuf
<
if
(
cifs_sb
_master_tcon
(
cifs_sb
)
->
ses
->
server
->
maxBuf
<
PAGE_CACHE_SIZE
+
MAX_CIFS_HDR_SIZE
)
inode
->
i_data
.
a_ops
=
&
cifs_addr_ops_smallbuf
;
else
...
...
@@ -288,8 +288,8 @@ int cifs_get_file_info_unix(struct file *filp)
struct
cifs_fattr
fattr
;
struct
inode
*
inode
=
filp
->
f_path
.
dentry
->
d_inode
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
cifsFileInfo
*
cfile
=
filp
->
private_data
;
struct
cifsTconInfo
*
tcon
=
tlink_tcon
(
cfile
->
tlink
);
xid
=
GetXid
();
rc
=
CIFSSMBUnixQFileInfo
(
xid
,
tcon
,
cfile
->
netfid
,
&
find_data
);
...
...
@@ -313,15 +313,21 @@ int cifs_get_inode_info_unix(struct inode **pinode,
FILE_UNIX_BASIC_INFO
find_data
;
struct
cifs_fattr
fattr
;
struct
cifsTconInfo
*
tcon
;
struct
tcon_link
*
tlink
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
);
tcon
=
cifs_sb
->
tcon
;
cFYI
(
1
,
"Getting info on %s"
,
full_path
);
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
/* could have done a find first instead but this returns more info */
rc
=
CIFSSMBUnixQPathInfo
(
xid
,
tcon
,
full_path
,
&
find_data
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
if
(
!
rc
)
{
cifs_unix_basic_to_fattr
(
&
fattr
,
&
find_data
,
cifs_sb
);
...
...
@@ -332,6 +338,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
return
rc
;
}
/* check for Minshall+French symlinks */
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
{
int
tmprc
=
CIFSCheckMFSymlink
(
&
fattr
,
full_path
,
cifs_sb
,
xid
);
if
(
tmprc
)
cFYI
(
1
,
"CIFSCheckMFSymlink: %d"
,
tmprc
);
}
if
(
*
pinode
==
NULL
)
{
/* get new inode */
cifs_fill_uniqueid
(
sb
,
&
fattr
);
...
...
@@ -353,7 +366,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
int
rc
;
int
oplock
=
0
;
__u16
netfid
;
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
char
buf
[
24
];
unsigned
int
bytes_read
;
char
*
pbuf
;
...
...
@@ -372,7 +386,12 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
return
-
EINVAL
;
/* EOPNOTSUPP? */
}
rc
=
CIFSSMBOpen
(
xid
,
pTcon
,
path
,
FILE_OPEN
,
GENERIC_READ
,
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
path
,
FILE_OPEN
,
GENERIC_READ
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
...
...
@@ -380,7 +399,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
if
(
rc
==
0
)
{
int
buf_type
=
CIFS_NO_BUFFER
;
/* Read header */
rc
=
CIFSSMBRead
(
xid
,
pT
con
,
netfid
,
rc
=
CIFSSMBRead
(
xid
,
t
con
,
netfid
,
24
/* length */
,
0
/* offset */
,
&
bytes_read
,
&
pbuf
,
&
buf_type
);
if
((
rc
==
0
)
&&
(
bytes_read
>=
8
))
{
...
...
@@ -422,8 +441,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
fattr
->
cf_dtype
=
DT_REG
;
rc
=
-
EOPNOTSUPP
;
/* or some unknown SFU type */
}
CIFSSMBClose
(
xid
,
pT
con
,
netfid
);
CIFSSMBClose
(
xid
,
t
con
,
netfid
);
}
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -441,11 +461,19 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
ssize_t
rc
;
char
ea_value
[
4
];
__u32
mode
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBQAllEAs
(
xid
,
cifs_sb
->
tcon
,
path
,
"SETFILEBITS"
,
rc
=
CIFSSMBQAllEAs
(
xid
,
tcon
,
path
,
"SETFILEBITS"
,
ea_value
,
4
/* size of buf */
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
if
(
rc
<
0
)
return
(
int
)
rc
;
else
if
(
rc
>
3
)
{
...
...
@@ -468,6 +496,8 @@ static void
cifs_all_info_to_fattr
(
struct
cifs_fattr
*
fattr
,
FILE_ALL_INFO
*
info
,
struct
cifs_sb_info
*
cifs_sb
,
bool
adjust_tz
)
{
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
memset
(
fattr
,
0
,
sizeof
(
*
fattr
));
fattr
->
cf_cifsattrs
=
le32_to_cpu
(
info
->
Attributes
);
if
(
info
->
DeletePending
)
...
...
@@ -482,8 +512,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr
->
cf_mtime
=
cifs_NTtimeToUnix
(
info
->
LastWriteTime
);
if
(
adjust_tz
)
{
fattr
->
cf_ctime
.
tv_sec
+=
cifs_sb
->
tcon
->
ses
->
server
->
timeAdj
;
fattr
->
cf_mtime
.
tv_sec
+=
cifs_sb
->
tcon
->
ses
->
server
->
timeAdj
;
fattr
->
cf_ctime
.
tv_sec
+=
tcon
->
ses
->
server
->
timeAdj
;
fattr
->
cf_mtime
.
tv_sec
+=
tcon
->
ses
->
server
->
timeAdj
;
}
fattr
->
cf_eof
=
le64_to_cpu
(
info
->
EndOfFile
);
...
...
@@ -515,8 +545,8 @@ int cifs_get_file_info(struct file *filp)
struct
cifs_fattr
fattr
;
struct
inode
*
inode
=
filp
->
f_path
.
dentry
->
d_inode
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
cifsFileInfo
*
cfile
=
filp
->
private_data
;
struct
cifsTconInfo
*
tcon
=
tlink_tcon
(
cfile
->
tlink
);
xid
=
GetXid
();
rc
=
CIFSSMBQFileInfo
(
xid
,
tcon
,
cfile
->
netfid
,
&
find_data
);
...
...
@@ -554,26 +584,33 @@ int cifs_get_inode_info(struct inode **pinode,
{
int
rc
=
0
,
tmprc
;
struct
cifsTconInfo
*
pTcon
;
struct
tcon_link
*
tlink
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
);
char
*
buf
=
NULL
;
bool
adjustTZ
=
false
;
struct
cifs_fattr
fattr
;
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
cFYI
(
1
,
"Getting info on %s"
,
full_path
);
if
((
pfindData
==
NULL
)
&&
(
*
pinode
!=
NULL
))
{
if
(
CIFS_I
(
*
pinode
)
->
clientCanCacheRead
)
{
cFYI
(
1
,
"No need to revalidate cached inode sizes"
);
return
rc
;
goto
cgii_exit
;
}
}
/* if file info not passed in then get it from server */
if
(
pfindData
==
NULL
)
{
buf
=
kmalloc
(
sizeof
(
FILE_ALL_INFO
),
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
if
(
buf
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
cgii_exit
;
}
pfindData
=
(
FILE_ALL_INFO
*
)
buf
;
/* could do find first instead but this returns more info */
...
...
@@ -661,6 +698,13 @@ int cifs_get_inode_info(struct inode **pinode,
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_UNX_EMUL
)
cifs_sfu_mode
(
&
fattr
,
full_path
,
cifs_sb
,
xid
);
/* check for Minshall+French symlinks */
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
{
tmprc
=
CIFSCheckMFSymlink
(
&
fattr
,
full_path
,
cifs_sb
,
xid
);
if
(
tmprc
)
cFYI
(
1
,
"CIFSCheckMFSymlink: %d"
,
tmprc
);
}
if
(
!*
pinode
)
{
*
pinode
=
cifs_iget
(
sb
,
&
fattr
);
if
(
!*
pinode
)
...
...
@@ -671,6 +715,7 @@ int cifs_get_inode_info(struct inode **pinode,
cgii_exit:
kfree
(
buf
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -683,6 +728,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
int
pplen
=
cifs_sb
->
prepathlen
;
int
dfsplen
;
char
*
full_path
=
NULL
;
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
/* if no prefix path, simply set path to the root of share to "" */
if
(
pplen
==
0
)
{
...
...
@@ -692,8 +738,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
return
full_path
;
}
if
(
cifs_sb
->
tcon
&&
(
cifs_sb
->
tcon
->
Flags
&
SMB_SHARE_IS_IN_DFS
)
)
dfsplen
=
strnlen
(
cifs_sb
->
tcon
->
treeName
,
MAX_TREE_SIZE
+
1
);
if
(
tcon
->
Flags
&
SMB_SHARE_IS_IN_DFS
)
dfsplen
=
strnlen
(
tcon
->
treeName
,
MAX_TREE_SIZE
+
1
);
else
dfsplen
=
0
;
...
...
@@ -702,7 +748,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
return
full_path
;
if
(
dfsplen
)
{
strncpy
(
full_path
,
cifs_sb
->
tcon
->
treeName
,
dfsplen
);
strncpy
(
full_path
,
tcon
->
treeName
,
dfsplen
);
/* switch slash direction in prepath depending on whether
* windows or posix style path names
*/
...
...
@@ -818,18 +864,18 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
struct
inode
*
cifs_root_iget
(
struct
super_block
*
sb
,
unsigned
long
ino
)
{
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
)
;
struct
inode
*
inode
=
NULL
;
long
rc
;
char
*
full_path
;
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
cifs_sb
=
CIFS_SB
(
sb
);
full_path
=
cifs_build_path_to_root
(
cifs_sb
);
if
(
full_path
==
NULL
)
return
ERR_PTR
(
-
ENOMEM
);
xid
=
GetXid
();
if
(
cifs_sb
->
tcon
->
unix_ext
)
if
(
tcon
->
unix_ext
)
rc
=
cifs_get_inode_info_unix
(
&
inode
,
full_path
,
sb
,
xid
);
else
rc
=
cifs_get_inode_info
(
&
inode
,
full_path
,
NULL
,
sb
,
...
...
@@ -840,10 +886,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
#ifdef CONFIG_CIFS_FSCACHE
/* populate tcon->resource_id */
cifs_sb
->
tcon
->
resource_id
=
CIFS_I
(
inode
)
->
uniqueid
;
tcon
->
resource_id
=
CIFS_I
(
inode
)
->
uniqueid
;
#endif
if
(
rc
&&
cifs_sb
->
tcon
->
ipc
)
{
if
(
rc
&&
tcon
->
ipc
)
{
cFYI
(
1
,
"ipc connection - fake read inode"
);
inode
->
i_mode
|=
S_IFDIR
;
inode
->
i_nlink
=
2
;
...
...
@@ -879,7 +925,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
struct
cifsFileInfo
*
open_file
;
struct
cifsInodeInfo
*
cifsInode
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
=
NULL
;
struct
cifsTconInfo
*
pTcon
;
FILE_BASIC_INFO
info_buf
;
if
(
attrs
==
NULL
)
...
...
@@ -918,13 +965,22 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
/*
* If the file is already open for write, just use that fileid
*/
open_file
=
find_writable_file
(
cifsInode
);
open_file
=
find_writable_file
(
cifsInode
,
true
);
if
(
open_file
)
{
netfid
=
open_file
->
netfid
;
netpid
=
open_file
->
pid
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
goto
set_via_filehandle
;
}
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
tlink
=
NULL
;
goto
out
;
}
pTcon
=
tlink_tcon
(
tlink
);
/*
* NT4 apparently returns success on this call, but it doesn't
* really work.
...
...
@@ -968,6 +1024,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
else
cifsFileInfo_put
(
open_file
);
out:
if
(
tlink
!=
NULL
)
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -985,10 +1043,16 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
cifsInodeInfo
*
cifsInode
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
__u32
dosattr
,
origattr
;
FILE_BASIC_INFO
*
info_buf
=
NULL
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
full_path
,
FILE_OPEN
,
DELETE
|
FILE_WRITE_ATTRIBUTES
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
,
...
...
@@ -1057,6 +1121,7 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
CIFSSMBClose
(
xid
,
tcon
,
netfid
);
out:
kfree
(
info_buf
);
cifs_put_tlink
(
tlink
);
return
rc
;
/*
...
...
@@ -1096,12 +1161,18 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
struct
cifsInodeInfo
*
cifs_inode
;
struct
super_block
*
sb
=
dir
->
i_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
struct
iattr
*
attrs
=
NULL
;
__u32
dosattr
=
0
,
origattr
=
0
;
cFYI
(
1
,
"cifs_unlink, dir=0x%p, dentry=0x%p"
,
dir
,
dentry
);
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
/* Unlink can be called from rename so we can not take the
...
...
@@ -1109,8 +1180,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
full_path
=
build_path_from_dentry
(
dentry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
unlink_out
;
}
if
((
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
&&
...
...
@@ -1176,10 +1246,11 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
dir
->
i_ctime
=
dir
->
i_mtime
=
current_fs_time
(
sb
);
cifs_inode
=
CIFS_I
(
dir
);
CIFS_I
(
dir
)
->
time
=
0
;
/* force revalidate of dir as well */
unlink_out:
kfree
(
full_path
);
kfree
(
attrs
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -1188,6 +1259,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
int
rc
=
0
,
tmprc
;
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
struct
inode
*
newinode
=
NULL
;
...
...
@@ -1195,16 +1267,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cFYI
(
1
,
"In cifs_mkdir, mode = 0x%x inode = 0x%p"
,
mode
,
inode
);
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
mkdir_out
;
}
if
((
pTcon
->
ses
->
capabilities
&
CAP_UNIX
)
&&
...
...
@@ -1362,6 +1436,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
mkdir_out:
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -1370,6 +1445,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
int
rc
=
0
;
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
struct
cifsInodeInfo
*
cifsInode
;
...
...
@@ -1378,18 +1454,23 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
rmdir_exit
;
}
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
goto
rmdir_exit
;
}
pTcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBRmDir
(
xid
,
pTcon
,
full_path
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
if
(
!
rc
)
{
drop_nlink
(
inode
);
...
...
@@ -1410,6 +1491,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
direntry
->
d_inode
->
i_ctime
=
inode
->
i_ctime
=
inode
->
i_mtime
=
current_fs_time
(
inode
->
i_sb
);
rmdir_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
return
rc
;
...
...
@@ -1420,10 +1502,16 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
struct
dentry
*
to_dentry
,
const
char
*
toPath
)
{
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
from_dentry
->
d_sb
);
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
__u16
srcfid
;
int
oplock
,
rc
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
/* try path-based rename first */
rc
=
CIFSSMBRename
(
xid
,
pTcon
,
fromPath
,
toPath
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
...
...
@@ -1435,11 +1523,11 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
* rename by filehandle to various Windows servers.
*/
if
(
rc
==
0
||
rc
!=
-
ETXTBSY
)
return
rc
;
goto
do_rename_exit
;
/* open-file renames don't work across directories */
if
(
to_dentry
->
d_parent
!=
from_dentry
->
d_parent
)
return
rc
;
goto
do_rename_exit
;
/* open the file to be renamed -- we need DELETE perms */
rc
=
CIFSSMBOpen
(
xid
,
pTcon
,
fromPath
,
FILE_OPEN
,
DELETE
,
...
...
@@ -1455,7 +1543,8 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
CIFSSMBClose
(
xid
,
pTcon
,
srcfid
);
}
do_rename_exit:
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -1465,13 +1554,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
char
*
fromName
=
NULL
;
char
*
toName
=
NULL
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
tcon
;
FILE_UNIX_BASIC_INFO
*
info_buf_source
=
NULL
;
FILE_UNIX_BASIC_INFO
*
info_buf_target
;
int
xid
,
rc
,
tmprc
;
cifs_sb
=
CIFS_SB
(
source_dir
->
i_sb
);
tcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
tcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
...
...
@@ -1547,6 +1640,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
kfree
(
fromName
);
kfree
(
toName
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -1599,11 +1693,12 @@ int cifs_revalidate_file(struct file *filp)
{
int
rc
=
0
;
struct
inode
*
inode
=
filp
->
f_path
.
dentry
->
d_inode
;
struct
cifsFileInfo
*
cfile
=
(
struct
cifsFileInfo
*
)
filp
->
private_data
;
if
(
!
cifs_inode_needs_reval
(
inode
))
goto
check_inval
;
if
(
CIFS_SB
(
inode
->
i_sb
)
->
tcon
->
unix_ext
)
if
(
tlink_tcon
(
cfile
->
tlink
)
->
unix_ext
)
rc
=
cifs_get_file_info_unix
(
filp
);
else
rc
=
cifs_get_file_info
(
filp
);
...
...
@@ -1644,7 +1739,7 @@ int cifs_revalidate_dentry(struct dentry *dentry)
"jiffies %ld"
,
full_path
,
inode
,
inode
->
i_count
.
counter
,
dentry
,
dentry
->
d_time
,
jiffies
);
if
(
CIFS_SB
(
sb
)
->
tcon
->
unix_ext
)
if
(
cifs_sb_master_tcon
(
CIFS_SB
(
sb
))
->
unix_ext
)
rc
=
cifs_get_inode_info_unix
(
&
inode
,
full_path
,
sb
,
xid
);
else
rc
=
cifs_get_inode_info
(
&
inode
,
full_path
,
NULL
,
sb
,
...
...
@@ -1662,11 +1757,21 @@ int cifs_revalidate_dentry(struct dentry *dentry)
int
cifs_getattr
(
struct
vfsmount
*
mnt
,
struct
dentry
*
dentry
,
struct
kstat
*
stat
)
{
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
dentry
->
d_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb_master_tcon
(
cifs_sb
);
int
err
=
cifs_revalidate_dentry
(
dentry
);
if
(
!
err
)
{
generic_fillattr
(
dentry
->
d_inode
,
stat
);
stat
->
blksize
=
CIFS_MAX_MSGSIZE
;
stat
->
ino
=
CIFS_I
(
dentry
->
d_inode
)
->
uniqueid
;
if
((
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MULTIUSER
)
&&
!
tcon
->
unix_ext
)
{
if
(
!
cifs_sb
->
mnt_uid
)
stat
->
uid
=
current_fsuid
();
if
(
!
cifs_sb
->
mnt_uid
)
stat
->
gid
=
current_fsgid
();
}
}
return
err
;
}
...
...
@@ -1708,7 +1813,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
struct
cifsFileInfo
*
open_file
;
struct
cifsInodeInfo
*
cifsInode
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
=
NULL
;
struct
cifsTconInfo
*
pTcon
=
NULL
;
/*
* To avoid spurious oplock breaks from server, in the case of
...
...
@@ -1719,10 +1825,11 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
* writebehind data than the SMB timeout for the SetPathInfo
* request would allow
*/
open_file
=
find_writable_file
(
cifsInode
);
open_file
=
find_writable_file
(
cifsInode
,
true
);
if
(
open_file
)
{
__u16
nfid
=
open_file
->
netfid
;
__u32
npid
=
open_file
->
pid
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
rc
=
CIFSSMBSetFileSize
(
xid
,
pTcon
,
attrs
->
ia_size
,
nfid
,
npid
,
false
);
cifsFileInfo_put
(
open_file
);
...
...
@@ -1737,6 +1844,13 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
rc
=
-
EINVAL
;
if
(
rc
!=
0
)
{
if
(
pTcon
==
NULL
)
{
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
}
/* Set file size by pathname rather than by handle
either because no valid, writeable file handle for
it was found or because there was an error setting
...
...
@@ -1766,6 +1880,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
CIFSSMBClose
(
xid
,
pTcon
,
netfid
);
}
}
if
(
tlink
)
cifs_put_tlink
(
tlink
);
}
if
(
rc
==
0
)
{
...
...
@@ -1786,7 +1902,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
struct
inode
*
inode
=
direntry
->
d_inode
;
struct
cifsInodeInfo
*
cifsInode
=
CIFS_I
(
inode
);
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
cifs_unix_set_info_args
*
args
=
NULL
;
struct
cifsFileInfo
*
open_file
;
...
...
@@ -1873,17 +1990,25 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args
->
ctime
=
NO_CHANGE_64
;
args
->
device
=
0
;
open_file
=
find_writable_file
(
cifsInode
);
open_file
=
find_writable_file
(
cifsInode
,
true
);
if
(
open_file
)
{
u16
nfid
=
open_file
->
netfid
;
u32
npid
=
open_file
->
pid
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
rc
=
CIFSSMBUnixSetFileInfo
(
xid
,
pTcon
,
args
,
nfid
,
npid
);
cifsFileInfo_put
(
open_file
);
}
else
{
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
goto
out
;
}
pTcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBUnixSetPathInfo
(
xid
,
pTcon
,
full_path
,
args
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
cifs_put_tlink
(
tlink
);
}
if
(
rc
)
...
...
@@ -2064,7 +2189,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
{
struct
inode
*
inode
=
direntry
->
d_inode
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
pTcon
=
cifs_sb
->
tcon
;
struct
cifsTconInfo
*
pTcon
=
cifs_sb
_master_tcon
(
cifs_sb
)
;
if
(
pTcon
->
unix_ext
)
return
cifs_setattr_unix
(
direntry
,
attrs
);
...
...
fs/cifs/ioctl.c
View file @
6ea75952
...
...
@@ -37,11 +37,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
#ifdef CONFIG_CIFS_POSIX
struct
cifsFileInfo
*
pSMBFile
=
filep
->
private_data
;
struct
cifsTconInfo
*
tcon
=
tlink_tcon
(
pSMBFile
->
tlink
);
__u64
ExtAttrBits
=
0
;
__u64
ExtAttrMask
=
0
;
__u64
caps
;
struct
cifsTconInfo
*
tcon
;
struct
cifsFileInfo
*
pSMBFile
=
filep
->
private_data
;
__u64
caps
=
le64_to_cpu
(
tcon
->
fsUnixInfo
.
Capability
);
#endif
/* CONFIG_CIFS_POSIX */
xid
=
GetXid
();
...
...
@@ -50,17 +50,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
#ifdef CONFIG_CIFS_POSIX
tcon
=
cifs_sb
->
tcon
;
if
(
tcon
)
caps
=
le64_to_cpu
(
tcon
->
fsUnixInfo
.
Capability
);
else
{
rc
=
-
EIO
;
FreeXid
(
xid
);
return
-
EIO
;
}
#endif
/* CONFIG_CIFS_POSIX */
switch
(
command
)
{
case
CIFS_IOC_CHECKUMOUNT
:
cFYI
(
1
,
"User unmount attempted"
);
...
...
fs/cifs/link.c
View file @
6ea75952
...
...
@@ -28,6 +28,296 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "md5.h"
#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
#define CIFS_MF_SYMLINK_FILE_SIZE \
(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
#define CIFS_MF_SYMLINK_MD5_FORMAT \
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \
md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \
md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\
md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
static
int
CIFSParseMFSymlink
(
const
u8
*
buf
,
unsigned
int
buf_len
,
unsigned
int
*
_link_len
,
char
**
_link_str
)
{
int
rc
;
unsigned
int
link_len
;
const
char
*
md5_str1
;
const
char
*
link_str
;
struct
MD5Context
md5_ctx
;
u8
md5_hash
[
16
];
char
md5_str2
[
34
];
if
(
buf_len
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
return
-
EINVAL
;
md5_str1
=
(
const
char
*
)
&
buf
[
CIFS_MF_SYMLINK_MD5_OFFSET
];
link_str
=
(
const
char
*
)
&
buf
[
CIFS_MF_SYMLINK_LINK_OFFSET
];
rc
=
sscanf
(
buf
,
CIFS_MF_SYMLINK_LEN_FORMAT
,
&
link_len
);
if
(
rc
!=
1
)
return
-
EINVAL
;
cifs_MD5_init
(
&
md5_ctx
);
cifs_MD5_update
(
&
md5_ctx
,
(
const
u8
*
)
link_str
,
link_len
);
cifs_MD5_final
(
md5_hash
,
&
md5_ctx
);
snprintf
(
md5_str2
,
sizeof
(
md5_str2
),
CIFS_MF_SYMLINK_MD5_FORMAT
,
CIFS_MF_SYMLINK_MD5_ARGS
(
md5_hash
));
if
(
strncmp
(
md5_str1
,
md5_str2
,
17
)
!=
0
)
return
-
EINVAL
;
if
(
_link_str
)
{
*
_link_str
=
kstrndup
(
link_str
,
link_len
,
GFP_KERNEL
);
if
(
!*
_link_str
)
return
-
ENOMEM
;
}
*
_link_len
=
link_len
;
return
0
;
}
static
int
CIFSFormatMFSymlink
(
u8
*
buf
,
unsigned
int
buf_len
,
const
char
*
link_str
)
{
unsigned
int
link_len
;
unsigned
int
ofs
;
struct
MD5Context
md5_ctx
;
u8
md5_hash
[
16
];
if
(
buf_len
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
return
-
EINVAL
;
link_len
=
strlen
(
link_str
);
if
(
link_len
>
CIFS_MF_SYMLINK_LINK_MAXLEN
)
return
-
ENAMETOOLONG
;
cifs_MD5_init
(
&
md5_ctx
);
cifs_MD5_update
(
&
md5_ctx
,
(
const
u8
*
)
link_str
,
link_len
);
cifs_MD5_final
(
md5_hash
,
&
md5_ctx
);
snprintf
(
buf
,
buf_len
,
CIFS_MF_SYMLINK_LEN_FORMAT
CIFS_MF_SYMLINK_MD5_FORMAT
,
link_len
,
CIFS_MF_SYMLINK_MD5_ARGS
(
md5_hash
));
ofs
=
CIFS_MF_SYMLINK_LINK_OFFSET
;
memcpy
(
buf
+
ofs
,
link_str
,
link_len
);
ofs
+=
link_len
;
if
(
ofs
<
CIFS_MF_SYMLINK_FILE_SIZE
)
{
buf
[
ofs
]
=
'\n'
;
ofs
++
;
}
while
(
ofs
<
CIFS_MF_SYMLINK_FILE_SIZE
)
{
buf
[
ofs
]
=
' '
;
ofs
++
;
}
return
0
;
}
static
int
CIFSCreateMFSymLink
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
fromName
,
const
char
*
toName
,
const
struct
nls_table
*
nls_codepage
,
int
remap
)
{
int
rc
;
int
oplock
=
0
;
__u16
netfid
=
0
;
u8
*
buf
;
unsigned
int
bytes_written
=
0
;
buf
=
kmalloc
(
CIFS_MF_SYMLINK_FILE_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
rc
=
CIFSFormatMFSymlink
(
buf
,
CIFS_MF_SYMLINK_FILE_SIZE
,
toName
);
if
(
rc
!=
0
)
{
kfree
(
buf
);
return
rc
;
}
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
fromName
,
FILE_CREATE
,
GENERIC_WRITE
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
NULL
,
nls_codepage
,
remap
);
if
(
rc
!=
0
)
{
kfree
(
buf
);
return
rc
;
}
rc
=
CIFSSMBWrite
(
xid
,
tcon
,
netfid
,
CIFS_MF_SYMLINK_FILE_SIZE
/* length */
,
0
/* offset */
,
&
bytes_written
,
buf
,
NULL
,
0
);
CIFSSMBClose
(
xid
,
tcon
,
netfid
);
kfree
(
buf
);
if
(
rc
!=
0
)
return
rc
;
if
(
bytes_written
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
return
-
EIO
;
return
0
;
}
static
int
CIFSQueryMFSymLink
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
char
**
symlinkinfo
,
const
struct
nls_table
*
nls_codepage
,
int
remap
)
{
int
rc
;
int
oplock
=
0
;
__u16
netfid
=
0
;
u8
*
buf
;
char
*
pbuf
;
unsigned
int
bytes_read
=
0
;
int
buf_type
=
CIFS_NO_BUFFER
;
unsigned
int
link_len
=
0
;
FILE_ALL_INFO
file_info
;
rc
=
CIFSSMBOpen
(
xid
,
tcon
,
searchName
,
FILE_OPEN
,
GENERIC_READ
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
&
file_info
,
nls_codepage
,
remap
);
if
(
rc
!=
0
)
return
rc
;
if
(
file_info
.
EndOfFile
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
{
CIFSSMBClose
(
xid
,
tcon
,
netfid
);
/* it's not a symlink */
return
-
EINVAL
;
}
buf
=
kmalloc
(
CIFS_MF_SYMLINK_FILE_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
pbuf
=
buf
;
rc
=
CIFSSMBRead
(
xid
,
tcon
,
netfid
,
CIFS_MF_SYMLINK_FILE_SIZE
/* length */
,
0
/* offset */
,
&
bytes_read
,
&
pbuf
,
&
buf_type
);
CIFSSMBClose
(
xid
,
tcon
,
netfid
);
if
(
rc
!=
0
)
{
kfree
(
buf
);
return
rc
;
}
rc
=
CIFSParseMFSymlink
(
buf
,
bytes_read
,
&
link_len
,
symlinkinfo
);
kfree
(
buf
);
if
(
rc
!=
0
)
return
rc
;
return
0
;
}
bool
CIFSCouldBeMFSymlink
(
const
struct
cifs_fattr
*
fattr
)
{
if
(
!
(
fattr
->
cf_mode
&
S_IFREG
))
/* it's not a symlink */
return
false
;
if
(
fattr
->
cf_eof
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
/* it's not a symlink */
return
false
;
return
true
;
}
int
CIFSCheckMFSymlink
(
struct
cifs_fattr
*
fattr
,
const
unsigned
char
*
path
,
struct
cifs_sb_info
*
cifs_sb
,
int
xid
)
{
int
rc
;
int
oplock
=
0
;
__u16
netfid
=
0
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
u8
*
buf
;
char
*
pbuf
;
unsigned
int
bytes_read
=
0
;
int
buf_type
=
CIFS_NO_BUFFER
;
unsigned
int
link_len
=
0
;
FILE_ALL_INFO
file_info
;
if
(
!
CIFSCouldBeMFSymlink
(
fattr
))
/* it's not a symlink */
return
0
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
rc
=
CIFSSMBOpen
(
xid
,
pTcon
,
path
,
FILE_OPEN
,
GENERIC_READ
,
CREATE_NOT_DIR
,
&
netfid
,
&
oplock
,
&
file_info
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
(
rc
!=
0
)
goto
out
;
if
(
file_info
.
EndOfFile
!=
CIFS_MF_SYMLINK_FILE_SIZE
)
{
CIFSSMBClose
(
xid
,
pTcon
,
netfid
);
/* it's not a symlink */
goto
out
;
}
buf
=
kmalloc
(
CIFS_MF_SYMLINK_FILE_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
{
rc
=
-
ENOMEM
;
goto
out
;
}
pbuf
=
buf
;
rc
=
CIFSSMBRead
(
xid
,
pTcon
,
netfid
,
CIFS_MF_SYMLINK_FILE_SIZE
/* length */
,
0
/* offset */
,
&
bytes_read
,
&
pbuf
,
&
buf_type
);
CIFSSMBClose
(
xid
,
pTcon
,
netfid
);
if
(
rc
!=
0
)
{
kfree
(
buf
);
goto
out
;
}
rc
=
CIFSParseMFSymlink
(
buf
,
bytes_read
,
&
link_len
,
NULL
);
kfree
(
buf
);
if
(
rc
==
-
EINVAL
)
{
/* it's not a symlink */
rc
=
0
;
goto
out
;
}
if
(
rc
!=
0
)
goto
out
;
/* it is a symlink */
fattr
->
cf_eof
=
link_len
;
fattr
->
cf_mode
&=
~
S_IFMT
;
fattr
->
cf_mode
|=
S_IFLNK
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
;
fattr
->
cf_dtype
=
DT_LNK
;
out:
cifs_put_tlink
(
tlink
);
return
rc
;
}
int
cifs_hardlink
(
struct
dentry
*
old_file
,
struct
inode
*
inode
,
...
...
@@ -37,17 +327,17 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
int
xid
;
char
*
fromName
=
NULL
;
char
*
toName
=
NULL
;
struct
cifs_sb_info
*
cifs_sb_target
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
cifsInodeInfo
*
cifsInode
;
xid
=
GetXid
(
);
cifs_sb_target
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb_target
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
)
;
/* No need to check for cross device links since server will do that
BB note DFS case in future though (when we may have to check) */
xid
=
GetXid
();
fromName
=
build_path_from_dentry
(
old_file
);
toName
=
build_path_from_dentry
(
direntry
);
...
...
@@ -56,16 +346,15 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
goto
cifs_hl_exit
;
}
/* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
if
(
pTcon
->
unix_ext
)
rc
=
CIFSUnixCreateHardLink
(
xid
,
pTcon
,
fromName
,
toName
,
cifs_sb
_target
->
local_nls
,
cifs_sb
_target
->
mnt_cifs_flags
&
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
else
{
rc
=
CIFSCreateHardLink
(
xid
,
pTcon
,
fromName
,
toName
,
cifs_sb
_target
->
local_nls
,
cifs_sb
_target
->
mnt_cifs_flags
&
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
((
rc
==
-
EIO
)
||
(
rc
==
-
EINVAL
))
rc
=
-
EOPNOTSUPP
;
...
...
@@ -101,6 +390,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
kfree
(
fromName
);
kfree
(
toName
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -113,10 +403,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
char
*
full_path
=
NULL
;
char
*
target_path
=
NULL
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
cifsTconInfo
*
tcon
=
cifs_sb
->
tcon
;
struct
tcon_link
*
tlink
=
NULL
;
struct
cifsTconInfo
*
tcon
;
xid
=
GetXid
();
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
tlink
=
NULL
;
goto
out
;
}
tcon
=
tlink_tcon
(
tlink
);
/*
* For now, we just handle symlinks with unix extensions enabled.
* Eventually we should handle NTFS reparse points, and MacOS
...
...
@@ -130,7 +429,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
* but there doesn't seem to be any harm in allowing the client to
* read them.
*/
if
(
!
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
))
{
if
(
!
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
&&
!
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
))
{
rc
=
-
EACCES
;
goto
out
;
}
...
...
@@ -141,8 +441,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
cFYI
(
1
,
"Full path: %s inode = 0x%p"
,
full_path
,
inode
);
rc
=
CIFSSMBUnixQuerySymLink
(
xid
,
tcon
,
full_path
,
&
target_path
,
cifs_sb
->
local_nls
);
rc
=
-
EACCES
;
/*
* First try Minshall+French Symlinks, if configured
* and fallback to UNIX Extensions Symlinks.
*/
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
rc
=
CIFSQueryMFSymLink
(
xid
,
tcon
,
full_path
,
&
target_path
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
if
((
rc
!=
0
)
&&
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
))
rc
=
CIFSSMBUnixQuerySymLink
(
xid
,
tcon
,
full_path
,
&
target_path
,
cifs_sb
->
local_nls
);
kfree
(
full_path
);
out:
if
(
rc
!=
0
)
{
...
...
@@ -151,6 +464,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
}
FreeXid
(
xid
);
if
(
tlink
)
cifs_put_tlink
(
tlink
);
nd_set_link
(
nd
,
target_path
);
return
NULL
;
}
...
...
@@ -160,29 +475,37 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
{
int
rc
=
-
EOPNOTSUPP
;
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
struct
inode
*
newinode
=
NULL
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
inode
->
i_sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
{
rc
=
PTR_ERR
(
tlink
);
goto
symlink_exit
;
}
pTcon
=
tlink_tcon
(
tlink
);
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
symlink_exit
;
}
cFYI
(
1
,
"Full path: %s"
,
full_path
);
cFYI
(
1
,
"symname is %s"
,
symname
);
/* BB what if DFS and this volume is on different share? BB */
if
(
pTcon
->
unix_ext
)
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
rc
=
CIFSCreateMFSymLink
(
xid
,
pTcon
,
full_path
,
symname
,
cifs_sb
->
local_nls
,
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
else
if
(
pTcon
->
unix_ext
)
rc
=
CIFSUnixCreateSymLink
(
xid
,
pTcon
,
full_path
,
symname
,
cifs_sb
->
local_nls
);
/* else
...
...
@@ -208,8 +531,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
d_instantiate
(
direntry
,
newinode
);
}
}
symlink_exit:
kfree
(
full_path
);
cifs_put_tlink
(
tlink
);
FreeXid
(
xid
);
return
rc
;
}
...
...
fs/cifs/misc.c
View file @
6ea75952
...
...
@@ -729,6 +729,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
"properly. Hardlinks will not be recognized on this "
"mount. Consider mounting with the
\"
noserverino
\"
"
"option to silence this message."
,
cifs_sb
->
tcon
->
treeName
);
cifs_sb
_master_tcon
(
cifs_sb
)
->
treeName
);
}
}
fs/cifs/ntlmssp.h
View file @
6ea75952
...
...
@@ -61,6 +61,21 @@
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000
/* Define AV Pair Field IDs */
enum
av_field_type
{
NTLMSSP_AV_EOL
=
0
,
NTLMSSP_AV_NB_COMPUTER_NAME
,
NTLMSSP_AV_NB_DOMAIN_NAME
,
NTLMSSP_AV_DNS_COMPUTER_NAME
,
NTLMSSP_AV_DNS_DOMAIN_NAME
,
NTLMSSP_AV_DNS_TREE_NAME
,
NTLMSSP_AV_FLAGS
,
NTLMSSP_AV_TIMESTAMP
,
NTLMSSP_AV_RESTRICTION
,
NTLMSSP_AV_TARGET_NAME
,
NTLMSSP_AV_CHANNEL_BINDINGS
};
/* Although typedefs are not commonly used for structure definitions */
/* in the Linux kernel, in this particular case they are useful */
/* to more closely match the standards document for NTLMSSP from */
...
...
fs/cifs/readdir.c
View file @
6ea75952
...
...
@@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
return
NULL
;
}
if
(
CIFS_SB
(
sb
)
->
tcon
->
nocase
)
if
(
cifs_sb_master_tcon
(
CIFS_SB
(
sb
))
->
nocase
)
dentry
->
d_op
=
&
cifs_ci_dentry_ops
;
else
dentry
->
d_op
=
&
cifs_dentry_ops
;
...
...
@@ -171,7 +171,7 @@ static void
cifs_std_info_to_fattr
(
struct
cifs_fattr
*
fattr
,
FIND_FILE_STANDARD_INFO
*
info
,
struct
cifs_sb_info
*
cifs_sb
)
{
int
offset
=
cifs_sb
->
tcon
->
ses
->
server
->
timeAdj
;
int
offset
=
cifs_sb
_master_tcon
(
cifs_sb
)
->
ses
->
server
->
timeAdj
;
memset
(
fattr
,
0
,
sizeof
(
*
fattr
));
fattr
->
cf_atime
=
cnvrtDosUnixTm
(
info
->
LastAccessDate
,
...
...
@@ -199,7 +199,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
int len;
int oplock = 0;
int rc;
struct cifsTconInfo *ptcon = cifs_sb
->tcon
;
struct cifsTconInfo *ptcon = cifs_sb
_tcon(cifs_sb)
;
char *tmpbuffer;
rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
...
...
@@ -223,34 +223,35 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
static
int
initiate_cifs_search
(
const
int
xid
,
struct
file
*
file
)
{
int
rc
=
0
;
char
*
full_path
;
char
*
full_path
=
NULL
;
struct
cifsFileInfo
*
cifsFile
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
if
(
file
->
private_data
==
NULL
)
{
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
if
(
file
->
private_data
==
NULL
)
file
->
private_data
=
kzalloc
(
sizeof
(
struct
cifsFileInfo
),
GFP_KERNEL
);
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
error_exit
;
}
if
(
file
->
private_data
==
NULL
)
return
-
ENOMEM
;
cifsFile
=
file
->
private_data
;
cifsFile
->
invalidHandle
=
true
;
cifsFile
->
srch_inf
.
endOfSearch
=
false
;
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
if
(
cifs_sb
==
NULL
)
return
-
EINVAL
;
pTcon
=
cifs_sb
->
tcon
;
if
(
pTcon
==
NULL
)
return
-
EINVAL
;
cifsFile
->
tlink
=
cifs_get_tlink
(
tlink
);
full_path
=
build_path_from_dentry
(
file
->
f_path
.
dentry
);
if
(
full_path
==
NULL
)
return
-
ENOMEM
;
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
error_exit
;
}
cFYI
(
1
,
"Full path: %s start at: %lld"
,
full_path
,
file
->
f_pos
);
...
...
@@ -283,7 +284,9 @@ static int initiate_cifs_search(const int xid, struct file *file)
cifs_sb
->
mnt_cifs_flags
&=
~
CIFS_MOUNT_SERVER_INUM
;
goto
ffirst_retry
;
}
error_exit:
kfree
(
full_path
);
cifs_put_tlink
(
tlink
);
return
rc
;
}
...
...
@@ -738,6 +741,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
cifs_autodisable_serverino
(
cifs_sb
);
}
if
((
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MF_SYMLINKS
)
&&
CIFSCouldBeMFSymlink
(
&
fattr
))
/*
* trying to get the type and mode can be slow,
* so just call those regular files for now, and mark
* for reval
*/
fattr
.
cf_flags
|=
CIFS_FATTR_NEED_REVAL
;
ino
=
cifs_uniqueid_to_ino_t
(
fattr
.
cf_uniqueid
);
tmp_dentry
=
cifs_readdir_lookup
(
file
->
f_dentry
,
&
qstring
,
&
fattr
);
...
...
@@ -777,9 +789,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
pTcon
==
NULL
)
return
-
EINVAL
;
switch
((
int
)
file
->
f_pos
)
{
case
0
:
...
...
@@ -829,6 +838,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
CIFSFindClose(xid, pTcon, cifsFile->netfid);
} */
pTcon
=
tlink_tcon
(
cifsFile
->
tlink
);
rc
=
find_cifs_entry
(
xid
,
pTcon
,
file
,
&
current_entry
,
&
num_to_fill
);
if
(
rc
)
{
...
...
fs/cifs/sess.c
View file @
6ea75952
...
...
@@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
static
int
decode_ntlmssp_challenge
(
char
*
bcc_ptr
,
int
blob_len
,
struct
cifsSesInfo
*
ses
)
{
unsigned
int
tioffset
;
/* challenge message target info area */
unsigned
int
tilen
;
/* challenge message target info area length */
CHALLENGE_MESSAGE
*
pblob
=
(
CHALLENGE_MESSAGE
*
)
bcc_ptr
;
if
(
blob_len
<
sizeof
(
CHALLENGE_MESSAGE
))
{
...
...
@@ -405,6 +408,19 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
/* BB spec says that if AvId field of MsvAvTimestamp is populated then
we must set the MIC field of the AUTHENTICATE_MESSAGE */
tioffset
=
cpu_to_le16
(
pblob
->
TargetInfoArray
.
BufferOffset
);
tilen
=
cpu_to_le16
(
pblob
->
TargetInfoArray
.
Length
);
ses
->
tilen
=
tilen
;
if
(
ses
->
tilen
)
{
ses
->
tiblob
=
kmalloc
(
tilen
,
GFP_KERNEL
);
if
(
!
ses
->
tiblob
)
{
cERROR
(
1
,
"Challenge target info allocation failure"
);
ses
->
tilen
=
0
;
return
-
ENOMEM
;
}
memcpy
(
ses
->
tiblob
,
bcc_ptr
+
tioffset
,
ses
->
tilen
);
}
return
0
;
}
...
...
@@ -425,7 +441,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
/* BB is NTLMV2 session security format easier to use here? */
flags
=
NTLMSSP_NEGOTIATE_56
|
NTLMSSP_REQUEST_TARGET
|
NTLMSSP_NEGOTIATE_128
|
NTLMSSP_NEGOTIATE_UNICODE
|
NTLMSSP_NEGOTIATE_NT
_ONLY
|
NTLMSSP_NEGOTIATE_NT
LM
;
NTLMSSP_NEGOTIATE_NTLM
;
if
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
flags
|=
NTLMSSP_NEGOTIATE_SIGN
;
...
...
@@ -449,12 +465,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
This function returns the length of the data in the blob */
static
int
build_ntlmssp_auth_blob
(
unsigned
char
*
pbuffer
,
struct
cifsSesInfo
*
ses
,
const
struct
nls_table
*
nls_cp
,
bool
first
)
const
struct
nls_table
*
nls_cp
)
{
int
rc
;
unsigned
int
size
;
AUTHENTICATE_MESSAGE
*
sec_blob
=
(
AUTHENTICATE_MESSAGE
*
)
pbuffer
;
__u32
flags
;
unsigned
char
*
tmp
;
char
ntlm_session_key
[
CIFS_SESS_KEY_SIZE
]
;
struct
ntlmv2_resp
ntlmv2_response
=
{}
;
memcpy
(
sec_blob
->
Signature
,
NTLMSSP_SIGNATURE
,
8
);
sec_blob
->
MessageType
=
NtLmAuthenticate
;
...
...
@@ -462,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
flags
=
NTLMSSP_NEGOTIATE_56
|
NTLMSSP_REQUEST_TARGET
|
NTLMSSP_NEGOTIATE_TARGET_INFO
|
NTLMSSP_NEGOTIATE_128
|
NTLMSSP_NEGOTIATE_UNICODE
|
NTLMSSP_NEGOTIATE_NT
_ONLY
|
NTLMSSP_NEGOTIATE_NT
LM
;
NTLMSSP_NEGOTIATE_NTLM
;
if
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
flags
|=
NTLMSSP_NEGOTIATE_SIGN
;
...
...
@@ -477,19 +495,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
sec_blob
->
LmChallengeResponse
.
Length
=
0
;
sec_blob
->
LmChallengeResponse
.
MaximumLength
=
0
;
/* calculate session key, BB what about adding similar ntlmv2 path? */
SMBNTencrypt
(
ses
->
password
,
ses
->
server
->
cryptKey
,
ntlm_session_key
);
if
(
first
)
cifs_calculate_mac_key
(
&
ses
->
server
->
mac_signing_key
,
ntlm_session_key
,
ses
->
password
);
memcpy
(
tmp
,
ntlm_session_key
,
CIFS_SESS_KEY_SIZE
);
sec_blob
->
NtChallengeResponse
.
BufferOffset
=
cpu_to_le32
(
tmp
-
pbuffer
);
sec_blob
->
NtChallengeResponse
.
Length
=
cpu_to_le16
(
CIFS_SESS_KEY_SIZE
);
sec_blob
->
NtChallengeResponse
.
MaximumLength
=
cpu_to_le16
(
CIFS_SESS_KEY_SIZE
);
rc
=
setup_ntlmv2_rsp
(
ses
,
(
char
*
)
&
ntlmv2_response
,
nls_cp
);
if
(
rc
)
{
cERROR
(
1
,
"Error %d during NTLMSSP authentication"
,
rc
);
goto
setup_ntlmv2_ret
;
}
size
=
sizeof
(
struct
ntlmv2_resp
);
memcpy
(
tmp
,
(
char
*
)
&
ntlmv2_response
,
size
);
tmp
+=
size
;
if
(
ses
->
tilen
>
0
)
{
memcpy
(
tmp
,
ses
->
tiblob
,
ses
->
tilen
);
tmp
+=
ses
->
tilen
;
}
tmp
+=
CIFS_SESS_KEY_SIZE
;
sec_blob
->
NtChallengeResponse
.
Length
=
cpu_to_le16
(
size
+
ses
->
tilen
);
sec_blob
->
NtChallengeResponse
.
MaximumLength
=
cpu_to_le16
(
size
+
ses
->
tilen
);
kfree
(
ses
->
tiblob
);
ses
->
tiblob
=
NULL
;
ses
->
tilen
=
0
;
if
(
ses
->
domainName
==
NULL
)
{
sec_blob
->
DomainName
.
BufferOffset
=
cpu_to_le32
(
tmp
-
pbuffer
);
...
...
@@ -501,7 +526,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len
=
cifs_strtoUCS
((
__le16
*
)
tmp
,
ses
->
domainName
,
MAX_USERNAME_SIZE
,
nls_cp
);
len
*=
2
;
/* unicode is 2 bytes each */
len
+=
2
;
/* trailing null */
sec_blob
->
DomainName
.
BufferOffset
=
cpu_to_le32
(
tmp
-
pbuffer
);
sec_blob
->
DomainName
.
Length
=
cpu_to_le16
(
len
);
sec_blob
->
DomainName
.
MaximumLength
=
cpu_to_le16
(
len
);
...
...
@@ -518,7 +542,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len
=
cifs_strtoUCS
((
__le16
*
)
tmp
,
ses
->
userName
,
MAX_USERNAME_SIZE
,
nls_cp
);
len
*=
2
;
/* unicode is 2 bytes each */
len
+=
2
;
/* trailing null */
sec_blob
->
UserName
.
BufferOffset
=
cpu_to_le32
(
tmp
-
pbuffer
);
sec_blob
->
UserName
.
Length
=
cpu_to_le16
(
len
);
sec_blob
->
UserName
.
MaximumLength
=
cpu_to_le16
(
len
);
...
...
@@ -533,6 +556,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
sec_blob
->
SessionKey
.
BufferOffset
=
cpu_to_le32
(
tmp
-
pbuffer
);
sec_blob
->
SessionKey
.
Length
=
0
;
sec_blob
->
SessionKey
.
MaximumLength
=
0
;
setup_ntlmv2_ret:
return
tmp
-
pbuffer
;
}
...
...
@@ -545,19 +570,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
return
;
}
static
int
setup_ntlmssp_auth_req
(
SESSION_SETUP_ANDX
*
pSMB
,
struct
cifsSesInfo
*
ses
,
const
struct
nls_table
*
nls
,
bool
first_time
)
{
int
bloblen
;
bloblen
=
build_ntlmssp_auth_blob
(
&
pSMB
->
req
.
SecurityBlob
[
0
],
ses
,
nls
,
first_time
);
pSMB
->
req
.
SecurityBlobLength
=
cpu_to_le16
(
bloblen
);
return
bloblen
;
}
#endif
int
...
...
@@ -580,6 +592,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
struct
key
*
spnego_key
=
NULL
;
__le32
phase
=
NtLmNegotiate
;
/* NTLMSSP, if needed, is multistage */
bool
first_time
;
int
blob_len
;
char
*
ntlmsspblob
=
NULL
;
if
(
ses
==
NULL
)
return
-
EINVAL
;
...
...
@@ -690,7 +704,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
if
(
first_time
)
/* should this be moved into common code
with similar ntlmv2 path? */
cifs_calculate_
mac_key
(
&
ses
->
server
->
mac_signing
_key
,
cifs_calculate_
session_key
(
&
ses
->
server
->
session
_key
,
ntlm_session_key
,
ses
->
password
);
/* copy session key */
...
...
@@ -725,16 +739,31 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB
->
req_no_secext
.
CaseInsensitivePasswordLength
=
0
;
/* cpu_to_le16(LM2_SESS_KEY_SIZE); */
pSMB
->
req_no_secext
.
CaseSensitivePasswordLength
=
cpu_to_le16
(
sizeof
(
struct
ntlmv2_resp
));
/* calculate session key */
setup_ntlmv2_rsp
(
ses
,
v2_sess_key
,
nls_cp
);
/* FIXME: calculate MAC key */
rc
=
setup_ntlmv2_rsp
(
ses
,
v2_sess_key
,
nls_cp
);
if
(
rc
)
{
cERROR
(
1
,
"Error %d during NTLMv2 authentication"
,
rc
);
kfree
(
v2_sess_key
);
goto
ssetup_exit
;
}
memcpy
(
bcc_ptr
,
(
char
*
)
v2_sess_key
,
sizeof
(
struct
ntlmv2_resp
));
sizeof
(
struct
ntlmv2_resp
));
bcc_ptr
+=
sizeof
(
struct
ntlmv2_resp
);
kfree
(
v2_sess_key
);
/* set case sensitive password length after tilen may get
* assigned, tilen is 0 otherwise.
*/
pSMB
->
req_no_secext
.
CaseSensitivePasswordLength
=
cpu_to_le16
(
sizeof
(
struct
ntlmv2_resp
)
+
ses
->
tilen
);
if
(
ses
->
tilen
>
0
)
{
memcpy
(
bcc_ptr
,
ses
->
tiblob
,
ses
->
tilen
);
bcc_ptr
+=
ses
->
tilen
;
/* we never did allocate ses->domainName to free */
kfree
(
ses
->
tiblob
);
ses
->
tiblob
=
NULL
;
ses
->
tilen
=
0
;
}
if
(
ses
->
capabilities
&
CAP_UNICODE
)
{
if
(
iov
[
0
].
iov_len
%
2
)
{
*
bcc_ptr
=
0
;
...
...
@@ -765,15 +794,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
/* bail out if key is too long */
if
(
msg
->
sesskey_len
>
sizeof
(
ses
->
server
->
mac_signing
_key
.
data
.
krb5
))
{
sizeof
(
ses
->
server
->
session
_key
.
data
.
krb5
))
{
cERROR
(
1
,
"Kerberos signing key too long (%u bytes)"
,
msg
->
sesskey_len
);
rc
=
-
EOVERFLOW
;
goto
ssetup_exit
;
}
if
(
first_time
)
{
ses
->
server
->
mac_signing
_key
.
len
=
msg
->
sesskey_len
;
memcpy
(
ses
->
server
->
mac_signing
_key
.
data
.
krb5
,
ses
->
server
->
session
_key
.
len
=
msg
->
sesskey_len
;
memcpy
(
ses
->
server
->
session
_key
.
data
.
krb5
,
msg
->
data
,
msg
->
sesskey_len
);
}
pSMB
->
req
.
hdr
.
Flags2
|=
SMBFLG2_EXT_SEC
;
...
...
@@ -815,12 +844,28 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
if
(
phase
==
NtLmNegotiate
)
{
setup_ntlmssp_neg_req
(
pSMB
,
ses
);
iov
[
1
].
iov_len
=
sizeof
(
NEGOTIATE_MESSAGE
);
iov
[
1
].
iov_base
=
&
pSMB
->
req
.
SecurityBlob
[
0
];
}
else
if
(
phase
==
NtLmAuthenticate
)
{
int
blob_len
;
blob_len
=
setup_ntlmssp_auth_req
(
pSMB
,
ses
,
nls_cp
,
first_time
);
/* 5 is an empirical value, large enought to
* hold authenticate message, max 10 of
* av paris, doamin,user,workstation mames,
* flags etc..
*/
ntlmsspblob
=
kmalloc
(
5
*
sizeof
(
struct
_AUTHENTICATE_MESSAGE
),
GFP_KERNEL
);
if
(
!
ntlmsspblob
)
{
cERROR
(
1
,
"Can't allocate NTLMSSP"
);
rc
=
-
ENOMEM
;
goto
ssetup_exit
;
}
blob_len
=
build_ntlmssp_auth_blob
(
ntlmsspblob
,
ses
,
nls_cp
);
iov
[
1
].
iov_len
=
blob_len
;
iov
[
1
].
iov_base
=
ntlmsspblob
;
pSMB
->
req
.
SecurityBlobLength
=
cpu_to_le16
(
blob_len
);
/* Make sure that we tell the server that we
are using the uid that it just gave us back
on the response (challenge) */
...
...
@@ -830,7 +875,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
rc
=
-
ENOSYS
;
goto
ssetup_exit
;
}
iov
[
1
].
iov_base
=
&
pSMB
->
req
.
SecurityBlob
[
0
];
/* unicode strings must be word aligned */
if
((
iov
[
0
].
iov_len
+
iov
[
1
].
iov_len
)
%
2
)
{
*
bcc_ptr
=
0
;
...
...
@@ -931,6 +975,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
key_put
(
spnego_key
);
}
kfree
(
str_area
);
kfree
(
ntlmsspblob
);
ntlmsspblob
=
NULL
;
if
(
resp_buf_type
==
CIFS_SMALL_BUFFER
)
{
cFYI
(
1
,
"ssetup freeing small buf %p"
,
iov
[
0
].
iov_base
);
cifs_small_buf_release
(
iov
[
0
].
iov_base
);
...
...
fs/cifs/transport.c
View file @
6ea75952
...
...
@@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
)))
{
rc
=
cifs_verify_signature
(
midQ
->
resp_buf
,
&
ses
->
server
->
mac_signing
_key
,
&
ses
->
server
->
session
_key
,
midQ
->
sequence_number
+
1
);
if
(
rc
)
{
cERROR
(
1
,
"Unexpected SMB signature"
);
...
...
@@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
)))
{
rc
=
cifs_verify_signature
(
out_buf
,
&
ses
->
server
->
mac_signing
_key
,
&
ses
->
server
->
session
_key
,
midQ
->
sequence_number
+
1
);
if
(
rc
)
{
cERROR
(
1
,
"Unexpected SMB signature"
);
...
...
@@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
)))
{
rc
=
cifs_verify_signature
(
out_buf
,
&
ses
->
server
->
mac_signing
_key
,
&
ses
->
server
->
session
_key
,
midQ
->
sequence_number
+
1
);
if
(
rc
)
{
cERROR
(
1
,
"Unexpected SMB signature"
);
...
...
fs/cifs/xattr.c
View file @
6ea75952
...
...
@@ -47,9 +47,10 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
#ifdef CONFIG_CIFS_XATTR
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
super_block
*
sb
;
char
*
full_path
;
char
*
full_path
=
NULL
;
if
(
direntry
==
NULL
)
return
-
EIO
;
...
...
@@ -58,16 +59,19 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
sb
=
direntry
->
d_inode
->
i_sb
;
if
(
sb
==
NULL
)
return
-
EIO
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
remove_ea_exit
;
}
if
(
ea_name
==
NULL
)
{
cFYI
(
1
,
"Null xattr names not supported"
);
...
...
@@ -91,6 +95,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
remove_ea_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
#endif
return
rc
;
}
...
...
@@ -102,6 +107,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
#ifdef CONFIG_CIFS_XATTR
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
super_block
*
sb
;
char
*
full_path
;
...
...
@@ -113,16 +119,19 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
sb
=
direntry
->
d_inode
->
i_sb
;
if
(
sb
==
NULL
)
return
-
EIO
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
set_ea_exit
;
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
...
...
@@ -132,9 +141,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
returns as xattrs */
if
(
value_size
>
MAX_EA_VALUE_SIZE
)
{
cFYI
(
1
,
"size of EA value too large"
);
kfree
(
full_path
);
FreeXid
(
xid
);
return
-
EOPNOTSUPP
;
rc
=
-
EOPNOTSUPP
;
goto
set_ea_exit
;
}
if
(
ea_name
==
NULL
)
{
...
...
@@ -198,6 +206,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
set_ea_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
#endif
return
rc
;
}
...
...
@@ -209,6 +218,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
#ifdef CONFIG_CIFS_XATTR
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
super_block
*
sb
;
char
*
full_path
;
...
...
@@ -221,16 +231,18 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
if
(
sb
==
NULL
)
return
-
EIO
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
sb
);
pTcon
=
cifs_sb
->
tcon
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
get_ea_exit
;
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
...
...
@@ -323,6 +335,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
get_ea_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
#endif
return
rc
;
}
...
...
@@ -333,6 +346,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
#ifdef CONFIG_CIFS_XATTR
int
xid
;
struct
cifs_sb_info
*
cifs_sb
;
struct
tcon_link
*
tlink
;
struct
cifsTconInfo
*
pTcon
;
struct
super_block
*
sb
;
char
*
full_path
;
...
...
@@ -346,18 +360,20 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
return
-
EIO
;
cifs_sb
=
CIFS_SB
(
sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_NO_XATTR
)
return
-
EOPNOTSUPP
;
tlink
=
cifs_sb_tlink
(
cifs_sb
);
if
(
IS_ERR
(
tlink
))
return
PTR_ERR
(
tlink
);
pTcon
=
tlink_tcon
(
tlink
);
xid
=
GetXid
();
full_path
=
build_path_from_dentry
(
direntry
);
if
(
full_path
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
rc
;
goto
list_ea_exit
;
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
...
...
@@ -370,8 +386,10 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_MAP_SPECIAL_CHR
);
list_ea_exit:
kfree
(
full_path
);
FreeXid
(
xid
);
cifs_put_tlink
(
tlink
);
#endif
return
rc
;
}
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