]> err.no Git - linux-2.6/blob - fs/cifs/cifs_debug.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / fs / cifs / cifs_debug.c
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
34 void
35 cifs_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
60 #ifdef CONFIG_CIFS_DEBUG2
61 void cifs_dump_detail(struct smb_hdr *smb)
62 {
63         cERROR(1, ("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
64                   smb->Command, smb->Status.CifsError,
65                   smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
66         cERROR(1, ("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
67 }
68
69
70 void cifs_dump_mids(struct TCP_Server_Info *server)
71 {
72         struct list_head *tmp;
73         struct mid_q_entry *mid_entry;
74
75         if (server == NULL)
76                 return;
77
78         cERROR(1, ("Dump pending requests:"));
79         spin_lock(&GlobalMid_Lock);
80         list_for_each(tmp, &server->pending_mid_q) {
81                 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
82                 if (mid_entry) {
83                         cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
84                                 mid_entry->midState,
85                                 (int)mid_entry->command,
86                                 mid_entry->pid,
87                                 mid_entry->tsk,
88                                 mid_entry->mid));
89 #ifdef CONFIG_CIFS_STATS2
90                         cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
91                                 mid_entry->largeBuf,
92                                 mid_entry->resp_buf,
93                                 mid_entry->when_received,
94                                 jiffies));
95 #endif /* STATS2 */
96                         cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
97                                   mid_entry->multiEnd));
98                         if (mid_entry->resp_buf) {
99                                 cifs_dump_detail(mid_entry->resp_buf);
100                                 cifs_dump_mem("existing buf: ",
101                                         mid_entry->resp_buf,
102                                         62 /* fixme */);
103                         }
104                 }
105         }
106         spin_unlock(&GlobalMid_Lock);
107 }
108 #endif /* CONFIG_CIFS_DEBUG2 */
109
110 #ifdef CONFIG_PROC_FS
111 static int
112 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
113                      int count, int *eof, void *data)
114 {
115         struct list_head *tmp;
116         struct list_head *tmp1;
117         struct mid_q_entry *mid_entry;
118         struct cifsSesInfo *ses;
119         struct cifsTconInfo *tcon;
120         int i;
121         int length = 0;
122         char *original_buf = buf;
123
124         *beginBuffer = buf + offset;
125
126         length =
127             sprintf(buf,
128                     "Display Internal CIFS Data Structures for Debugging\n"
129                     "---------------------------------------------------\n");
130         buf += length;
131         length = sprintf(buf, "CIFS Version %s\n", CIFS_VERSION);
132         buf += length;
133         length = sprintf(buf,
134                 "Active VFS Requests: %d\n", GlobalTotalActiveXid);
135         buf += length;
136         length = sprintf(buf, "Servers:");
137         buf += length;
138
139         i = 0;
140         read_lock(&GlobalSMBSeslock);
141         list_for_each(tmp, &GlobalSMBSessionList) {
142                 i++;
143                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
144                 if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
145                    (ses->serverNOS == NULL)) {
146                         buf += sprintf(buf, "\nentry for %s not fully "
147                                         "displayed\n\t", ses->serverName);
148                 } else {
149                         length =
150                             sprintf(buf,
151                                     "\n%d) Name: %s  Domain: %s Mounts: %d OS:"
152                                     " %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
153                                     " session status: %d\t",
154                                 i, ses->serverName, ses->serverDomain,
155                                 atomic_read(&ses->inUse),
156                                 ses->serverOS, ses->serverNOS,
157                                 ses->capabilities, ses->status);
158                         buf += length;
159                 }
160                 if (ses->server) {
161                         buf += sprintf(buf, "TCP status: %d\n\tLocal Users To "
162                                     "Server: %d SecMode: 0x%x Req On Wire: %d",
163                                 ses->server->tcpStatus,
164                                 atomic_read(&ses->server->socketUseCount),
165                                 ses->server->secMode,
166                                 atomic_read(&ses->server->inFlight));
167
168 #ifdef CONFIG_CIFS_STATS2
169                         buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d",
170                                 atomic_read(&ses->server->inSend),
171                                 atomic_read(&ses->server->num_waiters));
172 #endif
173
174                         length = sprintf(buf, "\nMIDs:\n");
175                         buf += length;
176
177                         spin_lock(&GlobalMid_Lock);
178                         list_for_each(tmp1, &ses->server->pending_mid_q) {
179                                 mid_entry = list_entry(tmp1, struct
180                                         mid_q_entry,
181                                         qhead);
182                                 if (mid_entry) {
183                                         length = sprintf(buf,
184                                                         "State: %d com: %d pid:"
185                                                         " %d tsk: %p mid %d\n",
186                                                         mid_entry->midState,
187                                                         (int)mid_entry->command,
188                                                         mid_entry->pid,
189                                                         mid_entry->tsk,
190                                                         mid_entry->mid);
191                                         buf += length;
192                                 }
193                         }
194                         spin_unlock(&GlobalMid_Lock);
195                 }
196
197         }
198         read_unlock(&GlobalSMBSeslock);
199         sprintf(buf, "\n");
200         buf++;
201
202         length = sprintf(buf, "Shares:");
203         buf += length;
204
205         i = 0;
206         read_lock(&GlobalSMBSeslock);
207         list_for_each(tmp, &GlobalTreeConnectionList) {
208                 __u32 dev_type;
209                 i++;
210                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
211                 dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
212                 length =
213                     sprintf(buf,
214                             "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x "
215                             "Attributes: 0x%x\nPathComponentMax: %d Status: %d",
216                             i, tcon->treeName,
217                             atomic_read(&tcon->useCount),
218                             tcon->nativeFileSystem,
219                             le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
220                             le32_to_cpu(tcon->fsAttrInfo.Attributes),
221                             le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
222                             tcon->tidStatus);
223                 buf += length;
224                 if (dev_type == FILE_DEVICE_DISK)
225                         length = sprintf(buf, " type: DISK ");
226                 else if (dev_type == FILE_DEVICE_CD_ROM)
227                         length = sprintf(buf, " type: CDROM ");
228                 else
229                         length =
230                             sprintf(buf, " type: %d ", dev_type);
231                 buf += length;
232                 if (tcon->tidStatus == CifsNeedReconnect) {
233                         buf += sprintf(buf, "\tDISCONNECTED ");
234                         length += 14;
235                 }
236         }
237         read_unlock(&GlobalSMBSeslock);
238
239         length = sprintf(buf, "\n");
240         buf += length;
241
242         /* BB add code to dump additional info such as TCP session info now */
243         /* Now calculate total size of returned data */
244         length = buf - original_buf;
245
246         if (offset + count >= length)
247                 *eof = 1;
248         if (length < offset) {
249                 *eof = 1;
250                 return 0;
251         } else {
252                 length = length - offset;
253         }
254         if (length > count)
255                 length = count;
256
257         return length;
258 }
259
260 #ifdef CONFIG_CIFS_STATS
261
262 static int
263 cifs_stats_write(struct file *file, const char __user *buffer,
264                  unsigned long count, void *data)
265 {
266         char c;
267         int rc;
268         struct list_head *tmp;
269         struct cifsTconInfo *tcon;
270
271         rc = get_user(c, buffer);
272         if (rc)
273                 return rc;
274
275         if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
276                 read_lock(&GlobalSMBSeslock);
277 #ifdef CONFIG_CIFS_STATS2
278                 atomic_set(&totBufAllocCount, 0);
279                 atomic_set(&totSmBufAllocCount, 0);
280 #endif /* CONFIG_CIFS_STATS2 */
281                 list_for_each(tmp, &GlobalTreeConnectionList) {
282                         tcon = list_entry(tmp, struct cifsTconInfo,
283                                         cifsConnectionList);
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_closes, 0);
290                         atomic_set(&tcon->num_deletes, 0);
291                         atomic_set(&tcon->num_mkdirs, 0);
292                         atomic_set(&tcon->num_rmdirs, 0);
293                         atomic_set(&tcon->num_renames, 0);
294                         atomic_set(&tcon->num_t2renames, 0);
295                         atomic_set(&tcon->num_ffirst, 0);
296                         atomic_set(&tcon->num_fnext, 0);
297                         atomic_set(&tcon->num_fclose, 0);
298                         atomic_set(&tcon->num_hardlinks, 0);
299                         atomic_set(&tcon->num_symlinks, 0);
300                         atomic_set(&tcon->num_locks, 0);
301                 }
302                 read_unlock(&GlobalSMBSeslock);
303         }
304
305         return count;
306 }
307
308 static int
309 cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
310                   int count, int *eof, void *data)
311 {
312         int item_length, i, length;
313         struct list_head *tmp;
314         struct cifsTconInfo *tcon;
315
316         *beginBuffer = buf + offset;
317
318         length = sprintf(buf,
319                         "Resources in use\nCIFS Session: %d\n",
320                         sesInfoAllocCount.counter);
321         buf += length;
322         item_length =
323                 sprintf(buf, "Share (unique mount targets): %d\n",
324                         tconInfoAllocCount.counter);
325         length += item_length;
326         buf += item_length;
327         item_length =
328                 sprintf(buf, "SMB Request/Response Buffer: %d Pool size: %d\n",
329                         bufAllocCount.counter,
330                         cifs_min_rcv + tcpSesAllocCount.counter);
331         length += item_length;
332         buf += item_length;
333         item_length =
334                 sprintf(buf, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
335                         smBufAllocCount.counter, cifs_min_small);
336         length += item_length;
337         buf += item_length;
338 #ifdef CONFIG_CIFS_STATS2
339         item_length = sprintf(buf, "Total Large %d Small %d Allocations\n",
340                                 atomic_read(&totBufAllocCount),
341                                 atomic_read(&totSmBufAllocCount));
342         length += item_length;
343         buf += item_length;
344 #endif /* CONFIG_CIFS_STATS2 */
345
346         item_length =
347                 sprintf(buf, "Operations (MIDs): %d\n",
348                         midCount.counter);
349         length += item_length;
350         buf += item_length;
351         item_length = sprintf(buf,
352                 "\n%d session %d share reconnects\n",
353                 tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
354         length += item_length;
355         buf += item_length;
356
357         item_length = sprintf(buf,
358                 "Total vfs operations: %d maximum at one time: %d\n",
359                 GlobalCurrentXid, GlobalMaxActiveXid);
360         length += item_length;
361         buf += item_length;
362
363         i = 0;
364         read_lock(&GlobalSMBSeslock);
365         list_for_each(tmp, &GlobalTreeConnectionList) {
366                 i++;
367                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
368                 item_length = sprintf(buf, "\n%d) %s", i, tcon->treeName);
369                 buf += item_length;
370                 length += item_length;
371                 if (tcon->tidStatus == CifsNeedReconnect) {
372                         buf += sprintf(buf, "\tDISCONNECTED ");
373                         length += 14;
374                 }
375                 item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
376                         atomic_read(&tcon->num_smbs_sent),
377                         atomic_read(&tcon->num_oplock_brks));
378                 buf += item_length;
379                 length += item_length;
380                 item_length = sprintf(buf, "\nReads:  %d Bytes: %lld",
381                         atomic_read(&tcon->num_reads),
382                         (long long)(tcon->bytes_read));
383                 buf += item_length;
384                 length += item_length;
385                 item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
386                         atomic_read(&tcon->num_writes),
387                         (long long)(tcon->bytes_written));
388                 buf += item_length;
389                 length += item_length;
390                 item_length = sprintf(buf,
391                         "\nLocks: %d HardLinks: %d Symlinks: %d",
392                         atomic_read(&tcon->num_locks),
393                         atomic_read(&tcon->num_hardlinks),
394                         atomic_read(&tcon->num_symlinks));
395                 buf += item_length;
396                 length += item_length;
397
398                 item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
399                         atomic_read(&tcon->num_opens),
400                         atomic_read(&tcon->num_closes),
401                         atomic_read(&tcon->num_deletes));
402                 buf += item_length;
403                 length += item_length;
404                 item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
405                         atomic_read(&tcon->num_mkdirs),
406                         atomic_read(&tcon->num_rmdirs));
407                 buf += item_length;
408                 length += item_length;
409                 item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
410                         atomic_read(&tcon->num_renames),
411                         atomic_read(&tcon->num_t2renames));
412                 buf += item_length;
413                 length += item_length;
414                 item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
415                         atomic_read(&tcon->num_ffirst),
416                         atomic_read(&tcon->num_fnext),
417                         atomic_read(&tcon->num_fclose));
418                 buf += item_length;
419                 length += item_length;
420         }
421         read_unlock(&GlobalSMBSeslock);
422
423         buf += sprintf(buf, "\n");
424         length++;
425
426         if (offset + count >= length)
427                 *eof = 1;
428         if (length < offset) {
429                 *eof = 1;
430                 return 0;
431         } else {
432                 length = length - offset;
433         }
434         if (length > count)
435                 length = count;
436
437         return length;
438 }
439 #endif
440
441 static struct proc_dir_entry *proc_fs_cifs;
442 read_proc_t cifs_txanchor_read;
443 static read_proc_t cifsFYI_read;
444 static write_proc_t cifsFYI_write;
445 static read_proc_t oplockEnabled_read;
446 static write_proc_t oplockEnabled_write;
447 static read_proc_t lookupFlag_read;
448 static write_proc_t lookupFlag_write;
449 static read_proc_t traceSMB_read;
450 static write_proc_t traceSMB_write;
451 static read_proc_t multiuser_mount_read;
452 static write_proc_t multiuser_mount_write;
453 static read_proc_t security_flags_read;
454 static write_proc_t security_flags_write;
455 /* static read_proc_t ntlmv2_enabled_read;
456 static write_proc_t ntlmv2_enabled_write;
457 static read_proc_t packet_signing_enabled_read;
458 static write_proc_t packet_signing_enabled_write;*/
459 static read_proc_t experimEnabled_read;
460 static write_proc_t experimEnabled_write;
461 static read_proc_t linuxExtensionsEnabled_read;
462 static write_proc_t linuxExtensionsEnabled_write;
463
464 void
465 cifs_proc_init(void)
466 {
467         struct proc_dir_entry *pde;
468
469         proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
470         if (proc_fs_cifs == NULL)
471                 return;
472
473         proc_fs_cifs->owner = THIS_MODULE;
474         create_proc_read_entry("DebugData", 0, proc_fs_cifs,
475                                 cifs_debug_data_read, NULL);
476
477 #ifdef CONFIG_CIFS_STATS
478         pde = create_proc_read_entry("Stats", 0, proc_fs_cifs,
479                                 cifs_stats_read, NULL);
480         if (pde)
481                 pde->write_proc = cifs_stats_write;
482 #endif
483         pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
484                                 cifsFYI_read, NULL);
485         if (pde)
486                 pde->write_proc = cifsFYI_write;
487
488         pde =
489             create_proc_read_entry("traceSMB", 0, proc_fs_cifs,
490                                 traceSMB_read, NULL);
491         if (pde)
492                 pde->write_proc = traceSMB_write;
493
494         pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
495                                 oplockEnabled_read, NULL);
496         if (pde)
497                 pde->write_proc = oplockEnabled_write;
498
499         pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
500                                 experimEnabled_read, NULL);
501         if (pde)
502                 pde->write_proc = experimEnabled_write;
503
504         pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
505                                 linuxExtensionsEnabled_read, NULL);
506         if (pde)
507                 pde->write_proc = linuxExtensionsEnabled_write;
508
509         pde =
510             create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs,
511                                 multiuser_mount_read, NULL);
512         if (pde)
513                 pde->write_proc = multiuser_mount_write;
514
515         pde =
516             create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
517                                 security_flags_read, NULL);
518         if (pde)
519                 pde->write_proc = security_flags_write;
520
521         pde =
522         create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
523                                 lookupFlag_read, NULL);
524         if (pde)
525                 pde->write_proc = lookupFlag_write;
526
527 /*      pde =
528             create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
529                                 ntlmv2_enabled_read, NULL);
530         if (pde)
531                 pde->write_proc = ntlmv2_enabled_write;
532
533         pde =
534             create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
535                                 packet_signing_enabled_read, NULL);
536         if (pde)
537                 pde->write_proc = packet_signing_enabled_write;*/
538 }
539
540 void
541 cifs_proc_clean(void)
542 {
543         if (proc_fs_cifs == NULL)
544                 return;
545
546         remove_proc_entry("DebugData", proc_fs_cifs);
547         remove_proc_entry("cifsFYI", proc_fs_cifs);
548         remove_proc_entry("traceSMB", proc_fs_cifs);
549 #ifdef CONFIG_CIFS_STATS
550         remove_proc_entry("Stats", proc_fs_cifs);
551 #endif
552         remove_proc_entry("MultiuserMount", proc_fs_cifs);
553         remove_proc_entry("OplockEnabled", proc_fs_cifs);
554 /*      remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
555         remove_proc_entry("SecurityFlags", proc_fs_cifs);
556 /*      remove_proc_entry("PacketSigningEnabled", proc_fs_cifs); */
557         remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
558         remove_proc_entry("Experimental", proc_fs_cifs);
559         remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
560         remove_proc_entry("cifs", proc_root_fs);
561 }
562
563 static int
564 cifsFYI_read(char *page, char **start, off_t off, int count,
565              int *eof, void *data)
566 {
567         int len;
568
569         len = sprintf(page, "%d\n", cifsFYI);
570
571         len -= off;
572         *start = page + off;
573
574         if (len > count)
575                 len = count;
576         else
577                 *eof = 1;
578
579         if (len < 0)
580                 len = 0;
581
582         return len;
583 }
584 static int
585 cifsFYI_write(struct file *file, const char __user *buffer,
586               unsigned long count, void *data)
587 {
588         char c;
589         int rc;
590
591         rc = get_user(c, buffer);
592         if (rc)
593                 return rc;
594         if (c == '0' || c == 'n' || c == 'N')
595                 cifsFYI = 0;
596         else if (c == '1' || c == 'y' || c == 'Y')
597                 cifsFYI = 1;
598         else if ((c > '1') && (c <= '9'))
599                 cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
600
601         return count;
602 }
603
604 static int
605 oplockEnabled_read(char *page, char **start, off_t off,
606                    int count, int *eof, void *data)
607 {
608         int len;
609
610         len = sprintf(page, "%d\n", oplockEnabled);
611
612         len -= off;
613         *start = page + off;
614
615         if (len > count)
616                 len = count;
617         else
618                 *eof = 1;
619
620         if (len < 0)
621                 len = 0;
622
623         return len;
624 }
625 static int
626 oplockEnabled_write(struct file *file, const char __user *buffer,
627                     unsigned long count, void *data)
628 {
629         char c;
630         int rc;
631
632         rc = get_user(c, buffer);
633         if (rc)
634                 return rc;
635         if (c == '0' || c == 'n' || c == 'N')
636                 oplockEnabled = 0;
637         else if (c == '1' || c == 'y' || c == 'Y')
638                 oplockEnabled = 1;
639
640         return count;
641 }
642
643 static int
644 experimEnabled_read(char *page, char **start, off_t off,
645                     int count, int *eof, void *data)
646 {
647         int len;
648
649         len = sprintf(page, "%d\n", experimEnabled);
650
651         len -= off;
652         *start = page + off;
653
654         if (len > count)
655                 len = count;
656         else
657                 *eof = 1;
658
659         if (len < 0)
660                 len = 0;
661
662         return len;
663 }
664 static int
665 experimEnabled_write(struct file *file, const char __user *buffer,
666                      unsigned long count, void *data)
667 {
668         char c;
669         int rc;
670
671         rc = get_user(c, buffer);
672         if (rc)
673                 return rc;
674         if (c == '0' || c == 'n' || c == 'N')
675                 experimEnabled = 0;
676         else if (c == '1' || c == 'y' || c == 'Y')
677                 experimEnabled = 1;
678         else if (c == '2')
679                 experimEnabled = 2;
680
681         return count;
682 }
683
684 static int
685 linuxExtensionsEnabled_read(char *page, char **start, off_t off,
686                             int count, int *eof, void *data)
687 {
688         int len;
689
690         len = sprintf(page, "%d\n", linuxExtEnabled);
691         len -= off;
692         *start = page + off;
693
694         if (len > count)
695                 len = count;
696         else
697                 *eof = 1;
698
699         if (len < 0)
700                 len = 0;
701
702         return len;
703 }
704 static int
705 linuxExtensionsEnabled_write(struct file *file, const char __user *buffer,
706                              unsigned long count, void *data)
707 {
708         char c;
709         int rc;
710
711         rc = get_user(c, buffer);
712         if (rc)
713                 return rc;
714         if (c == '0' || c == 'n' || c == 'N')
715                 linuxExtEnabled = 0;
716         else if (c == '1' || c == 'y' || c == 'Y')
717                 linuxExtEnabled = 1;
718
719         return count;
720 }
721
722
723 static int
724 lookupFlag_read(char *page, char **start, off_t off,
725                 int count, int *eof, void *data)
726 {
727         int len;
728
729         len = sprintf(page, "%d\n", lookupCacheEnabled);
730
731         len -= off;
732         *start = page + off;
733
734         if (len > count)
735                 len = count;
736         else
737                 *eof = 1;
738
739         if (len < 0)
740                 len = 0;
741
742         return len;
743 }
744 static int
745 lookupFlag_write(struct file *file, const char __user *buffer,
746                     unsigned long count, void *data)
747 {
748         char c;
749         int rc;
750
751         rc = get_user(c, buffer);
752         if (rc)
753                 return rc;
754         if (c == '0' || c == 'n' || c == 'N')
755                 lookupCacheEnabled = 0;
756         else if (c == '1' || c == 'y' || c == 'Y')
757                 lookupCacheEnabled = 1;
758
759         return count;
760 }
761 static int
762 traceSMB_read(char *page, char **start, off_t off, int count,
763               int *eof, void *data)
764 {
765         int len;
766
767         len = sprintf(page, "%d\n", traceSMB);
768
769         len -= off;
770         *start = page + off;
771
772         if (len > count)
773                 len = count;
774         else
775                 *eof = 1;
776
777         if (len < 0)
778                 len = 0;
779
780         return len;
781 }
782 static int
783 traceSMB_write(struct file *file, const char __user *buffer,
784                unsigned long count, void *data)
785 {
786         char c;
787         int rc;
788
789         rc = get_user(c, buffer);
790         if (rc)
791                 return rc;
792         if (c == '0' || c == 'n' || c == 'N')
793                 traceSMB = 0;
794         else if (c == '1' || c == 'y' || c == 'Y')
795                 traceSMB = 1;
796
797         return count;
798 }
799
800 static int
801 multiuser_mount_read(char *page, char **start, off_t off,
802                      int count, int *eof, void *data)
803 {
804         int len;
805
806         len = sprintf(page, "%d\n", multiuser_mount);
807
808         len -= off;
809         *start = page + off;
810
811         if (len > count)
812                 len = count;
813         else
814                 *eof = 1;
815
816         if (len < 0)
817                 len = 0;
818
819         return len;
820 }
821 static int
822 multiuser_mount_write(struct file *file, const char __user *buffer,
823                       unsigned long count, void *data)
824 {
825         char c;
826         int rc;
827
828         rc = get_user(c, buffer);
829         if (rc)
830                 return rc;
831         if (c == '0' || c == 'n' || c == 'N')
832                 multiuser_mount = 0;
833         else if (c == '1' || c == 'y' || c == 'Y')
834                 multiuser_mount = 1;
835
836         return count;
837 }
838
839 static int
840 security_flags_read(char *page, char **start, off_t off,
841                        int count, int *eof, void *data)
842 {
843         int len;
844
845         len = sprintf(page, "0x%x\n", extended_security);
846
847         len -= off;
848         *start = page + off;
849
850         if (len > count)
851                 len = count;
852         else
853                 *eof = 1;
854
855         if (len < 0)
856                 len = 0;
857
858         return len;
859 }
860 static int
861 security_flags_write(struct file *file, const char __user *buffer,
862                         unsigned long count, void *data)
863 {
864         unsigned int flags;
865         char flags_string[12];
866         char c;
867
868         if ((count < 1) || (count > 11))
869                 return -EINVAL;
870
871         memset(flags_string, 0, 12);
872
873         if (copy_from_user(flags_string, buffer, count))
874                 return -EFAULT;
875
876         if (count < 3) {
877                 /* single char or single char followed by null */
878                 c = flags_string[0];
879                 if (c == '0' || c == 'n' || c == 'N')
880                         extended_security = CIFSSEC_DEF; /* default */
881                 else if (c == '1' || c == 'y' || c == 'Y')
882                         extended_security = CIFSSEC_MAX;
883                 return count;
884         }
885         /* else we have a number */
886
887         flags = simple_strtoul(flags_string, NULL, 0);
888
889         cFYI(1, ("sec flags 0x%x", flags));
890
891         if (flags <= 0)  {
892                 cERROR(1, ("invalid security flags %s", flags_string));
893                 return -EINVAL;
894         }
895
896         if (flags & ~CIFSSEC_MASK) {
897                 cERROR(1, ("attempt to set unsupported security flags 0x%x",
898                         flags & ~CIFSSEC_MASK));
899                 return -EINVAL;
900         }
901         /* flags look ok - update the global security flags for cifs module */
902         extended_security = flags;
903         if (extended_security & CIFSSEC_MUST_SIGN) {
904                 /* requiring signing implies signing is allowed */
905                 extended_security |= CIFSSEC_MAY_SIGN;
906                 cFYI(1, ("packet signing now required"));
907         } else if ((extended_security & CIFSSEC_MAY_SIGN) == 0) {
908                 cFYI(1, ("packet signing disabled"));
909         }
910         /* BB should we turn on MAY flags for other MUST options? */
911         return count;
912 }
913 #endif