Skip to content

Commit db68e4c

Browse files
committed
Merge tag 'v6.17-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client updates from Steve French: - Fix network namespace refcount leak - Multichannel reconnect fix - Perf improvement to not do unneeded EA query on native symlinks - Performance improvement for directory leases to allow extending lease for actively queried directories - Improve debugging of directory leases by adding pseudofile to show them - Five minor mount cleanup patches - Minor directory lease cleanup patch - Allow creating special files via reparse points over SMB1 - Two minor improvements to FindFirst over SMB1 - Two NTLMSSP session setup fixes * tag 'v6.17-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb3 client: add way to show directory leases for improved debugging smb: client: get rid of kstrdup() when parsing iocharset mount option smb: client: get rid of kstrdup() when parsing domain mount option smb: client: get rid of kstrdup() when parsing pass2 mount option smb: client: get rid of kstrdup() when parsing pass mount option smb: client: get rid of kstrdup() when parsing user mount option cifs: Add support for creating reparse points over SMB1 cifs: Do not query WSL EAs for native SMB symlink cifs: Optimize CIFSFindFirst() response when not searching cifs: Fix calling CIFSFindFirst() for root path without msearch smb: client: fix session setup against servers that require SPN smb: client: allow parsing zero-length AV pairs cifs: add new field to track the last access time of cfid smb: change return type of cached_dir_lease_break() to bool cifs: reset iface weights when we cannot find a candidate smb: client: fix netns refcount leak after net_passive changes
2 parents f2d282e + 844e5c0 commit db68e4c

17 files changed

+343
-105
lines changed

fs/smb/client/cached_dir.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
195195
* from @cfids->entries. Caller will put last reference if the latter.
196196
*/
197197
if (cfid->has_lease && cfid->time) {
198+
cfid->last_access_time = jiffies;
198199
spin_unlock(&cfids->cfid_list_lock);
199200
*ret_cfid = cfid;
200201
kfree(utf16_path);
@@ -363,6 +364,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
363364
cfid->file_all_info_is_valid = true;
364365

365366
cfid->time = jiffies;
367+
cfid->last_access_time = jiffies;
366368
spin_unlock(&cfids->cfid_list_lock);
367369
/* At this point the directory handle is fully cached */
368370
rc = 0;
@@ -617,7 +619,7 @@ static void cached_dir_put_work(struct work_struct *work)
617619
queue_work(serverclose_wq, &cfid->close_work);
618620
}
619621

620-
int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
622+
bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
621623
{
622624
struct cached_fids *cfids = tcon->cfids;
623625
struct cached_fid *cfid;
@@ -730,8 +732,8 @@ static void cfids_laundromat_worker(struct work_struct *work)
730732

731733
spin_lock(&cfids->cfid_list_lock);
732734
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
733-
if (cfid->time &&
734-
time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) {
735+
if (cfid->last_access_time &&
736+
time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) {
735737
cfid->on_list = false;
736738
list_move(&cfid->entry, &entry);
737739
cfids->num_entries--;

fs/smb/client/cached_dir.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ struct cached_dirent {
1414
char *name;
1515
int namelen;
1616
loff_t pos;
17-
1817
struct cifs_fattr fattr;
1918
};
2019

@@ -39,6 +38,7 @@ struct cached_fid {
3938
bool on_list:1;
4039
bool file_all_info_is_valid:1;
4140
unsigned long time; /* jiffies of when lease was taken */
41+
unsigned long last_access_time; /* jiffies of when last accessed */
4242
struct kref refcount;
4343
struct cifs_fid fid;
4444
spinlock_t fid_lock;
@@ -80,6 +80,6 @@ extern void drop_cached_dir_by_name(const unsigned int xid,
8080
struct cifs_sb_info *cifs_sb);
8181
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
8282
extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
83-
extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
83+
extern bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
8484

8585
#endif /* _CACHED_DIR_H */

fs/smb/client/cifs_debug.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "smbdirect.h"
2727
#endif
2828
#include "cifs_swn.h"
29+
#include "cached_dir.h"
2930

3031
void
3132
cifs_dump_mem(char *label, void *data, int length)
@@ -280,6 +281,54 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
280281
return 0;
281282
}
282283

284+
static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
285+
{
286+
struct list_head *stmp, *tmp, *tmp1;
287+
struct TCP_Server_Info *server;
288+
struct cifs_ses *ses;
289+
struct cifs_tcon *tcon;
290+
struct cached_fids *cfids;
291+
struct cached_fid *cfid;
292+
LIST_HEAD(entry);
293+
294+
seq_puts(m, "# Version:1\n");
295+
seq_puts(m, "# Format:\n");
296+
seq_puts(m, "# <tree id> <sess id> <persistent fid> <path>\n");
297+
298+
spin_lock(&cifs_tcp_ses_lock);
299+
list_for_each(stmp, &cifs_tcp_ses_list) {
300+
server = list_entry(stmp, struct TCP_Server_Info,
301+
tcp_ses_list);
302+
list_for_each(tmp, &server->smb_ses_list) {
303+
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
304+
list_for_each(tmp1, &ses->tcon_list) {
305+
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
306+
cfids = tcon->cfids;
307+
spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
308+
seq_printf(m, "Num entries: %d\n", cfids->num_entries);
309+
list_for_each_entry(cfid, &cfids->entries, entry) {
310+
seq_printf(m, "0x%x 0x%llx 0x%llx %s",
311+
tcon->tid,
312+
ses->Suid,
313+
cfid->fid.persistent_fid,
314+
cfid->path);
315+
if (cfid->file_all_info_is_valid)
316+
seq_printf(m, "\tvalid file info");
317+
if (cfid->dirents.is_valid)
318+
seq_printf(m, ", valid dirents");
319+
seq_printf(m, "\n");
320+
}
321+
spin_unlock(&cfids->cfid_list_lock);
322+
323+
324+
}
325+
}
326+
}
327+
spin_unlock(&cifs_tcp_ses_lock);
328+
seq_putc(m, '\n');
329+
return 0;
330+
}
331+
283332
static __always_inline const char *compression_alg_str(__le16 alg)
284333
{
285334
switch (alg) {
@@ -863,6 +912,9 @@ cifs_proc_init(void)
863912
proc_create_single("open_files", 0400, proc_fs_cifs,
864913
cifs_debug_files_proc_show);
865914

915+
proc_create_single("open_dirs", 0400, proc_fs_cifs,
916+
cifs_debug_dirs_proc_show);
917+
866918
proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops);
867919
proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops);
868920
proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);
@@ -907,6 +959,7 @@ cifs_proc_clean(void)
907959

908960
remove_proc_entry("DebugData", proc_fs_cifs);
909961
remove_proc_entry("open_files", proc_fs_cifs);
962+
remove_proc_entry("open_dirs", proc_fs_cifs);
910963
remove_proc_entry("cifsFYI", proc_fs_cifs);
911964
remove_proc_entry("traceSMB", proc_fs_cifs);
912965
remove_proc_entry("Stats", proc_fs_cifs);

fs/smb/client/cifsencrypt.c

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ static struct ntlmssp2_name *find_next_av(struct cifs_ses *ses,
343343
len = AV_LEN(av);
344344
if (AV_TYPE(av) == NTLMSSP_AV_EOL)
345345
return NULL;
346-
if (!len || (u8 *)av + sizeof(*av) + len > end)
346+
if ((u8 *)av + sizeof(*av) + len > end)
347347
return NULL;
348348
return av;
349349
}
@@ -363,7 +363,7 @@ static int find_av_name(struct cifs_ses *ses, u16 type, char **name, u16 maxlen)
363363

364364
av_for_each_entry(ses, av) {
365365
len = AV_LEN(av);
366-
if (AV_TYPE(av) != type)
366+
if (AV_TYPE(av) != type || !len)
367367
continue;
368368
if (!IS_ALIGNED(len, sizeof(__le16))) {
369369
cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n",
@@ -532,17 +532,67 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_
532532
return rc;
533533
}
534534

535+
/*
536+
* Set up NTLMv2 response blob with SPN (cifs/<hostname>) appended to the
537+
* existing list of AV pairs.
538+
*/
539+
static int set_auth_key_response(struct cifs_ses *ses)
540+
{
541+
size_t baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
542+
size_t len, spnlen, tilen = 0, num_avs = 2 /* SPN + EOL */;
543+
struct TCP_Server_Info *server = ses->server;
544+
char *spn __free(kfree) = NULL;
545+
struct ntlmssp2_name *av;
546+
char *rsp = NULL;
547+
int rc;
548+
549+
spnlen = strlen(server->hostname);
550+
len = sizeof("cifs/") + spnlen;
551+
spn = kmalloc(len, GFP_KERNEL);
552+
if (!spn) {
553+
rc = -ENOMEM;
554+
goto out;
555+
}
556+
557+
spnlen = scnprintf(spn, len, "cifs/%.*s",
558+
(int)spnlen, server->hostname);
559+
560+
av_for_each_entry(ses, av)
561+
tilen += sizeof(*av) + AV_LEN(av);
562+
563+
len = baselen + tilen + spnlen * sizeof(__le16) + num_avs * sizeof(*av);
564+
rsp = kmalloc(len, GFP_KERNEL);
565+
if (!rsp) {
566+
rc = -ENOMEM;
567+
goto out;
568+
}
569+
570+
memcpy(rsp + baselen, ses->auth_key.response, tilen);
571+
av = (void *)(rsp + baselen + tilen);
572+
av->type = cpu_to_le16(NTLMSSP_AV_TARGET_NAME);
573+
av->length = cpu_to_le16(spnlen * sizeof(__le16));
574+
cifs_strtoUTF16((__le16 *)av->data, spn, spnlen, ses->local_nls);
575+
av = (void *)((__u8 *)av + sizeof(*av) + AV_LEN(av));
576+
av->type = cpu_to_le16(NTLMSSP_AV_EOL);
577+
av->length = 0;
578+
579+
rc = 0;
580+
ses->auth_key.len = len;
581+
out:
582+
ses->auth_key.response = rsp;
583+
return rc;
584+
}
585+
535586
int
536587
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
537588
{
538589
struct shash_desc *hmacmd5 = NULL;
539-
int rc;
540-
int baselen;
541-
unsigned int tilen;
590+
unsigned char *tiblob = NULL; /* target info blob */
542591
struct ntlmv2_resp *ntlmv2;
543592
char ntlmv2_hash[16];
544-
unsigned char *tiblob = NULL; /* target info blob */
545593
__le64 rsp_timestamp;
594+
__u64 cc;
595+
int rc;
546596

547597
if (nls_cp == NULL) {
548598
cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__);
@@ -588,32 +638,25 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
588638
* (as Windows 7 does)
589639
*/
590640
rsp_timestamp = find_timestamp(ses);
641+
get_random_bytes(&cc, sizeof(cc));
591642

592-
baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
593-
tilen = ses->auth_key.len;
594-
tiblob = ses->auth_key.response;
643+
cifs_server_lock(ses->server);
595644

596-
ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
597-
if (!ses->auth_key.response) {
598-
rc = -ENOMEM;
645+
tiblob = ses->auth_key.response;
646+
rc = set_auth_key_response(ses);
647+
if (rc) {
599648
ses->auth_key.len = 0;
600-
goto setup_ntlmv2_rsp_ret;
649+
goto unlock;
601650
}
602-
ses->auth_key.len += baselen;
603651

604652
ntlmv2 = (struct ntlmv2_resp *)
605653
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
606654
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
607655
ntlmv2->reserved = 0;
608656
ntlmv2->time = rsp_timestamp;
609-
610-
get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
657+
ntlmv2->client_chal = cc;
611658
ntlmv2->reserved2 = 0;
612659

613-
memcpy(ses->auth_key.response + baselen, tiblob, tilen);
614-
615-
cifs_server_lock(ses->server);
616-
617660
rc = cifs_alloc_hash("hmac(md5)", &hmacmd5);
618661
if (rc) {
619662
cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc);

fs/smb/client/cifsglob.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -627,12 +627,14 @@ struct smb_version_operations {
627627
bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
628628
struct reparse_data_buffer * (*get_reparse_point_buffer)(const struct kvec *rsp_iov,
629629
u32 *plen);
630-
int (*create_reparse_symlink)(const unsigned int xid,
631-
struct inode *inode,
632-
struct dentry *dentry,
633-
struct cifs_tcon *tcon,
634-
const char *full_path,
635-
const char *symname);
630+
struct inode * (*create_reparse_inode)(struct cifs_open_info_data *data,
631+
struct super_block *sb,
632+
const unsigned int xid,
633+
struct cifs_tcon *tcon,
634+
const char *full_path,
635+
bool directory,
636+
struct kvec *reparse_iov,
637+
struct kvec *xattr_iov);
636638
};
637639

638640
struct smb_version_values {

fs/smb/client/cifsproto.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,14 @@ extern int cifs_query_reparse_point(const unsigned int xid,
483483
const char *full_path,
484484
u32 *tag, struct kvec *rsp,
485485
int *rsp_buftype);
486+
extern struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
487+
struct super_block *sb,
488+
const unsigned int xid,
489+
struct cifs_tcon *tcon,
490+
const char *full_path,
491+
bool directory,
492+
struct kvec *reparse_iov,
493+
struct kvec *xattr_iov);
486494
extern int CIFSSMB_set_compression(const unsigned int xid,
487495
struct cifs_tcon *tcon, __u16 fid);
488496
extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,

0 commit comments

Comments
 (0)