]> git.hungrycats.org Git - linux/commitdiff
Fix oops in getdfs when null path passed in on mount. Fix oops when changed readsize...
authorSteve French <stevef@smfhome1.austin.rr.com>
Fri, 7 Mar 2003 11:01:46 +0000 (05:01 -0600)
committerSteve French <stevef@steveft21.austin.ibm.com>
Fri, 7 Mar 2003 11:01:46 +0000 (05:01 -0600)
below default of 4

fs/cifs/CHANGES
fs/cifs/TODO
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/transport.c

index 10bb570f2c586ad57fcd309b80d721b0baa568f2..c6dc9ba2b0d7e305aff2563fdf898d2a4b903492 100644 (file)
@@ -1,3 +1,8 @@
+Version 0.70
+------------
+Fix oops in get dfs referral (triggered when null path sent in to
+mount).  Add support for overriding rsize at mount time.
+
 Version 0.69
 ------------
 Fix buffer overrun in readdir which caused intermittent kernel oopses.
index d962087d3b04d1e32e320db9b15bb2ef4500d475..99b4d92af60e0cf35932a00c624cb95324670cfe 100644 (file)
@@ -42,13 +42,24 @@ extra copy in/out of the socket buffers in some cases.
 
 m) finish support for IPv6
 
-KNOWN BUGS (updated February 15, 2003)
+n) send oplock break response when sent (oplock currently disabled in
+/proc/fs/cifs)
+
+o) remove calls to set end of file by name when we already have file open
+(use the existing handle since some servers only support that and it
+reduces the oplock breaks coming from windows).  Piggyback identical
+file opens on top of each other by incrementing reference count rather
+than resending (helps reduce server resource utilization and avoid
+spurious oplock breaks).
+
+KNOWN BUGS (updated March 7, 2003)
 ====================================
 1) existing symbolic links (Windows reparse points) are recognized but
 can not be created remotely. They are implemented for Samba and those that
 support the CIFS Unix extensions but Samba has a bug currently handling
 symlink text beginning with slash
 2) delete of file with read-only attribute set will fail (may be ok)
+3) mount helper syntax not quite matching man page
 
 Misc testing to do
 =================
index ace0c5ba071230c007a2c44c036e06f0324a9be9..09834bce62a32bb576209260abd8bebab8911602 100644 (file)
@@ -227,7 +227,7 @@ cifs_proc_init(void)
        if (pde)
                pde->write_proc = traceSMB_write;
 
-       pde = create_proc_read_entry("oplockEnabled", 0, proc_fs_cifs,
+       pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
                                     oplockEnabled_read, 0);
        if (pde)
                pde->write_proc = oplockEnabled_write;
@@ -269,7 +269,7 @@ cifs_proc_clean(void)
        remove_proc_entry("SimultaneousOps", proc_fs_cifs);
        remove_proc_entry("TotalOps", proc_fs_cifs);
        remove_proc_entry("MultiuserMount", proc_fs_cifs);
-       remove_proc_entry("oplockEnabled", proc_fs_cifs);
+       remove_proc_entry("OplockEnabled", proc_fs_cifs);
        remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
        remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
        remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
index 0590d93a13e1b7f36486a17692d5e4d0a81a9dbe..7b1bb82687d1582759face75a7a6ad9a3c72eaf8 100644 (file)
@@ -20,8 +20,9 @@
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
-       /* list of implicit mounts beneath this mount point - needed in dfs case */
        struct list_head nested_tcon_q;
        struct nls_table *local_nls;
+    unsigned int rsize;
+    unsigned int wsize;
 };
 #endif                         /* _CIFS_FS_SB_H */
index 8f937cc26379170a15747e1797b0cd17c95165ee..6d582e6e91a27b8a178c6d5402aebfae5fd90af3 100644 (file)
@@ -52,6 +52,7 @@ unsigned int multiuser_mount = 0;
 unsigned int extended_security = 0;
 unsigned int ntlmv2_support = 0;
 unsigned int sign_CIFS_PDUs = 0;
+unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
                        char *);
@@ -83,8 +84,11 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
 
        sb->s_magic = CIFS_MAGIC_NUMBER;
        sb->s_op = &cifs_super_ops;
-       sb->s_blocksize = CIFS_MAX_MSGSIZE;     /* BB check SMBSessSetup negotiated size */
-       sb->s_blocksize_bits = 10;      /* 2**10 = CIFS_MAX_MSGSIZE */
+       if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+           sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
+       else
+               sb->s_blocksize = CIFSMaximumBufferSize;
+       sb->s_blocksize_bits = 14;      /* default 2**14 = CIFS_MAX_MSGSIZE */
        inode = iget(sb, ROOT_I);
 
        if (!inode)
@@ -162,6 +166,12 @@ cifs_statfs(struct super_block *sb, struct statfs *buf)
        return 0;               /* always return success? what if volume is no longer available? */
 }
 
+static int cifs_permission(struct inode * inode, int mask)
+{
+       /* the server does permission checks, we do not need to do it here */
+       return 0;
+}
+
 static kmem_cache_t *cifs_inode_cachep;
 kmem_cache_t *cifs_req_cachep;
 kmem_cache_t *cifs_mid_cachep;
@@ -270,6 +280,7 @@ struct inode_operations cifs_dir_inode_ops = {
        .mkdir = cifs_mkdir,
        .rmdir = cifs_rmdir,
        .rename = cifs_rename,
+       .permission = cifs_permission,
 /*     revalidate:cifs_revalidate,   */
        .setattr = cifs_setattr,
        .symlink = cifs_symlink,
@@ -280,18 +291,19 @@ struct inode_operations cifs_file_inode_ops = {
        .setattr = cifs_setattr,
        .getattr = cifs_getattr, /* do we need this anymore? */
        .rename = cifs_rename,
+       .permission = cifs_permission,
 #ifdef CIFS_XATTR
        .setxattr = cifs_setxattr,
        .getxattr = cifs_getxattr,
        .listxattr = cifs_listxattr,
        .removexattr = cifs_removexattr,
-       .permission = cifs_permission,
 #endif 
 };
 
 struct inode_operations cifs_symlink_inode_ops = {
        .readlink = cifs_readlink,
        .follow_link = cifs_follow_link,
+       .permission = cifs_permission,
        /* BB add the following two eventually */
        /* revalidate: cifs_revalidate,
           setattr:    cifs_notify_change, *//* BB do we need notify change */
index 629278777eca1ee38e57713442bb5fc15f8ace4e..02804188d2b18cab4e4f12117b1efeb55a66c6af 100644 (file)
@@ -519,8 +519,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
        pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
        pSMB->Remaining = 0;
-       pSMB->MaxCount = cpu_to_le16(min_t(const unsigned int, count,
-               (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00));
+       pSMB->MaxCount = cpu_to_le16(count);
        pSMB->MaxCountHigh = 0;
        pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
 
index 3b1ec26f8ad19556471e3b0f1c92ab0c8a06670a..c2303a79f69b75c7ba00be6272fc51602d84db66 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/wait.h>
 #include <linux/version.h>
 #include <linux/ipv6.h>
+#include <linux/pagemap.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -56,6 +57,8 @@ struct smb_vol {
        mode_t file_mode;
        mode_t dir_mode;
        int rw;
+    unsigned int rsize;
+    unsigned int wsize;
        unsigned short int port;
 };
 
@@ -447,6 +450,16 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
                                vol->port =
                                        simple_strtoul(value, &value, 0);
                        }
+               } else if (strnicmp(data, "rsize", 5) == 0) {
+                       if (value && *value) {
+                               vol->rsize =
+                                       simple_strtoul(value, &value, 0);
+                       }
+               } else if (strnicmp(data, "wsize", 5) == 0) {
+                       if (value && *value) {
+                               vol->wsize =
+                                       simple_strtoul(value, &value, 0);
+                       }
                } else if (strnicmp(data, "version", 3) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
@@ -573,11 +586,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                        return -ENOMEM;
                temp_unc[0] = '\\';
                temp_unc[1] = '\\';
-               strncpy(temp_unc + 2, pSesInfo->serverName,
-                       SERVER_NAME_LEN_WITH_NULL * 2);
-               strncpy(temp_unc + 2 + 
-                       strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2), 
-                       "\\IPC$", 5);
+               strcpy(temp_unc + 2, pSesInfo->serverName);
+               strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
                rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
                cFYI(1,
                     ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
@@ -598,6 +608,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab
        char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
        int ntlmv2_flag = FALSE;
 
+    /* what if server changes its buffer size after dropping the session? */
        if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */
                rc = CIFSSMBNegotiate(xid, pSesInfo);
        pSesInfo->capabilities = pSesInfo->server->capabilities;
@@ -778,7 +789,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        struct TCP_Server_Info *srvTcp = NULL;
 
        xid = GetXid();
-       cFYI(0, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data));
+       cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data));
 
        if(parse_mount_options(mount_data, devname, &volume_info)) {
                FreeXid(xid);
@@ -875,9 +886,23 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                atomic_inc(&srvTcp->socketUseCount);
                }
        }
-
+    
        /* search for existing tcon to this server share */
        if (!rc) {
+               if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+                       cifs_sb->rsize = volume_info.rsize;
+               else
+                       cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+               if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+                       cifs_sb->wsize = volume_info.wsize;
+               else
+                       cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+               if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
+                       cifs_sb->rsize = PAGE_CACHE_SIZE;
+                       cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+               }
+
+
                tcon =
                    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
                             volume_info.username);
@@ -980,7 +1005,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        if (smb_buffer == 0) {
                return -ENOMEM;
        }
-    smb_buffer_response = smb_buffer;
+       smb_buffer_response = smb_buffer;
        pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
 
        /* send SMBsessionSetup here */
index ff294c2033c39a66dc7796ae2e9d49672fa518bd..61bddd871bc0d0a11cfbe7f30620391725cb52d4 100644 (file)
@@ -608,6 +608,7 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
        int rc = -EACCES;
        int bytes_read = 0;
        int total_read;
+       int current_read_size;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        int xid;
@@ -624,10 +625,11 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
 
        for (total_read = 0,current_offset=read_data; read_size > total_read;
                                total_read += bytes_read,current_offset+=bytes_read) {
+               current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
                rc = CIFSSMBRead(xid, pTcon,
                                 ((struct cifsFileInfo *) file->
                                  private_data)->netfid,
-                                read_size - total_read, *poffset,
+                                current_read_size, *poffset,
                                 &bytes_read, &current_offset);
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
@@ -744,6 +746,8 @@ cifs_readpages(struct file *file, struct address_space *mapping,
                        num_pages-i, (unsigned long) offset)); 
                
                read_size = (num_pages - i) * PAGE_CACHE_SIZE;
+               /* Read size needs to be in multiples of one page */
+               read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
                rc = CIFSSMBRead(xid, pTcon,
                        ((struct cifsFileInfo *) file->
                         private_data)->netfid,
index 02a235ee9442888e80fa814c8582fb0c89514674..fcc689adba4e4aa78f7fd950491d69d4eaf980f2 100644 (file)
@@ -153,7 +153,8 @@ buf_get(void)
 
 /* We could use negotiated size instead of max_msgsize - 
    but it may be more efficient to always alloc same size 
-   albeit slightly larger */
+   albeit slightly larger than necessary and maxbuffersize 
+   defaults to this and can not be bigger */
        ret_buf =
            (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
 
index aad3a7b4aac8ffc2c5dd0976b13ec87a5ebd1fc5..70687d645e6443c689118db5b4087cd517d8aae4 100644 (file)
@@ -159,7 +159,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        midQ = AllocMidQEntry(in_buf, ses);
        if (midQ == NULL)
                return -EIO;
-       if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
+       if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
                cERROR(1,
                       ("Illegal length, greater than maximum frame, %d ",
                        in_buf->smb_buf_length));