mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
16 smb3 client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmjf7TUACgkQiiy9cAdy T1EeoQv/cCbhCv5S+wM9mtqtJt3ea+0E4+fXc012198jgphgd39s5cV07flVj4vA P5gC0ZGQmTsCOhcmYzxOefUpyq5N+ckIY8PoQKEXyHf3e/0GqczkdDokkhB8eOkh aC/arAcQvYXzcR+RwLdkRa0W/kwoXJ6iQ4+44KS7U6AUzWOR3H21UAJ2tg96xNLk Qp4dKOG3i1RcBMMX2iuFKbF693XQPhoefs+/kPzWe2R99IIfJrFT7rLPhuwV+iJ7 TIHgXk+UEUiDizLsSi9SPs59X0oOrQ2BlVI6mR0sUso94yQanItla9TTVTVTy2Tz tB7FUbF5x7a0Yaj3pVai5MXLRaKDEP38KWoM5mUsDyxDLblE5cHLtfxZzPwK8VO0 oTVRDQu9DigOmfyiwJ9tu3O5/ZnAr0A5pJEYHHfue84xuBRb1mUPyzX+ML2yym7u 8K+CUOKXS3M8x4Ep+88MukSX3PNEhJ1ohleyQghJHQVqrcA4tp289X+GJRuG9Q1b NiII7Tk0 =4Nt1 -----END PGP SIGNATURE----- Merge tag '6.18-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client updates from Steve French: - Fix oops in crypt message - Remove duplicate arc4 code - Fix potential io_uring reconnect - Two important directory leases fixes and three perf improvements - Three minor cleanups - Four debug improvements (e.g. for showing more information on leases, and one for adding more helpful information on reconnect) * tag '6.18-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: client: force multichannel=off when max_channels=1 smb client: fix bug with newly created file in cached dir smb: client: short-circuit negative lookups when parent dir is fully cached smb: client: short-circuit in open_cached_dir_by_dentry() if !dentry smb: client: remove pointless cfid->has_lease check smb: client: transport: minor indentation style fix smb: client: transport: avoid reconnects triggered by pending task work smb: client: remove unused fid_lock smb: client: update cfid->last_access_time in open_cached_dir_by_dentry() smb: client: ensure open_cached_dir_by_dentry() only returns valid cfid smb: client: account smb directory cache usage and per-tcon totals smb: client: add drop_dir_cache module parameter to invalidate cached dirents smb: client: show lease state as R/H/W (or NONE) in open_files smb: client: fix crypto buffers in non-linear memory smb: Use arc4 library instead of duplicate arc4 code smb: client: add tcon information to smb2_reconnect() debug messages
This commit is contained in:
commit
63e62baaa7
|
|
@ -15,6 +15,7 @@ config CIFS
|
|||
select CRYPTO_GCM
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_LIB_ARC4
|
||||
select KEYS
|
||||
select DNS_RESOLVER
|
||||
select ASN1
|
||||
|
|
|
|||
|
|
@ -36,9 +36,8 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
|
|||
* fully cached or it may be in the process of
|
||||
* being deleted due to a lease break.
|
||||
*/
|
||||
if (!cfid->time || !cfid->has_lease) {
|
||||
if (!is_valid_cached_dir(cfid))
|
||||
return NULL;
|
||||
}
|
||||
kref_get(&cfid->refcount);
|
||||
return cfid;
|
||||
}
|
||||
|
|
@ -194,7 +193,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
|||
* Otherwise, it is either a new entry or laundromat worker removed it
|
||||
* from @cfids->entries. Caller will put last reference if the latter.
|
||||
*/
|
||||
if (cfid->has_lease && cfid->time) {
|
||||
if (is_valid_cached_dir(cfid)) {
|
||||
cfid->last_access_time = jiffies;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
*ret_cfid = cfid;
|
||||
|
|
@ -233,7 +232,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
|||
list_for_each_entry(parent_cfid, &cfids->entries, entry) {
|
||||
if (parent_cfid->dentry == dentry->d_parent) {
|
||||
cifs_dbg(FYI, "found a parent cached file handle\n");
|
||||
if (parent_cfid->has_lease && parent_cfid->time) {
|
||||
if (is_valid_cached_dir(parent_cfid)) {
|
||||
lease_flags
|
||||
|= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
|
||||
memcpy(pfid->parent_lease_key,
|
||||
|
|
@ -417,12 +416,18 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
|||
if (cfids == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!dentry)
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry(cfid, &cfids->entries, entry) {
|
||||
if (dentry && cfid->dentry == dentry) {
|
||||
if (cfid->dentry == dentry) {
|
||||
if (!is_valid_cached_dir(cfid))
|
||||
break;
|
||||
cifs_dbg(FYI, "found a cached file handle by dentry\n");
|
||||
kref_get(&cfid->refcount);
|
||||
*ret_cfid = cfid;
|
||||
cfid->last_access_time = jiffies;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -522,10 +527,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
|
|||
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||
goto done;
|
||||
}
|
||||
spin_lock(&cfid->fid_lock);
|
||||
|
||||
tmp_list->dentry = cfid->dentry;
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
list_add_tail(&tmp_list->entry, &entry);
|
||||
}
|
||||
|
|
@ -608,14 +612,9 @@ static void cached_dir_put_work(struct work_struct *work)
|
|||
{
|
||||
struct cached_fid *cfid = container_of(work, struct cached_fid,
|
||||
put_work);
|
||||
struct dentry *dentry;
|
||||
|
||||
spin_lock(&cfid->fid_lock);
|
||||
dentry = cfid->dentry;
|
||||
dput(cfid->dentry);
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
dput(dentry);
|
||||
queue_work(serverclose_wq, &cfid->close_work);
|
||||
}
|
||||
|
||||
|
|
@ -673,7 +672,6 @@ static struct cached_fid *init_cached_dir(const char *path)
|
|||
INIT_LIST_HEAD(&cfid->entry);
|
||||
INIT_LIST_HEAD(&cfid->dirents.entries);
|
||||
mutex_init(&cfid->dirents.de_mutex);
|
||||
spin_lock_init(&cfid->fid_lock);
|
||||
kref_init(&cfid->refcount);
|
||||
return cfid;
|
||||
}
|
||||
|
|
@ -697,6 +695,21 @@ static void free_cached_dir(struct cached_fid *cfid)
|
|||
kfree(dirent);
|
||||
}
|
||||
|
||||
/* adjust tcon-level counters and reset per-dir accounting */
|
||||
if (cfid->cfids) {
|
||||
if (cfid->dirents.entries_count)
|
||||
atomic_long_sub((long)cfid->dirents.entries_count,
|
||||
&cfid->cfids->total_dirents_entries);
|
||||
if (cfid->dirents.bytes_used) {
|
||||
atomic64_sub((long long)cfid->dirents.bytes_used,
|
||||
&cfid->cfids->total_dirents_bytes);
|
||||
atomic64_sub((long long)cfid->dirents.bytes_used,
|
||||
&cifs_dircache_bytes_used);
|
||||
}
|
||||
}
|
||||
cfid->dirents.entries_count = 0;
|
||||
cfid->dirents.bytes_used = 0;
|
||||
|
||||
kfree(cfid->path);
|
||||
cfid->path = NULL;
|
||||
kfree(cfid);
|
||||
|
|
@ -725,7 +738,6 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
|||
{
|
||||
struct cached_fids *cfids;
|
||||
struct cached_fid *cfid, *q;
|
||||
struct dentry *dentry;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
cfids = container_of(work, struct cached_fids, laundromat_work.work);
|
||||
|
|
@ -752,12 +764,9 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
|||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
|
||||
spin_lock(&cfid->fid_lock);
|
||||
dentry = cfid->dentry;
|
||||
dput(cfid->dentry);
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
dput(dentry);
|
||||
if (cfid->is_open) {
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
++cfid->tcon->tc_count;
|
||||
|
|
@ -792,6 +801,9 @@ struct cached_fids *init_cached_dirs(void)
|
|||
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
||||
dir_cache_timeout * HZ);
|
||||
|
||||
atomic_long_set(&cfids->total_dirents_entries, 0);
|
||||
atomic64_set(&cfids->total_dirents_bytes, 0);
|
||||
|
||||
return cfids;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ struct cached_dirents {
|
|||
struct mutex de_mutex;
|
||||
loff_t pos; /* Expected ctx->pos */
|
||||
struct list_head entries;
|
||||
/* accounting for cached entries in this directory */
|
||||
unsigned long entries_count;
|
||||
unsigned long bytes_used;
|
||||
};
|
||||
|
||||
struct cached_fid {
|
||||
|
|
@ -41,7 +44,6 @@ struct cached_fid {
|
|||
unsigned long last_access_time; /* jiffies of when last accessed */
|
||||
struct kref refcount;
|
||||
struct cifs_fid fid;
|
||||
spinlock_t fid_lock;
|
||||
struct cifs_tcon *tcon;
|
||||
struct dentry *dentry;
|
||||
struct work_struct put_work;
|
||||
|
|
@ -62,8 +64,20 @@ struct cached_fids {
|
|||
struct list_head dying;
|
||||
struct work_struct invalidation_work;
|
||||
struct delayed_work laundromat_work;
|
||||
/* aggregate accounting for all cached dirents under this tcon */
|
||||
atomic_long_t total_dirents_entries;
|
||||
atomic64_t total_dirents_bytes;
|
||||
};
|
||||
|
||||
/* Module-wide directory cache accounting (defined in cifsfs.c) */
|
||||
extern atomic64_t cifs_dircache_bytes_used; /* bytes across all mounts */
|
||||
|
||||
static inline bool
|
||||
is_valid_cached_dir(struct cached_fid *cfid)
|
||||
{
|
||||
return cfid->time && cfid->has_lease;
|
||||
}
|
||||
|
||||
extern struct cached_fids *init_cached_dirs(void);
|
||||
extern void free_cached_dirs(struct cached_fids *cfids);
|
||||
extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
|
|
|||
|
|
@ -240,14 +240,18 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
|
|||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct inode *inode;
|
||||
struct cifsInodeInfo *cinode;
|
||||
char lease[4];
|
||||
int n;
|
||||
|
||||
seq_puts(m, "# Version:1\n");
|
||||
seq_puts(m, "# Format:\n");
|
||||
seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
seq_printf(m, " <filename> <mid>\n");
|
||||
seq_puts(m, " <filename> <lease> <mid>\n");
|
||||
#else
|
||||
seq_printf(m, " <filename>\n");
|
||||
seq_puts(m, " <filename> <lease>\n");
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
||||
|
|
@ -267,11 +271,30 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
|
|||
cfile->pid,
|
||||
from_kuid(&init_user_ns, cfile->uid),
|
||||
cfile->dentry);
|
||||
|
||||
/* Append lease/oplock caching state as RHW letters */
|
||||
inode = d_inode(cfile->dentry);
|
||||
n = 0;
|
||||
if (inode) {
|
||||
cinode = CIFS_I(inode);
|
||||
if (CIFS_CACHE_READ(cinode))
|
||||
lease[n++] = 'R';
|
||||
if (CIFS_CACHE_HANDLE(cinode))
|
||||
lease[n++] = 'H';
|
||||
if (CIFS_CACHE_WRITE(cinode))
|
||||
lease[n++] = 'W';
|
||||
}
|
||||
lease[n] = '\0';
|
||||
seq_puts(m, " ");
|
||||
if (n)
|
||||
seq_printf(m, "%s", lease);
|
||||
else
|
||||
seq_puts(m, "NONE");
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
seq_printf(m, " %llu\n", cfile->fid.mid);
|
||||
#else
|
||||
seq_printf(m, " %llu", cfile->fid.mid);
|
||||
#endif /* CONFIG_CIFS_DEBUG2 */
|
||||
seq_printf(m, "\n");
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
}
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
}
|
||||
|
|
@ -308,7 +331,10 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
|
|||
if (!cfids)
|
||||
continue;
|
||||
spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
|
||||
seq_printf(m, "Num entries: %d\n", cfids->num_entries);
|
||||
seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
|
||||
cfids->num_entries,
|
||||
(unsigned long)atomic_long_read(&cfids->total_dirents_entries),
|
||||
(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
|
||||
list_for_each_entry(cfid, &cfids->entries, entry) {
|
||||
seq_printf(m, "0x%x 0x%llx 0x%llx %s",
|
||||
tcon->tid,
|
||||
|
|
@ -319,6 +345,9 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, "\tvalid file info");
|
||||
if (cfid->dirents.is_valid)
|
||||
seq_printf(m, ", valid dirents");
|
||||
if (!list_empty(&cfid->dirents.entries))
|
||||
seq_printf(m, ", dirents: %lu entries, %lu bytes",
|
||||
cfid->dirents.entries_count, cfid->dirents.bytes_used);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
#include <linux/highmem.h>
|
||||
#include <linux/fips.h>
|
||||
#include <linux/iov_iter.h>
|
||||
#include "../common/arc4.h"
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/arc4.h>
|
||||
|
||||
static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
|
||||
void *priv, void *priv2)
|
||||
|
|
@ -725,9 +725,9 @@ calc_seckey(struct cifs_ses *ses)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
|
||||
cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
|
||||
CIFS_CPHTXT_SIZE);
|
||||
arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
|
||||
arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
|
||||
CIFS_CPHTXT_SIZE);
|
||||
|
||||
/* make secondary_key/nonce as session key */
|
||||
memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,46 @@ unsigned int dir_cache_timeout = 30;
|
|||
module_param(dir_cache_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(dir_cache_timeout, "Number of seconds to cache directory contents for which we have a lease. Default: 30 "
|
||||
"Range: 1 to 65000 seconds, 0 to disable caching dir contents");
|
||||
/* Module-wide total cached dirents (in bytes) across all tcons */
|
||||
atomic64_t cifs_dircache_bytes_used = ATOMIC64_INIT(0);
|
||||
|
||||
/*
|
||||
* Write-only module parameter to drop all cached directory entries across
|
||||
* all CIFS mounts. Echo a non-zero value to trigger.
|
||||
*/
|
||||
static void cifs_drop_all_dir_caches(void)
|
||||
{
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
||||
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
||||
if (cifs_ses_exiting(ses))
|
||||
continue;
|
||||
list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
|
||||
invalidate_all_cached_dirs(tcon);
|
||||
}
|
||||
}
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
|
||||
static int cifs_param_set_drop_dir_cache(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
bool bv;
|
||||
int rc = kstrtobool(val, &bv);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (bv)
|
||||
cifs_drop_all_dir_caches();
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_param_call(drop_dir_cache, cifs_param_set_drop_dir_cache, NULL, NULL, 0200);
|
||||
MODULE_PARM_DESC(drop_dir_cache, "Write 1 to drop all cached directory entries across all CIFS mounts");
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
unsigned int slow_rsp_threshold = 1;
|
||||
module_param(slow_rsp_threshold, uint, 0644);
|
||||
|
|
|
|||
|
|
@ -322,13 +322,14 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
|
|||
list_for_each_entry(parent_cfid, &tcon->cfids->entries, entry) {
|
||||
if (parent_cfid->dentry == direntry->d_parent) {
|
||||
cifs_dbg(FYI, "found a parent cached file handle\n");
|
||||
if (parent_cfid->has_lease && parent_cfid->time) {
|
||||
if (is_valid_cached_dir(parent_cfid)) {
|
||||
lease_flags
|
||||
|= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
|
||||
memcpy(fid->parent_lease_key,
|
||||
parent_cfid->fid.lease_key,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
parent_cfid->dirents.is_valid = false;
|
||||
parent_cfid->dirents.is_failed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -677,6 +678,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
const char *full_path;
|
||||
void *page;
|
||||
int retry_count = 0;
|
||||
struct cached_fid *cfid = NULL;
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
|
|
@ -716,6 +718,28 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
cifs_dbg(FYI, "non-NULL inode in lookup\n");
|
||||
} else {
|
||||
cifs_dbg(FYI, "NULL inode in lookup\n");
|
||||
|
||||
/*
|
||||
* We can only rely on negative dentries having the same
|
||||
* spelling as the cached dirent if case insensitivity is
|
||||
* forced on mount.
|
||||
*
|
||||
* XXX: if servers correctly announce Case Sensitivity Search
|
||||
* on GetInfo of FileFSAttributeInformation, then we can take
|
||||
* correct action even if case insensitive is not forced on
|
||||
* mount.
|
||||
*/
|
||||
if (pTcon->nocase && !open_cached_dir_by_dentry(pTcon, direntry->d_parent, &cfid)) {
|
||||
/*
|
||||
* dentry is negative and parent is fully cached:
|
||||
* we can assume file does not exist
|
||||
*/
|
||||
if (cfid->dirents.is_valid) {
|
||||
close_cached_dir(cfid);
|
||||
goto out;
|
||||
}
|
||||
close_cached_dir(cfid);
|
||||
}
|
||||
}
|
||||
cifs_dbg(FYI, "Full path: %s inode = 0x%p\n",
|
||||
full_path, d_inode(direntry));
|
||||
|
|
@ -749,6 +773,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
}
|
||||
newInode = ERR_PTR(rc);
|
||||
}
|
||||
|
||||
out:
|
||||
free_dentry_path(page);
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid(xid);
|
||||
|
|
@ -759,7 +785,8 @@ static int
|
|||
cifs_d_revalidate(struct inode *dir, const struct qstr *name,
|
||||
struct dentry *direntry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = NULL;
|
||||
struct cached_fid *cfid;
|
||||
int rc;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
|
|
@ -806,6 +833,21 @@ cifs_d_revalidate(struct inode *dir, const struct qstr *name,
|
|||
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dir->i_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
|
||||
if (!open_cached_dir_by_dentry(tcon, direntry->d_parent, &cfid)) {
|
||||
/*
|
||||
* dentry is negative and parent is fully cached:
|
||||
* we can assume file does not exist
|
||||
*/
|
||||
if (cfid->dirents.is_valid) {
|
||||
close_cached_dir(cfid);
|
||||
return 1;
|
||||
}
|
||||
close_cached_dir(cfid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1818,6 +1818,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
|||
goto cifs_parse_mount_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multichannel is not meaningful if max_channels is 1.
|
||||
* Force multichannel to false to ensure consistent configuration.
|
||||
*/
|
||||
if (ctx->multichannel && ctx->max_channels == 1)
|
||||
ctx->multichannel = false;
|
||||
|
||||
return 0;
|
||||
|
||||
cifs_parse_mount_err:
|
||||
|
|
|
|||
|
|
@ -2704,7 +2704,7 @@ cifs_dentry_needs_reval(struct dentry *dentry)
|
|||
return true;
|
||||
|
||||
if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) {
|
||||
if (cfid->time && cifs_i->time > cfid->time) {
|
||||
if (cifs_i->time > cfid->time) {
|
||||
close_cached_dir(cfid);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -874,39 +874,42 @@ static void finished_cached_dirents_count(struct cached_dirents *cde,
|
|||
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 file *file)
|
||||
static bool add_cached_dirent(struct cached_dirents *cde,
|
||||
struct dir_context *ctx, const char *name,
|
||||
int namelen, struct cifs_fattr *fattr,
|
||||
struct file *file)
|
||||
{
|
||||
struct cached_dirent *de;
|
||||
|
||||
if (cde->file != file)
|
||||
return;
|
||||
return false;
|
||||
if (cde->is_valid || cde->is_failed)
|
||||
return;
|
||||
return false;
|
||||
if (ctx->pos != cde->pos) {
|
||||
cde->is_failed = 1;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
de = kzalloc(sizeof(*de), GFP_ATOMIC);
|
||||
if (de == NULL) {
|
||||
cde->is_failed = 1;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
de->namelen = namelen;
|
||||
de->name = kstrndup(name, namelen, GFP_ATOMIC);
|
||||
if (de->name == NULL) {
|
||||
kfree(de);
|
||||
cde->is_failed = 1;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
de->pos = ctx->pos;
|
||||
|
||||
memcpy(&de->fattr, fattr, sizeof(struct cifs_fattr));
|
||||
|
||||
list_add_tail(&de->entry, &cde->entries);
|
||||
/* update accounting */
|
||||
cde->entries_count++;
|
||||
cde->bytes_used += sizeof(*de) + (size_t)namelen + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cifs_dir_emit(struct dir_context *ctx,
|
||||
|
|
@ -915,7 +918,8 @@ static bool cifs_dir_emit(struct dir_context *ctx,
|
|||
struct cached_fid *cfid,
|
||||
struct file *file)
|
||||
{
|
||||
bool rc;
|
||||
size_t delta_bytes = 0;
|
||||
bool rc, added = false;
|
||||
ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
|
||||
|
||||
rc = dir_emit(ctx, name, namelen, ino, fattr->cf_dtype);
|
||||
|
|
@ -923,10 +927,20 @@ static bool cifs_dir_emit(struct dir_context *ctx,
|
|||
return rc;
|
||||
|
||||
if (cfid) {
|
||||
/* Cost of this entry */
|
||||
delta_bytes = sizeof(struct cached_dirent) + (size_t)namelen + 1;
|
||||
|
||||
mutex_lock(&cfid->dirents.de_mutex);
|
||||
add_cached_dirent(&cfid->dirents, ctx, name, namelen,
|
||||
fattr, file);
|
||||
added = add_cached_dirent(&cfid->dirents, ctx, name, namelen,
|
||||
fattr, file);
|
||||
mutex_unlock(&cfid->dirents.de_mutex);
|
||||
|
||||
if (added) {
|
||||
/* per-tcon then global for consistency with free path */
|
||||
atomic64_add((long long)delta_bytes, &cfid->cfids->total_dirents_bytes);
|
||||
atomic_long_inc(&cfid->cfids->total_dirents_entries);
|
||||
atomic64_add((long long)delta_bytes, &cifs_dircache_bytes_used);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -954,11 +954,8 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, true, &cfid);
|
||||
if (!rc) {
|
||||
if (cfid->has_lease) {
|
||||
close_cached_dir(cfid);
|
||||
return 0;
|
||||
}
|
||||
close_cached_dir(cfid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
|
|
@ -4219,7 +4216,7 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
|
|||
static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
|
||||
int num_rqst, const u8 *sig, u8 **iv,
|
||||
struct aead_request **req, struct sg_table *sgt,
|
||||
unsigned int *num_sgs, size_t *sensitive_size)
|
||||
unsigned int *num_sgs)
|
||||
{
|
||||
unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
|
||||
unsigned int iv_size = crypto_aead_ivsize(tfm);
|
||||
|
|
@ -4236,9 +4233,8 @@ static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst
|
|||
len += req_size;
|
||||
len = ALIGN(len, __alignof__(struct scatterlist));
|
||||
len += array_size(*num_sgs, sizeof(struct scatterlist));
|
||||
*sensitive_size = len;
|
||||
|
||||
p = kvzalloc(len, GFP_NOFS);
|
||||
p = kzalloc(len, GFP_NOFS);
|
||||
if (!p)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -4252,16 +4248,14 @@ static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst
|
|||
|
||||
static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *rqst,
|
||||
int num_rqst, const u8 *sig, u8 **iv,
|
||||
struct aead_request **req, struct scatterlist **sgl,
|
||||
size_t *sensitive_size)
|
||||
struct aead_request **req, struct scatterlist **sgl)
|
||||
{
|
||||
struct sg_table sgtable = {};
|
||||
unsigned int skip, num_sgs, i, j;
|
||||
ssize_t rc;
|
||||
void *p;
|
||||
|
||||
p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable,
|
||||
&num_sgs, sensitive_size);
|
||||
p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable, &num_sgs);
|
||||
if (IS_ERR(p))
|
||||
return ERR_CAST(p);
|
||||
|
||||
|
|
@ -4350,7 +4344,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||
DECLARE_CRYPTO_WAIT(wait);
|
||||
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
void *creq;
|
||||
size_t sensitive_size;
|
||||
|
||||
rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
|
||||
if (rc) {
|
||||
|
|
@ -4376,8 +4369,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||
return rc;
|
||||
}
|
||||
|
||||
creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg,
|
||||
&sensitive_size);
|
||||
creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg);
|
||||
if (IS_ERR(creq))
|
||||
return PTR_ERR(creq);
|
||||
|
||||
|
|
@ -4407,7 +4399,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||
if (!rc && enc)
|
||||
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
|
||||
|
||||
kvfree_sensitive(creq, sensitive_size);
|
||||
kfree_sensitive(creq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
*/
|
||||
if (smb2_command != SMB2_TREE_DISCONNECT) {
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
|
||||
smb2_command);
|
||||
cifs_tcon_dbg(FYI, "can not send cmd %d while umounting\n",
|
||||
smb2_command);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
|
@ -296,9 +296,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
return 0;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d",
|
||||
tcon->ses->chans_need_reconnect,
|
||||
tcon->need_reconnect);
|
||||
cifs_tcon_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d\n",
|
||||
tcon->ses->chans_need_reconnect,
|
||||
tcon->need_reconnect);
|
||||
|
||||
mutex_lock(&ses->session_mutex);
|
||||
/*
|
||||
|
|
@ -392,11 +392,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
|
||||
rc = cifs_tree_connect(0, tcon);
|
||||
|
||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
cifs_tcon_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
if (rc) {
|
||||
/* If sess reconnected but tcon didn't, something strange ... */
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
|
||||
cifs_tcon_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -442,8 +442,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
from_reconnect);
|
||||
goto skip_add_channels;
|
||||
} else if (rc)
|
||||
cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
|
||||
__func__, rc);
|
||||
cifs_tcon_dbg(FYI, "%s: failed to query server interfaces: %d\n",
|
||||
__func__, rc);
|
||||
|
||||
if (ses->chan_max > ses->chan_count &&
|
||||
ses->iface_count &&
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/mempool.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/task_io_accounting_ops.h>
|
||||
#include <linux/task_work.h>
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
|
|
@ -173,9 +174,16 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
|
|||
* send a packet. In most cases if we fail to send
|
||||
* after the retries we will kill the socket and
|
||||
* reconnect which may clear the network problem.
|
||||
*
|
||||
* Even if regular signals are masked, EINTR might be
|
||||
* propagated from sk_stream_wait_memory() to here when
|
||||
* TIF_NOTIFY_SIGNAL is used for task work. For example,
|
||||
* certain io_uring completions will use that. Treat
|
||||
* having EINTR with pending task work the same as EAGAIN
|
||||
* to avoid unnecessary reconnects.
|
||||
*/
|
||||
rc = sock_sendmsg(ssocket, smb_msg);
|
||||
if (rc == -EAGAIN) {
|
||||
if (rc == -EAGAIN || unlikely(rc == -EINTR && task_work_pending(current))) {
|
||||
retries++;
|
||||
if (retries >= 14 ||
|
||||
(!server->noblocksnd && (retries > 2))) {
|
||||
|
|
@ -323,8 +331,7 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
break;
|
||||
total_len += sent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
unmask:
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
|
|
|
|||
|
|
@ -3,5 +3,4 @@
|
|||
# Makefile for Linux filesystem routines that are shared by client and server.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SMBFS) += cifs_arc4.o
|
||||
obj-$(CONFIG_SMBFS) += cifs_md4.o
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Common values for ARC4 Cipher Algorithm
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_ARC4_H
|
||||
#define _CRYPTO_ARC4_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define ARC4_MIN_KEY_SIZE 1
|
||||
#define ARC4_MAX_KEY_SIZE 256
|
||||
#define ARC4_BLOCK_SIZE 1
|
||||
|
||||
struct arc4_ctx {
|
||||
u32 S[256];
|
||||
u32 x, y;
|
||||
};
|
||||
|
||||
int cifs_arc4_setkey(struct arc4_ctx *ctx, const u8 *in_key, unsigned int key_len);
|
||||
void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int len);
|
||||
|
||||
#endif /* _CRYPTO_ARC4_H */
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Cryptographic API
|
||||
*
|
||||
* ARC4 Cipher Algorithm
|
||||
*
|
||||
* Jon Oberheide <jon@oberheide.org>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "arc4.h"
|
||||
|
||||
MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
int cifs_arc4_setkey(struct arc4_ctx *ctx, const u8 *in_key, unsigned int key_len)
|
||||
{
|
||||
int i, j = 0, k = 0;
|
||||
|
||||
ctx->x = 1;
|
||||
ctx->y = 0;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
ctx->S[i] = i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
u32 a = ctx->S[i];
|
||||
|
||||
j = (j + in_key[k] + a) & 0xff;
|
||||
ctx->S[i] = ctx->S[j];
|
||||
ctx->S[j] = a;
|
||||
if (++k >= key_len)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cifs_arc4_setkey);
|
||||
|
||||
void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int len)
|
||||
{
|
||||
u32 *const S = ctx->S;
|
||||
u32 x, y, a, b;
|
||||
u32 ty, ta, tb;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
x = ctx->x;
|
||||
y = ctx->y;
|
||||
|
||||
a = S[x];
|
||||
y = (y + a) & 0xff;
|
||||
b = S[y];
|
||||
|
||||
do {
|
||||
S[y] = a;
|
||||
a = (a + b) & 0xff;
|
||||
S[x] = b;
|
||||
x = (x + 1) & 0xff;
|
||||
ta = S[x];
|
||||
ty = (y + ta) & 0xff;
|
||||
tb = S[ty];
|
||||
*out++ = *in++ ^ S[a];
|
||||
if (--len == 0)
|
||||
break;
|
||||
y = ty;
|
||||
a = ta;
|
||||
b = tb;
|
||||
} while (true);
|
||||
|
||||
ctx->x = x;
|
||||
ctx->y = y;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cifs_arc4_crypt);
|
||||
|
|
@ -10,6 +10,7 @@ config SMB_SERVER
|
|||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_LIB_ARC4
|
||||
select CRYPTO_LIB_DES
|
||||
select CRYPTO_LIB_SHA256
|
||||
select CRYPTO_SHA256
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "glob.h"
|
||||
|
||||
#include <linux/fips.h>
|
||||
#include <crypto/arc4.h>
|
||||
#include <crypto/des.h>
|
||||
|
||||
#include "server.h"
|
||||
|
|
@ -29,7 +30,6 @@
|
|||
#include "mgmt/user_config.h"
|
||||
#include "crypto_ctx.h"
|
||||
#include "transport_ipc.h"
|
||||
#include "../common/arc4.h"
|
||||
|
||||
/*
|
||||
* Fixed format data defining GSS header and fixed string
|
||||
|
|
@ -365,10 +365,9 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
|||
if (!ctx_arc4)
|
||||
return -ENOMEM;
|
||||
|
||||
cifs_arc4_setkey(ctx_arc4, sess->sess_key,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
cifs_arc4_crypt(ctx_arc4, sess->sess_key,
|
||||
(char *)authblob + sess_key_off, sess_key_len);
|
||||
arc4_setkey(ctx_arc4, sess->sess_key, SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
arc4_crypt(ctx_arc4, sess->sess_key,
|
||||
(char *)authblob + sess_key_off, sess_key_len);
|
||||
kfree_sensitive(ctx_arc4);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user