xref: /linux/fs/smb/client/cifs_debug.c (revision 7a5f1cd22d47f8ca4b760b6334378ae42c1bd24b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *   Copyright (C) International Business Machines  Corp., 2000,2005
5  *
6  *   Modified by Steve French (sfrench@us.ibm.com)
7  */
8 #include <linux/fs.h>
9 #include <linux/string.h>
10 #include <linux/ctype.h>
11 #include <linux/kstrtox.h>
12 #include <linux/module.h>
13 #include <linux/proc_fs.h>
14 #include <linux/uaccess.h>
15 #include <uapi/linux/ethtool.h>
16 #include "cifsglob.h"
17 #include "cifsproto.h"
18 #include "cifs_debug.h"
19 #include "cifsfs.h"
20 #include "fs_context.h"
21 #ifdef CONFIG_CIFS_DFS_UPCALL
22 #include "dfs_cache.h"
23 #endif
24 #ifdef CONFIG_CIFS_SMB_DIRECT
25 #include "smbdirect.h"
26 #endif
27 #include "cifs_swn.h"
28 #include "cached_dir.h"
29 
30 void
31 cifs_dump_mem(char *label, void *data, int length)
32 {
33 	pr_debug("%s: dump of %d bytes of data at 0x%p\n", label, length, data);
34 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4,
35 		       data, length, true);
36 }
37 
38 void cifs_dump_mids(struct TCP_Server_Info *server)
39 {
40 #ifdef CONFIG_CIFS_DEBUG2
41 	struct mid_q_entry *mid_entry;
42 
43 	if (server == NULL)
44 		return;
45 
46 	cifs_dbg(VFS, "Dump pending requests:\n");
47 	spin_lock(&server->mid_queue_lock);
48 	list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
49 		cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n",
50 			 mid_entry->mid_state,
51 			 le16_to_cpu(mid_entry->command),
52 			 mid_entry->pid,
53 			 mid_entry->callback_data,
54 			 mid_entry->mid);
55 #ifdef CONFIG_CIFS_STATS2
56 		cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n",
57 			 mid_entry->large_buf,
58 			 mid_entry->resp_buf,
59 			 mid_entry->when_received,
60 			 jiffies);
61 #endif /* STATS2 */
62 		cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n",
63 			 mid_entry->multiRsp, mid_entry->multiEnd);
64 		if (mid_entry->resp_buf) {
65 			server->ops->dump_detail(mid_entry->resp_buf,
66 					 mid_entry->response_pdu_len, server);
67 			cifs_dump_mem("existing buf: ", mid_entry->resp_buf, 62);
68 		}
69 	}
70 	spin_unlock(&server->mid_queue_lock);
71 #endif /* CONFIG_CIFS_DEBUG2 */
72 }
73 
74 #ifdef CONFIG_PROC_FS
75 static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
76 {
77 	__u32 dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
78 
79 	seq_printf(m, "%s Mounts: %d ", tcon->tree_name, tcon->tc_count);
80 	if (tcon->nativeFileSystem)
81 		seq_printf(m, "Type: %s ", tcon->nativeFileSystem);
82 	seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x\n\tPathComponentMax: %d Status: %d",
83 		   le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
84 		   le32_to_cpu(tcon->fsAttrInfo.Attributes),
85 		   le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
86 		   tcon->status);
87 	if (dev_type == FILE_DEVICE_DISK)
88 		seq_puts(m, " type: DISK ");
89 	else if (dev_type == FILE_DEVICE_CD_ROM)
90 		seq_puts(m, " type: CDROM ");
91 	else
92 		seq_printf(m, " type: %d ", dev_type);
93 
94 	seq_printf(m, "Serial Number: 0x%x", tcon->vol_serial_number);
95 
96 	if ((tcon->seal) ||
97 	    (tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
98 	    (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
99 		seq_puts(m, " encrypted");
100 	if (tcon->nocase)
101 		seq_printf(m, " nocase");
102 	if (tcon->unix_ext)
103 		seq_printf(m, " POSIX Extensions");
104 	if (tcon->ses->server->ops->dump_share_caps)
105 		tcon->ses->server->ops->dump_share_caps(m, tcon);
106 	if (tcon->use_witness)
107 		seq_puts(m, " Witness");
108 	if (tcon->broken_sparse_sup)
109 		seq_puts(m, " nosparse");
110 	if (tcon->need_reconnect)
111 		seq_puts(m, "\tDISCONNECTED ");
112 	spin_lock(&tcon->tc_lock);
113 	if (tcon->origin_fullpath) {
114 		seq_printf(m, "\n\tDFS origin fullpath: %s",
115 			   tcon->origin_fullpath);
116 	}
117 	spin_unlock(&tcon->tc_lock);
118 	seq_putc(m, '\n');
119 }
120 
121 static void
122 cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
123 {
124 	struct TCP_Server_Info *server = chan->server;
125 
126 	if (!server) {
127 		seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
128 		return;
129 	}
130 
131 	seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
132 		   "\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
133 		   "\n\t\tTCP status: %d Instance: %d"
134 		   "\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
135 		   "\n\t\tIn Send: %d In MaxReq Wait: %d",
136 		   i+1, server->conn_id,
137 		   server->credits,
138 		   server->echo_credits,
139 		   server->oplock_credits,
140 		   server->dialect,
141 		   server->tcpStatus,
142 		   server->reconnect_instance,
143 		   server->srv_count,
144 		   server->sec_mode,
145 		   in_flight(server),
146 		   atomic_read(&server->in_send),
147 		   atomic_read(&server->num_waiters));
148 #ifdef CONFIG_NET_NS
149 	if (server->net)
150 		seq_printf(m, " Net namespace: %u ", server->net->ns.inum);
151 #endif /* NET_NS */
152 
153 }
154 
155 static inline const char *smb_speed_to_str(size_t bps)
156 {
157 	size_t mbps = bps / 1000 / 1000;
158 
159 	switch (mbps) {
160 	case SPEED_10:
161 		return "10Mbps";
162 	case SPEED_100:
163 		return "100Mbps";
164 	case SPEED_1000:
165 		return "1Gbps";
166 	case SPEED_2500:
167 		return "2.5Gbps";
168 	case SPEED_5000:
169 		return "5Gbps";
170 	case SPEED_10000:
171 		return "10Gbps";
172 	case SPEED_14000:
173 		return "14Gbps";
174 	case SPEED_20000:
175 		return "20Gbps";
176 	case SPEED_25000:
177 		return "25Gbps";
178 	case SPEED_40000:
179 		return "40Gbps";
180 	case SPEED_50000:
181 		return "50Gbps";
182 	case SPEED_56000:
183 		return "56Gbps";
184 	case SPEED_100000:
185 		return "100Gbps";
186 	case SPEED_200000:
187 		return "200Gbps";
188 	case SPEED_400000:
189 		return "400Gbps";
190 	case SPEED_800000:
191 		return "800Gbps";
192 	default:
193 		return "Unknown";
194 	}
195 }
196 
197 static void
198 cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
199 {
200 	struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
201 	struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
202 
203 	seq_printf(m, "\tSpeed: %s\n", smb_speed_to_str(iface->speed));
204 	seq_puts(m, "\t\tCapabilities: ");
205 	if (iface->rdma_capable)
206 		seq_puts(m, "rdma ");
207 	if (iface->rss_capable)
208 		seq_puts(m, "rss ");
209 	if (!iface->rdma_capable && !iface->rss_capable)
210 		seq_puts(m, "None");
211 	seq_putc(m, '\n');
212 	if (iface->sockaddr.ss_family == AF_INET)
213 		seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
214 	else if (iface->sockaddr.ss_family == AF_INET6)
215 		seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
216 	if (!iface->is_active)
217 		seq_puts(m, "\t\t[for-cleanup]\n");
218 }
219 
220 static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
221 {
222 	struct TCP_Server_Info *server;
223 	struct cifs_ses *ses;
224 	struct cifs_tcon *tcon;
225 	struct cifsFileInfo *cfile;
226 	struct inode *inode;
227 	struct cifsInodeInfo *cinode;
228 	char lease[4];
229 	int n;
230 
231 	seq_puts(m, "# Version:1\n");
232 	seq_puts(m, "# Format:\n");
233 	seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
234 #ifdef CONFIG_CIFS_DEBUG2
235 	seq_puts(m, " <filename> <lease> <lease-key> <mid>\n");
236 #else
237 	seq_puts(m, " <filename> <lease> <lease-key>\n");
238 #endif /* CIFS_DEBUG2 */
239 	spin_lock(&cifs_tcp_ses_lock);
240 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
241 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
242 			if (cifs_ses_exiting(ses))
243 				continue;
244 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
245 				spin_lock(&tcon->open_file_lock);
246 				list_for_each_entry(cfile, &tcon->openFileList, tlist) {
247 					seq_printf(m,
248 						"0x%x 0x%llx 0x%llx 0x%x %d %d %d %pd",
249 						tcon->tid,
250 						ses->Suid,
251 						cfile->fid.persistent_fid,
252 						cfile->f_flags,
253 						cfile->count,
254 						cfile->pid,
255 						from_kuid(&init_user_ns, cfile->uid),
256 						cfile->dentry);
257 
258 					/* Append lease/oplock caching state as RHW letters */
259 					inode = d_inode(cfile->dentry);
260 					cinode = NULL;
261 					n = 0;
262 					if (inode) {
263 						cinode = CIFS_I(inode);
264 						if (CIFS_CACHE_READ(cinode))
265 							lease[n++] = 'R';
266 						if (CIFS_CACHE_HANDLE(cinode))
267 							lease[n++] = 'H';
268 						if (CIFS_CACHE_WRITE(cinode))
269 							lease[n++] = 'W';
270 					}
271 					lease[n] = '\0';
272 					seq_puts(m, " ");
273 					if (n)
274 						seq_printf(m, "%s", lease);
275 					else
276 						seq_puts(m, "NONE");
277 
278 					seq_puts(m, " ");
279 					if (cinode && cinode->lease_granted)
280 						seq_printf(m, "%pUl", cinode->lease_key);
281 					else
282 						seq_puts(m, "-");
283 
284 #ifdef CONFIG_CIFS_DEBUG2
285 					seq_printf(m, " %llu", cfile->fid.mid);
286 #endif /* CONFIG_CIFS_DEBUG2 */
287 					seq_printf(m, "\n");
288 				}
289 				spin_unlock(&tcon->open_file_lock);
290 			}
291 		}
292 	}
293 	spin_unlock(&cifs_tcp_ses_lock);
294 	seq_putc(m, '\n');
295 	return 0;
296 }
297 
298 static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
299 {
300 	struct list_head *stmp, *tmp, *tmp1;
301 	struct TCP_Server_Info *server;
302 	struct cifs_ses *ses;
303 	struct cifs_tcon *tcon;
304 	struct cached_fids *cfids;
305 	struct cached_fid *cfid;
306 	LIST_HEAD(entry);
307 
308 	seq_puts(m, "# Version:1\n");
309 #ifdef CONFIG_CIFS_DEBUG
310 	seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n");
311 #endif /* CONFIG_CIFS_DEBUG */
312 	seq_puts(m, "# Format:\n");
313 	seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n");
314 
315 	spin_lock(&cifs_tcp_ses_lock);
316 	list_for_each(stmp, &cifs_tcp_ses_list) {
317 		server = list_entry(stmp, struct TCP_Server_Info,
318 				    tcp_ses_list);
319 		list_for_each(tmp, &server->smb_ses_list) {
320 			ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
321 			list_for_each(tmp1, &ses->tcon_list) {
322 				tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
323 				cfids = tcon->cfids;
324 				if (!cfids)
325 					continue;
326 				spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
327 				seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
328 						cfids->num_entries,
329 						(unsigned long)atomic_long_read(&cfids->total_dirents_entries),
330 						(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
331 				list_for_each_entry(cfid, &cfids->entries, entry) {
332 					seq_printf(m, "0x%x 0x%llx 0x%llx ",
333 						tcon->tid,
334 						ses->Suid,
335 						cfid->fid.persistent_fid);
336 					if (cfid->has_lease)
337 						seq_printf(m, "%pUl ", cfid->fid.lease_key);
338 					else
339 						seq_puts(m, "- ");
340 					seq_printf(m, "%s", cfid->path);
341 					if (cfid->file_all_info_is_valid)
342 						seq_printf(m, "\tvalid file info");
343 					if (cfid->dirents.is_valid)
344 						seq_printf(m, ", valid dirents");
345 					if (!list_empty(&cfid->dirents.entries))
346 						seq_printf(m, ", dirents: %lu entries, %lu bytes",
347 						cfid->dirents.entries_count, cfid->dirents.bytes_used);
348 					seq_printf(m, "\n");
349 				}
350 				spin_unlock(&cfids->cfid_list_lock);
351 			}
352 		}
353 	}
354 	spin_unlock(&cifs_tcp_ses_lock);
355 	seq_putc(m, '\n');
356 	return 0;
357 }
358 
359 #ifdef CONFIG_CIFS_DEBUG
360 static int cifs_debug_dirs_proc_open(struct inode *inode, struct file *file)
361 {
362 	return single_open(file, cifs_debug_dirs_proc_show, NULL);
363 }
364 
365 /* Drop all cached directory entries across all CIFS mounts. */
366 static ssize_t cifs_debug_dirs_proc_write(struct file *file, const char __user *buffer,
367 					  size_t count, loff_t *ppos)
368 {
369 	int rc, v;
370 
371 	rc = kstrtoint_from_user(buffer, count, 10, &v);
372 	if (rc)
373 		return rc;
374 
375 	if (v == 0) {
376 		struct TCP_Server_Info *server;
377 		struct cifs_ses *ses;
378 		struct cifs_tcon *tcon;
379 
380 		spin_lock(&cifs_tcp_ses_lock);
381 		list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
382 			list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
383 				if (cifs_ses_exiting(ses))
384 					continue;
385 				list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
386 					invalidate_all_cached_dirs(tcon, false);
387 			}
388 		}
389 		spin_unlock(&cifs_tcp_ses_lock);
390 	}
391 
392 	return count;
393 }
394 
395 static const struct proc_ops cifs_debug_dirs_proc_ops = {
396 	.proc_open	= cifs_debug_dirs_proc_open,
397 	.proc_read	= seq_read,
398 	.proc_lseek	= seq_lseek,
399 	.proc_release	= single_release,
400 	.proc_write	= cifs_debug_dirs_proc_write,
401 };
402 #endif /* CONFIG_CIFS_DEBUG */
403 
404 static __always_inline const char *compression_alg_str(__le16 alg)
405 {
406 	switch (alg) {
407 	case SMB3_COMPRESS_NONE:
408 		return "NONE";
409 	case SMB3_COMPRESS_LZNT1:
410 		return "LZNT1";
411 	case SMB3_COMPRESS_LZ77:
412 		return "LZ77";
413 	case SMB3_COMPRESS_LZ77_HUFF:
414 		return "LZ77-Huffman";
415 	case SMB3_COMPRESS_PATTERN:
416 		return "Pattern_V1";
417 	default:
418 		return "invalid";
419 	}
420 }
421 
422 static __always_inline const char *cipher_alg_str(__le16 cipher)
423 {
424 	switch (cipher) {
425 	case SMB2_ENCRYPTION_AES128_CCM:
426 		return "AES128-CCM";
427 	case SMB2_ENCRYPTION_AES128_GCM:
428 		return "AES128-GCM";
429 	case SMB2_ENCRYPTION_AES256_CCM:
430 		return "AES256-CCM";
431 	case SMB2_ENCRYPTION_AES256_GCM:
432 		return "AES256-GCM";
433 	default:
434 		return "UNKNOWN";
435 	}
436 }
437 
438 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
439 {
440 	struct mid_q_entry *mid_entry;
441 	struct TCP_Server_Info *server;
442 	struct TCP_Server_Info *chan_server;
443 	struct cifs_ses *ses;
444 	struct cifs_tcon *tcon;
445 	struct cifs_server_iface *iface;
446 	size_t iface_weight = 0, iface_min_speed = 0;
447 	struct cifs_server_iface *last_iface = NULL;
448 	int c, i, j;
449 
450 	seq_puts(m,
451 		    "Display Internal CIFS Data Structures for Debugging\n"
452 		    "---------------------------------------------------\n");
453 	seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
454 	seq_printf(m, "Features:");
455 #ifdef CONFIG_CIFS_DFS_UPCALL
456 	seq_printf(m, " DFS");
457 #endif
458 #ifdef CONFIG_CIFS_FSCACHE
459 	seq_printf(m, ",FSCACHE");
460 #endif
461 #ifdef CONFIG_CIFS_SMB_DIRECT
462 	seq_printf(m, ",SMB_DIRECT");
463 #endif
464 #ifdef CONFIG_CIFS_STATS2
465 	seq_printf(m, ",STATS2");
466 #else
467 	seq_printf(m, ",STATS");
468 #endif
469 #ifdef CONFIG_CIFS_DEBUG2
470 	seq_printf(m, ",DEBUG2");
471 #elif defined(CONFIG_CIFS_DEBUG)
472 	seq_printf(m, ",DEBUG");
473 #endif
474 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
475 	seq_printf(m, ",ALLOW_INSECURE_LEGACY");
476 #endif
477 #ifdef CONFIG_CIFS_POSIX
478 	seq_printf(m, ",CIFS_POSIX");
479 #endif
480 #ifdef CONFIG_CIFS_UPCALL
481 	seq_printf(m, ",UPCALL(SPNEGO)");
482 #endif
483 #ifdef CONFIG_CIFS_XATTR
484 	seq_printf(m, ",XATTR");
485 #endif
486 	seq_printf(m, ",ACL");
487 #ifdef CONFIG_CIFS_SWN_UPCALL
488 	seq_puts(m, ",WITNESS");
489 #endif
490 #ifdef CONFIG_CIFS_COMPRESSION
491 	seq_puts(m, ",COMPRESSION");
492 #endif
493 	seq_putc(m, '\n');
494 	seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
495 	seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
496 
497 	seq_printf(m, "\nServers: ");
498 
499 	c = 0;
500 	spin_lock(&cifs_tcp_ses_lock);
501 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
502 		/* channel info will be printed as a part of sessions below */
503 		if (SERVER_IS_CHAN(server))
504 			continue;
505 
506 		c++;
507 		seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
508 			c, server->conn_id);
509 
510 		spin_lock(&server->srv_lock);
511 		if (server->hostname)
512 			seq_printf(m, "Hostname: %s ", server->hostname);
513 		seq_printf(m, "\nClientGUID: %pUL", server->client_guid);
514 		spin_unlock(&server->srv_lock);
515 #ifdef CONFIG_CIFS_SMB_DIRECT
516 		smbd_debug_proc_show(server, m);
517 #endif
518 		seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
519 			server->credits,
520 			server->echo_credits,
521 			server->oplock_credits,
522 			server->dialect);
523 		if (server->sign)
524 			seq_printf(m, " signed");
525 		if (server->posix_ext_supported)
526 			seq_printf(m, " posix");
527 		if (server->nosharesock)
528 			seq_printf(m, " nosharesock");
529 
530 		seq_printf(m, "\nServer capabilities: 0x%x", server->capabilities);
531 
532 		if (server->rdma)
533 			seq_printf(m, "\nRDMA ");
534 		seq_printf(m, "\nTCP status: %d Instance: %d"
535 				"\nLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
536 				server->tcpStatus,
537 				server->reconnect_instance,
538 				server->srv_count,
539 				server->sec_mode, in_flight(server));
540 #ifdef CONFIG_NET_NS
541 		if (server->net)
542 			seq_printf(m, " Net namespace: %u ", server->net->ns.inum);
543 #endif /* NET_NS */
544 
545 		seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d",
546 				atomic_read(&server->in_send),
547 				atomic_read(&server->num_waiters));
548 
549 		if (server->leaf_fullpath) {
550 			seq_printf(m, "\nDFS leaf full path: %s",
551 				   server->leaf_fullpath);
552 		}
553 
554 		seq_puts(m, "\nCompression: ");
555 		if (!IS_ENABLED(CONFIG_CIFS_COMPRESSION))
556 			seq_puts(m, "no built-in support");
557 		else if (!server->compression.requested)
558 			seq_puts(m, "disabled on mount");
559 		else if (server->compression.enabled)
560 			seq_printf(m, "enabled (%s)", compression_alg_str(server->compression.alg));
561 		else
562 			seq_puts(m, "disabled (not supported by this server)");
563 
564 		/* Show negotiated encryption cipher, even if not required */
565 		seq_puts(m, "\nEncryption: ");
566 		if (server->cipher_type)
567 			seq_printf(m, "Negotiated cipher (%s)", cipher_alg_str(server->cipher_type));
568 
569 		seq_printf(m, "\n\n\tSessions: ");
570 		i = 0;
571 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
572 			spin_lock(&ses->ses_lock);
573 			if (ses->ses_status == SES_EXITING) {
574 				spin_unlock(&ses->ses_lock);
575 				continue;
576 			}
577 			i++;
578 			if ((ses->serverDomain == NULL) ||
579 				(ses->serverOS == NULL) ||
580 				(ses->serverNOS == NULL)) {
581 				seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
582 					i, ses->ip_addr, ses->ses_count,
583 					ses->capabilities, ses->ses_status);
584 				if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
585 					seq_printf(m, "Guest ");
586 				else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
587 					seq_printf(m, "Anonymous ");
588 			} else {
589 				seq_printf(m,
590 				    "\n\t%d) Name: %s  Domain: %s Uses: %d OS: %s "
591 				    "\n\tNOS: %s\tCapability: 0x%x"
592 					"\n\tSMB session status: %d ",
593 				i, ses->ip_addr, ses->serverDomain,
594 				ses->ses_count, ses->serverOS, ses->serverNOS,
595 				ses->capabilities, ses->ses_status);
596 			}
597 			if (ses->expired_pwd)
598 				seq_puts(m, "password no longer valid ");
599 			spin_unlock(&ses->ses_lock);
600 
601 			seq_printf(m, "\n\tSecurity type: %s ",
602 				get_security_type_str(server->ops->select_sectype(server, ses->sectype)));
603 
604 			/* dump session id helpful for use with network trace */
605 			seq_printf(m, " SessionId: 0x%llx", ses->Suid);
606 			if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
607 				seq_puts(m, " encrypted");
608 			if (ses->sign)
609 				seq_puts(m, " signed");
610 
611 			seq_printf(m, "\n\tUser: %d Cred User: %d",
612 				   from_kuid(&init_user_ns, ses->linux_uid),
613 				   from_kuid(&init_user_ns, ses->cred_uid));
614 
615 			if (ses->dfs_root_ses) {
616 				seq_printf(m, "\n\tDFS root session id: 0x%llx",
617 					   ses->dfs_root_ses->Suid);
618 			}
619 
620 			spin_lock(&ses->chan_lock);
621 			if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
622 				seq_puts(m, "\tPrimary channel: DISCONNECTED ");
623 			if (CIFS_CHAN_IN_RECONNECT(ses, 0))
624 				seq_puts(m, "\t[RECONNECTING] ");
625 
626 			if (ses->chan_count > 1) {
627 				seq_printf(m, "\n\n\tExtra Channels: %zu ",
628 					   ses->chan_count-1);
629 				for (j = 1; j < ses->chan_count; j++) {
630 					cifs_dump_channel(m, j, &ses->chans[j]);
631 					if (CIFS_CHAN_NEEDS_RECONNECT(ses, j))
632 						seq_puts(m, "\tDISCONNECTED ");
633 					if (CIFS_CHAN_IN_RECONNECT(ses, j))
634 						seq_puts(m, "\t[RECONNECTING] ");
635 				}
636 			}
637 			spin_unlock(&ses->chan_lock);
638 
639 			seq_puts(m, "\n\n\tShares: ");
640 			j = 0;
641 
642 			seq_printf(m, "\n\t%d) IPC: ", j);
643 			if (ses->tcon_ipc)
644 				cifs_debug_tcon(m, ses->tcon_ipc);
645 			else
646 				seq_puts(m, "none\n");
647 
648 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
649 				++j;
650 				seq_printf(m, "\n\t%d) ", j);
651 				cifs_debug_tcon(m, tcon);
652 			}
653 
654 			spin_lock(&ses->iface_lock);
655 			if (ses->iface_count)
656 				seq_printf(m, "\n\n\tServer interfaces: %zu"
657 					   "\tLast updated: %lu seconds ago",
658 					   ses->iface_count,
659 					   (jiffies - ses->iface_last_update) / HZ);
660 
661 			last_iface = list_last_entry(&ses->iface_list,
662 						     struct cifs_server_iface,
663 						     iface_head);
664 			iface_min_speed = last_iface->speed;
665 
666 			j = 0;
667 			list_for_each_entry(iface, &ses->iface_list,
668 						 iface_head) {
669 				seq_printf(m, "\n\t%d)", ++j);
670 				cifs_dump_iface(m, iface);
671 
672 				iface_weight = iface->speed / iface_min_speed;
673 				seq_printf(m, "\t\tWeight (cur,total): (%zu,%zu)"
674 					   "\n\t\tAllocated channels: %u\n",
675 					   iface->weight_fulfilled,
676 					   iface_weight,
677 					   iface->num_channels);
678 
679 				if (is_ses_using_iface(ses, iface))
680 					seq_puts(m, "\t\t[CONNECTED]\n");
681 			}
682 			spin_unlock(&ses->iface_lock);
683 
684 			seq_puts(m, "\n\n\tMIDs: ");
685 			spin_lock(&ses->chan_lock);
686 			for (j = 0; j < ses->chan_count; j++) {
687 				chan_server = ses->chans[j].server;
688 				if (!chan_server)
689 					continue;
690 
691 				if (list_empty(&chan_server->pending_mid_q))
692 					continue;
693 
694 				seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
695 					   chan_server->conn_id);
696 				spin_lock(&chan_server->mid_queue_lock);
697 				list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
698 					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
699 						   mid_entry->mid_state,
700 						   le16_to_cpu(mid_entry->command),
701 						   mid_entry->pid,
702 						   mid_entry->callback_data,
703 						   mid_entry->mid);
704 				}
705 				spin_unlock(&chan_server->mid_queue_lock);
706 			}
707 			spin_unlock(&ses->chan_lock);
708 			seq_puts(m, "\n--\n");
709 		}
710 		if (i == 0)
711 			seq_printf(m, "\n\t\t[NONE]");
712 	}
713 	if (c == 0)
714 		seq_printf(m, "\n\t[NONE]");
715 
716 	spin_unlock(&cifs_tcp_ses_lock);
717 	seq_putc(m, '\n');
718 	cifs_swn_dump(m);
719 
720 	/* BB add code to dump additional info such as TCP session info now */
721 	return 0;
722 }
723 
724 static ssize_t cifs_stats_proc_write(struct file *file,
725 		const char __user *buffer, size_t count, loff_t *ppos)
726 {
727 	bool bv;
728 	int rc;
729 	struct TCP_Server_Info *server;
730 	struct cifs_ses *ses;
731 	struct cifs_tcon *tcon;
732 
733 	rc = kstrtobool_from_user(buffer, count, &bv);
734 	if (rc == 0) {
735 #ifdef CONFIG_CIFS_STATS2
736 		int i;
737 
738 		atomic_set(&total_buf_alloc_count, 0);
739 		atomic_set(&total_small_buf_alloc_count, 0);
740 #endif /* CONFIG_CIFS_STATS2 */
741 		atomic_set(&tcpSesReconnectCount, 0);
742 		atomic_set(&tconInfoReconnectCount, 0);
743 
744 		spin_lock(&GlobalMid_Lock);
745 		GlobalMaxActiveXid = 0;
746 		GlobalCurrentXid = 0;
747 		spin_unlock(&GlobalMid_Lock);
748 		spin_lock(&cifs_tcp_ses_lock);
749 		list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
750 			server->max_in_flight = 0;
751 #ifdef CONFIG_CIFS_STATS2
752 			for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
753 				atomic_set(&server->num_cmds[i], 0);
754 				atomic_set(&server->smb2slowcmd[i], 0);
755 				server->time_per_cmd[i] = 0;
756 				server->slowest_cmd[i] = 0;
757 				server->fastest_cmd[0] = 0;
758 			}
759 #endif /* CONFIG_CIFS_STATS2 */
760 			list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
761 				if (cifs_ses_exiting(ses))
762 					continue;
763 				list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
764 					atomic_set(&tcon->num_smbs_sent, 0);
765 					spin_lock(&tcon->stat_lock);
766 					tcon->bytes_read = 0;
767 					tcon->bytes_written = 0;
768 					tcon->stats_from_time = ktime_get_real_seconds();
769 					spin_unlock(&tcon->stat_lock);
770 					if (server->ops->clear_stats)
771 						server->ops->clear_stats(tcon);
772 				}
773 			}
774 		}
775 		spin_unlock(&cifs_tcp_ses_lock);
776 	} else {
777 		return rc;
778 	}
779 
780 	return count;
781 }
782 
783 static int cifs_stats_proc_show(struct seq_file *m, void *v)
784 {
785 	int i;
786 #ifdef CONFIG_CIFS_STATS2
787 	int j;
788 #endif /* STATS2 */
789 	struct TCP_Server_Info *server;
790 	struct cifs_ses *ses;
791 	struct cifs_tcon *tcon;
792 
793 	seq_printf(m, "Resources in use\nCIFS Session: %d\n",
794 			sesInfoAllocCount.counter);
795 	seq_printf(m, "Share (unique mount targets): %d\n",
796 			tconInfoAllocCount.counter);
797 	seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n",
798 			buf_alloc_count.counter,
799 			cifs_min_rcv + tcpSesAllocCount.counter);
800 	seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
801 			small_buf_alloc_count.counter, cifs_min_small);
802 #ifdef CONFIG_CIFS_STATS2
803 	seq_printf(m, "Total Large %d Small %d Allocations\n",
804 				atomic_read(&total_buf_alloc_count),
805 				atomic_read(&total_small_buf_alloc_count));
806 #endif /* CONFIG_CIFS_STATS2 */
807 
808 	seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&mid_count));
809 	seq_printf(m,
810 		"\n%d session %d share reconnects\n",
811 		tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
812 
813 	seq_printf(m,
814 		"Total vfs operations: %d maximum at one time: %d\n",
815 		GlobalCurrentXid, GlobalMaxActiveXid);
816 
817 	i = 0;
818 	spin_lock(&cifs_tcp_ses_lock);
819 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
820 		seq_printf(m, "\nMax requests in flight: %d", server->max_in_flight);
821 #ifdef CONFIG_CIFS_STATS2
822 		seq_puts(m, "\nTotal time spent processing by command. Time ");
823 		seq_printf(m, "units are jiffies (%d per second)\n", HZ);
824 		seq_puts(m, "  SMB3 CMD\tNumber\tTotal Time\tFastest\tSlowest\n");
825 		seq_puts(m, "  --------\t------\t----------\t-------\t-------\n");
826 		for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
827 			seq_printf(m, "  %d\t\t%d\t%llu\t\t%u\t%u\n", j,
828 				atomic_read(&server->num_cmds[j]),
829 				server->time_per_cmd[j],
830 				server->fastest_cmd[j],
831 				server->slowest_cmd[j]);
832 		for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
833 			if (atomic_read(&server->smb2slowcmd[j])) {
834 				spin_lock(&server->srv_lock);
835 				seq_printf(m, "  %d slow responses from %s for command %d\n",
836 					atomic_read(&server->smb2slowcmd[j]),
837 					server->hostname, j);
838 				spin_unlock(&server->srv_lock);
839 			}
840 #endif /* STATS2 */
841 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
842 			if (cifs_ses_exiting(ses))
843 				continue;
844 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
845 				i++;
846 				seq_printf(m, "\n%d) %s", i, tcon->tree_name);
847 				if (tcon->need_reconnect)
848 					seq_puts(m, "\tDISCONNECTED ");
849 				seq_printf(m, "\nSMBs: %d since %ptTs UTC",
850 					   atomic_read(&tcon->num_smbs_sent),
851 					   &tcon->stats_from_time);
852 				if (server->ops->print_stats)
853 					server->ops->print_stats(m, tcon);
854 			}
855 		}
856 	}
857 	spin_unlock(&cifs_tcp_ses_lock);
858 
859 	seq_putc(m, '\n');
860 	return 0;
861 }
862 
863 static int cifs_stats_proc_open(struct inode *inode, struct file *file)
864 {
865 	return single_open(file, cifs_stats_proc_show, NULL);
866 }
867 
868 static const struct proc_ops cifs_stats_proc_ops = {
869 	.proc_open	= cifs_stats_proc_open,
870 	.proc_read	= seq_read,
871 	.proc_lseek	= seq_lseek,
872 	.proc_release	= single_release,
873 	.proc_write	= cifs_stats_proc_write,
874 };
875 
876 #ifdef CONFIG_CIFS_SMB_DIRECT
877 #define PROC_FILE_DEFINE(name) \
878 static ssize_t name##_write(struct file *file, const char __user *buffer, \
879 	size_t count, loff_t *ppos) \
880 { \
881 	int rc; \
882 	rc = kstrtoint_from_user(buffer, count, 10, &name); \
883 	if (rc) \
884 		return rc; \
885 	return count; \
886 } \
887 static int name##_proc_show(struct seq_file *m, void *v) \
888 { \
889 	seq_printf(m, "%d\n", name); \
890 	return 0; \
891 } \
892 static int name##_open(struct inode *inode, struct file *file) \
893 { \
894 	return single_open(file, name##_proc_show, NULL); \
895 } \
896 \
897 static const struct proc_ops cifs_##name##_proc_fops = { \
898 	.proc_open	= name##_open, \
899 	.proc_read	= seq_read, \
900 	.proc_lseek	= seq_lseek, \
901 	.proc_release	= single_release, \
902 	.proc_write	= name##_write, \
903 }
904 
905 PROC_FILE_DEFINE(rdma_readwrite_threshold);
906 PROC_FILE_DEFINE(smbd_max_frmr_depth);
907 PROC_FILE_DEFINE(smbd_keep_alive_interval);
908 PROC_FILE_DEFINE(smbd_max_receive_size);
909 PROC_FILE_DEFINE(smbd_max_fragmented_recv_size);
910 PROC_FILE_DEFINE(smbd_max_send_size);
911 PROC_FILE_DEFINE(smbd_send_credit_target);
912 PROC_FILE_DEFINE(smbd_receive_credit_max);
913 #endif
914 
915 static struct proc_dir_entry *proc_fs_cifs;
916 static const struct proc_ops cifsFYI_proc_ops;
917 static const struct proc_ops cifs_lookup_cache_proc_ops;
918 static const struct proc_ops traceSMB_proc_ops;
919 static const struct proc_ops cifs_security_flags_proc_ops;
920 static const struct proc_ops cifs_linux_ext_proc_ops;
921 static const struct proc_ops cifs_mount_params_proc_ops;
922 
923 void
924 cifs_proc_init(void)
925 {
926 	proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
927 	if (proc_fs_cifs == NULL)
928 		return;
929 
930 	proc_create_single("DebugData", 0, proc_fs_cifs,
931 			cifs_debug_data_proc_show);
932 
933 	proc_create_single("open_files", 0400, proc_fs_cifs,
934 			cifs_debug_files_proc_show);
935 
936 #ifdef CONFIG_CIFS_DEBUG
937 	proc_create("open_dirs", 0600, proc_fs_cifs, &cifs_debug_dirs_proc_ops);
938 #else /* CONFIG_CIFS_DEBUG */
939 	proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show);
940 #endif /* !CONFIG_CIFS_DEBUG */
941 	proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops);
942 	proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops);
943 	proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);
944 	proc_create("LinuxExtensionsEnabled", 0644, proc_fs_cifs,
945 		    &cifs_linux_ext_proc_ops);
946 	proc_create("SecurityFlags", 0644, proc_fs_cifs,
947 		    &cifs_security_flags_proc_ops);
948 	proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
949 		    &cifs_lookup_cache_proc_ops);
950 
951 	proc_create("mount_params", 0444, proc_fs_cifs, &cifs_mount_params_proc_ops);
952 
953 #ifdef CONFIG_CIFS_DFS_UPCALL
954 	proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_ops);
955 #endif
956 
957 #ifdef CONFIG_CIFS_SMB_DIRECT
958 	proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
959 		&cifs_rdma_readwrite_threshold_proc_fops);
960 	proc_create("smbd_max_frmr_depth", 0644, proc_fs_cifs,
961 		&cifs_smbd_max_frmr_depth_proc_fops);
962 	proc_create("smbd_keep_alive_interval", 0644, proc_fs_cifs,
963 		&cifs_smbd_keep_alive_interval_proc_fops);
964 	proc_create("smbd_max_receive_size", 0644, proc_fs_cifs,
965 		&cifs_smbd_max_receive_size_proc_fops);
966 	proc_create("smbd_max_fragmented_recv_size", 0644, proc_fs_cifs,
967 		&cifs_smbd_max_fragmented_recv_size_proc_fops);
968 	proc_create("smbd_max_send_size", 0644, proc_fs_cifs,
969 		&cifs_smbd_max_send_size_proc_fops);
970 	proc_create("smbd_send_credit_target", 0644, proc_fs_cifs,
971 		&cifs_smbd_send_credit_target_proc_fops);
972 	proc_create("smbd_receive_credit_max", 0644, proc_fs_cifs,
973 		&cifs_smbd_receive_credit_max_proc_fops);
974 #endif
975 }
976 
977 void
978 cifs_proc_clean(void)
979 {
980 	if (proc_fs_cifs == NULL)
981 		return;
982 
983 	remove_proc_entry("DebugData", proc_fs_cifs);
984 	remove_proc_entry("open_files", proc_fs_cifs);
985 	remove_proc_entry("open_dirs", proc_fs_cifs);
986 	remove_proc_entry("cifsFYI", proc_fs_cifs);
987 	remove_proc_entry("traceSMB", proc_fs_cifs);
988 	remove_proc_entry("Stats", proc_fs_cifs);
989 	remove_proc_entry("SecurityFlags", proc_fs_cifs);
990 	remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
991 	remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
992 	remove_proc_entry("mount_params", proc_fs_cifs);
993 
994 #ifdef CONFIG_CIFS_DFS_UPCALL
995 	remove_proc_entry("dfscache", proc_fs_cifs);
996 #endif
997 #ifdef CONFIG_CIFS_SMB_DIRECT
998 	remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
999 	remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
1000 	remove_proc_entry("smbd_keep_alive_interval", proc_fs_cifs);
1001 	remove_proc_entry("smbd_max_receive_size", proc_fs_cifs);
1002 	remove_proc_entry("smbd_max_fragmented_recv_size", proc_fs_cifs);
1003 	remove_proc_entry("smbd_max_send_size", proc_fs_cifs);
1004 	remove_proc_entry("smbd_send_credit_target", proc_fs_cifs);
1005 	remove_proc_entry("smbd_receive_credit_max", proc_fs_cifs);
1006 #endif
1007 	remove_proc_entry("fs/cifs", NULL);
1008 }
1009 
1010 static int cifsFYI_proc_show(struct seq_file *m, void *v)
1011 {
1012 	seq_printf(m, "%d\n", cifsFYI);
1013 	return 0;
1014 }
1015 
1016 static int cifsFYI_proc_open(struct inode *inode, struct file *file)
1017 {
1018 	return single_open(file, cifsFYI_proc_show, NULL);
1019 }
1020 
1021 static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
1022 		size_t count, loff_t *ppos)
1023 {
1024 	char c[2] = { '\0' };
1025 	bool bv;
1026 	int rc;
1027 
1028 	rc = get_user(c[0], buffer);
1029 	if (rc)
1030 		return rc;
1031 	if (kstrtobool(c, &bv) == 0)
1032 		cifsFYI = bv;
1033 	else if ((c[0] > '1') && (c[0] <= '9'))
1034 		cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
1035 	else
1036 		return -EINVAL;
1037 
1038 	return count;
1039 }
1040 
1041 static const struct proc_ops cifsFYI_proc_ops = {
1042 	.proc_open	= cifsFYI_proc_open,
1043 	.proc_read	= seq_read,
1044 	.proc_lseek	= seq_lseek,
1045 	.proc_release	= single_release,
1046 	.proc_write	= cifsFYI_proc_write,
1047 };
1048 
1049 static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
1050 {
1051 	seq_printf(m, "%d\n", linuxExtEnabled);
1052 	return 0;
1053 }
1054 
1055 static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
1056 {
1057 	return single_open(file, cifs_linux_ext_proc_show, NULL);
1058 }
1059 
1060 static ssize_t cifs_linux_ext_proc_write(struct file *file,
1061 		const char __user *buffer, size_t count, loff_t *ppos)
1062 {
1063 	int rc;
1064 
1065 	rc = kstrtobool_from_user(buffer, count, &linuxExtEnabled);
1066 	if (rc)
1067 		return rc;
1068 
1069 	return count;
1070 }
1071 
1072 static const struct proc_ops cifs_linux_ext_proc_ops = {
1073 	.proc_open	= cifs_linux_ext_proc_open,
1074 	.proc_read	= seq_read,
1075 	.proc_lseek	= seq_lseek,
1076 	.proc_release	= single_release,
1077 	.proc_write	= cifs_linux_ext_proc_write,
1078 };
1079 
1080 static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v)
1081 {
1082 	seq_printf(m, "%d\n", lookupCacheEnabled);
1083 	return 0;
1084 }
1085 
1086 static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
1087 {
1088 	return single_open(file, cifs_lookup_cache_proc_show, NULL);
1089 }
1090 
1091 static ssize_t cifs_lookup_cache_proc_write(struct file *file,
1092 		const char __user *buffer, size_t count, loff_t *ppos)
1093 {
1094 	int rc;
1095 
1096 	rc = kstrtobool_from_user(buffer, count, &lookupCacheEnabled);
1097 	if (rc)
1098 		return rc;
1099 
1100 	return count;
1101 }
1102 
1103 static const struct proc_ops cifs_lookup_cache_proc_ops = {
1104 	.proc_open	= cifs_lookup_cache_proc_open,
1105 	.proc_read	= seq_read,
1106 	.proc_lseek	= seq_lseek,
1107 	.proc_release	= single_release,
1108 	.proc_write	= cifs_lookup_cache_proc_write,
1109 };
1110 
1111 static int traceSMB_proc_show(struct seq_file *m, void *v)
1112 {
1113 	seq_printf(m, "%d\n", traceSMB);
1114 	return 0;
1115 }
1116 
1117 static int traceSMB_proc_open(struct inode *inode, struct file *file)
1118 {
1119 	return single_open(file, traceSMB_proc_show, NULL);
1120 }
1121 
1122 static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
1123 		size_t count, loff_t *ppos)
1124 {
1125 	int rc;
1126 
1127 	rc = kstrtobool_from_user(buffer, count, &traceSMB);
1128 	if (rc)
1129 		return rc;
1130 
1131 	return count;
1132 }
1133 
1134 static const struct proc_ops traceSMB_proc_ops = {
1135 	.proc_open	= traceSMB_proc_open,
1136 	.proc_read	= seq_read,
1137 	.proc_lseek	= seq_lseek,
1138 	.proc_release	= single_release,
1139 	.proc_write	= traceSMB_proc_write,
1140 };
1141 
1142 static int cifs_security_flags_proc_show(struct seq_file *m, void *v)
1143 {
1144 	seq_printf(m, "0x%x\n", global_secflags);
1145 	return 0;
1146 }
1147 
1148 static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
1149 {
1150 	return single_open(file, cifs_security_flags_proc_show, NULL);
1151 }
1152 
1153 /*
1154  * Ensure that if someone sets a MUST flag, that we disable all other MAY
1155  * flags except for the ones corresponding to the given MUST flag. If there are
1156  * multiple MUST flags, then try to prefer more secure ones.
1157  */
1158 static void
1159 cifs_security_flags_handle_must_flags(unsigned int *flags)
1160 {
1161 	unsigned int signflags = *flags & (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL);
1162 
1163 	if ((*flags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
1164 		*flags = CIFSSEC_MUST_KRB5;
1165 	else if ((*flags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
1166 		*flags = CIFSSEC_MUST_NTLMSSP;
1167 	else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
1168 		*flags = CIFSSEC_MUST_NTLMV2;
1169 
1170 	*flags |= signflags;
1171 }
1172 
1173 static ssize_t cifs_security_flags_proc_write(struct file *file,
1174 		const char __user *buffer, size_t count, loff_t *ppos)
1175 {
1176 	int rc;
1177 	unsigned int flags;
1178 	char flags_string[12];
1179 	bool bv;
1180 
1181 	if ((count < 1) || (count > 11))
1182 		return -EINVAL;
1183 
1184 	memset(flags_string, 0, sizeof(flags_string));
1185 
1186 	if (copy_from_user(flags_string, buffer, count))
1187 		return -EFAULT;
1188 
1189 	if (count < 3) {
1190 		/* single char or single char followed by null */
1191 		if (kstrtobool(flags_string, &bv) == 0) {
1192 			global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
1193 			return count;
1194 		} else if (!isdigit(flags_string[0])) {
1195 			cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
1196 					flags_string);
1197 			return -EINVAL;
1198 		}
1199 	}
1200 
1201 	/* else we have a number */
1202 	rc = kstrtouint(flags_string, 0, &flags);
1203 	if (rc) {
1204 		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
1205 				flags_string);
1206 		return rc;
1207 	}
1208 
1209 	cifs_dbg(FYI, "sec flags 0x%x\n", flags);
1210 
1211 	if (flags == 0)  {
1212 		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n", flags_string);
1213 		return -EINVAL;
1214 	}
1215 
1216 	if (flags & ~CIFSSEC_MASK) {
1217 		cifs_dbg(VFS, "Unsupported security flags: 0x%x\n",
1218 			 flags & ~CIFSSEC_MASK);
1219 		return -EINVAL;
1220 	}
1221 
1222 	cifs_security_flags_handle_must_flags(&flags);
1223 
1224 	/* flags look ok - update the global security flags for cifs module */
1225 	global_secflags = flags;
1226 	if (global_secflags & CIFSSEC_MUST_SIGN) {
1227 		/* requiring signing implies signing is allowed */
1228 		global_secflags |= CIFSSEC_MAY_SIGN;
1229 		cifs_dbg(FYI, "packet signing now required\n");
1230 	} else if ((global_secflags & CIFSSEC_MAY_SIGN) == 0) {
1231 		cifs_dbg(FYI, "packet signing disabled\n");
1232 	}
1233 	/* BB should we turn on MAY flags for other MUST options? */
1234 	return count;
1235 }
1236 
1237 static const struct proc_ops cifs_security_flags_proc_ops = {
1238 	.proc_open	= cifs_security_flags_proc_open,
1239 	.proc_read	= seq_read,
1240 	.proc_lseek	= seq_lseek,
1241 	.proc_release	= single_release,
1242 	.proc_write	= cifs_security_flags_proc_write,
1243 };
1244 
1245 /* To make it easier to debug, can help to show mount params */
1246 static int cifs_mount_params_proc_show(struct seq_file *m, void *v)
1247 {
1248 	const struct fs_parameter_spec *p;
1249 	const char *type;
1250 
1251 	for (p = smb3_fs_parameters; p->name; p++) {
1252 		/* cannot use switch with pointers... */
1253 		if (!p->type) {
1254 			if (p->flags == fs_param_neg_with_no)
1255 				type = "noflag";
1256 			else
1257 				type = "flag";
1258 		} else if (p->type == fs_param_is_bool)
1259 			type = "bool";
1260 		else if (p->type == fs_param_is_u32)
1261 			type = "u32";
1262 		else if (p->type == fs_param_is_u64)
1263 			type = "u64";
1264 		else if (p->type == fs_param_is_string)
1265 			type = "string";
1266 		else
1267 			type = "unknown";
1268 
1269 		seq_printf(m, "%s:%s\n", p->name, type);
1270 	}
1271 
1272 	return 0;
1273 }
1274 
1275 static int cifs_mount_params_proc_open(struct inode *inode, struct file *file)
1276 {
1277 	return single_open(file, cifs_mount_params_proc_show, NULL);
1278 }
1279 
1280 static const struct proc_ops cifs_mount_params_proc_ops = {
1281 	.proc_open	= cifs_mount_params_proc_open,
1282 	.proc_read	= seq_read,
1283 	.proc_lseek	= seq_lseek,
1284 	.proc_release	= single_release,
1285 	/* No need for write for now */
1286 	/* .proc_write	= cifs_mount_params_proc_write, */
1287 };
1288 
1289 #else
1290 void cifs_proc_init(void)
1291 {
1292 }
1293 
1294 void cifs_proc_clean(void)
1295 {
1296 }
1297 #endif /* PROC_FS */
1298