[CIFS] Readdir fixes to allow search to start at arbitrary position in directory

Also includes first part of fix to compensate for servers which forget
to return . and .. as well as updates to changelog and cifs readme.

Signed-off-by: Steve French <sfrench@us.ibm.com>

+74 -36
+5 -1
fs/cifs/CHANGES
··· 1 Version 1.42 2 ------------ 3 Fix slow oplock break when mounted to different servers at the same time and 4 - the tids match and we try to find matching fid on wrong server. 5 6 Version 1.41 7 ------------
··· 1 Version 1.42 2 ------------ 3 Fix slow oplock break when mounted to different servers at the same time and 4 + the tids match and we try to find matching fid on wrong server. Fix read 5 + looping when signing required by server (2.6.16 kernel only). Fix readdir 6 + vs. rename race which could cause each to hang. Return . and .. even 7 + if server does not. Allow searches to skip first three entries and 8 + begin at any location. Fix oops in find_writeable_file. 9 10 Version 1.41 11 ------------
+8
fs/cifs/README
··· 511 support and want to map the uid and gid fields 512 to values supplied at mount (rather than the 513 actual values, then set this to zero. (default 1) 514 515 These experimental features and tracing can be enabled by changing flags in 516 /proc/fs/cifs (after the cifs module has been installed or built into the
··· 511 support and want to map the uid and gid fields 512 to values supplied at mount (rather than the 513 actual values, then set this to zero. (default 1) 514 + Experimental When set to 1 used to enable certain experimental 515 + features (currently enables multipage writes 516 + when signing is enabled, the multipage write 517 + performance enhancement was disabled when 518 + signing turned on in case buffer was modified 519 + just before it was sent, also this flag will 520 + be used to use the new experimental sessionsetup 521 + code). 522 523 These experimental features and tracing can be enabled by changing flags in 524 /proc/fs/cifs (after the cifs module has been installed or built into the
+1 -1
fs/cifs/cifssmb.c
··· 3119 psrch_inf->endOfSearch = FALSE; 3120 3121 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); 3122 - psrch_inf->index_of_last_entry = 3123 psrch_inf->entries_in_buffer; 3124 *pnetfid = parms->SearchHandle; 3125 } else {
··· 3119 psrch_inf->endOfSearch = FALSE; 3120 3121 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); 3122 + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + 3123 psrch_inf->entries_in_buffer; 3124 *pnetfid = parms->SearchHandle; 3125 } else {
+4 -1
fs/cifs/connect.c
··· 3447 pSesInfo->server->secMode, 3448 pSesInfo->server->capabilities, 3449 pSesInfo->server->timeZone)); 3450 - if (extended_security 3451 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) 3452 && (pSesInfo->server->secType == NTLMSSP)) { 3453 cFYI(1, ("New style sesssetup"));
··· 3447 pSesInfo->server->secMode, 3448 pSesInfo->server->capabilities, 3449 pSesInfo->server->timeZone)); 3450 + if(experimEnabled > 1) 3451 + rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, 3452 + &ntlmv2_flag, nls_info); 3453 + else if (extended_security 3454 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) 3455 && (pSesInfo->server->secType == NTLMSSP)) { 3456 cFYI(1, ("New style sesssetup"));
+20 -12
fs/cifs/file.c
··· 904 if (rc != 0) 905 break; 906 } 907 - /* BB FIXME We can not sign across two buffers yet */ 908 - if((pTcon->ses->server->secMode & 909 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { 910 struct kvec iov[2]; 911 unsigned int len; ··· 920 *poffset, &bytes_written, 921 iov, 1, long_op); 922 } else 923 - /* BB FIXME fixup indentation of line below */ 924 - rc = CIFSSMBWrite(xid, pTcon, 925 - open_file->netfid, 926 - min_t(const int, cifs_sb->wsize, 927 - write_size - total_written), 928 - *poffset, &bytes_written, 929 - write_data + total_written, NULL, long_op); 930 } 931 if (rc || (bytes_written == 0)) { 932 if (total_written) ··· 964 { 965 struct cifsFileInfo *open_file; 966 int rc; 967 968 read_lock(&GlobalSMBSeslock); 969 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { ··· 1100 if (cifs_sb->wsize < PAGE_CACHE_SIZE) 1101 return generic_writepages(mapping, wbc); 1102 1103 - /* BB FIXME we do not have code to sign across multiple buffers yet, 1104 - so go to older writepage style write which we can sign if needed */ 1105 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) 1106 if(cifs_sb->tcon->ses->server->secMode & 1107 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 1108 - return generic_writepages(mapping, wbc); 1109 1110 /* 1111 * BB: Is this meaningful for a non-block-device file system?
··· 904 if (rc != 0) 905 break; 906 } 907 + if(experimEnabled || (pTcon->ses->server->secMode & 908 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { 909 struct kvec iov[2]; 910 unsigned int len; ··· 921 *poffset, &bytes_written, 922 iov, 1, long_op); 923 } else 924 + rc = CIFSSMBWrite(xid, pTcon, 925 + open_file->netfid, 926 + min_t(const int, cifs_sb->wsize, 927 + write_size - total_written), 928 + *poffset, &bytes_written, 929 + write_data + total_written, 930 + NULL, long_op); 931 } 932 if (rc || (bytes_written == 0)) { 933 if (total_written) ··· 965 { 966 struct cifsFileInfo *open_file; 967 int rc; 968 + 969 + /* Having a null inode here (because mapping->host was set to zero by 970 + the VFS or MM) should not happen but we had reports of on oops (due to 971 + it being zero) during stress testcases so we need to check for it */ 972 + 973 + if(cifs_inode == NULL) { 974 + cERROR(1,("Null inode passed to cifs_writeable_file")); 975 + dump_stack(); 976 + return NULL; 977 + } 978 979 read_lock(&GlobalSMBSeslock); 980 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { ··· 1091 if (cifs_sb->wsize < PAGE_CACHE_SIZE) 1092 return generic_writepages(mapping, wbc); 1093 1094 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) 1095 if(cifs_sb->tcon->ses->server->secMode & 1096 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 1097 + if(!experimEnabled) 1098 + return generic_writepages(mapping, wbc); 1099 1100 /* 1101 * BB: Is this meaningful for a non-block-device file system?
+14
fs/cifs/ntlmssp.c
··· 121 } 122 123 124 /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ 125 /* SMB request buf freed in SendReceive2 */ 126
··· 121 } 122 123 124 + /* copy session key */ 125 + 126 + /* if Unicode, align strings to two byte boundary */ 127 + 128 + /* copy user name */ /* BB Do we need to special case null user name? */ 129 + 130 + /* copy domain name */ 131 + 132 + /* copy Linux version */ 133 + 134 + /* copy network operating system name */ 135 + 136 + /* update bcc and smb buffer length */ 137 + 138 /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ 139 /* SMB request buf freed in SendReceive2 */ 140
+22 -21
fs/cifs/readdir.c
··· 590 first_entry_in_buffer = 591 cifsFile->srch_inf.index_of_last_entry - 592 cifsFile->srch_inf.entries_in_buffer; 593 /* dump_cifs_file_struct(file, "In fce ");*/ 594 if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 595 is_dir_changed(file)) || ··· 639 char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 640 smbCalcSize((struct smb_hdr *) 641 cifsFile->srch_inf.ntwrk_buf_start); 642 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 643 - cifsFile->srch_inf.entries_in_buffer; 644 pos_in_buf = index_to_find - first_entry_in_buffer; 645 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 646 - current_entry = cifsFile->srch_inf.srch_entries_start; 647 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 648 /* go entry by entry figuring out which is first */ 649 - /* if( . or ..) 650 - skip */ 651 - rc = cifs_entry_is_dot(current_entry,cifsFile); 652 - if(rc == 1) /* is . or .. so skip */ { 653 - cFYI(1,("Entry is .")); /* BB removeme BB */ 654 - /* continue; */ 655 - } else if (rc == 2 ) { 656 - cFYI(1,("Entry is ..")); /* BB removeme BB */ 657 - /* continue; */ 658 - } 659 current_entry = nxt_dir_entry(current_entry,end_of_smb); 660 } 661 if((current_entry == NULL) && (i < pos_in_buf)) { ··· 765 766 if(file->f_dentry == NULL) 767 return -ENOENT; 768 769 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 770 ··· 899 900 switch ((int) file->f_pos) { 901 case 0: 902 - /*if (filldir(direntry, ".", 1, file->f_pos, 903 file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { 904 - cERROR(1, ("Filldir for current dir failed ")); 905 rc = -ENOMEM; 906 break; 907 } 908 - file->f_pos++; */ 909 case 1: 910 - /* if (filldir(direntry, "..", 2, file->f_pos, 911 file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 912 cERROR(1, ("Filldir for parent dir failed ")); 913 rc = -ENOMEM; 914 break; 915 } 916 - file->f_pos++; */ 917 - case 2: 918 /* 1) If search is active, 919 is in current search buffer? 920 if it before then restart search ··· 928 return rc; 929 } 930 } 931 - default: 932 if(file->private_data == NULL) { 933 rc = -EINVAL; 934 FreeXid(xid); ··· 946 } 947 kfree(cifsFile->search_resume_name); 948 cifsFile->search_resume_name = NULL; */ 949 - 950 - /* BB account for . and .. in f_pos as special case */ 951 952 rc = find_cifs_entry(xid,pTcon, file, 953 &current_entry,&num_to_fill); ··· 975 num_to_fill, i)); 976 break; 977 } 978 - 979 rc = cifs_filldir(current_entry, file, 980 filldir, direntry,tmp_buf); 981 file->f_pos++;
··· 590 first_entry_in_buffer = 591 cifsFile->srch_inf.index_of_last_entry - 592 cifsFile->srch_inf.entries_in_buffer; 593 + 594 + /* if first entry in buf is zero then is first buffer 595 + in search response data which means it is likely . and .. 596 + will be in this buffer, although some servers do not return 597 + . and .. for the root of a drive and for those we need 598 + to start two entries earlier */ 599 + 600 /* dump_cifs_file_struct(file, "In fce ");*/ 601 if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 602 is_dir_changed(file)) || ··· 632 char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 633 smbCalcSize((struct smb_hdr *) 634 cifsFile->srch_inf.ntwrk_buf_start); 635 + 636 + current_entry = cifsFile->srch_inf.srch_entries_start; 637 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 638 - cifsFile->srch_inf.entries_in_buffer; 639 pos_in_buf = index_to_find - first_entry_in_buffer; 640 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 641 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 642 /* go entry by entry figuring out which is first */ 643 current_entry = nxt_dir_entry(current_entry,end_of_smb); 644 } 645 if((current_entry == NULL) && (i < pos_in_buf)) { ··· 767 768 if(file->f_dentry == NULL) 769 return -ENOENT; 770 + 771 + rc = cifs_entry_is_dot(pfindEntry,cifsF); 772 + /* skip . and .. since we added them first */ 773 + if(rc != 0) 774 + return 0; 775 776 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 777 ··· 896 897 switch ((int) file->f_pos) { 898 case 0: 899 + if (filldir(direntry, ".", 1, file->f_pos, 900 file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { 901 + cERROR(1, ("Filldir for current dir failed")); 902 rc = -ENOMEM; 903 break; 904 } 905 + file->f_pos++; 906 case 1: 907 + if (filldir(direntry, "..", 2, file->f_pos, 908 file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 909 cERROR(1, ("Filldir for parent dir failed ")); 910 rc = -ENOMEM; 911 break; 912 } 913 + file->f_pos++; 914 + default: 915 /* 1) If search is active, 916 is in current search buffer? 917 if it before then restart search ··· 925 return rc; 926 } 927 } 928 if(file->private_data == NULL) { 929 rc = -EINVAL; 930 FreeXid(xid); ··· 944 } 945 kfree(cifsFile->search_resume_name); 946 cifsFile->search_resume_name = NULL; */ 947 948 rc = find_cifs_entry(xid,pTcon, file, 949 &current_entry,&num_to_fill); ··· 975 num_to_fill, i)); 976 break; 977 } 978 + /* if buggy server returns . and .. late do 979 + we want to check for that here? */ 980 rc = cifs_filldir(current_entry, file, 981 filldir, direntry,tmp_buf); 982 file->f_pos++;