cifs_debug.c 23.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs_debug.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2000,2005
L
Linus Torvalds 已提交
5 6 7 8 9
 *
 *   Modified by Steve French (sfrench@us.ibm.com)
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
S
Steve French 已提交
10
 *   the Free Software Foundation; either version 2 of the License, or
L
Linus Torvalds 已提交
11
 *   (at your option) any later version.
S
Steve French 已提交
12
 *
L
Linus Torvalds 已提交
13 14 15 16 17 18
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
S
Steve French 已提交
19
 *   along with this program;  if not, write to the Free Software
L
Linus Torvalds 已提交
20 21 22 23 24 25 26
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
27
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
28 29 30 31
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
32
#include "cifsfs.h"
33 34 35
#ifdef CONFIG_CIFS_SMB_DIRECT
#include "smbdirect.h"
#endif
L
Linus Torvalds 已提交
36 37 38 39

void
cifs_dump_mem(char *label, void *data, int length)
{
40
	pr_debug("%s: dump of %d bytes of data at 0x%p\n", label, length, data);
41 42
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4,
		       data, length, true);
L
Linus Torvalds 已提交
43 44
}

45 46 47 48 49 50 51 52 53 54 55
#ifdef CONFIG_CIFS_DEBUG
void cifs_vfs_err(const char *fmt, ...)
{
	struct va_format vaf;
	va_list args;

	va_start(args, fmt);

	vaf.fmt = fmt;
	vaf.va = &args;

56
	pr_err_ratelimited("CIFS VFS: %pV", &vaf);
57 58 59 60 61

	va_end(args);
}
#endif

62
void cifs_dump_detail(void *buf)
63
{
64
#ifdef CONFIG_CIFS_DEBUG2
65 66
	struct smb_hdr *smb = (struct smb_hdr *)buf;

67 68 69 70
	cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d\n",
		 smb->Command, smb->Status.CifsError,
		 smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
	cifs_dbg(VFS, "smb buf %p len %u\n", smb, smbCalcSize(smb));
71
#endif /* CONFIG_CIFS_DEBUG2 */
72 73
}

S
Steve French 已提交
74
void cifs_dump_mids(struct TCP_Server_Info *server)
75
{
76
#ifdef CONFIG_CIFS_DEBUG2
77
	struct list_head *tmp;
S
Steve French 已提交
78
	struct mid_q_entry *mid_entry;
79

S
Steve French 已提交
80
	if (server == NULL)
81 82
		return;

83
	cifs_dbg(VFS, "Dump pending requests:\n");
84 85 86
	spin_lock(&GlobalMid_Lock);
	list_for_each(tmp, &server->pending_mid_q) {
		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
87 88 89 90 91 92
		cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n",
			 mid_entry->mid_state,
			 le16_to_cpu(mid_entry->command),
			 mid_entry->pid,
			 mid_entry->callback_data,
			 mid_entry->mid);
93
#ifdef CONFIG_CIFS_STATS2
94 95 96 97 98
		cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n",
			 mid_entry->large_buf,
			 mid_entry->resp_buf,
			 mid_entry->when_received,
			 jiffies);
99
#endif /* STATS2 */
100 101
		cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n",
			 mid_entry->multiRsp, mid_entry->multiEnd);
102 103 104 105
		if (mid_entry->resp_buf) {
			cifs_dump_detail(mid_entry->resp_buf);
			cifs_dump_mem("existing buf: ",
				mid_entry->resp_buf, 62);
106 107 108 109
		}
	}
	spin_unlock(&GlobalMid_Lock);
#endif /* CONFIG_CIFS_DEBUG2 */
110
}
111

L
Linus Torvalds 已提交
112
#ifdef CONFIG_PROC_FS
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
{
	__u32 dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);

	seq_printf(m, "%s Mounts: %d ", tcon->treeName, tcon->tc_count);
	if (tcon->nativeFileSystem)
		seq_printf(m, "Type: %s ", tcon->nativeFileSystem);
	seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x\n\tPathComponentMax: %d Status: %d",
		   le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
		   le32_to_cpu(tcon->fsAttrInfo.Attributes),
		   le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
		   tcon->tidStatus);
	if (dev_type == FILE_DEVICE_DISK)
		seq_puts(m, " type: DISK ");
	else if (dev_type == FILE_DEVICE_CD_ROM)
		seq_puts(m, " type: CDROM ");
	else
		seq_printf(m, " type: %d ", dev_type);
131 132 133 134
	if (tcon->seal)
		seq_printf(m, " Encrypted");
	if (tcon->unix_ext)
		seq_printf(m, " POSIX Extensions");
135 136 137 138 139 140 141 142
	if (tcon->ses->server->ops->dump_share_caps)
		tcon->ses->server->ops->dump_share_caps(m, tcon);

	if (tcon->need_reconnect)
		seq_puts(m, "\tDISCONNECTED ");
	seq_putc(m, '\n');
}

143
static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
144
{
145
	struct list_head *tmp1, *tmp2, *tmp3;
S
Steve French 已提交
146
	struct mid_q_entry *mid_entry;
147
	struct TCP_Server_Info *server;
148 149
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
150
	int i, j;
L
Linus Torvalds 已提交
151

152
	seq_puts(m,
L
Linus Torvalds 已提交
153 154
		    "Display Internal CIFS Data Structures for Debugging\n"
		    "---------------------------------------------------\n");
155
	seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
156
	seq_printf(m, "Features:");
157
#ifdef CONFIG_CIFS_DFS_UPCALL
158
	seq_printf(m, " dfs");
159 160
#endif
#ifdef CONFIG_CIFS_FSCACHE
161
	seq_printf(m, " fscache");
162 163
#endif
#ifdef CONFIG_CIFS_WEAK_PW_HASH
164
	seq_printf(m, " lanman");
165 166
#endif
#ifdef CONFIG_CIFS_POSIX
167
	seq_printf(m, " posix");
168 169
#endif
#ifdef CONFIG_CIFS_UPCALL
170
	seq_printf(m, " spnego");
171 172
#endif
#ifdef CONFIG_CIFS_XATTR
173 174 175 176
	seq_printf(m, " xattr");
#endif
#ifdef CONFIG_CIFS_ACL
	seq_printf(m, " acl");
177 178
#endif
	seq_putc(m, '\n');
179 180
	seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
	seq_printf(m, "Servers:");
L
Linus Torvalds 已提交
181 182

	i = 0;
183
	spin_lock(&cifs_tcp_ses_lock);
184 185
	list_for_each(tmp1, &cifs_tcp_ses_list) {
		server = list_entry(tmp1, struct TCP_Server_Info,
186
				    tcp_ses_list);
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

#ifdef CONFIG_CIFS_SMB_DIRECT
		if (!server->rdma)
			goto skip_rdma;

		seq_printf(m, "\nSMBDirect (in hex) protocol version: %x "
			"transport status: %x",
			server->smbd_conn->protocol,
			server->smbd_conn->transport_status);
		seq_printf(m, "\nConn receive_credit_max: %x "
			"send_credit_target: %x max_send_size: %x",
			server->smbd_conn->receive_credit_max,
			server->smbd_conn->send_credit_target,
			server->smbd_conn->max_send_size);
		seq_printf(m, "\nConn max_fragmented_recv_size: %x "
			"max_fragmented_send_size: %x max_receive_size:%x",
			server->smbd_conn->max_fragmented_recv_size,
			server->smbd_conn->max_fragmented_send_size,
			server->smbd_conn->max_receive_size);
		seq_printf(m, "\nConn keep_alive_interval: %x "
			"max_readwrite_size: %x rdma_readwrite_threshold: %x",
			server->smbd_conn->keep_alive_interval,
			server->smbd_conn->max_readwrite_size,
			server->smbd_conn->rdma_readwrite_threshold);
		seq_printf(m, "\nDebug count_get_receive_buffer: %x "
			"count_put_receive_buffer: %x count_send_empty: %x",
			server->smbd_conn->count_get_receive_buffer,
			server->smbd_conn->count_put_receive_buffer,
			server->smbd_conn->count_send_empty);
		seq_printf(m, "\nRead Queue count_reassembly_queue: %x "
			"count_enqueue_reassembly_queue: %x "
			"count_dequeue_reassembly_queue: %x "
			"fragment_reassembly_remaining: %x "
			"reassembly_data_length: %x "
			"reassembly_queue_length: %x",
			server->smbd_conn->count_reassembly_queue,
			server->smbd_conn->count_enqueue_reassembly_queue,
			server->smbd_conn->count_dequeue_reassembly_queue,
			server->smbd_conn->fragment_reassembly_remaining,
			server->smbd_conn->reassembly_data_length,
			server->smbd_conn->reassembly_queue_length);
		seq_printf(m, "\nCurrent Credits send_credits: %x "
			"receive_credits: %x receive_credit_target: %x",
			atomic_read(&server->smbd_conn->send_credits),
			atomic_read(&server->smbd_conn->receive_credits),
			server->smbd_conn->receive_credit_target);
		seq_printf(m, "\nPending send_pending: %x send_payload_pending:"
			" %x smbd_send_pending: %x smbd_recv_pending: %x",
			atomic_read(&server->smbd_conn->send_pending),
			atomic_read(&server->smbd_conn->send_payload_pending),
			server->smbd_conn->smbd_send_pending,
			server->smbd_conn->smbd_recv_pending);
		seq_printf(m, "\nReceive buffers count_receive_queue: %x "
			"count_empty_packet_queue: %x",
			server->smbd_conn->count_receive_queue,
			server->smbd_conn->count_empty_packet_queue);
		seq_printf(m, "\nMR responder_resources: %x "
			"max_frmr_depth: %x mr_type: %x",
			server->smbd_conn->responder_resources,
			server->smbd_conn->max_frmr_depth,
			server->smbd_conn->mr_type);
		seq_printf(m, "\nMR mr_ready_count: %x mr_used_count: %x",
			atomic_read(&server->smbd_conn->mr_ready_count),
			atomic_read(&server->smbd_conn->mr_used_count));
skip_rdma:
#endif
253 254 255 256
		seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
			server->credits,  server->dialect);
		if (server->sign)
			seq_printf(m, " signed");
L
Linus Torvalds 已提交
257
		i++;
258
		list_for_each(tmp2, &server->smb_ses_list) {
259
			ses = list_entry(tmp2, struct cifs_ses,
260 261 262 263
					 smb_ses_list);
			if ((ses->serverDomain == NULL) ||
				(ses->serverOS == NULL) ||
				(ses->serverNOS == NULL)) {
264 265 266 267 268 269 270
				seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d\t",
					i, ses->serverName, ses->ses_count,
					ses->capabilities, ses->status);
				if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
					seq_printf(m, "Guest\t");
				else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
					seq_printf(m, "Anonymous\t");
271 272
			} else {
				seq_printf(m,
273 274
				    "\n%d) Name: %s  Domain: %s Uses: %d OS:"
				    " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
S
Steve French 已提交
275
				    " session status: %d\t",
276
				i, ses->serverName, ses->serverDomain,
277
				ses->ses_count, ses->serverOS, ses->serverNOS,
S
Steve French 已提交
278
				ses->capabilities, ses->status);
279
			}
L
Long Li 已提交
280 281
			if (server->rdma)
				seq_printf(m, "RDMA\n\t");
282
			seq_printf(m, "TCP status: %d\n\tLocal Users To "
283 284
				   "Server: %d SecMode: 0x%x Req On Wire: %d",
				   server->tcpStatus, server->srv_count,
P
Pavel Shilovsky 已提交
285
				   server->sec_mode, in_flight(server));
286 287

#ifdef CONFIG_CIFS_STATS2
288
			seq_printf(m, " In Send: %d In MaxReq Wait: %d",
289
				atomic_read(&server->in_send),
290
				atomic_read(&server->num_waiters));
291 292
#endif

293 294
			seq_puts(m, "\n\tShares:");
			j = 0;
295 296 297 298 299 300 301

			seq_printf(m, "\n\t%d) IPC: ", j);
			if (ses->tcon_ipc)
				cifs_debug_tcon(m, ses->tcon_ipc);
			else
				seq_puts(m, "none\n");

302
			list_for_each(tmp3, &ses->tcon_list) {
303
				tcon = list_entry(tmp3, struct cifs_tcon,
304 305
						  tcon_list);
				++j;
306 307
				seq_printf(m, "\n\t%d) ", j);
				cifs_debug_tcon(m, tcon);
308 309 310
			}

			seq_puts(m, "\n\tMIDs:\n");
L
Linus Torvalds 已提交
311 312

			spin_lock(&GlobalMid_Lock);
313
			list_for_each(tmp3, &server->pending_mid_q) {
314
				mid_entry = list_entry(tmp3, struct mid_q_entry,
L
Linus Torvalds 已提交
315
					qhead);
316
				seq_printf(m, "\tState: %d com: %d pid:"
317 318 319 320 321 322
					      " %d cbdata: %p mid %llu\n",
					      mid_entry->mid_state,
					      le16_to_cpu(mid_entry->command),
					      mid_entry->pid,
					      mid_entry->callback_data,
					      mid_entry->mid);
L
Linus Torvalds 已提交
323
			}
S
Steve French 已提交
324
			spin_unlock(&GlobalMid_Lock);
L
Linus Torvalds 已提交
325 326
		}
	}
327
	spin_unlock(&cifs_tcp_ses_lock);
328
	seq_putc(m, '\n');
L
Linus Torvalds 已提交
329 330

	/* BB add code to dump additional info such as TCP session info now */
331 332
	return 0;
}
L
Linus Torvalds 已提交
333

334 335 336
static int cifs_debug_data_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifs_debug_data_proc_show, NULL);
L
Linus Torvalds 已提交
337 338
}

339 340 341 342 343 344
static const struct file_operations cifs_debug_data_proc_fops = {
	.open		= cifs_debug_data_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
S
Steve French 已提交
345

346 347 348
#ifdef CONFIG_CIFS_STATS
static ssize_t cifs_stats_proc_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
S
Steve French 已提交
349
{
350
	bool bv;
S
Steve French 已提交
351
	int rc;
352 353
	struct list_head *tmp1, *tmp2, *tmp3;
	struct TCP_Server_Info *server;
354 355
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
S
Steve French 已提交
356

357 358
	rc = kstrtobool_from_user(buffer, count, &bv);
	if (rc == 0) {
359 360 361 362
#ifdef CONFIG_CIFS_STATS2
		atomic_set(&totBufAllocCount, 0);
		atomic_set(&totSmBufAllocCount, 0);
#endif /* CONFIG_CIFS_STATS2 */
363
		spin_lock(&cifs_tcp_ses_lock);
364 365 366
		list_for_each(tmp1, &cifs_tcp_ses_list) {
			server = list_entry(tmp1, struct TCP_Server_Info,
					    tcp_ses_list);
S
Steve French 已提交
367
			list_for_each(tmp2, &server->smb_ses_list) {
368
				ses = list_entry(tmp2, struct cifs_ses,
S
Steve French 已提交
369
						 smb_ses_list);
370 371
				list_for_each(tmp3, &ses->tcon_list) {
					tcon = list_entry(tmp3,
372
							  struct cifs_tcon,
373 374
							  tcon_list);
					atomic_set(&tcon->num_smbs_sent, 0);
375 376
					if (server->ops->clear_stats)
						server->ops->clear_stats(tcon);
377 378
				}
			}
S
Steve French 已提交
379
		}
380
		spin_unlock(&cifs_tcp_ses_lock);
381 382
	} else {
		return rc;
S
Steve French 已提交
383 384
	}

S
Steve French 已提交
385
	return count;
S
Steve French 已提交
386 387
}

388
static int cifs_stats_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
389
{
390
	int i;
391 392
	struct list_head *tmp1, *tmp2, *tmp3;
	struct TCP_Server_Info *server;
393 394
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
L
Linus Torvalds 已提交
395

396
	seq_printf(m,
L
Linus Torvalds 已提交
397 398
			"Resources in use\nCIFS Session: %d\n",
			sesInfoAllocCount.counter);
399
	seq_printf(m, "Share (unique mount targets): %d\n",
L
Linus Torvalds 已提交
400
			tconInfoAllocCount.counter);
401
	seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n",
402 403
			bufAllocCount.counter,
			cifs_min_rcv + tcpSesAllocCount.counter);
404
	seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
S
Steve French 已提交
405
			smBufAllocCount.counter, cifs_min_small);
406
#ifdef CONFIG_CIFS_STATS2
407
	seq_printf(m, "Total Large %d Small %d Allocations\n",
408
				atomic_read(&totBufAllocCount),
S
Steve French 已提交
409
				atomic_read(&totSmBufAllocCount));
410 411
#endif /* CONFIG_CIFS_STATS2 */

412
	seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount));
413
	seq_printf(m,
L
Linus Torvalds 已提交
414
		"\n%d session %d share reconnects\n",
S
Steve French 已提交
415
		tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
L
Linus Torvalds 已提交
416

417
	seq_printf(m,
L
Linus Torvalds 已提交
418
		"Total vfs operations: %d maximum at one time: %d\n",
S
Steve French 已提交
419
		GlobalCurrentXid, GlobalMaxActiveXid);
L
Linus Torvalds 已提交
420 421

	i = 0;
422
	spin_lock(&cifs_tcp_ses_lock);
423 424 425 426
	list_for_each(tmp1, &cifs_tcp_ses_list) {
		server = list_entry(tmp1, struct TCP_Server_Info,
				    tcp_ses_list);
		list_for_each(tmp2, &server->smb_ses_list) {
427
			ses = list_entry(tmp2, struct cifs_ses,
428 429 430
					 smb_ses_list);
			list_for_each(tmp3, &ses->tcon_list) {
				tcon = list_entry(tmp3,
431
						  struct cifs_tcon,
432 433 434 435 436
						  tcon_list);
				i++;
				seq_printf(m, "\n%d) %s", i, tcon->treeName);
				if (tcon->need_reconnect)
					seq_puts(m, "\tDISCONNECTED ");
437 438 439 440
				seq_printf(m, "\nSMBs: %d",
					   atomic_read(&tcon->num_smbs_sent));
				if (server->ops->print_stats)
					server->ops->print_stats(m, tcon);
441 442
			}
		}
L
Linus Torvalds 已提交
443
	}
444
	spin_unlock(&cifs_tcp_ses_lock);
L
Linus Torvalds 已提交
445

446 447 448
	seq_putc(m, '\n');
	return 0;
}
S
Steve French 已提交
449

450 451 452
static int cifs_stats_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifs_stats_proc_show, NULL);
L
Linus Torvalds 已提交
453
}
454 455 456 457 458 459 460 461

static const struct file_operations cifs_stats_proc_fops = {
	.open		= cifs_stats_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= cifs_stats_proc_write,
};
462
#endif /* STATS */
L
Linus Torvalds 已提交
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
#ifdef CONFIG_CIFS_SMB_DIRECT
#define PROC_FILE_DEFINE(name) \
static ssize_t name##_write(struct file *file, const char __user *buffer, \
	size_t count, loff_t *ppos) \
{ \
	int rc; \
	rc = kstrtoint_from_user(buffer, count, 10, & name); \
	if (rc) \
		return rc; \
	return count; \
} \
static int name##_proc_show(struct seq_file *m, void *v) \
{ \
	seq_printf(m, "%d\n", name ); \
	return 0; \
} \
static int name##_open(struct inode *inode, struct file *file) \
{ \
	return single_open(file, name##_proc_show, NULL); \
} \
\
static const struct file_operations cifs_##name##_proc_fops = { \
	.open		= name##_open, \
	.read		= seq_read, \
	.llseek		= seq_lseek, \
	.release	= single_release, \
	.write		= name##_write, \
}

PROC_FILE_DEFINE(rdma_readwrite_threshold);
PROC_FILE_DEFINE(smbd_max_frmr_depth);
PROC_FILE_DEFINE(smbd_keep_alive_interval);
PROC_FILE_DEFINE(smbd_max_receive_size);
PROC_FILE_DEFINE(smbd_max_fragmented_recv_size);
PROC_FILE_DEFINE(smbd_max_send_size);
PROC_FILE_DEFINE(smbd_send_credit_target);
PROC_FILE_DEFINE(smbd_receive_credit_max);
#endif

L
Linus Torvalds 已提交
503
static struct proc_dir_entry *proc_fs_cifs;
504 505 506 507 508
static const struct file_operations cifsFYI_proc_fops;
static const struct file_operations cifs_lookup_cache_proc_fops;
static const struct file_operations traceSMB_proc_fops;
static const struct file_operations cifs_security_flags_proc_fops;
static const struct file_operations cifs_linux_ext_proc_fops;
L
Linus Torvalds 已提交
509 510 511 512

void
cifs_proc_init(void)
{
A
Alexey Dobriyan 已提交
513
	proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
L
Linus Torvalds 已提交
514 515 516
	if (proc_fs_cifs == NULL)
		return;

517
	proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops);
L
Linus Torvalds 已提交
518 519

#ifdef CONFIG_CIFS_STATS
520
	proc_create("Stats", 0, proc_fs_cifs, &cifs_stats_proc_fops);
521
#endif /* STATS */
522 523
	proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
	proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
S
Steve French 已提交
524 525 526 527 528 529
	proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
		    &cifs_linux_ext_proc_fops);
	proc_create("SecurityFlags", 0, proc_fs_cifs,
		    &cifs_security_flags_proc_fops);
	proc_create("LookupCacheEnabled", 0, proc_fs_cifs,
		    &cifs_lookup_cache_proc_fops);
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
#ifdef CONFIG_CIFS_SMB_DIRECT
	proc_create("rdma_readwrite_threshold", 0, proc_fs_cifs,
		&cifs_rdma_readwrite_threshold_proc_fops);
	proc_create("smbd_max_frmr_depth", 0, proc_fs_cifs,
		&cifs_smbd_max_frmr_depth_proc_fops);
	proc_create("smbd_keep_alive_interval", 0, proc_fs_cifs,
		&cifs_smbd_keep_alive_interval_proc_fops);
	proc_create("smbd_max_receive_size", 0, proc_fs_cifs,
		&cifs_smbd_max_receive_size_proc_fops);
	proc_create("smbd_max_fragmented_recv_size", 0, proc_fs_cifs,
		&cifs_smbd_max_fragmented_recv_size_proc_fops);
	proc_create("smbd_max_send_size", 0, proc_fs_cifs,
		&cifs_smbd_max_send_size_proc_fops);
	proc_create("smbd_send_credit_target", 0, proc_fs_cifs,
		&cifs_smbd_send_credit_target_proc_fops);
	proc_create("smbd_receive_credit_max", 0, proc_fs_cifs,
		&cifs_smbd_receive_credit_max_proc_fops);
#endif
L
Linus Torvalds 已提交
548 549 550 551 552 553 554 555 556 557 558 559 560 561
}

void
cifs_proc_clean(void)
{
	if (proc_fs_cifs == NULL)
		return;

	remove_proc_entry("DebugData", proc_fs_cifs);
	remove_proc_entry("cifsFYI", proc_fs_cifs);
	remove_proc_entry("traceSMB", proc_fs_cifs);
#ifdef CONFIG_CIFS_STATS
	remove_proc_entry("Stats", proc_fs_cifs);
#endif
S
Steve French 已提交
562 563 564
	remove_proc_entry("SecurityFlags", proc_fs_cifs);
	remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
	remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
565 566 567 568 569 570 571 572 573 574
#ifdef CONFIG_CIFS_SMB_DIRECT
	remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
	remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
	remove_proc_entry("smbd_keep_alive_interval", proc_fs_cifs);
	remove_proc_entry("smbd_max_receive_size", proc_fs_cifs);
	remove_proc_entry("smbd_max_fragmented_recv_size", proc_fs_cifs);
	remove_proc_entry("smbd_max_send_size", proc_fs_cifs);
	remove_proc_entry("smbd_send_credit_target", proc_fs_cifs);
	remove_proc_entry("smbd_receive_credit_max", proc_fs_cifs);
#endif
A
Alexey Dobriyan 已提交
575
	remove_proc_entry("fs/cifs", NULL);
L
Linus Torvalds 已提交
576 577
}

578
static int cifsFYI_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
579
{
580 581 582
	seq_printf(m, "%d\n", cifsFYI);
	return 0;
}
L
Linus Torvalds 已提交
583

584 585 586
static int cifsFYI_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifsFYI_proc_show, NULL);
L
Linus Torvalds 已提交
587
}
588 589 590

static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
		size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
591
{
592
	char c[2] = { '\0' };
593
	bool bv;
L
Linus Torvalds 已提交
594 595
	int rc;

596
	rc = get_user(c[0], buffer);
L
Linus Torvalds 已提交
597 598
	if (rc)
		return rc;
599
	if (strtobool(c, &bv) == 0)
600
		cifsFYI = bv;
601 602
	else if ((c[0] > '1') && (c[0] <= '9'))
		cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
L
Linus Torvalds 已提交
603 604 605 606

	return count;
}

607 608 609 610 611 612 613
static const struct file_operations cifsFYI_proc_fops = {
	.open		= cifsFYI_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= cifsFYI_proc_write,
};
L
Linus Torvalds 已提交
614

615 616 617 618 619
static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, "%d\n", linuxExtEnabled);
	return 0;
}
L
Linus Torvalds 已提交
620

621 622 623
static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifs_linux_ext_proc_show, NULL);
L
Linus Torvalds 已提交
624
}
625 626 627

static ssize_t cifs_linux_ext_proc_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
628
{
S
Steve French 已提交
629 630
	int rc;

631
	rc = kstrtobool_from_user(buffer, count, &linuxExtEnabled);
S
Steve French 已提交
632 633
	if (rc)
		return rc;
634

S
Steve French 已提交
635
	return count;
L
Linus Torvalds 已提交
636 637
}

638 639 640 641 642 643 644
static const struct file_operations cifs_linux_ext_proc_fops = {
	.open		= cifs_linux_ext_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= cifs_linux_ext_proc_write,
};
L
Linus Torvalds 已提交
645

646
static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
647
{
648 649 650
	seq_printf(m, "%d\n", lookupCacheEnabled);
	return 0;
}
L
Linus Torvalds 已提交
651

652 653 654
static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifs_lookup_cache_proc_show, NULL);
L
Linus Torvalds 已提交
655
}
656 657 658

static ssize_t cifs_lookup_cache_proc_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
659 660 661
{
	int rc;

662
	rc = kstrtobool_from_user(buffer, count, &lookupCacheEnabled);
L
Linus Torvalds 已提交
663 664
	if (rc)
		return rc;
665

L
Linus Torvalds 已提交
666 667 668
	return count;
}

669 670 671 672 673 674 675
static const struct file_operations cifs_lookup_cache_proc_fops = {
	.open		= cifs_lookup_cache_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= cifs_lookup_cache_proc_write,
};
L
Linus Torvalds 已提交
676

677 678 679 680 681
static int traceSMB_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, "%d\n", traceSMB);
	return 0;
}
L
Linus Torvalds 已提交
682

683 684 685
static int traceSMB_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, traceSMB_proc_show, NULL);
L
Linus Torvalds 已提交
686
}
687 688 689

static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
		size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
690 691 692
{
	int rc;

693
	rc = kstrtobool_from_user(buffer, count, &traceSMB);
L
Linus Torvalds 已提交
694 695
	if (rc)
		return rc;
696

L
Linus Torvalds 已提交
697 698 699
	return count;
}

700 701 702 703 704 705 706
static const struct file_operations traceSMB_proc_fops = {
	.open		= traceSMB_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= traceSMB_proc_write,
};
L
Linus Torvalds 已提交
707

708 709
static int cifs_security_flags_proc_show(struct seq_file *m, void *v)
{
710
	seq_printf(m, "0x%x\n", global_secflags);
711 712
	return 0;
}
L
Linus Torvalds 已提交
713

714 715 716
static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, cifs_security_flags_proc_show, NULL);
L
Linus Torvalds 已提交
717
}
718

719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
/*
 * Ensure that if someone sets a MUST flag, that we disable all other MAY
 * flags except for the ones corresponding to the given MUST flag. If there are
 * multiple MUST flags, then try to prefer more secure ones.
 */
static void
cifs_security_flags_handle_must_flags(unsigned int *flags)
{
	unsigned int signflags = *flags & CIFSSEC_MUST_SIGN;

	if ((*flags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
		*flags = CIFSSEC_MUST_KRB5;
	else if ((*flags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
		*flags = CIFSSEC_MUST_NTLMSSP;
	else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
		*flags = CIFSSEC_MUST_NTLMV2;
	else if ((*flags & CIFSSEC_MUST_NTLM) == CIFSSEC_MUST_NTLM)
		*flags = CIFSSEC_MUST_NTLM;
737 738
	else if (CIFSSEC_MUST_LANMAN &&
		 (*flags & CIFSSEC_MUST_LANMAN) == CIFSSEC_MUST_LANMAN)
739
		*flags = CIFSSEC_MUST_LANMAN;
740 741
	else if (CIFSSEC_MUST_PLNTXT &&
		 (*flags & CIFSSEC_MUST_PLNTXT) == CIFSSEC_MUST_PLNTXT)
742 743 744 745 746
		*flags = CIFSSEC_MUST_PLNTXT;

	*flags |= signflags;
}

747 748
static ssize_t cifs_security_flags_proc_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
749
{
750
	int rc;
751 752
	unsigned int flags;
	char flags_string[12];
753
	bool bv;
754

S
Steve French 已提交
755
	if ((count < 1) || (count > 11))
756
		return -EINVAL;
L
Linus Torvalds 已提交
757

758
	memset(flags_string, 0, 12);
759

S
Steve French 已提交
760
	if (copy_from_user(flags_string, buffer, count))
761
		return -EFAULT;
762

S
Steve French 已提交
763
	if (count < 3) {
764
		/* single char or single char followed by null */
765
		if (strtobool(flags_string, &bv) == 0) {
766
			global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
767
			return count;
768
		} else if (!isdigit(flags_string[0])) {
769 770
			cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
					flags_string);
771 772
			return -EINVAL;
		}
773 774
	}

775 776 777 778 779 780 781
	/* else we have a number */
	rc = kstrtouint(flags_string, 0, &flags);
	if (rc) {
		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
				flags_string);
		return rc;
	}
782

783
	cifs_dbg(FYI, "sec flags 0x%x\n", flags);
784

785 786
	if (flags == 0)  {
		cifs_dbg(VFS, "Invalid SecurityFlags: %s\n", flags_string);
787 788
		return -EINVAL;
	}
L
Linus Torvalds 已提交
789

S
Steve French 已提交
790
	if (flags & ~CIFSSEC_MASK) {
791
		cifs_dbg(VFS, "Unsupported security flags: 0x%x\n",
792
			 flags & ~CIFSSEC_MASK);
793 794
		return -EINVAL;
	}
795

796 797
	cifs_security_flags_handle_must_flags(&flags);

798
	/* flags look ok - update the global security flags for cifs module */
799 800
	global_secflags = flags;
	if (global_secflags & CIFSSEC_MUST_SIGN) {
801
		/* requiring signing implies signing is allowed */
802
		global_secflags |= CIFSSEC_MAY_SIGN;
803
		cifs_dbg(FYI, "packet signing now required\n");
804
	} else if ((global_secflags & CIFSSEC_MAY_SIGN) == 0) {
805
		cifs_dbg(FYI, "packet signing disabled\n");
806 807
	}
	/* BB should we turn on MAY flags for other MUST options? */
L
Linus Torvalds 已提交
808 809
	return count;
}
810 811 812 813 814 815 816 817

static const struct file_operations cifs_security_flags_proc_fops = {
	.open		= cifs_security_flags_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= cifs_security_flags_proc_write,
};
818
#else
819
inline void cifs_proc_init(void)
820 821 822
{
}

823
inline void cifs_proc_clean(void)
824 825 826
{
}
#endif /* PROC_FS */