Twenty four cifs/smb3 client fixes, including multichannel but does not include the iov_iter ones

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmKRBV4ACgkQiiy9cAdy
 T1FYcgv7BWeF/72rw2qxuLUnj9B2aCnjCkpb2r7sN0951gTgFV9Iw4Bg5KyCym1A
 Pjl7H3hj0R/djIwzSTbPmsIUZxEzAB56MyKgaoBbkg0N0AfwHYqEOHpTa7c9NaqT
 CkbgJxtqcFBl3uNLMW9qyAD7MFDqF8OkSFCv01HYUukaQKBgzUnuoLmhvNQYeN50
 DhxSIk+6+ekyUpuTKitHclldbk8IbUDRO5jRZrhXjP7SObWID1EMVBz4QNyrw3Du
 G3Mi4K/FbVkrHe4OTcyMMc4rTVbaOwaHJmvgBFM5Qb1buaplbGEo7lTxus0PUVzd
 aWyaj2duXNuKjFZuov/ZCsnSJMvl2TG21Bku/uLNGKsnIQn7UhYCLcDyZa/UCnRE
 zPd5M2PD/L8uKONSg/6IVlVIzNMmvYRpyqqGg/4CZpu1Qhs53MkLdnZqSB+NyzV7
 O2I6CIGVbp64f8YyBFZ6bhdxBwyXeoiF3RkYeKYrtCp4Z0RfQYjyMb5t2NDcpVo/
 gL0tho/Q
 =bR0w
 -----END PGP SIGNATURE-----

Merge tag '5.19-rc-smb3-client-fixes-updated' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs client updates from Steve French:

 - multichannel fixes to improve reconnect after network failure

 - improved caching of root directory contents (extending benefit of
   directory leases)

 - two DFS fixes

 - three fixes for improved debugging

 - an NTLMSSP fix for mounts t0 older servers

 - new mount parm to allow disabling creating sparse files

 - various cleanup fixes and minor fixes pointed out by coverity

* tag '5.19-rc-smb3-client-fixes-updated' of git://git.samba.org/sfrench/cifs-2.6: (24 commits)
  smb3: remove unneeded null check in cifs_readdir
  cifs: fix ntlmssp on old servers
  cifs: cache the dirents for entries in a cached directory
  cifs: avoid parallel session setups on same channel
  cifs: use new enum for ses_status
  cifs: do not use tcpStatus after negotiate completes
  smb3: add mount parm nosparse
  smb3: don't set rc when used and unneeded in query_info_compound
  smb3: check for null tcon
  cifs: fix minor compile warning
  Add various fsctl structs
  Add defines for various newer FSCTLs
  smb3: add trace point for oplock not found
  cifs: return the more nuanced writeback error on close()
  smb3: add trace point for lease not found issue
  cifs: smbd: fix typo in comment
  cifs: set the CREATE_NOT_FILE when opening the directory in use_cached_dir()
  cifs: check for smb1 in open_cached_dir()
  cifs: move definition of cifs_fattr earlier in cifsglob.h
  cifs: print TIDs as hex
  ...
This commit is contained in:
Linus Torvalds 2022-05-27 16:05:57 -07:00
commit bf272460d7
24 changed files with 559 additions and 189 deletions

View File

@ -116,7 +116,8 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
tcon->ses->server->ops->dump_share_caps(m, tcon);
if (tcon->use_witness)
seq_puts(m, " Witness");
if (tcon->broken_sparse_sup)
seq_puts(m, " nosparse");
if (tcon->need_reconnect)
seq_puts(m, "\tDISCONNECTED ");
seq_putc(m, '\n');
@ -386,7 +387,7 @@ skip_rdma:
(ses->serverNOS == NULL)) {
seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
i, ses->ip_addr, ses->ses_count,
ses->capabilities, ses->status);
ses->capabilities, ses->ses_status);
if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
seq_printf(m, "Guest ");
else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
@ -398,7 +399,7 @@ skip_rdma:
"\n\tSMB session status: %d ",
i, ses->ip_addr, ses->serverDomain,
ses->ses_count, ses->serverOS, ses->serverNOS,
ses->capabilities, ses->status);
ses->capabilities, ses->ses_status);
}
seq_printf(m, "\n\tSecurity type: %s ",
@ -418,6 +419,8 @@ skip_rdma:
spin_lock(&ses->chan_lock);
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
seq_puts(m, "\tPrimary channel: DISCONNECTED ");
if (CIFS_CHAN_IN_RECONNECT(ses, 0))
seq_puts(m, "\t[RECONNECTING] ");
if (ses->chan_count > 1) {
seq_printf(m, "\n\n\tExtra Channels: %zu ",
@ -426,6 +429,8 @@ skip_rdma:
cifs_dump_channel(m, j, &ses->chans[j]);
if (CIFS_CHAN_NEEDS_RECONNECT(ses, j))
seq_puts(m, "\tDISCONNECTED ");
if (CIFS_CHAN_IN_RECONNECT(ses, j))
seq_puts(m, "\t[RECONNECTING] ");
}
}
spin_unlock(&ses->chan_lock);

View File

@ -582,6 +582,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",nocase");
if (tcon->nodelete)
seq_puts(s, ",nodelete");
if (cifs_sb->ctx->no_sparse)
seq_puts(s, ",nosparse");
if (tcon->local_lease)
seq_puts(s, ",locallease");
if (tcon->retry)

View File

@ -106,7 +106,7 @@
* CIFS vfs client Status information (based on what we know.)
*/
/* associated with each tcp and smb session */
/* associated with each connection */
enum statusEnum {
CifsNew = 0,
CifsGood,
@ -114,8 +114,15 @@ enum statusEnum {
CifsNeedReconnect,
CifsNeedNegotiate,
CifsInNegotiate,
CifsNeedSessSetup,
CifsInSessSetup,
};
/* associated with each smb session */
enum ses_status_enum {
SES_NEW = 0,
SES_GOOD,
SES_EXITING,
SES_NEED_RECON,
SES_IN_SETUP
};
/* associated with each tree connection to the server */
@ -915,6 +922,7 @@ struct cifs_server_iface {
};
struct cifs_chan {
unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
struct TCP_Server_Info *server;
__u8 signkey[SMB3_SIGN_KEY_SIZE];
};
@ -930,7 +938,7 @@ struct cifs_ses {
struct mutex session_mutex;
struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */
enum statusEnum status; /* updates protected by cifs_tcp_ses_lock */
enum ses_status_enum ses_status; /* updates protected by cifs_tcp_ses_lock */
unsigned overrideSecFlg; /* if non-zero override global sec flags */
char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */
@ -944,7 +952,7 @@ struct cifs_ses {
and after mount option parsing we fill it */
char *domainName;
char *password;
char *workstation_name;
char workstation_name[CIFS_MAX_WORKSTATION_LEN];
struct session_key auth_key;
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
enum securityEnum sectype; /* what security flavor was specified? */
@ -977,12 +985,16 @@ struct cifs_ses {
#define CIFS_MAX_CHANNELS 16
#define CIFS_ALL_CHANNELS_SET(ses) \
((1UL << (ses)->chan_count) - 1)
#define CIFS_ALL_CHANS_GOOD(ses) \
(!(ses)->chans_need_reconnect)
#define CIFS_ALL_CHANS_NEED_RECONNECT(ses) \
((ses)->chans_need_reconnect == CIFS_ALL_CHANNELS_SET(ses))
#define CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses) \
((ses)->chans_need_reconnect = CIFS_ALL_CHANNELS_SET(ses))
#define CIFS_CHAN_NEEDS_RECONNECT(ses, index) \
test_bit((index), &(ses)->chans_need_reconnect)
#define CIFS_CHAN_IN_RECONNECT(ses, index) \
((ses)->chans[(index)].in_reconnect)
struct cifs_chan chans[CIFS_MAX_CHANNELS];
size_t chan_count;
@ -1009,6 +1021,58 @@ cap_unix(struct cifs_ses *ses)
return ses->server->vals->cap_unix & ses->capabilities;
}
/*
* common struct for holding inode info when searching for or updating an
* inode with new info
*/
#define CIFS_FATTR_DFS_REFERRAL 0x1
#define CIFS_FATTR_DELETE_PENDING 0x2
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
#define CIFS_FATTR_FAKE_ROOT_INO 0x20
struct cifs_fattr {
u32 cf_flags;
u32 cf_cifsattrs;
u64 cf_uniqueid;
u64 cf_eof;
u64 cf_bytes;
u64 cf_createtime;
kuid_t cf_uid;
kgid_t cf_gid;
umode_t cf_mode;
dev_t cf_rdev;
unsigned int cf_nlink;
unsigned int cf_dtype;
struct timespec64 cf_atime;
struct timespec64 cf_mtime;
struct timespec64 cf_ctime;
u32 cf_cifstag;
};
struct cached_dirent {
struct list_head entry;
char *name;
int namelen;
loff_t pos;
struct cifs_fattr fattr;
};
struct cached_dirents {
bool is_valid:1;
bool is_failed:1;
struct dir_context *ctx; /*
* Only used to make sure we only take entries
* from a single context. Never dereferenced.
*/
struct mutex de_mutex;
int pos; /* Expected ctx->pos */
struct list_head entries;
};
struct cached_fid {
bool is_valid:1; /* Do we have a useable root fid */
bool file_all_info_is_valid:1;
@ -1021,6 +1085,7 @@ struct cached_fid {
struct dentry *dentry;
struct work_struct lease_break;
struct smb2_file_all_info file_all_info;
struct cached_dirents dirents;
};
/*
@ -1641,37 +1706,6 @@ struct file_list {
struct cifsFileInfo *cfile;
};
/*
* common struct for holding inode info when searching for or updating an
* inode with new info
*/
#define CIFS_FATTR_DFS_REFERRAL 0x1
#define CIFS_FATTR_DELETE_PENDING 0x2
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
#define CIFS_FATTR_FAKE_ROOT_INO 0x20
struct cifs_fattr {
u32 cf_flags;
u32 cf_cifsattrs;
u64 cf_uniqueid;
u64 cf_eof;
u64 cf_bytes;
u64 cf_createtime;
kuid_t cf_uid;
kgid_t cf_gid;
umode_t cf_mode;
dev_t cf_rdev;
unsigned int cf_nlink;
unsigned int cf_dtype;
struct timespec64 cf_atime;
struct timespec64 cf_mtime;
struct timespec64 cf_ctime;
u32 cf_cifstag;
};
static inline void free_dfs_info_param(struct dfs_info3_param *param)
{
if (param) {
@ -1979,4 +2013,22 @@ static inline bool cifs_is_referral_server(struct cifs_tcon *tcon,
return is_tcon_dfs(tcon) || (ref && (ref->flags & DFSREF_REFERRAL_SERVER));
}
static inline u64 cifs_flock_len(struct file_lock *fl)
{
return fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1;
}
static inline size_t ntlmssp_workstation_name_size(const struct cifs_ses *ses)
{
if (WARN_ON_ONCE(!ses || !ses->server))
return 0;
/*
* Make workstation name no more than 15 chars when using insecure dialects as some legacy
* servers do require it during NTLMSSP.
*/
if (ses->server->dialect <= SMB20_PROT_ID)
return min_t(size_t, sizeof(ses->workstation_name), RFC1001_NAME_LEN_WITH_NULL);
return sizeof(ses->workstation_name);
}
#endif /* _CIFS_GLOB_H */

View File

@ -619,6 +619,15 @@ unsigned int
cifs_ses_get_chan_index(struct cifs_ses *ses,
struct TCP_Server_Info *server);
void
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server);
void
cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server);
bool
cifs_chan_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server);
void
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server);
void

View File

@ -75,7 +75,7 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
/* only send once per connect */
spin_lock(&cifs_tcp_ses_lock);
if ((tcon->ses->status != CifsGood) || (tcon->status != TID_NEED_RECON)) {
if ((tcon->ses->ses_status != SES_GOOD) || (tcon->status != TID_NEED_RECON)) {
spin_unlock(&cifs_tcp_ses_lock);
return;
}
@ -2558,7 +2558,8 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
pLockData->fl_start = le64_to_cpu(parm_data->start);
pLockData->fl_end = pLockData->fl_start +
le64_to_cpu(parm_data->length) - 1;
(le64_to_cpu(parm_data->length) ?
le64_to_cpu(parm_data->length) - 1 : 0);
pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
}
}

View File

@ -241,7 +241,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
goto next_session;
ses->status = CifsNeedReconnect;
ses->ses_status = SES_NEED_RECON;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
tcon->need_reconnect = true;
@ -1789,7 +1789,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
goto out;
}
cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
ses->tcon_ipc = tcon;
out:
@ -1828,7 +1828,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
if (ses->status == CifsExiting)
if (ses->ses_status == SES_EXITING)
continue;
if (!match_session(ses, ctx))
continue;
@ -1848,7 +1848,7 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
spin_lock(&cifs_tcp_ses_lock);
if (ses->status == CifsExiting) {
if (ses->ses_status == SES_EXITING) {
spin_unlock(&cifs_tcp_ses_lock);
return;
}
@ -1864,13 +1864,13 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
/* ses_count can never go negative */
WARN_ON(ses->ses_count < 0);
if (ses->status == CifsGood)
ses->status = CifsExiting;
if (ses->ses_status == SES_GOOD)
ses->ses_status = SES_EXITING;
spin_unlock(&cifs_tcp_ses_lock);
cifs_free_ipc(ses);
if (ses->status == CifsExiting && server->ops->logoff) {
if (ses->ses_status == SES_EXITING && server->ops->logoff) {
xid = get_xid();
rc = server->ops->logoff(xid, ses);
if (rc)
@ -2037,18 +2037,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
}
}
ctx->workstation_name = kstrdup(ses->workstation_name, GFP_KERNEL);
if (!ctx->workstation_name) {
cifs_dbg(FYI, "Unable to allocate memory for workstation_name\n");
rc = -ENOMEM;
kfree(ctx->username);
ctx->username = NULL;
kfree_sensitive(ctx->password);
ctx->password = NULL;
kfree(ctx->domainname);
ctx->domainname = NULL;
goto out_key_put;
}
strscpy(ctx->workstation_name, ses->workstation_name, sizeof(ctx->workstation_name));
out_key_put:
up_read(&key->sem);
@ -2090,7 +2079,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
ses = cifs_find_smb_ses(server, ctx);
if (ses) {
cifs_dbg(FYI, "Existing smb sess found (status=%d)\n",
ses->status);
ses->ses_status);
spin_lock(&ses->chan_lock);
if (cifs_chan_needs_reconnect(ses, server)) {
@ -2157,12 +2146,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
if (!ses->domainName)
goto get_ses_fail;
}
if (ctx->workstation_name) {
ses->workstation_name = kstrdup(ctx->workstation_name,
GFP_KERNEL);
if (!ses->workstation_name)
goto get_ses_fail;
}
strscpy(ses->workstation_name, ctx->workstation_name, sizeof(ses->workstation_name));
if (ctx->domainauto)
ses->domainAuto = ctx->domainauto;
ses->cred_uid = ctx->cred_uid;
@ -2509,6 +2495,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
*/
tcon->retry = ctx->retry;
tcon->nocase = ctx->nocase;
tcon->broken_sparse_sup = ctx->no_sparse;
if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
tcon->nohandlecache = ctx->nohandlecache;
else
@ -3420,8 +3407,9 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
}
/*
* Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
* otherwise 0.
* Check if path is remote (i.e. a DFS share).
*
* Return -EREMOTE if it is, otherwise 0 or -errno.
*/
static int is_path_remote(struct mount_ctx *mnt_ctx)
{
@ -3432,6 +3420,9 @@ static int is_path_remote(struct mount_ctx *mnt_ctx)
struct cifs_tcon *tcon = mnt_ctx->tcon;
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
char *full_path;
#ifdef CONFIG_CIFS_DFS_UPCALL
bool nodfs = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS;
#endif
if (!server->ops->is_path_accessible)
return -EOPNOTSUPP;
@ -3449,14 +3440,20 @@ static int is_path_remote(struct mount_ctx *mnt_ctx)
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
full_path);
#ifdef CONFIG_CIFS_DFS_UPCALL
if (nodfs) {
if (rc == -EREMOTE)
rc = -EOPNOTSUPP;
goto out;
}
/* path *might* exist with non-ASCII characters in DFS root
* try again with full path (only if nodfs is not set) */
if (rc == -ENOENT && is_tcon_dfs(tcon))
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon, cifs_sb,
full_path);
#endif
if (rc != 0 && rc != -EREMOTE) {
kfree(full_path);
return rc;
}
if (rc != 0 && rc != -EREMOTE)
goto out;
if (rc != -EREMOTE) {
rc = cifs_are_all_path_components_accessible(server, xid, tcon,
@ -3468,6 +3465,7 @@ static int is_path_remote(struct mount_ctx *mnt_ctx)
}
}
out:
kfree(full_path);
return rc;
}
@ -3703,6 +3701,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
if (!isdfs)
goto out;
/* proceed as DFS mount */
uuid_gen(&mnt_ctx.mount_id);
rc = connect_dfs_root(&mnt_ctx, &tl);
dfs_cache_free_tgts(&tl);
@ -3960,7 +3959,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
if (rc == 0) {
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsInNegotiate)
server->tcpStatus = CifsNeedSessSetup;
server->tcpStatus = CifsGood;
else
rc = -EHOSTDOWN;
spin_unlock(&cifs_tcp_ses_lock);
@ -3982,20 +3981,31 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
int rc = -ENOSYS;
bool is_binding = false;
/* only send once per connect */
spin_lock(&cifs_tcp_ses_lock);
if ((server->tcpStatus != CifsNeedSessSetup) &&
(ses->status == CifsGood)) {
if (ses->ses_status != SES_GOOD &&
ses->ses_status != SES_NEW &&
ses->ses_status != SES_NEED_RECON) {
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
server->tcpStatus = CifsInSessSetup;
spin_unlock(&cifs_tcp_ses_lock);
/* only send once per connect */
spin_lock(&ses->chan_lock);
if (CIFS_ALL_CHANS_GOOD(ses) ||
cifs_chan_in_reconnect(ses, server)) {
spin_unlock(&ses->chan_lock);
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
cifs_chan_set_in_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
if (!is_binding)
ses->ses_status = SES_IN_SETUP;
spin_unlock(&cifs_tcp_ses_lock);
if (!is_binding) {
ses->capabilities = server->capabilities;
if (!linuxExtEnabled)
@ -4019,20 +4029,21 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
if (rc) {
cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsInSessSetup)
server->tcpStatus = CifsNeedSessSetup;
if (ses->ses_status == SES_IN_SETUP)
ses->ses_status = SES_NEED_RECON;
spin_lock(&ses->chan_lock);
cifs_chan_clear_in_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
spin_unlock(&cifs_tcp_ses_lock);
} else {
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsInSessSetup)
server->tcpStatus = CifsGood;
/* Even if one channel is active, session is in good state */
ses->status = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
if (ses->ses_status == SES_IN_SETUP)
ses->ses_status = SES_GOOD;
spin_lock(&ses->chan_lock);
cifs_chan_clear_in_reconnect(ses, server);
cifs_chan_clear_need_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
spin_unlock(&cifs_tcp_ses_lock);
}
return rc;
@ -4497,7 +4508,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */
spin_lock(&cifs_tcp_ses_lock);
if (tcon->ses->status != CifsGood ||
if (tcon->ses->ses_status != SES_GOOD ||
(tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON)) {
spin_unlock(&cifs_tcp_ses_lock);
@ -4565,7 +4576,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */
spin_lock(&cifs_tcp_ses_lock);
if (tcon->ses->status != CifsGood ||
if (tcon->ses->ses_status != SES_GOOD ||
(tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON)) {
spin_unlock(&cifs_tcp_ses_lock);

View File

@ -654,7 +654,7 @@ static struct cache_entry *__lookup_cache_entry(const char *path, unsigned int h
return ce;
}
}
return ERR_PTR(-EEXIST);
return ERR_PTR(-ENOENT);
}
/*
@ -662,7 +662,7 @@ static struct cache_entry *__lookup_cache_entry(const char *path, unsigned int h
*
* Use whole path components in the match. Must be called with htable_rw_lock held.
*
* Return ERR_PTR(-EEXIST) if the entry is not found.
* Return ERR_PTR(-ENOENT) if the entry is not found.
*/
static struct cache_entry *lookup_cache_entry(const char *path)
{
@ -710,7 +710,7 @@ static struct cache_entry *lookup_cache_entry(const char *path)
while (e > s && *e != sep)
e--;
}
return ERR_PTR(-EEXIST);
return ERR_PTR(-ENOENT);
}
/**

View File

@ -1395,7 +1395,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
cifs_dbg(VFS, "Can't push all brlocks!\n");
break;
}
length = 1 + flock->fl_end - flock->fl_start;
length = cifs_flock_len(flock);
if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
type = CIFS_RDLCK;
else
@ -1511,7 +1511,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
bool wait_flag, bool posix_lck, unsigned int xid)
{
int rc = 0;
__u64 length = 1 + flock->fl_end - flock->fl_start;
__u64 length = cifs_flock_len(flock);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
@ -1609,7 +1609,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
struct cifsLockInfo *li, *tmp;
__u64 length = 1 + flock->fl_end - flock->fl_start;
__u64 length = cifs_flock_len(flock);
struct list_head tmp_llist;
INIT_LIST_HEAD(&tmp_llist);
@ -1713,7 +1713,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
unsigned int xid)
{
int rc = 0;
__u64 length = 1 + flock->fl_end - flock->fl_start;
__u64 length = cifs_flock_len(flock);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
@ -2777,8 +2777,11 @@ int cifs_flush(struct file *file, fl_owner_t id)
rc = filemap_write_and_wait(inode->i_mapping);
cifs_dbg(FYI, "Flush inode %p file %p rc %d\n", inode, file, rc);
if (rc)
if (rc) {
/* get more nuanced writeback errors */
rc = filemap_check_wb_err(file->f_mapping, 0);
trace_cifs_flush_err(inode->i_ino, rc);
}
return rc;
}

View File

@ -119,6 +119,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_flag_no("persistenthandles", Opt_persistent),
fsparam_flag_no("resilienthandles", Opt_resilient),
fsparam_flag_no("tcpnodelay", Opt_tcp_nodelay),
fsparam_flag("nosparse", Opt_nosparse),
fsparam_flag("domainauto", Opt_domainauto),
fsparam_flag("rdma", Opt_rdma),
fsparam_flag("modesid", Opt_modesid),
@ -312,7 +313,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
new_ctx->password = NULL;
new_ctx->server_hostname = NULL;
new_ctx->domainname = NULL;
new_ctx->workstation_name = NULL;
new_ctx->UNC = NULL;
new_ctx->source = NULL;
new_ctx->iocharset = NULL;
@ -327,7 +327,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
DUP_CTX_STR(UNC);
DUP_CTX_STR(source);
DUP_CTX_STR(domainname);
DUP_CTX_STR(workstation_name);
DUP_CTX_STR(nodename);
DUP_CTX_STR(iocharset);
@ -766,8 +765,7 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
cifs_errorf(fc, "can not change domainname during remount\n");
return -EINVAL;
}
if (new_ctx->workstation_name &&
(!old_ctx->workstation_name || strcmp(new_ctx->workstation_name, old_ctx->workstation_name))) {
if (strcmp(new_ctx->workstation_name, old_ctx->workstation_name)) {
cifs_errorf(fc, "can not change workstation_name during remount\n");
return -EINVAL;
}
@ -814,7 +812,6 @@ static int smb3_reconfigure(struct fs_context *fc)
STEAL_STRING(cifs_sb, ctx, username);
STEAL_STRING(cifs_sb, ctx, password);
STEAL_STRING(cifs_sb, ctx, domainname);
STEAL_STRING(cifs_sb, ctx, workstation_name);
STEAL_STRING(cifs_sb, ctx, nodename);
STEAL_STRING(cifs_sb, ctx, iocharset);
@ -943,6 +940,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
case Opt_nolease:
ctx->no_lease = 1;
break;
case Opt_nosparse:
ctx->no_sparse = 1;
break;
case Opt_nodelete:
ctx->nodelete = 1;
break;
@ -1467,22 +1467,15 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
int smb3_init_fs_context(struct fs_context *fc)
{
int rc;
struct smb3_fs_context *ctx;
char *nodename = utsname()->nodename;
int i;
ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
if (unlikely(!ctx)) {
rc = -ENOMEM;
goto err_exit;
}
if (unlikely(!ctx))
return -ENOMEM;
ctx->workstation_name = kstrdup(nodename, GFP_KERNEL);
if (unlikely(!ctx->workstation_name)) {
rc = -ENOMEM;
goto err_exit;
}
strscpy(ctx->workstation_name, nodename, sizeof(ctx->workstation_name));
/*
* does not have to be perfect mapping since field is
@ -1555,14 +1548,6 @@ int smb3_init_fs_context(struct fs_context *fc)
fc->fs_private = ctx;
fc->ops = &smb3_fs_context_ops;
return 0;
err_exit:
if (ctx) {
kfree(ctx->workstation_name);
kfree(ctx);
}
return rc;
}
void
@ -1588,8 +1573,6 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
ctx->source = NULL;
kfree(ctx->domainname);
ctx->domainname = NULL;
kfree(ctx->workstation_name);
ctx->workstation_name = NULL;
kfree(ctx->nodename);
ctx->nodename = NULL;
kfree(ctx->iocharset);

View File

@ -62,6 +62,7 @@ enum cifs_param {
Opt_noblocksend,
Opt_noautotune,
Opt_nolease,
Opt_nosparse,
Opt_hard,
Opt_soft,
Opt_perm,
@ -170,7 +171,7 @@ struct smb3_fs_context {
char *server_hostname;
char *UNC;
char *nodename;
char *workstation_name;
char workstation_name[CIFS_MAX_WORKSTATION_LEN];
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
@ -222,6 +223,7 @@ struct smb3_fs_context {
bool noautotune:1;
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
bool no_lease:1; /* disable requesting leases */
bool no_sparse:1; /* do not attempt to set files sparse */
bool fsc:1; /* enable fscache */
bool mfsymlinks:1; /* use Minshall+French Symlinks */
bool multiuser:1;

View File

@ -69,7 +69,7 @@ sesInfoAlloc(void)
ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
if (ret_buf) {
atomic_inc(&sesInfoAllocCount);
ret_buf->status = CifsNew;
ret_buf->ses_status = SES_NEW;
++ret_buf->ses_count;
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list);
@ -95,7 +95,6 @@ sesInfoFree(struct cifs_ses *buf_to_free)
kfree_sensitive(buf_to_free->password);
kfree(buf_to_free->user_name);
kfree(buf_to_free->domainName);
kfree(buf_to_free->workstation_name);
kfree_sensitive(buf_to_free->auth_key.response);
kfree(buf_to_free->iface_list);
kfree_sensitive(buf_to_free);
@ -114,6 +113,8 @@ tconInfoAlloc(void)
kfree(ret_buf);
return NULL;
}
INIT_LIST_HEAD(&ret_buf->crfid.dirents.entries);
mutex_init(&ret_buf->crfid.dirents.de_mutex);
atomic_inc(&tconInfoAllocCount);
ret_buf->status = TID_NEW;
@ -1309,7 +1310,7 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
* for "\<server>\<dfsname>\<linkpath>" DFS reference,
* where <dfsname> contains non-ASCII unicode symbols.
*
* Check such DFS reference and emulate -ENOENT if it is actual.
* Check such DFS reference.
*/
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
struct cifs_tcon *tcon,
@ -1341,10 +1342,6 @@ int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
cifs_dbg(FYI, "DFS ref '%s' is found, emulate -EREMOTE\n",
dfspath);
rc = -EREMOTE;
} else if (rc == -EEXIST) {
cifs_dbg(FYI, "DFS ref '%s' is not found, emulate -ENOENT\n",
dfspath);
rc = -ENOENT;
} else {
cifs_dbg(FYI, "%s: dfs_cache_find returned %d\n", __func__, rc);
}

View File

@ -840,9 +840,109 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
return rc;
}
static bool emit_cached_dirents(struct cached_dirents *cde,
struct dir_context *ctx)
{
struct cached_dirent *dirent;
int rc;
list_for_each_entry(dirent, &cde->entries, entry) {
if (ctx->pos >= dirent->pos)
continue;
ctx->pos = dirent->pos;
rc = dir_emit(ctx, dirent->name, dirent->namelen,
dirent->fattr.cf_uniqueid,
dirent->fattr.cf_dtype);
if (!rc)
return rc;
}
return true;
}
static void update_cached_dirents_count(struct cached_dirents *cde,
struct dir_context *ctx)
{
if (cde->ctx != ctx)
return;
if (cde->is_valid || cde->is_failed)
return;
cde->pos++;
}
static void finished_cached_dirents_count(struct cached_dirents *cde,
struct dir_context *ctx)
{
if (cde->ctx != ctx)
return;
if (cde->is_valid || cde->is_failed)
return;
if (ctx->pos != cde->pos)
return;
cde->is_valid = 1;
}
static void add_cached_dirent(struct cached_dirents *cde,
struct dir_context *ctx,
const char *name, int namelen,
struct cifs_fattr *fattr)
{
struct cached_dirent *de;
if (cde->ctx != ctx)
return;
if (cde->is_valid || cde->is_failed)
return;
if (ctx->pos != cde->pos) {
cde->is_failed = 1;
return;
}
de = kzalloc(sizeof(*de), GFP_ATOMIC);
if (de == NULL) {
cde->is_failed = 1;
return;
}
de->namelen = namelen;
de->name = kstrndup(name, namelen, GFP_ATOMIC);
if (de->name == NULL) {
kfree(de);
cde->is_failed = 1;
return;
}
de->pos = ctx->pos;
memcpy(&de->fattr, fattr, sizeof(struct cifs_fattr));
list_add_tail(&de->entry, &cde->entries);
}
static bool cifs_dir_emit(struct dir_context *ctx,
const char *name, int namelen,
struct cifs_fattr *fattr,
struct cached_fid *cfid)
{
bool rc;
ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
rc = dir_emit(ctx, name, namelen, ino, fattr->cf_dtype);
if (!rc)
return rc;
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
add_cached_dirent(&cfid->dirents, ctx, name, namelen,
fattr);
mutex_unlock(&cfid->dirents.de_mutex);
}
return rc;
}
static int cifs_filldir(char *find_entry, struct file *file,
struct dir_context *ctx,
char *scratch_buf, unsigned int max_len)
struct dir_context *ctx,
char *scratch_buf, unsigned int max_len,
struct cached_fid *cfid)
{
struct cifsFileInfo *file_info = file->private_data;
struct super_block *sb = file_inode(file)->i_sb;
@ -851,7 +951,6 @@ static int cifs_filldir(char *find_entry, struct file *file,
struct cifs_fattr fattr;
struct qstr name;
int rc = 0;
ino_t ino;
rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
file_info->srch_inf.unicode);
@ -931,8 +1030,8 @@ static int cifs_filldir(char *find_entry, struct file *file,
cifs_prime_dcache(file_dentry(file), &name, &fattr);
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
return !cifs_dir_emit(ctx, name.name, name.len,
&fattr, cfid);
}
@ -941,8 +1040,9 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
int rc = 0;
unsigned int xid;
int i;
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon;
struct cifsFileInfo *cifsFile = NULL;
struct cifsFileInfo *cifsFile;
char *current_entry;
int num_to_fill = 0;
char *tmp_buf = NULL;
@ -950,6 +1050,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
unsigned int max_len;
const char *full_path;
void *page = alloc_dentry_path();
struct cached_fid *cfid = NULL;
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
xid = get_xid();
@ -959,6 +1061,54 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
goto rddir2_exit;
}
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
goto cache_not_found;
tcon = tlink_tcon(tlink);
} else {
cifsFile = file->private_data;
tcon = tlink_tcon(cifsFile->tlink);
}
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
cifs_put_tlink(tlink);
if (rc)
goto cache_not_found;
mutex_lock(&cfid->dirents.de_mutex);
/*
* If this was reading from the start of the directory
* we need to initialize scanning and storing the
* directory content.
*/
if (ctx->pos == 0 && cfid->dirents.ctx == NULL) {
cfid->dirents.ctx = ctx;
cfid->dirents.pos = 2;
}
/*
* If we already have the entire directory cached then
* we can just serve the cache.
*/
if (cfid->dirents.is_valid) {
if (!dir_emit_dots(file, ctx)) {
mutex_unlock(&cfid->dirents.de_mutex);
goto rddir2_exit;
}
emit_cached_dirents(&cfid->dirents, ctx);
mutex_unlock(&cfid->dirents.de_mutex);
goto rddir2_exit;
}
mutex_unlock(&cfid->dirents.de_mutex);
/* Drop the cache while calling initiate_cifs_search and
* find_cifs_entry in case there will be reconnects during
* query_directory.
*/
close_cached_dir(cfid);
cfid = NULL;
cache_not_found:
/*
* Ensure FindFirst doesn't fail before doing filldir() for '.' and
* '..'. Otherwise we won't be able to notify VFS in case of failure.
@ -977,7 +1127,6 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
is in current search buffer?
if it before then restart search
if after then keep searching till find it */
cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) {
if (cifsFile->srch_inf.emptyDir) {
@ -993,12 +1142,18 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
tcon = tlink_tcon(cifsFile->tlink);
rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path,
&current_entry, &num_to_fill);
open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
if (rc) {
cifs_dbg(FYI, "fce error %d\n", rc);
goto rddir2_exit;
} else if (current_entry != NULL) {
cifs_dbg(FYI, "entry %lld found\n", ctx->pos);
} else {
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
finished_cached_dirents_count(&cfid->dirents, ctx);
mutex_unlock(&cfid->dirents.de_mutex);
}
cifs_dbg(FYI, "Could not find entry\n");
goto rddir2_exit;
}
@ -1028,7 +1183,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
*/
*tmp_buf = 0;
rc = cifs_filldir(current_entry, file, ctx,
tmp_buf, max_len);
tmp_buf, max_len, cfid);
if (rc) {
if (rc > 0)
rc = 0;
@ -1036,6 +1191,12 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
}
ctx->pos++;
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
update_cached_dirents_count(&cfid->dirents, ctx);
mutex_unlock(&cfid->dirents.de_mutex);
}
if (ctx->pos ==
cifsFile->srch_inf.index_of_last_entry) {
cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
@ -1050,6 +1211,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
kfree(tmp_buf);
rddir2_exit:
if (cfid)
close_cached_dir(cfid);
free_dentry_path(page);
free_xid(xid);
return rc;

View File

@ -85,6 +85,33 @@ cifs_ses_get_chan_index(struct cifs_ses *ses,
return 0;
}
void
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
ses->chans[chan_index].in_reconnect = true;
}
void
cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
ses->chans[chan_index].in_reconnect = false;
}
bool
cifs_chan_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
}
void
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
@ -714,9 +741,9 @@ static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
else
sz += sizeof(__le16);
if (ses->workstation_name)
if (ses->workstation_name[0])
sz += sizeof(__le16) * strnlen(ses->workstation_name,
CIFS_MAX_WORKSTATION_LEN);
ntlmssp_workstation_name_size(ses));
else
sz += sizeof(__le16);
@ -960,7 +987,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
cifs_security_buffer_from_str(&sec_blob->WorkstationName,
ses->workstation_name,
CIFS_MAX_WORKSTATION_LEN,
ntlmssp_workstation_name_size(ses),
*pbuffer, &tmp,
nls_cp);

View File

@ -362,8 +362,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
num_rqst++;
if (cfile) {
cifsFileInfo_put(cfile);
cfile = NULL;
rc = compound_send_recv(xid, ses, server,
flags, num_rqst - 2,
&rqst[1], &resp_buftype[1],
@ -514,8 +512,11 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
if (smb2_data == NULL)
return -ENOMEM;
if (strcmp(full_path, ""))
rc = -ENOENT;
else
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
/* If it is a root and its handle is cached then use it */
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
if (!rc) {
if (tcon->crfid.file_all_info_is_valid) {
move_smb2_info_to_cifs(data,

View File

@ -656,6 +656,12 @@ smb2_is_valid_lease_break(char *buffer)
}
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
trace_smb3_lease_not_found(le32_to_cpu(rsp->CurrentLeaseState),
le32_to_cpu(rsp->hdr.Id.SyncId.TreeId),
le64_to_cpu(rsp->hdr.SessionId),
*((u64 *)rsp->LeaseKey),
*((u64 *)&rsp->LeaseKey[8]));
return false;
}
@ -726,6 +732,10 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
}
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "No file id matched, oplock break ignored\n");
trace_smb3_oplock_not_found(0 /* no xid */, rsp->PersistentFid,
le32_to_cpu(rsp->hdr.Id.SyncId.TreeId),
le64_to_cpu(rsp->hdr.SessionId));
return true;
}
@ -798,7 +808,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
if (tcon->ses)
server = tcon->ses->server;
cifs_server_dbg(FYI, "tid=%u: tcon is closing, skipping async close retry of fid %llu %llu\n",
cifs_server_dbg(FYI, "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n",
tcon->tid, persistent_fid, volatile_fid);
return 0;

View File

@ -699,6 +699,7 @@ smb2_close_cached_fid(struct kref *ref)
{
struct cached_fid *cfid = container_of(ref, struct cached_fid,
refcount);
struct cached_dirent *dirent, *q;
if (cfid->is_valid) {
cifs_dbg(FYI, "clear cached root file handle\n");
@ -718,6 +719,21 @@ smb2_close_cached_fid(struct kref *ref)
dput(cfid->dentry);
cfid->dentry = NULL;
}
/*
* Delete all cached dirent names
*/
mutex_lock(&cfid->dirents.de_mutex);
list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) {
list_del(&dirent->entry);
kfree(dirent->name);
kfree(dirent);
}
cfid->dirents.is_valid = 0;
cfid->dirents.is_failed = 0;
cfid->dirents.ctx = NULL;
cfid->dirents.pos = 0;
mutex_unlock(&cfid->dirents.de_mutex);
}
void close_cached_dir(struct cached_fid *cfid)
@ -754,14 +770,15 @@ smb2_cached_lease_break(struct work_struct *work)
/*
* Open the and cache a directory handle.
* Only supported for the root handle.
* If error then *cfid is not initialized.
*/
int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
const char *path,
struct cifs_sb_info *cifs_sb,
struct cached_fid **cfid)
{
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = ses->server;
struct cifs_ses *ses;
struct TCP_Server_Info *server;
struct cifs_open_parms oparms;
struct smb2_create_rsp *o_rsp = NULL;
struct smb2_query_info_rsp *qi_rsp = NULL;
@ -776,9 +793,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid *pfid;
struct dentry *dentry;
if (tcon->nohandlecache)
if (tcon == NULL || tcon->nohandlecache ||
is_smb1_server(tcon->ses->server))
return -ENOTSUPP;
ses = tcon->ses;
server = ses->server;
if (cifs_sb->root == NULL)
return -ENOENT;
@ -824,7 +845,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
oparms.tcon = tcon;
oparms.create_options = cifs_create_options(cifs_sb, 0);
oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE);
oparms.desired_access = FILE_READ_ATTRIBUTES;
oparms.disposition = FILE_OPEN;
oparms.fid = pfid;
@ -2695,7 +2716,8 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
memset(rsp_iov, 0, sizeof(rsp_iov));
rc = open_cached_dir(xid, tcon, path, cifs_sb, &cfid);
if (!strcmp(path, ""))
open_cached_dir(xid, tcon, path, cifs_sb, &cfid); /* cfid null if open dir failed */
memset(&open_iov, 0, sizeof(open_iov));
rqst[0].rq_iov = open_iov;

View File

@ -179,7 +179,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
}
}
spin_unlock(&cifs_tcp_ses_lock);
if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
if ((!tcon->ses) || (tcon->ses->ses_status == SES_EXITING) ||
(!tcon->ses->server) || !server)
return -EIO;
@ -3899,7 +3899,8 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_dbg(FYI, "In echo request for conn_id %lld\n", server->conn_id);
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) {
if (server->ops->need_neg &&
server->ops->need_neg(server)) {
spin_unlock(&cifs_tcp_ses_lock);
/* No need to send echo on newly established connections */
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);

View File

@ -260,28 +260,6 @@ struct get_retrieval_pointers_refcount_rsp {
struct smb3_extents extents[];
} __packed;
struct fsctl_set_integrity_information_req {
__le16 ChecksumAlgorithm;
__le16 Reserved;
__le32 Flags;
} __packed;
struct fsctl_get_integrity_information_rsp {
__le16 ChecksumAlgorithm;
__le16 Reserved;
__le32 Flags;
__le32 ChecksumChunkSizeInBytes;
__le32 ClusterSizeInBytes;
} __packed;
/* Integrity ChecksumAlgorithm choices for above */
#define CHECKSUM_TYPE_NONE 0x0000
#define CHECKSUM_TYPE_CRC64 0x0002
#define CHECKSUM_TYPE_UNCHANGED 0xFFFF /* set only */
/* Integrity flags for above */
#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001
/* See MS-DFSC 2.2.2 */
struct fsctl_get_dfs_referral_req {
__le16 MaxReferralLevel;

View File

@ -641,7 +641,8 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (!is_signed)
return 0;
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) {
if (server->ops->need_neg &&
server->ops->need_neg(server)) {
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
@ -779,7 +780,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
return -EAGAIN;
}
if (ses->status == CifsNew) {
if (ses->ses_status == SES_NEW) {
if ((shdr->Command != SMB2_SESSION_SETUP) &&
(shdr->Command != SMB2_NEGOTIATE)) {
spin_unlock(&cifs_tcp_ses_lock);
@ -788,7 +789,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
/* else ok - we are setting up session */
}
if (ses->status == CifsExiting) {
if (ses->ses_status == SES_EXITING) {
if (shdr->Command != SMB2_LOGOFF) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN;

View File

@ -1350,7 +1350,7 @@ void smbd_destroy(struct TCP_Server_Info *server)
wait_event(info->wait_send_pending,
atomic_read(&info->send_pending) == 0);
/* It's not posssible for upper layer to get to reassembly */
/* It's not possible for upper layer to get to reassembly */
log_rdma_event(INFO, "drain the reassembly queue\n");
do {
spin_lock_irqsave(&info->reassembly_queue_lock, flags);

View File

@ -158,6 +158,7 @@ DEFINE_SMB3_FD_EVENT(flush_enter);
DEFINE_SMB3_FD_EVENT(flush_done);
DEFINE_SMB3_FD_EVENT(close_enter);
DEFINE_SMB3_FD_EVENT(close_done);
DEFINE_SMB3_FD_EVENT(oplock_not_found);
DECLARE_EVENT_CLASS(smb3_fd_err_class,
TP_PROTO(unsigned int xid,
@ -814,6 +815,7 @@ DEFINE_EVENT(smb3_lease_done_class, smb3_##name, \
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high))
DEFINE_SMB3_LEASE_DONE_EVENT(lease_done);
DEFINE_SMB3_LEASE_DONE_EVENT(lease_not_found);
DECLARE_EVENT_CLASS(smb3_lease_err_class,
TP_PROTO(__u32 lease_state,

View File

@ -726,7 +726,7 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
struct mid_q_entry **ppmidQ)
{
spin_lock(&cifs_tcp_ses_lock);
if (ses->status == CifsNew) {
if (ses->ses_status == SES_NEW) {
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) {
spin_unlock(&cifs_tcp_ses_lock);
@ -735,7 +735,7 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
/* else ok - we are setting up session */
}
if (ses->status == CifsExiting) {
if (ses->ses_status == SES_EXITING) {
/* check if SMB session is bad because we are setting it up */
if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
spin_unlock(&cifs_tcp_ses_lock);
@ -1187,7 +1187,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
* Compounding is never used during session establish.
*/
spin_lock(&cifs_tcp_ses_lock);
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
spin_unlock(&cifs_tcp_ses_lock);
mutex_lock(&server->srv_mutex);
@ -1260,7 +1260,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
* Compounding is never used during session establish.
*/
spin_lock(&cifs_tcp_ses_lock);
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
struct kvec iov = {
.iov_base = resp_iov[0].iov_base,
.iov_len = resp_iov[0].iov_len

View File

@ -1244,6 +1244,106 @@ struct file_zero_data_information {
__le64 BeyondFinalZero;
} __packed;
/* See MS-FSCC 2.3.7 */
struct duplicate_extents_to_file {
__u64 PersistentFileHandle; /* source file handle, opaque endianness */
__u64 VolatileFileHandle;
__le64 SourceFileOffset;
__le64 TargetFileOffset;
__le64 ByteCount; /* Bytes to be copied */
} __packed;
/* See MS-FSCC 2.3.8 */
#define DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC 0x00000001
struct duplicate_extents_to_file_ex {
__u64 PersistentFileHandle; /* source file handle, opaque endianness */
__u64 VolatileFileHandle;
__le64 SourceFileOffset;
__le64 TargetFileOffset;
__le64 ByteCount; /* Bytes to be copied */
__le32 Flags;
__le32 Reserved;
} __packed;
/* See MS-FSCC 2.3.20 */
struct fsctl_get_integrity_information_rsp {
__le16 ChecksumAlgorithm;
__le16 Reserved;
__le32 Flags;
__le32 ChecksumChunkSizeInBytes;
__le32 ClusterSizeInBytes;
} __packed;
/* See MS-FSCC 2.3.55 */
struct fsctl_query_file_regions_req {
__le64 FileOffset;
__le64 Length;
__le32 DesiredUsage;
__le32 Reserved;
} __packed;
/* DesiredUsage flags see MS-FSCC 2.3.56.1 */
#define FILE_USAGE_INVALID_RANGE 0x00000000
#define FILE_USAGE_VALID_CACHED_DATA 0x00000001
#define FILE_USAGE_NONCACHED_DATA 0x00000002
struct file_region_info {
__le64 FileOffset;
__le64 Length;
__le32 DesiredUsage;
__le32 Reserved;
} __packed;
/* See MS-FSCC 2.3.56 */
struct fsctl_query_file_region_rsp {
__le32 Flags;
__le32 TotalRegionEntryCount;
__le32 RegionEntryCount;
__u32 Reserved;
struct file_region_info Regions[];
} __packed;
/* See MS-FSCC 2.3.58 */
struct fsctl_query_on_disk_vol_info_rsp {
__le64 DirectoryCount;
__le64 FileCount;
__le16 FsFormatMajVersion;
__le16 FsFormatMinVersion;
__u8 FsFormatName[24];
__le64 FormatTime;
__le64 LastUpdateTime;
__u8 CopyrightInfo[68];
__u8 AbstractInfo[68];
__u8 FormatImplInfo[68];
__u8 LastModifyImplInfo[68];
} __packed;
/* See MS-FSCC 2.3.73 */
struct fsctl_set_integrity_information_req {
__le16 ChecksumAlgorithm;
__le16 Reserved;
__le32 Flags;
} __packed;
/* See MS-FSCC 2.3.75 */
struct fsctl_set_integrity_info_ex_req {
__u8 EnableIntegrity;
__u8 KeepState;
__u16 Reserved;
__le32 Flags;
__u8 Version;
__u8 Reserved2[7];
} __packed;
/* Integrity ChecksumAlgorithm choices for above */
#define CHECKSUM_TYPE_NONE 0x0000
#define CHECKSUM_TYPE_CRC64 0x0002
#define CHECKSUM_TYPE_UNCHANGED 0xFFFF /* set only */
/* Integrity flags for above */
#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001
/* Reparse structures - see MS-FSCC 2.1.2 */
/* struct fsctl_reparse_info_req is empty, only response structs (see below) */
@ -1304,13 +1404,6 @@ struct validate_negotiate_info_rsp {
__le16 Dialect; /* Dialect in use for the connection */
} __packed;
struct duplicate_extents_to_file {
__u64 PersistentFileHandle; /* source file handle, opaque endianness */
__u64 VolatileFileHandle;
__le64 SourceFileOffset;
__le64 TargetFileOffset;
__le64 ByteCount; /* Bytes to be copied */
} __packed;
/* Possible InfoType values */
#define SMB2_O_INFO_FILE 0x01
@ -1419,6 +1512,7 @@ struct smb2_query_info_rsp {
* PDU query infolevel structure definitions
*/
/* See MS-FSCC 2.3.52 */
struct file_allocated_range_buffer {
__le64 file_offset;
__le64 length;

View File

@ -88,21 +88,27 @@
#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 /* BB add struct */
#define FSCTL_READ_FILE_USN_DATA 0x000900EB /* BB add struct */
#define FSCTL_WRITE_USN_CLOSE_RECORD 0x000900EF /* BB add struct */
#define FSCTL_MARK_HANDLE 0x000900FC /* BB add struct */
#define FSCTL_SIS_COPYFILE 0x00090100 /* BB add struct */
#define FSCTL_RECALL_FILE 0x00090117 /* BB add struct */
#define FSCTL_QUERY_SPARING_INFO 0x00090138 /* BB add struct */
#define FSCTL_QUERY_ON_DISK_VOLUME_INFO 0x0009013C
#define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */
#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
#define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C
#define FSCTL_QUERY_FILE_REGIONS 0x00090284
#define FSCTL_GET_REFS_VOLUME_DATA 0x000902D8 /* See MS-FSCC 2.3.24 */
#define FSCTL_SET_INTEGRITY_INFORMATION_EXT 0x00090380
#define FSCTL_GET_RETRIEVAL_POINTERS_AND_REFCOUNT 0x000903d3
#define FSCTL_GET_RETRIEVAL_POINTER_COUNT 0x0009042b
#define FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT 0x00090440
#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF
#define FSCTL_OFFLOAD_READ 0x00094264 /* BB add struct */
#define FSCTL_OFFLOAD_WRITE 0x00098268 /* BB add struct */
#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */
#define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */
#define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344
#define FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX 0x000983E8
#define FSCTL_SIS_LINK_FILES 0x0009C104
#define FSCTL_SET_INTEGRITY_INFORMATION 0x0009C280
#define FSCTL_PIPE_PEEK 0x0011400C /* BB add struct */