mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
[CIFS] on reconnect to Samba - reset the unix capabilities
After temporary server or network failure and reconneciton, we were not resending the unix capabilities via SetFSInfo - which confused Samba posix byte range locking code. Discovered by jra Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
7ba526316a
commit
8af1897158
29
fs/Kconfig
29
fs/Kconfig
@ -1871,20 +1871,14 @@ config CIFS
|
|||||||
file servers such as Windows 2000 (including Windows 2003, NT 4
|
file servers such as Windows 2000 (including Windows 2003, NT 4
|
||||||
and Windows XP) as well by Samba (which provides excellent CIFS
|
and Windows XP) as well by Samba (which provides excellent CIFS
|
||||||
server support for Linux and many other operating systems). Limited
|
server support for Linux and many other operating systems). Limited
|
||||||
support for Windows ME and similar servers is provided as well.
|
support for OS/2 and Windows ME and similar servers is provided as well.
|
||||||
You must use the smbfs client filesystem to access older SMB servers
|
|
||||||
such as OS/2 and DOS.
|
|
||||||
|
|
||||||
The intent of the cifs module is to provide an advanced
|
The intent of the cifs module is to provide an advanced
|
||||||
network file system client for mounting to CIFS compliant servers,
|
network file system client for mounting to CIFS compliant servers,
|
||||||
including support for dfs (hierarchical name space), secure per-user
|
including support for dfs (hierarchical name space), secure per-user
|
||||||
session establishment, safe distributed caching (oplock), optional
|
session establishment, safe distributed caching (oplock), optional
|
||||||
packet signing, Unicode and other internationalization improvements,
|
packet signing, Unicode and other internationalization improvements.
|
||||||
and optional Winbind (nsswitch) integration. You do not need to enable
|
If you need to mount to Samba or Windows from this machine, say Y.
|
||||||
cifs if running only a (Samba) server. It is possible to enable both
|
|
||||||
smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003
|
|
||||||
and Samba 3 servers, and smbfs for accessing old servers). If you need
|
|
||||||
to mount to Samba or Windows from this machine, say Y.
|
|
||||||
|
|
||||||
config CIFS_STATS
|
config CIFS_STATS
|
||||||
bool "CIFS statistics"
|
bool "CIFS statistics"
|
||||||
@ -1977,14 +1971,13 @@ config CIFS_EXPERIMENTAL
|
|||||||
depends on CIFS && EXPERIMENTAL
|
depends on CIFS && EXPERIMENTAL
|
||||||
help
|
help
|
||||||
Enables cifs features under testing. These features are
|
Enables cifs features under testing. These features are
|
||||||
experimental and currently include support for writepages
|
experimental and currently include DFS support and directory
|
||||||
(multipage writebehind performance improvements) and directory
|
change notification ie fcntl(F_DNOTIFY), as well as the upcall
|
||||||
change notification ie fcntl(F_DNOTIFY) as well as some security
|
mechanism which will be used for Kerberos session negotiation
|
||||||
improvements. Some also depend on setting at runtime the
|
and uid remapping. Some of these features also may depend on
|
||||||
pseudo-file /proc/fs/cifs/Experimental (which is disabled by
|
setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental
|
||||||
default). See the file fs/cifs/README for more details.
|
(which is disabled by default). See the file fs/cifs/README
|
||||||
|
for more details. If unsure, say N.
|
||||||
If unsure, say N.
|
|
||||||
|
|
||||||
config CIFS_UPCALL
|
config CIFS_UPCALL
|
||||||
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
|
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
|
||||||
|
@ -4,7 +4,12 @@ Fix oops in list_del during mount caused by unaligned string.
|
|||||||
Fix file corruption which could occur on some large file
|
Fix file corruption which could occur on some large file
|
||||||
copies caused by writepages page i/o completion bug.
|
copies caused by writepages page i/o completion bug.
|
||||||
Seek to SEEK_END forces check for update of file size for non-cached
|
Seek to SEEK_END forces check for update of file size for non-cached
|
||||||
files.
|
files. Allow file size to be updated on remote extend of locally open,
|
||||||
|
non-cached file. Fix reconnect to newer Samba servers (or other servers
|
||||||
|
which support the CIFS Unix/POSIX extensions) so that we again tell the
|
||||||
|
server the Unix/POSIX cifs capabilities which we support (SetFSInfo).
|
||||||
|
Add experimental support for new POSIX Open/Mkdir (which returns
|
||||||
|
stat information on the open, and allows setting the mode).
|
||||||
|
|
||||||
Version 1.46
|
Version 1.46
|
||||||
------------
|
------------
|
||||||
|
@ -128,3 +128,11 @@ negotiated size) and send larger write sizes to modern servers.
|
|||||||
|
|
||||||
4) More exhaustively test against less common servers. More testing
|
4) More exhaustively test against less common servers. More testing
|
||||||
against Windows 9x, Windows ME servers.
|
against Windows 9x, Windows ME servers.
|
||||||
|
|
||||||
|
DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
|
||||||
|
|
||||||
|
mount check for unmatched uids - and uid override
|
||||||
|
|
||||||
|
Add mount option for Linux extension disable per mount, and partial disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
|
||||||
|
|
||||||
|
Free threads at umount --force that are stuck on the sesSem
|
||||||
|
@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||||||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||||
unsigned int command, unsigned long arg);
|
unsigned int command, unsigned long arg);
|
||||||
#define CIFS_VERSION "1.47"
|
#define CIFS_VERSION "1.48"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
@ -2108,7 +2108,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* reply varies based on requested level */
|
/* reply varies based on requested level */
|
||||||
} __atribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
|
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
|
||||||
|
|
||||||
|
|
||||||
struct file_internal_info {
|
struct file_internal_info {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
|
|
||||||
struct statfs;
|
struct statfs;
|
||||||
|
struct smb_vol;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*****************************************************************
|
*****************************************************************
|
||||||
@ -147,6 +148,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
|||||||
unsigned int *pnum_referrals,
|
unsigned int *pnum_referrals,
|
||||||
unsigned char ** preferrals,
|
unsigned char ** preferrals,
|
||||||
int remap);
|
int remap);
|
||||||
|
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
|
||||||
|
struct super_block * sb, struct smb_vol * vol);
|
||||||
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
||||||
struct kstatfs *FSData);
|
struct kstatfs *FSData);
|
||||||
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
||||||
|
@ -158,9 +158,15 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|||||||
nls_codepage);
|
nls_codepage);
|
||||||
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
|
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
|
||||||
mark_open_files_invalid(tcon);
|
mark_open_files_invalid(tcon);
|
||||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
|
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||||
, nls_codepage);
|
tcon, nls_codepage);
|
||||||
up(&tcon->ses->sesSem);
|
up(&tcon->ses->sesSem);
|
||||||
|
/* tell server which Unix caps we support */
|
||||||
|
if (tcon->ses->capabilities & CAP_UNIX)
|
||||||
|
reset_cifs_unix_caps(0 /* no xid */,
|
||||||
|
tcon,
|
||||||
|
NULL /* we do not know sb */,
|
||||||
|
NULL /* no vol info */);
|
||||||
/* BB FIXME add code to check if wsize needs
|
/* BB FIXME add code to check if wsize needs
|
||||||
update due to negotiated smb buffer size
|
update due to negotiated smb buffer size
|
||||||
shrinking */
|
shrinking */
|
||||||
@ -298,6 +304,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|||||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||||
tcon, nls_codepage);
|
tcon, nls_codepage);
|
||||||
up(&tcon->ses->sesSem);
|
up(&tcon->ses->sesSem);
|
||||||
|
/* tell server which Unix caps we support */
|
||||||
|
if (tcon->ses->capabilities & CAP_UNIX)
|
||||||
|
reset_cifs_unix_caps(0 /* no xid */,
|
||||||
|
tcon,
|
||||||
|
NULL /* do not know sb */,
|
||||||
|
NULL /* no vol info */);
|
||||||
/* BB FIXME add code to check if wsize needs
|
/* BB FIXME add code to check if wsize needs
|
||||||
update due to negotiated smb buffer size
|
update due to negotiated smb buffer size
|
||||||
shrinking */
|
shrinking */
|
||||||
|
@ -1613,6 +1613,76 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
|
||||||
|
struct super_block * sb, struct smb_vol * vol_info)
|
||||||
|
{
|
||||||
|
/* if we are reconnecting then should we check to see if
|
||||||
|
* any requested capabilities changed locally e.g. via
|
||||||
|
* remount but we can not do much about it here
|
||||||
|
* if they have (even if we could detect it by the following)
|
||||||
|
* Perhaps we could add a backpointer to array of sb from tcon
|
||||||
|
* or if we change to make all sb to same share the same
|
||||||
|
* sb as NFS - then we only have one backpointer to sb.
|
||||||
|
* What if we wanted to mount the server share twice once with
|
||||||
|
* and once without posixacls or posix paths? */
|
||||||
|
__u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
|
||||||
|
|
||||||
|
|
||||||
|
if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
|
||||||
|
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
|
||||||
|
|
||||||
|
/* check for reconnect case in which we do not
|
||||||
|
want to change the mount behavior if we can avoid it */
|
||||||
|
if(vol_info == NULL) {
|
||||||
|
/* turn off POSIX ACL and PATHNAMES if not set
|
||||||
|
originally at mount time */
|
||||||
|
if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
|
||||||
|
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
|
||||||
|
if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
|
||||||
|
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cap &= CIFS_UNIX_CAP_MASK;
|
||||||
|
if(vol_info && vol_info->no_psx_acl)
|
||||||
|
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
|
||||||
|
else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
|
||||||
|
cFYI(1,("negotiated posix acl support"));
|
||||||
|
if(sb)
|
||||||
|
sb->s_flags |= MS_POSIXACL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vol_info && vol_info->posix_paths == 0)
|
||||||
|
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
|
||||||
|
else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
|
||||||
|
cFYI(1,("negotiate posix pathnames"));
|
||||||
|
if(sb)
|
||||||
|
CIFS_SB(sb)->mnt_cifs_flags |=
|
||||||
|
CIFS_MOUNT_POSIX_PATHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
cFYI(1,("Negotiate caps 0x%x",(int)cap));
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
if(cap & CIFS_UNIX_FCNTL_CAP)
|
||||||
|
cFYI(1,("FCNTL cap"));
|
||||||
|
if(cap & CIFS_UNIX_EXTATTR_CAP)
|
||||||
|
cFYI(1,("EXTATTR cap"));
|
||||||
|
if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
|
||||||
|
cFYI(1,("POSIX path cap"));
|
||||||
|
if(cap & CIFS_UNIX_XATTR_CAP)
|
||||||
|
cFYI(1,("XATTR cap"));
|
||||||
|
if(cap & CIFS_UNIX_POSIX_ACL_CAP)
|
||||||
|
cFYI(1,("POSIX ACL cap"));
|
||||||
|
#endif /* CIFS_DEBUG2 */
|
||||||
|
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
|
||||||
|
cFYI(1,("setting capabilities failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
char *mount_data, const char *devname)
|
char *mount_data, const char *devname)
|
||||||
@ -1928,20 +1998,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||||||
if (tcon == NULL)
|
if (tcon == NULL)
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
else {
|
else {
|
||||||
/* check for null share name ie connect to dfs root */
|
/* check for null share name ie connecting to
|
||||||
|
* dfs root */
|
||||||
|
|
||||||
/* BB check if this works for exactly length three strings */
|
/* BB check if this works for exactly length
|
||||||
|
* three strings */
|
||||||
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
|
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
|
||||||
&& (strchr(volume_info.UNC + 3, '/') ==
|
&& (strchr(volume_info.UNC + 3, '/') ==
|
||||||
NULL)) {
|
NULL)) {
|
||||||
rc = connect_to_dfs_path(xid, pSesInfo,
|
rc = connect_to_dfs_path(xid, pSesInfo,
|
||||||
"", cifs_sb->local_nls,
|
"", cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
kfree(volume_info.UNC);
|
kfree(volume_info.UNC);
|
||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
} else {
|
} else {
|
||||||
|
/* BB Do we need to wrap sesSem around
|
||||||
|
* this TCon call and Unix SetFS as
|
||||||
|
* we do on SessSetup and reconnect? */
|
||||||
rc = CIFSTCon(xid, pSesInfo,
|
rc = CIFSTCon(xid, pSesInfo,
|
||||||
volume_info.UNC,
|
volume_info.UNC,
|
||||||
tcon, cifs_sb->local_nls);
|
tcon, cifs_sb->local_nls);
|
||||||
@ -1962,6 +2037,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||||||
sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
|
sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
|
||||||
sb->s_time_gran = 100;
|
sb->s_time_gran = 100;
|
||||||
|
|
||||||
/* on error free sesinfo and tcon struct if needed */
|
/* on error free sesinfo and tcon struct if needed */
|
||||||
@ -2006,45 +2082,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||||||
/* do not care if following two calls succeed - informational */
|
/* do not care if following two calls succeed - informational */
|
||||||
CIFSSMBQFSDeviceInfo(xid, tcon);
|
CIFSSMBQFSDeviceInfo(xid, tcon);
|
||||||
CIFSSMBQFSAttributeInfo(xid, tcon);
|
CIFSSMBQFSAttributeInfo(xid, tcon);
|
||||||
|
|
||||||
if (tcon->ses->capabilities & CAP_UNIX) {
|
/* tell server which Unix caps we support */
|
||||||
if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
|
if (tcon->ses->capabilities & CAP_UNIX)
|
||||||
__u64 cap =
|
reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
|
||||||
le64_to_cpu(tcon->fsUnixInfo.Capability);
|
|
||||||
cap &= CIFS_UNIX_CAP_MASK;
|
|
||||||
if(volume_info.no_psx_acl)
|
|
||||||
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
|
|
||||||
else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
|
|
||||||
cFYI(1,("negotiated posix acl support"));
|
|
||||||
sb->s_flags |= MS_POSIXACL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(volume_info.posix_paths == 0)
|
|
||||||
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
|
|
||||||
else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
|
|
||||||
cFYI(1,("negotiate posix pathnames"));
|
|
||||||
cifs_sb->mnt_cifs_flags |=
|
|
||||||
CIFS_MOUNT_POSIX_PATHS;
|
|
||||||
}
|
|
||||||
|
|
||||||
cFYI(1,("Negotiate caps 0x%x",(int)cap));
|
|
||||||
#ifdef CONFIG_CIFS_DEBUG2
|
|
||||||
if(cap & CIFS_UNIX_FCNTL_CAP)
|
|
||||||
cFYI(1,("FCNTL cap"));
|
|
||||||
if(cap & CIFS_UNIX_EXTATTR_CAP)
|
|
||||||
cFYI(1,("EXTATTR cap"));
|
|
||||||
if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
|
|
||||||
cFYI(1,("POSIX path cap"));
|
|
||||||
if(cap & CIFS_UNIX_XATTR_CAP)
|
|
||||||
cFYI(1,("XATTR cap"));
|
|
||||||
if(cap & CIFS_UNIX_POSIX_ACL_CAP)
|
|
||||||
cFYI(1,("POSIX ACL cap"));
|
|
||||||
#endif /* CIFS_DEBUG2 */
|
|
||||||
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
|
|
||||||
cFYI(1,("setting capabilities failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
|
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
|
||||||
cifs_sb->wsize = min(cifs_sb->wsize,
|
cifs_sb->wsize = min(cifs_sb->wsize,
|
||||||
(tcon->ses->server->maxBuf -
|
(tcon->ses->server->maxBuf -
|
||||||
|
Loading…
x
Reference in New Issue
Block a user