Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 *   fs/cifs_debug.c
  3 *
  4 *   Copyright (C) International Business Machines  Corp., 2000,2005
  5 *
  6 *   Modified by Steve French (sfrench@us.ibm.com)
  7 *
  8 *   This program is free software;  you can redistribute it and/or modify
  9 *   it under the terms of the GNU General Public License as published by
 10 *   the Free Software Foundation; either version 2 of the License, or
 11 *   (at your option) any later version.
 12 *
 13 *   This program is distributed in the hope that it will be useful,
 14 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 16 *   the GNU General Public License for more details.
 17 *
 18 *   You should have received a copy of the GNU General Public License
 19 *   along with this program;  if not, write to the Free Software
 20 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 21 */
 22#include <linux/fs.h>
 23#include <linux/string.h>
 24#include <linux/ctype.h>
 25#include <linux/module.h>
 26#include <linux/proc_fs.h>
 27#include <asm/uaccess.h>
 28#include "cifspdu.h"
 29#include "cifsglob.h"
 30#include "cifsproto.h"
 31#include "cifs_debug.h"
 32#include "cifsfs.h"
 33
 34void
 35cifs_dump_mem(char *label, void *data, int length)
 36{
 37	int i, j;
 38	int *intptr = data;
 39	char *charptr = data;
 40	char buf[10], line[80];
 41
 42	printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n",
 43		label, length, data);
 44	for (i = 0; i < length; i += 16) {
 45		line[0] = 0;
 46		for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
 47			sprintf(buf, " %08x", intptr[i / 4 + j]);
 48			strcat(line, buf);
 49		}
 50		buf[0] = ' ';
 51		buf[2] = 0;
 52		for (j = 0; (j < 16) && (i + j < length); j++) {
 53			buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.';
 54			strcat(line, buf);
 55		}
 56		printk(KERN_DEBUG "%s\n", line);
 57	}
 58}
 59
 60void cifs_dump_detail(void *buf)
 61{
 62#ifdef CONFIG_CIFS_DEBUG2
 63	struct smb_hdr *smb = (struct smb_hdr *)buf;
 64
 65	cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
 66		  smb->Command, smb->Status.CifsError,
 67		  smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
 68	cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
 69#endif /* CONFIG_CIFS_DEBUG2 */
 70}
 71
 72void cifs_dump_mids(struct TCP_Server_Info *server)
 73{
 74#ifdef CONFIG_CIFS_DEBUG2
 75	struct list_head *tmp;
 76	struct mid_q_entry *mid_entry;
 77
 78	if (server == NULL)
 79		return;
 80
 81	cERROR(1, "Dump pending requests:");
 82	spin_lock(&GlobalMid_Lock);
 83	list_for_each(tmp, &server->pending_mid_q) {
 84		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 85		cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu",
 86			mid_entry->mid_state,
 87			le16_to_cpu(mid_entry->command),
 88			mid_entry->pid,
 89			mid_entry->callback_data,
 90			mid_entry->mid);
 91#ifdef CONFIG_CIFS_STATS2
 92		cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
 93			mid_entry->large_buf,
 94			mid_entry->resp_buf,
 95			mid_entry->when_received,
 96			jiffies);
 97#endif /* STATS2 */
 98		cERROR(1, "IsMult: %d IsEnd: %d", mid_entry->multiRsp,
 99			  mid_entry->multiEnd);
100		if (mid_entry->resp_buf) {
101			cifs_dump_detail(mid_entry->resp_buf);
102			cifs_dump_mem("existing buf: ",
103				mid_entry->resp_buf, 62);
104		}
105	}
106	spin_unlock(&GlobalMid_Lock);
107#endif /* CONFIG_CIFS_DEBUG2 */
108}
109
110#ifdef CONFIG_PROC_FS
111static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
112{
113	struct list_head *tmp1, *tmp2, *tmp3;
114	struct mid_q_entry *mid_entry;
115	struct TCP_Server_Info *server;
116	struct cifs_ses *ses;
117	struct cifs_tcon *tcon;
118	int i, j;
119	__u32 dev_type;
120
121	seq_puts(m,
122		    "Display Internal CIFS Data Structures for Debugging\n"
123		    "---------------------------------------------------\n");
124	seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
125	seq_printf(m, "Features:");
126#ifdef CONFIG_CIFS_DFS_UPCALL
127	seq_printf(m, " dfs");
128#endif
129#ifdef CONFIG_CIFS_FSCACHE
130	seq_printf(m, " fscache");
131#endif
132#ifdef CONFIG_CIFS_WEAK_PW_HASH
133	seq_printf(m, " lanman");
134#endif
135#ifdef CONFIG_CIFS_POSIX
136	seq_printf(m, " posix");
137#endif
138#ifdef CONFIG_CIFS_UPCALL
139	seq_printf(m, " spnego");
140#endif
141#ifdef CONFIG_CIFS_XATTR
142	seq_printf(m, " xattr");
143#endif
144#ifdef CONFIG_CIFS_ACL
145	seq_printf(m, " acl");
146#endif
147	seq_putc(m, '\n');
148	seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
149	seq_printf(m, "Servers:");
150
151	i = 0;
152	spin_lock(&cifs_tcp_ses_lock);
153	list_for_each(tmp1, &cifs_tcp_ses_list) {
154		server = list_entry(tmp1, struct TCP_Server_Info,
155				    tcp_ses_list);
156		i++;
157		list_for_each(tmp2, &server->smb_ses_list) {
158			ses = list_entry(tmp2, struct cifs_ses,
159					 smb_ses_list);
160			if ((ses->serverDomain == NULL) ||
161				(ses->serverOS == NULL) ||
162				(ses->serverNOS == NULL)) {
163				seq_printf(m, "\n%d) entry for %s not fully "
164					   "displayed\n\t", i, ses->serverName);
165			} else {
166				seq_printf(m,
167				    "\n%d) Name: %s  Domain: %s Uses: %d OS:"
168				    " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
169				    " session status: %d\t",
170				i, ses->serverName, ses->serverDomain,
171				ses->ses_count, ses->serverOS, ses->serverNOS,
172				ses->capabilities, ses->status);
173			}
174			seq_printf(m, "TCP status: %d\n\tLocal Users To "
175				   "Server: %d SecMode: 0x%x Req On Wire: %d",
176				   server->tcpStatus, server->srv_count,
177				   server->sec_mode, in_flight(server));
178
179#ifdef CONFIG_CIFS_STATS2
180			seq_printf(m, " In Send: %d In MaxReq Wait: %d",
181				atomic_read(&server->in_send),
182				atomic_read(&server->num_waiters));
183#endif
184
185			seq_puts(m, "\n\tShares:");
186			j = 0;
187			list_for_each(tmp3, &ses->tcon_list) {
188				tcon = list_entry(tmp3, struct cifs_tcon,
189						  tcon_list);
190				++j;
191				dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
192				seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
193					   tcon->treeName, tcon->tc_count);
194				if (tcon->nativeFileSystem) {
195					seq_printf(m, "Type: %s ",
196						   tcon->nativeFileSystem);
197				}
198				seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
199					"\nPathComponentMax: %d Status: 0x%d",
200					le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
201					le32_to_cpu(tcon->fsAttrInfo.Attributes),
202					le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
203					tcon->tidStatus);
204				if (dev_type == FILE_DEVICE_DISK)
205					seq_puts(m, " type: DISK ");
206				else if (dev_type == FILE_DEVICE_CD_ROM)
207					seq_puts(m, " type: CDROM ");
208				else
209					seq_printf(m, " type: %d ", dev_type);
210
211				if (tcon->need_reconnect)
212					seq_puts(m, "\tDISCONNECTED ");
213				seq_putc(m, '\n');
214			}
215
216			seq_puts(m, "\n\tMIDs:\n");
217
218			spin_lock(&GlobalMid_Lock);
219			list_for_each(tmp3, &server->pending_mid_q) {
220				mid_entry = list_entry(tmp3, struct mid_q_entry,
221					qhead);
222				seq_printf(m, "\tState: %d com: %d pid:"
223					      " %d cbdata: %p mid %llu\n",
224					      mid_entry->mid_state,
225					      le16_to_cpu(mid_entry->command),
226					      mid_entry->pid,
227					      mid_entry->callback_data,
228					      mid_entry->mid);
229			}
230			spin_unlock(&GlobalMid_Lock);
231		}
232	}
233	spin_unlock(&cifs_tcp_ses_lock);
234	seq_putc(m, '\n');
235
236	/* BB add code to dump additional info such as TCP session info now */
237	return 0;
238}
239
240static int cifs_debug_data_proc_open(struct inode *inode, struct file *file)
241{
242	return single_open(file, cifs_debug_data_proc_show, NULL);
243}
244
245static const struct file_operations cifs_debug_data_proc_fops = {
246	.owner		= THIS_MODULE,
247	.open		= cifs_debug_data_proc_open,
248	.read		= seq_read,
249	.llseek		= seq_lseek,
250	.release	= single_release,
251};
252
253#ifdef CONFIG_CIFS_STATS
254static ssize_t cifs_stats_proc_write(struct file *file,
255		const char __user *buffer, size_t count, loff_t *ppos)
256{
257	char c;
258	int rc;
259	struct list_head *tmp1, *tmp2, *tmp3;
260	struct TCP_Server_Info *server;
261	struct cifs_ses *ses;
262	struct cifs_tcon *tcon;
263
264	rc = get_user(c, buffer);
265	if (rc)
266		return rc;
267
268	if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
269#ifdef CONFIG_CIFS_STATS2
270		atomic_set(&totBufAllocCount, 0);
271		atomic_set(&totSmBufAllocCount, 0);
272#endif /* CONFIG_CIFS_STATS2 */
273		spin_lock(&cifs_tcp_ses_lock);
274		list_for_each(tmp1, &cifs_tcp_ses_list) {
275			server = list_entry(tmp1, struct TCP_Server_Info,
276					    tcp_ses_list);
277			list_for_each(tmp2, &server->smb_ses_list) {
278				ses = list_entry(tmp2, struct cifs_ses,
279						 smb_ses_list);
280				list_for_each(tmp3, &ses->tcon_list) {
281					tcon = list_entry(tmp3,
282							  struct cifs_tcon,
283							  tcon_list);
284					atomic_set(&tcon->num_smbs_sent, 0);
285					atomic_set(&tcon->num_writes, 0);
286					atomic_set(&tcon->num_reads, 0);
287					atomic_set(&tcon->num_oplock_brks, 0);
288					atomic_set(&tcon->num_opens, 0);
289					atomic_set(&tcon->num_posixopens, 0);
290					atomic_set(&tcon->num_posixmkdirs, 0);
291					atomic_set(&tcon->num_closes, 0);
292					atomic_set(&tcon->num_deletes, 0);
293					atomic_set(&tcon->num_mkdirs, 0);
294					atomic_set(&tcon->num_rmdirs, 0);
295					atomic_set(&tcon->num_renames, 0);
296					atomic_set(&tcon->num_t2renames, 0);
297					atomic_set(&tcon->num_ffirst, 0);
298					atomic_set(&tcon->num_fnext, 0);
299					atomic_set(&tcon->num_fclose, 0);
300					atomic_set(&tcon->num_hardlinks, 0);
301					atomic_set(&tcon->num_symlinks, 0);
302					atomic_set(&tcon->num_locks, 0);
303				}
304			}
305		}
306		spin_unlock(&cifs_tcp_ses_lock);
307	}
308
309	return count;
310}
311
312static int cifs_stats_proc_show(struct seq_file *m, void *v)
313{
314	int i;
315	struct list_head *tmp1, *tmp2, *tmp3;
316	struct TCP_Server_Info *server;
317	struct cifs_ses *ses;
318	struct cifs_tcon *tcon;
319
320	seq_printf(m,
321			"Resources in use\nCIFS Session: %d\n",
322			sesInfoAllocCount.counter);
323	seq_printf(m, "Share (unique mount targets): %d\n",
324			tconInfoAllocCount.counter);
325	seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n",
326			bufAllocCount.counter,
327			cifs_min_rcv + tcpSesAllocCount.counter);
328	seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
329			smBufAllocCount.counter, cifs_min_small);
330#ifdef CONFIG_CIFS_STATS2
331	seq_printf(m, "Total Large %d Small %d Allocations\n",
332				atomic_read(&totBufAllocCount),
333				atomic_read(&totSmBufAllocCount));
334#endif /* CONFIG_CIFS_STATS2 */
335
336	seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount));
337	seq_printf(m,
338		"\n%d session %d share reconnects\n",
339		tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
340
341	seq_printf(m,
342		"Total vfs operations: %d maximum at one time: %d\n",
343		GlobalCurrentXid, GlobalMaxActiveXid);
344
345	i = 0;
346	spin_lock(&cifs_tcp_ses_lock);
347	list_for_each(tmp1, &cifs_tcp_ses_list) {
348		server = list_entry(tmp1, struct TCP_Server_Info,
349				    tcp_ses_list);
350		list_for_each(tmp2, &server->smb_ses_list) {
351			ses = list_entry(tmp2, struct cifs_ses,
352					 smb_ses_list);
353			list_for_each(tmp3, &ses->tcon_list) {
354				tcon = list_entry(tmp3,
355						  struct cifs_tcon,
356						  tcon_list);
357				i++;
358				seq_printf(m, "\n%d) %s", i, tcon->treeName);
359				if (tcon->need_reconnect)
360					seq_puts(m, "\tDISCONNECTED ");
361				seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
362					atomic_read(&tcon->num_smbs_sent),
363					atomic_read(&tcon->num_oplock_brks));
364				seq_printf(m, "\nReads:  %d Bytes: %lld",
365					atomic_read(&tcon->num_reads),
366					(long long)(tcon->bytes_read));
367				seq_printf(m, "\nWrites: %d Bytes: %lld",
368					atomic_read(&tcon->num_writes),
369					(long long)(tcon->bytes_written));
370				seq_printf(m, "\nFlushes: %d",
371					atomic_read(&tcon->num_flushes));
372				seq_printf(m, "\nLocks: %d HardLinks: %d "
373					      "Symlinks: %d",
374					atomic_read(&tcon->num_locks),
375					atomic_read(&tcon->num_hardlinks),
376					atomic_read(&tcon->num_symlinks));
377				seq_printf(m, "\nOpens: %d Closes: %d "
378					      "Deletes: %d",
379					atomic_read(&tcon->num_opens),
380					atomic_read(&tcon->num_closes),
381					atomic_read(&tcon->num_deletes));
382				seq_printf(m, "\nPosix Opens: %d "
383					      "Posix Mkdirs: %d",
384					atomic_read(&tcon->num_posixopens),
385					atomic_read(&tcon->num_posixmkdirs));
386				seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
387					atomic_read(&tcon->num_mkdirs),
388					atomic_read(&tcon->num_rmdirs));
389				seq_printf(m, "\nRenames: %d T2 Renames %d",
390					atomic_read(&tcon->num_renames),
391					atomic_read(&tcon->num_t2renames));
392				seq_printf(m, "\nFindFirst: %d FNext %d "
393					      "FClose %d",
394					atomic_read(&tcon->num_ffirst),
395					atomic_read(&tcon->num_fnext),
396					atomic_read(&tcon->num_fclose));
397			}
398		}
399	}
400	spin_unlock(&cifs_tcp_ses_lock);
401
402	seq_putc(m, '\n');
403	return 0;
404}
405
406static int cifs_stats_proc_open(struct inode *inode, struct file *file)
407{
408	return single_open(file, cifs_stats_proc_show, NULL);
409}
410
411static const struct file_operations cifs_stats_proc_fops = {
412	.owner		= THIS_MODULE,
413	.open		= cifs_stats_proc_open,
414	.read		= seq_read,
415	.llseek		= seq_lseek,
416	.release	= single_release,
417	.write		= cifs_stats_proc_write,
418};
419#endif /* STATS */
420
421static struct proc_dir_entry *proc_fs_cifs;
422static const struct file_operations cifsFYI_proc_fops;
423static const struct file_operations cifs_lookup_cache_proc_fops;
424static const struct file_operations traceSMB_proc_fops;
425static const struct file_operations cifs_security_flags_proc_fops;
426static const struct file_operations cifs_linux_ext_proc_fops;
427
428void
429cifs_proc_init(void)
430{
431	proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
432	if (proc_fs_cifs == NULL)
433		return;
434
435	proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops);
436
437#ifdef CONFIG_CIFS_STATS
438	proc_create("Stats", 0, proc_fs_cifs, &cifs_stats_proc_fops);
439#endif /* STATS */
440	proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
441	proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
442	proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
443		    &cifs_linux_ext_proc_fops);
444	proc_create("SecurityFlags", 0, proc_fs_cifs,
445		    &cifs_security_flags_proc_fops);
446	proc_create("LookupCacheEnabled", 0, proc_fs_cifs,
447		    &cifs_lookup_cache_proc_fops);
448}
449
450void
451cifs_proc_clean(void)
452{
453	if (proc_fs_cifs == NULL)
454		return;
455
456	remove_proc_entry("DebugData", proc_fs_cifs);
457	remove_proc_entry("cifsFYI", proc_fs_cifs);
458	remove_proc_entry("traceSMB", proc_fs_cifs);
459#ifdef CONFIG_CIFS_STATS
460	remove_proc_entry("Stats", proc_fs_cifs);
461#endif
462	remove_proc_entry("SecurityFlags", proc_fs_cifs);
463	remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
464	remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
465	remove_proc_entry("fs/cifs", NULL);
466}
467
468static int cifsFYI_proc_show(struct seq_file *m, void *v)
469{
470	seq_printf(m, "%d\n", cifsFYI);
471	return 0;
472}
473
474static int cifsFYI_proc_open(struct inode *inode, struct file *file)
475{
476	return single_open(file, cifsFYI_proc_show, NULL);
477}
478
479static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
480		size_t count, loff_t *ppos)
481{
482	char c;
483	int rc;
484
485	rc = get_user(c, buffer);
486	if (rc)
487		return rc;
488	if (c == '0' || c == 'n' || c == 'N')
489		cifsFYI = 0;
490	else if (c == '1' || c == 'y' || c == 'Y')
491		cifsFYI = 1;
492	else if ((c > '1') && (c <= '9'))
493		cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
494
495	return count;
496}
497
498static const struct file_operations cifsFYI_proc_fops = {
499	.owner		= THIS_MODULE,
500	.open		= cifsFYI_proc_open,
501	.read		= seq_read,
502	.llseek		= seq_lseek,
503	.release	= single_release,
504	.write		= cifsFYI_proc_write,
505};
506
507static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
508{
509	seq_printf(m, "%d\n", linuxExtEnabled);
510	return 0;
511}
512
513static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
514{
515	return single_open(file, cifs_linux_ext_proc_show, NULL);
516}
517
518static ssize_t cifs_linux_ext_proc_write(struct file *file,
519		const char __user *buffer, size_t count, loff_t *ppos)
520{
521	char c;
522	int rc;
523
524	rc = get_user(c, buffer);
525	if (rc)
526		return rc;
527	if (c == '0' || c == 'n' || c == 'N')
528		linuxExtEnabled = 0;
529	else if (c == '1' || c == 'y' || c == 'Y')
530		linuxExtEnabled = 1;
531
532	return count;
533}
534
535static const struct file_operations cifs_linux_ext_proc_fops = {
536	.owner		= THIS_MODULE,
537	.open		= cifs_linux_ext_proc_open,
538	.read		= seq_read,
539	.llseek		= seq_lseek,
540	.release	= single_release,
541	.write		= cifs_linux_ext_proc_write,
542};
543
544static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v)
545{
546	seq_printf(m, "%d\n", lookupCacheEnabled);
547	return 0;
548}
549
550static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
551{
552	return single_open(file, cifs_lookup_cache_proc_show, NULL);
553}
554
555static ssize_t cifs_lookup_cache_proc_write(struct file *file,
556		const char __user *buffer, size_t count, loff_t *ppos)
557{
558	char c;
559	int rc;
560
561	rc = get_user(c, buffer);
562	if (rc)
563		return rc;
564	if (c == '0' || c == 'n' || c == 'N')
565		lookupCacheEnabled = 0;
566	else if (c == '1' || c == 'y' || c == 'Y')
567		lookupCacheEnabled = 1;
568
569	return count;
570}
571
572static const struct file_operations cifs_lookup_cache_proc_fops = {
573	.owner		= THIS_MODULE,
574	.open		= cifs_lookup_cache_proc_open,
575	.read		= seq_read,
576	.llseek		= seq_lseek,
577	.release	= single_release,
578	.write		= cifs_lookup_cache_proc_write,
579};
580
581static int traceSMB_proc_show(struct seq_file *m, void *v)
582{
583	seq_printf(m, "%d\n", traceSMB);
584	return 0;
585}
586
587static int traceSMB_proc_open(struct inode *inode, struct file *file)
588{
589	return single_open(file, traceSMB_proc_show, NULL);
590}
591
592static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
593		size_t count, loff_t *ppos)
594{
595	char c;
596	int rc;
597
598	rc = get_user(c, buffer);
599	if (rc)
600		return rc;
601	if (c == '0' || c == 'n' || c == 'N')
602		traceSMB = 0;
603	else if (c == '1' || c == 'y' || c == 'Y')
604		traceSMB = 1;
605
606	return count;
607}
608
609static const struct file_operations traceSMB_proc_fops = {
610	.owner		= THIS_MODULE,
611	.open		= traceSMB_proc_open,
612	.read		= seq_read,
613	.llseek		= seq_lseek,
614	.release	= single_release,
615	.write		= traceSMB_proc_write,
616};
617
618static int cifs_security_flags_proc_show(struct seq_file *m, void *v)
619{
620	seq_printf(m, "0x%x\n", global_secflags);
621	return 0;
622}
623
624static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
625{
626	return single_open(file, cifs_security_flags_proc_show, NULL);
627}
628
629static ssize_t cifs_security_flags_proc_write(struct file *file,
630		const char __user *buffer, size_t count, loff_t *ppos)
631{
632	unsigned int flags;
633	char flags_string[12];
634	char c;
635
636	if ((count < 1) || (count > 11))
637		return -EINVAL;
638
639	memset(flags_string, 0, 12);
640
641	if (copy_from_user(flags_string, buffer, count))
642		return -EFAULT;
643
644	if (count < 3) {
645		/* single char or single char followed by null */
646		c = flags_string[0];
647		if (c == '0' || c == 'n' || c == 'N') {
648			global_secflags = CIFSSEC_DEF; /* default */
649			return count;
650		} else if (c == '1' || c == 'y' || c == 'Y') {
651			global_secflags = CIFSSEC_MAX;
652			return count;
653		} else if (!isdigit(c)) {
654			cERROR(1, "invalid flag %c", c);
655			return -EINVAL;
656		}
657	}
658	/* else we have a number */
659
660	flags = simple_strtoul(flags_string, NULL, 0);
661
662	cFYI(1, "sec flags 0x%x", flags);
663
664	if (flags <= 0)  {
665		cERROR(1, "invalid security flags %s", flags_string);
666		return -EINVAL;
667	}
668
669	if (flags & ~CIFSSEC_MASK) {
670		cERROR(1, "attempt to set unsupported security flags 0x%x",
671			flags & ~CIFSSEC_MASK);
672		return -EINVAL;
673	}
674	/* flags look ok - update the global security flags for cifs module */
675	global_secflags = flags;
676	if (global_secflags & CIFSSEC_MUST_SIGN) {
677		/* requiring signing implies signing is allowed */
678		global_secflags |= CIFSSEC_MAY_SIGN;
679		cFYI(1, "packet signing now required");
680	} else if ((global_secflags & CIFSSEC_MAY_SIGN) == 0) {
681		cFYI(1, "packet signing disabled");
682	}
683	/* BB should we turn on MAY flags for other MUST options? */
684	return count;
685}
686
687static const struct file_operations cifs_security_flags_proc_fops = {
688	.owner		= THIS_MODULE,
689	.open		= cifs_security_flags_proc_open,
690	.read		= seq_read,
691	.llseek		= seq_lseek,
692	.release	= single_release,
693	.write		= cifs_security_flags_proc_write,
694};
695#else
696inline void cifs_proc_init(void)
697{
698}
699
700inline void cifs_proc_clean(void)
701{
702}
703#endif /* PROC_FS */