[CIFS] Readdir fixes to allow search to start at arbitrary position
authorSteve French <sfrench@us.ibm.com>
Sat, 22 Apr 2006 15:53:05 +0000 (15:53 +0000)
committerSteve French <sfrench@us.ibm.com>
Sat, 22 Apr 2006 15:53:05 +0000 (15:53 +0000)
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>
fs/cifs/CHANGES
fs/cifs/README
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/ntlmssp.c
fs/cifs/readdir.c

index 8a2de038882e32bb881e53c92171e5967e073a42..1a27ecb46c9a71d7458b9119b345a8a4f6ec104c 100644 (file)
@@ -1,7 +1,11 @@
 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
 ------------
index b2b4d0803761b82ed937d795bdecf539ac35a9b4..0355003f4f0a3b69eb021606d96f9e5261480c40 100644 (file)
@@ -511,6 +511,14 @@ LinuxExtensionsEnabled     If set to one then the client will attempt to
                        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 
index d705500aa283ab7170f42d9ff654668d1b1ad6a6..fd36892eda55a282fc207842e0ff62787c746703 100644 (file)
@@ -3119,7 +3119,7 @@ findFirstRetry:
                                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 {
index 0b86d5ca90143be659add6e82b29282b6279b764..aaf151cb5822b35c3e95eb04ec99a1036a4ea6da 100644 (file)
@@ -3447,7 +3447,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        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"));
index 1476725e6051b3d06d13da91d00c08afe8814c1b..e152bf6afa60fadc91c2080231858d9b5653f0fb 100644 (file)
@@ -904,8 +904,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                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;
@@ -921,13 +920,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                                *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)
@@ -966,6 +965,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
        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)
@@ -1091,12 +1100,11 @@ static int cifs_writepages(struct address_space *mapping,
        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?
index 78866f9257474ad8049ef5694748ac94cbcea0c3..115359cc7a32ce6cb5332435688bcaba5ee56397 100644 (file)
@@ -121,6 +121,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
        }
 
 
+       /* 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 */
 
index 7b8591acc5ada648fc1f4d3cd67d33f050ac9b08..41c022e3c1325caf75a772de5679eeef0734e012 100644 (file)
@@ -590,6 +590,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
        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)) || 
@@ -632,23 +639,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                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)) {
@@ -768,6 +766,11 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        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;
@@ -896,22 +899,22 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 
        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
@@ -925,7 +928,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                                return rc;
                        }
                }
-       default:
                if(file->private_data == NULL) {
                        rc = -EINVAL;
                        FreeXid(xid);
@@ -945,8 +947,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                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,
                                &current_entry,&num_to_fill);
                if(rc) {
@@ -975,7 +975,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                                          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++;