xref: /linux/fs/smb/client/cifs_debug.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
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 	seq_puts(m, "# Format:\n");
310 	seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n");
311 
312 	spin_lock(&cifs_tcp_ses_lock);
313 	list_for_each(stmp, &cifs_tcp_ses_list) {
314 		server = list_entry(stmp, struct TCP_Server_Info,
315 				    tcp_ses_list);
316 		list_for_each(tmp, &server->smb_ses_list) {
317 			ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
318 			list_for_each(tmp1, &ses->tcon_list) {
319 				tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
320 				cfids = tcon->cfids;
321 				if (!cfids)
322 					continue;
323 				spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
324 				seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
325 						cfids->num_entries,
326 						(unsigned long)atomic_long_read(&cfids->total_dirents_entries),
327 						(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
328 				list_for_each_entry(cfid, &cfids->entries, entry) {
329 					seq_printf(m, "0x%x 0x%llx 0x%llx ",
330 						tcon->tid,
331 						ses->Suid,
332 						cfid->fid.persistent_fid);
333 					if (cfid->has_lease)
334 						seq_printf(m, "%pUl ", cfid->fid.lease_key);
335 					else
336 						seq_puts(m, "- ");
337 					seq_printf(m, "%s", cfid->path);
338 					if (cfid->file_all_info_is_valid)
339 						seq_printf(m, "\tvalid file info");
340 					if (cfid->dirents.is_valid)
341 						seq_printf(m, ", valid dirents");
342 					if (!list_empty(&cfid->dirents.entries))
343 						seq_printf(m, ", dirents: %lu entries, %lu bytes",
344 						cfid->dirents.entries_count, cfid->dirents.bytes_used);
345 					seq_printf(m, "\n");
346 				}
347 				spin_unlock(&cfids->cfid_list_lock);
348 			}
349 		}
350 	}
351 	spin_unlock(&cifs_tcp_ses_lock);
352 	seq_putc(m, '\n');
353 	return 0;
354 }
355 
356 static __always_inline const char *compression_alg_str(__le16 alg)
357 {
358 	switch (alg) {
359 	case SMB3_COMPRESS_NONE:
360 		return "NONE";
361 	case SMB3_COMPRESS_LZNT1:
362 		return "LZNT1";
363 	case SMB3_COMPRESS_LZ77:
364 		return "LZ77";
365 	case SMB3_COMPRESS_LZ77_HUFF:
366 		return "LZ77-Huffman";
367 	case SMB3_COMPRESS_PATTERN:
368 		return "Pattern_V1";
369 	default:
370 		return "invalid";
371 	}
372 }
373 
374 static __always_inline const char *cipher_alg_str(__le16 cipher)
375 {
376 	switch (cipher) {
377 	case SMB2_ENCRYPTION_AES128_CCM:
378 		return "AES128-CCM";
379 	case SMB2_ENCRYPTION_AES128_GCM:
380 		return "AES128-GCM";
381 	case SMB2_ENCRYPTION_AES256_CCM:
382 		return "AES256-CCM";
383 	case SMB2_ENCRYPTION_AES256_GCM:
384 		return "AES256-GCM";
385 	default:
386 		return "UNKNOWN";
387 	}
388 }
389 
390 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
391 {
392 	struct mid_q_entry *mid_entry;
393 	struct TCP_Server_Info *server;
394 	struct TCP_Server_Info *chan_server;
395 	struct cifs_ses *ses;
396 	struct cifs_tcon *tcon;
397 	struct cifs_server_iface *iface;
398 	size_t iface_weight = 0, iface_min_speed = 0;
399 	struct cifs_server_iface *last_iface = NULL;
400 	int c, i, j;
401 
402 	seq_puts(m,
403 		    "Display Internal CIFS Data Structures for Debugging\n"
404 		    "---------------------------------------------------\n");
405 	seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
406 	seq_printf(m, "Features:");
407 #ifdef CONFIG_CIFS_DFS_UPCALL
408 	seq_printf(m, " DFS");
409 #endif
410 #ifdef CONFIG_CIFS_FSCACHE
411 	seq_printf(m, ",FSCACHE");
412 #endif
413 #ifdef CONFIG_CIFS_SMB_DIRECT
414 	seq_printf(m, ",SMB_DIRECT");
415 #endif
416 #ifdef CONFIG_CIFS_STATS2
417 	seq_printf(m, ",STATS2");
418 #else
419 	seq_printf(m, ",STATS");
420 #endif
421 #ifdef CONFIG_CIFS_DEBUG2
422 	seq_printf(m, ",DEBUG2");
423 #elif defined(CONFIG_CIFS_DEBUG)
424 	seq_printf(m, ",DEBUG");
425 #endif
426 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
427 	seq_printf(m, ",ALLOW_INSECURE_LEGACY");
428 #endif
429 #ifdef CONFIG_CIFS_POSIX
430 	seq_printf(m, ",CIFS_POSIX");
431 #endif
432 #ifdef CONFIG_CIFS_UPCALL
433 	seq_printf(m, ",UPCALL(SPNEGO)");
434 #endif
435 #ifdef CONFIG_CIFS_XATTR
436 	seq_printf(m, ",XATTR");
437 #endif
438 	seq_printf(m, ",ACL");
439 #ifdef CONFIG_CIFS_SWN_UPCALL
440 	seq_puts(m, ",WITNESS");
441 #endif
442 #ifdef CONFIG_CIFS_COMPRESSION
443 	seq_puts(m, ",COMPRESSION");
444 #endif
445 	seq_putc(m, '\n');
446 	seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
447 	seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
448 
449 	seq_printf(m, "\nServers: ");
450 
451 	c = 0;
452 	spin_lock(&cifs_tcp_ses_lock);
453 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
454 		/* channel info will be printed as a part of sessions below */
455 		if (SERVER_IS_CHAN(server))
456 			continue;
457 
458 		c++;
459 		seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
460 			c, server->conn_id);
461 
462 		spin_lock(&server->srv_lock);
463 		if (server->hostname)
464 			seq_printf(m, "Hostname: %s ", server->hostname);
465 		seq_printf(m, "\nClientGUID: %pUL", server->client_guid);
466 		spin_unlock(&server->srv_lock);
467 #ifdef CONFIG_CIFS_SMB_DIRECT
468 		smbd_debug_proc_show(server, m);
469 #endif
470 		seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
471 			server->credits,
472 			server->echo_credits,
473 			server->oplock_credits,
474 			server->dialect);
475 		if (server->sign)
476 			seq_printf(m, " signed");
477 		if (server->posix_ext_supported)
478 			seq_printf(m, " posix");
479 		if (server->nosharesock)
480 			seq_printf(m, " nosharesock");
481 
482 		seq_printf(m, "\nServer capabilities: 0x%x", server->capabilities);
483 
484 		if (server->rdma)
485 			seq_printf(m, "\nRDMA ");
486 		seq_printf(m, "\nTCP status: %d Instance: %d"
487 				"\nLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
488 				server->tcpStatus,
489 				server->reconnect_instance,
490 				server->srv_count,
491 				server->sec_mode, in_flight(server));
492 #ifdef CONFIG_NET_NS
493 		if (server->net)
494 			seq_printf(m, " Net namespace: %u ", server->net->ns.inum);
495 #endif /* NET_NS */
496 
497 		seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d",
498 				atomic_read(&server->in_send),
499 				atomic_read(&server->num_waiters));
500 
501 		if (server->leaf_fullpath) {
502 			seq_printf(m, "\nDFS leaf full path: %s",
503 				   server->leaf_fullpath);
504 		}
505 
506 		seq_puts(m, "\nCompression: ");
507 		if (!IS_ENABLED(CONFIG_CIFS_COMPRESSION))
508 			seq_puts(m, "no built-in support");
509 		else if (!server->compression.requested)
510 			seq_puts(m, "disabled on mount");
511 		else if (server->compression.enabled)
512 			seq_printf(m, "enabled (%s)", compression_alg_str(server->compression.alg));
513 		else
514 			seq_puts(m, "disabled (not supported by this server)");
515 
516 		/* Show negotiated encryption cipher, even if not required */
517 		seq_puts(m, "\nEncryption: ");
518 		if (server->cipher_type)
519 			seq_printf(m, "Negotiated cipher (%s)", cipher_alg_str(server->cipher_type));
520 
521 		seq_printf(m, "\n\n\tSessions: ");
522 		i = 0;
523 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
524 			spin_lock(&ses->ses_lock);
525 			if (ses->ses_status == SES_EXITING) {
526 				spin_unlock(&ses->ses_lock);
527 				continue;
528 			}
529 			i++;
530 			if ((ses->serverDomain == NULL) ||
531 				(ses->serverOS == NULL) ||
532 				(ses->serverNOS == NULL)) {
533 				seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
534 					i, ses->ip_addr, ses->ses_count,
535 					ses->capabilities, ses->ses_status);
536 				if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
537 					seq_printf(m, "Guest ");
538 				else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
539 					seq_printf(m, "Anonymous ");
540 			} else {
541 				seq_printf(m,
542 				    "\n\t%d) Name: %s  Domain: %s Uses: %d OS: %s "
543 				    "\n\tNOS: %s\tCapability: 0x%x"
544 					"\n\tSMB session status: %d ",
545 				i, ses->ip_addr, ses->serverDomain,
546 				ses->ses_count, ses->serverOS, ses->serverNOS,
547 				ses->capabilities, ses->ses_status);
548 			}
549 			if (ses->expired_pwd)
550 				seq_puts(m, "password no longer valid ");
551 			spin_unlock(&ses->ses_lock);
552 
553 			seq_printf(m, "\n\tSecurity type: %s ",
554 				get_security_type_str(server->ops->select_sectype(server, ses->sectype)));
555 
556 			/* dump session id helpful for use with network trace */
557 			seq_printf(m, " SessionId: 0x%llx", ses->Suid);
558 			if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
559 				seq_puts(m, " encrypted");
560 			if (ses->sign)
561 				seq_puts(m, " signed");
562 
563 			seq_printf(m, "\n\tUser: %d Cred User: %d",
564 				   from_kuid(&init_user_ns, ses->linux_uid),
565 				   from_kuid(&init_user_ns, ses->cred_uid));
566 
567 			if (ses->dfs_root_ses) {
568 				seq_printf(m, "\n\tDFS root session id: 0x%llx",
569 					   ses->dfs_root_ses->Suid);
570 			}
571 
572 			spin_lock(&ses->chan_lock);
573 			if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
574 				seq_puts(m, "\tPrimary channel: DISCONNECTED ");
575 			if (CIFS_CHAN_IN_RECONNECT(ses, 0))
576 				seq_puts(m, "\t[RECONNECTING] ");
577 
578 			if (ses->chan_count > 1) {
579 				seq_printf(m, "\n\n\tExtra Channels: %zu ",
580 					   ses->chan_count-1);
581 				for (j = 1; j < ses->chan_count; j++) {
582 					cifs_dump_channel(m, j, &ses->chans[j]);
583 					if (CIFS_CHAN_NEEDS_RECONNECT(ses, j))
584 						seq_puts(m, "\tDISCONNECTED ");
585 					if (CIFS_CHAN_IN_RECONNECT(ses, j))
586 						seq_puts(m, "\t[RECONNECTING] ");
587 				}
588 			}
589 			spin_unlock(&ses->chan_lock);
590 
591 			seq_puts(m, "\n\n\tShares: ");
592 			j = 0;
593 
594 			seq_printf(m, "\n\t%d) IPC: ", j);
595 			if (ses->tcon_ipc)
596 				cifs_debug_tcon(m, ses->tcon_ipc);
597 			else
598 				seq_puts(m, "none\n");
599 
600 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
601 				++j;
602 				seq_printf(m, "\n\t%d) ", j);
603 				cifs_debug_tcon(m, tcon);
604 			}
605 
606 			spin_lock(&ses->iface_lock);
607 			if (ses->iface_count)
608 				seq_printf(m, "\n\n\tServer interfaces: %zu"
609 					   "\tLast updated: %lu seconds ago",
610 					   ses->iface_count,
611 					   (jiffies - ses->iface_last_update) / HZ);
612 
613 			last_iface = list_last_entry(&ses->iface_list,
614 						     struct cifs_server_iface,
615 						     iface_head);
616 			iface_min_speed = last_iface->speed;
617 
618 			j = 0;
619 			list_for_each_entry(iface, &ses->iface_list,
620 						 iface_head) {
621 				seq_printf(m, "\n\t%d)", ++j);
622 				cifs_dump_iface(m, iface);
623 
624 				iface_weight = iface->speed / iface_min_speed;
625 				seq_printf(m, "\t\tWeight (cur,total): (%zu,%zu)"
626 					   "\n\t\tAllocated channels: %u\n",
627 					   iface->weight_fulfilled,
628 					   iface_weight,
629 					   iface->num_channels);
630 
631 				if (is_ses_using_iface(ses, iface))
632 					seq_puts(m, "\t\t[CONNECTED]\n");
633 			}
634 			spin_unlock(&ses->iface_lock);
635 
636 			seq_puts(m, "\n\n\tMIDs: ");
637 			spin_lock(&ses->chan_lock);
638 			for (j = 0; j < ses->chan_count; j++) {
639 				chan_server = ses->chans[j].server;
640 				if (!chan_server)
641 					continue;
642 
643 				if (list_empty(&chan_server->pending_mid_q))
644 					continue;
645 
646 				seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
647 					   chan_server->conn_id);
648 				spin_lock(&chan_server->mid_queue_lock);
649 				list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
650 					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
651 						   mid_entry->mid_state,
652 						   le16_to_cpu(mid_entry->command),
653 						   mid_entry->pid,
654 						   mid_entry->callback_data,
655 						   mid_entry->mid);
656 				}
657 				spin_unlock(&chan_server->mid_queue_lock);
658 			}
659 			spin_unlock(&ses->chan_lock);
660 			seq_puts(m, "\n--\n");
661 		}
662 		if (i == 0)
663 			seq_printf(m, "\n\t\t[NONE]");
664 	}
665 	if (c == 0)
666 		seq_printf(m, "\n\t[NONE]");
667 
668 	spin_unlock(&cifs_tcp_ses_lock);
669 	seq_putc(m, '\n');
670 	cifs_swn_dump(m);
671 
672 	/* BB add code to dump additional info such as TCP session info now */
673 	return 0;
674 }
675 
676 static ssize_t cifs_stats_proc_write(struct file *file,
677 		const char __user *buffer, size_t count, loff_t *ppos)
678 {
679 	bool bv;
680 	int rc;
681 	struct TCP_Server_Info *server;
682 	struct cifs_ses *ses;
683 	struct cifs_tcon *tcon;
684 
685 	rc = kstrtobool_from_user(buffer, count, &bv);
686 	if (rc == 0) {
687 #ifdef CONFIG_CIFS_STATS2
688 		int i;
689 
690 		atomic_set(&total_buf_alloc_count, 0);
691 		atomic_set(&total_small_buf_alloc_count, 0);
692 #endif /* CONFIG_CIFS_STATS2 */
693 		atomic_set(&tcpSesReconnectCount, 0);
694 		atomic_set(&tconInfoReconnectCount, 0);
695 
696 		spin_lock(&GlobalMid_Lock);
697 		GlobalMaxActiveXid = 0;
698 		GlobalCurrentXid = 0;
699 		spin_unlock(&GlobalMid_Lock);
700 		spin_lock(&cifs_tcp_ses_lock);
701 		list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
702 			server->max_in_flight = 0;
703 #ifdef CONFIG_CIFS_STATS2
704 			for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
705 				atomic_set(&server->num_cmds[i], 0);
706 				atomic_set(&server->smb2slowcmd[i], 0);
707 				server->time_per_cmd[i] = 0;
708 				server->slowest_cmd[i] = 0;
709 				server->fastest_cmd[0] = 0;
710 			}
711 #endif /* CONFIG_CIFS_STATS2 */
712 			list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
713 				if (cifs_ses_exiting(ses))
714 					continue;
715 				list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
716 					atomic_set(&tcon->num_smbs_sent, 0);
717 					spin_lock(&tcon->stat_lock);
718 					tcon->bytes_read = 0;
719 					tcon->bytes_written = 0;
720 					tcon->stats_from_time = ktime_get_real_seconds();
721 					spin_unlock(&tcon->stat_lock);
722 					if (server->ops->clear_stats)
723 						server->ops->clear_stats(tcon);
724 				}
725 			}
726 		}
727 		spin_unlock(&cifs_tcp_ses_lock);
728 	} else {
729 		return rc;
730 	}
731 
732 	return count;
733 }
734 
735 static int cifs_stats_proc_show(struct seq_file *m, void *v)
736 {
737 	int i;
738 #ifdef CONFIG_CIFS_STATS2
739 	int j;
740 #endif /* STATS2 */
741 	struct TCP_Server_Info *server;
742 	struct cifs_ses *ses;
743 	struct cifs_tcon *tcon;
744 
745 	seq_printf(m, "Resources in use\nCIFS Session: %d\n",
746 			sesInfoAllocCount.counter);
747 	seq_printf(m, "Share (unique mount targets): %d\n",
748 			tconInfoAllocCount.counter);
749 	seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n",
750 			buf_alloc_count.counter,
751 			cifs_min_rcv + tcpSesAllocCount.counter);
752 	seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
753 			small_buf_alloc_count.counter, cifs_min_small);
754 #ifdef CONFIG_CIFS_STATS2
755 	seq_printf(m, "Total Large %d Small %d Allocations\n",
756 				atomic_read(&total_buf_alloc_count),
757 				atomic_read(&total_small_buf_alloc_count));
758 #endif /* CONFIG_CIFS_STATS2 */
759 
760 	seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&mid_count));
761 	seq_printf(m,
762 		"\n%d session %d share reconnects\n",
763 		tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
764 
765 	seq_printf(m,
766 		"Total vfs operations: %d maximum at one time: %d\n",
767 		GlobalCurrentXid, GlobalMaxActiveXid);
768 
769 	i = 0;
770 	spin_lock(&cifs_tcp_ses_lock);
771 	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
772 		seq_printf(m, "\nMax requests in flight: %d", server->max_in_flight);
773 #ifdef CONFIG_CIFS_STATS2
774 		seq_puts(m, "\nTotal time spent processing by command. Time ");
775 		seq_printf(m, "units are jiffies (%d per second)\n", HZ);
776 		seq_puts(m, "  SMB3 CMD\tNumber\tTotal Time\tFastest\tSlowest\n");
777 		seq_puts(m, "  --------\t------\t----------\t-------\t-------\n");
778 		for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
779 			seq_printf(m, "  %d\t\t%d\t%llu\t\t%u\t%u\n", j,
780 				atomic_read(&server->num_cmds[j]),
781 				server->time_per_cmd[j],
782 				server->fastest_cmd[j],
783 				server->slowest_cmd[j]);
784 		for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
785 			if (atomic_read(&server->smb2slowcmd[j])) {
786 				spin_lock(&server->srv_lock);
787 				seq_printf(m, "  %d slow responses from %s for command %d\n",
788 					atomic_read(&server->smb2slowcmd[j]),
789 					server->hostname, j);
790 				spin_unlock(&server->srv_lock);
791 			}
792 #endif /* STATS2 */
793 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
794 			if (cifs_ses_exiting(ses))
795 				continue;
796 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
797 				i++;
798 				seq_printf(m, "\n%d) %s", i, tcon->tree_name);
799 				if (tcon->need_reconnect)
800 					seq_puts(m, "\tDISCONNECTED ");
801 				seq_printf(m, "\nSMBs: %d since %ptTs UTC",
802 					   atomic_read(&tcon->num_smbs_sent),
803 					   &tcon->stats_from_time);
804 				if (server->ops->print_stats)
805 					server->ops->print_stats(m, tcon);
806 			}
807 		}
808 	}
809 	spin_unlock(&cifs_tcp_ses_lock);
810 
811 	seq_putc(m, '\n');
812 	return 0;
813 }
814 
815 static int cifs_stats_proc_open(struct inode *inode, struct file *file)
816 {
817 	return single_open(file, cifs_stats_proc_show, NULL);
818 }
819 
820 static const struct proc_ops cifs_stats_proc_ops = {
821 	.proc_open	= cifs_stats_proc_open,
822 	.proc_read	= seq_read,
823 	.proc_lseek	= seq_lseek,
824 	.proc_release	= single_release,
825 	.proc_write	= cifs_stats_proc_write,
826 };
827 
828 #ifdef CONFIG_CIFS_SMB_DIRECT
829 #define PROC_FILE_DEFINE(name) \
830 static ssize_t name##_write(struct file *file, const char __user *buffer, \
831 	size_t count, loff_t *ppos) \
832 { \
833 	int rc; \
834 	rc = kstrtoint_from_user(buffer, count, 10, &name); \
835 	if (rc) \
836 		return rc; \
837 	return count; \
838 } \
839 static int name##_proc_show(struct seq_file *m, void *v) \
840 { \
841 	seq_printf(m, "%d\n", name); \
842 	return 0; \
843 } \
844 static int name##_open(struct inode *inode, struct file *file) \
845 { \
846 	return single_open(file, name##_proc_show, NULL); \
847 } \
848 \
849 static const struct proc_ops cifs_##name##_proc_fops = { \
850 	.proc_open	= name##_open, \
851 	.proc_read	= seq_read, \
852 	.proc_lseek	= seq_lseek, \
853 	.proc_release	= single_release, \
854 	.proc_write	= name##_write, \
855 }
856 
857 PROC_FILE_DEFINE(rdma_readwrite_threshold);
858 PROC_FILE_DEFINE(smbd_max_frmr_depth);
859 PROC_FILE_DEFINE(smbd_keep_alive_interval);
860 PROC_FILE_DEFINE(smbd_max_receive_size);
861 PROC_FILE_DEFINE(smbd_max_fragmented_recv_size);
862 PROC_FILE_DEFINE(smbd_max_send_size);
863 PROC_FILE_DEFINE(smbd_send_credit_target);
864 PROC_FILE_DEFINE(smbd_receive_credit_max);
865 #endif
866 
867 static struct proc_dir_entry *proc_fs_cifs;
868 static const struct proc_ops cifsFYI_proc_ops;
869 static const struct proc_ops cifs_lookup_cache_proc_ops;
870 static const struct proc_ops traceSMB_proc_ops;
871 static const struct proc_ops cifs_security_flags_proc_ops;
872 static const struct proc_ops cifs_linux_ext_proc_ops;
873 static const struct proc_ops cifs_mount_params_proc_ops;
874 
875 void
876 cifs_proc_init(void)
877 {
878 	proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
879 	if (proc_fs_cifs == NULL)
880 		return;
881 
882 	proc_create_single("DebugData", 0, proc_fs_cifs,
883 			cifs_debug_data_proc_show);
884 
885 	proc_create_single("open_files", 0400, proc_fs_cifs,
886 			cifs_debug_files_proc_show);
887 
888 	proc_create_single("open_dirs", 0400, proc_fs_cifs,
889 			cifs_debug_dirs_proc_show);
890 
891 	proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops);
892 	proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops);
893 	proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);
894 	proc_create("LinuxExtensionsEnabled", 0644, proc_fs_cifs,
895 		    &cifs_linux_ext_proc_ops);
896 	proc_create("SecurityFlags", 0644, proc_fs_cifs,
897 		    &cifs_security_flags_proc_ops);
898 	proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
899 		    &cifs_lookup_cache_proc_ops);
900 
901 	proc_create("mount_params", 0444, proc_fs_cifs, &cifs_mount_params_proc_ops);
902 
903 #ifdef CONFIG_CIFS_DFS_UPCALL
904 	proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_ops);
905 #endif
906 
907 #ifdef CONFIG_CIFS_SMB_DIRECT
908 	proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
909 		&cifs_rdma_readwrite_threshold_proc_fops);
910 	proc_create("smbd_max_frmr_depth", 0644, proc_fs_cifs,
911 		&cifs_smbd_max_frmr_depth_proc_fops);
912 	proc_create("smbd_keep_alive_interval", 0644, proc_fs_cifs,
913 		&cifs_smbd_keep_alive_interval_proc_fops);
914 	proc_create("smbd_max_receive_size", 0644, proc_fs_cifs,
915 		&cifs_smbd_max_receive_size_proc_fops);
916 	proc_create("smbd_max_fragmented_recv_size", 0644, proc_fs_cifs,
917 		&cifs_smbd_max_fragmented_recv_size_proc_fops);
918 	proc_create("smbd_max_send_size", 0644, proc_fs_cifs,
919 		&cifs_smbd_max_send_size_proc_fops);
920 	proc_create("smbd_send_credit_target", 0644, proc_fs_cifs,
921 		&cifs_smbd_send_credit_target_proc_fops);
922 	proc_create("smbd_receive_credit_max", 0644, proc_fs_cifs,
923 		&cifs_smbd_receive_credit_max_proc_fops);
924 #endif
925 }
926 
927 void
928 cifs_proc_clean(void)
929 {
930 	if (proc_fs_cifs == NULL)
931 		return;
932 
933 	remove_proc_entry("DebugData", proc_fs_cifs);
934 	remove_proc_entry("open_files", proc_fs_cifs);
935 	remove_proc_entry("open_dirs", proc_fs_cifs);
936 	remove_proc_entry("cifsFYI", proc_fs_cifs);
937 	remove_proc_entry("traceSMB", proc_fs_cifs);
938 	remove_proc_entry("Stats", proc_fs_cifs);
939 	remove_proc_entry("SecurityFlags", proc_fs_cifs);
940 	remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
941 	remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
942 	remove_proc_entry("mount_params", proc_fs_cifs);
943 
944 #ifdef CONFIG_CIFS_DFS_UPCALL
945 	remove_proc_entry("dfscache", proc_fs_cifs);
946 #endif
947 #ifdef CONFIG_CIFS_SMB_DIRECT
948 	remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
949 	remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
950 	remove_proc_entry("smbd_keep_alive_interval", proc_fs_cifs);
951 	remove_proc_entry("smbd_max_receive_size", proc_fs_cifs);
952 	remove_proc_entry("smbd_max_fragmented_recv_size", proc_fs_cifs);
953 	remove_proc_entry("smbd_max_send_size", proc_fs_cifs);
954 	remove_proc_entry("smbd_send_credit_target", proc_fs_cifs);
955 	remove_proc_entry("smbd_receive_credit_max", proc_fs_cifs);
956 #endif
957 	remove_proc_entry("fs/cifs", NULL);
958 }
959 
960 static int cifsFYI_proc_show(struct seq_file *m, void *v)
961 {
962 	seq_printf(m, "%d\n", cifsFYI);
963 	return 0;
964 }
965 
966 static int cifsFYI_proc_open(struct inode *inode, struct file *file)
967 {
968 	return single_open(file, cifsFYI_proc_show, NULL);
969 }
970 
971 static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
972 		size_t count, loff_t *ppos)
973 {
974 	char c[2] = { '\0' };
975 	bool bv;
976 	int rc;
977 
978 	rc = get_user(c[0], buffer);
979 	if (rc)
980 		return rc;
981 	if (kstrtobool(c, &bv) == 0)
982 		cifsFYI = bv;
983 	else if ((c[0] > '1') && (c[0] <= '9'))
984 		cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
985 	else
986 		return -EINVAL;
987 
988 	return count;
989 }
990 
991 static const struct proc_ops cifsFYI_proc_ops = {
992 	.proc_open	= cifsFYI_proc_open,
993 	.proc_read	= seq_read,
994 	.proc_lseek	= seq_lseek,
995 	.proc_release	= single_release,
996 	.proc_write	= cifsFYI_proc_write,
997 };
998 
999 static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
1000 {
1001 	seq_printf(m, "%d\n", linuxExtEnabled);
1002 	return 0;
1003 }
1004 
1005 static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
1006 {
1007 	return single_open(file, cifs_linux_ext_proc_show, NULL);
1008 }
1009 
1010 static ssize_t cifs_linux_ext_proc_write(struct file *file,
1011 		const char __user *buffer, size_t count, loff_t *ppos)
1012 {
1013 	int rc;
1014 
1015 	rc = kstrtobool_from_user(buffer, count, &linuxExtEnabled);
1016 	if (rc)
1017 		return rc;
1018 
1019 	return count;
1020 }
1021 
1022 static const struct proc_ops cifs_linux_ext_proc_ops = {
1023 	.proc_open	= cifs_linux_ext_proc_open,
1024 	.proc_read	= seq_read,
1025 	.proc_lseek	= seq_lseek,
1026 	.proc_release	= single_release,
1027 	.proc_write	= cifs_linux_ext_proc_write,
1028 };
1029 
1030 static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v)
1031 {
1032 	seq_printf(m, "%d\n", lookupCacheEnabled);
1033 	return 0;
1034 }
1035 
1036 static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
1037 {
1038 	return single_open(file, cifs_lookup_cache_proc_show, NULL);
1039 }
1040 
1041 static ssize_t cifs_lookup_cache_proc_write(struct file *file,
1042 		const char __user *buffer, size_t count, loff_t *ppos)
1043 {
1044 	int rc;
1045 
1046 	rc = kstrtobool_from_user(buffer, count, &lookupCacheEnabled);
1047 	if (rc)
1048 		return rc;
1049 
1050 	return count;
1051 }
1052 
1053 static const struct proc_ops cifs_lookup_cache_proc_ops = {
1054 	.proc_open	= cifs_lookup_cache_proc_open,
1055 	.proc_read	= seq_read,
1056 	.proc_lseek	= seq_lseek,
1057 	.proc_release	= single_release,
1058 	.proc_write	= cifs_lookup_cache_proc_write,
1059 };
1060 
1061 static int traceSMB_proc_show(struct seq_file *m, void *v)
1062 {
1063 	seq_printf(m, "%d\n", traceSMB);
1064 	return 0;
1065 }
1066 
1067 static int traceSMB_proc_open(struct inode *inode, struct file *file)
1068 {
1069 	return single_open(file, traceSMB_proc_show, NULL);
1070 }
1071 
1072 static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
1073 		size_t count, loff_t *ppos)
1074 {
1075 	int rc;
1076 
1077 	rc = kstrtobool_from_user(buffer, count, &traceSMB);
1078 	if (rc)
1079 		return rc;
1080 
1081 	return count;
1082 }
1083 
1084 static const struct proc_ops traceSMB_proc_ops = {
1085 	.proc_open	= traceSMB_proc_open,
1086 	.proc_read	= seq_read,
1087 	.proc_lseek	= seq_lseek,
1088 	.proc_release	= single_release,
1089 	.proc_write	= traceSMB_proc_write,
1090 };
1091 
1092 static int cifs_security_flags_proc_show(struct seq_file *m, void *v)
1093 {
1094 	seq_printf(m, "0x%x\n", global_secflags);
1095 	return 0;
1096 }
1097 
1098 static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
1099 {
1100 	return single_open(file, cifs_security_flags_proc_show, NULL);
1101 }
1102 
1103 /*
1104  * Ensure that if someone sets a MUST flag, that we disable all other MAY
1105  * flags except for the ones corresponding to the given MUST flag. If there are
1106  * multiple MUST flags, then try to prefer more secure ones.
1107  */
1108 static void
1109 cifs_security_flags_handle_must_flags(unsigned int *flags)
1110 {
1111 	unsigned int signflags = *flags & (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL);
1112 
1113 	if ((*flags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
1114 		*flags = CIFSSEC_MUST_KRB5;
1115 	else if ((*flags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
1116 		*flags = CIFSSEC_MUST_NTLMSSP;
1117 	else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
1118 		*flags = CIFSSEC_MUST_NTLMV2;
1119 
1120 	*flags |= signflags;
1121 }
1122 
1123 static ssize_t cifs_security_flags_proc_write(struct file *file,
1124 		const char __user *buffer, size_t count, loff_t *ppos)
1125 {
1126 	int rc;
1127 	unsigned int flags;
1128 	char flags_string[12];
1129 	bool bv;
1130 
1131 	if ((count < 1) || (count > 11))
1132 		return -EINVAL;
1133 
1134 	memset(flags_string, 0, sizeof(flags_string));
1135 
1136 	if (copy_from_user(flags_string, buffer, count))
1137 		return -EFAULT;
1138 
1139 	if (count < 3) {
1140 		/* single char or single char followed by null */
1141 		if (kstrtobool(flags_string, &bv) == 0) {
1142 			global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
1143 			return count;
1144 		} else if (!isdigit(flags_string[0])) {
1145 			cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
1146 					flags_string);
1147 			return -EINVAL;
1148 		}
1149 	}
1150 
1151 	/* else we have a number */
1152 	rc = kstrtouint(flags_string, 0, &flags);
1153 	if (rc) {
1154 		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
1155 				flags_string);
1156 		return rc;
1157 	}
1158 
1159 	cifs_dbg(FYI, "sec flags 0x%x\n", flags);
1160 
1161 	if (flags == 0)  {
1162 		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n", flags_string);
1163 		return -EINVAL;
1164 	}
1165 
1166 	if (flags & ~CIFSSEC_MASK) {
1167 		cifs_dbg(VFS, "Unsupported security flags: 0x%x\n",
1168 			 flags & ~CIFSSEC_MASK);
1169 		return -EINVAL;
1170 	}
1171 
1172 	cifs_security_flags_handle_must_flags(&flags);
1173 
1174 	/* flags look ok - update the global security flags for cifs module */
1175 	global_secflags = flags;
1176 	if (global_secflags & CIFSSEC_MUST_SIGN) {
1177 		/* requiring signing implies signing is allowed */
1178 		global_secflags |= CIFSSEC_MAY_SIGN;
1179 		cifs_dbg(FYI, "packet signing now required\n");
1180 	} else if ((global_secflags & CIFSSEC_MAY_SIGN) == 0) {
1181 		cifs_dbg(FYI, "packet signing disabled\n");
1182 	}
1183 	/* BB should we turn on MAY flags for other MUST options? */
1184 	return count;
1185 }
1186 
1187 static const struct proc_ops cifs_security_flags_proc_ops = {
1188 	.proc_open	= cifs_security_flags_proc_open,
1189 	.proc_read	= seq_read,
1190 	.proc_lseek	= seq_lseek,
1191 	.proc_release	= single_release,
1192 	.proc_write	= cifs_security_flags_proc_write,
1193 };
1194 
1195 /* To make it easier to debug, can help to show mount params */
1196 static int cifs_mount_params_proc_show(struct seq_file *m, void *v)
1197 {
1198 	const struct fs_parameter_spec *p;
1199 	const char *type;
1200 
1201 	for (p = smb3_fs_parameters; p->name; p++) {
1202 		/* cannot use switch with pointers... */
1203 		if (!p->type) {
1204 			if (p->flags == fs_param_neg_with_no)
1205 				type = "noflag";
1206 			else
1207 				type = "flag";
1208 		} else if (p->type == fs_param_is_bool)
1209 			type = "bool";
1210 		else if (p->type == fs_param_is_u32)
1211 			type = "u32";
1212 		else if (p->type == fs_param_is_u64)
1213 			type = "u64";
1214 		else if (p->type == fs_param_is_string)
1215 			type = "string";
1216 		else
1217 			type = "unknown";
1218 
1219 		seq_printf(m, "%s:%s\n", p->name, type);
1220 	}
1221 
1222 	return 0;
1223 }
1224 
1225 static int cifs_mount_params_proc_open(struct inode *inode, struct file *file)
1226 {
1227 	return single_open(file, cifs_mount_params_proc_show, NULL);
1228 }
1229 
1230 static const struct proc_ops cifs_mount_params_proc_ops = {
1231 	.proc_open	= cifs_mount_params_proc_open,
1232 	.proc_read	= seq_read,
1233 	.proc_lseek	= seq_lseek,
1234 	.proc_release	= single_release,
1235 	/* No need for write for now */
1236 	/* .proc_write	= cifs_mount_params_proc_write, */
1237 };
1238 
1239 #else
1240 void cifs_proc_init(void)
1241 {
1242 }
1243 
1244 void cifs_proc_clean(void)
1245 {
1246 }
1247 #endif /* PROC_FS */
1248