Skip to content

Commit 63e62ba

Browse files
committed
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
2 parents b3fee71 + 37e263e commit 63e62ba

File tree

18 files changed

+236
-177
lines changed

18 files changed

+236
-177
lines changed

fs/smb/client/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ config CIFS
1515
select CRYPTO_GCM
1616
select CRYPTO_ECB
1717
select CRYPTO_AES
18+
select CRYPTO_LIB_ARC4
1819
select KEYS
1920
select DNS_RESOLVER
2021
select ASN1

fs/smb/client/cached_dir.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
3636
* fully cached or it may be in the process of
3737
* being deleted due to a lease break.
3838
*/
39-
if (!cfid->time || !cfid->has_lease) {
39+
if (!is_valid_cached_dir(cfid))
4040
return NULL;
41-
}
4241
kref_get(&cfid->refcount);
4342
return cfid;
4443
}
@@ -194,7 +193,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
194193
* Otherwise, it is either a new entry or laundromat worker removed it
195194
* from @cfids->entries. Caller will put last reference if the latter.
196195
*/
197-
if (cfid->has_lease && cfid->time) {
196+
if (is_valid_cached_dir(cfid)) {
198197
cfid->last_access_time = jiffies;
199198
spin_unlock(&cfids->cfid_list_lock);
200199
*ret_cfid = cfid;
@@ -233,7 +232,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
233232
list_for_each_entry(parent_cfid, &cfids->entries, entry) {
234233
if (parent_cfid->dentry == dentry->d_parent) {
235234
cifs_dbg(FYI, "found a parent cached file handle\n");
236-
if (parent_cfid->has_lease && parent_cfid->time) {
235+
if (is_valid_cached_dir(parent_cfid)) {
237236
lease_flags
238237
|= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
239238
memcpy(pfid->parent_lease_key,
@@ -417,12 +416,18 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
417416
if (cfids == NULL)
418417
return -EOPNOTSUPP;
419418

419+
if (!dentry)
420+
return -ENOENT;
421+
420422
spin_lock(&cfids->cfid_list_lock);
421423
list_for_each_entry(cfid, &cfids->entries, entry) {
422-
if (dentry && cfid->dentry == dentry) {
424+
if (cfid->dentry == dentry) {
425+
if (!is_valid_cached_dir(cfid))
426+
break;
423427
cifs_dbg(FYI, "found a cached file handle by dentry\n");
424428
kref_get(&cfid->refcount);
425429
*ret_cfid = cfid;
430+
cfid->last_access_time = jiffies;
426431
spin_unlock(&cfids->cfid_list_lock);
427432
return 0;
428433
}
@@ -522,10 +527,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
522527
spin_unlock(&cifs_sb->tlink_tree_lock);
523528
goto done;
524529
}
525-
spin_lock(&cfid->fid_lock);
530+
526531
tmp_list->dentry = cfid->dentry;
527532
cfid->dentry = NULL;
528-
spin_unlock(&cfid->fid_lock);
529533

530534
list_add_tail(&tmp_list->entry, &entry);
531535
}
@@ -608,14 +612,9 @@ static void cached_dir_put_work(struct work_struct *work)
608612
{
609613
struct cached_fid *cfid = container_of(work, struct cached_fid,
610614
put_work);
611-
struct dentry *dentry;
612-
613-
spin_lock(&cfid->fid_lock);
614-
dentry = cfid->dentry;
615+
dput(cfid->dentry);
615616
cfid->dentry = NULL;
616-
spin_unlock(&cfid->fid_lock);
617617

618-
dput(dentry);
619618
queue_work(serverclose_wq, &cfid->close_work);
620619
}
621620

@@ -673,7 +672,6 @@ static struct cached_fid *init_cached_dir(const char *path)
673672
INIT_LIST_HEAD(&cfid->entry);
674673
INIT_LIST_HEAD(&cfid->dirents.entries);
675674
mutex_init(&cfid->dirents.de_mutex);
676-
spin_lock_init(&cfid->fid_lock);
677675
kref_init(&cfid->refcount);
678676
return cfid;
679677
}
@@ -697,6 +695,21 @@ static void free_cached_dir(struct cached_fid *cfid)
697695
kfree(dirent);
698696
}
699697

698+
/* adjust tcon-level counters and reset per-dir accounting */
699+
if (cfid->cfids) {
700+
if (cfid->dirents.entries_count)
701+
atomic_long_sub((long)cfid->dirents.entries_count,
702+
&cfid->cfids->total_dirents_entries);
703+
if (cfid->dirents.bytes_used) {
704+
atomic64_sub((long long)cfid->dirents.bytes_used,
705+
&cfid->cfids->total_dirents_bytes);
706+
atomic64_sub((long long)cfid->dirents.bytes_used,
707+
&cifs_dircache_bytes_used);
708+
}
709+
}
710+
cfid->dirents.entries_count = 0;
711+
cfid->dirents.bytes_used = 0;
712+
700713
kfree(cfid->path);
701714
cfid->path = NULL;
702715
kfree(cfid);
@@ -725,7 +738,6 @@ static void cfids_laundromat_worker(struct work_struct *work)
725738
{
726739
struct cached_fids *cfids;
727740
struct cached_fid *cfid, *q;
728-
struct dentry *dentry;
729741
LIST_HEAD(entry);
730742

731743
cfids = container_of(work, struct cached_fids, laundromat_work.work);
@@ -752,12 +764,9 @@ static void cfids_laundromat_worker(struct work_struct *work)
752764
list_for_each_entry_safe(cfid, q, &entry, entry) {
753765
list_del(&cfid->entry);
754766

755-
spin_lock(&cfid->fid_lock);
756-
dentry = cfid->dentry;
767+
dput(cfid->dentry);
757768
cfid->dentry = NULL;
758-
spin_unlock(&cfid->fid_lock);
759769

760-
dput(dentry);
761770
if (cfid->is_open) {
762771
spin_lock(&cifs_tcp_ses_lock);
763772
++cfid->tcon->tc_count;
@@ -792,6 +801,9 @@ struct cached_fids *init_cached_dirs(void)
792801
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
793802
dir_cache_timeout * HZ);
794803

804+
atomic_long_set(&cfids->total_dirents_entries, 0);
805+
atomic64_set(&cfids->total_dirents_bytes, 0);
806+
795807
return cfids;
796808
}
797809

fs/smb/client/cached_dir.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct cached_dirents {
2727
struct mutex de_mutex;
2828
loff_t pos; /* Expected ctx->pos */
2929
struct list_head entries;
30+
/* accounting for cached entries in this directory */
31+
unsigned long entries_count;
32+
unsigned long bytes_used;
3033
};
3134

3235
struct cached_fid {
@@ -41,7 +44,6 @@ struct cached_fid {
4144
unsigned long last_access_time; /* jiffies of when last accessed */
4245
struct kref refcount;
4346
struct cifs_fid fid;
44-
spinlock_t fid_lock;
4547
struct cifs_tcon *tcon;
4648
struct dentry *dentry;
4749
struct work_struct put_work;
@@ -62,8 +64,20 @@ struct cached_fids {
6264
struct list_head dying;
6365
struct work_struct invalidation_work;
6466
struct delayed_work laundromat_work;
67+
/* aggregate accounting for all cached dirents under this tcon */
68+
atomic_long_t total_dirents_entries;
69+
atomic64_t total_dirents_bytes;
6570
};
6671

72+
/* Module-wide directory cache accounting (defined in cifsfs.c) */
73+
extern atomic64_t cifs_dircache_bytes_used; /* bytes across all mounts */
74+
75+
static inline bool
76+
is_valid_cached_dir(struct cached_fid *cfid)
77+
{
78+
return cfid->time && cfid->has_lease;
79+
}
80+
6781
extern struct cached_fids *init_cached_dirs(void);
6882
extern void free_cached_dirs(struct cached_fids *cfids);
6983
extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,

fs/smb/client/cifs_debug.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,14 +240,18 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
240240
struct cifs_ses *ses;
241241
struct cifs_tcon *tcon;
242242
struct cifsFileInfo *cfile;
243+
struct inode *inode;
244+
struct cifsInodeInfo *cinode;
245+
char lease[4];
246+
int n;
243247

244248
seq_puts(m, "# Version:1\n");
245249
seq_puts(m, "# Format:\n");
246250
seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
247251
#ifdef CONFIG_CIFS_DEBUG2
248-
seq_printf(m, " <filename> <mid>\n");
252+
seq_puts(m, " <filename> <lease> <mid>\n");
249253
#else
250-
seq_printf(m, " <filename>\n");
254+
seq_puts(m, " <filename> <lease>\n");
251255
#endif /* CIFS_DEBUG2 */
252256
spin_lock(&cifs_tcp_ses_lock);
253257
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)
267271
cfile->pid,
268272
from_kuid(&init_user_ns, cfile->uid),
269273
cfile->dentry);
274+
275+
/* Append lease/oplock caching state as RHW letters */
276+
inode = d_inode(cfile->dentry);
277+
n = 0;
278+
if (inode) {
279+
cinode = CIFS_I(inode);
280+
if (CIFS_CACHE_READ(cinode))
281+
lease[n++] = 'R';
282+
if (CIFS_CACHE_HANDLE(cinode))
283+
lease[n++] = 'H';
284+
if (CIFS_CACHE_WRITE(cinode))
285+
lease[n++] = 'W';
286+
}
287+
lease[n] = '\0';
288+
seq_puts(m, " ");
289+
if (n)
290+
seq_printf(m, "%s", lease);
291+
else
292+
seq_puts(m, "NONE");
293+
270294
#ifdef CONFIG_CIFS_DEBUG2
271-
seq_printf(m, " %llu\n", cfile->fid.mid);
272-
#else
295+
seq_printf(m, " %llu", cfile->fid.mid);
296+
#endif /* CONFIG_CIFS_DEBUG2 */
273297
seq_printf(m, "\n");
274-
#endif /* CIFS_DEBUG2 */
275298
}
276299
spin_unlock(&tcon->open_file_lock);
277300
}
@@ -308,7 +331,10 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
308331
if (!cfids)
309332
continue;
310333
spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
311-
seq_printf(m, "Num entries: %d\n", cfids->num_entries);
334+
seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
335+
cfids->num_entries,
336+
(unsigned long)atomic_long_read(&cfids->total_dirents_entries),
337+
(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
312338
list_for_each_entry(cfid, &cfids->entries, entry) {
313339
seq_printf(m, "0x%x 0x%llx 0x%llx %s",
314340
tcon->tid,
@@ -319,6 +345,9 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
319345
seq_printf(m, "\tvalid file info");
320346
if (cfid->dirents.is_valid)
321347
seq_printf(m, ", valid dirents");
348+
if (!list_empty(&cfid->dirents.entries))
349+
seq_printf(m, ", dirents: %lu entries, %lu bytes",
350+
cfid->dirents.entries_count, cfid->dirents.bytes_used);
322351
seq_printf(m, "\n");
323352
}
324353
spin_unlock(&cfids->cfid_list_lock);

fs/smb/client/cifsencrypt.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
#include <linux/highmem.h>
2323
#include <linux/fips.h>
2424
#include <linux/iov_iter.h>
25-
#include "../common/arc4.h"
2625
#include <crypto/aead.h>
26+
#include <crypto/arc4.h>
2727

2828
static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
2929
void *priv, void *priv2)
@@ -725,9 +725,9 @@ calc_seckey(struct cifs_ses *ses)
725725
return -ENOMEM;
726726
}
727727

728-
cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
729-
cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
730-
CIFS_CPHTXT_SIZE);
728+
arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
729+
arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
730+
CIFS_CPHTXT_SIZE);
731731

732732
/* make secondary_key/nonce as session key */
733733
memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);

fs/smb/client/cifsfs.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,46 @@ unsigned int dir_cache_timeout = 30;
121121
module_param(dir_cache_timeout, uint, 0644);
122122
MODULE_PARM_DESC(dir_cache_timeout, "Number of seconds to cache directory contents for which we have a lease. Default: 30 "
123123
"Range: 1 to 65000 seconds, 0 to disable caching dir contents");
124+
/* Module-wide total cached dirents (in bytes) across all tcons */
125+
atomic64_t cifs_dircache_bytes_used = ATOMIC64_INIT(0);
126+
127+
/*
128+
* Write-only module parameter to drop all cached directory entries across
129+
* all CIFS mounts. Echo a non-zero value to trigger.
130+
*/
131+
static void cifs_drop_all_dir_caches(void)
132+
{
133+
struct TCP_Server_Info *server;
134+
struct cifs_ses *ses;
135+
struct cifs_tcon *tcon;
136+
137+
spin_lock(&cifs_tcp_ses_lock);
138+
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
139+
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
140+
if (cifs_ses_exiting(ses))
141+
continue;
142+
list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
143+
invalidate_all_cached_dirs(tcon);
144+
}
145+
}
146+
spin_unlock(&cifs_tcp_ses_lock);
147+
}
148+
149+
static int cifs_param_set_drop_dir_cache(const char *val, const struct kernel_param *kp)
150+
{
151+
bool bv;
152+
int rc = kstrtobool(val, &bv);
153+
154+
if (rc)
155+
return rc;
156+
if (bv)
157+
cifs_drop_all_dir_caches();
158+
return 0;
159+
}
160+
161+
module_param_call(drop_dir_cache, cifs_param_set_drop_dir_cache, NULL, NULL, 0200);
162+
MODULE_PARM_DESC(drop_dir_cache, "Write 1 to drop all cached directory entries across all CIFS mounts");
163+
124164
#ifdef CONFIG_CIFS_STATS2
125165
unsigned int slow_rsp_threshold = 1;
126166
module_param(slow_rsp_threshold, uint, 0644);

0 commit comments

Comments
 (0)