Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French: "Small set of cifs fixes. Most important is Jeff's fix that works around disconnection problems which can be caused by simultaneous use of user space tools (starting a long running smbclient backup then doing a cifs kernel mount) or multiple cifs mounts through a NAT, and Jim's fix to deal with reexport of cifs share. I expect to send two more cifs fixes next week (being tested now) - fixes to address an SMB2 unmount hang when server dies and a fix for cifs symlink handling of Windows "NFS" symlinks" * 'for-linus' of git://git.samba.org/sfrench/cifs-2.6: [CIFS] update cifs.ko version [CIFS] Remove ext2 flags that have been moved to fs.h [CIFS] Provide sane values for nlink cifs: stop trying to use virtual circuits CIFS: FS-Cache: Uncache unread pages in cifs_readpages() before freeing them
This commit is contained in:
Коммит
a5c984cc29
|
@ -132,5 +132,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.01"
|
||||
#define CIFS_VERSION "2.02"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -547,9 +547,6 @@ struct TCP_Server_Info {
|
|||
unsigned int max_rw; /* maxRw specifies the maximum */
|
||||
/* message size the server can send or receive for */
|
||||
/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
|
||||
unsigned int max_vcs; /* maximum number of smb sessions, at least
|
||||
those that can be specified uniquely with
|
||||
vcnumbers */
|
||||
unsigned int capabilities; /* selective disabling of caps by smb sess */
|
||||
int timeAdj; /* Adjust for difference in server time zone in sec */
|
||||
__u64 CurrentMid; /* multiplex id - rotating counter */
|
||||
|
@ -715,7 +712,6 @@ struct cifs_ses {
|
|||
enum statusEnum status;
|
||||
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
__u16 vcnum;
|
||||
char *serverOS; /* name of operating system underlying server */
|
||||
char *serverNOS; /* name of network operating system of server */
|
||||
char *serverDomain; /* security realm of server */
|
||||
|
@ -1272,6 +1268,7 @@ struct dfs_info3_param {
|
|||
#define CIFS_FATTR_DELETE_PENDING 0x2
|
||||
#define CIFS_FATTR_NEED_REVAL 0x4
|
||||
#define CIFS_FATTR_INO_COLLISION 0x8
|
||||
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
|
||||
|
||||
struct cifs_fattr {
|
||||
u32 cf_flags;
|
||||
|
|
|
@ -2652,26 +2652,7 @@ typedef struct file_xattr_info {
|
|||
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
|
||||
level 0x205 */
|
||||
|
||||
|
||||
/* flags for chattr command */
|
||||
#define EXT_SECURE_DELETE 0x00000001 /* EXT3_SECRM_FL */
|
||||
#define EXT_ENABLE_UNDELETE 0x00000002 /* EXT3_UNRM_FL */
|
||||
/* Reserved for compress file 0x4 */
|
||||
#define EXT_SYNCHRONOUS 0x00000008 /* EXT3_SYNC_FL */
|
||||
#define EXT_IMMUTABLE_FL 0x00000010 /* EXT3_IMMUTABLE_FL */
|
||||
#define EXT_OPEN_APPEND_ONLY 0x00000020 /* EXT3_APPEND_FL */
|
||||
#define EXT_DO_NOT_BACKUP 0x00000040 /* EXT3_NODUMP_FL */
|
||||
#define EXT_NO_UPDATE_ATIME 0x00000080 /* EXT3_NOATIME_FL */
|
||||
/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
|
||||
#define EXT_HASH_TREE_INDEXED_DIR 0x00001000 /* GET-ONLY EXT3_INDEX_FL */
|
||||
/* 0x2000 reserved for IMAGIC_FL */
|
||||
#define EXT_JOURNAL_THIS_FILE 0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
|
||||
/* 0x8000 reserved for EXT3_NOTAIL_FL */
|
||||
#define EXT_SYNCHRONOUS_DIR 0x00010000 /* EXT3_DIRSYNC_FL */
|
||||
#define EXT_TOPDIR 0x00020000 /* EXT3_TOPDIR_FL */
|
||||
|
||||
#define EXT_SET_MASK 0x000300FF
|
||||
#define EXT_GET_MASK 0x0003DFFF
|
||||
/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
|
||||
|
||||
typedef struct file_chattr_info {
|
||||
__le64 mask; /* list of all possible attribute bits */
|
||||
|
|
|
@ -463,7 +463,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
|
|||
cifs_max_pending);
|
||||
set_credits(server, server->maxReq);
|
||||
server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
|
||||
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
|
||||
/* even though we do not use raw we might as well set this
|
||||
accurately, in case we ever find a need for it */
|
||||
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
|
||||
|
|
|
@ -3254,6 +3254,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|||
/*
|
||||
* Reads as many pages as possible from fscache. Returns -ENOBUFS
|
||||
* immediately if the cookie is negative
|
||||
*
|
||||
* After this point, every page in the list might have PG_fscache set,
|
||||
* so we will need to clean that up off of every page we don't use.
|
||||
*/
|
||||
rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
|
||||
&num_pages);
|
||||
|
@ -3376,6 +3379,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|||
kref_put(&rdata->refcount, cifs_readdata_release);
|
||||
}
|
||||
|
||||
/* Any pages that have been shown to fscache but didn't get added to
|
||||
* the pagecache must be uncached before they get returned to the
|
||||
* allocator.
|
||||
*/
|
||||
cifs_fscache_readpages_cancel(mapping->host, page_list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
|
|||
fscache_uncache_page(CIFS_I(inode)->fscache, page);
|
||||
}
|
||||
|
||||
void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
|
||||
{
|
||||
cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
|
||||
__func__, CIFS_I(inode)->fscache, inode);
|
||||
fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
|
||||
}
|
||||
|
||||
void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
|
||||
{
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||||
|
|
|
@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *,
|
|||
struct address_space *,
|
||||
struct list_head *,
|
||||
unsigned *);
|
||||
extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
|
||||
|
||||
extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
|
||||
|
||||
|
@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
|
|||
__cifs_readpage_to_fscache(inode, page);
|
||||
}
|
||||
|
||||
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
|
||||
struct list_head *pages)
|
||||
{
|
||||
if (CIFS_I(inode)->fscache)
|
||||
return __cifs_fscache_readpages_cancel(inode, pages);
|
||||
}
|
||||
|
||||
#else /* CONFIG_CIFS_FSCACHE */
|
||||
static inline int cifs_fscache_register(void) { return 0; }
|
||||
static inline void cifs_fscache_unregister(void) {}
|
||||
|
@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
|
|||
static inline void cifs_readpage_to_fscache(struct inode *inode,
|
||||
struct page *page) {}
|
||||
|
||||
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
|
||||
struct list_head *pages)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CIFS_FSCACHE */
|
||||
|
||||
#endif /* _CIFS_FSCACHE_H */
|
||||
|
|
|
@ -120,6 +120,33 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
|
|||
cifs_i->invalid_mapping = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy nlink to the inode, unless it wasn't provided. Provide
|
||||
* sane values if we don't have an existing one and none was provided
|
||||
*/
|
||||
static void
|
||||
cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
{
|
||||
/*
|
||||
* if we're in a situation where we can't trust what we
|
||||
* got from the server (readdir, some non-unix cases)
|
||||
* fake reasonable values
|
||||
*/
|
||||
if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
|
||||
/* only provide fake values on a new inode */
|
||||
if (inode->i_state & I_NEW) {
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
|
||||
set_nlink(inode, 2);
|
||||
else
|
||||
set_nlink(inode, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* we trust the server, so update it */
|
||||
set_nlink(inode, fattr->cf_nlink);
|
||||
}
|
||||
|
||||
/* populate an inode with info from a cifs_fattr struct */
|
||||
void
|
||||
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
|
@ -134,7 +161,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
|||
inode->i_mtime = fattr->cf_mtime;
|
||||
inode->i_ctime = fattr->cf_ctime;
|
||||
inode->i_rdev = fattr->cf_rdev;
|
||||
set_nlink(inode, fattr->cf_nlink);
|
||||
cifs_nlink_fattr_to_inode(inode, fattr);
|
||||
inode->i_uid = fattr->cf_uid;
|
||||
inode->i_gid = fattr->cf_gid;
|
||||
|
||||
|
@ -541,6 +568,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
|||
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
||||
|
||||
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
|
||||
fattr->cf_dtype = DT_DIR;
|
||||
|
@ -548,7 +576,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
|||
* Server can return wrong NumberOfLinks value for directories
|
||||
* when Unix extensions are disabled - fake it.
|
||||
*/
|
||||
fattr->cf_nlink = 2;
|
||||
if (!tcon->unix_ext)
|
||||
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
|
||||
} else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
|
||||
fattr->cf_mode = S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
|
@ -561,11 +590,15 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
|||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~(S_IWUGO);
|
||||
|
||||
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||
if (fattr->cf_nlink < 1) {
|
||||
cifs_dbg(1, "replacing bogus file nlink value %u\n",
|
||||
/*
|
||||
* Don't accept zero nlink from non-unix servers unless
|
||||
* delete is pending. Instead mark it as unknown.
|
||||
*/
|
||||
if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
|
||||
!info->DeletePending) {
|
||||
cifs_dbg(1, "bogus file nlink value %u\n",
|
||||
fattr->cf_nlink);
|
||||
fattr->cf_nlink = 1;
|
||||
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
|||
fattr->cf_dtype = DT_REG;
|
||||
}
|
||||
|
||||
/* non-unix readdir doesn't provide nlink */
|
||||
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~S_IWUGO;
|
||||
|
||||
|
|
|
@ -32,88 +32,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include "cifs_spnego.h"
|
||||
|
||||
/*
|
||||
* Checks if this is the first smb session to be reconnected after
|
||||
* the socket has been reestablished (so we know whether to use vc 0).
|
||||
* Called while holding the cifs_tcp_ses_lock, so do not block
|
||||
*/
|
||||
static bool is_first_ses_reconnect(struct cifs_ses *ses)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct cifs_ses *tmp_ses;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifs_ses,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->need_reconnect == false)
|
||||
return false;
|
||||
}
|
||||
/* could not find a session that was already connected,
|
||||
this must be the first one we are reconnecting */
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* vc number 0 is treated specially by some servers, and should be the
|
||||
* first one we request. After that we can use vcnumbers up to maxvcs,
|
||||
* one for each smb session (some Windows versions set maxvcs incorrectly
|
||||
* so maxvc=1 can be ignored). If we have too many vcs, we can reuse
|
||||
* any vc but zero (some servers reset the connection on vcnum zero)
|
||||
*
|
||||
*/
|
||||
static __le16 get_next_vcnum(struct cifs_ses *ses)
|
||||
{
|
||||
__u16 vcnum = 0;
|
||||
struct list_head *tmp;
|
||||
struct cifs_ses *tmp_ses;
|
||||
__u16 max_vcs = ses->server->max_vcs;
|
||||
__u16 i;
|
||||
int free_vc_found = 0;
|
||||
|
||||
/* Quoting the MS-SMB specification: "Windows-based SMB servers set this
|
||||
field to one but do not enforce this limit, which allows an SMB client
|
||||
to establish more virtual circuits than allowed by this value ... but
|
||||
other server implementations can enforce this limit." */
|
||||
if (max_vcs < 2)
|
||||
max_vcs = 0xFFFF;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
|
||||
goto get_vc_num_exit; /* vcnum will be zero */
|
||||
for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
|
||||
if (i == 0) /* this is the only connection, use vc 0 */
|
||||
break;
|
||||
|
||||
free_vc_found = 1;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifs_ses,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->vcnum == i) {
|
||||
free_vc_found = 0;
|
||||
break; /* found duplicate, try next vcnum */
|
||||
}
|
||||
}
|
||||
if (free_vc_found)
|
||||
break; /* we found a vcnumber that will work - use it */
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
vcnum = 0; /* for most common case, ie if one smb session, use
|
||||
vc zero. Also for case when no free vcnum, zero
|
||||
is safest to send (some clients only send zero) */
|
||||
else if (free_vc_found == 0)
|
||||
vcnum = 1; /* we can not reuse vc=0 safely, since some servers
|
||||
reset all uids on that, but 1 is ok. */
|
||||
else
|
||||
vcnum = i;
|
||||
ses->vcnum = vcnum;
|
||||
get_vc_num_exit:
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return cpu_to_le16(vcnum);
|
||||
}
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
|
||||
{
|
||||
__u32 capabilities = 0;
|
||||
|
@ -128,7 +46,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
|
|||
CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
|
||||
USHRT_MAX));
|
||||
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||
pSMB->req.VcNumber = get_next_vcnum(ses);
|
||||
pSMB->req.VcNumber = __constant_cpu_to_le16(1);
|
||||
|
||||
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче