[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 1 Version 1.42 2 2 ------------ 3 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. 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. 5 9 6 10 Version 1.41 7 11 ------------
+8
fs/cifs/README
··· 511 511 support and want to map the uid and gid fields 512 512 to values supplied at mount (rather than the 513 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). 514 522 515 523 These experimental features and tracing can be enabled by changing flags in 516 524 /proc/fs/cifs (after the cifs module has been installed or built into the
+1 -1
fs/cifs/cifssmb.c
··· 3119 3119 psrch_inf->endOfSearch = FALSE; 3120 3120 3121 3121 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); 3122 - psrch_inf->index_of_last_entry = 3122 + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + 3123 3123 psrch_inf->entries_in_buffer; 3124 3124 *pnetfid = parms->SearchHandle; 3125 3125 } else {
+4 -1
fs/cifs/connect.c
··· 3447 3447 pSesInfo->server->secMode, 3448 3448 pSesInfo->server->capabilities, 3449 3449 pSesInfo->server->timeZone)); 3450 - if (extended_security 3450 + if(experimEnabled > 1) 3451 + rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, 3452 + &ntlmv2_flag, nls_info); 3453 + else if (extended_security 3451 3454 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) 3452 3455 && (pSesInfo->server->secType == NTLMSSP)) { 3453 3456 cFYI(1, ("New style sesssetup"));
+20 -12
fs/cifs/file.c
··· 904 904 if (rc != 0) 905 905 break; 906 906 } 907 - /* BB FIXME We can not sign across two buffers yet */ 908 - if((pTcon->ses->server->secMode & 907 + if(experimEnabled || (pTcon->ses->server->secMode & 909 908 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { 910 909 struct kvec iov[2]; 911 910 unsigned int len; ··· 920 921 *poffset, &bytes_written, 921 922 iov, 1, long_op); 922 923 } 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); 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); 930 931 } 931 932 if (rc || (bytes_written == 0)) { 932 933 if (total_written) ··· 964 965 { 965 966 struct cifsFileInfo *open_file; 966 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 + } 967 978 968 979 read_lock(&GlobalSMBSeslock); 969 980 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { ··· 1100 1091 if (cifs_sb->wsize < PAGE_CACHE_SIZE) 1101 1092 return generic_writepages(mapping, wbc); 1102 1093 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 1094 if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) 1106 1095 if(cifs_sb->tcon->ses->server->secMode & 1107 1096 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 1108 - return generic_writepages(mapping, wbc); 1097 + if(!experimEnabled) 1098 + return generic_writepages(mapping, wbc); 1109 1099 1110 1100 /* 1111 1101 * BB: Is this meaningful for a non-block-device file system?
+14
fs/cifs/ntlmssp.c
··· 121 121 } 122 122 123 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 + 124 138 /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ 125 139 /* SMB request buf freed in SendReceive2 */ 126 140
+22 -21
fs/cifs/readdir.c
··· 590 590 first_entry_in_buffer = 591 591 cifsFile->srch_inf.index_of_last_entry - 592 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 + 593 600 /* dump_cifs_file_struct(file, "In fce ");*/ 594 601 if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 595 602 is_dir_changed(file)) || ··· 639 632 char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 640 633 smbCalcSize((struct smb_hdr *) 641 634 cifsFile->srch_inf.ntwrk_buf_start); 635 + 636 + current_entry = cifsFile->srch_inf.srch_entries_start; 642 637 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry 643 638 - cifsFile->srch_inf.entries_in_buffer; 644 639 pos_in_buf = index_to_find - first_entry_in_buffer; 645 640 cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 646 - current_entry = cifsFile->srch_inf.srch_entries_start; 647 641 for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { 648 642 /* 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 643 current_entry = nxt_dir_entry(current_entry,end_of_smb); 660 644 } 661 645 if((current_entry == NULL) && (i < pos_in_buf)) { ··· 765 767 766 768 if(file->f_dentry == NULL) 767 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; 768 775 769 776 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 770 777 ··· 899 896 900 897 switch ((int) file->f_pos) { 901 898 case 0: 902 - /*if (filldir(direntry, ".", 1, file->f_pos, 899 + if (filldir(direntry, ".", 1, file->f_pos, 903 900 file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { 904 - cERROR(1, ("Filldir for current dir failed ")); 901 + cERROR(1, ("Filldir for current dir failed")); 905 902 rc = -ENOMEM; 906 903 break; 907 904 } 908 - file->f_pos++; */ 905 + file->f_pos++; 909 906 case 1: 910 - /* if (filldir(direntry, "..", 2, file->f_pos, 907 + if (filldir(direntry, "..", 2, file->f_pos, 911 908 file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 912 909 cERROR(1, ("Filldir for parent dir failed ")); 913 910 rc = -ENOMEM; 914 911 break; 915 912 } 916 - file->f_pos++; */ 917 - case 2: 913 + file->f_pos++; 914 + default: 918 915 /* 1) If search is active, 919 916 is in current search buffer? 920 917 if it before then restart search ··· 928 925 return rc; 929 926 } 930 927 } 931 - default: 932 928 if(file->private_data == NULL) { 933 929 rc = -EINVAL; 934 930 FreeXid(xid); ··· 946 944 } 947 945 kfree(cifsFile->search_resume_name); 948 946 cifsFile->search_resume_name = NULL; */ 949 - 950 - /* BB account for . and .. in f_pos as special case */ 951 947 952 948 rc = find_cifs_entry(xid,pTcon, file, 953 949 &current_entry,&num_to_fill); ··· 975 975 num_to_fill, i)); 976 976 break; 977 977 } 978 - 978 + /* if buggy server returns . and .. late do 979 + we want to check for that here? */ 979 980 rc = cifs_filldir(current_entry, file, 980 981 filldir, direntry,tmp_buf); 981 982 file->f_pos++;