X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Fcifsfs.c;h=8cc23e7d0d5d34e69924e7752e3a816dd6297cfc;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=729cdba71530d4f2119f4f93d6f8cc04cdf39a19;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 729cdba71..8cc23e7d0 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -50,24 +50,35 @@ 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; +extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; - -extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, - const char *); -extern int cifs_umount(struct super_block *, struct cifs_sb_info *); -void cifs_proc_init(void); -void cifs_proc_clean(void); +unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; +module_param(CIFSMaxBufSize, int, 0); +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, 0); +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, 0); +MODULE_PARM_DESC(cifs_min_small,"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, 0); +MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); static DECLARE_COMPLETION(cifs_oplock_exited); +extern mempool_t *cifs_sm_req_poolp; +extern mempool_t *cifs_req_poolp; +extern mempool_t *cifs_mid_poolp; + +extern kmem_cache_t *cifs_oplock_cachep; static int cifs_read_super(struct super_block *sb, void *data, @@ -158,7 +169,8 @@ cifs_put_super(struct super_block *sb) static int cifs_statfs(struct super_block *sb, struct kstatfs *buf) { - int xid, rc; + int xid; + int rc = -EOPNOTSUPP; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; @@ -170,22 +182,34 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) buf->f_type = CIFS_MAGIC_NUMBER; /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ - buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably - be length of total path, note that some servers may be - able to support more than this, but best to be safe - since Win2k and others can not handle very long filenames */ + buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would + presumably be total path, but note + that some servers (includinng Samba 3) + have a shorter maximum path */ buf->f_files = 0; /* undefined */ buf->f_ffree = 0; /* unlimited */ - rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); +#ifdef CONFIG_CIFS_EXPERIMENTAL +/* BB we could add a second check for a QFS Unix capability bit */ +/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */ + if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS & + le64_to_cpu(pTcon->fsUnixInfo.Capability))) + rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf); + + /* Only need to call the old QFSInfo if failed + on newer one */ + if(rc) +#endif /* CIFS_EXPERIMENTAL */ + rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* int f_type; __fsid_t f_fsid; int f_namelen; */ - /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ + /* BB get from info in tcon struct at mount time call to QFSAttrInfo */ FreeXid(xid); - return 0; /* always return success? what if volume is no longer available? */ + return 0; /* always return success? what if volume is no + longer available? */ } static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) @@ -200,13 +224,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; @@ -214,9 +240,7 @@ static struct inode * cifs_alloc_inode(struct super_block *sb) { struct cifsInodeInfo *cifs_inode; - cifs_inode = - (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, - SLAB_KERNEL); + cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL); if (!cifs_inode) return NULL; cifs_inode->cifsAttrs = 0x20; /* default */ @@ -423,14 +447,13 @@ static ssize_t cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, loff_t * poffset) { - if(file == NULL) - return -EIO; - else if(file->f_dentry == NULL) + if(file->f_dentry == NULL) return -EIO; else if(file->f_dentry->d_inode == NULL) return -EIO; cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { return generic_file_read(file,read_data,read_size,poffset); } else { @@ -454,16 +477,13 @@ cifs_write_wrapper(struct file * file, const char __user *write_data, { ssize_t written; - if(file == NULL) - return -EIO; - else if(file->f_dentry == NULL) + if(file->f_dentry == NULL) return -EIO; else if(file->f_dentry->d_inode == NULL) return -EIO; cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); - /* check whether we can cache writes locally */ 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) { @@ -495,6 +515,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 = { @@ -537,20 +563,53 @@ struct file_operations cifs_file_ops = { .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#ifdef CONFIG_CIFS_EXPERIMENTAL + .readv = generic_file_readv, + .writev = generic_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; + +struct file_operations cifs_file_direct_ops = { + /* no mmap, no aio, no readv - + BB reevaluate whether they can be done with directio, no cache */ + .read = cifs_user_read, + .write = cifs_user_write, + .open = cifs_open, + .release = cifs_close, + .lock = cifs_lock, + .fsync = cifs_fsync, + .flush = cifs_flush, + .sendfile = generic_file_sendfile, /* BB removeme BB */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#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 */ + .ioctl = cifs_ioctl, }; static void cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) { - struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode; + struct cifsInodeInfo *cifsi = inode; if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { @@ -582,14 +641,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; + cERROR(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); @@ -598,6 +674,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; } @@ -609,6 +719,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 @@ -721,6 +835,7 @@ static int cifs_oplock_thread(void * dummyarg) } } while(!signal_pending(current)); complete_and_exit (&cifs_oplock_exited, 0); + oplockThread = NULL; } static int __init @@ -748,8 +863,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) {