Version 1.42
 ------------
 Fix slow oplock break when mounted to different servers at the same time and
-the tids match and we try to find matching fid on wrong server.
+the tids match and we try to find matching fid on wrong server. Fix read
+looping when signing required by server (2.6.16 kernel only). Fix readdir
+vs. rename race which could cause each to hang. Return . and .. even
+if server does not.  Allow searches to skip first three entries and
+begin at any location. Fix oops in find_writeable_file.
 
 Version 1.41
 ------------
 
                        support and want to map the uid and gid fields 
                        to values supplied at mount (rather than the 
                        actual values, then set this to zero. (default 1)
+Experimental            When set to 1 used to enable certain experimental
+                       features (currently enables multipage writes
+                       when signing is enabled, the multipage write
+                       performance enhancement was disabled when
+                       signing turned on in case buffer was modified
+                       just before it was sent, also this flag will
+                       be used to use the new experimental sessionsetup
+                       code).
 
 These experimental features and tracing can be enabled by changing flags in 
 /proc/fs/cifs (after the cifs module has been installed or built into the 
 
                                psrch_inf->endOfSearch = FALSE;
 
                        psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
-                       psrch_inf->index_of_last_entry = 
+                       psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
                        *pnetfid = parms->SearchHandle;
                } else {
 
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeZone));
-               if (extended_security
+               if(experimEnabled > 1)
+                       rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
+                                           &ntlmv2_flag, nls_info);    
+               else if (extended_security
                                && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
                        cFYI(1, ("New style sesssetup"));
 
                                if (rc != 0)
                                        break;
                        }
-                       /* BB FIXME We can not sign across two buffers yet */
-                       if((pTcon->ses->server->secMode & 
+                       if(experimEnabled || (pTcon->ses->server->secMode & 
                         (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) {
                                struct kvec iov[2];
                                unsigned int len;
                                                *poffset, &bytes_written,
                                                iov, 1, long_op);
                        } else
-                       /* BB FIXME fixup indentation of line below */
-                       rc = CIFSSMBWrite(xid, pTcon,
-                                open_file->netfid,
-                                min_t(const int, cifs_sb->wsize, 
-                                      write_size - total_written),
-                                *poffset, &bytes_written,
-                                write_data + total_written, NULL, long_op);
+                               rc = CIFSSMBWrite(xid, pTcon,
+                                        open_file->netfid,
+                                        min_t(const int, cifs_sb->wsize,
+                                              write_size - total_written),
+                                        *poffset, &bytes_written,
+                                        write_data + total_written,
+                                        NULL, long_op);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
        struct cifsFileInfo *open_file;
        int rc;
 
+       /* Having a null inode here (because mapping->host was set to zero by
+       the VFS or MM) should not happen but we had reports of on oops (due to
+       it being zero) during stress testcases so we need to check for it */
+
+       if(cifs_inode == NULL) {
+               cERROR(1,("Null inode passed to cifs_writeable_file"));
+               dump_stack();
+               return NULL;
+       }
+
        read_lock(&GlobalSMBSeslock);
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
                if (open_file->closePend)
        if (cifs_sb->wsize < PAGE_CACHE_SIZE)
                return generic_writepages(mapping, wbc);
 
-       /* BB FIXME we do not have code to sign across multiple buffers yet,
-          so go to older writepage style write which we can sign if needed */
        if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
                if(cifs_sb->tcon->ses->server->secMode &
                           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       return generic_writepages(mapping, wbc);
+                       if(!experimEnabled)
+                               return generic_writepages(mapping, wbc);
 
        /*
         * BB: Is this meaningful for a non-block-device file system?
 
        }
 
 
+       /* copy session key */
+
+       /* if Unicode, align strings to two byte boundary */
+
+       /* copy user name */ /* BB Do we need to special case null user name? */
+
+       /* copy domain name */
+
+       /* copy Linux version */
+
+       /* copy network operating system name */
+
+       /* update bcc and smb buffer length */
+
 /*     rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
        /* SMB request buf freed in SendReceive2 */
 
 
        first_entry_in_buffer = 
                cifsFile->srch_inf.index_of_last_entry - 
                        cifsFile->srch_inf.entries_in_buffer;
+
+       /* if first entry in buf is zero then is first buffer
+       in search response data which means it is likely . and ..
+       will be in this buffer, although some servers do not return
+       . and .. for the root of a drive and for those we need
+       to start two entries earlier */
+
 /*     dump_cifs_file_struct(file, "In fce ");*/
        if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
             is_dir_changed(file)) || 
                char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
                        smbCalcSize((struct smb_hdr *)
                                cifsFile->srch_inf.ntwrk_buf_start);
+
+               current_entry = cifsFile->srch_inf.srch_entries_start;
                first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
                                        - cifsFile->srch_inf.entries_in_buffer;
                pos_in_buf = index_to_find - first_entry_in_buffer;
                cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
-               current_entry = cifsFile->srch_inf.srch_entries_start;
                for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
                        /* go entry by entry figuring out which is first */
-                       /* if( . or ..)
-                               skip */
-                       rc = cifs_entry_is_dot(current_entry,cifsFile);
-                       if(rc == 1) /* is . or .. so skip */ {
-                               cFYI(1,("Entry is .")); /* BB removeme BB */
-                               /* continue; */
-                       } else if (rc == 2 ) {
-                               cFYI(1,("Entry is ..")); /* BB removeme BB */
-                               /* continue; */
-                       }
                        current_entry = nxt_dir_entry(current_entry,end_of_smb);
                }
                if((current_entry == NULL) && (i < pos_in_buf)) {
        if(file->f_dentry == NULL)
                return -ENOENT;
 
+       rc = cifs_entry_is_dot(pfindEntry,cifsF);
+       /* skip . and .. since we added them first */
+       if(rc != 0) 
+               return 0;
+
        cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 
        qstring.name = scratch_buf;
 
        switch ((int) file->f_pos) {
        case 0:
-               /*if (filldir(direntry, ".", 1, file->f_pos,
+               if (filldir(direntry, ".", 1, file->f_pos,
                     file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
-                       cERROR(1, ("Filldir for current dir failed "));
+                       cERROR(1, ("Filldir for current dir failed"));
                        rc = -ENOMEM;
                        break;
                }
-               file->f_pos++; */
+               file->f_pos++;
        case 1:
-               /* if (filldir(direntry, "..", 2, file->f_pos,
+               if (filldir(direntry, "..", 2, file->f_pos,
                     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
                        cERROR(1, ("Filldir for parent dir failed "));
                        rc = -ENOMEM;
                        break;
                }
-               file->f_pos++; */
-       case 2:
+               file->f_pos++;
+       default:
                /* 1) If search is active, 
                        is in current search buffer? 
                        if it before then restart search
                                return rc;
                        }
                }
-       default:
                if(file->private_data == NULL) {
                        rc = -EINVAL;
                        FreeXid(xid);
                kfree(cifsFile->search_resume_name);
                cifsFile->search_resume_name = NULL; */
 
-               /* BB account for . and .. in f_pos as special case */
-
                rc = find_cifs_entry(xid,pTcon, file,
                                ¤t_entry,&num_to_fill);
                if(rc) {
                                          num_to_fill, i));
                                break;
                        }
-
+                       /* if buggy server returns . and .. late do
+                       we want to check for that here? */
                        rc = cifs_filldir(current_entry, file, 
                                        filldir, direntry,tmp_buf);
                        file->f_pos++;