vserver 1.9.5.x5
[linux-2.6.git] / fs / cifs / cifsfs.c
index fbc737e..b0884aa 100644 (file)
@@ -50,15 +50,27 @@ int cifsFYI = 0;
 int cifsERROR = 1;
 int traceSMB = 0;
 unsigned int oplockEnabled = 1;
-unsigned int quotaEnabled = 0;
+unsigned int experimEnabled = 0;
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
 unsigned int extended_security = 0;
 unsigned int ntlmv2_support = 0;
 unsigned int sign_CIFS_PDUs = 1;
-unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
 struct task_struct * oplockThread = NULL;
+unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
+module_param(CIFSMaxBufSize, int, CIFS_MAX_MSGSIZE);
+MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
+unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
+module_param(cifs_min_rcv, int, CIFS_MIN_RCV_POOL);
+MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
+unsigned int cifs_min_small = 30;
+module_param(cifs_min_small, int, 30);
+MODULE_PARM_DESC(cifs_small_rcv,"Small network buffers in pool. Default: 30 Range: 2 to 256");
+unsigned int cifs_max_pending = CIFS_MAX_REQ;
+module_param(cifs_max_pending, int, CIFS_MAX_REQ);
+MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
+
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
                        const char *);
@@ -200,13 +212,15 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
                on the client (above and beyond ACL on servers) for  
                servers which do not support setting and viewing mode bits,
                so allowing client to check permissions is useful */ 
-               return vfs_permission(inode, mask);
+               return generic_permission(inode, mask, NULL);
 }
 
 static kmem_cache_t *cifs_inode_cachep;
 static kmem_cache_t *cifs_req_cachep;
 static kmem_cache_t *cifs_mid_cachep;
 kmem_cache_t *cifs_oplock_cachep;
+static kmem_cache_t *cifs_sm_req_cachep;
+mempool_t *cifs_sm_req_poolp;
 mempool_t *cifs_req_poolp;
 mempool_t *cifs_mid_poolp;
 
@@ -255,12 +269,14 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
        if (cifs_sb) {
                if (cifs_sb->tcon) {
                        seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
-                       if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName))
-                               seq_printf(s, ",username=%s",
+                       if (cifs_sb->tcon->ses) {
+                               if (cifs_sb->tcon->ses->userName)
+                                       seq_printf(s, ",username=%s",
                                           cifs_sb->tcon->ses->userName);
-                       if(cifs_sb->tcon->ses->domainName)
-                               seq_printf(s, ",domain=%s",
-                                       cifs_sb->tcon->ses->domainName);
+                               if(cifs_sb->tcon->ses->domainName)
+                                       seq_printf(s, ",domain=%s",
+                                          cifs_sb->tcon->ses->domainName);
+                       }
                }
                seq_printf(s, ",rsize=%d",cifs_sb->rsize);
                seq_printf(s, ",wsize=%d",cifs_sb->wsize);
@@ -429,6 +445,20 @@ cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
                return -EIO;
 
        cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset));
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+       /* check whether we can cache writes locally */
+       if(file->f_dentry->d_sb) {
+               struct cifs_sb_info *cifs_sb;
+               cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+               if(cifs_sb != NULL) {
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+                               return cifs_user_read(file,read_data,
+                                                       read_size,poffset);
+               }
+       }
+#endif /* CIFS_EXPERIMENTAL */
+
        if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
                return generic_file_read(file,read_data,read_size,poffset);
        } else {
@@ -461,7 +491,19 @@ cifs_write_wrapper(struct file * file, const char __user *write_data,
 
        cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset));
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL    /* BB fixme - fix user char * to kernel char * mapping here BB */
        /* check whether we can cache writes locally */
+       if(file->f_dentry->d_sb) {
+               struct cifs_sb_info *cifs_sb;
+               cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+               if(cifs_sb != NULL) {
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+                               return cifs_user_write(file,write_data,
+                                                       write_size,poffset);
+                       }
+               }
+       }
+#endif /* CIFS_EXPERIMENTAL */
        written = generic_file_write(file,write_data,write_size,poffset);
        if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll)  {
                if(file->f_dentry->d_inode->i_mapping) {
@@ -493,6 +535,12 @@ struct inode_operations cifs_dir_inode_ops = {
        .setattr = cifs_setattr,
        .symlink = cifs_symlink,
        .mknod   = cifs_mknod,
+#ifdef CONFIG_CIFS_XATTR
+       .setxattr = cifs_setxattr,
+       .getxattr = cifs_getxattr,
+       .listxattr = cifs_listxattr,
+       .removexattr = cifs_removexattr,
+#endif
 };
 
 struct inode_operations cifs_file_inode_ops = {
@@ -510,8 +558,9 @@ struct inode_operations cifs_file_inode_ops = {
 };
 
 struct inode_operations cifs_symlink_inode_ops = {
-       .readlink = cifs_readlink,
+       .readlink = generic_readlink, 
        .follow_link = cifs_follow_link,
+       .put_link = cifs_put_link,
        .permission = cifs_permission,
        /* BB add the following two eventually */
        /* revalidate: cifs_revalidate,
@@ -534,14 +583,18 @@ struct file_operations cifs_file_ops = {
        .flush = cifs_flush,
        .mmap  = cifs_file_mmap,
        .sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_EXPERIMENTAL
        .dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
 struct file_operations cifs_dir_ops = {
        .readdir = cifs_readdir,
        .release = cifs_closedir,
        .read    = generic_read_dir,
+#ifdef CONFIG_CIFS_EXPERIMENTAL
        .dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
 static void
@@ -561,7 +614,7 @@ cifs_init_inodecache(void)
 {
        cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
                                              sizeof (struct cifsInodeInfo),
-                                             0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+                                             0, SLAB_RECLAIM_ACCOUNT,
                                              cifs_init_once, NULL);
        if (cifs_inode_cachep == NULL)
                return -ENOMEM;
@@ -579,14 +632,31 @@ cifs_destroy_inodecache(void)
 static int
 cifs_init_request_bufs(void)
 {
+       if(CIFSMaxBufSize < 8192) {
+       /* Buffer size can not be smaller than 2 * PATH_MAX since maximum
+       Unicode path name has to fit in any SMB/CIFS path based frames */
+               CIFSMaxBufSize = 8192;
+       } else if (CIFSMaxBufSize > 1024*127) {
+               CIFSMaxBufSize = 1024 * 127;
+       } else {
+               CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/
+       }
+/*     cERROR(1,("CIFSMaxBufSize %d 0x%x",CIFSMaxBufSize,CIFSMaxBufSize)); */
        cifs_req_cachep = kmem_cache_create("cifs_request",
-                                           CIFS_MAX_MSGSIZE +
+                                           CIFSMaxBufSize +
                                            MAX_CIFS_HDR_SIZE, 0,
                                            SLAB_HWCACHE_ALIGN, NULL, NULL);
        if (cifs_req_cachep == NULL)
                return -ENOMEM;
 
-       cifs_req_poolp = mempool_create(CIFS_MIN_RCV_POOL,
+       if(cifs_min_rcv < 1)
+               cifs_min_rcv = 1;
+       else if (cifs_min_rcv > 64) {
+               cifs_min_rcv = 64;
+               cFYI(1,("cifs_min_rcv set to maximum (64)"));
+       }
+
+       cifs_req_poolp = mempool_create(cifs_min_rcv,
                                        mempool_alloc_slab,
                                        mempool_free_slab,
                                        cifs_req_cachep);
@@ -595,6 +665,40 @@ cifs_init_request_bufs(void)
                kmem_cache_destroy(cifs_req_cachep);
                return -ENOMEM;
        }
+       /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and
+       almost all handle based requests (but not write response, nor is it
+       sufficient for path based requests).  A smaller size would have
+       been more efficient (compacting multiple slab items on one 4k page) 
+       for the case in which debug was on, but this larger size allows
+       more SMBs to use small buffer alloc and is still much more
+       efficient to alloc 1 per page off the slab compared to 17K (5page) 
+       alloc of large cifs buffers even when page debugging is on */
+       cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
+                       MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (cifs_sm_req_cachep == NULL) {
+               mempool_destroy(cifs_req_poolp);
+               kmem_cache_destroy(cifs_req_cachep);
+               return -ENOMEM;              
+       }
+
+       if(cifs_min_small < 2)
+               cifs_min_small = 2;
+       else if (cifs_min_small > 256) {
+               cifs_min_small = 256;
+               cFYI(1,("cifs_min_small set to maximum (256)"));
+       }
+
+       cifs_sm_req_poolp = mempool_create(cifs_min_small,
+                               mempool_alloc_slab,
+                               mempool_free_slab,
+                               cifs_sm_req_cachep);
+
+       if(cifs_sm_req_poolp == NULL) {
+               mempool_destroy(cifs_req_poolp);
+               kmem_cache_destroy(cifs_req_cachep);
+               kmem_cache_destroy(cifs_sm_req_cachep);
+               return -ENOMEM;
+       }
 
        return 0;
 }
@@ -606,6 +710,10 @@ cifs_destroy_request_bufs(void)
        if (kmem_cache_destroy(cifs_req_cachep))
                printk(KERN_WARNING
                       "cifs_destroy_request_cache: error not all structures were freed\n");
+       mempool_destroy(cifs_sm_req_poolp);
+       if (kmem_cache_destroy(cifs_sm_req_cachep))
+               printk(KERN_WARNING
+                     "cifs_destroy_request_cache: cifs_small_rq free error\n");
 }
 
 static int
@@ -745,8 +853,16 @@ init_cifs(void)
        GlobalCurrentXid = 0;
        GlobalTotalActiveXid = 0;
        GlobalMaxActiveXid = 0;
-       GlobalSMBSeslock = RW_LOCK_UNLOCKED;
-       GlobalMid_Lock = SPIN_LOCK_UNLOCKED;
+       rwlock_init(&GlobalSMBSeslock);
+       spin_lock_init(&GlobalMid_Lock);
+
+       if(cifs_max_pending < 2) {
+               cifs_max_pending = 2;
+               cFYI(1,("cifs_max_pending set to min of 2"));
+       } else if(cifs_max_pending > 256) {
+               cifs_max_pending = 256;
+               cFYI(1,("cifs_max_pending set to max of 256"));
+       }
 
        rc = cifs_init_inodecache();
        if (!rc) {
@@ -756,11 +872,14 @@ init_cifs(void)
                        if (!rc) {
                                rc = register_filesystem(&cifs_fs_type);
                                if (!rc) {                
-                                       kernel_thread(cifs_oplock_thread, NULL, 
+                                       rc = (int)kernel_thread(cifs_oplock_thread, NULL, 
                                                CLONE_FS | CLONE_FILES | CLONE_VM);
-                                       return rc; /* Success */
-                               } else
-                                       cifs_destroy_request_bufs();
+                                       if(rc > 0)
+                                               return 0;
+                                       else 
+                                               cERROR(1,("error %d create oplock thread",rc));
+                               }
+                               cifs_destroy_request_bufs();
                        }
                        cifs_destroy_mids();
                }