diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 529 |
1 files changed, 450 insertions, 79 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0db0b313d715..c8ae3ef422ba 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -166,11 +166,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
166 | 166 | ||
167 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); | 167 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); |
168 | 168 | ||
169 | #ifdef CONFIG_CIFS_STATS | 169 | if(tcon != NULL) |
170 | if(tcon != NULL) { | 170 | cifs_stats_inc(&tcon->num_smbs_sent); |
171 | atomic_inc(&tcon->num_smbs_sent); | 171 | |
172 | } | ||
173 | #endif /* CONFIG_CIFS_STATS */ | ||
174 | return rc; | 172 | return rc; |
175 | } | 173 | } |
176 | 174 | ||
@@ -269,11 +267,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
269 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 267 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
270 | wct /*wct */ ); | 268 | wct /*wct */ ); |
271 | 269 | ||
272 | #ifdef CONFIG_CIFS_STATS | 270 | if(tcon != NULL) |
273 | if(tcon != NULL) { | 271 | cifs_stats_inc(&tcon->num_smbs_sent); |
274 | atomic_inc(&tcon->num_smbs_sent); | 272 | |
275 | } | ||
276 | #endif /* CONFIG_CIFS_STATS */ | ||
277 | return rc; | 273 | return rc; |
278 | } | 274 | } |
279 | 275 | ||
@@ -330,7 +326,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
330 | (void **) &pSMB, (void **) &pSMBr); | 326 | (void **) &pSMB, (void **) &pSMBr); |
331 | if (rc) | 327 | if (rc) |
332 | return rc; | 328 | return rc; |
333 | 329 | pSMB->hdr.Mid = GetNextMid(server); | |
334 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 330 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
335 | if (extended_security) | 331 | if (extended_security) |
336 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 332 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
@@ -422,8 +418,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
422 | } | 418 | } |
423 | 419 | ||
424 | } | 420 | } |
425 | if (pSMB) | 421 | |
426 | cifs_buf_release(pSMB); | 422 | cifs_buf_release(pSMB); |
427 | return rc; | 423 | return rc; |
428 | } | 424 | } |
429 | 425 | ||
@@ -518,6 +514,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
518 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | 514 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ |
519 | 515 | ||
520 | if(ses->server) { | 516 | if(ses->server) { |
517 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
518 | |||
521 | if(ses->server->secMode & | 519 | if(ses->server->secMode & |
522 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 520 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
523 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 521 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
@@ -537,9 +535,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
537 | rc = -ESHUTDOWN; | 535 | rc = -ESHUTDOWN; |
538 | } | 536 | } |
539 | } | 537 | } |
540 | if (pSMB) | ||
541 | cifs_small_buf_release(pSMB); | ||
542 | up(&ses->sesSem); | 538 | up(&ses->sesSem); |
539 | cifs_small_buf_release(pSMB); | ||
543 | 540 | ||
544 | /* if session dead then we do not need to do ulogoff, | 541 | /* if session dead then we do not need to do ulogoff, |
545 | since server closed smb session, no sense reporting | 542 | since server closed smb session, no sense reporting |
@@ -583,14 +580,10 @@ DelFileRetry: | |||
583 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 580 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
584 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 581 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
585 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 582 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
583 | cifs_stats_inc(&tcon->num_deletes); | ||
586 | if (rc) { | 584 | if (rc) { |
587 | cFYI(1, ("Error in RMFile = %d", rc)); | 585 | cFYI(1, ("Error in RMFile = %d", rc)); |
588 | } | 586 | } |
589 | #ifdef CONFIG_CIFS_STATS | ||
590 | else { | ||
591 | atomic_inc(&tcon->num_deletes); | ||
592 | } | ||
593 | #endif | ||
594 | 587 | ||
595 | cifs_buf_release(pSMB); | 588 | cifs_buf_release(pSMB); |
596 | if (rc == -EAGAIN) | 589 | if (rc == -EAGAIN) |
@@ -632,14 +625,10 @@ RmDirRetry: | |||
632 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 625 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
633 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 626 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
634 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 627 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
628 | cifs_stats_inc(&tcon->num_rmdirs); | ||
635 | if (rc) { | 629 | if (rc) { |
636 | cFYI(1, ("Error in RMDir = %d", rc)); | 630 | cFYI(1, ("Error in RMDir = %d", rc)); |
637 | } | 631 | } |
638 | #ifdef CONFIG_CIFS_STATS | ||
639 | else { | ||
640 | atomic_inc(&tcon->num_rmdirs); | ||
641 | } | ||
642 | #endif | ||
643 | 632 | ||
644 | cifs_buf_release(pSMB); | 633 | cifs_buf_release(pSMB); |
645 | if (rc == -EAGAIN) | 634 | if (rc == -EAGAIN) |
@@ -680,20 +669,157 @@ MkDirRetry: | |||
680 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 669 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
681 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 670 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
682 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 671 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
672 | cifs_stats_inc(&tcon->num_mkdirs); | ||
683 | if (rc) { | 673 | if (rc) { |
684 | cFYI(1, ("Error in Mkdir = %d", rc)); | 674 | cFYI(1, ("Error in Mkdir = %d", rc)); |
685 | } | 675 | } |
686 | #ifdef CONFIG_CIFS_STATS | 676 | |
687 | else { | ||
688 | atomic_inc(&tcon->num_mkdirs); | ||
689 | } | ||
690 | #endif | ||
691 | cifs_buf_release(pSMB); | 677 | cifs_buf_release(pSMB); |
692 | if (rc == -EAGAIN) | 678 | if (rc == -EAGAIN) |
693 | goto MkDirRetry; | 679 | goto MkDirRetry; |
694 | return rc; | 680 | return rc; |
695 | } | 681 | } |
696 | 682 | ||
683 | static __u16 convert_disposition(int disposition) | ||
684 | { | ||
685 | __u16 ofun = 0; | ||
686 | |||
687 | switch (disposition) { | ||
688 | case FILE_SUPERSEDE: | ||
689 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
690 | break; | ||
691 | case FILE_OPEN: | ||
692 | ofun = SMBOPEN_OAPPEND; | ||
693 | break; | ||
694 | case FILE_CREATE: | ||
695 | ofun = SMBOPEN_OCREATE; | ||
696 | break; | ||
697 | case FILE_OPEN_IF: | ||
698 | ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; | ||
699 | break; | ||
700 | case FILE_OVERWRITE: | ||
701 | ofun = SMBOPEN_OTRUNC; | ||
702 | break; | ||
703 | case FILE_OVERWRITE_IF: | ||
704 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
705 | break; | ||
706 | default: | ||
707 | cFYI(1,("unknown disposition %d",disposition)); | ||
708 | ofun = SMBOPEN_OAPPEND; /* regular open */ | ||
709 | } | ||
710 | return ofun; | ||
711 | } | ||
712 | |||
713 | int | ||
714 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
715 | const char *fileName, const int openDisposition, | ||
716 | const int access_flags, const int create_options, __u16 * netfid, | ||
717 | int *pOplock, FILE_ALL_INFO * pfile_info, | ||
718 | const struct nls_table *nls_codepage, int remap) | ||
719 | { | ||
720 | int rc = -EACCES; | ||
721 | OPENX_REQ *pSMB = NULL; | ||
722 | OPENX_RSP *pSMBr = NULL; | ||
723 | int bytes_returned; | ||
724 | int name_len; | ||
725 | __u16 count; | ||
726 | |||
727 | OldOpenRetry: | ||
728 | rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, | ||
729 | (void **) &pSMBr); | ||
730 | if (rc) | ||
731 | return rc; | ||
732 | |||
733 | pSMB->AndXCommand = 0xFF; /* none */ | ||
734 | |||
735 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
736 | count = 1; /* account for one byte pad to word boundary */ | ||
737 | name_len = | ||
738 | cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), | ||
739 | fileName, PATH_MAX, nls_codepage, remap); | ||
740 | name_len++; /* trailing null */ | ||
741 | name_len *= 2; | ||
742 | } else { /* BB improve check for buffer overruns BB */ | ||
743 | count = 0; /* no pad */ | ||
744 | name_len = strnlen(fileName, PATH_MAX); | ||
745 | name_len++; /* trailing null */ | ||
746 | strncpy(pSMB->fileName, fileName, name_len); | ||
747 | } | ||
748 | if (*pOplock & REQ_OPLOCK) | ||
749 | pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); | ||
750 | else if (*pOplock & REQ_BATCHOPLOCK) { | ||
751 | pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); | ||
752 | } | ||
753 | pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); | ||
754 | /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ | ||
755 | /* 0 = read | ||
756 | 1 = write | ||
757 | 2 = rw | ||
758 | 3 = execute | ||
759 | */ | ||
760 | pSMB->Mode = cpu_to_le16(2); | ||
761 | pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ | ||
762 | /* set file as system file if special file such | ||
763 | as fifo and server expecting SFU style and | ||
764 | no Unix extensions */ | ||
765 | |||
766 | if(create_options & CREATE_OPTION_SPECIAL) | ||
767 | pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); | ||
768 | else | ||
769 | pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL); | ||
770 | |||
771 | /* if ((omode & S_IWUGO) == 0) | ||
772 | pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ | ||
773 | /* Above line causes problems due to vfs splitting create into two | ||
774 | pieces - need to set mode after file created not while it is | ||
775 | being created */ | ||
776 | |||
777 | /* BB FIXME BB */ | ||
778 | /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */ | ||
779 | /* BB FIXME END BB */ | ||
780 | pSMB->OpenFunction = convert_disposition(openDisposition); | ||
781 | count += name_len; | ||
782 | pSMB->hdr.smb_buf_length += count; | ||
783 | |||
784 | pSMB->ByteCount = cpu_to_le16(count); | ||
785 | /* long_op set to 1 to allow for oplock break timeouts */ | ||
786 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
787 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | ||
788 | cifs_stats_inc(&tcon->num_opens); | ||
789 | if (rc) { | ||
790 | cFYI(1, ("Error in Open = %d", rc)); | ||
791 | } else { | ||
792 | /* BB verify if wct == 15 */ | ||
793 | |||
794 | /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ | ||
795 | |||
796 | *netfid = pSMBr->Fid; /* cifs fid stays in le */ | ||
797 | /* Let caller know file was created so we can set the mode. */ | ||
798 | /* Do we care about the CreateAction in any other cases? */ | ||
799 | /* BB FIXME BB */ | ||
800 | /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | ||
801 | *pOplock |= CIFS_CREATE_ACTION; */ | ||
802 | /* BB FIXME END */ | ||
803 | |||
804 | if(pfile_info) { | ||
805 | pfile_info->CreationTime = 0; /* BB convert CreateTime*/ | ||
806 | pfile_info->LastAccessTime = 0; /* BB fixme */ | ||
807 | pfile_info->LastWriteTime = 0; /* BB fixme */ | ||
808 | pfile_info->ChangeTime = 0; /* BB fixme */ | ||
809 | pfile_info->Attributes = pSMBr->FileAttributes; | ||
810 | /* the file_info buf is endian converted by caller */ | ||
811 | pfile_info->AllocationSize = pSMBr->EndOfFile; | ||
812 | pfile_info->EndOfFile = pSMBr->EndOfFile; | ||
813 | pfile_info->NumberOfLinks = cpu_to_le32(1); | ||
814 | } | ||
815 | } | ||
816 | |||
817 | cifs_buf_release(pSMB); | ||
818 | if (rc == -EAGAIN) | ||
819 | goto OldOpenRetry; | ||
820 | return rc; | ||
821 | } | ||
822 | |||
697 | int | 823 | int |
698 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 824 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, |
699 | const char *fileName, const int openDisposition, | 825 | const char *fileName, const int openDisposition, |
@@ -738,7 +864,13 @@ openRetry: | |||
738 | } | 864 | } |
739 | pSMB->DesiredAccess = cpu_to_le32(access_flags); | 865 | pSMB->DesiredAccess = cpu_to_le32(access_flags); |
740 | pSMB->AllocationSize = 0; | 866 | pSMB->AllocationSize = 0; |
741 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | 867 | /* set file as system file if special file such |
868 | as fifo and server expecting SFU style and | ||
869 | no Unix extensions */ | ||
870 | if(create_options & CREATE_OPTION_SPECIAL) | ||
871 | pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); | ||
872 | else | ||
873 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | ||
742 | /* XP does not handle ATTR_POSIX_SEMANTICS */ | 874 | /* XP does not handle ATTR_POSIX_SEMANTICS */ |
743 | /* but it helps speed up case sensitive checks for other | 875 | /* but it helps speed up case sensitive checks for other |
744 | servers such as Samba */ | 876 | servers such as Samba */ |
@@ -752,7 +884,7 @@ openRetry: | |||
752 | being created */ | 884 | being created */ |
753 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | 885 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); |
754 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); | 886 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); |
755 | pSMB->CreateOptions = cpu_to_le32(create_options); | 887 | pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); |
756 | /* BB Expirement with various impersonation levels and verify */ | 888 | /* BB Expirement with various impersonation levels and verify */ |
757 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); | 889 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); |
758 | pSMB->SecurityFlags = | 890 | pSMB->SecurityFlags = |
@@ -765,6 +897,7 @@ openRetry: | |||
765 | /* long_op set to 1 to allow for oplock break timeouts */ | 897 | /* long_op set to 1 to allow for oplock break timeouts */ |
766 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 898 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
767 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 899 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); |
900 | cifs_stats_inc(&tcon->num_opens); | ||
768 | if (rc) { | 901 | if (rc) { |
769 | cFYI(1, ("Error in Open = %d", rc)); | 902 | cFYI(1, ("Error in Open = %d", rc)); |
770 | } else { | 903 | } else { |
@@ -782,17 +915,89 @@ openRetry: | |||
782 | pfile_info->EndOfFile = pSMBr->EndOfFile; | 915 | pfile_info->EndOfFile = pSMBr->EndOfFile; |
783 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 916 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
784 | } | 917 | } |
785 | |||
786 | #ifdef CONFIG_CIFS_STATS | ||
787 | atomic_inc(&tcon->num_opens); | ||
788 | #endif | ||
789 | } | 918 | } |
919 | |||
790 | cifs_buf_release(pSMB); | 920 | cifs_buf_release(pSMB); |
791 | if (rc == -EAGAIN) | 921 | if (rc == -EAGAIN) |
792 | goto openRetry; | 922 | goto openRetry; |
793 | return rc; | 923 | return rc; |
794 | } | 924 | } |
795 | 925 | ||
926 | int | ||
927 | SMBLegacyRead(const int xid, struct cifsTconInfo *tcon, | ||
928 | const int netfid, unsigned int count, | ||
929 | const __u64 lseek, unsigned int *nbytes, char **buf) | ||
930 | { | ||
931 | int rc = -EACCES; | ||
932 | READX_REQ *pSMB = NULL; | ||
933 | READ_RSP *pSMBr = NULL; | ||
934 | char *pReadData = NULL; | ||
935 | int bytes_returned; | ||
936 | |||
937 | cFYI(1,("Legacy read %d bytes fid %d",count,netfid)); | ||
938 | |||
939 | /* field is shorter in legacy read, only 16 bits */ | ||
940 | if(count > 2048) | ||
941 | count = 2048; /* BB FIXME make this configurable */ | ||
942 | |||
943 | if(lseek > 0xFFFFFFFF) | ||
944 | return -EIO; /* can not read that far into file on old server */ | ||
945 | |||
946 | *nbytes = 0; | ||
947 | rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB, | ||
948 | (void **) &pSMBr); | ||
949 | if (rc) | ||
950 | return rc; | ||
951 | |||
952 | /* tcon and ses pointer are checked in smb_init */ | ||
953 | if (tcon->ses->server == NULL) | ||
954 | return -ECONNABORTED; | ||
955 | |||
956 | pSMB->AndXCommand = 0xFF; /* none */ | ||
957 | pSMB->Fid = netfid; | ||
958 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | ||
959 | pSMB->Remaining = 0; | ||
960 | pSMB->MaxCount = cpu_to_le16(count); | ||
961 | pSMB->Reserved = 0; /* Must Be Zero */ | ||
962 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | ||
963 | |||
964 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
965 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
966 | cifs_stats_inc(&tcon->num_reads); | ||
967 | if (rc) { | ||
968 | cERROR(1, ("Send error in legacy read = %d", rc)); | ||
969 | } else { | ||
970 | int data_length = le16_to_cpu(pSMBr->DataLengthHigh); | ||
971 | data_length = data_length << 16; | ||
972 | data_length += le16_to_cpu(pSMBr->DataLength); | ||
973 | *nbytes = data_length; | ||
974 | |||
975 | /*check that DataLength would not go beyond end of SMB */ | ||
976 | if ((data_length > CIFSMaxBufSize) || (data_length > count)) { | ||
977 | cFYI(1,("bad length %d for count %d",data_length,count)); | ||
978 | rc = -EIO; | ||
979 | *nbytes = 0; | ||
980 | } else { | ||
981 | pReadData = (char *) (&pSMBr->hdr.Protocol) + | ||
982 | le16_to_cpu(pSMBr->DataOffset); | ||
983 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { | ||
984 | cERROR(1,("Faulting on read rc = %d",rc)); | ||
985 | rc = -EFAULT; | ||
986 | }*/ /* can not use copy_to_user when using page cache*/ | ||
987 | if(*buf) | ||
988 | memcpy(*buf,pReadData,data_length); | ||
989 | } | ||
990 | } | ||
991 | if(*buf) | ||
992 | cifs_buf_release(pSMB); | ||
993 | else | ||
994 | *buf = (char *)pSMB; | ||
995 | |||
996 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
997 | since file handle passed in no longer valid */ | ||
998 | return rc; | ||
999 | } | ||
1000 | |||
796 | /* If no buffer passed in, then caller wants to do the copy | 1001 | /* If no buffer passed in, then caller wants to do the copy |
797 | as in the case of readpages so the SMB buffer must be | 1002 | as in the case of readpages so the SMB buffer must be |
798 | freed by the caller */ | 1003 | freed by the caller */ |
@@ -831,6 +1036,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
831 | 1036 | ||
832 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1037 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
833 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1038 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1039 | cifs_stats_inc(&tcon->num_reads); | ||
834 | if (rc) { | 1040 | if (rc) { |
835 | cERROR(1, ("Send error in read = %d", rc)); | 1041 | cERROR(1, ("Send error in read = %d", rc)); |
836 | } else { | 1042 | } else { |
@@ -933,6 +1139,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
933 | 1139 | ||
934 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1140 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
935 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); | 1141 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); |
1142 | cifs_stats_inc(&tcon->num_writes); | ||
936 | if (rc) { | 1143 | if (rc) { |
937 | cFYI(1, ("Send error in write = %d", rc)); | 1144 | cFYI(1, ("Send error in write = %d", rc)); |
938 | *nbytes = 0; | 1145 | *nbytes = 0; |
@@ -951,56 +1158,70 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
951 | } | 1158 | } |
952 | 1159 | ||
953 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1160 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1161 | int |
1162 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
955 | const int netfid, const unsigned int count, | 1163 | const int netfid, const unsigned int count, |
956 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | 1164 | const __u64 offset, unsigned int *nbytes, const char *buf, |
957 | const int long_op) | 1165 | const int long_op) |
958 | { | 1166 | { |
959 | int rc = -EACCES; | 1167 | int rc = -EACCES; |
960 | WRITE_REQ *pSMB = NULL; | 1168 | WRITE_REQ *pSMB = NULL; |
961 | WRITE_RSP *pSMBr = NULL; | 1169 | int bytes_returned; |
962 | /*int bytes_returned;*/ | 1170 | int smb_hdr_len; |
963 | unsigned bytes_sent; | 1171 | __u32 bytes_sent; |
964 | __u16 byte_count; | 1172 | __u16 byte_count; |
965 | 1173 | ||
1174 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ | ||
966 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1175 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); |
967 | |||
968 | if (rc) | 1176 | if (rc) |
969 | return rc; | 1177 | return rc; |
970 | |||
971 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
972 | |||
973 | /* tcon and ses pointer are checked in smb_init */ | 1178 | /* tcon and ses pointer are checked in smb_init */ |
974 | if (tcon->ses->server == NULL) | 1179 | if (tcon->ses->server == NULL) |
975 | return -ECONNABORTED; | 1180 | return -ECONNABORTED; |
976 | 1181 | ||
977 | pSMB->AndXCommand = 0xFF; /* none */ | 1182 | pSMB->AndXCommand = 0xFF; /* none */ |
978 | pSMB->Fid = netfid; | 1183 | pSMB->Fid = netfid; |
979 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1184 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
980 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1185 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); |
981 | pSMB->Reserved = 0xFFFFFFFF; | 1186 | pSMB->Reserved = 0xFFFFFFFF; |
982 | pSMB->WriteMode = 0; | 1187 | pSMB->WriteMode = 0; |
983 | pSMB->Remaining = 0; | 1188 | pSMB->Remaining = 0; |
984 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | 1189 | |
1190 | /* Can increase buffer size if buffer is big enough in some cases - ie | ||
1191 | can send more if LARGE_WRITE_X capability returned by the server and if | ||
1192 | our buffer is big enough or if we convert to iovecs on socket writes | ||
1193 | and eliminate the copy to the CIFS buffer */ | ||
1194 | if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | ||
1195 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | ||
1196 | } else { | ||
1197 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | ||
1198 | & ~0xFF; | ||
1199 | } | ||
1200 | |||
985 | if (bytes_sent > count) | 1201 | if (bytes_sent > count) |
986 | bytes_sent = count; | 1202 | bytes_sent = count; |
987 | pSMB->DataLengthHigh = 0; | ||
988 | pSMB->DataOffset = | 1203 | pSMB->DataOffset = |
989 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1204 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
990 | 1205 | ||
991 | byte_count = bytes_sent + 1 /* pad */ ; | 1206 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ |
992 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | 1207 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
993 | pSMB->DataLengthHigh = 0; | 1208 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
994 | pSMB->hdr.smb_buf_length += byte_count; | 1209 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
1210 | pSMB->hdr.smb_buf_length += bytes_sent+1; | ||
995 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1211 | pSMB->ByteCount = cpu_to_le16(byte_count); |
996 | 1212 | ||
997 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1213 | rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len, |
998 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | 1214 | buf, bytes_sent, &bytes_returned, long_op); |
1215 | cifs_stats_inc(&tcon->num_writes); | ||
999 | if (rc) { | 1216 | if (rc) { |
1000 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | 1217 | cFYI(1, ("Send error in write = %d", rc)); |
1001 | *nbytes = 0; | 1218 | *nbytes = 0; |
1002 | } else | 1219 | } else { |
1003 | *nbytes = le16_to_cpu(pSMBr->Count); | 1220 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; |
1221 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
1222 | *nbytes = (*nbytes) << 16; | ||
1223 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
1224 | } | ||
1004 | 1225 | ||
1005 | cifs_small_buf_release(pSMB); | 1226 | cifs_small_buf_release(pSMB); |
1006 | 1227 | ||
@@ -1009,6 +1230,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1009 | 1230 | ||
1010 | return rc; | 1231 | return rc; |
1011 | } | 1232 | } |
1233 | |||
1234 | |||
1012 | #endif /* CIFS_EXPERIMENTAL */ | 1235 | #endif /* CIFS_EXPERIMENTAL */ |
1013 | 1236 | ||
1014 | int | 1237 | int |
@@ -1065,7 +1288,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1065 | 1288 | ||
1066 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1289 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1067 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1290 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); |
1068 | 1291 | cifs_stats_inc(&tcon->num_locks); | |
1069 | if (rc) { | 1292 | if (rc) { |
1070 | cFYI(1, ("Send error in Lock = %d", rc)); | 1293 | cFYI(1, ("Send error in Lock = %d", rc)); |
1071 | } | 1294 | } |
@@ -1099,6 +1322,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
1099 | pSMB->ByteCount = 0; | 1322 | pSMB->ByteCount = 0; |
1100 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1323 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1101 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1324 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1325 | cifs_stats_inc(&tcon->num_closes); | ||
1102 | if (rc) { | 1326 | if (rc) { |
1103 | if(rc!=-EINTR) { | 1327 | if(rc!=-EINTR) { |
1104 | /* EINTR is expected when user ctl-c to kill app */ | 1328 | /* EINTR is expected when user ctl-c to kill app */ |
@@ -1171,16 +1395,11 @@ renameRetry: | |||
1171 | 1395 | ||
1172 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1396 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1173 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1397 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1398 | cifs_stats_inc(&tcon->num_renames); | ||
1174 | if (rc) { | 1399 | if (rc) { |
1175 | cFYI(1, ("Send error in rename = %d", rc)); | 1400 | cFYI(1, ("Send error in rename = %d", rc)); |
1176 | } | 1401 | } |
1177 | 1402 | ||
1178 | #ifdef CONFIG_CIFS_STATS | ||
1179 | else { | ||
1180 | atomic_inc(&tcon->num_renames); | ||
1181 | } | ||
1182 | #endif | ||
1183 | |||
1184 | cifs_buf_release(pSMB); | 1403 | cifs_buf_release(pSMB); |
1185 | 1404 | ||
1186 | if (rc == -EAGAIN) | 1405 | if (rc == -EAGAIN) |
@@ -1255,14 +1474,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | |||
1255 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1474 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1256 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 1475 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, |
1257 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1476 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1477 | cifs_stats_inc(&pTcon->num_t2renames); | ||
1258 | if (rc) { | 1478 | if (rc) { |
1259 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); | 1479 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); |
1260 | } | 1480 | } |
1261 | #ifdef CONFIG_CIFS_STATS | 1481 | |
1262 | else { | ||
1263 | atomic_inc(&pTcon->num_t2renames); | ||
1264 | } | ||
1265 | #endif | ||
1266 | cifs_buf_release(pSMB); | 1482 | cifs_buf_release(pSMB); |
1267 | 1483 | ||
1268 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1484 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
@@ -1416,6 +1632,7 @@ createSymLinkRetry: | |||
1416 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1632 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1417 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1633 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1418 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1634 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1635 | cifs_stats_inc(&tcon->num_symlinks); | ||
1419 | if (rc) { | 1636 | if (rc) { |
1420 | cFYI(1, | 1637 | cFYI(1, |
1421 | ("Send error in SetPathInfo (create symlink) = %d", | 1638 | ("Send error in SetPathInfo (create symlink) = %d", |
@@ -1505,6 +1722,7 @@ createHardLinkRetry: | |||
1505 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1722 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1506 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1723 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1507 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1724 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1725 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1508 | if (rc) { | 1726 | if (rc) { |
1509 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); | 1727 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); |
1510 | } | 1728 | } |
@@ -1575,6 +1793,7 @@ winCreateHardLinkRetry: | |||
1575 | 1793 | ||
1576 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1794 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1577 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1795 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1796 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1578 | if (rc) { | 1797 | if (rc) { |
1579 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); | 1798 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); |
1580 | } | 1799 | } |
@@ -1775,8 +1994,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
1775 | } | 1994 | } |
1776 | } | 1995 | } |
1777 | qreparse_out: | 1996 | qreparse_out: |
1778 | if (pSMB) | 1997 | cifs_buf_release(pSMB); |
1779 | cifs_buf_release(pSMB); | ||
1780 | 1998 | ||
1781 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1999 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1782 | since file handle passed in no longer valid */ | 2000 | since file handle passed in no longer valid */ |
@@ -2165,6 +2383,65 @@ GetExtAttrOut: | |||
2165 | 2383 | ||
2166 | #endif /* CONFIG_POSIX */ | 2384 | #endif /* CONFIG_POSIX */ |
2167 | 2385 | ||
2386 | /* Legacy Query Path Information call for lookup to old servers such | ||
2387 | as Win9x/WinME */ | ||
2388 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
2389 | const unsigned char *searchName, | ||
2390 | FILE_ALL_INFO * pFinfo, | ||
2391 | const struct nls_table *nls_codepage, int remap) | ||
2392 | { | ||
2393 | QUERY_INFORMATION_REQ * pSMB; | ||
2394 | QUERY_INFORMATION_RSP * pSMBr; | ||
2395 | int rc = 0; | ||
2396 | int bytes_returned; | ||
2397 | int name_len; | ||
2398 | |||
2399 | cFYI(1, ("In SMBQPath path %s", searchName)); | ||
2400 | QInfRetry: | ||
2401 | rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, | ||
2402 | (void **) &pSMBr); | ||
2403 | if (rc) | ||
2404 | return rc; | ||
2405 | |||
2406 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2407 | name_len = | ||
2408 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | ||
2409 | PATH_MAX, nls_codepage, remap); | ||
2410 | name_len++; /* trailing null */ | ||
2411 | name_len *= 2; | ||
2412 | } else { | ||
2413 | name_len = strnlen(searchName, PATH_MAX); | ||
2414 | name_len++; /* trailing null */ | ||
2415 | strncpy(pSMB->FileName, searchName, name_len); | ||
2416 | } | ||
2417 | pSMB->BufferFormat = 0x04; | ||
2418 | name_len++; /* account for buffer type byte */ | ||
2419 | pSMB->hdr.smb_buf_length += (__u16) name_len; | ||
2420 | pSMB->ByteCount = cpu_to_le16(name_len); | ||
2421 | |||
2422 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2423 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2424 | if (rc) { | ||
2425 | cFYI(1, ("Send error in QueryInfo = %d", rc)); | ||
2426 | } else if (pFinfo) { /* decode response */ | ||
2427 | memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); | ||
2428 | pFinfo->AllocationSize = (__le64) pSMBr->size; | ||
2429 | pFinfo->EndOfFile = (__le64) pSMBr->size; | ||
2430 | pFinfo->Attributes = (__le32) pSMBr->attr; | ||
2431 | } else | ||
2432 | rc = -EIO; /* bad buffer passed in */ | ||
2433 | |||
2434 | cifs_buf_release(pSMB); | ||
2435 | |||
2436 | if (rc == -EAGAIN) | ||
2437 | goto QInfRetry; | ||
2438 | |||
2439 | return rc; | ||
2440 | } | ||
2441 | |||
2442 | |||
2443 | |||
2444 | |||
2168 | int | 2445 | int |
2169 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 2446 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
2170 | const unsigned char *searchName, | 2447 | const unsigned char *searchName, |
@@ -2396,7 +2673,7 @@ findUniqueRetry: | |||
2396 | if (rc) { | 2673 | if (rc) { |
2397 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); | 2674 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); |
2398 | } else { /* decode response */ | 2675 | } else { /* decode response */ |
2399 | 2676 | cifs_stats_inc(&tcon->num_ffirst); | |
2400 | /* BB fill in */ | 2677 | /* BB fill in */ |
2401 | } | 2678 | } |
2402 | 2679 | ||
@@ -2414,7 +2691,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | |||
2414 | const char *searchName, | 2691 | const char *searchName, |
2415 | const struct nls_table *nls_codepage, | 2692 | const struct nls_table *nls_codepage, |
2416 | __u16 * pnetfid, | 2693 | __u16 * pnetfid, |
2417 | struct cifs_search_info * psrch_inf, int remap) | 2694 | struct cifs_search_info * psrch_inf, int remap, const char dirsep) |
2418 | { | 2695 | { |
2419 | /* level 257 SMB_ */ | 2696 | /* level 257 SMB_ */ |
2420 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 2697 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; |
@@ -2441,7 +2718,7 @@ findFirstRetry: | |||
2441 | it got remapped to 0xF03A as if it were part of the | 2718 | it got remapped to 0xF03A as if it were part of the |
2442 | directory name instead of a wildcard */ | 2719 | directory name instead of a wildcard */ |
2443 | name_len *= 2; | 2720 | name_len *= 2; |
2444 | pSMB->FileName[name_len] = '\\'; | 2721 | pSMB->FileName[name_len] = dirsep; |
2445 | pSMB->FileName[name_len+1] = 0; | 2722 | pSMB->FileName[name_len+1] = 0; |
2446 | pSMB->FileName[name_len+2] = '*'; | 2723 | pSMB->FileName[name_len+2] = '*'; |
2447 | pSMB->FileName[name_len+3] = 0; | 2724 | pSMB->FileName[name_len+3] = 0; |
@@ -2455,7 +2732,7 @@ findFirstRetry: | |||
2455 | if(name_len > buffersize-header) | 2732 | if(name_len > buffersize-header) |
2456 | free buffer exit; BB */ | 2733 | free buffer exit; BB */ |
2457 | strncpy(pSMB->FileName, searchName, name_len); | 2734 | strncpy(pSMB->FileName, searchName, name_len); |
2458 | pSMB->FileName[name_len] = '\\'; | 2735 | pSMB->FileName[name_len] = dirsep; |
2459 | pSMB->FileName[name_len+1] = '*'; | 2736 | pSMB->FileName[name_len+1] = '*'; |
2460 | pSMB->FileName[name_len+2] = 0; | 2737 | pSMB->FileName[name_len+2] = 0; |
2461 | name_len += 3; | 2738 | name_len += 3; |
@@ -2496,6 +2773,7 @@ findFirstRetry: | |||
2496 | 2773 | ||
2497 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2774 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2498 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2775 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2776 | cifs_stats_inc(&tcon->num_ffirst); | ||
2499 | 2777 | ||
2500 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ | 2778 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ |
2501 | /* BB Add code to handle unsupported level rc */ | 2779 | /* BB Add code to handle unsupported level rc */ |
@@ -2617,7 +2895,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
2617 | 2895 | ||
2618 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2896 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2619 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2897 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2620 | 2898 | cifs_stats_inc(&tcon->num_fnext); | |
2621 | if (rc) { | 2899 | if (rc) { |
2622 | if (rc == -EBADF) { | 2900 | if (rc == -EBADF) { |
2623 | psrch_inf->endOfSearch = TRUE; | 2901 | psrch_inf->endOfSearch = TRUE; |
@@ -2694,6 +2972,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle | |||
2694 | if (rc) { | 2972 | if (rc) { |
2695 | cERROR(1, ("Send error in FindClose = %d", rc)); | 2973 | cERROR(1, ("Send error in FindClose = %d", rc)); |
2696 | } | 2974 | } |
2975 | cifs_stats_inc(&tcon->num_fclose); | ||
2697 | cifs_small_buf_release(pSMB); | 2976 | cifs_small_buf_release(pSMB); |
2698 | 2977 | ||
2699 | /* Since session is dead, search handle closed on server already */ | 2978 | /* Since session is dead, search handle closed on server already */ |
@@ -2827,7 +3106,10 @@ getDFSRetry: | |||
2827 | (void **) &pSMBr); | 3106 | (void **) &pSMBr); |
2828 | if (rc) | 3107 | if (rc) |
2829 | return rc; | 3108 | return rc; |
2830 | 3109 | ||
3110 | /* server pointer checked in called function, | ||
3111 | but should never be null here anyway */ | ||
3112 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
2831 | pSMB->hdr.Tid = ses->ipc_tid; | 3113 | pSMB->hdr.Tid = ses->ipc_tid; |
2832 | pSMB->hdr.Uid = ses->Suid; | 3114 | pSMB->hdr.Uid = ses->Suid; |
2833 | if (ses->capabilities & CAP_STATUS32) { | 3115 | if (ses->capabilities & CAP_STATUS32) { |
@@ -3257,6 +3539,77 @@ QFSUnixRetry: | |||
3257 | return rc; | 3539 | return rc; |
3258 | } | 3540 | } |
3259 | 3541 | ||
3542 | int | ||
3543 | CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | ||
3544 | { | ||
3545 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | ||
3546 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | ||
3547 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | ||
3548 | int rc = 0; | ||
3549 | int bytes_returned = 0; | ||
3550 | __u16 params, param_offset, offset, byte_count; | ||
3551 | |||
3552 | cFYI(1, ("In SETFSUnixInfo")); | ||
3553 | SETFSUnixRetry: | ||
3554 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3555 | (void **) &pSMBr); | ||
3556 | if (rc) | ||
3557 | return rc; | ||
3558 | |||
3559 | params = 4; /* 2 bytes zero followed by info level. */ | ||
3560 | pSMB->MaxSetupCount = 0; | ||
3561 | pSMB->Reserved = 0; | ||
3562 | pSMB->Flags = 0; | ||
3563 | pSMB->Timeout = 0; | ||
3564 | pSMB->Reserved2 = 0; | ||
3565 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; | ||
3566 | offset = param_offset + params; | ||
3567 | |||
3568 | pSMB->MaxParameterCount = cpu_to_le16(4); | ||
3569 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3570 | pSMB->SetupCount = 1; | ||
3571 | pSMB->Reserved3 = 0; | ||
3572 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | ||
3573 | byte_count = 1 /* pad */ + params + 12; | ||
3574 | |||
3575 | pSMB->DataCount = cpu_to_le16(12); | ||
3576 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3577 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3578 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3579 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3580 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3581 | |||
3582 | /* Params. */ | ||
3583 | pSMB->FileNum = 0; | ||
3584 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | ||
3585 | |||
3586 | /* Data. */ | ||
3587 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | ||
3588 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | ||
3589 | pSMB->ClientUnixCap = cpu_to_le64(cap); | ||
3590 | |||
3591 | pSMB->hdr.smb_buf_length += byte_count; | ||
3592 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3593 | |||
3594 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3595 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3596 | if (rc) { | ||
3597 | cERROR(1, ("Send error in SETFSUnixInfo = %d", rc)); | ||
3598 | } else { /* decode response */ | ||
3599 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3600 | if (rc) { | ||
3601 | rc = -EIO; /* bad smb */ | ||
3602 | } | ||
3603 | } | ||
3604 | cifs_buf_release(pSMB); | ||
3605 | |||
3606 | if (rc == -EAGAIN) | ||
3607 | goto SETFSUnixRetry; | ||
3608 | |||
3609 | return rc; | ||
3610 | } | ||
3611 | |||
3612 | |||
3260 | 3613 | ||
3261 | int | 3614 | int |
3262 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3615 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
@@ -3839,12 +4192,14 @@ setPermsRetry: | |||
3839 | } | 4192 | } |
3840 | 4193 | ||
3841 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 4194 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
3842 | const int notify_subdirs, const __u16 netfid, | 4195 | const int notify_subdirs, const __u16 netfid, |
3843 | __u32 filter, const struct nls_table *nls_codepage) | 4196 | __u32 filter, struct file * pfile, int multishot, |
4197 | const struct nls_table *nls_codepage) | ||
3844 | { | 4198 | { |
3845 | int rc = 0; | 4199 | int rc = 0; |
3846 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | 4200 | struct smb_com_transaction_change_notify_req * pSMB = NULL; |
3847 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | 4201 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; |
4202 | struct dir_notify_req *dnotify_req; | ||
3848 | int bytes_returned; | 4203 | int bytes_returned; |
3849 | 4204 | ||
3850 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); | 4205 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); |
@@ -3877,6 +4232,22 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
3877 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | 4232 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); |
3878 | if (rc) { | 4233 | if (rc) { |
3879 | cFYI(1, ("Error in Notify = %d", rc)); | 4234 | cFYI(1, ("Error in Notify = %d", rc)); |
4235 | } else { | ||
4236 | /* Add file to outstanding requests */ | ||
4237 | dnotify_req = (struct dir_notify_req *) kmalloc( | ||
4238 | sizeof(struct dir_notify_req), GFP_KERNEL); | ||
4239 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
4240 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
4241 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
4242 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
4243 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
4244 | dnotify_req->netfid = netfid; | ||
4245 | dnotify_req->pfile = pfile; | ||
4246 | dnotify_req->filter = filter; | ||
4247 | dnotify_req->multishot = multishot; | ||
4248 | spin_lock(&GlobalMid_Lock); | ||
4249 | list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList); | ||
4250 | spin_unlock(&GlobalMid_Lock); | ||
3880 | } | 4251 | } |
3881 | cifs_buf_release(pSMB); | 4252 | cifs_buf_release(pSMB); |
3882 | return rc; | 4253 | return rc; |